1#include <assert.h>
2#include <stdio.h>
3#include "renwindow.h"
4
5#ifdef LITE_USE_SDL_RENDERER
6static int query_surface_scale(RenWindow *ren) {
7 int w_pixels, h_pixels;
8 int w_points, h_points;
9 SDL_GL_GetDrawableSize(ren->window, &w_pixels, &h_pixels);
10 SDL_GetWindowSize(ren->window, &w_points, &h_points);
11 /* We consider that the ratio pixel/point will always be an integer and
12 it is the same along the x and the y axis. */
13 assert(w_pixels % w_points == 0 && h_pixels % h_points == 0 && w_pixels / w_points == h_pixels / h_points);
14 return w_pixels / w_points;
15}
16
17static void setup_renderer(RenWindow *ren, int w, int h) {
18 /* Note that w and h here should always be in pixels and obtained from
19 a call to SDL_GL_GetDrawableSize(). */
20 if (!ren->renderer) {
21 ren->renderer = SDL_CreateRenderer(ren->window, -1, 0);
22 }
23 if (ren->texture) {
24 SDL_DestroyTexture(ren->texture);
25 }
26 ren->texture = SDL_CreateTexture(ren->renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_STREAMING, w, h);
27 ren->rensurface.scale = query_surface_scale(ren);
28}
29#endif
30
31
32void renwin_init_surface(UNUSED RenWindow *ren) {
33#ifdef LITE_USE_SDL_RENDERER
34 if (ren->rensurface.surface) {
35 SDL_FreeSurface(ren->rensurface.surface);
36 }
37 int w, h;
38 SDL_GL_GetDrawableSize(ren->window, &w, &h);
39 ren->rensurface.surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_BGRA32);
40 if (!ren->rensurface.surface) {
41 fprintf(stderr, "Error creating surface: %s", SDL_GetError());
42 exit(1);
43 }
44 setup_renderer(ren, w, h);
45#endif
46}
47
48
49static RenRect scaled_rect(const RenRect rect, const int scale) {
50 return (RenRect) {rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale};
51}
52
53
54void renwin_clip_to_surface(RenWindow *ren) {
55 SDL_SetClipRect(renwin_get_surface(ren).surface, NULL);
56}
57
58
59void renwin_set_clip_rect(RenWindow *ren, RenRect rect) {
60 RenSurface rs = renwin_get_surface(ren);
61 RenRect sr = scaled_rect(rect, rs.scale);
62 SDL_SetClipRect(rs.surface, &(SDL_Rect){.x = sr.x, .y = sr.y, .w = sr.width, .h = sr.height});
63}
64
65
66RenSurface renwin_get_surface(RenWindow *ren) {
67#ifdef LITE_USE_SDL_RENDERER
68 return ren->rensurface;
69#else
70 SDL_Surface *surface = SDL_GetWindowSurface(ren->window);
71 if (!surface) {
72 fprintf(stderr, "Error getting window surface: %s", SDL_GetError());
73 exit(1);
74 }
75 return (RenSurface){.surface = surface, .scale = 1};
76#endif
77}
78
79void renwin_resize_surface(UNUSED RenWindow *ren) {
80#ifdef LITE_USE_SDL_RENDERER
81 int new_w, new_h;
82 SDL_GL_GetDrawableSize(ren->window, &new_w, &new_h);
83 /* Note that (w, h) may differ from (new_w, new_h) on retina displays. */
84 if (new_w != ren->rensurface.surface->w || new_h != ren->rensurface.surface->h) {
85 renwin_init_surface(ren);
86 renwin_clip_to_surface(ren);
87 setup_renderer(ren, new_w, new_h);
88 }
89#endif
90}
91
92void renwin_show_window(RenWindow *ren) {
93 SDL_ShowWindow(ren->window);
94}
95
96void renwin_update_rects(RenWindow *ren, RenRect *rects, int count) {
97#ifdef LITE_USE_SDL_RENDERER
98 const int scale = ren->rensurface.scale;
99 for (int i = 0; i < count; i++) {
100 const RenRect *r = &rects[i];
101 const int x = scale * r->x, y = scale * r->y;
102 const int w = scale * r->width, h = scale * r->height;
103 const SDL_Rect sr = {.x = x, .y = y, .w = w, .h = h};
104 int32_t *pixels = ((int32_t *) ren->rensurface.surface->pixels) + x + ren->rensurface.surface->w * y;
105 SDL_UpdateTexture(ren->texture, &sr, pixels, ren->rensurface.surface->w * 4);
106 }
107 SDL_RenderCopy(ren->renderer, ren->texture, NULL, NULL);
108 SDL_RenderPresent(ren->renderer);
109#else
110 SDL_UpdateWindowSurfaceRects(ren->window, (SDL_Rect*) rects, count);
111#endif
112}
113
114void renwin_free(RenWindow *ren) {
115 SDL_DestroyWindow(ren->window);
116 ren->window = NULL;
117#ifdef LITE_USE_SDL_RENDERER
118 SDL_DestroyTexture(ren->texture);
119 SDL_DestroyRenderer(ren->renderer);
120 SDL_FreeSurface(ren->rensurface.surface);
121#endif
122}
123