source: trunk/core/gui_draw.c @ 1250

Revision 1250, 19.8 KB checked in by philmoz, 22 months ago (diff)

Fix for CHDK sometimes forgetting to redraw the menus.
See - http://chdk.setepontos.com/index.php?topic=6659.0
Added an optional system for detecting if the camera firmware has erased the screen, and force a menu redraw (define CAM_DETECT_SCREEN_ERASE in platform_camera.h to enable).
Updated comment for CAM_MENU_BORDERWIDTH in camera.h

  • Property svn:eol-style set to native
Line 
1#include "stdlib.h"
2#include "platform.h"
3#include "core.h"
4#include "keyboard.h"
5#include "conf.h"
6#include "font.h"
7#include "gui_draw.h"
8
9//-------------------------------------------------------------------
10static char*    frame_buffer[2];
11unsigned int    screen_width=0, screen_height=0, screen_size=0;
12unsigned int    screen_buffer_width=0, screen_buffer_height=0, screen_buffer_size=0;
13void            (*draw_pixel_proc)(unsigned int offset, color cl);
14
15//-------------------------------------------------------------------
16static void draw_pixel_std(unsigned int offset, color cl) {
17    frame_buffer[0][offset] = frame_buffer[1][offset] = cl & 0xff;
18}
19
20//-------------------------------------------------------------------
21void draw_set_draw_proc(void (*pixel_proc)(unsigned int offset, color cl)) {
22    draw_pixel_proc = (pixel_proc)?pixel_proc:draw_pixel_std;
23}
24
25#if CAM_USES_ASPECT_CORRECTION //nandoide sept-2009
26
27unsigned int (*aspect_xcorrection_proc)(unsigned int x);
28unsigned int (*aspect_ycorrection_proc)(unsigned int y);
29
30//-------------------------------------------------------------------
31unsigned int aspect_xcorrection_std(unsigned int x) {
32   return (ASPECT_XCORRECTION(x));
33}
34//-------------------------------------------------------------------
35static unsigned int aspect_ycorrection_std(unsigned int y) {
36   return (ASPECT_YCORRECTION(y));
37}
38//-------------------------------------------------------------------
39unsigned int aspect_xcorrection_games_360(unsigned int x) {
40   return (ASPECT_GAMES_XCORRECTION(x));
41}
42//-------------------------------------------------------------------
43unsigned int aspect_ycorrection_games_360(unsigned int y) {
44   return (ASPECT_GAMES_YCORRECTION(y));
45}
46//-------------------------------------------------------------------
47void draw_set_aspect_xcorrection_proc(unsigned int (*xcorrection_proc)(unsigned int x)) {
48   aspect_xcorrection_proc = (xcorrection_proc)?xcorrection_proc:aspect_xcorrection_std;
49}
50//-------------------------------------------------------------------
51void draw_set_aspect_ycorrection_proc(unsigned int (*ycorrection_proc)(unsigned int y)) {
52   aspect_ycorrection_proc = (ycorrection_proc)?ycorrection_proc:aspect_ycorrection_std;
53}
54//-------------------------------------------------------------------
55void draw_set_environment(unsigned int (*xcorrection_proc)(unsigned int x),
56                                       unsigned int (*ycorrection_proc)(unsigned int y),
57                                       int screenx, int screeny ) {
58   screen_width=screenx;
59   screen_height=screeny;
60   draw_set_aspect_xcorrection_proc(xcorrection_proc);
61   draw_set_aspect_ycorrection_proc(ycorrection_proc);
62}
63
64#endif
65
66//-------------------------------------------------------------------
67#ifdef CAM_DETECT_SCREEN_ERASE
68
69#define GUARD_VAL   SCREEN_COLOR
70
71void draw_set_guard()
72{
73    *((unsigned char*)(frame_buffer[0])) = GUARD_VAL;
74    *((unsigned char*)(frame_buffer[1])) = GUARD_VAL;
75}
76
77int draw_test_guard()
78{
79    if (*((unsigned char*)(frame_buffer[0])) != GUARD_VAL) return 0;
80    if (*((unsigned char*)(frame_buffer[1])) != GUARD_VAL) return 0;
81    return 1;
82}
83
84// Test a pixel value in both frame buffers, returns 0 if either doesn't match or co-ords out of range
85int draw_test_pixel(coord x, coord y, color c)
86{
87    if (x >= screen_width || y >= screen_height) return 0;
88#if CAM_USES_ASPECT_CORRECTION
89    return (frame_buffer[0][y * screen_buffer_width + aspect_xcorrection_proc(x)] == c) &&
90           (frame_buffer[1][y * screen_buffer_width + aspect_xcorrection_proc(x)] == c);
91#else
92    return (frame_buffer[0][y * screen_buffer_width + x] == c) &&
93           (frame_buffer[1][y * screen_buffer_width + x] == c);
94#endif
95}
96
97#endif
98
99//-------------------------------------------------------------------
100void draw_init() {
101    register int i;
102
103    screen_width = vid_get_bitmap_screen_width();
104    screen_height  = vid_get_bitmap_screen_height();
105    screen_size = screen_width * screen_height;
106    screen_buffer_width = vid_get_bitmap_buffer_width();
107    screen_buffer_height = vid_get_bitmap_buffer_height();
108    screen_buffer_size = screen_buffer_width * screen_buffer_height;
109    frame_buffer[0] = vid_get_bitmap_fb();
110    frame_buffer[1] = frame_buffer[0] + screen_buffer_size;
111    draw_set_draw_proc(NULL);
112    #if CAM_USES_ASPECT_CORRECTION
113      draw_set_aspect_xcorrection_proc(NULL);
114      draw_set_aspect_ycorrection_proc(NULL);
115    #endif
116
117#ifdef CAM_DETECT_SCREEN_ERASE
118    draw_set_guard();
119#endif
120}
121
122#if CAM_USES_ASPECT_CORRECTION
123
124// nandoide: sept-2009: draw_pixel_xarray draws a horizontal line at height y, from xi to xf
125// includes a correction of aspect ratio on x from buffer to screen
126// can be used to optimize computations (offset calculus) in other primitives (rectangles, and so on...) and compensate tne increase in computation time
127// of aspect ratio correction.
128// sx200is:
129//    we have a 720x240 efective memory buffer (in a 960x270 physical memory buffer) and a screen of 320x240 (!)
130//   the drawing primitives work on screen coordinates (the other approach, less modular it's to paint on buffer coordinates, deforming on x direction, I think it would be harder to live with it
131//   and requires a full bunch of changes of the actual software).
132//   then we do paint a x coordinate transformed in buffer by a factor 720/320=9/4 and then we do correct (deform) x  to x*9/4 previously to save it on buffer
133// other:
134//     the default mapping is x=x (NOTE: I think important to check that on every model, and necessary in newer models. it seems to me very strange screen sizes of 360x240 for 4/3 and 480/240 for 16/9 (SX1S).
135
136void draw_pixel_xarray(coord y, coord xi, coord xf, color cl) {
137    if (xi >= screen_width || y >= screen_height) return;
138    else {
139        unsigned int offsetx, offsetxf, offsetxi, offsety;
140        offsety=aspect_ycorrection_proc(y) * screen_buffer_width;
141        offsetxi = aspect_xcorrection_proc(xi);
142        xf++;
143        offsetxf= (xf >= screen_width) ? screen_buffer_width - 1 :  aspect_xcorrection_proc(xf);
144        for (offsetx=offsetxi; offsetx<=offsetxf-1; offsetx++) {
145           draw_pixel_proc(offsety+offsetx, cl);
146        }
147    }
148}
149
150#if  CAM_USES_ASPECT_YCORRECTION
151//generalization for cases than we need to correct both coordinates: symetric algorithm
152void draw_pixel_rectanglearray(coord yi, coord yf, coord xi, coord xf, color cl) {
153    if (xi >= screen_width || yi >= screen_height) return;
154    else {
155        unsigned int offsetx, offsetxf, offsetxi, offsety, offsetyf, offsetyi, offset;
156        offsetyi = aspect_ycorrection_proc(yi);
157        yf++;
158        offsetyf= (yf >= screen_height) ? screen_buffer_height - 1 :  aspect_ycorrection_proc(yf);
159        offsetxi = aspect_xcorrection_proc(xi);
160        xf++;
161        offsetxf= (xf >= screen_width) ? screen_buffer_width - 1 :  aspect_xcorrection_proc(xf);
162        for (offsety=offsetyi; offsety<=offsetyf-1; offsety++) {
163          offset=offsety*screen_buffer_width;
164          for (offsetx=offsetxi; offsetx<=offsetxf-1; offsetx++) {
165             draw_pixel_proc(offset+offsetx, cl);
166          }
167        }
168    }
169}
170#endif
171
172// nandoide sept-2009: draw_pixel version that calls draw_pixel_xarray for calculations. It's necessary to paint more than a pixel. In other case we got holes due
173// to the nature of discrete drawing algoritms and the aspect-ratio correction.
174// so, we need paint a horizontal line from the point coordinate to the next point (x to x+1)
175// it's a brute force algorithm and it's possible that we have aliasing problems ...
176// but the display seems OK on sx200is ( good!) , due perhaps to the fact that the system makes a final reverse (bilinear?) resize 720 -> 320, to display the buffer data.
177
178void draw_pixel(coord x, coord y, color cl) {
179  #if  CAM_USES_ASPECT_YCORRECTION
180    draw_pixel_rectanglearray(y, y, x, x, cl);
181  #else
182    draw_pixel_xarray(y, x, x, cl);
183  #endif
184}
185
186color draw_get_pixel(coord x, coord y) {
187    if (x >= screen_width || y >= screen_height) return 0;
188    return frame_buffer[0][y * screen_buffer_width + aspect_xcorrection_proc(x) ];
189}
190#else
191//-------------------------------------------------------------------
192void draw_pixel(coord x, coord y, color cl) {
193    if (x >= screen_width || y >= screen_height) return;
194    else {
195        register unsigned int offset = y * screen_buffer_width + x;
196        draw_pixel_proc(offset, cl);
197   }
198}
199
200//-------------------------------------------------------------------
201color draw_get_pixel(coord x, coord y) {
202    if (x >= screen_width || y >= screen_height) return 0;
203    return frame_buffer[0][y * screen_buffer_width + x];
204}
205#endif
206
207//-------------------------------------------------------------------
208#define swap(v1, v2)   {v1^=v2; v2^=v1; v1^=v2;}
209//-------------------------------------------------------------------
210void draw_line(coord x1, coord y1, coord x2, coord y2, color cl) {
211     unsigned char steep = abs(y2 - y1) > abs(x2 - x1);
212     if (steep) {
213         swap(x1, y1);
214         swap(x2, y2);
215     }
216     if (x1 > x2) {
217         swap(x1, x2);
218         swap(y1, y2);
219     }
220     int deltax = x2 - x1;
221     int deltay = abs(y2 - y1);
222     int error = 0;
223     int y = y1;
224     int ystep = (y1 < y2)?1:-1;
225     int x;
226     for (x=x1; x<=x2; ++x) {
227         if (steep) draw_pixel(y, x, cl);
228         else draw_pixel(x, y, cl);
229         error += deltay;
230         if ((error<<1) >= deltax) {
231             y += ystep;
232             error -= deltax;
233         }
234     }
235}
236//-------------------------------------------------------------------
237void draw_hline(coord x, coord y, int len, color cl)
238{
239    #if CAM_USES_ASPECT_CORRECTION &&  !CAM_USES_ASPECT_YCORRECTION
240      draw_pixel_xarray(y, x, x+len, cl);
241    #else
242      for (; len>=0; len--, x++) {
243          draw_pixel(x, y, cl);
244      }
245    #endif
246}
247
248void draw_vline(coord x, coord y, int len, color cl)
249{
250    for (; len>=0; len--, y++) {
251      draw_pixel(x, y, cl);
252    }
253}
254//-------------------------------------------------------------------
255
256static unsigned int xMin, yMin, xMax, yMax;
257
258static void draw_rectangle(coord x1, coord y1, coord x2, coord y2, color cl, int round)
259{
260    register unsigned int x, y;
261
262    if (x1>x2) {
263        xMax=x1; xMin=x2;
264    } else {
265        xMin=x1; xMax=x2;
266    }
267    if (y1>y2) {
268        yMax=y1; yMin=y2;
269    } else {
270        yMin=y1; yMax=y2;
271    }
272    if (xMax>=screen_width) xMax=screen_width-1;
273    if (xMin>=screen_width) xMin=screen_width-1;
274    if (yMax>=screen_height) yMax=screen_height-1;
275    if (yMin>=screen_height) yMin=screen_height-1;
276
277    for (y=yMin+(round<<1); y<=yMax-(round<<1); ++y) {
278      draw_pixel(xMin, y, cl);
279      draw_pixel(xMax, y, cl);
280    }
281    #if CAM_USES_ASPECT_CORRECTION &&  !CAM_USES_ASPECT_YCORRECTION
282      draw_pixel_xarray(yMin, xMin+1+round, xMax-1-round, cl);
283      draw_pixel_xarray(yMax, xMin+1+round, xMax-1-round, cl);
284    #else
285      for (x=xMin+1+round; x<=xMax-1-round; ++x) {
286          draw_pixel(x, yMin, cl);
287          draw_pixel(x, yMax, cl);
288      }
289    #endif
290}
291
292//-------------------------------------------------------------------
293void draw_rect(coord x1, coord y1, coord x2, coord y2, color cl) {
294    draw_rectangle(x1,y1,x2,y2,cl&0xff,0);
295}
296
297void draw_rect_thick(coord x1, coord y1, coord x2, coord y2, color cl, int thickness) {
298    int i;
299    cl = cl & 0xff;
300    for (i=0; i<thickness; i++)
301    {
302        draw_rectangle(x1+i,y1+i,x2-i,y2-i,cl,0);
303    }
304}
305
306void draw_rect_shadow(coord x1, coord y1, coord x2, coord y2, color cl, int thickness) {
307    int i;
308    cl = cl & 0xff;
309    for (i=0; i<thickness; i++)
310    {
311        draw_rectangle(x1+i,y1+i,x2+i,y2+i,cl,0);
312    }
313}
314//-------------------------------------------------------------------
315void draw_round_rect(coord x1, coord y1, coord x2, coord y2, color cl) {
316    draw_rectangle(x1,y1,x2,y2,cl&0xff,1);
317}
318//-------------------------------------------------------------------
319static void fill_rect(color cl) {
320    register unsigned int x, y;
321
322    for (y=yMin+1; y<=yMax-1; ++y) {
323      #if CAM_USES_ASPECT_CORRECTION &&  !CAM_USES_ASPECT_YCORRECTION
324        draw_pixel_xarray(y, xMin+1, xMax-1, cl>>8);
325      #else 
326        for (x=xMin+1; x<=xMax-1; ++x) {
327          draw_pixel(x, y, cl>>8);
328        }
329      #endif
330    }
331}
332//-------------------------------------------------------------------
333void draw_filled_rect(coord x1, coord y1, coord x2, coord y2, color cl) {
334    draw_rect(x1, y1, x2, y2, cl);
335    fill_rect(cl);
336}
337
338void draw_filled_rect_thick(coord x1, coord y1, coord x2, coord y2, color cl, int thickness) {
339    draw_rect_thick(x1, y1, x2, y2, cl, thickness);
340    fill_rect(cl);
341}
342//-------------------------------------------------------------------
343void draw_filled_round_rect(coord x1, coord y1, coord x2, coord y2, color cl) {
344    draw_round_rect(x1, y1, x2, y2, cl);
345    fill_rect(cl);
346}
347//-------------------------------------------------------------------
348void draw_char(coord x, coord y, const char ch, color cl) {
349    const unsigned char *sym = (unsigned char*)current_font + ((const unsigned char)ch)*FONT_HEIGHT;
350    int i, ii;
351
352    // XXX optimize. probably use 4bit -> 32bit lookup table
353    // so 4(8) pixels were drawn at a time
354    for (i=0; i<FONT_HEIGHT; i++)
355    {
356            for (ii=0; ii<FONT_WIDTH; ii++)
357        {
358            draw_pixel(x+ii ,y+i, (sym[i] & (0x80>>ii))? cl&0xff : cl>>8);
359            }
360    }
361}
362
363//-------------------------------------------------------------------
364void draw_string(coord x, coord y, const char *s, color cl) {
365    while(*s)
366    {
367            draw_char(x, y, *s, cl);
368            s++;
369            x+=FONT_WIDTH;
370            if ((x>=screen_width) && (*s))
371        {
372                draw_char(x-FONT_WIDTH,y, '>', cl);
373                break;
374            }
375    }
376}
377
378//-------------------------------------------------------------------
379void draw_txt_rect(coord col, coord row, unsigned int length, unsigned int height, color cl) {
380    draw_rect(col*FONT_WIDTH, row*FONT_HEIGHT, (col+length)*FONT_WIDTH-1, (row+height)*FONT_HEIGHT-1, cl);
381}
382
383//-------------------------------------------------------------------
384void draw_txt_rect_exp(coord col, coord row, unsigned int length, unsigned int height, unsigned int exp, color cl) {
385    draw_rect(col*FONT_WIDTH-exp, row*FONT_HEIGHT-exp, (col+length)*FONT_WIDTH-1+exp, (row+height)*FONT_HEIGHT-1+exp, cl);
386}
387
388//-------------------------------------------------------------------
389void draw_txt_filled_rect(coord col, coord row, unsigned int length, unsigned int height, color cl) {
390    draw_filled_rect(col*FONT_WIDTH, row*FONT_HEIGHT, (col+length)*FONT_WIDTH-1, (row+height)*FONT_HEIGHT-1, cl);
391}
392
393//-------------------------------------------------------------------
394void draw_txt_filled_rect_exp(coord col, coord row, unsigned int length, unsigned int height, unsigned int exp, color cl) {
395    draw_filled_rect(col*FONT_WIDTH-exp, row*FONT_HEIGHT-exp, (col+length)*FONT_WIDTH-1+exp, (row+height)*FONT_HEIGHT-1+exp, cl);
396}
397
398//-------------------------------------------------------------------
399void draw_txt_string(coord col, coord row, const char *str, color cl) {
400    draw_string(col*FONT_WIDTH, row*FONT_HEIGHT, str, cl);
401}
402
403//-------------------------------------------------------------------
404void draw_txt_char(coord col, coord row, const char ch, color cl) {
405    draw_char(col*FONT_WIDTH, row*FONT_HEIGHT, ch, cl);
406}
407
408//-------------------------------------------------------------------
409void draw_clear() {
410    memset(frame_buffer[0], COLOR_TRANSPARENT, screen_buffer_size*2);
411}
412
413//-------------------------------------------------------------------
414void draw_restore() {
415    vid_bitmap_refresh();
416
417#ifdef CAM_DETECT_SCREEN_ERASE
418    draw_set_guard();
419#endif
420}
421
422//-------------------------------------------------------------------
423//void draw_fill(coord x, coord y, color cl_fill, color cl_bound) {
424//   if (draw_get_pixel(x, y) != cl_bound && draw_get_pixel(x, y) != cl_fill) {
425//       draw_pixel(x, y, cl_fill);
426//
427//       draw_fill((x+1), y, cl_fill,cl_bound);
428//       draw_fill((x-1), y, cl_fill,cl_bound);
429//       draw_fill(x, (y+1), cl_fill,cl_bound);
430//       draw_fill(x, (y-1), cl_fill,cl_bound);
431//   }
432//}
433
434//-------------------------------------------------------------------
435void draw_circle(coord x, coord y, const unsigned int r, color cl) {
436    int dx = 0;
437    int dy = r;
438    int p=(3-(r<<1));
439
440    do {
441        draw_pixel((x+dx),(y+dy),cl);
442        draw_pixel((x+dy),(y+dx),cl);
443        draw_pixel((x+dy),(y-dx),cl);
444        draw_pixel((x+dx),(y-dy),cl);
445        draw_pixel((x-dx),(y-dy),cl);
446        draw_pixel((x-dy),(y-dx),cl);
447        draw_pixel((x-dy),(y+dx),cl);
448        draw_pixel((x-dx),(y+dy),cl);
449
450        ++dx;
451
452        if (p<0)
453            p += ((dx<<2)+6);
454        else {
455            --dy;
456            p += (((dx-dy)<<2)+10);
457        }
458    } while (dx<=dy);
459}
460
461//-------------------------------------------------------------------
462void draw_ellipse(coord xc, coord yc, unsigned int a, unsigned int b, color cl) {
463    int x = 0, y = b;
464    long a2 = (long)a*a, b2 = (long)b*b;
465    long crit1 = -((a2>>2) + (a&1) + b2);
466    long crit2 = -((b2>>2) + (b&1) + a2);
467    long crit3 = -((b2>>2) + (b&1));
468    long t = -a2*y;
469    long dxt = b2*x*2, dyt = -2*a2*y;
470    long d2xt = b2*2, d2yt = a2*2;
471
472    while (y>=0 && x<=a) {
473        draw_pixel(xc+x, yc+y, cl);
474        if (x!=0 || y!=0)
475            draw_pixel(xc-x, yc-y, cl);
476        if (x!=0 && y!=0) {
477            draw_pixel(xc+x, yc-y, cl);
478            draw_pixel(xc-x, yc+y, cl);
479        }
480        if (t + b2*x <= crit1 || t + a2*y <= crit3)
481            ++x, dxt += d2xt, t += dxt;
482        else if (t - a2*y > crit2)
483            --y, dyt += d2yt, t += dyt;
484        else {
485            ++x, dxt += d2xt, t += dxt;
486            --y, dyt += d2yt, t += dyt;
487        }
488   }
489}
490
491//-------------------------------------------------------------------
492void draw_filled_ellipse(coord xc, coord yc, unsigned int a, unsigned int b, color cl) {
493    int x = 0, y = b;
494    int rx = x, ry = y;
495    unsigned int width = 1;
496    unsigned int height = 1;
497    long a2 = (long)a*a, b2 = (long)b*b;
498    long crit1 = -((a2>>2) + (a&1) + b2);
499    long crit2 = -((b2>>2) + (b&1) + a2);
500    long crit3 = -((b2>>2) + (b&1));
501    long t = -a2*y;
502    long dxt = 2*b2*x, dyt = -2*a2*y;
503    long d2xt = 2*b2, d2yt = 2*a2;
504   
505    color cl_fill = ((cl >> 8) & 0xff) | (cl & 0xff00);
506
507    if (b == 0) {
508        draw_filled_rect(xc-a, yc, (a<<1)+1, 1, cl_fill);
509    } else {
510        while (y>=0 && x<=a) {
511            if (t + b2*x <= crit1 || t + a2*y <= crit3) {
512                if (height == 1)
513                    ; /* draw nothing */
514                else if (ry*2+1 > (height-1)*2) {
515                    draw_filled_rect(xc-rx, yc-ry, xc-rx+width-1, yc-ry+(height-1)-1, cl_fill);
516                    draw_filled_rect(xc-rx, yc+ry+1, xc-rx+width-1, yc+ry+1+(1-height)-1, cl_fill);
517                    ry -= height-1;
518                    height = 1;
519                }
520                else {
521                    draw_filled_rect(xc-rx, yc-ry, xc-rx+width-1, yc-ry+(ry*2+1)-1, cl_fill);
522                    ry -= ry;
523                    height = 1;
524                }
525                ++x, dxt += d2xt, t += dxt;
526                rx++;
527                width += 2;
528            }
529            else if (t - a2*y > crit2) {
530                --y, dyt += d2yt, t += dyt;
531                height++;
532            }
533            else {
534                if (ry*2+1 > height*2) {
535                    draw_filled_rect(xc-rx, yc-ry, xc-rx+width-1, yc-ry+height-1, cl_fill);
536                    draw_filled_rect(xc-rx, yc+ry+1, xc-rx+width-1, yc+ry+1-height-1, cl_fill);
537                }
538                else {
539                    draw_filled_rect(xc-rx, yc-ry, xc-rx+width-1, yc-ry+(ry*2+1)-1, cl_fill);
540                }
541                ++x, dxt += d2xt, t += dxt;
542                --y, dyt += d2yt, t += dyt;
543                rx++;
544                width += 2;
545                ry -= height;
546                height = 1;
547            }
548        }
549
550        if (ry > height) {
551            draw_filled_rect(xc-rx, yc-ry, xc-rx+width-1, yc-ry+height-1, cl_fill);
552            draw_filled_rect(xc-rx, yc+ry+1, xc-rx+width-1, yc+ry+1-height-1, cl_fill);
553        }
554        else {
555            draw_filled_rect(xc-rx, yc-ry, xc-rx+width-1, yc-ry+(ry*2+1)-1, cl_fill);
556        }
557    }
558}
Note: See TracBrowser for help on using the repository browser.