source: trunk/core/edgeoverlay.c @ 580

Revision 580, 9.7 KB checked in by phyrephox, 5 years ago (diff)

tadaa! major pimping of an already cool feature!
you can now SAVE and LOAD edge overlays! this was written by PlasmaHH (shy guy, only in irc :D)
Yes, you read it right:

  • save an edge overlay: create an overlay (enable overlay and press half-press) -> go to overlay menu and press save
  • load an overlay (go to menu and choose an *.edg file)
  • create overlays from jpgs in playmode! (only works on cameras that have a "hardware" switch of play/recmode for now, because on for example s3is halfpressing the shutter activates rec mode!
  • free memory by using the item in the edge menu (also you should disable edge-overlay)

changes / enhancements to the mod by me:

  • together with the edge overlay the zoom setting is saved, so when you load the file after one year it zooms to the position your camera had when you shot it!
  • added the option so that an edge overlay is "locked", meaning the edgeoverlay you loaded or just created is not overwritten in the osd at half-press (this checkbox is overwritten on each camera startup... no big deal, but i dont like it like that right now)

This is a really great feature (for example for LONG-TERM TIMELAPSES, or stop-motion movies, or vertigo-effect, or stereography... the list is endless :D)

  • restructured the root menu (put imo the most often used items to the top, moved edge overlay from OSD menu to the root menu, moved remote params menu to the misc menu)

because of this new feature and all the new cams i upped the version to 0.8.0 already...
P.S: had to rewrite some of PlasmaHHs stuff (e.g. write -> fwrite), i hope i did everything correctly (it's working flawlessly on s3is and a620)

  • 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
8// This edge overlay code has major changes to the "old" one. One major change
9// is, that it doesn cause my cam (ixus 950) to crash anymore by mistaking the
10// boundaries of the viewport buffer it can read from and write pixels to.
11// Unfortunately it still has the bug (that is also present in the original
12// version) that when you move the overlay too much you again overwrite data.
13// One might not necessarily notice it at once, or at all, but for me
14// unfortunately it overwrote vital data for the chdk menu structure.
15//
16// Also the old version was flickering for me and wasn't playing well with the
17// chdk osd. I tried to change a bit about that, which makes it also a bit
18// faster updating, at least on my cam.
19//
20// And then of course, this can load the viewport to a seperate file
21
22// the way we save edge overlays on their own...
23#define EDGE_FILE_PREFIX "edge_"
24#define EDGE_FILE_FORMAT EDGE_FILE_PREFIX "%04d.edg"
25
26static char * imgbuf = 0;
27static char * imgbuf_end = 0;
28static int inmem=0;
29// whole viewport size in bytes ??
30static int viewport_size = 0;
31// width in bytes of one viewport line ??
32static int viewport_width;// screenwidth * 3
33// flag to remember if current buffer is already saved, so hitting save won't
34// save it again
35static int is_saved = 0;
36// set this to 1 when things need to be moved, so that a redraw clears "old"
37// pixels... Otherwise it just will write pixels that need edge overlay data.
38// This sometimes leaves trails when the pixel alignment isn't nice but it is
39// better than writing "transparent" to everwhere, essentially overwriting
40// important things that will cause flickering.
41static int need_redraw = 0;
42
43// debug output that waits
44void out_wait( const char* buf );
45
46void get_viewport_size( ) {
47        static int viewport_height;
48
49        // since screen_height is used in the drawing downwards, we should use it
50        // here too to calculate the buffer we need...
51        viewport_height = screen_height;//vid_get_viewport_height();
52        viewport_width = screen_width * 3;
53        viewport_size = viewport_height * screen_width * 3;
54}
55
56void ensure_allocate_imagebuffer( ) {
57        if(imgbuf == 0)
58        {
59                imgbuf = malloc( viewport_size );
60                imgbuf_end = imgbuf + (viewport_size);
61        }
62}
63
64// scans a filename for the number of the edge detection file it contains
65int get_edge_file_num( const char* fn )
66{
67        int num = 0;
68        if( strncmp(fn,EDGE_FILE_PREFIX,sizeof(EDGE_FILE_PREFIX)-1) == 0 )
69        { // has the correct beginning at least, now try to read as a number...
70                fn += sizeof(EDGE_FILE_PREFIX);
71                while( *fn == '0' ) // skip leading 0s
72                {
73                        ++fn;
74                }
75                while( isdigit(*fn) )
76                {
77                        num *= 10;
78                        num += *fn - '0';
79                        ++fn;
80                }
81                // ignore anything else after it, that is like the ending etc.
82        }
83        return num;
84}
85
86// we eat up to 300k of memory, for people needing it we have a menu point
87// where they can manually free it. makes of course only sense when the edge
88// overlay is not active.
89void free_memory_edge_overlay(void){
90        char buf[64];
91        free(imgbuf);
92        imgbuf = 0;
93        sprintf(buf,"Freed %u bytes",viewport_size);
94        draw_string(30, 10, buf, conf.osd_color);
95        viewport_size = 0;
96}
97
98// saves the actual active overlay data to a file... Well, actually the
99// viewport is saved...
100void save_edge_overlay(void){
101
102        char fn[64];
103        char msg[64];
104        FILE *fd;
105        DIR* d;
106        int fnum = 0;
107        int fr = 0;
108        int zoom = shooting_get_zoom();
109        struct dirent* de;
110
111        // nothing to save? then dont save
112        if( !imgbuf ) return;
113
114        // first figure out the most appropriate filename to use
115        d = opendir(EDGE_SAVE_DIR);
116        if( ! d )
117        {
118                return;
119        }
120
121        while( (de = readdir(d)) )
122        {
123                fr = get_edge_file_num(de->name);
124                if( fr > fnum )
125                {
126                        fnum = fr;
127                }
128        }
129        ++fnum; // the highest is set, we use the next one
130        get_viewport_size();
131        // open the right file
132        sprintf(fn, EDGE_SAVE_DIR "/" EDGE_FILE_FORMAT, fnum );
133        fd = fopen(fn, "wb");
134        if(fd !=NULL)
135        {
136                // write the data
137                fwrite(imgbuf,viewport_size,1,fd);
138                fwrite(&zoom,4,1,fd);
139                is_saved = 1;
140                fclose(fd);
141                sprintf(msg, "Saved as %s",fn);
142                draw_string(30, 10, msg, conf.osd_color);
143        }
144        closedir(d);
145}
146
147// load the viewport copy thats being used for edge detection (and from that
148// displaying) from a file
149void load_edge_overlay( const char* fn ) {
150        FILE *fd;
151        int ret,ret2=0;
152        int zoom;
153
154        is_saved = 1; // won't want to save it again, its already there
155        get_viewport_size();
156        ensure_allocate_imagebuffer( );
157        fd = fopen(fn,"rb");
158        if( fd != NULL )
159        {
160                ret = fread(imgbuf,viewport_size,1,fd);
161                ret2 = fread (&zoom,4,1,fd);
162                fclose(fd);
163                if( (ret == 1) && (ret2 == 1) )
164                {
165                        inmem = 1; // fake having loaded stuff
166                        if (conf.edge_overlay_zoom)     shooting_set_zoom(zoom);
167                }
168        }
169}
170
171// paint the edge overlay
172void edge_overlay(){
173
174        static int shotTaken = 0;
175        static int imgmem = 0;
176        static int ymin = 0;
177        static int thresh;
178        thresh = conf.edge_overlay_thresh; //40
179        static int xoffset = 0;
180        static int yoffset = 0;
181        static int full_press = 0;//cure for flaky behavior. due to multiple  returns to the scrip during one full press
182        static char strbuf[7] = "Frozen";
183        static unsigned char *img;
184        int i, hi, c;
185        int x, y, h, v, ymax, y1, x1, y2;
186        const char * ptrh1;
187        const char * ptrh2;
188        const char * ptrv1;
189        const char * ptrv2;
190        char xbuf[64];
191        char * optr;
192
193        is_saved = 0; // a new one, we could potentially save it
194        if((mode_get()&MODE_MASK) != MODE_PLAY)
195        {
196                img = vid_get_viewport_fb();
197        }
198        else
199        {
200                img = vid_get_viewport_fb_d();
201        }
202        get_viewport_size();
203        ensure_allocate_imagebuffer( );
204        if(imgbuf == 0) return; // ensure failed, make the best we can out of it
205
206        if(conf.edge_overlay_play || ((mode_get()&MODE_MASK) != MODE_PLAY) ) {
207                // setup offsets for moving the edge overlay around. Always set
208                // need_redraw so that we actually do a complete redraw, overwriting
209                // also old pixels
210                if (kbd_is_key_pressed(KEY_RIGHT)) {
211                        xoffset -=XINC;
212                        ++need_redraw;
213                }
214                if (kbd_is_key_pressed(KEY_LEFT)) {
215                        xoffset +=XINC;
216                        ++need_redraw;
217                }
218                if (kbd_is_key_pressed(KEY_DOWN)) {
219                        yoffset -=YINC;
220                        ++need_redraw;
221                }
222                if (kbd_is_key_pressed(KEY_UP)) {
223                        yoffset +=YINC;
224                        ++need_redraw;
225                }
226
227                if ((kbd_is_key_pressed(KEY_SHOOT_HALF)||kbd_is_key_pressed(KEY_SHOOT_FULL)) && (conf.edge_overlay_lock!=1)) {
228                        if (kbd_is_key_pressed(KEY_SHOOT_FULL) && !full_press) {
229                                shotTaken = 1 - shotTaken;
230                                memcpy(imgbuf,img,viewport_size);
231                                ymin = CALCYMARGIN;
232                                inmem = 1;
233                                full_press = 1;
234                                xoffset = 0;
235                                yoffset = 0;
236                                return;
237                        }
238                        if(shotTaken) {
239                                return;
240                        }
241                        memcpy(imgbuf,img,viewport_size);
242                        ymin = CALCYMARGIN;
243                        inmem = 1;
244                        xoffset = 0;
245                        yoffset = 0;
246                        return;
247                }
248                else full_press = 0;
249
250
251
252                if (inmem && (ymin < screen_height-CALCYMARGIN)) {
253                        ymax = ymin + (screen_height - 2 * CALCYMARGIN) / NSTAGES;
254                        if(ymax > screen_height - CALCYMARGIN) ymax = screen_height - CALCYMARGIN;
255                        for (y=ymin; y<ymax; y++) {
256                                ptrh1 = imgbuf + y * viewport_width + 7;
257                                ptrh2 = imgbuf + y * viewport_width - 5;
258                                ptrv1 = imgbuf + (y + 1) * viewport_width + 1;
259                                ptrv2 = imgbuf + (y - 1) * viewport_width + 1;
260                                optr = imgbuf + y * viewport_width + 3;
261                                for (x=12; x<(screen_width- 4) * 3; x+=6) {
262                                        h = ptrh1[x] - ptrh2[x];
263                                        if(h  < 0) h = -h;
264                                        v = ptrv1[x] - ptrv2[x];
265                                        if(v  < 0) v = -v;
266                                        optr[x] = h + v;
267                                        h = ptrh1[x + 3] - ptrh2[x + 3];
268                                        if(h  < 0) h = -h;
269                                        v = ptrv1[x + 3] - ptrv2[x + 3];
270                                        if(v  < 0) v = -v;
271                                        optr[x + 2] = h + v;
272                                }
273                        }
274                        ymin += (screen_height - 2 * CALCYMARGIN) / NSTAGES;
275                        return;
276                }
277
278                if(inmem &&(ymin >= screen_height-CALCYMARGIN) &&
279                        ((gui_get_mode() == GUI_MODE_NONE) || (gui_get_mode() == GUI_MODE_ALT))){
280
281                                for (y=MARGIN; y<screen_height-MARGIN; y++) {
282                                        y1 = y + yoffset;
283                                        if((y1 < CALCYMARGIN) || (y1 >= screen_height - CALCYMARGIN)) {
284                                                /*
285                                                for (x=MARGIN; x < screen_width - MARGIN; x+=2) {
286                                                        draw_pixel(x, y, 0);
287                                                        draw_pixel(x+1, y, 0);
288                                                }
289                                                */
290                                        }
291                                        else {
292                                                for (x=MARGIN; x < screen_width - MARGIN; x+=2) {
293                                                        x1 = x + xoffset;
294                                                        // leave a margin normally, only write to it when a
295                                                        // full redraw is requested
296                                                        if((x1 < 12) || (x1 >= screen_width-13)) {
297                                                                if( need_redraw )
298                                                                {
299                                                                        draw_pixel(x, y, 0);
300                                                                        draw_pixel(x+1, y, 0);
301                                                                }
302                                                        }
303                                                        else {
304                                                                // draw a pixel if the threshold is reached. If
305                                                                // not, draw it transparent only if we want a
306                                                                // complete redraw to overwrite spurious pixels
307                                                                // or if the color of the existing pixel is the
308                                                                // same as the overlay color
309                                                                if(imgbuf[y1 * viewport_width + x1 * 3 + 3]  > thresh)
310                                                                {
311                                                                        draw_pixel(x, y, conf.edge_overlay_color );
312                                                                }
313                                                                else if( need_redraw || (draw_get_pixel(x,y) == conf.edge_overlay_color) )
314                                                                {
315                                                                        draw_pixel(x, y, 0);
316                                                                }
317
318                                                                if(imgbuf[y1 * viewport_width + x1 * 3 + 5]  > thresh)
319                                                                {
320                                                                        draw_pixel(x+1, y, conf.edge_overlay_color );
321                                                                }
322                                                                else if( need_redraw || (draw_get_pixel(x,y) == conf.edge_overlay_color) )
323                                                                {
324                                                                        draw_pixel(x+1, y, 0);
325                                                                }
326                                                        }
327                                                }
328                                }
329                                // disabled drawing the grid, the new way of drawing the
330                                // overlay should leave the standard grid intact, allowing the
331                                // custom grid to remain intact too.
332                                if(shotTaken) draw_string(30, 10, strbuf, conf.osd_color);
333                        }
334                        // If a complete redraw was requested, decrement the request. That
335                        // way we do it as much as it was requested, also in one run. Will
336                        // cause some flickering, but better than nothing.
337                        if( need_redraw )
338                        {
339                                --need_redraw;
340                        }
341                        return;
342                }
343        }
344        else {
345                full_press = 0;
346                inmem = 0;
347                shotTaken = 0;
348                ymin = 0;
349                xoffset = 0;
350                yoffset = 0;
351        }
352        return;
353}
354
355// there used to be some commented out version here. it was confusing, so I
356// removed it. Its still in the svn anyways.
357 
358// vim: tabstop=4 shiftwidth=4
Note: See TracBrowser for help on using the repository browser.