]> git.sesse.net Git - pistorm/blob - platforms/amiga/rtg/rtg.c
86aa550f760cd2cb596cafe91bff29fa16ab4310
[pistorm] / platforms / amiga / rtg / rtg.c
1 #include <stdint.h>
2 #include <endian.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <time.h>
7 #include "rtg.h"
8 #include "../../../config_file/config_file.h"
9
10 static uint8_t rtg_u8[4];
11 static uint16_t rtg_x[8], rtg_y[8];
12 static uint16_t rtg_user[8];
13 static uint16_t rtg_format;
14 static uint32_t rtg_address[2];
15 static uint32_t rtg_address_adj[2];
16 static uint32_t rtg_rgb[2];
17
18 static uint8_t display_enabled = 0xFF;
19
20 uint16_t rtg_display_width, rtg_display_height;
21 uint16_t rtg_display_format;
22 uint16_t rtg_pitch, rtg_total_rows;
23 uint16_t rtg_offset_x, rtg_offset_y;
24
25 uint8_t *rtg_mem; // FIXME
26
27 uint32_t framebuffer_addr = 0;
28 uint32_t framebuffer_addr_adj = 0;
29
30 static void handle_rtg_command(uint32_t cmd);
31 static struct timespec f1, f2;
32
33 static const char *op_type_names[OP_TYPE_NUM] = {
34     "BYTE",
35     "WORD",
36     "LONGWORD",
37     "MEM",
38 };
39
40 static const char *rtg_format_names[RTGFMT_NUM] = {
41     "8BPP CLUT",
42     "16BPP RGB (565)",
43     "32BPP RGB (RGBA)",
44     "15BPP RGB (555)",
45 };
46
47 int init_rtg_data() {
48     rtg_mem = calloc(1, 32 * SIZE_MEGA);
49     if (!rtg_mem) {
50         printf("Failed to allocate RTG video memory.\n");
51         return 0;
52     }
53
54     return 1;
55 }
56
57 extern uint8_t busy, rtg_on;
58 void rtg_update_screen();
59
60 unsigned int rtg_read(uint32_t address, uint8_t mode) {
61     //printf("%s read from RTG: %.8X\n", op_type_names[mode], address);
62     if (address >= PIGFX_REG_SIZE) {
63         if (rtg_mem) {
64             switch (mode) {
65                 case OP_TYPE_BYTE:
66                     return (rtg_mem[address - PIGFX_REG_SIZE]);
67                     break;
68                 case OP_TYPE_WORD:
69                     return be16toh(*(( uint16_t *) (&rtg_mem[address - PIGFX_REG_SIZE])));
70                     break;
71                 case OP_TYPE_LONGWORD:
72                     return be32toh(*(( uint32_t *) (&rtg_mem[address - PIGFX_REG_SIZE])));
73                     break;
74                 default:
75                     return 0;
76             }
77         }
78     }
79
80     return 0;
81 }
82
83 struct timespec diff(struct timespec start, struct timespec end)
84 {
85     struct timespec temp;
86     if ((end.tv_nsec-start.tv_nsec)<0) {
87         temp.tv_sec = end.tv_sec-start.tv_sec-1;
88         temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
89     } else {
90         temp.tv_sec = end.tv_sec-start.tv_sec;
91         temp.tv_nsec = end.tv_nsec-start.tv_nsec;
92     }
93     return temp;
94 }
95
96 #define CHKREG(a, b) case a: b = value; break;
97
98 void rtg_write(uint32_t address, uint32_t value, uint8_t mode) {
99     //printf("%s write to RTG: %.8X (%.8X)\n", op_type_names[mode], address, value);
100     if (address >= PIGFX_REG_SIZE) {
101         /*if ((address - PIGFX_REG_SIZE) < framebuffer_addr) {// || (address - PIGFX_REG_SIZE) > framebuffer_addr + ((rtg_display_width << rtg_display_format) * rtg_display_height)) {
102             printf("Write to RTG memory outside frame buffer %.8X (%.8X).\n", (address - PIGFX_REG_SIZE), framebuffer_addr);
103         }*/
104         if (rtg_mem) {
105             switch (mode) {
106                 case OP_TYPE_BYTE:
107                     rtg_mem[address - PIGFX_REG_SIZE] = value;
108                     break;
109                 case OP_TYPE_WORD:
110                     *(( uint16_t *) (&rtg_mem[address - PIGFX_REG_SIZE])) = htobe16(value);
111                     break;
112                 case OP_TYPE_LONGWORD:
113                     *(( uint32_t *) (&rtg_mem[address - PIGFX_REG_SIZE])) = htobe32(value);
114                     break;
115                 default:
116                     return;
117             }
118         }
119     }
120     else {
121         switch (mode) {
122             case OP_TYPE_BYTE:
123                 switch (address) {
124                     CHKREG(RTG_U81, rtg_u8[0]);
125                     CHKREG(RTG_U82, rtg_u8[1]);
126                     CHKREG(RTG_U83, rtg_u8[2]);
127                     CHKREG(RTG_U84, rtg_u8[3]);
128                 }
129                 break;
130             case OP_TYPE_WORD:
131                 switch (address) {
132                     CHKREG(RTG_X1, rtg_x[0]);
133                     CHKREG(RTG_X2, rtg_x[1]);
134                     CHKREG(RTG_X3, rtg_x[2]);
135                     CHKREG(RTG_X4, rtg_x[3]);
136                     CHKREG(RTG_X5, rtg_x[4]);
137                     CHKREG(RTG_Y1, rtg_y[0]);
138                     CHKREG(RTG_Y2, rtg_y[1]);
139                     CHKREG(RTG_Y3, rtg_y[2]);
140                     CHKREG(RTG_Y4, rtg_y[3]);
141                     CHKREG(RTG_Y5, rtg_y[4]);
142                     CHKREG(RTG_U1, rtg_user[0]);
143                     CHKREG(RTG_U2, rtg_user[1]);
144                     CHKREG(RTG_FORMAT, rtg_format);
145                     case RTG_COMMAND:
146                         handle_rtg_command(value);
147                         break;
148                 }
149                 break;
150             case OP_TYPE_LONGWORD:
151                 switch (address) {
152                     case RTG_ADDR1:
153                         rtg_address[0] = value;
154                         rtg_address_adj[0] = value - (PIGFX_RTG_BASE + PIGFX_REG_SIZE);
155                         break;
156                     case RTG_ADDR2:
157                         rtg_address[1] = value;
158                         rtg_address_adj[1] = value - (PIGFX_RTG_BASE + PIGFX_REG_SIZE);
159                         break;
160                     CHKREG(RTG_RGB1, rtg_rgb[0]);
161                     CHKREG(RTG_RGB2, rtg_rgb[1]);
162                 }
163                 break;
164         }
165     }
166
167     return;
168 }
169
170 static void handle_rtg_command(uint32_t cmd) {
171     //printf("Handling RTG command %d (%.8X)\n", cmd, cmd);
172     switch (cmd) {
173         case RTGCMD_SETGC:
174             rtg_display_format = rtg_format;
175             rtg_display_width = rtg_x[0];
176             rtg_display_height = rtg_y[0];
177             if (rtg_u8[0]) {
178                 //rtg_pitch = rtg_display_width << rtg_format;
179                 framebuffer_addr_adj = framebuffer_addr + (rtg_offset_x << rtg_display_format) + (rtg_offset_y * rtg_pitch);
180                 rtg_total_rows = rtg_y[1];
181             }
182             else {
183                 //rtg_pitch = rtg_display_width << rtg_format;
184                 framebuffer_addr_adj = framebuffer_addr + (rtg_offset_x << rtg_display_format) + (rtg_offset_y * rtg_pitch);
185                 rtg_total_rows = rtg_y[1];
186             }
187             printf("Set RTG mode:\n");
188             printf("%dx%d pixels\n", rtg_display_width, rtg_display_height);
189             printf("Pixel format: %s\n", rtg_format_names[rtg_display_format]);
190             break;
191         case RTGCMD_SETPAN:
192             //printf("Command: SetPan.\n");
193             rtg_offset_x = rtg_x[1];
194             rtg_offset_y = rtg_y[1];
195             rtg_pitch = (rtg_x[0] << rtg_display_format);
196             framebuffer_addr = rtg_address[0] - (PIGFX_RTG_BASE + PIGFX_REG_SIZE);
197             framebuffer_addr_adj = framebuffer_addr + (rtg_offset_x << rtg_display_format) + (rtg_offset_y * rtg_pitch);
198             printf("Set panning to $%.8X (%.8X)\n", framebuffer_addr, rtg_address[0]);
199             printf("(Panned: $%.8X)\n", framebuffer_addr_adj);
200             printf("Offset X/Y: %d/%d\n", rtg_offset_x, rtg_offset_y);
201             printf("Pitch: %d (%d bytes)\n", rtg_x[0], rtg_pitch);
202             break;
203         case RTGCMD_SETCLUT: {
204             //printf("Command: SetCLUT.\n");
205             //printf("Set palette entry %d to %d, %d, %d\n", rtg_u8[0], rtg_u8[1], rtg_u8[2], rtg_u8[3]);
206             //printf("Set palette entry %d to 32-bit palette color: %.8X\n", rtg_u8[0], rtg_rgb[0]);
207             rtg_set_clut_entry(rtg_u8[0], rtg_rgb[0]);
208             break;
209         }
210         case RTGCMD_SETDISPLAY:
211             //printf("RTG SetDisplay %s\n", (rtg_u8[1]) ? "enabled" : "disabled");
212             // I remeber wrongs.
213             //printf("Command: SetDisplay.\n");
214             break;
215         case RTGCMD_ENABLE:
216         case RTGCMD_SETSWITCH:
217             //printf("RTG SetSwitch %s\n", ((rtg_x[0]) & 0x01) ? "enabled" : "disabled");
218             //printf("LAL: %.4X\n", rtg_x[0]);
219             if (display_enabled != ((rtg_x[0]) & 0x01)) {
220                 display_enabled = ((rtg_x[0]) & 0x01);
221                 if (display_enabled) {
222                     rtg_init_display();
223                 }
224                 else
225                     rtg_shutdown_display();
226             }
227             break;
228         case RTGCMD_FILLRECT:
229             rtg_fillrect(rtg_x[0], rtg_y[0], rtg_x[1], rtg_y[1], rtg_rgb[0], rtg_x[2], rtg_format, 0xFF);
230             break;
231         case RTGCMD_BLITRECT:
232             rtg_blitrect(rtg_x[0], rtg_y[0], rtg_x[1], rtg_y[1], rtg_x[2], rtg_y[2], rtg_x[3], rtg_format, 0xFF);
233             break;
234         case RTGCMD_BLITRECT_NOMASK_COMPLETE:
235             rtg_blitrect_nomask_complete(rtg_x[0], rtg_y[0], rtg_x[1], rtg_y[1], rtg_x[2], rtg_y[2], rtg_x[3], rtg_x[4], rtg_address[0], rtg_address[1], rtg_display_format, rtg_u8[0]);
236             break;
237         case RTGCMD_BLITPATTERN:
238             rtg_blitpattern(rtg_x[0], rtg_y[0], rtg_x[1], rtg_y[1], rtg_address[0], rtg_rgb[0], rtg_rgb[1], rtg_x[3], rtg_display_format, rtg_x[2], rtg_y[2], rtg_u8[0], rtg_u8[1], rtg_u8[2]);
239             return;
240         case RTGCMD_BLITTEMPLATE:
241             rtg_blittemplate(rtg_x[0], rtg_y[0], rtg_x[1], rtg_y[1], rtg_address[0], rtg_rgb[0], rtg_rgb[1], rtg_x[3], rtg_x[4], rtg_display_format, rtg_x[2], rtg_u8[0], rtg_u8[1]);
242             break;
243     }
244 }
245
246 void rtg_fillrect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t color, uint16_t pitch, uint16_t format, uint8_t mask) {
247     if (mask) {}
248     uint8_t *dptr = &rtg_mem[rtg_address_adj[0] + (x << format) + (y * pitch)];
249     //printf("FillRect: %d,%d to %d,%d C%.8X, p:%d dp: %d m:%.2X\n", x, y, x+w, y+h, color, pitch, rtg_pitch, mask);
250     //printf("%.8X - %.8X (%p) (%p)\n", framebuffer_addr, rtg_address_adj[0], rtg_mem, dptr);
251     switch(format) {
252         case RTGFMT_8BIT: {
253             //printf("Incoming 8-bit color: %.8X\n", color);
254             for (int xs = 0; xs < w; xs++) {
255                 dptr[xs] = color & 0xFF;
256             }
257             break;
258         }
259         case RTGFMT_RBG565: {
260             //printf("Incoming raw 16-bit color: %.8X\n", htobe32(color));
261             color = htobe16((color & 0xFFFF));
262             //printf("Incoming 16-bit color: %.8X\n", color);
263             uint16_t *ptr = (uint16_t *)dptr;
264             for (int xs = 0; xs < w; xs++) {
265                 ptr[xs] = color;
266             }
267             break;
268         }
269         case RTGFMT_RGB32: {
270             color = htobe32(color);
271             //printf("Incoming 32-bit color: %.8X\n", color);
272             uint32_t *ptr = (uint32_t *)dptr;
273             for (int xs = 0; xs < w; xs++) {
274                 ptr[xs] = color;
275             }
276             break;
277         }
278     }
279     for (int ys = 1; ys < h; ys++) {
280         dptr += pitch;
281         memcpy(dptr, (void *)(size_t)(dptr - pitch), (w << format));
282     }
283     //printf("FillRect done.\n");
284 }
285
286 void rtg_blitrect(uint16_t x, uint16_t y, uint16_t dx, uint16_t dy, uint16_t w, uint16_t h, uint16_t pitch, uint16_t format, uint8_t mask) {
287     if (mask) {}
288     //printf("BlitRect: %d,%d to %d,%d (%dx%d) p:%d dp: %d\n", x, y, dx, dy, w, h, pitch, rtg_pitch);
289     uint8_t *sptr = &rtg_mem[rtg_address_adj[0] + (x << format) + (y * pitch)];
290     uint8_t *dptr = &rtg_mem[rtg_address_adj[0] + (dx << format) + (dy * pitch)];
291
292     uint32_t xdir = 1, pitchstep = pitch;
293
294     if (y < dy) {
295         pitchstep = -pitch;
296         sptr += ((h - 1) * pitch);
297         dptr += ((h - 1) * pitch);
298     }
299     if (x < dx) {
300         xdir = 0;
301     }
302
303     for (int ys = 0; ys < h; ys++) {
304         if (xdir)
305             memcpy(dptr, sptr, w << format);
306         else
307             memmove(dptr, sptr, w << format);
308         sptr += pitchstep;
309         dptr += pitchstep;
310     }
311 }
312
313 void rtg_blitrect_nomask_complete(uint16_t sx, uint16_t sy, uint16_t dx, uint16_t dy, uint16_t w, uint16_t h, uint16_t srcpitch, uint16_t dstpitch, uint32_t src_addr, uint32_t dst_addr, uint16_t format, uint8_t minterm) {
314     if (minterm) {}
315     //printf("BlitRectNoMaskComplete\n");
316     uint8_t *sptr = &rtg_mem[src_addr - (PIGFX_RTG_BASE + PIGFX_REG_SIZE) + (sx << format) + (sy * srcpitch)];
317     uint8_t *dptr = &rtg_mem[dst_addr - (PIGFX_RTG_BASE + PIGFX_REG_SIZE) + (dx << format) + (dy * dstpitch)];
318
319     uint32_t xdir = 1, src_pitchstep = srcpitch, dst_pitchstep = dstpitch;
320
321     if (src_addr == dst_addr) {
322         if (sy < dy) {
323             src_pitchstep = -srcpitch;
324             sptr += ((h - 1) * srcpitch);
325             dst_pitchstep = -dstpitch;
326             dptr += ((h - 1) * dstpitch);
327         }
328         if (sx < dx) {
329             xdir = 0;
330         }
331     }
332
333     for (int ys = 0; ys < h; ys++) {
334         if (xdir)
335             memcpy(dptr, sptr, w << format);
336         else
337             memmove(dptr, sptr, w << format);
338         sptr += src_pitchstep;
339         dptr += dst_pitchstep;
340     }
341 }
342
343 extern struct emulator_config *cfg;
344
345 void rtg_blittemplate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t src_addr, uint32_t fgcol, uint32_t bgcol, uint16_t pitch, uint16_t t_pitch, uint16_t format, uint16_t offset_x, uint8_t mask, uint8_t draw_mode) {
346     if (mask) {}
347     //printf("BlitTemplate: %d,%d (%dx%d) @%.8X p:%d dp: %d DM: %d Format: %d\n", x, y, w, h, src_addr, pitch, t_pitch, draw_mode & 0x03, format);
348     //printf("FBA: %.8x\n", framebuffer_addr);
349
350     uint8_t *dptr = &rtg_mem[rtg_address_adj[1] + (x << format) + (y * pitch)];
351     uint8_t *sptr = NULL;
352     uint8_t cur_bit = 0, base_bit = 0, cur_byte = 0;
353     uint8_t invert = (draw_mode & DRAWMODE_INVERSVID);
354     uint16_t tmpl_x = 0;
355
356     draw_mode &= 0x03;
357
358         tmpl_x = offset_x / 8;
359     cur_bit = base_bit = (0x80 >> (offset_x % 8));
360
361     uint32_t fg_color[3] = {
362         (fgcol & 0xFF),
363         htobe16((fgcol & 0xFFFF)),
364         htobe32(fgcol),
365     };
366     uint32_t bg_color[3] = {
367         (bgcol & 0xFF),
368         htobe16((bgcol & 0xFFFF)),
369         htobe32(bgcol),
370     };
371
372     if (src_addr >= PIGFX_RTG_BASE)
373         sptr = &rtg_mem[src_addr - PIGFX_RTG_BASE];
374     else {
375         int i = get_mapped_item_by_address(cfg, src_addr);
376         if (i != -1) {
377             //printf("Grabbing data from mapped range %d at offset %ld.\n", i, src_addr - cfg->map_offset[i]);
378             sptr = &cfg->map_data[i][src_addr - cfg->map_offset[i]];
379         }
380         else {
381             printf("BlitTemplate: Failed to find mapped range for address %.8X\n", src_addr);
382             return;
383         }
384     }
385
386     switch (draw_mode) {
387         case DRAWMODE_JAM1:
388             for (uint16_t ys = 0; ys < h; ys++) {
389                 //printf("JAM1: Get byte from sptr[%d] (%p) <- (%p)...\n", tmpl_x, sptr, cfg->map_data[1]);
390                 cur_byte = (invert) ? sptr[tmpl_x] ^ 0xFF : sptr[tmpl_x];
391
392                 for (int xs = 0; xs < w; xs++) {
393                     if (w >= 8 && cur_bit == 0x80 && xs < w - 8) {
394                         SET_RTG_PIXELS(dptr, xs, format, fg_color);
395                         xs += 7;
396                     }
397                     else {
398                         while (cur_bit > 0 && xs < w) {
399                             if (cur_byte & cur_bit) {
400                                 //printf("JAM1: Write byte to dptr[%d] (%p) <- (%p)...\n", xs, dptr, rtg_mem);
401                                 SET_RTG_PIXEL(dptr, xs, format, fg_color);
402                             }
403                             xs++;
404                             cur_bit >>= 1;
405                         }
406                         xs--;
407                         cur_bit = 0x80;
408                     }
409                     TEMPLATE_LOOPX;
410                 }
411                 TEMPLATE_LOOPY;
412             }
413             return;
414         case DRAWMODE_JAM2:
415             for (uint16_t ys = 0; ys < h; ys++) {
416                 //printf("JAM2: Get byte from sptr[%d] (%p) <- (%p)...\n", tmpl_x, sptr, cfg->map_data[1]);
417                 cur_byte = (invert) ? sptr[tmpl_x] ^ 0xFF : sptr[tmpl_x];
418
419                 for (int xs = 0; xs < w; xs++) {
420                     if (w >= 8 && cur_bit == 0x80 && xs < w - 8) {
421                         SET_RTG_PIXELS_COND(dptr, xs, format, fg_color, bg_color);
422                         xs += 7;
423                     }
424                     else {
425                         while (cur_bit > 0 && xs < w) {
426                             if (cur_byte & cur_bit) {
427                                 SET_RTG_PIXEL(dptr, xs, format, fg_color)
428                             }
429                             else {
430                                 SET_RTG_PIXEL(dptr, xs, format, bg_color)
431                             }
432                             xs++;
433                             cur_bit >>= 1;
434                         }
435                         xs--;
436                         cur_bit = 0x80;
437                     }
438                     TEMPLATE_LOOPX;
439                 }
440                 TEMPLATE_LOOPY;
441             }
442             return;
443         case DRAWMODE_COMPLEMENT:
444             for (uint16_t ys = 0; ys < h; ys++) {
445                 cur_byte = (invert) ? sptr[tmpl_x] ^ 0xFF : sptr[tmpl_x];
446
447                 for (int xs = 0; xs < w; xs++) {
448                     if (w >= 8 && cur_bit == 0x80 && xs < w - 8) {
449                         SET_RTG_PIXELS_COND(dptr, xs, format, fg_color, bg_color);
450                         xs += 7;
451                     }
452                     else {
453                         while (cur_bit > 0 && xs < w) {
454                             if (cur_byte & cur_bit) {
455                                 INVERT_RTG_PIXELS(dptr, xs, format)
456                             }
457                             else {
458                                 INVERT_RTG_PIXEL(dptr, xs, format)
459                             }
460                             xs++;
461                             cur_bit >>= 1;
462                         }
463                         xs--;
464                         cur_bit = 0x80;
465                     }
466                     TEMPLATE_LOOPX;
467                 }
468                 TEMPLATE_LOOPY;
469             }
470             return;
471     }
472 }
473
474 void rtg_blitpattern(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t src_addr, uint32_t fgcol, uint32_t bgcol, uint16_t pitch, uint16_t format, uint16_t offset_x, uint16_t offset_y, uint8_t mask, uint8_t draw_mode, uint8_t loop_rows) {
475     if (mask) {}
476     //printf("BlitPattern: %d,%d (%dx%d) @%.8X p:%d dp: %d DM: %d Format: %d\n", x, y, w, h, src_addr, pitch, 2, draw_mode & 0x03, format);
477     //printf("FBA: %.8x - lr: %d\n", framebuffer_addr, loop_rows);
478
479     uint8_t *dptr = &rtg_mem[rtg_address_adj[1] + (x << format) + (y * pitch)];
480     uint8_t *sptr = NULL, *sptr_base = NULL;
481     uint8_t cur_bit = 0, base_bit = 0, cur_byte = 0;
482     uint8_t invert = (draw_mode & DRAWMODE_INVERSVID);
483     uint16_t tmpl_x = 0;
484
485     draw_mode &= 0x03;
486
487         tmpl_x = (offset_x / 8) % 2;
488     cur_bit = base_bit = (0x80 >> (offset_x % 8));
489
490     uint32_t fg_color[3] = {
491         (fgcol & 0xFF),
492         htobe16((fgcol & 0xFFFF)),
493         htobe32(fgcol),
494     };
495     uint32_t bg_color[3] = {
496         (bgcol & 0xFF),
497         htobe16((bgcol & 0xFFFF)),
498         htobe32(bgcol),
499     };
500
501
502     if (src_addr >= PIGFX_RTG_BASE)
503         sptr = &rtg_mem[src_addr - PIGFX_RTG_BASE];
504     else {
505         int i = get_mapped_item_by_address(cfg, src_addr);
506         if (i != -1) {
507             //printf("BlitPattern: Grabbing data from mapped range %d at offset %ld.\n", i, src_addr - cfg->map_offset[i]);
508             sptr = &cfg->map_data[i][src_addr - cfg->map_offset[i]];
509         }
510         else {
511             printf("BlitPattern: Failed to find mapped range for address %.8X\n", src_addr);
512             return;
513         }
514     }
515
516     sptr_base = sptr;
517     sptr += (offset_y % loop_rows) * 2;
518
519     switch (draw_mode) {
520         case DRAWMODE_JAM1:
521             for (uint16_t ys = 0; ys < h; ys++) {
522                 //printf("JAM1: Get byte from sptr[%d] (%p) <- (%p)...\n", tmpl_x, sptr, cfg->map_data[1]);
523                 cur_byte = (invert) ? sptr[tmpl_x] ^ 0xFF : sptr[tmpl_x];
524
525                 for (int xs = 0; xs < w; xs++) {
526                     if (w >= 8 && cur_bit == 0x80 && xs < w - 8) {
527                         SET_RTG_PIXELS(dptr, xs, format, fg_color);
528                         xs += 7;
529                     }
530                     else {
531                         while (cur_bit > 0 && xs < w) {
532                             if (cur_byte & cur_bit) {
533                                 //printf("JAM1: Write byte to dptr[%d] (%p) <- (%p)...\n", xs, dptr, rtg_mem);
534                                 SET_RTG_PIXEL(dptr, xs, format, fg_color);
535                             }
536                             xs++;
537                             cur_bit >>= 1;
538                         }
539                         xs--;
540                         cur_bit = 0x80;
541                     }
542                     PATTERN_LOOPX;
543                 }
544                 PATTERN_LOOPY;
545             }
546             return;
547         case DRAWMODE_JAM2:
548             for (uint16_t ys = 0; ys < h; ys++) {
549                 //printf("JAM2: Get byte from sptr[%d] (%p) <- (%p)...\n", tmpl_x, sptr, cfg->map_data[1]);
550                 cur_byte = (invert) ? sptr[tmpl_x] ^ 0xFF : sptr[tmpl_x];
551
552                 for (int xs = 0; xs < w; xs++) {
553                     //printf("JAM2: Write byte to dptr[%d] (%p) <- (%p)...\n", xs, dptr, rtg_mem);
554                     if (w >= 8 && cur_bit == 0x80 && xs < w - 8) {
555                         SET_RTG_PIXELS_COND(dptr, xs, format, fg_color, bg_color);
556                         xs += 7;
557                     }
558                     else {
559                         while (cur_bit > 0 && xs < w) {
560                             if (cur_byte & cur_bit) {
561                                 SET_RTG_PIXEL(dptr, xs, format, fg_color)
562                             }
563                             else {
564                                 SET_RTG_PIXEL(dptr, xs, format, bg_color)
565                             }
566                             xs++;
567                             cur_bit >>= 1;
568                         }
569                         xs--;
570                         cur_bit = 0x80;
571                     }
572                     PATTERN_LOOPX;
573                 }
574                 PATTERN_LOOPY;
575             }
576             return;
577         case DRAWMODE_COMPLEMENT:
578             for (uint16_t ys = 0; ys < h; ys++) {
579                 cur_byte = (invert) ? sptr[tmpl_x] ^ 0xFF : sptr[tmpl_x];
580
581                 for (int xs = 0; xs < w; xs++) {
582                     if (w >= 8 && cur_bit == 0x80 && xs < w - 8) {
583                         SET_RTG_PIXELS_COND(dptr, xs, format, fg_color, bg_color);
584                         xs += 7;
585                     }
586                     else {
587                         while (cur_bit > 0 && xs < w) {
588                             if (cur_byte & cur_bit) {
589                                 INVERT_RTG_PIXELS(dptr, xs, format)
590                             }
591                             else {
592                                 INVERT_RTG_PIXEL(dptr, xs, format)
593                             }
594                             xs++;
595                             cur_bit >>= 1;
596                         }
597                         xs--;
598                         cur_bit = 0x80;
599                     }
600                     PATTERN_LOOPX;
601                 }
602                 PATTERN_LOOPY;
603             }
604             return;
605     }
606 }