1 #include "cursor.h"
2 
3 #include "core/config.h"
4 #include "core/png_read.h"
5 #include "game/system.h"
6 #include "graphics/color.h"
7 #include "input/cursor.h"
8 #include "platform/screen.h"
9 #include "platform/haiku/haiku.h"
10 #include "platform/switch/switch.h"
11 #include "platform/vita/vita.h"
12 
13 #include "SDL.h"
14 
15 #include <string.h>
16 
17 static char cursor_path[64] = "Color_Cursors/";
18 static size_t cursor_path_offset;
19 
20 static struct {
21     SDL_Cursor *cursors[CURSOR_MAX];
22     SDL_Surface *surfaces[CURSOR_MAX];
23     cursor_shape current_shape;
24     cursor_scale current_scale;
25 } data;
26 
27 static const color_t mouse_colors[] = {
28     ALPHA_TRANSPARENT,
29     ALPHA_TRANSPARENT,
30     ALPHA_TRANSPARENT,
31     ALPHA_OPAQUE | COLOR_BLACK,
32     ALPHA_OPAQUE | COLOR_MOUSE_DARK_GRAY,
33     ALPHA_OPAQUE | COLOR_MOUSE_MEDIUM_GRAY,
34     ALPHA_OPAQUE | COLOR_MOUSE_LIGHT_GRAY,
35     ALPHA_OPAQUE | COLOR_WHITE
36 };
37 
generate_cursor_surface(const cursor * c)38 static SDL_Surface *generate_cursor_surface(const cursor *c)
39 {
40     int size = platform_cursor_get_texture_size(c);
41     SDL_Surface *cursor_surface =
42         SDL_CreateRGBSurface(0, size, size, 32,
43         COLOR_CHANNEL_RED, COLOR_CHANNEL_GREEN, COLOR_CHANNEL_BLUE, COLOR_CHANNEL_ALPHA);
44     color_t *pixels = cursor_surface->pixels;
45     SDL_memset(pixels, 0, sizeof(color_t) * size * size);
46     if (!config_get(CONFIG_SCREEN_COLOR_CURSORS) ||
47         !png_read(cursor_path, pixels, size, size)) {
48         for (int y = 0; y < c->height; y++) {
49             for (int x = 0; x < c->width; x++) {
50                 pixels[y * size + x] = mouse_colors[c->data[y * c->width + x] - 32];
51             }
52         }
53     }
54     return cursor_surface;
55 }
56 
get_cursor_scale(int scale_percentage)57 static cursor_scale get_cursor_scale(int scale_percentage)
58 {
59     if (scale_percentage <= 100) {
60         return CURSOR_SCALE_1;
61     } else if (scale_percentage <= 150) {
62         return CURSOR_SCALE_1_5;
63     } else {
64         return CURSOR_SCALE_2;
65     }
66 }
67 
system_init_cursors(int scale_percentage)68 void system_init_cursors(int scale_percentage)
69 {
70     data.current_scale = get_cursor_scale(scale_percentage);
71     for (int i = 0; i < CURSOR_MAX; i++) {
72         const cursor *c = input_cursor_data(i, data.current_scale);
73         if (data.surfaces[i]) {
74             SDL_FreeSurface(data.surfaces[i]);
75         }
76         if (data.cursors[i]) {
77             SDL_FreeCursor(data.cursors[i]);
78         }
79         data.surfaces[i] = generate_cursor_surface(c);
80 #ifndef PLATFORM_USE_SOFTWARE_CURSOR
81         data.cursors[i] = SDL_CreateColorCursor(data.surfaces[i], c->hotspot_x, c->hotspot_y);
82 #else
83         SDL_ShowCursor(SDL_DISABLE);
84         platform_screen_generate_mouse_cursor_texture(i, data.current_scale, data.surfaces[i]->pixels);
85 #endif
86     }
87     system_set_cursor(data.current_shape);
88 }
89 
system_set_cursor(int cursor_id)90 void system_set_cursor(int cursor_id)
91 {
92     data.current_shape = cursor_id;
93 #ifndef PLATFORM_USE_SOFTWARE_CURSOR
94     SDL_SetCursor(data.cursors[cursor_id]);
95 #endif
96 }
97 
platform_cursor_get_current_shape(void)98 cursor_shape platform_cursor_get_current_shape(void)
99 {
100     return data.current_shape;
101 }
102 
platform_cursor_get_current_scale(void)103 cursor_scale platform_cursor_get_current_scale(void)
104 {
105     return data.current_scale;
106 }
107 
platform_cursor_get_texture_size(const cursor * c)108 int platform_cursor_get_texture_size(const cursor *c)
109 {
110     int width;
111     int height;
112     if (config_get(CONFIG_SCREEN_COLOR_CURSORS)) {
113         if (!cursor_path_offset) {
114             cursor_path_offset = strlen(cursor_path);
115         }
116         strncpy(cursor_path + cursor_path_offset, c->png_path, 64 - cursor_path_offset);
117         if (!png_get_image_size(cursor_path, &width, &height)) {
118             width = c->width;
119             height = c->height;
120         }
121     } else {
122         width = c->width;
123         height = c->height;
124     }
125 
126     int size = 32;
127     while (size < width || size < height) {
128         size *= 2;
129     }
130     return size;
131 }
132