ysbaddaden / sdl.cr

SDL2 bindings for Crystal
102 stars 32 forks source link

When debugging, Surface.pixels is not set #29

Open AresAndy opened 5 years ago

AresAndy commented 5 years ago

When debugging, Surface struct returned from window.surface.to_unsafe does not contain pixels, but property is clearly defined (at sdl/src/lib_sdl/surface.cr), therefore pixel read access is impossible

ysbaddaden commented 5 years ago

Please add some details or better, reproducible code. I gave no idea what you're doing and expecting...

AresAndy commented 5 years ago

Yes, sorry, I totally forgot to include any actual source code..

What I'm trying to do (surely in a unsafe, inefficient way, but I don't mind at the moment..) is to get the RGB values of a pixel at x,y coordinates. I looked around for quite a while, and stumbled on a piece of C code, that I roughly transliterated to crystal:

def get_pix_at(surf, x, y)
    # debugger
    LibSDL.lock_surface(surf)
    ll_surface = surf.surface
    bpp = ll_surface.format.value.bytesPerPixel
    pix = (ll_surface.pixels + y * ll_surface.pitch * bpp).as(UInt32*).value

    r  = 0_u8
    g  = 0_u8
    b  = 0_u8
    pr : UInt8* = pointerof(r)
    pg : UInt8* = pointerof(g) 
    pb : UInt8* = pointerof(b) 
    LibSDL.get_rgb(pix, ll_surface.format, pr, pg, pb)
    res = [pr.value, pg.value, pb.value]
    LibSDL.unlock_surface(surf)
    return res
end

This compiles with no warning whatsoever, does not crash when used, but the RGB array is constantly [0,0,0].. When debugging this function, ll_surface contains most of the property of its type, except for pixels. It's nice to see that rather than crashing for a bad pointer dereference it returns zero, but still.. If ll_surface is a LibSDL::Surface, one instance of it should contain pixels.. Right?

lib LibSDL
 # ...
  struct Surface
    flags : UInt32
    format : PixelFormat*
    w : Int
    h : Int
    pitch : Int
    pixels : Void*
    userdata : Void*
    locked : Int
    lock_data : Void*
    clip_rect : Rect
    map : Void* # BlitMap*
    refcount : Int
  end
# and so forth...
ysbaddaden commented 5 years ago

Have a look to http://lazyfoo.net/SDL_tutorials/lesson31/index.php

All samples are ports of Lazy Foo' tutorials, but I never went as far as reading a pixel color (lesson 31) and Surface#pixels is unavailable for the moment.

AresAndy commented 5 years ago

Oh, I see... Are there any plans/timelines to make Surface#pixels available? Or any workarounds? I'm doing a fun weekend project, but it could be interesting for newcomers to show how Crystal can be used outside from web development and library bindings design, in a practical manner.

ysbaddaden commented 5 years ago

You can reopen SDL::Surface:

class SDL::Surface
  def pixels
    surface.pixels
  end
end

Then you have a direct access to the underlying void* buffer of the surface, whose actual format depends on the surface format. For example:

def get_pixel(surface, x, y)
  buffer = surface.pixels.as(UInt32*) # <= assumes 32-bit depth!
  pixel = buffer + x + y * surface.width
  LibSDL.get_rgb(pixel.value, out r, out g, out b)
  {r, g, b}
end

window = SDL::Window.new(640, 480)
window.surface.fill(255, 0, 0)

p get_pixel(window.surface, 120, 240)
AresAndy commented 5 years ago

Hi, sorry to reply so lately, but I got stuck with other things..

I tried this piece of code, it has the problem that you're not passing a format parameter to LibSDL.get_rgb, but that can be fetched from the surface parameter. Anyhow, the final result of the function is alway {0,0,0}, no matter what kind of bit depth I use, no matter what the coordinates are. I feel like there is something missing in the library at this point

ysbaddaden commented 5 years ago

No problem for me on Linux. Is the surface really 32-bit?