root/trunk/core/edgeoverlay.c @ 955

Revision 955, 24.8 KB (checked in by fe50, 3 years ago)

* Fixes by ultimA from  http://chdk.setepontos.com/index.php/topic,650.msg55640.html#msg55640
- Make the A2000, G11 and ixus100_sd780 ports compatible with GCC 4.5. Apparently GCC 4.4 was too forgiving and still built the code, but GCC 4.5.1 errored out on them. This patch fixes the ASM so that these cams can be built successfully. The changes were not actually tested, but the fixes are trivial. As a result, all stable ports can be built using GCC 4.5.1 now. Credit also goes to whim who noticed these cams failing to build and he also suggested the first set of fixes.
- Shut up some (not all) warnings from ixus100_sd780, ixus40_sd300, ixus65_sd630, s5is, ixus60_sd600
- Make edge overlay respect OPT_EDGEOVERLAY. Previously, generated binary size did not get significantly smaller even when OPT_EDGEOVERLAY was undefined, because undefining it only resulted in the overlay being excluded from the menu, but still being built. Excluding edge overlay now saves appr. 3Kbytes.
- Edge overlay erroneously depended on OPT_DEBUGGING. Builds failed when OPT_DEBUGGING was not defined previously.

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