Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Save a screenshot #7

Open
danisfast opened this issue Sep 16, 2023 · 6 comments
Open

Feature Request: Save a screenshot #7

danisfast opened this issue Sep 16, 2023 · 6 comments

Comments

@danisfast
Copy link

Hi! I'm really enjoying this library, thank you for writing it!

Do you know if there is any way to write the rendered output to disk?

Thanks so much

@let-def
Copy link
Owner

let-def commented Sep 18, 2023

If you want to save the rendered pixels, this can be done at the OpenGL level, for instance using glReadPixels.
When using SDL, the right function might be (I haven't tried) SDL_RenderReadPixels. Here is a related post from Stackoverflow: https://stackoverflow.com/questions/22315980/sdl2-c-taking-a-screenshot .

In theory, it should also be possible to save the image as a vector file (.svg or .pdf), but nothing as been done in this direction so far, that would be a lot of work.

@danisfast
Copy link
Author

Thanks, I will check this out!
It looks like that implementation path relies on an SDL.renderer, and I'm not sure how to access one of those when rendering with Wall. Do you recommend that I create a new one against my existing window, or is this an "I need a deeper understanding of SDL" situation?
Thanks again.

@let-def
Copy link
Owner

let-def commented Sep 20, 2023

Hi, @danisfast, sorry, my answer is incomplete and probably incorrect anyway, SDL_RenderReadPixels doesn't define what happens when an OpenGL context is used.

Your best bet might be to use glReadPixels directly, for instance through Daniel Buenzli's Tgls library. I will write an example when I have more time, not before this week-end.

@let-def
Copy link
Owner

let-def commented Sep 20, 2023

What happens is that Wall renders to an "OpenGL context", which is a global (or thread-local) object maintained by the OpenGL library. This context has a notion of "target" to render to, which is usually a (buffer to a) window surface (visible on screen), or an OpenGL texture.
Usually, the default target is setup by the windowing library. In Wall's examples it is SDL2. To retrieve the pixels, we have to ask one of these libraries (OpenGL or SDL), and in this case it seems the proper way is to ask OpenGL directly.

@danisfast
Copy link
Author

@let-def thanks for the explanation, this is super helpful. I'll check out glReadPixels and update this thread if I happen to end up with some code.

@danisfast
Copy link
Author

For future readers, here is the code that I used to save a bitmap of a Wall render target. Thanks again @let-def for the advice!

open Tsdl

let screenshot (win : Sdl.window) (name : string) =
  let ok r =
    match r with Result.Ok v -> v | Result.Error (`Msg e) -> failwith e
  in
  let rmask = Int32.of_int 0xff000000 in
  let gmask = Int32.of_int 0x00ff0000 in
  let bmask = Int32.of_int 0x0000ff00 in
  let amask = Int32.of_int 0x000000ff in
  let depth = 32 in
  let w, h = Sdl.get_window_size win in
  let pitch = w * 4 in
  let total = pitch * h in
  let buffer =
    Bigarray.Array1.create Bigarray.int8_unsigned Bigarray.c_layout total
  in
  Tgl4.Gl.read_buffer Tgl4.Gl.back;
  Tgl4.Gl.read_pixels 0 0 w h Tgl4.Gl.rgba Tgl4.Gl.unsigned_byte (`Data buffer);
  let s0 =
    ok
      (Sdl.create_rgb_surface_from buffer ~w ~h ~depth ~pitch rmask gmask bmask
         amask )
  in
  (* The rendered target is upside down, this flips it right side up *)
  let s1 = ok (Sdl.create_rgb_surface ~w ~h ~depth rmask gmask bmask amask) in
  List.init (h - 1) succ
  |> List.iter (fun y ->
         let src_rect = Sdl.Rect.create ~x:0 ~y ~w ~h:1 in
         let dst_rect = Sdl.Rect.create ~x:0 ~y:(h - 1 - y) ~w ~h:1 in
         ok (Sdl.blit_surface ~src:s0 (Some src_rect) ~dst:s1 (Some dst_rect)) );
  ok (Sdl.save_bmp s1 name);
  Sdl.free_surface s0;
  Sdl.free_surface s1;
  ()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants