source: trunk/core/edgeoverlay.c @ 931

Revision 931, 24.8 KB checked in by fe50, 3 years ago (diff)
  • Optimazions & fixes by ultimA, from http://chdk.setepontos.com/index.php/topic,650.msg54493.html#msg54493 :
    • Optimizations to edge overlay
    • Make edge overlay more "multitask-friendly"
    • Detect a full shutter press during edge calculations too
    • Wrap pano-modes in edge menu & change icons (by msl)
    • Backport fixes from #928 SX20 1.02d to 1.02b
    • Add experimental PTP support to SX20 1.02d (based on mweerden's PTP proposal 20/07/2010)
    • Center edge overlay horizontally
    • Make the overlay's horizontal area larger (+6 pixels)
  • The SX20 1.02b is now enabled (in the main makefile) for the autobuild server
  • Property svn:eol-style set to native
Line 
1#include "edgeoverlay.h"
2#include "platform.h"
3#include "conf.h"
4#include "keyboard.h"
5#include "stdlib.h"
6#include "gui_draw.h"
7#include "bitvector.h"
8
9// the way we save edge overlays on their own...
10#define EDGE_FILE_PREFIX "EDG_"
11#define EDGE_FILE_FORMAT EDGE_FILE_PREFIX "%04d.edg"
12#define EDGE_SLICES     2
13
14typedef enum _edge_fsm_state
15{
16    EDGE_LIVE = 0,
17    EDGE_FROZEN
18} edge_fsm_state_t;
19
20static edge_fsm_state_t fsm_state = EDGE_LIVE;
21static bit_vector_t* edgebuf = NULL;
22static int xoffset = 0, yoffset = 0;
23static unsigned char* smbuf = NULL;
24
25static int slice = 0;       // the current slice of the frame we are calculating/drawing
26static int slice_height;    // the height of a single slice
27
28static int viewport_size;   // whole viewport size in bytes ??
29static int viewport_width;      // screenwidth * 3, width in bytes of one viewport line ??
30static int viewport_height;
31#if CAM_USES_ASPECT_CORRECTION
32static int viewportw; //nandoide , width of viewport (not necessarily equal to width of screen)
33#endif
34
35static void get_viewport_size()
36{
37    // since screen_height is used in the drawing downwards, we should use it
38    // here too to calculate the buffer we need...
39
40#if CAM_USES_ASPECT_CORRECTION//nandoide sept-2009 get the viewport dimensions, not the screen dimensions, on sx200is they aren't the same.
41    viewport_height = vid_get_viewport_height()-EDGE_HMARGIN*2; //don't trace bottom lines
42    viewportw = vid_get_viewport_width();
43    viewport_width = viewportw * 3;
44#else
45    viewport_height = screen_height;//vid_get_viewport_height();
46    viewport_width = screen_width * 3;
47#endif
48
49    viewport_size = viewport_height * viewport_width;
50    slice_height = viewport_height / EDGE_SLICES;
51
52}
53
54static void ensure_allocate_imagebuffer()
55{
56    if(edgebuf == NULL)
57    {
58        edgebuf = bv_create(viewport_size, 1);
59        if (edgebuf != NULL)
60            memset(edgebuf->ptr, 0, edgebuf->ptrLen);
61    }
62    if (conf.edge_overlay_filter && (smbuf == NULL))
63    {
64        smbuf = (unsigned char*)malloc(viewport_width*3);
65        if (smbuf != NULL)
66            memset(smbuf, 0, viewport_width*3);
67        else
68        {
69            // Disable filtering if we do not have enough memory for it
70            conf.edge_overlay_filter = 0;
71        }
72    }
73}
74
75static void reset_edge_overlay()
76{
77    if (smbuf != NULL)
78    {
79        free(smbuf);
80        smbuf = NULL;
81    }
82
83    bv_free(edgebuf);
84    edgebuf = NULL;
85    fsm_state = EDGE_LIVE;
86    slice = 0;
87}
88
89static int is_buffer_ready()
90{
91    if (edgebuf == NULL) return 0;
92    if (edgebuf->ptr == NULL) return 0; // this should never happen, but it does not hurt to check
93    return 1;
94}
95
96// scans a filename for the number of the edge detection file it contains
97static int get_edge_file_num(const char* fn)
98{
99    int num = 0;
100    if( strncmp(fn,EDGE_FILE_PREFIX,sizeof(EDGE_FILE_PREFIX)-1) == 0 )
101    {
102        // has the correct beginning at least, now try to read as a number...
103        fn += sizeof(EDGE_FILE_PREFIX);
104        while( *fn == '0' ) // skip leading 0s
105        {
106            ++fn;
107        }
108        while( isdigit(*fn) )
109        {
110            num *= 10;
111            num += *fn - '0';
112            ++fn;
113        }
114        // ignore anything else after it, that is like the ending etc.
115    }
116    return num;
117}
118
119// saves the actual active overlay data to a file.
120void save_edge_overlay(void)
121{
122
123    char fn[64];
124    char msg[64];
125    FILE *fd;
126    DIR* d;
127    int fnum = 0;
128    int fr = 0;
129    int zoom = 0;
130    struct dirent* de;
131    static struct utimbuf t;
132    // nothing to save? then dont save
133
134    if( !is_buffer_ready() )
135    {
136        draw_string(0, 0, "No overlay to save.", conf.osd_color);
137        return;
138    }
139
140    zoom = shooting_get_zoom();
141
142    // first figure out the most appropriate filename to use
143    d = opendir(EDGE_SAVE_DIR);
144    if( ! d )
145    {
146        return;
147    }
148
149    while( (de = readdir(d)) )
150    {
151        fr = get_edge_file_num(de->d_name);
152        if( fr > fnum )
153        {
154            fnum = fr;
155        }
156    }
157    ++fnum; // the highest is set, we use the next one
158    get_viewport_size();
159    // open the right file
160    sprintf(fn, EDGE_SAVE_DIR "/" EDGE_FILE_FORMAT, fnum );
161    fd = fopen(fn, "wb");
162    if(fd !=NULL)
163    {
164        // write the data
165        fwrite(edgebuf->ptr,edgebuf->ptrLen,1,fd);
166        fwrite(&zoom,sizeof(zoom),1,fd);
167        fclose(fd);
168        t.actime = t.modtime = time(NULL);
169        utime(fn, &t);
170        sprintf(msg, "Saved as %s",fn);
171        draw_string(0, 0, msg, conf.osd_color);
172    }
173    closedir(d);
174}
175
176// load the edge overlay from a file
177void load_edge_overlay(const char* fn)
178{
179    FILE *fd;
180    int zoom;
181
182    get_viewport_size();
183    ensure_allocate_imagebuffer( );
184    fd = fopen(fn,"rb");
185    if( fd != NULL )
186    {
187        int ret = fread(edgebuf->ptr,edgebuf->ptrLen,1,fd);
188        int ret2 = fread (&zoom,sizeof(zoom),1,fd);
189        fclose(fd);
190        if( (ret == 1) && (ret2 == 1) )
191        {
192            fsm_state = EDGE_FROZEN;    // switch to "edge overlay frozen"-mode
193            if (conf.edge_overlay_zoom)
194            {
195                shooting_set_zoom(zoom);
196            }
197        }
198    }
199}
200
201static void average_filter_row(const unsigned char*  ptrh1,  // previous row
202                               const unsigned char*  ptrh2,  // current row
203                               const unsigned char*  ptrh3,  // next row
204                               unsigned char*  smptr )       // write results here
205{
206    int x;
207#if CAM_USES_ASPECT_CORRECTION
208    const int x_max = (viewportw - 2) * 3;
209#else
210    const int x_max = (screen_width - 2) * 3;
211#endif
212
213    for (x=6; x<x_max; x+=6)
214    {
215        *(smptr + x + 1) = (*(ptrh1 + x - 1) +
216                            *(ptrh1 + x + 1) +
217                            *(ptrh1 + x + 3) +
218
219                            *(ptrh2 + x - 1) +
220                            *(ptrh2 + x + 1) +
221                            *(ptrh2 + x + 3) +
222
223                            *(ptrh3 + x - 1) +
224                            *(ptrh3 + x + 1) +
225                            *(ptrh3 + x + 3)) / 9u;
226
227        *(smptr + x + 3) = (*(ptrh1 + x + 1) +
228                            *(ptrh1 + x + 3) +
229                            *(ptrh1 + x + 4) +
230
231                            *(ptrh2 + x + 1) +
232                            *(ptrh2 + x + 3) +
233                            *(ptrh2 + x + 4) +
234
235                            *(ptrh3 + x + 1) +
236                            *(ptrh3 + x + 3) +
237                            *(ptrh3 + x + 4)) / 9u;
238
239        *(smptr + x + 4) = (*(ptrh1 + x + 3) +
240                            *(ptrh1 + x + 4) +
241                            *(ptrh1 + x + 5) +
242
243                            *(ptrh2 + x + 3) +
244                            *(ptrh2 + x + 4) +
245                            *(ptrh2 + x + 5) +
246
247                            *(ptrh3 + x + 3) +
248                            *(ptrh3 + x + 4) +
249                            *(ptrh3 + x + 5)) / 9u;
250
251        *(smptr + x + 5) = (*(ptrh1 + x + 4) +
252                            *(ptrh1 + x + 5) +
253                            *(ptrh1 + x + 7) +
254
255                            *(ptrh2 + x + 4) +
256                            *(ptrh2 + x + 5) +
257                            *(ptrh2 + x + 7) +
258
259                            *(ptrh3 + x + 4) +
260                            *(ptrh3 + x + 5) +
261                            *(ptrh3 + x + 7)) / 9u;
262    }
263}
264
265// Sobel edge detector
266static int calc_edge_overlay()
267{
268    int shutter_fullpress = kbd_is_key_pressed(KEY_SHOOT_FULL);
269
270    const int bPlayMode = (mode_get() & MODE_MASK) == MODE_PLAY;
271    const unsigned char* img = bPlayMode ? vid_get_viewport_fb_d() :  vid_get_viewport_fb();
272    const unsigned char*  ptrh1 = NULL;    // previous pixel line
273    const unsigned char*  ptrh2 = NULL;    // current pixel line
274    const unsigned char*  ptrh3 = NULL;    // next pixel line
275    unsigned char*  smptr = NULL;    // pointer to line in smbuf
276    int x, y, xdiv3;
277    int conv1, conv2;
278
279    const int y_min = EDGE_HMARGIN+ slice   *slice_height;
280    const int y_max = EDGE_HMARGIN+(slice+1)*slice_height;
281    const int x_min = 6;
282#if CAM_USES_ASPECT_CORRECTION
283    const int x_max = (viewportw - 2) * 3;
284#else
285    const int x_max = (screen_width - 2) * 3;
286#endif
287
288    const int vp_width = viewport_width;
289
290    xoffset = 0;
291    yoffset = 0;
292
293    // Reserve buffers
294    ensure_allocate_imagebuffer();
295    if( !is_buffer_ready() ) return 0;
296
297    // In every 6 bytes the Y of four pixels are described in the
298    // viewport (UYVYYY format). For edge detection we only
299    // consider the second in the current and the first
300    // in the next pixel.
301
302    // Clear all edges in the current slice
303    int compressed_slice = edgebuf->ptrLen / EDGE_SLICES;
304    memset(edgebuf->ptr + slice*compressed_slice, 0, compressed_slice);
305
306    if (conf.edge_overlay_filter)
307    {
308        // Prefill smbuf with three lines of avergae-filtered data.
309        // This looks much more complex then it actually is.
310        // We really are just summing up nine pixels in a 3x3 box
311        // and averaging the current pixel based on them. And
312        // we do it 4 bytes at a time because of the UYVYYY format.
313        for (y = -1; y <= 1; ++y)
314        {
315            shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
316
317            ptrh1 = img + (y_min+y-1) * vp_width;
318            ptrh2 = img + (y_min+y  ) * vp_width;
319            ptrh3 = img + (y_min+y+1) * vp_width;
320            smptr = smbuf + (y+1) * vp_width;
321
322            average_filter_row(ptrh1, ptrh2, ptrh3, smptr);
323        }
324    }
325
326    for (y = y_min; y < y_max; ++y)
327    {
328        shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
329
330        if (conf.edge_overlay_filter)
331        {
332            // We need to shift up our smbuf one line,
333            // and fill in the last line (which now empty)
334            // with average-filtered data from img.
335            // By storing only three lines of smoothed picture
336            // in memory, we save memory.
337
338            // Shift
339            memcpy(smbuf+vp_width*0, smbuf+vp_width*1, vp_width);
340            memcpy(smbuf+vp_width*1, smbuf+vp_width*2, vp_width);
341
342            // Filter new line
343            ptrh1 = img +  y * vp_width;
344            ptrh2 = img + (y+1) * vp_width;
345            ptrh3 = img + (y+2) * vp_width;
346            smptr = smbuf + 2   * vp_width;
347            average_filter_row(ptrh1, ptrh2, ptrh3, smptr);
348
349            ptrh1 = smbuf + 0 * vp_width;
350            ptrh2 = smbuf + 1 * vp_width;
351            ptrh3 = smbuf + 2 * vp_width;
352        }
353        else
354        {
355            ptrh1 = img + (y-1) * vp_width;
356            ptrh2 = img +  y    * vp_width;
357            ptrh3 = img + (y+1) * vp_width;
358        }
359
360        // Now we do sobel on the current line
361
362        for (x = x_min, xdiv3 = x_min/3; x < x_max; x += 6, xdiv3 += 2)
363        {
364            // convolve vert (second Y)
365            conv1 = *(ptrh1 + x + 1) * ( 1) +
366                    *(ptrh1 + x + 4) * (-1) +
367
368                    *(ptrh2 + x + 1) * ( 2) +
369                    *(ptrh2 + x + 4) * (-2) +
370
371                    *(ptrh3 + x + 1) * ( 1) +
372                    *(ptrh3 + x + 4) * (-1);
373            if  (conv1 < 0)     // abs()
374                conv1 = -conv1;
375
376            // convolve vert (first Y of next pixel)
377            conv2 = *(ptrh1 + x + 1) * ( 1) +
378                    *(ptrh1 + x + 3) * ( 2) +
379                    *(ptrh1 + x + 4) * ( 1) +
380
381                    *(ptrh3 + x + 1) * (-1) +
382                    *(ptrh3 + x + 3) * (-2) +
383                    *(ptrh3 + x + 4) * (-1);
384            if  (conv2 < 0)     // abs()
385                conv2 = -conv2;
386
387            if (conv1 + conv2 > conf.edge_overlay_thresh)
388            {
389                bv_set(edgebuf, (y-EDGE_HMARGIN)*vp_width + xdiv3, 1);
390            }
391
392            // Do it once again for the next 'pixel'
393
394            // convolve vert (second Y)
395            conv1 = *(ptrh1 + x + 5) * ( 1) +
396                    *(ptrh1 + x + 9) * (-1) +
397
398                    *(ptrh2 + x + 5) * ( 2) +
399                    *(ptrh2 + x + 9) * (-2) +
400
401                    *(ptrh3 + x + 5) * ( 1) +
402                    *(ptrh3 + x + 9) * (-1);
403            if  (conv1 < 0)     // abs()
404                conv1 = -conv1;
405
406            // convolve vert (first Y of next pixel)
407            conv2 = *(ptrh1 + x + 5) * ( 1) +
408                    *(ptrh1 + x + 7) * ( 2) +
409                    *(ptrh1 + x + 9) * ( 1) +
410
411                    *(ptrh3 + x + 5) * (-1) +
412                    *(ptrh3 + x + 7) * (-2) +
413                    *(ptrh3 + x + 9) * (-1);
414            if  (conv2 < 0)     // abs()
415                conv2 = -conv2;
416
417            if (conv1 + conv2 > conf.edge_overlay_thresh)
418            {
419                bv_set(edgebuf, (y-EDGE_HMARGIN)*vp_width + xdiv3+1, 1);
420            }
421        }   // for x
422    }   // for y
423
424
425//  For an even more improved edge overlay, enabling the following lines will
426//  post-filter the results of the edge detection, removing false edge 'dots'
427//  from the display. However, the speed hit is large. In the developer's opinion
428//  this code is not needed, but if you want that additional quality and do not
429//  care so much about performance, you can enable it.
430//
431//    if (conf.edge_overlay_filter)
432//    {
433//        // Here we do basic filtering on the detected edges.
434//        // If a pixel is marked as edge but just a few of its
435//        // neighbors are also edges, then we assume that the
436//        // current pixel is just noise and delete the mark.
437//
438//        bit_vector_t* bv_tmp = bv_create(edgebuf->nElem, edgebuf->nBits);
439//        if (bv_tmp != NULL)
440//        {
441//            memset(bv_tmp->ptr, 0, bv_tmp->ptrLen);
442//
443//            for (y = 1; y < viewport_height-1; ++y)
444//            {
445//                shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
446//
447//#if CAM_USES_ASPECT_CORRECTION
448//                for (x=12; x<(viewportw - 4); ++x)
449//#else
450//                for (x=12; x<(screen_width - 4); ++x)
451//#endif
452//                {
453//                    int bEdge = bv_get(edgebuf, y*viewport_width + x);
454//                    if (bEdge)
455//                    {
456//                        // Count the number of neighbor edges
457//                        int sum =
458//                            bv_get(edgebuf, (y-1)*viewport_width + (x-1)) +
459//                            bv_get(edgebuf, (y-1)*viewport_width + (x)) +
460//                            bv_get(edgebuf, (y-1)*viewport_width + (x+1)) +
461//
462//                            bv_get(edgebuf, (y)*viewport_width + (x-1)) +
463////              bv_get(&edgebuf, (y)*viewport_width + (x)) + //  we only inspect the neighbors
464//                            bv_get(edgebuf, (y)*viewport_width + (x+1)) +
465//
466//                            bv_get(edgebuf, (y+1)*viewport_width + (x-1)) +
467//                            bv_get(edgebuf, (y+1)*viewport_width + (x)) +
468//                            bv_get(edgebuf, (y+1)*viewport_width + (x+1));
469//
470//                        if (!conf.edge_overlay_show)
471//                        {
472//                            if (sum >= 5)    // if we have at least 5 neighboring edges
473//                                bv_set(bv_tmp, y*viewport_width + x, 1);   // keep the edge
474//                            // else
475//                            // there is no need to delete because the buffer is already zeroed
476//                        }
477//                    }
478//                }   // for x
479//            }   // for y
480//
481//            // Swap the filtered edge buffer for the real one
482//            bit_vector_t* swap_tmp = edgebuf;
483//            edgebuf = bv_tmp;
484//            bv_free(swap_tmp);
485//        }   // NULL-check
486//    }   // if filtering
487
488    return shutter_fullpress;
489}
490
491static int draw_edge_overlay()
492{
493    int shutter_fullpress = kbd_is_key_pressed(KEY_SHOOT_FULL);
494
495    int x, y;
496    int x_off, y_off;
497
498    const color cl = conf.edge_overlay_color;
499    const int y_slice_min = EDGE_HMARGIN+ slice   *slice_height;
500    const int y_slice_max = EDGE_HMARGIN+(slice+1)*slice_height;
501    const int y_min = EDGE_HMARGIN;
502    const int y_max = EDGE_HMARGIN+viewport_height;
503    const int x_min = 2;
504#if CAM_USES_ASPECT_CORRECTION
505    const int x_max = (viewportw - 2);
506#else
507    const int x_max = (screen_width - 2);
508#endif
509
510    if( !is_buffer_ready() ) return 0;
511
512    for (y = y_slice_min; y < y_slice_max; ++y)
513    {
514        y_off = y + yoffset;
515       
516        shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
517
518        if ((unsigned)(y_off-y_min) < (y_max-y_min)) // is the same as ((y_off > y_min) && (y_off < y_max)) // do not draw outside of allowed area
519        {
520            const int y_edgebuf = (y-y_min) * viewport_width;
521
522            for (x = x_min; x < x_max; ++x)
523            {
524                x_off = x + xoffset;
525
526                if ((unsigned)(x_off-x_min) < (x_max-x_min)) // is the same as  ((x_off > x_min) && (x_off < x_max)) // do not draw outside of allowed area
527                {
528                    // Draw a pixel to the screen wherever we detected an edge.
529                    // If there is no edge based on the newest data, but there is one painted on the screen
530                    // from previous calls, delete it from the screen.
531                    const int aspect_correct_x_off = ASPECT_VIEWPORT_XCORRECTION(x_off);
532                    const int bEdge = bv_get(edgebuf, y_edgebuf + x);
533                    const int bDraw = bEdge || (draw_get_pixel(aspect_correct_x_off, y_off) == conf.edge_overlay_color);
534                    const color cl = bEdge ? conf.edge_overlay_color : 0;
535                    if (bEdge || bDraw)
536                        draw_pixel(aspect_correct_x_off, y_off, cl);
537                   
538                }
539            }   // for x
540        }
541    }   // for y
542
543
544    // Drawing the overlay is over.
545    // But as a finishing touch we clear up garbage on the screen
546    // by clearing those parts that the overlay has left.
547
548    if (xoffset != 0)
549    {
550        // Cleans up leftover from horizontal motion
551
552        const int x_min_c = (xoffset < 0) ? x_max + xoffset : x_min;
553        const int x_max_c = (xoffset > 0) ? x_min + xoffset : x_max;
554
555        for (y = y_min; y < y_max; ++y)
556        {
557            for (x = x_min_c; x < x_max_c; ++x)
558            {
559                const int aspect_correct_x = ASPECT_VIEWPORT_XCORRECTION(x);
560                if (draw_get_pixel(aspect_correct_x, y) == cl)  // if there is an edge drawn on the screen but there is no edge there based on the newest data, delete it from the screen
561                    draw_pixel(aspect_correct_x, y, 0 );
562            }
563        }
564    }
565
566    if (yoffset != 0)
567    {
568        // Cleans up leftover from vertical motion
569
570        const int y_min_c = (yoffset < 0) ? y_max + yoffset : y_min;
571        const int y_max_c = (yoffset > 0) ? y_min + yoffset : y_max;
572
573        for (y = y_min_c; y < y_max_c; ++y)
574        {
575            for (x = x_min; x < x_max; ++x)
576            {
577                const int aspect_correct_x = ASPECT_VIEWPORT_XCORRECTION(x);
578                if (draw_get_pixel(aspect_correct_x, y) == cl)  // if there is an edge drawn on the screen but there is no edge there based on the newest data, delete it from the screen
579                    draw_pixel(aspect_correct_x, y, 0 );
580            }
581        }
582    }
583
584    return shutter_fullpress;
585}
586
587static void set_offset_from_overlap()
588{
589    const int y_max = viewport_height;
590#if CAM_USES_ASPECT_CORRECTION
591    const int x_max = (viewportw - 2);
592#else
593    const int x_max = (screen_width - 2);
594#endif
595
596    switch(conf.edge_overlay_pano)
597    {
598    case 0:     // pano off
599        xoffset = 0;
600        yoffset = 0;
601        break;
602    case 1:     // pano from left to right
603        xoffset = -x_max*(100-conf.edge_overlay_pano_overlap)/100;
604        break;
605    case 2:     // pano from top to bottom
606        yoffset = -y_max*(100-conf.edge_overlay_pano_overlap)/100;
607        break;
608    case 3:     // pano from right to left
609        xoffset = x_max*(100-conf.edge_overlay_pano_overlap)/100;
610        break;
611    case 4:     // pano from bottom to top
612        yoffset = y_max*(100-conf.edge_overlay_pano_overlap)/100;
613        break;
614    case 5:     // free mode
615    default:
616        // free mode: change position with "ALT" and cursor
617        // nothing to do here.
618        break;
619    }
620}
621
622
623// Main edge overlay function.
624// It works by detecting edges using the Sobel operator
625// (calc_edgeoverlay()), the detected edges are then stored into an
626// array of 1-bit elements. A set bit indicates that there is an
627// edge and that it should be drawn onto the overlay.
628// When needed, the 1-bit edge buffer is drawn onto the screen
629// (dynamically decompressing it) using draw_edge_overlay().
630void edge_overlay()
631{
632
633    // Was the shutter fully pressed the last time we ran?
634    // We use this to make sure that the user has released
635    // the button before processing the next FullPress event.
636    // This prevents switching FSM states more than once
637    // per press.
638    static int bFullPress_prev = 0;
639
640    // Have we already started taking pictures in panorama mode?
641    // We use this variable to be able to detect if panorama
642    // mode has been turned off.
643    static int bPanoInProgress = 0;
644
645    // Precalculate some values to make the rest of the
646    // code easier to read.
647    int bFullPress = kbd_is_key_pressed(KEY_SHOOT_FULL);
648    const int bHalfPress = kbd_is_key_pressed(KEY_SHOOT_HALF);
649    const int bPlayMode = (mode_get() & MODE_MASK) == MODE_PLAY;
650    const int bPanoramaMode = (conf.edge_overlay_pano != 0);
651    const int bNeedHalfPress = (conf.edge_overlay_show != 1);
652    const int bDisplayInPlay = (conf.edge_overlay_play == 1);
653    const int bGuiModeNone = (gui_get_mode() == GUI_MODE_NONE);
654    const int bGuiModeAlt = (gui_get_mode() == GUI_MODE_ALT);
655    const int bCanDisplay = (
656                                (!bPlayMode && (bHalfPress || !bNeedHalfPress)) ||   // we have a HalfPress in rec-mode
657                                ( bPlayMode && bDisplayInPlay)  // or we are in play-mode with the right settings
658                            );
659
660    if (bPanoInProgress && !bPanoramaMode)
661    {
662        // This means panorama mode has been recently
663        // turned off in the menu. So let's release
664        // Frozen mode for the user.
665        reset_edge_overlay();
666        bPanoInProgress = 0;
667    }
668
669    get_viewport_size();
670
671    // For just two states a state machine is not actually needed.
672    // But it is scalable in the future in case anybody
673    // wants to extend the functionality of edge overlay.
674    switch (fsm_state)
675    {
676    case EDGE_LIVE:
677    {
678        // In this state we assume no edge overlay in memory,
679        // but we are ready to create one if the user presses wishes so.
680
681        int bRealtimeUpdate = bCanDisplay && (bGuiModeAlt || bGuiModeNone);
682        if (bRealtimeUpdate)
683        {
684            // We try to detect button presses during the lengthy
685            // calculations.
686            bFullPress |= calc_edge_overlay();
687            bFullPress |= draw_edge_overlay();
688        }
689
690        int bSwitch2Frozen = bFullPress && !bFullPress_prev && bGuiModeNone;
691        if (bSwitch2Frozen)
692        {
693            // Switch to Frozen mode
694
695            // Make sure we have one whole consistent frame
696            for (slice = 0; slice < EDGE_SLICES; ++slice)
697                calc_edge_overlay();
698
699            set_offset_from_overlap();
700            fsm_state = EDGE_FROZEN;
701            bPanoInProgress = bPanoramaMode;
702        }
703
704        if (!bRealtimeUpdate && !bSwitch2Frozen)
705        {
706            // Nothing happens. So do nothing.
707            // Or rather, we could clean up if we are that bored.
708            reset_edge_overlay();
709        }
710        break;
711    }
712    case EDGE_FROZEN:
713    {
714        // We have a stored edge overlay in memory and we display
715        // it on screen in 'frozen' mode.
716
717        // Move edge overlay around.
718        if (gui_get_mode() == GUI_MODE_ALT)
719        {
720            if (kbd_is_key_pressed(KEY_RIGHT))
721                xoffset +=XINC;
722            if (kbd_is_key_pressed(KEY_LEFT))
723                xoffset -=XINC;
724            if (kbd_is_key_pressed(KEY_DOWN))
725                yoffset +=YINC;
726            if (kbd_is_key_pressed(KEY_UP))
727                yoffset -=YINC;
728        }
729
730        if (bCanDisplay && (bGuiModeAlt || bGuiModeNone))
731        {
732            // We try to detect button presses during the lengthy
733            // calculations.
734            bFullPress |= draw_edge_overlay();
735            draw_string(0, 0, "Frozen", conf.osd_color);
736        }
737
738        // In event of a FullPress, we either capture a new
739        // overlay and stay frozen, OR we go back to live mode.
740        if (bFullPress && !bFullPress_prev && bGuiModeNone)
741        {
742            // Possible mode switch
743            if (bPanoramaMode)
744            {
745                // Make sure we have one whole consistent frame
746                for (slice = 0; slice < EDGE_SLICES; ++slice)
747                    calc_edge_overlay();
748
749                set_offset_from_overlap();
750                bPanoInProgress = 1;
751            }
752            else
753                fsm_state = EDGE_LIVE;
754        }
755
756        break;
757    }   // case
758    }   // switch
759
760
761    bFullPress_prev = bFullPress;
762
763    if (++slice >= EDGE_SLICES)
764        slice = 0;
765
766}   // function
Note: See TracBrowser for help on using the repository browser.