summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAndreas Rumpf <andreas@andreas-desktop>2010-03-10 00:40:34 +0100
committerAndreas Rumpf <andreas@andreas-desktop>2010-03-10 00:40:34 +0100
commit2e280eafa8b13802980cf0e2f309342742e61347 (patch)
treeff06081d75caa000e57c36e0848cc9cf6eace286 /lib
parent7dff3e64bbb44cfc57314038c2c047f2ccb1da1e (diff)
downloadNim-2e280eafa8b13802980cf0e2f309342742e61347.tar.gz
bugfix: tseqtuple
Diffstat (limited to 'lib')
-rwxr-xr-xlib/impure/graphics.nim226
1 files changed, 189 insertions, 37 deletions
diff --git a/lib/impure/graphics.nim b/lib/impure/graphics.nim
index ecbd9a1fa..68a686fac 100755
--- a/lib/impure/graphics.nim
+++ b/lib/impure/graphics.nim
@@ -11,8 +11,9 @@
 ## implementation uses SDL but the interface is meant to support multiple
 ## backends some day. 
 
-import colors
+import colors, math
 from sdl import PSurface # Bug
+from sdl_ttf import OpenFont
 
 type
   TRect* = tuple[x, y, width, height: int]
@@ -23,6 +24,8 @@ type
     w, h: int
     s: sdl.PSurface
   
+  ESDLError = object of EBase
+  
 proc surfaceFinalizer(s: PSurface) = sdl.freeSurface(s.s)
   
 proc newSurface*(width, height: int): PSurface =
@@ -35,8 +38,18 @@ proc newSurface*(width, height: int): PSurface =
    
   assert(not sdl.MustLock(result.s))
 
-#proc textBounds*(text: string): tuple[len, height: int]
-#proc drawText*(sur: PSurface, p: TPoint, text: string)
+proc newScreenSurface(width, height: int): PSurface =
+  ## Creates a new screen surface
+  new(result, surfaceFinalizer)
+  result.w = width
+  result.h = height
+  result.s = SDL.SetVideoMode(width, height, 0, 0)
+
+template withEvents(surf: PSurface, event: expr, actions: stmt): stmt =
+  while True:
+    var event: SDL.TEvent
+    if SDL.PollEvent(addr(event)) == 1:
+      actions
 
 proc writeToBMP*(sur: PSurface, filename: string) =
   ## Saves the contents of the surface `sur` to the file `filename` as a 
@@ -77,6 +90,91 @@ proc `[]=`*(sur: PSurface, p: TPoint, col: TColor) =
 #proc `[,]=`*(sur: PSurface, x, y: int, col: TColor) =
 #  setPixel(sur, x, y, col)
 
