Howdy ho nimorinos,
I've been wrapping sdl-gpu , and it's been going pretty well considering I'm a novice programmer with no experience in C and just bit in nim, but I've run into a snag. To access the dimensions of images in sdl-gpu, you call image->w and image->h. I've tried wrapping this as follows:
type
target* = object
ptrTarget* = ptr target
image* = object #prototype for this is available at https://grimfang4.github.io/sdl-gpu/structGPU__Image.html if that's helpful
data*: pointer
w*, h*: uint16
ptrImage* = ptr image
{.push dynlib: "libSDL2_gpu.so".}
proc init*(w, h: uint16, sdlFlags: uint32): ptrTarget {.importc: "GPU_Init".}
proc loadImage*(fileName: cstring): ptrImage {.importc: "GPU_LoadImage".}
{.pop.}
let window = init(800, 600, 0)
var img = loadImage("blah.png")
echo "width: ", img.w, " height: ", img.h #if I'm reading the nim manual right img.w == img[].w
Every time I run this code I get what appear to be random integers for width and height. If I run it on multiple images, every image reports the same dimensions.
Not sure if I'm just doing something wrong or there's something else at work here. Any ideas? Thanks.
You likely need to importc the fields...
type
target* = object
ptrTarget* = ptr target
image* = object #prototype for this is available at https://grimfang4.github.io/sdl-gpu/structGPU__Image.html if that's helpful
data* {.importc.}: pointer
w* {.importc.}: uint16
h* {.importc.}: uint16
ptrImage* = ptr image
That said, if you're wrapping a library like this the best thing to do is to use c2nim on the header file
Btw, convention is uppercase first letter for type names, and no prefix/suffix for the most common type. You should rename image to ImageObj and ptrImage to Image etc.
OK, so I got a c2nim version working. Strangely, instead of a random integer or the correct value img.w/h is now returning 0. Only obvious difference between its implementation and mine is that it used the bycopy pragma on the Image type, but there must be something else going on. Not sure what accounts for the difference.
ETA: Fortunately I can pull the width and height from the underlying SDL surface data, so I'm gonna give up on solving this for now.
the complete struct of GPU_Image is this:
typedef struct GPU_Image
{
struct GPU_Renderer* renderer;
GPU_Target* context_target;
GPU_Target* target;
Uint16 w, h;
GPU_bool using_virtual_resolution;
GPU_FormatEnum format;
int num_layers;
int bytes_per_pixel;
Uint16 base_w, base_h;
Uint16 texture_w, texture_h;
GPU_bool has_mipmaps;
float anchor_x;
float anchor_y;
SDL_Color color;
GPU_bool use_blending;
GPU_BlendMode blend_mode;
GPU_FilterEnum filter_mode;
GPU_SnapEnum snap_mode;
GPU_WrapEnum wrap_mode_x;
GPU_WrapEnum wrap_mode_y;
void* data;
int refcount;
GPU_bool is_alias;
} GPU_Image;
it is true you don't have to write all of them in Nim if you only need to access the width and height, but you also cannot ignore fields that came before width and height.
this is minimal fields you need to write in Nim if you only need to access the width and height:
type
image* = object
renderer: pointer
context_target: pointer
target: pointer
w*, h*: uint16
ptrImage* = ptr image
Nim's object has strong relationship with C struct, so it works like C struct, not like javascript or python object if your target compilation is C
if you also need to access the data field, but you don't want to write all of the fields between w,h and data, you need to calculate the byte size and their padding and then insert a dummy field with appropiate size, for example:
type
image = object
before: array[3, pointer]
w, h: uint16
between: array[???, char] # you calculate the ??? yourself
data: pointer
but it doesn't hurt to translate all of them to Nim, and you can avoid trouble because of C compiler differences
If you don't need all the fields of your struct, you may just delegate field resolution to the C code
type
image* {.importc: "GPU_Image", header: "<SDL_gpu.h>", incompleteStruct.} = object
data*: pointer
w*, h*: uint16
but this approach requires C headers available.