diff options
Diffstat (limited to 'apps/plugins')
-rw-r--r-- | apps/plugins/puzzles/rockbox.c | 854 |
1 files changed, 678 insertions, 176 deletions
diff --git a/apps/plugins/puzzles/rockbox.c b/apps/plugins/puzzles/rockbox.c index 37d15b75b5..7b838ddb79 100644 --- a/apps/plugins/puzzles/rockbox.c +++ b/apps/plugins/puzzles/rockbox.c | |||
@@ -64,6 +64,11 @@ | |||
64 | #define midend_colors midend_colours | 64 | #define midend_colors midend_colours |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | #define PAN_X LCD_WIDTH / 4 | ||
68 | #define PAN_Y LCD_WIDTH / 4 /* not a typo */ | ||
69 | |||
70 | #define ZOOM_FACTOR 3 | ||
71 | |||
67 | static midend *me = NULL; | 72 | static midend *me = NULL; |
68 | static unsigned *colors = NULL; | 73 | static unsigned *colors = NULL; |
69 | static int ncolors = 0; | 74 | static int ncolors = 0; |
@@ -79,41 +84,206 @@ static int help_times = 0; | |||
79 | static void fix_size(void); | 84 | static void fix_size(void); |
80 | 85 | ||
81 | static struct viewport clip_rect; | 86 | static struct viewport clip_rect; |
82 | static bool clipped = false; | 87 | static bool clipped = false, audiobuf_available, zoom_enabled = false; |
83 | extern bool audiobuf_available; | 88 | |
89 | static fb_data *zoom_fb; | ||
90 | static int zoom_w, zoom_h, zoom_clipu, zoom_clipd, zoom_clipl, zoom_clipr; | ||
91 | static int cur_font = FONT_UI; | ||
84 | 92 | ||
85 | static struct settings_t { | 93 | static struct settings_t { |
86 | int slowmo_factor; | 94 | int slowmo_factor; |
87 | bool timerflash, clipoff, shortcuts, no_aa, polyanim; | 95 | bool timerflash, clipoff, shortcuts, no_aa, polyanim; |
88 | } settings; | 96 | } settings; |
89 | 97 | ||
98 | static inline void plot(fb_data *fb, int w, int h, | ||
99 | unsigned x, unsigned y, unsigned long a, | ||
100 | unsigned long r1, unsigned long g1, unsigned long b1, | ||
101 | unsigned cl, unsigned cr, unsigned cu, unsigned cd); | ||
102 | |||
103 | |||
104 | /* re-implementations of many rockbox primitives, adapted to draw into | ||
105 | * a custom framebuffer. */ | ||
106 | static void zoom_drawpixel(int x, int y) | ||
107 | { | ||
108 | if(y < zoom_clipu || y >= zoom_clipd) | ||
109 | return; | ||
110 | |||
111 | if(x < zoom_clipl || x >= zoom_clipr) | ||
112 | return; | ||
113 | |||
114 | zoom_fb[y * zoom_w + x] = rb->lcd_get_foreground(); | ||
115 | } | ||
116 | |||
117 | static void zoom_hline(int l, int r, int y) | ||
118 | { | ||
119 | if(y < zoom_clipu || y >= zoom_clipd) | ||
120 | return; | ||
121 | if(l > r) | ||
122 | { | ||
123 | int t = l; | ||
124 | l = r; | ||
125 | r = t; | ||
126 | } | ||
127 | |||
128 | if(l < zoom_clipl) | ||
129 | l = zoom_clipl; | ||
130 | if(r >= zoom_clipr) | ||
131 | r = zoom_clipr; | ||
132 | |||
133 | fb_data pixel = rb->lcd_get_foreground(); | ||
134 | fb_data *ptr = zoom_fb + y * zoom_w + l; | ||
135 | for(int i = 0; i < r - l; ++i) | ||
136 | *ptr++ = pixel; | ||
137 | } | ||
138 | |||
139 | static void zoom_fillcircle(int cx, int cy, int radius) | ||
140 | { | ||
141 | /* copied straight from xlcd_draw.c */ | ||
142 | int d = 3 - (radius * 2); | ||
143 | int x = 0; | ||
144 | int y = radius; | ||
145 | while(x <= y) | ||
146 | { | ||
147 | zoom_hline(cx - x, cx + x, cy + y); | ||
148 | zoom_hline(cx - x, cx + x, cy - y); | ||
149 | zoom_hline(cx - y, cx + y, cy + x); | ||
150 | zoom_hline(cx - y, cx + y, cy - x); | ||
151 | if(d < 0) | ||
152 | { | ||
153 | d += (x * 4) + 6; | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | d += ((x - y) * 4) + 10; | ||
158 | --y; | ||
159 | } | ||
160 | ++x; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static void zoom_drawcircle(int cx, int cy, int radius) | ||
165 | { | ||
166 | int d = 3 - (radius * 2); | ||
167 | int x = 0; | ||
168 | int y = radius; | ||
169 | while(x <= y) | ||
170 | { | ||
171 | zoom_drawpixel(cx + x, cy + y); | ||
172 | zoom_drawpixel(cx - x, cy + y); | ||
173 | zoom_drawpixel(cx + x, cy - y); | ||
174 | zoom_drawpixel(cx - x, cy - y); | ||
175 | zoom_drawpixel(cx + y, cy + x); | ||
176 | zoom_drawpixel(cx - y, cy + x); | ||
177 | zoom_drawpixel(cx + y, cy - x); | ||
178 | zoom_drawpixel(cx - y, cy - x); | ||
179 | if(d < 0) | ||
180 | { | ||
181 | d += (x * 4) + 6; | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | d += ((x - y) * 4) + 10; | ||
186 | --y; | ||
187 | } | ||
188 | ++x; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | /* This format is pretty crazy: each byte holds the states of 8 pixels | ||
193 | * in a column, with bit 0 being the topmost pixel. Who needs cache | ||
194 | * efficiency? */ | ||
195 | static void zoom_mono_bitmap(const unsigned char *bits, int x, int y, int w, int h) | ||
196 | { | ||
197 | for(int i = 0; i < h / 8 + 1; ++i) | ||
198 | { | ||
199 | for(int j = 0; j < w; ++j) | ||
200 | { | ||
201 | unsigned char column = bits[i * w + j]; | ||
202 | for(int dy = 0; dy < 8; ++dy) | ||
203 | { | ||
204 | if(column & 1) | ||
205 | zoom_fb[(y + i * 8 + dy) * zoom_w + x + j] = LCD_BLACK; | ||
206 | column >>= 1; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | |||
212 | /* Rockbox's alpha format is actually pretty sane: each byte holds | ||
213 | * alpha values for two horizontally adjacent pixels. Low half is | ||
214 | * leftmost pixel. See lcd-16bit-common.c for more info. */ | ||
215 | static void zoom_alpha_bitmap(const unsigned char *bits, int x, int y, int w, int h) | ||
216 | { | ||
217 | const unsigned char *ptr = bits; | ||
218 | unsigned char buf; | ||
219 | int n_read = 0; /* how many 4-bit nibbles we've read (read new when even) */ | ||
220 | for(int i = 0; i < h; ++i) | ||
221 | { | ||
222 | for(int j = 0; j < w; ++j) | ||
223 | { | ||
224 | if(n_read % 2 == 0) | ||
225 | { | ||
226 | buf = *ptr++; | ||
227 | } | ||
228 | int pix_alpha = (n_read++ % 2) ? buf >> 4 : buf & 0xF; /* in reverse order */ | ||
229 | |||
230 | pix_alpha = 15 - pix_alpha; /* correct order now, still 0-F */ | ||
231 | |||
232 | int plot_alpha = (pix_alpha << 4) | pix_alpha; /* so 0xF -> 0xFF, 0x1 -> 0x11, etc. */ | ||
233 | |||
234 | plot(zoom_fb, zoom_w, zoom_h, x + j, y + i, plot_alpha, 0, 0, 0, | ||
235 | 0, zoom_w, 0, zoom_h); | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
90 | /* clipping is implemented through viewports and offsetting | 240 | /* clipping is implemented through viewports and offsetting |
91 | * coordinates */ | 241 | * coordinates */ |
92 | static void rb_clip(void *handle, int x, int y, int w, int h) | 242 | static void rb_clip(void *handle, int x, int y, int w, int h) |
93 | { | 243 | { |
94 | if(!settings.clipoff) | 244 | if(!zoom_enabled) |
95 | { | 245 | { |
96 | LOGF("rb_clip(%d %d %d %d)", x, y, w, h); | 246 | if(!settings.clipoff) |
97 | clip_rect.x = MAX(0, x); | 247 | { |
98 | clip_rect.y = MAX(0, y); | 248 | LOGF("rb_clip(%d %d %d %d)", x, y, w, h); |
99 | clip_rect.width = MIN(LCD_WIDTH, w); | 249 | clip_rect.x = MAX(0, x); |
100 | clip_rect.height = MIN(LCD_HEIGHT, h); | 250 | clip_rect.y = MAX(0, y); |
101 | clip_rect.font = FONT_UI; | 251 | clip_rect.width = MIN(LCD_WIDTH, w); |
102 | clip_rect.drawmode = DRMODE_SOLID; | 252 | clip_rect.height = MIN(LCD_HEIGHT, h); |
253 | clip_rect.font = FONT_UI; | ||
254 | clip_rect.drawmode = DRMODE_SOLID; | ||
103 | #if LCD_DEPTH > 1 | 255 | #if LCD_DEPTH > 1 |
104 | clip_rect.fg_pattern = LCD_DEFAULT_FG; | 256 | clip_rect.fg_pattern = LCD_DEFAULT_FG; |
105 | clip_rect.bg_pattern = LCD_DEFAULT_BG; | 257 | clip_rect.bg_pattern = LCD_DEFAULT_BG; |
106 | #endif | 258 | #endif |
107 | rb->lcd_set_viewport(&clip_rect); | 259 | rb->lcd_set_viewport(&clip_rect); |
108 | clipped = true; | 260 | clipped = true; |
261 | } | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | zoom_clipu = y; | ||
266 | zoom_clipd = y + h; | ||
267 | zoom_clipl = x; | ||
268 | zoom_clipr = x + w; | ||
109 | } | 269 | } |
110 | } | 270 | } |
111 | 271 | ||
112 | static void rb_unclip(void *handle) | 272 | static void rb_unclip(void *handle) |
113 | { | 273 | { |
114 | LOGF("rb_unclip"); | 274 | if(!zoom_enabled) |
115 | rb->lcd_set_viewport(NULL); | 275 | { |
116 | clipped = false; | 276 | LOGF("rb_unclip"); |
277 | rb->lcd_set_viewport(NULL); | ||
278 | clipped = false; | ||
279 | } | ||
280 | else | ||
281 | { | ||
282 | zoom_clipu = 0; | ||
283 | zoom_clipd = LCD_HEIGHT; | ||
284 | zoom_clipl = 0; | ||
285 | zoom_clipr = LCD_WIDTH; | ||
286 | } | ||
117 | } | 287 | } |
118 | 288 | ||
119 | static void offset_coords(int *x, int *y) | 289 | static void offset_coords(int *x, int *y) |
@@ -158,7 +328,8 @@ static void unload_fonts(void) | |||
158 | loaded_fonts[i].status = -3; | 328 | loaded_fonts[i].status = -3; |
159 | } | 329 | } |
160 | access_counter = -1; | 330 | access_counter = -1; |
161 | rb->lcd_setfont(FONT_UI); | 331 | cur_font = FONT_UI; |
332 | rb->lcd_setfont(cur_font); | ||
162 | } | 333 | } |
163 | 334 | ||
164 | static void init_fonttab(void) | 335 | static void init_fonttab(void) |
@@ -241,7 +412,8 @@ static void rb_setfont(int type, int size) | |||
241 | goto fallback; | 412 | goto fallback; |
242 | loaded_fonts[font_idx].last_use = access_counter++; | 413 | loaded_fonts[font_idx].last_use = access_counter++; |
243 | n_fonts++; | 414 | n_fonts++; |
244 | rb->lcd_setfont(loaded_fonts[font_idx].status); | 415 | cur_font = loaded_fonts[font_idx].status; |
416 | rb->lcd_setfont(cur_font); | ||
245 | break; | 417 | break; |
246 | } | 418 | } |
247 | case -2: | 419 | case -2: |
@@ -249,15 +421,16 @@ static void rb_setfont(int type, int size) | |||
249 | goto fallback; | 421 | goto fallback; |
250 | default: | 422 | default: |
251 | loaded_fonts[font_idx].last_use = access_counter++; | 423 | loaded_fonts[font_idx].last_use = access_counter++; |
252 | rb->lcd_setfont(loaded_fonts[font_idx].status); | 424 | cur_font = loaded_fonts[font_idx].status; |
425 | rb->lcd_setfont(cur_font); | ||
253 | break; | 426 | break; |
254 | } | 427 | } |
255 | 428 | ||
256 | return; | 429 | return; |
257 | 430 | ||
258 | fallback: | 431 | fallback: |
259 | 432 | cur_font = type == FONT_FIXED ? FONT_SYSFIXED : FONT_UI; | |
260 | rb->lcd_setfont(type == FONT_FIXED ? FONT_SYSFIXED : FONT_UI); | 433 | rb->lcd_setfont(cur_font); |
261 | 434 | ||
262 | return; | 435 | return; |
263 | } | 436 | } |
@@ -266,37 +439,95 @@ static void rb_draw_text(void *handle, int x, int y, int fonttype, | |||
266 | int fontsize, int align, int color, char *text) | 439 | int fontsize, int align, int color, char *text) |
267 | { | 440 | { |
268 | (void) fontsize; | 441 | (void) fontsize; |
269 | LOGF("rb_draw_text(%d %d %s)", x, y, text); | 442 | if(!zoom_enabled) |
443 | { | ||
444 | LOGF("rb_draw_text(%d %d %s)", x, y, text); | ||
445 | |||
446 | offset_coords(&x, &y); | ||
447 | |||
448 | rb_setfont(fonttype, fontsize); | ||
449 | |||
450 | int w, h; | ||
451 | rb->lcd_getstringsize(text, &w, &h); | ||
452 | |||
453 | if(align & ALIGN_VNORMAL) | ||
454 | y -= h; | ||
455 | else if(align & ALIGN_VCENTRE) | ||
456 | y -= h / 2; | ||
457 | |||
458 | if(align & ALIGN_HCENTRE) | ||
459 | x -= w / 2; | ||
460 | else if(align & ALIGN_HRIGHT) | ||
461 | x -= w; | ||
270 | 462 | ||
271 | offset_coords(&x, &y); | 463 | rb_color(color); |
464 | rb->lcd_set_drawmode(DRMODE_FG); | ||
465 | rb->lcd_putsxy(x, y, text); | ||
466 | rb->lcd_set_drawmode(DRMODE_SOLID); | ||
467 | } | ||
468 | else | ||
469 | { | ||
470 | rb_setfont(fonttype, fontsize); /* size will be clamped if too large */ | ||
272 | 471 | ||
273 | rb_setfont(fonttype, fontsize); | 472 | int w, h; |
473 | rb->lcd_getstringsize(text, &w, &h); | ||
274 | 474 | ||
275 | int w, h; | 475 | if(align & ALIGN_VNORMAL) |
276 | rb->lcd_getstringsize(text, &w, &h); | 476 | y -= h; |
477 | else if(align & ALIGN_VCENTRE) | ||
478 | y -= h / 2; | ||
277 | 479 | ||
278 | if(align & ALIGN_VNORMAL) | 480 | if(align & ALIGN_HCENTRE) |
279 | y -= h; | 481 | x -= w / 2; |
280 | else if(align & ALIGN_VCENTRE) | 482 | else if(align & ALIGN_HRIGHT) |
281 | y -= h / 2; | 483 | x -= w; |
282 | 484 | ||
283 | if(align & ALIGN_HCENTRE) | 485 | /* we need to access the font bitmap directly */ |
284 | x -= w / 2; | 486 | struct font *pf = rb->font_get(cur_font); |
285 | else if(align & ALIGN_HRIGHT) | ||
286 | x -= w; | ||
287 | 487 | ||
288 | rb_color(color); | 488 | while(*text) |
289 | rb->lcd_set_drawmode(DRMODE_FG); | 489 | { |
290 | rb->lcd_putsxy(x, y, text); | 490 | /* still only reads 1 byte */ |
291 | rb->lcd_set_drawmode(DRMODE_SOLID); | 491 | unsigned short c = *text++; |
492 | const unsigned char *bits = rb->font_get_bits(pf, c); | ||
493 | int width = rb->font_get_width(pf, c); | ||
494 | |||
495 | /* straight from lcd-bitmap-common.c */ | ||
496 | #if defined(HAVE_LCD_COLOR) | ||
497 | if (pf->depth) | ||
498 | { | ||
499 | /* lcd_alpha_bitmap_part isn't exported directly. However, | ||
500 | * we can create a null bitmap struct with only an alpha | ||
501 | * channel to make lcd_bmp_part call it for us. */ | ||
502 | |||
503 | zoom_alpha_bitmap(bits, x, y, width, pf->height); | ||
504 | } | ||
505 | else | ||
506 | #endif | ||
507 | zoom_mono_bitmap(bits, x, y, width, pf->height); | ||
508 | x += width; | ||
509 | } | ||
510 | } | ||
292 | } | 511 | } |
293 | 512 | ||
294 | static void rb_draw_rect(void *handle, int x, int y, int w, int h, int color) | 513 | static void rb_draw_rect(void *handle, int x, int y, int w, int h, int color) |
295 | { | 514 | { |
296 | LOGF("rb_draw_rect(%d, %d, %d, %d, %d)", x, y, w, h, color); | 515 | if(!zoom_enabled) |
297 | rb_color(color); | 516 | { |
298 | offset_coords(&x, &y); | 517 | LOGF("rb_draw_rect(%d, %d, %d, %d, %d)", x, y, w, h, color); |
299 | rb->lcd_fillrect(x, y, w, h); | 518 | rb_color(color); |
519 | offset_coords(&x, &y); | ||
520 | rb->lcd_fillrect(x, y, w, h); | ||
521 | } | ||
522 | else | ||
523 | { | ||
524 | /* TODO: clipping */ | ||
525 | for(int i = y; i < y + h; ++i) | ||
526 | for(int j = x; j < x + w; ++j) | ||
527 | { | ||
528 | zoom_fb[i * zoom_w + j] = colors[color]; | ||
529 | } | ||
530 | } | ||
300 | } | 531 | } |
301 | 532 | ||
302 | #define SWAP(a, b, t) do { t = a; a = b; b = t; } while(0); | 533 | #define SWAP(a, b, t) do { t = a; a = b; b = t; } while(0); |
@@ -306,8 +537,9 @@ static void rb_draw_rect(void *handle, int x, int y, int w, int h, int color) | |||
306 | 537 | ||
307 | #define FRACBITS 16 | 538 | #define FRACBITS 16 |
308 | 539 | ||
309 | /* most of our time drawing lines is spent in this function! */ | 540 | /* a goes from 0-255, with a = 255 being fully opaque and a = 0 transparent */ |
310 | static inline void plot(unsigned x, unsigned y, unsigned long a, | 541 | static inline void plot(fb_data *fb, int w, int h, |
542 | unsigned x, unsigned y, unsigned long a, | ||
311 | unsigned long r1, unsigned long g1, unsigned long b1, | 543 | unsigned long r1, unsigned long g1, unsigned long b1, |
312 | unsigned cl, unsigned cr, unsigned cu, unsigned cd) | 544 | unsigned cl, unsigned cr, unsigned cu, unsigned cd) |
313 | { | 545 | { |
@@ -319,7 +551,7 @@ static inline void plot(unsigned x, unsigned y, unsigned long a, | |||
319 | if(!(cl <= x && x < cr && cu <= y && y < cd)) | 551 | if(!(cl <= x && x < cr && cu <= y && y < cd)) |
320 | return; | 552 | return; |
321 | 553 | ||
322 | fb_data *ptr = rb->lcd_framebuffer + y * LCD_WIDTH + x; | 554 | fb_data *ptr = fb + y * w + x; |
323 | fb_data orig = *ptr; | 555 | fb_data orig = *ptr; |
324 | unsigned long r2, g2, b2; | 556 | unsigned long r2, g2, b2; |
325 | #if LCD_DEPTH != 24 | 557 | #if LCD_DEPTH != 24 |
@@ -351,18 +583,28 @@ static inline void plot(unsigned x, unsigned y, unsigned long a, | |||
351 | * lines/sec at full optimization on ipod6g */ | 583 | * lines/sec at full optimization on ipod6g */ |
352 | 584 | ||
353 | /* expects UN-OFFSET coordinates, directly access framebuffer */ | 585 | /* expects UN-OFFSET coordinates, directly access framebuffer */ |
354 | static void draw_antialiased_line(int x0, int y0, int x1, int y1) | 586 | static void draw_antialiased_line(fb_data *fb, int w, int h, int x0, int y0, int x1, int y1) |
355 | { | 587 | { |
356 | /* fixed-point Wu's algorithm, modified for integer-only endpoints */ | 588 | /* fixed-point Wu's algorithm, modified for integer-only endpoints */ |
357 | 589 | ||
358 | /* passed to plot() to avoid re-calculation */ | 590 | /* passed to plot() to avoid re-calculation */ |
359 | unsigned short l = 0, r = LCD_WIDTH, u = 0, d = LCD_HEIGHT; | 591 | unsigned short l = 0, r = w, u = 0, d = h; |
360 | if(clipped) | 592 | if(!zoom_enabled) |
361 | { | 593 | { |
362 | l = clip_rect.x; | 594 | if(clipped) |
363 | r = clip_rect.x + clip_rect.width; | 595 | { |
364 | u = clip_rect.y; | 596 | l = clip_rect.x; |
365 | d = clip_rect.y + clip_rect.height; | 597 | r = clip_rect.x + clip_rect.width; |
598 | u = clip_rect.y; | ||
599 | d = clip_rect.y + clip_rect.height; | ||
600 | } | ||
601 | } | ||
602 | else | ||
603 | { | ||
604 | l = zoom_clipl; | ||
605 | r = zoom_clipr; | ||
606 | u = zoom_clipu; | ||
607 | d = zoom_clipd; | ||
366 | } | 608 | } |
367 | 609 | ||
368 | bool steep = ABS(y1 - y0) > ABS(x1 - x0); | 610 | bool steep = ABS(y1 - y0) > ABS(x1 - x0); |
@@ -402,8 +644,8 @@ static void draw_antialiased_line(int x0, int y0, int x1, int y1) | |||
402 | unsigned y = intery >> FRACBITS; | 644 | unsigned y = intery >> FRACBITS; |
403 | unsigned alpha = fp_fpart(intery, FRACBITS) >> (FRACBITS - 8); | 645 | unsigned alpha = fp_fpart(intery, FRACBITS) >> (FRACBITS - 8); |
404 | 646 | ||
405 | plot(y, x, (1 << 8) - alpha, r1, g1, b1, l, r, u, d); | 647 | plot(fb, w, h, y, x, (1 << 8) - alpha, r1, g1, b1, l, r, u, d); |
406 | plot(y + 1, x, alpha, r1, g1, b1, l, r, u, d); | 648 | plot(fb, w, h, y + 1, x, alpha, r1, g1, b1, l, r, u, d); |
407 | } | 649 | } |
408 | } | 650 | } |
409 | else | 651 | else |
@@ -413,8 +655,8 @@ static void draw_antialiased_line(int x0, int y0, int x1, int y1) | |||
413 | unsigned y = intery >> FRACBITS; | 655 | unsigned y = intery >> FRACBITS; |
414 | unsigned alpha = fp_fpart(intery, FRACBITS) >> (FRACBITS - 8); | 656 | unsigned alpha = fp_fpart(intery, FRACBITS) >> (FRACBITS - 8); |
415 | 657 | ||
416 | plot(x, y, (1 << 8) - alpha, r1, g1, b1, l, r, u, d); | 658 | plot(fb, w, h, x, y, (1 << 8) - alpha, r1, g1, b1, l, r, u, d); |
417 | plot(x, y + 1, alpha, r1, g1, b1, l, r, u, d); | 659 | plot(fb, w, h, x, y + 1, alpha, r1, g1, b1, l, r, u, d); |
418 | } | 660 | } |
419 | } | 661 | } |
420 | } | 662 | } |
@@ -422,16 +664,27 @@ static void draw_antialiased_line(int x0, int y0, int x1, int y1) | |||
422 | static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2, | 664 | static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2, |
423 | int color) | 665 | int color) |
424 | { | 666 | { |
425 | LOGF("rb_draw_line(%d, %d, %d, %d, %d)", x1, y1, x2, y2, color); | 667 | if(!zoom_enabled) |
426 | rb_color(color); | ||
427 | if(settings.no_aa) | ||
428 | { | 668 | { |
429 | offset_coords(&x1, &y1); | 669 | LOGF("rb_draw_line(%d, %d, %d, %d, %d)", x1, y1, x2, y2, color); |
430 | offset_coords(&x2, &y2); | 670 | rb_color(color); |
431 | rb->lcd_drawline(x1, y1, x2, y2); | 671 | if(settings.no_aa) |
672 | { | ||
673 | offset_coords(&x1, &y1); | ||
674 | offset_coords(&x2, &y2); | ||
675 | rb->lcd_drawline(x1, y1, x2, y2); | ||
676 | } | ||
677 | else | ||
678 | draw_antialiased_line(rb->lcd_framebuffer, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2); | ||
432 | } | 679 | } |
433 | else | 680 | else |
434 | draw_antialiased_line(x1, y1, x2, y2); | 681 | { |
682 | /* draw_antialiased_line uses rb->lcd_get_foreground() to get | ||
683 | * the color */ | ||
684 | rb_color(color); | ||
685 | |||
686 | draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2); | ||
687 | } | ||
435 | } | 688 | } |
436 | 689 | ||
437 | #if 0 | 690 | #if 0 |
@@ -489,7 +742,7 @@ static void fill_poly_line(int scanline, int count, int *pxy) | |||
489 | intersection[num_of_intersects] = | 742 | intersection[num_of_intersects] = |
490 | x1+((scanline-y1)*(x2-x1))/(y2-y1); | 743 | x1+((scanline-y1)*(x2-x1))/(y2-y1); |
491 | if ( (direct!=old_direct) | 744 | if ( (direct!=old_direct) |
492 | || (intersection[num_of_intersects] != intersection[num_of_intersects-1]) | 745 | || (intersection[num_of_intersects] != intersection[num_of_intersects-1]) |
493 | ) | 746 | ) |
494 | ++num_of_intersects; | 747 | ++num_of_intersects; |
495 | } | 748 | } |
@@ -531,32 +784,176 @@ static void v_fillarea(int count, int *pxy) | |||
531 | } | 784 | } |
532 | #endif | 785 | #endif |
533 | 786 | ||
787 | /* I'm a horrible person: this was copy-pasta'd straight from | ||
788 | * xlcd_draw.c */ | ||
789 | |||
790 | /* sort the given coordinates by increasing x value */ | ||
791 | static void sort_points_by_increasing_x(int* x1, int* y1, | ||
792 | int* x2, int* y2, | ||
793 | int* x3, int* y3) | ||
794 | { | ||
795 | int x, y; | ||
796 | if (*x1 > *x3) | ||
797 | { | ||
798 | if (*x2 < *x3) /* x2 < x3 < x1 */ | ||
799 | { | ||
800 | x = *x1; *x1 = *x2; *x2 = *x3; *x3 = x; | ||
801 | y = *y1; *y1 = *y2; *y2 = *y3; *y3 = y; | ||
802 | } | ||
803 | else if (*x2 > *x1) /* x3 < x1 < x2 */ | ||
804 | { | ||
805 | x = *x1; *x1 = *x3; *x3 = *x2; *x2 = x; | ||
806 | y = *y1; *y1 = *y3; *y3 = *y2; *y2 = y; | ||
807 | } | ||
808 | else /* x3 <= x2 <= x1 */ | ||
809 | { | ||
810 | x = *x1; *x1 = *x3; *x3 = x; | ||
811 | y = *y1; *y1 = *y3; *y3 = y; | ||
812 | } | ||
813 | } | ||
814 | else | ||
815 | { | ||
816 | if (*x2 < *x1) /* x2 < x1 <= x3 */ | ||
817 | { | ||
818 | x = *x1; *x1 = *x2; *x2 = x; | ||
819 | y = *y1; *y1 = *y2; *y2 = y; | ||
820 | } | ||
821 | else if (*x2 > *x3) /* x1 <= x3 < x2 */ | ||
822 | { | ||
823 | x = *x2; *x2 = *x3; *x3 = x; | ||
824 | y = *y2; *y2 = *y3; *y3 = y; | ||
825 | } | ||
826 | /* else already sorted */ | ||
827 | } | ||
828 | } | ||
829 | |||
830 | #define sort_points_by_increasing_y(x1, y1, x2, y2, x3, y3) \ | ||
831 | sort_points_by_increasing_x(y1, x1, y2, x2, y3, x3) | ||
832 | |||
833 | /* draw a filled triangle, using horizontal lines for speed */ | ||
834 | static void zoom_filltriangle(int x1, int y1, | ||
835 | int x2, int y2, | ||
836 | int x3, int y3) | ||
837 | { | ||
838 | long fp_x1, fp_x2, fp_dx1, fp_dx2; | ||
839 | int y; | ||
840 | sort_points_by_increasing_y(&x1, &y1, &x2, &y2, &x3, &y3); | ||
841 | |||
842 | if (y1 < y3) /* draw */ | ||
843 | { | ||
844 | fp_dx1 = ((x3 - x1) << 16) / (y3 - y1); | ||
845 | fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1); | ||
846 | |||
847 | if (y1 < y2) /* first part */ | ||
848 | { | ||
849 | fp_dx2 = ((x2 - x1) << 16) / (y2 - y1); | ||
850 | fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1); | ||
851 | for (y = y1; y < y2; y++) | ||
852 | { | ||
853 | zoom_hline(fp_x1 >> 16, fp_x2 >> 16, y); | ||
854 | fp_x1 += fp_dx1; | ||
855 | fp_x2 += fp_dx2; | ||
856 | } | ||
857 | } | ||
858 | if (y2 < y3) /* second part */ | ||
859 | { | ||
860 | fp_dx2 = ((x3 - x2) << 16) / (y3 - y2); | ||
861 | fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1); | ||
862 | for (y = y2; y < y3; y++) | ||
863 | { | ||
864 | zoom_hline(fp_x1 >> 16, fp_x2 >> 16, y); | ||
865 | fp_x1 += fp_dx1; | ||
866 | fp_x2 += fp_dx2; | ||
867 | } | ||
868 | } | ||
869 | } | ||
870 | } | ||
871 | |||
534 | static void rb_draw_poly(void *handle, int *coords, int npoints, | 872 | static void rb_draw_poly(void *handle, int *coords, int npoints, |
535 | int fillcolor, int outlinecolor) | 873 | int fillcolor, int outlinecolor) |
536 | { | 874 | { |
537 | LOGF("rb_draw_poly"); | 875 | if(!zoom_enabled) |
538 | |||
539 | if(fillcolor >= 0) | ||
540 | { | 876 | { |
541 | rb_color(fillcolor); | 877 | LOGF("rb_draw_poly"); |
878 | |||
879 | if(fillcolor >= 0) | ||
880 | { | ||
881 | rb_color(fillcolor); | ||
542 | #if 1 | 882 | #if 1 |
543 | /* serious hack: draw a bunch of triangles between adjacent points */ | 883 | /* serious hack: draw a bunch of triangles between adjacent points */ |
544 | /* this generally works, even with some concave polygons */ | 884 | /* this generally works, even with some concave polygons */ |
545 | for(int i = 2; i < npoints; ++i) | 885 | for(int i = 2; i < npoints; ++i) |
886 | { | ||
887 | int x1, y1, x2, y2, x3, y3; | ||
888 | x1 = coords[0]; | ||
889 | y1 = coords[1]; | ||
890 | x2 = coords[(i - 1) * 2]; | ||
891 | y2 = coords[(i - 1) * 2 + 1]; | ||
892 | x3 = coords[i * 2]; | ||
893 | y3 = coords[i * 2 + 1]; | ||
894 | offset_coords(&x1, &y1); | ||
895 | offset_coords(&x2, &y2); | ||
896 | offset_coords(&x3, &y3); | ||
897 | xlcd_filltriangle(x1, y1, | ||
898 | x2, y2, | ||
899 | x3, y3); | ||
900 | |||
901 | #ifdef DEBUG_MENU | ||
902 | if(settings.polyanim) | ||
903 | { | ||
904 | rb->lcd_update(); | ||
905 | rb->sleep(HZ/4); | ||
906 | } | ||
907 | #endif | ||
908 | #if 0 | ||
909 | /* debug code */ | ||
910 | rb->lcd_set_foreground(LCD_RGBPACK(255,0,0)); | ||
911 | rb->lcd_drawpixel(x1, y1); | ||
912 | rb->lcd_drawpixel(x2, y2); | ||
913 | rb->lcd_drawpixel(x3, y3); | ||
914 | rb->lcd_update(); | ||
915 | rb->sleep(HZ); | ||
916 | rb_color(fillcolor); | ||
917 | rb->lcd_drawpixel(x1, y1); | ||
918 | rb->lcd_drawpixel(x2, y2); | ||
919 | rb->lcd_drawpixel(x3, y3); | ||
920 | rb->lcd_update(); | ||
921 | #endif | ||
922 | } | ||
923 | #else | ||
924 | int *pxy = smalloc(sizeof(int) * 2 * npoints + 2); | ||
925 | /* copy points, offsetted */ | ||
926 | for(int i = 0; i < npoints; ++i) | ||
927 | { | ||
928 | pxy[2 * i + 0] = coords[2 * i + 0]; | ||
929 | pxy[2 * i + 1] = coords[2 * i + 1]; | ||
930 | offset_coords(&pxy[2*i+0], &pxy[2*i+1]); | ||
931 | } | ||
932 | v_fillarea(npoints, pxy); | ||
933 | sfree(pxy); | ||
934 | #endif | ||
935 | } | ||
936 | |||
937 | /* draw outlines last so they're not covered by the fill */ | ||
938 | assert(outlinecolor >= 0); | ||
939 | rb_color(outlinecolor); | ||
940 | |||
941 | for(int i = 1; i < npoints; ++i) | ||
546 | { | 942 | { |
547 | int x1, y1, x2, y2, x3, y3; | 943 | int x1, y1, x2, y2; |
548 | x1 = coords[0]; | 944 | x1 = coords[2 * (i - 1)]; |
549 | y1 = coords[1]; | 945 | y1 = coords[2 * (i - 1) + 1]; |
550 | x2 = coords[(i - 1) * 2]; | 946 | x2 = coords[2 * i]; |
551 | y2 = coords[(i - 1) * 2 + 1]; | 947 | y2 = coords[2 * i + 1]; |
552 | x3 = coords[i * 2]; | 948 | if(settings.no_aa) |
553 | y3 = coords[i * 2 + 1]; | 949 | { |
554 | offset_coords(&x1, &y1); | 950 | offset_coords(&x1, &y1); |
555 | offset_coords(&x2, &y2); | 951 | offset_coords(&x2, &y2); |
556 | offset_coords(&x3, &y3); | 952 | rb->lcd_drawline(x1, y1, |
557 | xlcd_filltriangle(x1, y1, | 953 | x2, y2); |
558 | x2, y2, | 954 | } |
559 | x3, y3); | 955 | else |
956 | draw_antialiased_line(rb->lcd_framebuffer, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2); | ||
560 | 957 | ||
561 | #ifdef DEBUG_MENU | 958 | #ifdef DEBUG_MENU |
562 | if(settings.polyanim) | 959 | if(settings.polyanim) |
@@ -565,97 +962,102 @@ static void rb_draw_poly(void *handle, int *coords, int npoints, | |||
565 | rb->sleep(HZ/4); | 962 | rb->sleep(HZ/4); |
566 | } | 963 | } |
567 | #endif | 964 | #endif |
568 | #if 0 | ||
569 | /* debug code */ | ||
570 | rb->lcd_set_foreground(LCD_RGBPACK(255,0,0)); | ||
571 | rb->lcd_drawpixel(x1, y1); | ||
572 | rb->lcd_drawpixel(x2, y2); | ||
573 | rb->lcd_drawpixel(x3, y3); | ||
574 | rb->lcd_update(); | ||
575 | rb->sleep(HZ); | ||
576 | rb_color(fillcolor); | ||
577 | rb->lcd_drawpixel(x1, y1); | ||
578 | rb->lcd_drawpixel(x2, y2); | ||
579 | rb->lcd_drawpixel(x3, y3); | ||
580 | rb->lcd_update(); | ||
581 | #endif | ||
582 | } | 965 | } |
583 | #else | ||
584 | int *pxy = smalloc(sizeof(int) * 2 * npoints + 2); | ||
585 | /* copy points, offsetted */ | ||
586 | for(int i = 0; i < npoints; ++i) | ||
587 | { | ||
588 | pxy[2 * i + 0] = coords[2 * i + 0]; | ||
589 | pxy[2 * i + 1] = coords[2 * i + 1]; | ||
590 | offset_coords(&pxy[2*i+0], &pxy[2*i+1]); | ||
591 | } | ||
592 | v_fillarea(npoints, pxy); | ||
593 | sfree(pxy); | ||
594 | #endif | ||
595 | } | ||
596 | |||
597 | /* draw outlines last so they're not covered by the fill */ | ||
598 | assert(outlinecolor >= 0); | ||
599 | rb_color(outlinecolor); | ||
600 | 966 | ||
601 | for(int i = 1; i < npoints; ++i) | ||
602 | { | ||
603 | int x1, y1, x2, y2; | 967 | int x1, y1, x2, y2; |
604 | x1 = coords[2 * (i - 1)]; | 968 | x1 = coords[0]; |
605 | y1 = coords[2 * (i - 1) + 1]; | 969 | y1 = coords[1]; |
606 | x2 = coords[2 * i]; | 970 | x2 = coords[2 * (npoints - 1)]; |
607 | y2 = coords[2 * i + 1]; | 971 | y2 = coords[2 * (npoints - 1) + 1]; |
608 | if(settings.no_aa) | 972 | if(settings.no_aa) |
609 | { | 973 | { |
610 | offset_coords(&x1, &y1); | 974 | offset_coords(&x1, &y1); |
611 | offset_coords(&x2, &y2); | 975 | offset_coords(&x2, &y2); |
976 | |||
612 | rb->lcd_drawline(x1, y1, | 977 | rb->lcd_drawline(x1, y1, |
613 | x2, y2); | 978 | x2, y2); |
614 | } | 979 | } |
615 | else | 980 | else |
616 | draw_antialiased_line(x1, y1, x2, y2); | 981 | draw_antialiased_line(rb->lcd_framebuffer, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2); |
982 | } | ||
983 | else | ||
984 | { | ||
985 | LOGF("rb_draw_poly"); | ||
617 | 986 | ||
618 | #ifdef DEBUG_MENU | 987 | if(fillcolor >= 0) |
619 | if(settings.polyanim) | ||
620 | { | 988 | { |
621 | rb->lcd_update(); | 989 | rb_color(fillcolor); |
622 | rb->sleep(HZ/4); | 990 | |
991 | /* serious hack: draw a bunch of triangles between adjacent points */ | ||
992 | /* this generally works, even with some concave polygons */ | ||
993 | for(int i = 2; i < npoints; ++i) | ||
994 | { | ||
995 | int x1, y1, x2, y2, x3, y3; | ||
996 | x1 = coords[0]; | ||
997 | y1 = coords[1]; | ||
998 | x2 = coords[(i - 1) * 2]; | ||
999 | y2 = coords[(i - 1) * 2 + 1]; | ||
1000 | x3 = coords[i * 2]; | ||
1001 | y3 = coords[i * 2 + 1]; | ||
1002 | zoom_filltriangle(x1, y1, | ||
1003 | x2, y2, | ||
1004 | x3, y3); | ||
1005 | } | ||
623 | } | 1006 | } |
624 | #endif | ||
625 | } | ||
626 | 1007 | ||
627 | int x1, y1, x2, y2; | 1008 | /* draw outlines last so they're not covered by the fill */ |
628 | x1 = coords[0]; | 1009 | assert(outlinecolor >= 0); |
629 | y1 = coords[1]; | 1010 | rb_color(outlinecolor); |
630 | x2 = coords[2 * (npoints - 1)]; | 1011 | |
631 | y2 = coords[2 * (npoints - 1) + 1]; | 1012 | for(int i = 1; i < npoints; ++i) |
632 | if(settings.no_aa) | 1013 | { |
633 | { | 1014 | int x1, y1, x2, y2; |
634 | offset_coords(&x1, &y1); | 1015 | x1 = coords[2 * (i - 1)]; |
635 | offset_coords(&x2, &y2); | 1016 | y1 = coords[2 * (i - 1) + 1]; |
1017 | x2 = coords[2 * i]; | ||
1018 | y2 = coords[2 * i + 1]; | ||
1019 | draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2); | ||
1020 | } | ||
636 | 1021 | ||
637 | rb->lcd_drawline(x1, y1, | 1022 | int x1, y1, x2, y2; |
638 | x2, y2); | 1023 | x1 = coords[0]; |
1024 | y1 = coords[1]; | ||
1025 | x2 = coords[2 * (npoints - 1)]; | ||
1026 | y2 = coords[2 * (npoints - 1) + 1]; | ||
1027 | draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2); | ||
639 | } | 1028 | } |
640 | else | ||
641 | draw_antialiased_line(x1, y1, x2, y2); | ||
642 | } | 1029 | } |
643 | 1030 | ||
644 | static void rb_draw_circle(void *handle, int cx, int cy, int radius, | 1031 | static void rb_draw_circle(void *handle, int cx, int cy, int radius, |
645 | int fillcolor, int outlinecolor) | 1032 | int fillcolor, int outlinecolor) |
646 | { | 1033 | { |
647 | LOGF("rb_draw_circle(%d, %d, %d)", cx, cy, radius); | 1034 | if(!zoom_enabled) |
648 | offset_coords(&cx, &cy); | ||
649 | |||
650 | if(fillcolor >= 0) | ||
651 | { | 1035 | { |
652 | rb_color(fillcolor); | 1036 | LOGF("rb_draw_circle(%d, %d, %d)", cx, cy, radius); |
653 | xlcd_fillcircle(cx, cy, radius - 1); | 1037 | offset_coords(&cx, &cy); |
1038 | |||
1039 | if(fillcolor >= 0) | ||
1040 | { | ||
1041 | rb_color(fillcolor); | ||
1042 | xlcd_fillcircle(cx, cy, radius - 1); | ||
1043 | } | ||
1044 | |||
1045 | assert(outlinecolor >= 0); | ||
1046 | rb_color(outlinecolor); | ||
1047 | xlcd_drawcircle(cx, cy, radius - 1); | ||
654 | } | 1048 | } |
1049 | else | ||
1050 | { | ||
1051 | if(fillcolor >= 0) | ||
1052 | { | ||
1053 | rb_color(fillcolor); | ||
1054 | zoom_fillcircle(cx, cy, radius - 1); | ||
1055 | } | ||
655 | 1056 | ||
656 | assert(outlinecolor >= 0); | 1057 | assert(outlinecolor >= 0); |
657 | rb_color(outlinecolor); | 1058 | rb_color(outlinecolor); |
658 | xlcd_drawcircle(cx, cy, radius - 1); | 1059 | zoom_drawcircle(cx, cy, radius - 1); |
1060 | } | ||
659 | } | 1061 | } |
660 | 1062 | ||
661 | struct blitter { | 1063 | struct blitter { |
@@ -680,11 +1082,14 @@ static void trim_rect(int *x, int *y, int *w, int *h) | |||
680 | x1 = *x + *w; | 1082 | x1 = *x + *w; |
681 | y1 = *y + *h; | 1083 | y1 = *y + *h; |
682 | 1084 | ||
1085 | int screenw = zoom_enabled ? zoom_w : LCD_WIDTH; | ||
1086 | int screenh = zoom_enabled ? zoom_h : LCD_HEIGHT; | ||
1087 | |||
683 | /* Clip each coordinate at both extremes of the canvas */ | 1088 | /* Clip each coordinate at both extremes of the canvas */ |
684 | x0 = (x0 < 0 ? 0 : x0 > LCD_WIDTH - 1 ? LCD_WIDTH - 1: x0); | 1089 | x0 = (x0 < 0 ? 0 : x0 > screenw - 1 ? screenw - 1: x0); |
685 | x1 = (x1 < 0 ? 0 : x1 > LCD_WIDTH - 1 ? LCD_WIDTH - 1: x1); | 1090 | x1 = (x1 < 0 ? 0 : x1 > screenw - 1 ? screenw - 1: x1); |
686 | y0 = (y0 < 0 ? 0 : y0 > LCD_HEIGHT - 1 ? LCD_HEIGHT - 1: y0); | 1091 | y0 = (y0 < 0 ? 0 : y0 > screenh - 1 ? screenh - 1: y0); |
687 | y1 = (y1 < 0 ? 0 : y1 > LCD_HEIGHT - 1 ? LCD_HEIGHT - 1: y1); | 1092 | y1 = (y1 < 0 ? 0 : y1 > screenh - 1 ? screenh - 1: y1); |
688 | 1093 | ||
689 | /* Transform back into x,y,w,h to return */ | 1094 | /* Transform back into x,y,w,h to return */ |
690 | *x = x0; | 1095 | *x = x0; |
@@ -723,12 +1128,13 @@ static void rb_blitter_save(void *handle, blitter *bl, int x, int y) | |||
723 | { | 1128 | { |
724 | int w = bl->bmp.width, h = bl->bmp.height; | 1129 | int w = bl->bmp.width, h = bl->bmp.height; |
725 | trim_rect(&x, &y, &w, &h); | 1130 | trim_rect(&x, &y, &w, &h); |
1131 | fb_data *fb = zoom_enabled ? zoom_fb : rb->lcd_framebuffer; | ||
726 | LOGF("rb_blitter_save(%d, %d, %d, %d)", x, y, w, h); | 1132 | LOGF("rb_blitter_save(%d, %d, %d, %d)", x, y, w, h); |
727 | for(int i = 0; i < h; ++i) | 1133 | for(int i = 0; i < h; ++i) |
728 | { | 1134 | { |
729 | /* copy line-by-line */ | 1135 | /* copy line-by-line */ |
730 | rb->memcpy(bl->bmp.data + sizeof(fb_data) * i * w, | 1136 | rb->memcpy(bl->bmp.data + sizeof(fb_data) * i * w, |
731 | rb->lcd_framebuffer + (y + i) * LCD_WIDTH + x, | 1137 | fb + (y + i) * LCD_WIDTH + x, |
732 | w * sizeof(fb_data)); | 1138 | w * sizeof(fb_data)); |
733 | } | 1139 | } |
734 | bl->x = x; | 1140 | bl->x = x; |
@@ -748,9 +1154,24 @@ static void rb_blitter_load(void *handle, blitter *bl, int x, int y) | |||
748 | if(x == BLITTER_FROMSAVED) x = bl->x; | 1154 | if(x == BLITTER_FROMSAVED) x = bl->x; |
749 | if(y == BLITTER_FROMSAVED) y = bl->y; | 1155 | if(y == BLITTER_FROMSAVED) y = bl->y; |
750 | 1156 | ||
751 | offset_coords(&x, &y); | 1157 | if(!zoom_enabled) |
1158 | offset_coords(&x, &y); | ||
1159 | |||
752 | trim_rect(&x, &y, &w, &h); | 1160 | trim_rect(&x, &y, &w, &h); |
753 | rb->lcd_bitmap((fb_data*)bl->bmp.data, x, y, w, h); | 1161 | |
1162 | if(!zoom_enabled) | ||
1163 | { | ||
1164 | rb->lcd_bitmap((fb_data*)bl->bmp.data, x, y, w, h); | ||
1165 | } | ||
1166 | else | ||
1167 | { | ||
1168 | for(int i = 0; i < h; ++i) | ||
1169 | { | ||
1170 | rb->memcpy(zoom_fb + i * zoom_w + x, | ||
1171 | bl->bmp.data + sizeof(fb_data) * i * w, | ||
1172 | w * sizeof(fb_data)); | ||
1173 | } | ||
1174 | } | ||
754 | } | 1175 | } |
755 | 1176 | ||
756 | static bool need_draw_update = false; | 1177 | static bool need_draw_update = false; |
@@ -793,11 +1214,17 @@ static void rb_start_draw(void *handle) | |||
793 | static void rb_end_draw(void *handle) | 1214 | static void rb_end_draw(void *handle) |
794 | { | 1215 | { |
795 | (void) handle; | 1216 | (void) handle; |
1217 | if(!zoom_enabled) | ||
1218 | { | ||
1219 | LOGF("rb_end_draw"); | ||
796 | 1220 | ||
797 | LOGF("rb_end_draw"); | 1221 | if(need_draw_update) |
798 | 1222 | rb->lcd_update_rect(MAX(0, ud_l), MAX(0, ud_u), MIN(LCD_WIDTH, ud_r - ud_l), MIN(LCD_HEIGHT, ud_d - ud_u)); | |
799 | if(need_draw_update) | 1223 | } |
800 | rb->lcd_update_rect(MAX(0, ud_l), MAX(0, ud_u), MIN(LCD_WIDTH, ud_r - ud_l), MIN(LCD_HEIGHT, ud_d - ud_u)); | 1224 | else |
1225 | { | ||
1226 | /* stubbed */ | ||
1227 | } | ||
801 | } | 1228 | } |
802 | 1229 | ||
803 | static char *titlebar = NULL; | 1230 | static char *titlebar = NULL; |
@@ -824,7 +1251,8 @@ static void draw_title(void) | |||
824 | rb_unclip(NULL); | 1251 | rb_unclip(NULL); |
825 | 1252 | ||
826 | int h; | 1253 | int h; |
827 | rb->lcd_setfont(FONT_UI); | 1254 | cur_font = FONT_UI; |
1255 | rb->lcd_setfont(cur_font); | ||
828 | rb->lcd_getstringsize(str, NULL, &h); | 1256 | rb->lcd_getstringsize(str, NULL, &h); |
829 | 1257 | ||
830 | rb->lcd_set_foreground(BG_COLOR); | 1258 | rb->lcd_set_foreground(BG_COLOR); |
@@ -866,6 +1294,73 @@ const drawing_api rb_drawing = { | |||
866 | NULL, | 1294 | NULL, |
867 | }; | 1295 | }; |
868 | 1296 | ||
1297 | /* render to a virtual framebuffer and let the user pan (but not make any moves) */ | ||
1298 | static void zoom(void) | ||
1299 | { | ||
1300 | zoom_w = LCD_WIDTH * ZOOM_FACTOR, zoom_h = LCD_HEIGHT * ZOOM_FACTOR; | ||
1301 | |||
1302 | zoom_clipu = 0; | ||
1303 | zoom_clipd = zoom_h; | ||
1304 | zoom_clipl = 0; | ||
1305 | zoom_clipr = zoom_w; | ||
1306 | |||
1307 | midend_size(me, &zoom_w, &zoom_h, TRUE); | ||
1308 | |||
1309 | /* allocate a framebuffer */ | ||
1310 | zoom_fb = smalloc(zoom_w * zoom_h * sizeof(fb_data)); | ||
1311 | zoom_enabled = true; | ||
1312 | |||
1313 | /* draws go to the enlarged framebuffer */ | ||
1314 | midend_force_redraw(me); | ||
1315 | |||
1316 | int x = 0, y = 0; | ||
1317 | |||
1318 | rb->lcd_bitmap_part(zoom_fb, x, y, STRIDE(SCREEN_MAIN, zoom_w, zoom_h), | ||
1319 | 0, 0, LCD_WIDTH, LCD_HEIGHT); | ||
1320 | rb->lcd_update(); | ||
1321 | |||
1322 | /* pan around the image */ | ||
1323 | while(1) | ||
1324 | { | ||
1325 | int button = rb->button_get(true); | ||
1326 | switch(button) | ||
1327 | { | ||
1328 | case BTN_UP: | ||
1329 | y -= PAN_Y; /* clamped later */ | ||
1330 | break; | ||
1331 | case BTN_DOWN: | ||
1332 | y += PAN_Y; /* clamped later */ | ||
1333 | break; | ||
1334 | case BTN_LEFT: | ||
1335 | x -= PAN_X; /* clamped later */ | ||
1336 | break; | ||
1337 | case BTN_RIGHT: | ||
1338 | x += PAN_X; /* clamped later */ | ||
1339 | break; | ||
1340 | case BTN_PAUSE: | ||
1341 | zoom_enabled = false; | ||
1342 | sfree(zoom_fb); | ||
1343 | fix_size(); | ||
1344 | return; | ||
1345 | default: | ||
1346 | break; | ||
1347 | } | ||
1348 | |||
1349 | if(y < 0) | ||
1350 | y = 0; | ||
1351 | if(x < 0) | ||
1352 | x = 0; | ||
1353 | if(y + LCD_HEIGHT >= zoom_h) | ||
1354 | y = zoom_h - LCD_HEIGHT; | ||
1355 | if(x + LCD_WIDTH >= zoom_w) | ||
1356 | x = zoom_w - LCD_WIDTH; | ||
1357 | |||
1358 | rb->lcd_bitmap_part(zoom_fb, x, y, STRIDE(SCREEN_MAIN, zoom_w, zoom_h), | ||
1359 | 0, 0, LCD_WIDTH, LCD_HEIGHT); | ||
1360 | rb->lcd_update(); | ||
1361 | } | ||
1362 | } | ||
1363 | |||
869 | void frontend_default_color(frontend *fe, float *out) | 1364 | void frontend_default_color(frontend *fe, float *out) |
870 | { | 1365 | { |
871 | *out++ = BG_R; | 1366 | *out++ = BG_R; |
@@ -1123,7 +1618,8 @@ static bool config_menu(void) | |||
1123 | char *title; | 1618 | char *title; |
1124 | config_item *config = midend_get_config(me, CFG_SETTINGS, &title); | 1619 | config_item *config = midend_get_config(me, CFG_SETTINGS, &title); |
1125 | 1620 | ||
1126 | rb->lcd_setfont(FONT_UI); | 1621 | cur_font = FONT_UI; |
1622 | rb->lcd_setfont(cur_font); | ||
1127 | 1623 | ||
1128 | bool success = false; | 1624 | bool success = false; |
1129 | 1625 | ||
@@ -1318,7 +1814,8 @@ static void full_help(const char *name) | |||
1318 | rb->lcd_set_foreground(LCD_WHITE); | 1814 | rb->lcd_set_foreground(LCD_WHITE); |
1319 | rb->lcd_set_background(LCD_BLACK); | 1815 | rb->lcd_set_background(LCD_BLACK); |
1320 | unload_fonts(); | 1816 | unload_fonts(); |
1321 | rb->lcd_setfont(FONT_UI); | 1817 | cur_font = FONT_UI; |
1818 | rb->lcd_setfont(cur_font); | ||
1322 | 1819 | ||
1323 | char *buf = smalloc(help_text_len); | 1820 | char *buf = smalloc(help_text_len); |
1324 | LZ4_decompress_tiny(help_text, buf, help_text_len); | 1821 | LZ4_decompress_tiny(help_text, buf, help_text_len); |
@@ -1354,7 +1851,7 @@ static void bench_aa(void) | |||
1354 | int i = 0; | 1851 | int i = 0; |
1355 | while(*rb->current_tick < next) | 1852 | while(*rb->current_tick < next) |
1356 | { | 1853 | { |
1357 | draw_antialiased_line(0, 0, 20, 31); | 1854 | draw_antialiased_line(rb->lcd_framebuffer, LCD_WIDTH, LCD_HEIGHT, 0, 0, 20, 31); |
1358 | ++i; | 1855 | ++i; |
1359 | } | 1856 | } |
1360 | rb->splashf(HZ, "%d AA lines/sec", i); | 1857 | rb->splashf(HZ, "%d AA lines/sec", i); |
@@ -1460,7 +1957,7 @@ static int pausemenu_cb(int action, const struct menu_item_ex *this_item) | |||
1460 | if(!midend_get_presets(me, NULL)->n_entries) | 1957 | if(!midend_get_presets(me, NULL)->n_entries) |
1461 | return ACTION_EXIT_MENUITEM; | 1958 | return ACTION_EXIT_MENUITEM; |
1462 | break; | 1959 | break; |
1463 | case 10: | 1960 | case 11: |
1464 | #if defined(FOR_REAL) && defined(DEBUG_MENU) | 1961 | #if defined(FOR_REAL) && defined(DEBUG_MENU) |
1465 | if(debug_mode) | 1962 | if(debug_mode) |
1466 | break; | 1963 | break; |
@@ -1468,7 +1965,7 @@ static int pausemenu_cb(int action, const struct menu_item_ex *this_item) | |||
1468 | #else | 1965 | #else |
1469 | break; | 1966 | break; |
1470 | #endif | 1967 | #endif |
1471 | case 11: | 1968 | case 12: |
1472 | if(!midend_which_game(me)->can_configure) | 1969 | if(!midend_which_game(me)->can_configure) |
1473 | return ACTION_EXIT_MENUITEM; | 1970 | return ACTION_EXIT_MENUITEM; |
1474 | break; | 1971 | break; |
@@ -1507,6 +2004,7 @@ static int pause_menu(void) | |||
1507 | "Undo", | 2004 | "Undo", |
1508 | "Redo", | 2005 | "Redo", |
1509 | "Solve", | 2006 | "Solve", |
2007 | "Zoom In", | ||
1510 | "Quick Help", | 2008 | "Quick Help", |
1511 | "Extensive Help", | 2009 | "Extensive Help", |
1512 | "Playback Control", | 2010 | "Playback Control", |
@@ -1568,15 +2066,18 @@ static int pause_menu(void) | |||
1568 | break; | 2066 | break; |
1569 | } | 2067 | } |
1570 | case 6: | 2068 | case 6: |
1571 | quick_help(); | 2069 | zoom(); |
1572 | break; | 2070 | break; |
1573 | case 7: | 2071 | case 7: |
1574 | full_help(midend_which_game(me)->name); | 2072 | quick_help(); |
1575 | break; | 2073 | break; |
1576 | case 8: | 2074 | case 8: |
1577 | playback_control(NULL); | 2075 | full_help(midend_which_game(me)->name); |
1578 | break; | 2076 | break; |
1579 | case 9: | 2077 | case 9: |
2078 | playback_control(NULL); | ||
2079 | break; | ||
2080 | case 10: | ||
1580 | if(presets_menu()) | 2081 | if(presets_menu()) |
1581 | { | 2082 | { |
1582 | midend_new_game(me); | 2083 | midend_new_game(me); |
@@ -1586,12 +2087,12 @@ static int pause_menu(void) | |||
1586 | quit = true; | 2087 | quit = true; |
1587 | } | 2088 | } |
1588 | break; | 2089 | break; |
1589 | case 10: | 2090 | case 11: |
1590 | #ifdef DEBUG_MENU | 2091 | #ifdef DEBUG_MENU |
1591 | debug_menu(); | 2092 | debug_menu(); |
1592 | #endif | 2093 | #endif |
1593 | break; | 2094 | break; |
1594 | case 11: | 2095 | case 12: |
1595 | if(config_menu()) | 2096 | if(config_menu()) |
1596 | { | 2097 | { |
1597 | midend_new_game(me); | 2098 | midend_new_game(me); |
@@ -1601,9 +2102,9 @@ static int pause_menu(void) | |||
1601 | quit = true; | 2102 | quit = true; |
1602 | } | 2103 | } |
1603 | break; | 2104 | break; |
1604 | case 12: | ||
1605 | return -2; | ||
1606 | case 13: | 2105 | case 13: |
2106 | return -2; | ||
2107 | case 14: | ||
1607 | return -3; | 2108 | return -3; |
1608 | default: | 2109 | default: |
1609 | break; | 2110 | break; |
@@ -1846,7 +2347,8 @@ static size_t giant_buffer_len = 0; /* set on start */ | |||
1846 | static void fix_size(void) | 2347 | static void fix_size(void) |
1847 | { | 2348 | { |
1848 | int w = LCD_WIDTH, h = LCD_HEIGHT, h_x; | 2349 | int w = LCD_WIDTH, h = LCD_HEIGHT, h_x; |
1849 | rb->lcd_setfont(FONT_UI); | 2350 | cur_font = FONT_UI; |
2351 | rb->lcd_setfont(cur_font); | ||
1850 | rb->lcd_getstringsize("X", NULL, &h_x); | 2352 | rb->lcd_getstringsize("X", NULL, &h_x); |
1851 | h -= h_x; | 2353 | h -= h_x; |
1852 | midend_size(me, &w, &h, TRUE); | 2354 | midend_size(me, &w, &h, TRUE); |