1 #include "platform/screen.h"
2 
3 #include "city/view.h"
4 #include "core/calc.h"
5 #include "core/config.h"
6 #include "game/settings.h"
7 #include "game/system.h"
8 #include "graphics/graphics.h"
9 #include "graphics/menu.h"
10 #include "graphics/screen.h"
11 #include "input/cursor.h"
12 #include "platform/android/android.h"
13 #include "platform/cursor.h"
14 #include "platform/haiku/haiku.h"
15 #include "platform/icon.h"
16 #include "platform/switch/switch.h"
17 #include "platform/vita/vita.h"
18 
19 #include "SDL.h"
20 
21 #include <stdlib.h>
22 
23 static struct {
24     SDL_Window *window;
25     SDL_Renderer *renderer;
26     SDL_Texture *texture_ui;
27     SDL_Texture *texture_city;
28     SDL_Texture *cursors[CURSOR_MAX];
29 } SDL;
30 
31 static struct {
32     struct {
33         SDL_Rect offset;
34         SDL_Rect renderer;
35     } position;
36     struct {
37         int width;
38         int height;
39     } max_size;
40 } city_texture;
41 
42 static struct {
43     int x;
44     int y;
45     int centered;
46 } window_pos = {0, 0, 1};
47 
48 static struct {
49     const int WIDTH;
50     const int HEIGHT;
51 } MINIMUM = {640, 480};
52 
53 static int scale_percentage = 100;
54 static color_t *framebuffer_ui;
55 static color_t *framebuffer_city;
56 
scale_logical_to_pixels(int logical_value)57 static int scale_logical_to_pixels(int logical_value)
58 {
59     return logical_value * scale_percentage / 100;
60 }
61 
scale_pixels_to_logical(int pixel_value)62 static int scale_pixels_to_logical(int pixel_value)
63 {
64     return pixel_value * 100 / scale_percentage;
65 }
66 
get_max_scale_percentage(int pixel_width,int pixel_height)67 static int get_max_scale_percentage(int pixel_width, int pixel_height)
68 {
69     int width_scale_pct = pixel_width * 100 / MINIMUM.WIDTH;
70     int height_scale_pct = pixel_height * 100 / MINIMUM.HEIGHT;
71     return SDL_min(width_scale_pct, height_scale_pct);
72 }
73 
set_scale_percentage(int new_scale,int pixel_width,int pixel_height)74 static void set_scale_percentage(int new_scale, int pixel_width, int pixel_height)
75 {
76 #ifdef __vita__
77     scale_percentage = 100;
78 #else
79     scale_percentage = calc_bound(new_scale, 50, 500);
80 #endif
81 
82     if (!pixel_width || !pixel_height) {
83         return;
84     }
85 
86     int max_scale_pct = get_max_scale_percentage(pixel_width, pixel_height);
87     if (max_scale_pct < scale_percentage) {
88         scale_percentage = max_scale_pct;
89         SDL_Log("Maximum scale of %i applied", scale_percentage);
90     }
91 
92     SDL_SetWindowMinimumSize(SDL.window,
93         scale_logical_to_pixels(MINIMUM.WIDTH), scale_logical_to_pixels(MINIMUM.HEIGHT));
94 
95     const char *scale_quality = "linear";
96 #ifndef __APPLE__
97     // Scale using nearest neighbour when we scale a multiple of 100%: makes it look sharper.
98     // But not on MacOS: users are used to the linear interpolation since that's what Apple also does.
99     if (scale_percentage % 100 == 0) {
100         scale_quality = "nearest";
101     }
102 #endif
103     SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, scale_quality);
104 }
105 
106 #ifdef __ANDROID__
set_scale_for_screen(int pixel_width,int pixel_height)107 static void set_scale_for_screen(int pixel_width, int pixel_height)
108 {
109     set_scale_percentage(android_get_screen_density() * 100, pixel_width, pixel_height);
110     config_set(CONFIG_SCREEN_CURSOR_SCALE, scale_percentage);
111     if (SDL.texture_ui) {
112         system_init_cursors(scale_percentage);
113     }
114     SDL_Log("Auto-setting scale to %i", scale_percentage);
115 }
116 #endif
117 
platform_screen_get_scale(void)118 int platform_screen_get_scale(void)
119 {
120     return scale_percentage;
121 }
122 
platform_screen_get_scaled_params(int * width,int * height)123 void platform_screen_get_scaled_params(int *width, int *height)
124 {
125     int fullscreen = setting_fullscreen();
126     if (fullscreen == 1) {
127         SDL_DisplayMode mode;
128         SDL_GetDesktopDisplayMode(SDL_GetWindowDisplayIndex(SDL.window), &mode);
129         *width = mode.w;
130         *height = mode.h;
131     } else {
132         setting_window(width, height);
133     }
134 }
135 
136 #if !defined(_WIN32) && !defined(__APPLE__)
set_window_icon(void)137 static void set_window_icon(void)
138 {
139     SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(platform_icon_get_pixels(), 16, 16, 32, 16 * 4,
140         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
141     if (!surface) {
142         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create surface for icon. Reason: %s", SDL_GetError());
143     }
144     SDL_SetWindowIcon(SDL.window, surface);
145     SDL_FreeSurface(surface);
146 }
147 #endif
148 
platform_screen_create(const char * title,int display_scale_percentage)149 int platform_screen_create(const char *title, int display_scale_percentage)
150 {
151     set_scale_percentage(display_scale_percentage, 0, 0);
152 
153     int width, height;
154     int fullscreen = system_is_fullscreen_only() ? 1 : setting_fullscreen();
155     if (fullscreen) {
156         SDL_DisplayMode mode;
157         SDL_GetDesktopDisplayMode(0, &mode);
158         width = mode.w;
159         height = mode.h;
160     } else {
161         setting_window(&width, &height);
162         width = scale_logical_to_pixels(width);
163         height = scale_logical_to_pixels(height);
164     }
165 
166     platform_screen_destroy();
167 
168 #ifdef __ANDROID__
169     // Fix for wrong colors on some android devices
170     SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
171     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
172     SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
173 #endif
174 
175     SDL_Log("Creating screen %d x %d, %s, driver: %s", width, height,
176         fullscreen ? "fullscreen" : "windowed", SDL_GetCurrentVideoDriver());
177     Uint32 flags = SDL_WINDOW_RESIZABLE;
178 
179 #if SDL_VERSION_ATLEAST(2, 0, 1)
180     flags |= SDL_WINDOW_ALLOW_HIGHDPI;
181 #endif
182 
183     if (fullscreen) {
184         flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
185     }
186 
187     SDL.window = SDL_CreateWindow(title,
188         SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
189         width, height, flags);
190 
191     if (!SDL.window) {
192         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create window: %s", SDL_GetError());
193         return 0;
194     }
195 
196 #if !defined(_WIN32) && !defined (__APPLE__)
197     // Windows and mac don't need setting a window icon. In fact the icon gets blurry if we do
198     set_window_icon();
199 #endif
200 
201     if (system_is_fullscreen_only()) {
202         SDL_GetWindowSize(SDL.window, &width, &height);
203     }
204 
205     SDL_Log("Creating renderer");
206     SDL.renderer = SDL_CreateRenderer(SDL.window, -1, SDL_RENDERER_PRESENTVSYNC);
207     if (!SDL.renderer) {
208         SDL_Log("Unable to create renderer, trying software renderer: %s", SDL_GetError());
209         SDL.renderer = SDL_CreateRenderer(SDL.window, -1, SDL_RENDERER_SOFTWARE);
210         if (!SDL.renderer) {
211             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create renderer: %s", SDL_GetError());
212             return 0;
213         }
214     }
215 
216     SDL_RendererInfo info;
217     SDL_GetRendererInfo(SDL.renderer, &info);
218     city_texture.max_size.width = info.max_texture_width;
219     city_texture.max_size.height = info.max_texture_height;
220 
221 #if !defined(__APPLE__)
222     if (fullscreen && SDL_GetNumVideoDisplays() > 1) {
223         SDL_SetWindowGrab(SDL.window, SDL_TRUE);
224     }
225 #endif
226     SDL_SetRenderDrawColor(SDL.renderer, 0, 0, 0, 0xff);
227     set_scale_percentage(display_scale_percentage, width, height);
228     return platform_screen_resize(width, height, 1);
229 }
230 
destroy_screen_textures(void)231 static void destroy_screen_textures(void)
232 {
233     if (SDL.texture_city) {
234         SDL_DestroyTexture(SDL.texture_city);
235         SDL.texture_city = 0;
236     }
237     if (SDL.texture_ui) {
238         SDL_DestroyTexture(SDL.texture_ui);
239         SDL.texture_ui = 0;
240     }
241 }
242 
create_textures(int width,int height)243 static int create_textures(int width, int height)
244 {
245     destroy_screen_textures();
246 
247     SDL.texture_ui = SDL_CreateTexture(SDL.renderer,
248         SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING,
249         width, height);
250 
251     int city_texture_error;
252 
253     if (config_get(CONFIG_UI_ZOOM)) {
254         int max_zoom = system_get_max_zoom(width, height);
255         SDL.texture_city = SDL_CreateTexture(SDL.renderer,
256             SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING,
257             calc_adjust_with_percentage(width, max_zoom), calc_adjust_with_percentage(height, max_zoom));
258         city_texture.position.renderer.x = 0;
259         city_texture.position.renderer.y = TOP_MENU_HEIGHT;
260         city_texture.position.renderer.h = height - TOP_MENU_HEIGHT;
261         SDL_SetTextureBlendMode(SDL.texture_ui, SDL_BLENDMODE_BLEND);
262         city_texture_error = SDL.texture_city == 0;
263     } else {
264         city_texture_error = 0;
265         SDL_SetTextureBlendMode(SDL.texture_ui, SDL_BLENDMODE_NONE);
266     }
267 
268     if (SDL.texture_ui) {
269         if (city_texture_error) {
270             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create city texture, zoom will be disabled: %s", SDL_GetError());
271             SDL_SetTextureBlendMode(SDL.texture_ui, SDL_BLENDMODE_NONE);
272             config_set(CONFIG_UI_ZOOM, 0);
273             return -1;
274         } else {
275             SDL_Log("Textures created (%d x %d)", width, height);
276         }
277         return 1;
278     } else {
279         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create textures: %s", SDL_GetError());
280         return 0;
281     }
282 }
283 
platform_screen_destroy(void)284 void platform_screen_destroy(void)
285 {
286     destroy_screen_textures();
287     if (SDL.renderer) {
288         SDL_DestroyRenderer(SDL.renderer);
289         SDL.renderer = 0;
290     }
291     if (SDL.window) {
292         SDL_DestroyWindow(SDL.window);
293         SDL.window = 0;
294     }
295 }
296 
platform_screen_resize(int pixel_width,int pixel_height,int save)297 int platform_screen_resize(int pixel_width, int pixel_height, int save)
298 {
299 #ifdef __ANDROID__
300     set_scale_for_screen(pixel_width, pixel_height);
301 #endif
302 
303     int logical_width = scale_pixels_to_logical(pixel_width);
304     int logical_height = scale_pixels_to_logical(pixel_height);
305 
306     if (save) {
307         setting_set_display(setting_fullscreen(), logical_width, logical_height);
308     }
309 
310     SDL_RenderSetLogicalSize(SDL.renderer, logical_width, logical_height);
311 
312     if (create_textures(logical_width, logical_height)) {
313         screen_set_resolution(logical_width, logical_height);
314         return 1;
315     } else {
316         return 0;
317     }
318 }
319 
system_scale_display(int display_scale_percentage)320 int system_scale_display(int display_scale_percentage)
321 {
322     int width, height;
323     SDL_GetWindowSize(SDL.window, &width, &height);
324     set_scale_percentage(display_scale_percentage, width, height);
325     platform_screen_resize(width, height, 1);
326     return scale_percentage;
327 }
328 
system_get_max_display_scale(void)329 int system_get_max_display_scale(void)
330 {
331     int width, height;
332     SDL_GetWindowSize(SDL.window, &width, &height);
333     return get_max_scale_percentage(width, height);
334 }
335 
platform_screen_move(int x,int y)336 void platform_screen_move(int x, int y)
337 {
338     if (!setting_fullscreen()) {
339         window_pos.x = x;
340         window_pos.y = y;
341         window_pos.centered = 0;
342     }
343 }
344 
platform_screen_set_fullscreen(void)345 void platform_screen_set_fullscreen(void)
346 {
347     SDL_GetWindowPosition(SDL.window, &window_pos.x, &window_pos.y);
348     int display = SDL_GetWindowDisplayIndex(SDL.window);
349     SDL_DisplayMode mode;
350     SDL_GetDesktopDisplayMode(display, &mode);
351     SDL_Log("User to fullscreen %d x %d on display %d", mode.w, mode.h, display);
352     if (0 != SDL_SetWindowFullscreen(SDL.window, SDL_WINDOW_FULLSCREEN_DESKTOP)) {
353         SDL_Log("Unable to enter fullscreen: %s", SDL_GetError());
354         return;
355     }
356     SDL_SetWindowDisplayMode(SDL.window, &mode);
357 
358 #if !defined(__APPLE__)
359     if (SDL_GetNumVideoDisplays() > 1) {
360         SDL_SetWindowGrab(SDL.window, SDL_TRUE);
361     }
362 #endif
363     setting_set_display(1, mode.w, mode.h);
364 }
365 
platform_screen_set_windowed(void)366 void platform_screen_set_windowed(void)
367 {
368     if (system_is_fullscreen_only()) {
369         return;
370     }
371     int logical_width, logical_height;
372     setting_window(&logical_width, &logical_height);
373     int pixel_width = scale_logical_to_pixels(logical_width);
374     int pixel_height = scale_logical_to_pixels(logical_height);
375     int display = SDL_GetWindowDisplayIndex(SDL.window);
376     SDL_Log("User to windowed %d x %d on display %d", pixel_width, pixel_height, display);
377     SDL_SetWindowFullscreen(SDL.window, 0);
378     SDL_SetWindowSize(SDL.window, pixel_width, pixel_height);
379     if (window_pos.centered) {
380         platform_screen_center_window();
381     }
382     if (SDL_GetWindowGrab(SDL.window) == SDL_TRUE) {
383         SDL_SetWindowGrab(SDL.window, SDL_FALSE);
384     }
385     setting_set_display(0, pixel_width, pixel_height);
386 }
387 
platform_screen_set_window_size(int logical_width,int logical_height)388 void platform_screen_set_window_size(int logical_width, int logical_height)
389 {
390     if (system_is_fullscreen_only()) {
391         return;
392     }
393     int pixel_width = scale_logical_to_pixels(logical_width);
394     int pixel_height = scale_logical_to_pixels(logical_height);
395     int display = SDL_GetWindowDisplayIndex(SDL.window);
396     if (setting_fullscreen()) {
397         SDL_SetWindowFullscreen(SDL.window, 0);
398     } else {
399         SDL_GetWindowPosition(SDL.window, &window_pos.x, &window_pos.y);
400     }
401     if (SDL_GetWindowFlags(SDL.window) & SDL_WINDOW_MAXIMIZED) {
402         SDL_RestoreWindow(SDL.window);
403     }
404     SDL_SetWindowSize(SDL.window, pixel_width, pixel_height);
405     if (window_pos.centered) {
406         platform_screen_center_window();
407     }
408     SDL_Log("User resize to %d x %d on display %d", pixel_width, pixel_height, display);
409     if (SDL_GetWindowGrab(SDL.window) == SDL_TRUE) {
410         SDL_SetWindowGrab(SDL.window, SDL_FALSE);
411     }
412     setting_set_display(0, pixel_width, pixel_height);
413 }
414 
platform_screen_center_window(void)415 void platform_screen_center_window(void)
416 {
417     int display = SDL_GetWindowDisplayIndex(SDL.window);
418     SDL_SetWindowPosition(SDL.window,
419         SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display));
420     window_pos.centered = 1;
421 }
422 
423 #ifdef PLATFORM_USE_SOFTWARE_CURSOR
draw_software_mouse_cursor(void)424 static void draw_software_mouse_cursor(void)
425 {
426     const mouse *mouse = mouse_get();
427     if (!mouse->is_touch) {
428         cursor_shape current_cursor_shape = platform_cursor_get_current_shape();
429         const cursor *c = input_cursor_data(current_cursor_shape, platform_cursor_get_current_scale());
430         if (c) {
431             int size = platform_cursor_get_texture_size(c);
432             size = calc_adjust_with_percentage(size, calc_percentage(100, scale_percentage));
433             SDL_Rect dst;
434             dst.x = mouse->x - c->hotspot_x;
435             dst.y = mouse->y - c->hotspot_y;
436             dst.w = size;
437             dst.h = size;
438             SDL_RenderCopy(SDL.renderer, SDL.cursors[current_cursor_shape], NULL, &dst);
439         }
440     }
441 }
442 #endif
443 
444 #ifdef _WIN32
platform_screen_recreate_texture(void)445 void platform_screen_recreate_texture(void)
446 {
447     // On Windows, if ctrl + alt + del is pressed during fullscreen, the rendering context may be lost for a few frames
448     // after restoring the window, preventing the texture from being recreated. This forces an attempt to recreate the
449     // texture every frame to bypass that issue.
450     if (!SDL.texture_ui && SDL.renderer && setting_fullscreen()) {
451         SDL_DisplayMode mode;
452         SDL_GetWindowDisplayMode(SDL.window, &mode);
453         screen_set_resolution(scale_pixels_to_logical(mode.w), scale_pixels_to_logical(mode.h));
454         create_textures(screen_width(), screen_height());
455     }
456 }
457 #endif
458 
platform_screen_clear(void)459 void platform_screen_clear(void)
460 {
461     SDL_RenderClear(SDL.renderer);
462 }
463 
platform_screen_update(void)464 void platform_screen_update(void)
465 {
466     SDL_RenderClear(SDL.renderer);
467     if (config_get(CONFIG_UI_ZOOM)) {
468         city_view_get_unscaled_viewport(&city_texture.position.offset.x, &city_texture.position.offset.y,
469             &city_texture.position.renderer.w, &city_texture.position.offset.h);
470         city_view_get_scaled_viewport(&city_texture.position.offset.x, &city_texture.position.offset.y,
471             &city_texture.position.offset.w, &city_texture.position.offset.h);
472 #ifndef __vita__
473         SDL_UpdateTexture(SDL.texture_city, &city_texture.position.offset, graphics_canvas(CANVAS_CITY), screen_width() * 4 * 2);
474 #endif
475         SDL_RenderCopy(SDL.renderer, SDL.texture_city, &city_texture.position.offset, &city_texture.position.renderer);
476     }
477 #ifndef __vita__
478     SDL_UpdateTexture(SDL.texture_ui, NULL, graphics_canvas(CANVAS_UI), screen_width() * 4);
479 #endif
480     SDL_RenderCopy(SDL.renderer, SDL.texture_ui, NULL, NULL);
481 #ifdef PLATFORM_USE_SOFTWARE_CURSOR
482     draw_software_mouse_cursor();
483 #endif
484 }
485 
platform_screen_render(void)486 void platform_screen_render(void)
487 {
488     SDL_RenderPresent(SDL.renderer);
489 }
490 
platform_screen_generate_mouse_cursor_texture(int cursor_id,int scale,const color_t * cursor_colors)491 void platform_screen_generate_mouse_cursor_texture(int cursor_id, int scale, const color_t *cursor_colors)
492 {
493     if (SDL.cursors[cursor_id]) {
494         SDL_DestroyTexture(SDL.cursors[cursor_id]);
495         SDL.cursors[cursor_id] = 0;
496     }
497     const cursor *c = input_cursor_data(cursor_id, scale);
498     int size = platform_cursor_get_texture_size(c);
499     SDL.cursors[cursor_id] = SDL_CreateTexture(SDL.renderer,
500         SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC,
501         size, size);
502     if (!SDL.cursors[cursor_id]) {
503         return;
504     }
505     SDL_UpdateTexture(SDL.cursors[cursor_id], NULL, cursor_colors, size * sizeof(color_t));
506     SDL_SetTextureBlendMode(SDL.cursors[cursor_id], SDL_BLENDMODE_BLEND);
507 }
508 
system_set_mouse_position(int * x,int * y)509 void system_set_mouse_position(int *x, int *y)
510 {
511     *x = calc_bound(*x, 0, screen_width() - 1);
512     *y = calc_bound(*y, 0, screen_height() - 1);
513     SDL_WarpMouseInWindow(SDL.window, scale_logical_to_pixels(*x), scale_logical_to_pixels(*y));
514 }
515 
system_is_fullscreen_only(void)516 int system_is_fullscreen_only(void)
517 {
518 #if defined(__ANDROID__) || defined(__SWITCH__) || defined(__vita__)
519     return 1;
520 #else
521     return 0;
522 #endif
523 }
524 
system_get_max_resolution(int * width,int * height)525 void system_get_max_resolution(int *width, int *height)
526 {
527     SDL_DisplayMode mode;
528     int index = SDL_GetWindowDisplayIndex(SDL.window);
529     SDL_GetCurrentDisplayMode(index, &mode);
530     *width = scale_pixels_to_logical(mode.w);
531     *height = scale_pixels_to_logical(mode.h);
532 }
533 
system_reload_textures(void)534 int system_reload_textures(void)
535 {
536     int width = screen_width();
537     int height = screen_height();
538     int result = create_textures(width, height);
539     screen_set_resolution(width, height);
540     return result != -1;
541 }
542 
system_get_max_zoom(int width,int height)543 int system_get_max_zoom(int width, int height)
544 {
545     int width_scale_pct = city_texture.max_size.width * 100 / width;
546     int height_scale_pct = city_texture.max_size.height * 100 / height;
547     int max_zoom = SDL_min(width_scale_pct, height_scale_pct);
548 
549     return calc_bound(max_zoom, 100, 200);
550 }
551 
system_save_screen_buffer(void * pixels)552 int system_save_screen_buffer(void *pixels)
553 {
554     if (scale_percentage == 100) {
555         return SDL_RenderReadPixels(SDL.renderer, NULL,
556             SDL_PIXELFORMAT_ARGB8888, pixels, screen_width() * sizeof(color_t)) == 0;
557     }
558     int width = screen_width();
559     int height = screen_height();
560     SDL_Texture *target = SDL_CreateTexture(SDL.renderer,
561         SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET,
562         width, height);
563     if (!target) {
564         return 0;
565     }
566     SDL_SetRenderTarget(SDL.renderer, target);
567     SDL_RenderClear(SDL.renderer);
568     SDL_RenderCopy(SDL.renderer, SDL.texture_city, &city_texture.position.offset, &city_texture.position.renderer);
569     SDL_RenderCopy(SDL.renderer, SDL.texture_ui, NULL, NULL);
570     int result = SDL_RenderReadPixels(SDL.renderer, NULL,
571         SDL_PIXELFORMAT_ARGB8888, pixels, width * sizeof(color_t)) == 0;
572     SDL_SetRenderTarget(SDL.renderer, NULL);
573     SDL_DestroyTexture(target);
574     return result;
575 }
576 
system_create_ui_framebuffer(int width,int height)577 color_t *system_create_ui_framebuffer(int width, int height)
578 {
579 #ifdef __vita__
580     int pitch;
581     SDL_LockTexture(SDL.texture_ui, NULL, (void **) &framebuffer_ui, &pitch);
582     SDL_UnlockTexture(SDL.texture_ui);
583 #else
584     free(framebuffer_ui);
585     framebuffer_ui = (color_t *) malloc((size_t) width * height * sizeof(color_t));
586 #endif
587     return framebuffer_ui;
588 }
589 
system_create_city_framebuffer(int width,int height)590 color_t *system_create_city_framebuffer(int width, int height)
591 {
592 #ifdef __vita__
593     if (!SDL.texture_city) {
594         return 0;
595     }
596     int pitch;
597     SDL_LockTexture(SDL.texture_city, NULL, (void **) &framebuffer_city, &pitch);
598     SDL_UnlockTexture(SDL.texture_city);
599 #else
600     free(framebuffer_city);
601     framebuffer_city = (color_t *) malloc((size_t) width * height * sizeof(color_t) * 4);
602 #endif
603     return framebuffer_city;
604 }
605 
system_release_city_framebuffer(void)606 void system_release_city_framebuffer(void)
607 {
608 #ifndef __vita__
609     free(framebuffer_city);
610 #endif
611     framebuffer_city = 0;
612 }
613