diff options
author | Andreas Rumpf <andreas@andreas-desktop> | 2010-03-10 00:40:34 +0100 |
---|---|---|
committer | Andreas Rumpf <andreas@andreas-desktop> | 2010-03-10 00:40:34 +0100 |
commit | 2e280eafa8b13802980cf0e2f309342742e61347 (patch) | |
tree | ff06081d75caa000e57c36e0848cc9cf6eace286 /lib | |
parent | 7dff3e64bbb44cfc57314038c2c047f2ccb1da1e (diff) | |
download | Nim-2e280eafa8b13802980cf0e2f309342742e61347.tar.gz |
bugfix: tseqtuple
Diffstat (limited to 'lib')
-rwxr-xr-x | lib/impure/graphics.nim | 226 |
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() |