+proc blitSurface*(destSurf: PSurface, destRect: TRect, srcSurf: PSurface, srcRect: TRect) =
+  ## Merges ``srcSurf`` into ``destSurf``
+  var destTRect, srcTRect: SDL.TRect
+
+  destTRect.x = int16(destRect.x)
+  destTRect.y = int16(destRect.y)
+  destTRect.w = int16(destRect.width)
+  destTRect.h = int16(destRect.height)
+
+  srcTRect.x = int16(srcRect.x)
+  srcTRect.y = int16(srcRect.y)
+  srcTRect.w = int16(srcRect.width)
+  srcTRect.h = int16(srcRect.height)
+
+  if SDL.blitSurface(srcSurf.s, addr(srcTRect), destSurf.s, addr(destTRect)) != 0:
+    raise newException(ESDLError, $SDL.GetError())
+
+proc textBounds*(font: string, fontSize: int, 
+                 text: string): tuple[width, height: int] =
+  var fontFile = OpenFont(font, fontSize) # Open the font file
+  if fontFile == nil: raise newException(ESDLError, "Could not open font file")
+    
+  var w, h: cint
+  if sdl_ttf.SizeUTF8(fontFile, text, w, h) < 0:
+    raise newException(ESDLError, $SDL.GetError())
+  return (int(w), int(h))
+
+proc drawText*(sur: PSurface, p: TPoint, font: string, text: string,
+    fg: TColor = colBlack, fontSize: int = 9) =
+  ## Draws text with a transparent background, at location ``p``.
+  ## ``font`` specifies the path to the ttf file, 
+  ## ``fontSize`` specifies the font size in pt, and ``fg``
+  ## specifies the foreground color.
+  var fontFile = OpenFont(font, fontSize) # Open the font file
+  if fontFile == nil: raise newException(ESDLError, "Could not open font file")
+  
+  var textSur: PSurface # This surface will have the text drawn on it
+  new(textSur, surfaceFinalizer)
+  
+  var RGBfg = fg.extractRGB
+  
+  # Convert the colors.TColor to SDL.TColor
+  var SDLfg: SDL.TColor
+  SDLfg.r = toU8(RGBfg.r)
+  SDLfg.g = toU8(RGBfg.g)
+  SDLfg.b = toU8(RGBfg.b)
+  
+  # Render the text
+  textSur.s = sdl_ttf.RenderTextBlended(fontFile, text, SDLfg)
+  # Merge the text surface with sur
+  sur.blitSurface((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h))
+  # Free the surface
+  SDL.FreeSurface(sur.s)
+
+proc drawText*(sur: PSurface, p: TPoint, font: string, text: string,
+    bg: TColor, fg: TColor = colBlack, fontSize: int = 9) =
+  ## Draws text, at location ``p``, ``font`` specifies the path to 
+  ## the ttf file, ``fontSize`` specifies the font size in pt, and ``fg`` 
+  ## and ``bg`` specify the foreground and background colors.
+  var fontFile = OpenFont(font, fontSize) # Open the font file
+  if fontFile == nil: raise newException(ESDLError, "Could not open font file")
+  
+  var textSur: PSurface # This surface will have the text drawn on it
+  new(textSur, surfaceFinalizer)
+  
+  var RGBfg = fg.extractRGB
+  var RGBbg = bg.extractRGB
+  
+  # Convert the colors.TColor to SDL.TColor
+  var SDLfg: SDL.TColor
+  SDLfg.r = toU8(RGBfg.r)
+  SDLfg.g = toU8(RGBfg.g)
+  SDLfg.b = toU8(RGBfg.b)
+  var SDLbg: SDL.TColor
+  SDLbg.r = toU8(RGBbg.r)
+  SDLbg.g = toU8(RGBbg.g)
+  SDLbg.b = toU8(RGBbg.b)
+  
+  # Render the text
+  textSur.s = sdl_ttf.RenderTextShaded(fontFile, text, SDLfg, SDLbg)
+  # Merge the text surface with sur
+  sur.blitSurface((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h))
+  # Free the surface
+  SDL.FreeSurface(sur.s)
+
 proc drawCircle*(sur: PSurface, p: TPoint, r: Natural, color: TColor) =
   ## draws a circle with center `p` and radius `r` with the given color
   ## onto the surface `sur`.
@@ -247,7 +345,7 @@ proc drawRect*(sur: PSurface, r: TRect, color: TColor) =
       setPix(video, pitch, r.x + minW - 1, r.y + i, color) # Draw right side
     
 proc fillRect*(sur: PSurface, r: TRect, col: TColor) =
-  ## draws and fills a rectancle.
+  ## draws and fills a rectangle.
   var video = cast[PPixels](sur.s.pixels)
   assert video != nil
   var pitch = sur.s.pitch div ColSize
@@ -256,17 +354,23 @@ proc fillRect*(sur: PSurface, r: TRect, col: TColor) =
     for j in r.x..min(sur.s.w, r.x+r.width-1)-1:
       setPix(video, pitch, j, i, col)
 
-
 proc Plot4EllipsePoints(sur: PSurface, CX, CY, X, Y: Natural, col: TColor) =
   var video = cast[PPixels](sur.s.pixels)
   var pitch = sur.s.pitch div ColSize
   
