| 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 | |
|---|
| 26 | static char * imgbuf = 0; |
|---|
| 27 | static char * imgbuf_end = 0; |
|---|
| 28 | static int inmem=0; |
|---|
| 29 | // whole viewport size in bytes ?? |
|---|
| 30 | static int viewport_size = 0; |
|---|
| 31 | // width in bytes of one viewport line ?? |
|---|
| 32 | static int viewport_width;// screenwidth * 3 |
|---|
| 33 | // flag to remember if current buffer is already saved, so hitting save won't |
|---|
| 34 | // save it again |
|---|
| 35 | static 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. |
|---|
| 41 | static int need_redraw = 0; |
|---|
| 42 | |
|---|
| 43 | // debug output that waits |
|---|
| 44 | void out_wait( const char* buf ); |
|---|
| 45 | |
|---|
| 46 | void 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 | |
|---|
| 56 | void 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 |
|---|
| 65 | int 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. |
|---|
| 89 | void 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... |
|---|
| 100 | void 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 |
|---|
| 149 | void 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 |
|---|
| 172 | void 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 |
|---|