]> git.sesse.net Git - pistorm/blob - platforms/amiga/rtg/rtg-output-raylib.c
d475ffafd822403ba86815cdd1fdcca3370164f4
[pistorm] / platforms / amiga / rtg / rtg-output-raylib.c
1 // SPDX-License-Identifier: MIT
2
3 #include "config_file/config_file.h"
4 #include "emulator.h"
5 #include "rtg.h"
6
7 #include "raylib/raylib.h"
8
9 #include <pthread.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 #define RTG_INIT_ERR(a) { printf(a); *data->running = 0; }
17
18 uint8_t busy = 0, rtg_on = 0, rtg_initialized = 0;
19 extern uint8_t *rtg_mem;
20 extern uint32_t framebuffer_addr;
21 extern uint32_t framebuffer_addr_adj;
22
23 extern uint16_t rtg_display_width, rtg_display_height;
24 extern uint16_t rtg_display_format;
25 extern uint16_t rtg_pitch, rtg_total_rows;
26 extern uint16_t rtg_offset_x, rtg_offset_y;
27
28 static pthread_t thread_id;
29 static uint8_t mouse_cursor_enabled = 0, cursor_image_updated = 0, updating_screen = 0, debug_palette = 0, show_fps = 0;
30 static uint8_t mouse_cursor_w = 16, mouse_cursor_h = 16;
31 static int16_t mouse_cursor_x = 0, mouse_cursor_y = 0;
32
33 struct rtg_shared_data {
34     uint16_t *width, *height;
35     uint16_t *format, *pitch;
36     uint16_t *offset_x, *offset_y;
37     uint8_t *memory;
38     uint32_t *addr;
39     uint8_t *running;
40 };
41
42 struct rtg_shared_data rtg_share_data;
43 static uint32_t palette[256];
44 static uint32_t cursor_palette[256];
45
46 uint32_t cursor_data[256 * 256];
47
48 void rtg_update_screen() {}
49
50 uint32_t rtg_to_raylib[RTGFMT_NUM] = {
51     PIXELFORMAT_UNCOMPRESSED_GRAYSCALE,
52     PIXELFORMAT_UNCOMPRESSED_R5G6B5,
53     PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
54     PIXELFORMAT_UNCOMPRESSED_R5G5B5A1,
55 };
56
57 uint32_t rtg_pixel_size[RTGFMT_NUM] = {
58     1,
59     2,
60     4,
61     2,
62 };
63
64 void *rtgThread(void *args) {
65
66     printf("RTG thread running\n");
67     fflush(stdout);
68
69     int reinit = 0;
70     rtg_on = 1;
71
72     uint32_t *indexed_buf = NULL;
73
74     rtg_share_data.format = &rtg_display_format;
75     rtg_share_data.width = &rtg_display_width;
76     rtg_share_data.height = &rtg_display_height;
77     rtg_share_data.pitch = &rtg_pitch;
78     rtg_share_data.offset_x = &rtg_offset_x;
79     rtg_share_data.offset_y = &rtg_offset_y;
80     rtg_share_data.memory = rtg_mem;
81     rtg_share_data.running = &rtg_on;
82     rtg_share_data.addr = &framebuffer_addr_adj;
83     struct rtg_shared_data *data = &rtg_share_data;
84
85     uint16_t width = rtg_display_width;
86     uint16_t height = rtg_display_height;
87     uint16_t format = rtg_display_format;
88     uint16_t pitch = rtg_pitch;
89
90     Texture raylib_texture, raylib_cursor_texture;
91     Texture raylib_clut_texture;
92     Image raylib_fb, raylib_cursor, raylib_clut;
93
94     InitWindow(GetScreenWidth(), GetScreenHeight(), "Pistorm RTG");
95     HideCursor();
96     SetTargetFPS(60);
97
98         Color bef = { 0, 64, 128, 255 };
99     float scale_x = 1.0f, scale_y = 1.0f;
100
101     Shader clut_shader = LoadShader(NULL, "platforms/amiga/rtg/clut.shader");
102     Shader swizzle_shader = LoadShader(NULL, "platforms/amiga/rtg/argbswizzle.shader");
103     int clut_loc = GetShaderLocation(clut_shader, "texture1");
104
105     raylib_clut.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
106     raylib_clut.width = 256;
107     raylib_clut.height = 1;
108     raylib_clut.mipmaps = 1;
109     raylib_clut.data = palette;
110
111     raylib_clut_texture = LoadTextureFromImage(raylib_clut);
112
113     raylib_cursor.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
114     raylib_cursor.width = 256;
115     raylib_cursor.height = 256;
116     raylib_cursor.mipmaps = 1;
117     raylib_cursor.data = cursor_data;
118     raylib_cursor_texture = LoadTextureFromImage(raylib_cursor);
119
120     Rectangle srcrect, dstscale;
121     Vector2 origin;
122
123 reinit_raylib:;
124     if (reinit) {
125         printf("Reinitializing raylib...\n");
126         width = rtg_display_width;
127         height = rtg_display_height;
128         format = rtg_display_format;
129         pitch = rtg_pitch;
130         if (indexed_buf) {
131             free(indexed_buf);
132             indexed_buf = NULL;
133         }
134         UnloadTexture(raylib_texture);
135         reinit = 0;
136     }
137
138     printf("Creating %dx%d raylib window...\n", width, height);
139
140     printf("Setting up raylib framebuffer image.\n");
141     raylib_fb.format = rtg_to_raylib[format];
142
143     switch (format) {
144         case RTGFMT_RBG565:
145             raylib_fb.width = width;
146             indexed_buf = calloc(1, width * height * 2);
147             break;
148         default:
149             raylib_fb.width = pitch / rtg_pixel_size[format];
150             break;
151     }
152     raylib_fb.height = height;
153         raylib_fb.mipmaps = 1;
154         raylib_fb.data = &data->memory[*data->addr];
155     printf("Width: %d\nPitch: %d\nBPP: %d\n", raylib_fb.width, pitch, rtg_pixel_size[format]);
156
157     raylib_texture = LoadTextureFromImage(raylib_fb);
158
159     srcrect.x = srcrect.y = 0;
160     srcrect.width = width;
161     srcrect.height = height;
162     dstscale.x = dstscale.y = 0;
163     dstscale.width = width;
164     dstscale.height = height;
165     scale_x = 1.0f;
166     scale_y = 1.0f;
167     origin.x = 0.0f;
168     origin.y = 0.0f;
169
170     if (dstscale.height * 2 < GetScreenHeight()) {
171         if (width == 320) {
172             if (GetScreenHeight() == 720) {
173                 dstscale.width = 960;
174                 dstscale.height = 720;
175             } else if (GetScreenHeight() == 1080) {
176                 dstscale.width = 1440;
177                 dstscale.height = 1080;
178             }
179         } else {
180             while (dstscale.height < GetScreenHeight()) {
181                 dstscale.height += height;
182                 dstscale.width += width;
183             }
184         }
185         scale_x = dstscale.width / (float)width;
186         scale_y = dstscale.height / (float)height;
187     }
188
189     while (1) {
190         if (rtg_on) {
191             BeginDrawing();
192             updating_screen = 1;
193
194             switch (format) {
195                 case RTGFMT_8BIT:
196                     UpdateTexture(raylib_clut_texture, palette);
197                     BeginShaderMode(clut_shader);
198                     SetShaderValueTexture(clut_shader, clut_loc, raylib_clut_texture);
199                     break;
200                 case RTGFMT_RGB32:
201                     BeginShaderMode(swizzle_shader);
202                     break;
203             }
204             
205             DrawTexturePro(raylib_texture, srcrect, dstscale, origin, 0.0f, RAYWHITE);
206
207             switch (format) {
208                 case RTGFMT_8BIT:
209                 case RTGFMT_RGB32:
210                     EndShaderMode();
211                     break;
212             }
213
214             if (mouse_cursor_enabled) {
215                 float mc_x = mouse_cursor_x - rtg_offset_x;
216                 float mc_y = mouse_cursor_y - rtg_offset_y;
217                 Rectangle cursor_srcrect = { 0, 0, mouse_cursor_w, mouse_cursor_h };
218                 Rectangle dstrect = { mc_x * scale_x, mc_y * scale_y, (float)mouse_cursor_w * scale_x, (float)mouse_cursor_h * scale_y };
219                 DrawTexturePro(raylib_cursor_texture, cursor_srcrect, dstrect, origin, 0.0f, RAYWHITE);
220             }
221
222             if (debug_palette) {
223                 if (format == RTGFMT_8BIT) {
224                     Rectangle srcrect = { 0, 0, 256, 1 };
225                     Rectangle dstrect = { 0, 0, 1024, 8 };
226                     DrawTexturePro(raylib_clut_texture, srcrect, dstrect, origin, 0.0f, RAYWHITE);
227                 }
228             }
229
230             if (show_fps) {
231                 DrawFPS(GetScreenWidth() - 128, 0);
232             }
233
234             EndDrawing();
235             if (format == RTGFMT_RBG565) {
236                 for (int y = 0; y < height; y++) {
237                     for (int x = 0; x < width; x++) {
238                         ((uint16_t *)indexed_buf)[x + (y * width)] = be16toh(((uint16_t *)data->memory)[(*data->addr / 2) + x + (y * (pitch / 2))]);
239                     }
240                 }
241                 UpdateTexture(raylib_texture, indexed_buf);
242             }
243             else {
244                 UpdateTexture(raylib_texture, &data->memory[*data->addr]);
245             }
246             if (cursor_image_updated) {
247                 UpdateTexture(raylib_cursor_texture, cursor_data);
248                 cursor_image_updated = 0;
249             }
250             updating_screen = 0;
251         } else {
252             BeginDrawing();
253             ClearBackground(bef);
254             DrawText("RTG is currently sleeping.", 16, 16, 12, RAYWHITE);
255             EndDrawing();
256         }
257         if (pitch != *data->pitch || height != *data->height || width != *data->width || format != *data->format) {
258             printf("Reinitializing due to something change.\n");
259             reinit = 1;
260             goto shutdown_raylib;
261         }
262         /*if (!rtg_on) {
263             goto shutdown_raylib;
264         }*/
265     }
266
267     rtg_initialized = 0;
268     printf("RTG thread shut down.\n");
269
270 shutdown_raylib:;
271
272     if (reinit)
273         goto reinit_raylib;
274
275     if (indexed_buf)
276         free(indexed_buf);
277
278     UnloadTexture(raylib_texture);
279     UnloadShader(clut_shader);
280
281     CloseWindow();
282
283     return args;
284 }
285
286 void rtg_set_clut_entry(uint8_t index, uint32_t xrgb) {
287     //palette[index] = xrgb;
288     unsigned char *src = (unsigned char *)&xrgb;
289     unsigned char *dst = (unsigned char *)&palette[index];
290     dst[0] = src[2];
291     dst[1] = src[1];
292     dst[2] = src[0];
293     dst[3] = 0xFF;
294 }
295
296 void rtg_init_display() {
297     int err;
298     rtg_on = 1;
299
300     if (!rtg_initialized) {
301         err = pthread_create(&thread_id, NULL, &rtgThread, (void *)&rtg_share_data);
302         if (err != 0) {
303             rtg_on = 0;
304             printf("can't create RTG thread :[%s]", strerror(err));
305         }
306         else {
307             rtg_initialized = 1;
308             pthread_setname_np(thread_id, "pistorm: rtg");
309             printf("RTG Thread created successfully\n");
310         }
311     }
312     printf("RTG display enabled.\n");
313 }
314
315 void rtg_shutdown_display() {
316     printf("RTG display disabled.\n");
317     rtg_on = 0;
318 }
319
320 void rtg_enable_mouse_cursor() {
321     mouse_cursor_enabled = 1;
322 }
323
324 void rtg_set_mouse_cursor_pos(int16_t x, int16_t y) {
325     mouse_cursor_x = x;
326     mouse_cursor_y = y;
327     //printf("Set mouse cursor pos to %d, %d.\n", x, y);
328 }
329
330 static uint8_t clut_cursor_data[256*256];
331
332 void update_mouse_cursor(uint8_t *src) {
333     if (src != NULL) {
334         memset(clut_cursor_data, 0x00, 256*256);
335         uint8_t cur_bit = 0x80;
336         uint8_t line_pitch = (mouse_cursor_w / 8) * 2;
337
338         for (uint8_t y = 0; y < mouse_cursor_h; y++) {
339             for (uint8_t x = 0; x < mouse_cursor_w; x++) {
340                 if (src[(x / 8) + (line_pitch * y)] & cur_bit)
341                     clut_cursor_data[x + (y * 256)] |= 0x01;
342                 if (src[(x / 8) + (line_pitch * y) + (mouse_cursor_w / 8)] & cur_bit)
343                     clut_cursor_data[x + (y * 256)] |= 0x02;
344                 cur_bit >>= 1;
345                 if (cur_bit == 0x00)
346                     cur_bit = 0x80;
347             }
348             cur_bit = 0x80;
349         }
350     }
351
352     for (int y = 0; y < mouse_cursor_h; y++) {
353         for (int x = 0; x < mouse_cursor_w; x++) {
354             cursor_data[x + (y * 256)] = cursor_palette[clut_cursor_data[x + (y * 256)]];
355         }
356     }
357
358     printf ("Updated mouse cursor data.\n");
359
360     while (rtg_on && !updating_screen)
361         usleep(0);
362     cursor_image_updated = 1;
363 }
364
365 void rtg_set_cursor_clut_entry(uint8_t r, uint8_t g, uint8_t b, uint8_t idx) {
366     uint32_t color = 0;
367     unsigned char *dst = (unsigned char *)&color;
368
369     dst[0] = r;
370     dst[1] = g;
371     dst[2] = b;
372     dst[3] = 0xFF;
373     if (cursor_palette[idx + 1] != color) {
374         cursor_palette[0] = 0;
375         cursor_palette[idx + 1] = color;
376         update_mouse_cursor(NULL);
377     }
378 }
379
380 static uint8_t old_mouse_w, old_mouse_h;
381 static uint8_t old_mouse_data[256];
382
383 void rtg_set_mouse_cursor_image(uint8_t *src, uint8_t w, uint8_t h) {
384     uint8_t new_cursor_data = 0;
385
386     mouse_cursor_w = w;
387     mouse_cursor_h = h;
388
389     if (memcmp(src, old_mouse_data, (w / 8 * h)) != 0) {
390         printf("New cursor data.\n");
391         new_cursor_data = 1;
392     } else {
393         printf("No new cursor data.\n");
394     }
395
396     if (old_mouse_w != w || old_mouse_h != h || new_cursor_data) {
397         printf("Set new %dx%d mouse cursor image.\n", mouse_cursor_w, mouse_cursor_h);
398         old_mouse_w = w;
399         old_mouse_h = h;
400         update_mouse_cursor(src);
401     }
402 }