-  setPix(video, pitch, CX+X, CY+Y, col)
-  setPix(video, pitch, CX-X, CY+Y, col)
-  setPix(video, pitch, CX-X, CY-Y, col)
-  setPix(video, pitch, CX+X, CY-Y, col)
+  if CX+X < sur.s.w and CY+Y < sur.s.h:
+    setPix(video, pitch, CX+X, CY+Y, col)
+  if CX-X < sur.s.w and CY+Y < sur.s.h:
+    setPix(video, pitch, CX-X, CY+Y, col)
+  if CX-X < sur.s.w and CY-Y < sur.s.h:
+    setPix(video, pitch, CX-X, CY-Y, col)
+  if CX+X < sur.s.w and CY-Y < sur.s.h:
+    setPix(video, pitch, CX+X, CY-Y, col)
 
 proc drawEllipse*(sur: PSurface, CX, CY, XRadius, YRadius: Natural, col: TColor) =
+  ## Draws an ellipse, ``CX`` and ``CY`` specify the center X and Y of
+  ## the ellipse, ``XRadius`` and ``YRadius`` specify the width and height 
+  ## of the ellipse.
   var 
     X, Y: Natural
     XChange, YChange: Natural
@@ -317,27 +421,29 @@ proc drawEllipse*(sur: PSurface, CX, CY, XRadius, YRadius: Natural, col: TColor)
       inc(YChange,TwoASquare)
   
 
-proc plot(sur: PSurface, x, y, c: float, color: TColor) =
-  var video = cast[PPixels](sur.s.pixels)
-  var pitch = sur.s.pitch div ColSize
-  var pixColor = getPix(video, pitch, x.toInt, y.toInt)
+proc plotAA(sur: PSurface, x, y, c: float, color: TColor) =
+  if (x.toInt() > 0 and x.toInt() < sur.s.w) and (y.toInt() > 0 and 
+      y.toInt() < sur.s.h):
+    var video = cast[PPixels](sur.s.pixels)
+    var pitch = sur.s.pitch div ColSize
+
+    var pixColor = getPix(video, pitch, x.toInt, y.toInt)
 
-  setPix(video, pitch, x.toInt(), y.toInt(), 
-         pixColor.intensity(1.0 - c) + color.intensity(c))
-import math
+    setPix(video, pitch, x.toInt(), y.toInt(), 
+           pixColor.intensity(1.0 - c) + color.intensity(c))
+         
 proc ipart(x: float): float =
   return x.trunc()
 proc fpart(x: float): float =
   return x - ipart(x)
 proc rfpart(x: float): float =
   return 1.0 - fpart(x)
-
-
-
+  
 proc drawLineAA(sur: PSurface, p1: TPoint, p2: TPoint, color: TColor) =
-  ## Draws a line from ``p1`` to ``p2``, using the Xiaolin Wu's line algorithm
+  ## Draws a anti-aliased line from ``p1`` to ``p2``, using Xiaolin Wu's line algorithm
   var (x1, x2, y1, y2) = (p1.x.toFloat(), p2.x.toFloat(), 
                           p1.y.toFloat(), p2.y.toFloat())
+  
   var dx = x2 - x1
   var dy = y2 - y1
   if abs(dx) < abs(dy):
@@ -354,41 +460,87 @@ proc drawLineAA(sur: PSurface, p1: TPoint, p2: TPoint, color: TColor) =
   var xgap = rfpart(x1 + 0.5)
   var xpxl1 = xend # this will be used in the main loop
   var ypxl1 = ipart(yend)
-  sur.plot(xpxl1, ypxl1, rfpart(yend) * xgap, color)
-  sur.plot(xpxl1, ypxl1 + 1.0, fpart(yend) * xgap, color)
+  sur.plotAA(xpxl1, ypxl1, rfpart(yend) * xgap, color)
+  sur.plotAA(xpxl1, ypxl1 + 1.0, fpart(yend) * xgap, color)
   var intery = yend + gradient # first y-intersection for the main loop
   # handle second endpoint
   xend = x2 # Should be round(x1), but since this is an int anyway..
   yend = y2 + gradient * (xend - x2)
   xgap = fpart(x2 + 0.5)
   var xpxl2 = xend  # this will be used in the main loop
