winlivebg_test1
diff src/app.c @ 2:a9025f31ae2d
sortof works, testing with colcycle hack
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 28 Oct 2019 16:07:25 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/app.c Mon Oct 28 16:07:25 2019 +0200 1.3 @@ -0,0 +1,477 @@ 1.4 +/* 1.5 +colcycle - color cycling image viewer 1.6 +Copyright (C) 2016 John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.20 +*/ 1.21 +#include <stdio.h> 1.22 +#include <stdlib.h> 1.23 +#include <string.h> 1.24 +#include <math.h> 1.25 +#include <errno.h> 1.26 +#ifdef __WATCOMC__ 1.27 +#include "inttypes.h" 1.28 +#include <direct.h> 1.29 +#else 1.30 +#include <inttypes.h> 1.31 +#include <dirent.h> 1.32 +#endif 1.33 +#include <sys/stat.h> 1.34 +#include "app.h" 1.35 +#include "image.h" 1.36 + 1.37 +/* define this if the assembly 32->64bit multiplication in cycle_offset doesn't 1.38 + * work for you for some reason, and you wish to compile the floating point 1.39 + * version of the time calculation. 1.40 + */ 1.41 +#undef NO_ASM 1.42 + 1.43 +#if defined(NO_ASM) || (!defined(__i386__) && !defined(__x86_64__) && !defined(__X86__)) 1.44 +#define USE_FLOAT 1.45 +#endif 1.46 + 1.47 + 1.48 +#ifndef M_PI 1.49 +#define M_PI 3.141593 1.50 +#endif 1.51 + 1.52 +struct ss_node { 1.53 + char *path; 1.54 + struct image *img; 1.55 + struct ss_node *next; 1.56 +}; 1.57 + 1.58 +static void set_image_palette(struct image *img); 1.59 +static void show_image(struct image *img, long time_msec); 1.60 +static int load_slideshow(const char *path); 1.61 +static int load_slide(void); 1.62 + 1.63 +int fbwidth, fbheight; 1.64 +unsigned char *fbpixels; 1.65 + 1.66 +static struct image *img; 1.67 +static int blend = 1; 1.68 +static int fade_dir; 1.69 +static unsigned long fade_start, fade_dur = 600; 1.70 +static int change_pending; 1.71 +static unsigned long showing_since, show_time = 15000; 1.72 + 1.73 +static struct ss_node *sslist; 1.74 + 1.75 +extern long upd_interval; 1.76 + 1.77 +int colc_init(int argc, char **argv) 1.78 +{ 1.79 + if(argv[1]) { 1.80 + struct stat st; 1.81 + 1.82 + if(stat(argv[1], &st) == -1) { 1.83 + fprintf(stderr, "failed to stat path: %s\n", argv[1]); 1.84 + return -1; 1.85 + } 1.86 + 1.87 + if(S_ISDIR(st.st_mode)) { 1.88 + if(load_slideshow(argv[1]) == -1) { 1.89 + fprintf(stderr, "failed to load slideshow in dir: %s\n", argv[1]); 1.90 + return -1; 1.91 + } 1.92 + if(load_slide() == -1) { 1.93 + return -1; 1.94 + } 1.95 + 1.96 + } else { 1.97 + if(!(img = malloc(sizeof *img))) { 1.98 + perror("failed to allocate image structure"); 1.99 + return -1; 1.100 + } 1.101 + if(colc_load_image(img, argv[1]) == -1) { 1.102 + fprintf(stderr, "failed to load image: %s\n", argv[1]); 1.103 + return -1; 1.104 + } 1.105 + } 1.106 + } else { 1.107 + if(!(img = malloc(sizeof *img))) { 1.108 + perror("failed to allocate image structure"); 1.109 + return -1; 1.110 + } 1.111 + if(colc_gen_test_image(img) == -1) { 1.112 + fprintf(stderr, "failed to generate test image\n"); 1.113 + return -1; 1.114 + } 1.115 + } 1.116 + 1.117 + set_image_palette(img); 1.118 + show_image(img, 0); 1.119 + return 0; 1.120 +} 1.121 + 1.122 +void colc_cleanup(void) 1.123 +{ 1.124 + if(sslist) { 1.125 + struct ss_node *start = sslist; 1.126 + sslist = sslist->next; 1.127 + start->next = 0; /* break the circle */ 1.128 + 1.129 + while(sslist) { 1.130 + struct ss_node *node = sslist; 1.131 + sslist = sslist->next; 1.132 + colc_destroy_image(node->img); 1.133 + free(node->path); 1.134 + free(node); 1.135 + } 1.136 + 1.137 + } else { 1.138 + colc_destroy_image(img); 1.139 + free(img); 1.140 + } 1.141 +} 1.142 + 1.143 +/* tx is fixed point with 10 bits decimal */ 1.144 +static void palfade(int dir, long tx) 1.145 +{ 1.146 + int i; 1.147 + 1.148 + if(!img) return; 1.149 + 1.150 + if(dir == -1) { 1.151 + tx = 1024 - tx; 1.152 + } 1.153 + 1.154 + for(i=0; i<256; i++) { 1.155 + int r = (img->palette[i].r * tx) >> 10; 1.156 + int g = (img->palette[i].g * tx) >> 10; 1.157 + int b = (img->palette[i].b * tx) >> 10; 1.158 + set_palette(i, r, g, b); 1.159 + } 1.160 +} 1.161 + 1.162 + 1.163 +/* modes: 1.164 + * 1. normal 1.165 + * 2. reverse 1.166 + * 3. ping-pong 1.167 + * 4. sine -> [0, rsize/2] 1.168 + * 5. sine -> [0, rsize] 1.169 + * 1.170 + * returns: offset in 24.8 fixed point 1.171 + */ 1.172 +#ifdef USE_FLOAT 1.173 +static int32_t cycle_offset(enum cycle_mode mode, int32_t rate, int32_t rsize, int32_t msec) 1.174 +{ 1.175 + float offs; 1.176 + float tm = (rate / 280.0) * (float)msec / 1000.0; 1.177 + 1.178 + switch(mode) { 1.179 + case CYCLE_PINGPONG: 1.180 + offs = fmod(tm, (float)(rsize * 2)); 1.181 + if(offs >= rsize) offs = (rsize * 2) - offs; 1.182 + break; 1.183 + 1.184 + case CYCLE_SINE: 1.185 + case CYCLE_SINE_HALF: 1.186 + { 1.187 + float x = fmod(tm, (float)rsize); 1.188 + offs = sin((x * M_PI * 2.0) / (float)rsize) + 1.0; 1.189 + offs *= rsize / (mode == CYCLE_SINE_HALF ? 4.0f : 2.0f); 1.190 + } 1.191 + break; 1.192 + 1.193 + default: /* normal or reverse */ 1.194 + offs = tm; 1.195 + } 1.196 + return (int32_t)(offs * 256.0); 1.197 +} 1.198 + 1.199 +#else /* fixed point variant for specific platforms (currently x86) */ 1.200 + 1.201 +#ifdef __GNUC__ 1.202 +#define CALC_TIME(res, anim_rate, time_msec) \ 1.203 + asm volatile ( \ 1.204 + "\n\tmull %1" /* edx:eax <- eax(rate << 8) * msec */ \ 1.205 + "\n\tmovl $280000, %%ebx" \ 1.206 + "\n\tdivl %%ebx" /* eax <- edx:eax / ebx */ \ 1.207 + : "=a" (res) \ 1.208 + : "g" ((uint32_t)(time_msec)), "a" ((anim_rate) << 8) \ 1.209 + : "ebx", "edx" ) 1.210 +#endif /* __GNUC__ */ 1.211 + 1.212 +#ifdef __WATCOMC__ 1.213 +#define CALC_TIME(res, anim_rate, time_msec) \ 1.214 + (res) = calc_time_offset(anim_rate, time_msec) 1.215 + 1.216 +int32_t calc_time_offset(int32_t anim_rate, int32_t time_msec); 1.217 +#pragma aux calc_time_offset = \ 1.218 + "shl eax, 8" /* eax(rate) <<= 8 convert to 24.8 fixed point */ \ 1.219 + "mul ebx" /* edx:eax <- eax(rate<<8) * ebx(msec) */ \ 1.220 + "mov ebx, 280000" \ 1.221 + "div ebx" /* eax <- edx:eax / ebx */ \ 1.222 + modify [eax ebx ecx] \ 1.223 + value [eax] \ 1.224 + parm [eax] [ebx]; 1.225 +#endif /* __WATCOMC__ */ 1.226 + 1.227 +static int32_t cycle_offset(enum cycle_mode mode, int32_t rate, int32_t rsize, int32_t msec) 1.228 +{ 1.229 + int32_t offs, tm; 1.230 + 1.231 + CALC_TIME(tm, rate, msec); 1.232 + 1.233 + switch(mode) { 1.234 + case CYCLE_PINGPONG: 1.235 + rsize <<= 8; /* rsize -> 24.8 fixed point */ 1.236 + offs = tm % (rsize * 2); 1.237 + if(offs > rsize) offs = (rsize * 2) - offs; 1.238 + rsize >>= 8; /* back to 32.0 */ 1.239 + break; 1.240 + 1.241 + case CYCLE_SINE: 1.242 + case CYCLE_SINE_HALF: 1.243 + { 1.244 + float t = (float)tm / 256.0; /* convert fixed24.8 -> float */ 1.245 + float x = fmod(t, (float)(rsize * 2)); 1.246 + float foffs = sin((x * M_PI * 2.0) / (float)rsize) + 1.0; 1.247 + if(mode == CYCLE_SINE_HALF) { 1.248 + foffs *= rsize / 4.0; 1.249 + } else { 1.250 + foffs *= rsize / 2.0; 1.251 + } 1.252 + offs = (int32_t)(foffs * 256.0); /* convert float -> fixed24.8 */ 1.253 + } 1.254 + break; 1.255 + 1.256 + default: /* normal or reverse */ 1.257 + offs = tm; 1.258 + } 1.259 + 1.260 + return offs; 1.261 +} 1.262 +#endif /* USE_FLOAT */ 1.263 + 1.264 +#define LERP_FIXED_T(a, b, xt) ((((a) << 8) + ((b) - (a)) * (xt)) >> 8) 1.265 + 1.266 +void colc_draw(long time_msec) 1.267 +{ 1.268 + int i, j; 1.269 + 1.270 + if(!img) return; 1.271 + 1.272 + if(sslist) { 1.273 + /* if there is a slideshow list of images, handle switching with fades between them */ 1.274 + if(!fade_dir && (change_pending || time_msec - showing_since > show_time)) { 1.275 + fade_dir = -1; 1.276 + fade_start = time_msec; 1.277 + change_pending = 0; 1.278 + } 1.279 + 1.280 + if(fade_dir) { 1.281 + unsigned long dt = time_msec - fade_start; 1.282 + 1.283 + if(dt >= fade_dur) { 1.284 + if(fade_dir == -1) { 1.285 + sslist = sslist->next; 1.286 + if(load_slide() == -1) { 1.287 + return; 1.288 + } 1.289 + show_image(img, time_msec); 1.290 + fade_dir = 1; 1.291 + time_msec = fade_start = time_msec; 1.292 + dt = 0; 1.293 + } else { 1.294 + set_image_palette(img); 1.295 + fade_dir = 0; 1.296 + } 1.297 + } 1.298 + 1.299 + if(fade_dir) { 1.300 + long tx = ((long)dt << 10) / fade_dur; 1.301 + palfade(fade_dir, tx); 1.302 + } 1.303 + showing_since = time_msec; 1.304 + return; 1.305 + } 1.306 + } 1.307 + 1.308 + /* for each cycling range in the image ... */ 1.309 + for(i=0; i<img->num_ranges; i++) { 1.310 + int32_t offs, rsize, ioffs; 1.311 + int rev; 1.312 + 1.313 + if(!img->range[i].rate) continue; 1.314 + rsize = img->range[i].high - img->range[i].low + 1; 1.315 + 1.316 + offs = cycle_offset(img->range[i].cmode, img->range[i].rate, rsize, time_msec); 1.317 + 1.318 + ioffs = (offs >> 8) % rsize; 1.319 + 1.320 + /* reverse when rev is 2 */ 1.321 + rev = img->range[i].cmode == CYCLE_REVERSE ? 1 : 0; 1.322 + 1.323 + for(j=0; j<rsize; j++) { 1.324 + int pidx, to, next; 1.325 + 1.326 + pidx = j + img->range[i].low; 1.327 + 1.328 + if(rev) { 1.329 + to = (j + ioffs) % rsize; 1.330 + next = (to + 1) % rsize; 1.331 + } else { 1.332 + if((to = (j - ioffs) % rsize) < 0) { 1.333 + to += rsize; 1.334 + } 1.335 + if((next = to - 1) < 0) { 1.336 + next += rsize; 1.337 + } 1.338 + } 1.339 + to += img->range[i].low; 1.340 + 1.341 + if(blend) { 1.342 + int r, g, b; 1.343 + int32_t frac_offs = offs & 0xff; 1.344 + 1.345 + next += img->range[i].low; 1.346 + 1.347 + r = LERP_FIXED_T(img->palette[to].r, img->palette[next].r, frac_offs); 1.348 + g = LERP_FIXED_T(img->palette[to].g, img->palette[next].g, frac_offs); 1.349 + b = LERP_FIXED_T(img->palette[to].b, img->palette[next].b, frac_offs); 1.350 + 1.351 + set_palette(pidx, r, g, b); 1.352 + } else { 1.353 + set_palette(pidx, img->palette[to].r, img->palette[to].g, img->palette[to].b); 1.354 + } 1.355 + } 1.356 + } 1.357 +} 1.358 + 1.359 + 1.360 +static void set_image_palette(struct image *img) 1.361 +{ 1.362 + int i; 1.363 + for(i=0; i<256; i++) { 1.364 + set_palette(i, img->palette[i].r, img->palette[i].g, img->palette[i].b); 1.365 + } 1.366 +} 1.367 + 1.368 +static void show_image(struct image *img, long time_msec) 1.369 +{ 1.370 + int i, j; 1.371 + unsigned char *dptr; 1.372 + unsigned int max_rate = 0; 1.373 + 1.374 + resize(img->width, img->height); 1.375 + 1.376 + dptr = fbpixels; 1.377 + for(i=0; i<fbheight; i++) { 1.378 + for(j=0; j<fbwidth; j++) { 1.379 + unsigned char c = 0; 1.380 + if(i < img->height && j < img->width) { 1.381 + c = img->pixels[i * img->width + j]; 1.382 + } 1.383 + *dptr++ = c; 1.384 + } 1.385 + } 1.386 + 1.387 + showing_since = time_msec; 1.388 + 1.389 + for(i=0; i<img->num_ranges; i++) { 1.390 + if(img->range[i].rate > max_rate) { 1.391 + max_rate = img->range[i].rate; 1.392 + } 1.393 + } 1.394 + upd_interval = max_rate * 10; 1.395 +} 1.396 + 1.397 +static int load_slideshow(const char *path) 1.398 +{ 1.399 + DIR *dir; 1.400 + struct dirent *dent; 1.401 + struct ss_node *head = 0, *tail = 0, *node; 1.402 + 1.403 + if(!(dir = opendir(path))) { 1.404 + fprintf(stderr, "failed to open directory: %s: %s\n", path, strerror(errno)); 1.405 + return -1; 1.406 + } 1.407 + 1.408 + while((dent = readdir(dir))) { 1.409 + int sz; 1.410 + 1.411 + if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { 1.412 + continue; 1.413 + } 1.414 + sz = strlen(path) + strlen(dent->d_name) + 1; /* +1 for a slash */ 1.415 + 1.416 + if(!(node = malloc(sizeof *node))) { 1.417 + perror("failed to allocate slideshow node"); 1.418 + goto err; 1.419 + } 1.420 + if(!(node->path = malloc(sz + 1))) { 1.421 + perror("failed to allocate image path"); 1.422 + free(node); 1.423 + goto err; 1.424 + } 1.425 + sprintf(node->path, "%s/%s", path, dent->d_name); 1.426 + node->img = 0; 1.427 + node->next = 0; 1.428 + 1.429 + if(head) { 1.430 + tail->next = node; 1.431 + tail = node; 1.432 + } else { 1.433 + head = tail = node; 1.434 + } 1.435 + } 1.436 + closedir(dir); 1.437 + 1.438 + sslist = head; 1.439 + tail->next = head; /* make circular */ 1.440 + return 0; 1.441 + 1.442 +err: 1.443 + closedir(dir); 1.444 + while(head) { 1.445 + node = head; 1.446 + head = head->next; 1.447 + free(node->path); 1.448 + free(node); 1.449 + } 1.450 + return -1; 1.451 +} 1.452 + 1.453 +static int load_slide(void) 1.454 +{ 1.455 + struct ss_node *start = sslist; 1.456 + 1.457 + img = 0; 1.458 + do { 1.459 + if(sslist->path) { 1.460 + if(!sslist->img) { 1.461 + if(!(sslist->img = malloc(sizeof *sslist->img))) { 1.462 + perror("failed to allocate image structure"); 1.463 + return -1; 1.464 + } 1.465 + if(colc_load_image(sslist->img, sslist->path) == -1) { 1.466 + fprintf(stderr, "failed to load image: %s\n", sslist->path); 1.467 + free(sslist->path); 1.468 + sslist->path = 0; 1.469 + free(sslist->img); 1.470 + sslist->img = 0; 1.471 + } 1.472 + } 1.473 + img = sslist->img; 1.474 + } 1.475 + 1.476 + sslist = sslist->next; 1.477 + } while(!img && sslist != start); 1.478 + 1.479 + return img ? 0 : -1; 1.480 +}