initial commit
This commit is contained in:
50
geo2d.nim
Normal file
50
geo2d.nim
Normal file
@@ -0,0 +1,50 @@
|
||||
import mmath/smatrix
|
||||
import mmath/svector
|
||||
from nwo/utils import `...`
|
||||
from math import sin, cos
|
||||
|
||||
type
|
||||
X2d* = SquareSMatrix[3, float32]
|
||||
P2d* = SVector[3, float32]
|
||||
Rect2d* = object
|
||||
tl*, br* : P2d
|
||||
|
||||
proc newP2d*(x, y : float32) : P2d =
|
||||
P2d(buildSVector[3, float32](x,y,1f32))
|
||||
|
||||
proc x*(p : P2d) : float32 = p[0]
|
||||
proc y*(p : P2d) : float32 = p[1]
|
||||
|
||||
proc newRect2d*(x, y, width, height : float32) : Rect2d = Rect2d(tl: newP2d(x,y), br: newP2d(x + width, y + height))
|
||||
proc top*(rect : Rect2d) : float32 = rect.tl.y
|
||||
proc bottom*(rect : Rect2d) : float32 = rect.br.y
|
||||
proc left*(rect : Rect2d) : float32 = rect.tl.x
|
||||
proc right*(rect : Rect2d) : float32 = rect.br.x
|
||||
proc width*(rect : Rect2d) : float32 = rect.br.x - rect.tl.x
|
||||
proc height*(rect : Rect2d) : float32 = rect.br.y - rect.tl.y
|
||||
proc `*`*(rect : Rect2d, xform : X2d) : Rect2d = Rect2d(tl: rect.tl * xform, br: rect.br * xform)
|
||||
|
||||
proc rot*(alpha: float32) : X2d =
|
||||
result = identity[3,float32]()
|
||||
let ca = cos(alpha)
|
||||
let sa = sin(alpha)
|
||||
result[0,0] = ca
|
||||
result[1,1] = ca
|
||||
result[0,1] = sa
|
||||
result[1,0] = -sa
|
||||
|
||||
proc scale*(x, y: float32) : X2d =
|
||||
result = identity[3,float32]()
|
||||
result[0,0] = x
|
||||
result[1,1] = y
|
||||
|
||||
proc xlate*(x, y: float32) : X2d =
|
||||
result = identity[3,float32]()
|
||||
result[2,0] = x
|
||||
result[2,1] = y
|
||||
|
||||
proc scale*(center : P2d, x, y : float32) : X2d = xlate(-center.x, -center.y) * scale(x,y) * xlate(center.x, center.y)
|
||||
proc rot*(center : P2d, angle : float32) : X2d = xlate(-center.x, -center.y) * rot(angle) * xlate(center.x, center.y)
|
||||
|
||||
|
||||
|
73
grid.nim
Normal file
73
grid.nim
Normal file
@@ -0,0 +1,73 @@
|
||||
import random
|
||||
from times import epochTime
|
||||
type Grid* = object
|
||||
rows*, columns* : uint32
|
||||
data : seq[uint32]
|
||||
|
||||
proc newGrid*(rows, columns : uint32) : Grid =
|
||||
Grid(
|
||||
rows: rows,
|
||||
columns: columns,
|
||||
data: newSeq[uint32]((rows * columns + 8 - 1) div 8)
|
||||
)
|
||||
|
||||
proc get(grid : Grid, x, y : uint32) : bool =
|
||||
assert x < grid.columns
|
||||
assert y < grid.rows
|
||||
let index = y * grid.columns + x
|
||||
(grid.data[index div 8] and (1u32 shl (index mod 8))) != 0
|
||||
|
||||
proc set(grid : var Grid, x, y : uint32, value : bool) : void =
|
||||
assert x < grid.columns
|
||||
assert y < grid.rows
|
||||
let index = y * grid.columns + x
|
||||
grid.data[(index div 8)] =
|
||||
if value:
|
||||
grid.data[(index div 8)] or (1u32 shl (index mod 8))
|
||||
else:
|
||||
grid.data[(index div 8)] and (not (1u32 shl (index mod 8)))
|
||||
|
||||
template `[]`*(grid : Grid, x,y : uint32) : bool =
|
||||
get(grid, x, y)
|
||||
|
||||
template `[]=`*(grid : Grid, x,y : uint32, value : bool) =
|
||||
set(grid, x, y, value)
|
||||
|
||||
proc next_step*(old_grid, new_grid : var Grid) =
|
||||
for x in 0..<old_grid.columns:
|
||||
for y in 0..<old_grid.rows:
|
||||
var alive_neighbours = 0
|
||||
if old_grid[(x+1) mod old_grid.columns, y]:
|
||||
alive_neighbours += 1
|
||||
if old_grid[(x+1) mod old_grid.columns, (y+1) mod old_grid.rows]:
|
||||
alive_neighbours += 1
|
||||
if old_grid[(x+1) mod old_grid.columns, (y-1) mod old_grid.rows]:
|
||||
alive_neighbours += 1
|
||||
if old_grid[(x-1) mod old_grid.columns, y]:
|
||||
alive_neighbours += 1
|
||||
if old_grid[(x-1) mod old_grid.columns, (y + 1) mod old_grid.rows]:
|
||||
alive_neighbours += 1
|
||||
if old_grid[(x-1) mod old_grid.columns, (y - 1) mod old_grid.rows]:
|
||||
alive_neighbours += 1
|
||||
if old_grid[x mod old_grid.columns, (y + 1) mod old_grid.rows]:
|
||||
alive_neighbours += 1
|
||||
if old_grid[x mod old_grid.columns, (y - 1) mod old_grid.rows]:
|
||||
alive_neighbours += 1
|
||||
|
||||
if old_grid[x, y]:
|
||||
if alive_neighbours < 2 or alive_neighbours > 3:
|
||||
new_grid[x, y] = false
|
||||
else:
|
||||
new_grid[x, y] = true
|
||||
elif alive_neighbours == 3:
|
||||
new_grid[x, y] = true
|
||||
else:
|
||||
new_grid[x, y] = false
|
||||
|
||||
proc rand_init*(grid : var Grid) =
|
||||
var rand = initRand(epochTime().int64)
|
||||
for x in 0..<grid.columns:
|
||||
for y in 0..<grid.rows:
|
||||
grid[x, y] = (rand.next() mod 2) != 0
|
||||
|
||||
|
132
main.nim
Normal file
132
main.nim
Normal file
@@ -0,0 +1,132 @@
|
||||
include options
|
||||
import sdl2, sdl2/gfx
|
||||
import grid
|
||||
import geo2d
|
||||
import mmath/smatrix
|
||||
import mmath/svector
|
||||
from nwo/utils import box
|
||||
|
||||
discard sdl2.init(INIT_EVERYTHING)
|
||||
|
||||
proc drawLine(renderer : RendererPtr, p0, p1 : P2d) = renderer.drawLine(p0.x.cint, p0.y.cint, p1.x.cint, p1.y.cint)
|
||||
proc fillRect(renderer : RendererPtr, rect : Rect2d) =
|
||||
var rect : Rect = (rect.left.cint, rect.top.cint, rect.width.cint, rect.height.cint)
|
||||
renderer.fillRect(addr(rect))
|
||||
|
||||
var
|
||||
window: WindowPtr
|
||||
render: RendererPtr
|
||||
|
||||
window = createWindow("Game of Life in SDL",
|
||||
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||
640, 480,
|
||||
SDL_WINDOW_SHOWN or SDL_WINDOW_RESIZABLE)
|
||||
render = createRenderer(window, -1, Renderer_Accelerated or Renderer_PresentVsync or Renderer_TargetTexture)
|
||||
|
||||
var
|
||||
evt = sdl2.defaultEvent
|
||||
quit = false
|
||||
freeze = true
|
||||
fpsman: FpsManager
|
||||
fpsman.init
|
||||
|
||||
let side : uint32 = 5
|
||||
let
|
||||
pixelx = 200u32
|
||||
pixely = 200u32
|
||||
|
||||
var
|
||||
current_grid, next_grid : ref[Grid]
|
||||
block:
|
||||
var grid = newGrid(pixelx, pixely)
|
||||
grid.rand_init()
|
||||
current_grid = box(grid)
|
||||
next_grid = box(grid)
|
||||
|
||||
let bb = newRect2d(0f32, 0f32, float32(side * pixelx), float32(side * pixely))
|
||||
let step = 3
|
||||
var elapsed_time_sec = 0
|
||||
var
|
||||
uxform : X2d = identity[3, float32]()
|
||||
pan_start : Option[P2d] = none[P2d]()
|
||||
|
||||
while not quit:
|
||||
let windowSize = block:
|
||||
var w, h : cint
|
||||
window.getSize(w, h)
|
||||
Rect2d(tl: newP2d(0f32, 0f32), br: newP2d(w.float32, h.float32))
|
||||
while pollEvent(evt):
|
||||
case evt.kind:
|
||||
of QuitEvent:
|
||||
quit = true
|
||||
break
|
||||
of KeyDown:
|
||||
let keyboardEvent = cast[KeyboardEventPtr](addr(evt))
|
||||
case keyboardEvent.keysym.sym.char:
|
||||
of ' ':
|
||||
freeze = not freeze
|
||||
of 'h':
|
||||
uxform = identity[3, float32]()
|
||||
else:
|
||||
discard
|
||||
of MouseButtonDown:
|
||||
let mouseButtonDownEvent = cast[MouseButtonEventPtr](addr(evt))
|
||||
if mouseButtonDownEvent.which == BUTTON_RIGHT:
|
||||
pan_start = some(newP2d(mouseButtonDownEvent.x.float32, mouseButtonDownEvent.y.float32))
|
||||
of MouseButtonUp:
|
||||
let mouseButtonDownEvent = cast[MouseButtonEventPtr](addr(evt))
|
||||
if mouseButtonDownEvent.which == BUTTON_RIGHT and pan_start.isSome():
|
||||
let xlation = newP2d(mouseButtonDownEvent.x.float32, mouseButtonDownEvent.y.float32) - pan_start.get()
|
||||
pan_start = none[P2d]()
|
||||
uxform = uxform * xlate(xlation.x, xlation.y)
|
||||
of MouseWheel:
|
||||
let mouseWheelEvent = cast[MouseWheelEventPtr](addr(evt))
|
||||
if mouseWheelEvent.y > 0:
|
||||
uxform = uxform * scale(newP2d(windowSize.width.float32 / 2f32, windowSize.height.float32 / 2f32), 1.1f32, 1.1f32)
|
||||
else:
|
||||
uxform = uxform * scale(newP2d(windowSize.width.float32 / 2f32, windowSize.height.float32 / 2f32), 0.9f32, 0.9f32)
|
||||
of MouseMotion:
|
||||
let mouseMotionEvent = cast[MouseMotionEventPtr](addr(evt))
|
||||
let position = newP2d(mouseMotionEvent.x.float32, mouseMotionEvent.y.float32)
|
||||
|
||||
else:
|
||||
discard
|
||||
|
||||
let dt = fpsman.getFramerate() / 1000
|
||||
|
||||
render.setDrawColor 0,0,0,255
|
||||
render.clear
|
||||
var
|
||||
x : float32 = bb.left
|
||||
y : float32 = bb.top
|
||||
|
||||
render.setDrawColor 127,127,127,255
|
||||
let f = min(windowSize.width / bb.width, windowSize.height / bb.height)
|
||||
let xform = xlate(-bb.width / 2.0f32, -bb.height / 2.0f32) * scale(f, f) *
|
||||
xlate(windowSize.width / 2.0f32, windowSize.height / 2.0f32) * uxform
|
||||
|
||||
while x <= bb.width:
|
||||
render.drawLine(newP2d(x, bb.top) * xform, newP2d(x, bb.height) * xform)
|
||||
x += side.float32
|
||||
|
||||
while y <= bb.height:
|
||||
render.drawLine(newP2d(bb.left, y) * xform, newP2d(bb.width, y) * xform)
|
||||
y += side.float32
|
||||
|
||||
render.setDrawColor 255,255,255,255
|
||||
for i in 0..<current_grid.columns:
|
||||
for j in 0..<current_grid.rows:
|
||||
if current_grid[][i, j]:
|
||||
render.fillRect(newRect2d((i * side).float32, (j * side).float32, side.float32, side.float32) * xform)
|
||||
render.present
|
||||
fpsman.delay
|
||||
let current_time_sec = fpsman.getFramecount() div step
|
||||
if not freeze and current_time_sec > elapsed_time_sec:
|
||||
elapsed_time_sec = current_time_sec
|
||||
next_step(current_grid[], next_grid[])
|
||||
let tmp = current_grid
|
||||
current_grid = next_grid
|
||||
next_grid = tmp
|
||||
|
||||
destroy render
|
||||
destroy window
|
Reference in New Issue
Block a user