Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq 2011-04-30 00:00:33 +02:00
commit 0d75723f91

View file

@ -9,7 +9,8 @@
## This module implements graphical output for Nimrod; the current ## This module implements graphical output for Nimrod; the current
## implementation uses SDL but the interface is meant to support multiple ## implementation uses SDL but the interface is meant to support multiple
## backends some day. ## backends some day. There is no need to init SDL as this module does that
## implicitly.
import colors, math import colors, math
from sdl import PSurface # Bug from sdl import PSurface # Bug
@ -20,9 +21,9 @@ type
TPoint* = tuple[x, y: int] TPoint* = tuple[x, y: int]
PSurface* = ref TSurface ## a surface to draw onto PSurface* = ref TSurface ## a surface to draw onto
TSurface {.pure, final.} = object TSurface* {.pure, final.} = object
w, h: int w*, h*: int
s: sdl.PSurface s*: sdl.PSurface
EGraphics* = object of EIO EGraphics* = object of EIO
@ -31,13 +32,25 @@ type
color: SDL.TColor color: SDL.TColor
PFont* = ref TFont ## represents a font PFont* = ref TFont ## represents a font
proc toSdlColor(c: TColor): Sdl.TColor = proc toSdlColor*(c: TColor): Sdl.TColor =
# Convert colors.TColor to SDL.TColor ## Convert colors.TColor to SDL.TColor
var x = c.extractRGB var x = c.extractRGB
result.r = toU8(x.r) result.r = toU8(x.r)
result.g = toU8(x.g) result.g = toU8(x.g)
result.b = toU8(x.b) result.b = toU8(x.b)
proc createSdlColor*(sur: PSurface, c: TColor, alpha: int = 0): int32 =
## Creates a color using ``sdl.MapRGBA``.
var x = c.extractRGB
return sdl.MapRGBA(sur.s.format, toU8(x.r), toU8(x.g), toU8(x.b), toU8(alpha))
proc toSdlRect*(r: TRect): sdl.TRect =
## Convert ``graphics.TRect`` to ``sdl.TRect``.
result.x = int16(r.x)
result.y = int16(r.y)
result.w = int16(r.width)
result.h = int16(r.height)
proc raiseEGraphics = proc raiseEGraphics =
raise newException(EGraphics, $SDL.GetError()) raise newException(EGraphics, $SDL.GetError())
@ -50,6 +63,8 @@ proc newSurface*(width, height: int): PSurface =
result.h = height result.h = height
result.s = SDL.CreateRGBSurface(SDL.SWSURFACE, width, height, result.s = SDL.CreateRGBSurface(SDL.SWSURFACE, width, height,
32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0) 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0)
if result.s == nil:
raiseEGraphics()
assert(not sdl.MustLock(result.s)) assert(not sdl.MustLock(result.s))
@ -71,12 +86,14 @@ proc initDefaultFont*(name = "VeraMono.ttf", size = 9, color = colBlack) =
## initializes the `defaultFont` var. ## initializes the `defaultFont` var.
defaultFont = newFont(name, size, color) defaultFont = newFont(name, size, color)
proc newScreenSurface(width, height: int): PSurface = proc newScreenSurface*(width, height: int): PSurface =
## Creates a new screen surface ## Creates a new screen surface
new(result, surfaceFinalizer) new(result, surfaceFinalizer)
result.w = width result.w = width
result.h = height result.h = height
result.s = SDL.SetVideoMode(width, height, 0, 0) result.s = SDL.SetVideoMode(width, height, 0, 0)
if result.s == nil:
raiseEGraphics()
proc writeToBMP*(sur: PSurface, filename: string) = proc writeToBMP*(sur: PSurface, filename: string) =
## Saves the contents of the surface `sur` to the file `filename` as a ## Saves the contents of the surface `sur` to the file `filename` as a
@ -113,7 +130,7 @@ proc `[]`*(sur: PSurface, p: TPoint): TColor =
## get pixel at position `p`. No range checking is done! ## get pixel at position `p`. No range checking is done!
result = getPixel(sur, p.x, p.y) result = getPixel(sur, p.x, p.y)
proc `[,]`*(sur: PSurface, x, y: int): TColor = proc `[]`*(sur: PSurface, x, y: int): TColor =
## get pixel at position ``(x, y)``. No range checking is done! ## get pixel at position ``(x, y)``. No range checking is done!
result = getPixel(sur, x, y) result = getPixel(sur, x, y)
@ -121,7 +138,7 @@ proc `[]=`*(sur: PSurface, p: TPoint, col: TColor) =
## set the pixel at position `p`. No range checking is done! ## set the pixel at position `p`. No range checking is done!
setPixel(sur, p.x, p.y, col) setPixel(sur, p.x, p.y, col)
proc `[,]=`*(sur: PSurface, x, y: int, col: TColor) = proc `[]=`*(sur: PSurface, x, y: int, col: TColor) =
## set the pixel at position ``(x, y)``. No range checking is done! ## set the pixel at position ``(x, y)``. No range checking is done!
setPixel(sur, x, y, col) setPixel(sur, x, y, col)
@ -159,8 +176,6 @@ proc drawText*(sur: PSurface, p: TPoint, text: string, font = defaultFont) =
textSur.s = sdl_ttf.RenderTextBlended(font.f, text, font.color) textSur.s = sdl_ttf.RenderTextBlended(font.f, text, font.color)
# Merge the text surface with sur # Merge the text surface with sur
sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h)) sur.blit((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, text: string, proc drawText*(sur: PSurface, p: TPoint, text: string,
bg: TColor, font = defaultFont) = bg: TColor, font = defaultFont) =
@ -171,8 +186,6 @@ proc drawText*(sur: PSurface, p: TPoint, text: string,
textSur.s = sdl_ttf.RenderTextShaded(font.f, text, font.color, toSdlColor(bg)) textSur.s = sdl_ttf.RenderTextShaded(font.f, text, font.color, toSdlColor(bg))
# Merge the text surface with sur # Merge the text surface with sur
sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h)) sur.blit((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) = proc drawCircle*(sur: PSurface, p: TPoint, r: Natural, color: TColor) =
## draws a circle with center `p` and radius `r` with the given color ## draws a circle with center `p` and radius `r` with the given color
@ -323,14 +336,10 @@ proc drawRect*(sur: PSurface, r: TRect, color: TColor) =
setPix(video, pitch, r.x + minW - 1, r.y + i, color) # Draw right side setPix(video, pitch, r.x + minW - 1, r.y + i, color) # Draw right side
proc fillRect*(sur: PSurface, r: TRect, col: TColor) = proc fillRect*(sur: PSurface, r: TRect, col: TColor) =
## draws and fills a rectangle. ## Fills a rectangle using sdl's ``FillRect`` function.
var video = cast[PPixels](sur.s.pixels) var rect = toSdlRect(r)
assert video != nil if sdl.FillRect(sur.s, addr(rect), sur.createSdlColor(col)) == -1:
var pitch = sur.s.pitch div ColSize raiseEGraphics()
for i in r.y..min(sur.s.h, r.y+r.height-1)-1:
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) = proc Plot4EllipsePoints(sur: PSurface, CX, CY, X, Y: Natural, col: TColor) =
var video = cast[PPixels](sur.s.pixels) var video = cast[PPixels](sur.s.pixels)
@ -450,7 +459,14 @@ proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: TColor) =
sur.plotAA(x.toFloat(), ipart(intery) + 1.0, fpart(intery), color) sur.plotAA(x.toFloat(), ipart(intery) + 1.0, fpart(intery), color)
intery = intery + gradient intery = intery + gradient
template withEvents(surf: PSurface, event: expr, actions: stmt): stmt = proc fillSurface*(sur: PSurface, color: TColor) =
## Fills the entire surface with ``color``.
if sdl.FillRect(sur.s, nil, sur.createSdlColor(color)) == -1:
raiseEGraphics()
template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt =
## Simple template which creates an event loop. ``Event`` is the name of the
## variable containing the TEvent object.
while True: while True:
var event: SDL.TEvent var event: SDL.TEvent
if SDL.PollEvent(addr(event)) == 1: if SDL.PollEvent(addr(event)) == 1:
@ -461,10 +477,9 @@ if sdl_ttf.Init() < 0: raiseEGraphics()
when isMainModule: when isMainModule:
var surf = newScreenSurface(800, 600) var surf = newScreenSurface(800, 600)
var r: TRect = (0, 0, 900, 900) surf.fillSurface(colWhite)
# Draw the shapes # Draw the shapes
surf.fillRect(r, colWhite)
surf.drawLineAA((100, 170), (400, 471), colTan) surf.drawLineAA((100, 170), (400, 471), colTan)
surf.drawLine((100, 170), (400, 471), colRed) surf.drawLine((100, 170), (400, 471), colRed)
@ -480,6 +495,8 @@ when isMainModule:
surf.drawVerLine(5, 60, 800, colRed) surf.drawVerLine(5, 60, 800, colRed)
surf.drawCircle((600, 500), 60, colRed) surf.drawCircle((600, 500), 60, colRed)
surf.fillRect((50, 50, 100, 100), colFuchsia)
#surf.drawText((300, 300), "TEST", colMidnightBlue) #surf.drawText((300, 300), "TEST", colMidnightBlue)
#var textSize = textBounds("TEST") #var textSize = textBounds("TEST")
#surf.drawText((300, 300 + textSize.height), $textSize.width & ", " & #surf.drawText((300, 300 + textSize.height), $textSize.width & ", " &
@ -488,33 +505,38 @@ when isMainModule:
var mouseStartX = 0 var mouseStartX = 0
var mouseStartY = 0 var mouseStartY = 0
withEvents(surf, event): withEvents(surf, event):
var eventp = addr(event)
case event.kind: case event.kind:
of SDL.QUITEV: of SDL.QUITEV:
break break
of SDL.KEYDOWN: of SDL.KEYDOWN:
if event.sym == SDL.K_LEFT: var evk = sdl.EvKeyboard(eventp)
echo(event.sym) if evk.keysym.sym == SDL.K_LEFT:
surf.drawHorLine(395, 300, 5, colPaleGoldenRod) surf.drawHorLine(395, 300, 50, colBlack)
echo("Drawing") echo("Drawing")
else: else:
echo(event.sym) echo(evk.keysym.sym)
of SDL.MOUSEBUTTONDOWN: of SDL.MOUSEBUTTONDOWN:
# button.x/y is F* UP! var mbd = sdl.EvMouseButton(eventp)
echo("MOUSEDOWN ", event.x) mouseStartX = mbd.x
mouseStartX = event.x mouseStartY = mbd.y
mouseStartY = event.y
of SDL.MOUSEBUTTONUP: of SDL.MOUSEBUTTONUP:
echo("MOUSEUP ", mouseStartX) var mbu = sdl.EvMouseButton(eventp)
if mouseStartX != 0 and mouseStartY != 0: if mouseStartX != 0 and mouseStartY != 0:
echo(mouseStartX, "->", int(event.x)) echo(mouseStartX, "x->", mbu.x)
echo(mouseStartY, "y->", mbu.y)
surf.drawLineAA((mouseStartX, MouseStartY), surf.drawLineAA((mouseStartX, MouseStartY),
(int(event.x), int(event.y)), colPaleGoldenRod) (int(mbu.x), int(mbu.y)), colRed)
mouseStartX = 0 mouseStartX = 0
mouseStartY = 0 mouseStartY = 0
of SDL.MouseMotion:
var mm = sdl.EvMouseMotion(eventp)
echo(mm.x, " ", mm.y, " ", mm.yrel)
else: else:
#echo(event.theType) #echo(event.kind)
SDL.UpdateRect(surf.s, int32(0), int32(0), int32(800), int32(600)) SDL.UpdateRect(surf.s, int32(0), int32(0), int32(800), int32(600))