source: trunk/core/edgeoverlay.c @ 1024

Revision 1024, 25.4 KB checked in by reyalP, 2 years ago (diff)

g12 and sx30 updates from philmoz in http://chdk.setepontos.com/index.php?topic=650.msg59326#msg59326

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