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