I am trying to follow Casey Muratori's HandmadeHero video blog where he writes a game in C from scratch in order to learn Nim and also see how good it is for game development. I did a pretty straight conversion from c to nim here. Now I wanted to try and replace working with pointers and manual memory allocation with just using a sequence but as soon as I add another field to Win32OffscreenBuffer tuple of type seq[int32] i get this error:
win64_handmade.nim(86, 86) Error: type mismatch: got (proc (window: HWND, message: WINUINT, wparam: WPARAM, lparam: LPARAM): LRESULT{.stdcall, locks: 0.}) but expected 'WNDPROC'
I figured that this error is somehow caused by the fact that given WNDPROC accesses a global variable of type Win32OffscreenBuffer because the error disappears when I remove that line from the proc but I don't understand why is this happening and how can I solve it. Can someone help?
Maybe it's related to the Nim version, it compiles for me with Nim 0.13.0 with GCC on XP64. Though I disabled the block related to XInput, I don't have that module. Maybe locks: 0 in the signature causes mismatch, and maybe that's caused by using a global variable.
Compiles also with 0.10.3.
EDIT: Compiles with XInput too.
Thanks for checking this out. I also have Nim 0.13.0 64bit windows version and I still get this error. Just to be clear, on github the latest version contains this tuple:
type
Win32OffscreenBuffer = tuple
# Pixels are always 32 bits
info: BITMAPINFO
memory: pointer
width: int32
height: int32
pitch: int
And like this everything compiles. But if you add a new seq field like this:
type
Win32OffscreenBuffer = tuple
# Pixels are always 32 bits
info: BITMAPINFO
memory: pointer
width: int32
height: int32
pitch: int
mem: seq[int32]
You get that compile error.
I have also been trying to implement the HandmadeHero series using Nim. The reason why WNDCLASS was failing to initialize, is because it is required that it is gcsafe.
However, WNDCLASS needs to call MainWindowCallBack, and MainWindowCallBack accesses the Win32OffScreenBuffer type. The problem with this is that the Win32OffScreenBuffer type contains the seq[uint32] that you were going to use for the backbuffer, which means the compiler can't infer that MainWindowCallBack is gcsafe.
Reassuring the compiler by adding the {.gcsafe.} pragma to MainWindowCallBack allows it to compile (with warnings). From there, it isn't too hard to hook things up so that windows can use the seq[uint32] to blit to the screen.
In the end though, I'm not sure much is gained by using a seq instead of a raw pointer. The code doesn't feel much more idiomatic, and the memory footprint is a lot bigger. The draw speed is the same though.
There was also a small bug in the way you were casting your colour information to the pixels, this fixes it:
proc renderWeirdGradient(buffer: var Win32OffscreenBuffer, greenOffset: var int; blueOffset: var int) =
var row = cast[uint32](buffer.memory)
for y in 0 .. <buffer.height:
var pixel = row
for x in 0 .. <buffer.width:
cast[ptr uint32](pixel)[] = (uint32(uint8(greenOffset + y)) shl 8 or uint32(uint8(blueOffset + x)))
inc(pixel, 4)
inc(row, buffer.pitch)