-  var ypxl2 = ipart (yend)
-  sur.plot(xpxl2, ypxl2, rfpart(yend) * xgap, color)
-  sur.plot(xpxl2, ypxl2 + 1.0, fpart(yend) * xgap, color)  
+  var ypxl2 = ipart(yend)
+  sur.plotAA(xpxl2, ypxl2, rfpart(yend) * xgap, color)
+  sur.plotAA(xpxl2, ypxl2 + 1.0, fpart(yend) * xgap, color)  
   # main loop
   for x in xpxl1.toInt + 1..xpxl2.toInt - 1:
-    sur.plot(x.toFloat(), ipart(intery), rfpart(intery), color)
-    sur.plot(x.toFloat(), ipart(intery) + 1.0, fpart(intery), color)
+    sur.plotAA(x.toFloat(), ipart(intery), rfpart(intery), color)
+    sur.plotAA(x.toFloat(), ipart(intery) + 1.0, fpart(intery), color)
     intery = intery + gradient
-
   
       
-if sdl.Init(sdl.INIT_VIDEO) < 0: 
-  echo "init failed"
-  
+if sdl.Init(sdl.INIT_VIDEO) < 0:
+  echo "sdl init failed: " & $SDL.GetError()
+
+if sdl_ttf.Init() < 0:
+  echo "sdl_ttf init failed: " & $SDL.GetError() 
+
 when isMainModule:
-  var surf = newSurface(800, 600)
+  #var txtSurf = drawText(
+
+  var surf = newScreenSurface(800, 600)
   var r: TRect = (0, 0, 900, 900)
+    
+  # Draw the shapes
   surf.fillRect(r, colWhite)
-  surf.drawLineAA((500, 300), (200, 270), colTan)
+  surf.drawLineAA((400, 599), (100, 170), colTan)
   
-  surf.drawEllipse(400, 300, 415, 200, colSeaGreen)
+  surf.drawEllipse(200, 300, 200, 30, colSeaGreen)
+  surf.drawHorLine(1, 300, 400, colViolet) # Check if the ellipse is the size it's suppose to be.
+  surf.drawVerLine(200, 300 - 30 + 1, 60, colViolet) # ^^ | i suppose it is
+  
+  surf.drawEllipse(400, 300, 300, 300, colOrange)
+  surf.drawEllipse(5, 5, 5, 5, colGreen)
   
   surf.drawHorLine(5, 5, 900, colRed)
   surf.drawVerLine(5, 60, 800, colRed)
-  surf.setPixel(70, 100, colWhite)
   surf.drawCircle((600, 500), 60, colRed)
-  #surf.setPixel(799, 599, colGreen)
-  echo(fpart(5.5))
   
+  surf.drawText((300, 300), "VeraMono.ttf", "TEST", colTan,  colMidnightBlue, 150)
+  var textSize = textBounds("VeraMono.ttf", 150, "TEST")
+  surf.drawText((300, 300 + textSize.height), "VeraMono.ttf", $textSize.width & ", " & $textSize.height, colDarkGreen, 50)
+  
+  var mouseStartX = 0
+  var mouseStartY = 0
+  withEvents(surf, event):
+    case event.theType:
+    of SDL.QUITEV:
+      break
+    of SDL.KEYDOWN:
+      if event.key.keysym.sym == SDL.K_LEFT:
+        echo(event.key.keysym.sym)
+        surf.drawHorLine(395, 300, 5, colPaleGoldenRod)
+        echo("Drawing")
+      else:
+        echo(event.key.keysym.sym)
+    of SDL.MOUSEBUTTONDOWN:
+      # button.x/y is F* UP!
+      echo("MOUSEDOWN", event.button.x)
+      mouseStartX = event.button.x
+      mouseStartY = event.button.y
+      
+    of SDL.MOUSEBUTTONUP:
+      echo("MOUSEUP ", mouseStartX)
+      if mouseStartX != 0 and mouseStartY != 0:
+        echo(mouseStartX, "->", int(event.button.x))
+        surf.drawLineAA((mouseStartX, MouseStartY), 
+          (int(event.button.x), int(event.button.y)), colPaleGoldenRod)
+        mouseStartX = 0
+        mouseStartY = 0
+      
+    else:
+      echo(event.theType)
+      
+    SDL.UpdateRect(surf.s, int32(0), int32(0), int32(800), int32(600))
+    
   surf.writeToBMP("test.bmp")
+  SDL.Quit()