winlivebg_test1

annotate 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
rev   line source
nuclear@2 1 /*
nuclear@2 2 colcycle - color cycling image viewer
nuclear@2 3 Copyright (C) 2016 John Tsiombikas <nuclear@member.fsf.org>
nuclear@2 4
nuclear@2 5 This program is free software: you can redistribute it and/or modify
nuclear@2 6 it under the terms of the GNU General Public License as published by
nuclear@2 7 the Free Software Foundation, either version 3 of the License, or
nuclear@2 8 (at your option) any later version.
nuclear@2 9
nuclear@2 10 This program is distributed in the hope that it will be useful,
nuclear@2 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
nuclear@2 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
nuclear@2 13 GNU General Public License for more details.
nuclear@2 14
nuclear@2 15 You should have received a copy of the GNU General Public License
nuclear@2 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
nuclear@2 17 */
nuclear@2 18 #include <stdio.h>
nuclear@2 19 #include <stdlib.h>
nuclear@2 20 #include <string.h>
nuclear@2 21 #include <math.h>
nuclear@2 22 #include <errno.h>
nuclear@2 23 #ifdef __WATCOMC__
nuclear@2 24 #include "inttypes.h"
nuclear@2 25 #include <direct.h>
nuclear@2 26 #else
nuclear@2 27 #include <inttypes.h>
nuclear@2 28 #include <dirent.h>
nuclear@2 29 #endif
nuclear@2 30 #include <sys/stat.h>
nuclear@2 31 #include "app.h"
nuclear@2 32 #include "image.h"
nuclear@2 33
nuclear@2 34 /* define this if the assembly 32->64bit multiplication in cycle_offset doesn't
nuclear@2 35 * work for you for some reason, and you wish to compile the floating point
nuclear@2 36 * version of the time calculation.
nuclear@2 37 */
nuclear@2 38 #undef NO_ASM
nuclear@2 39
nuclear@2 40 #if defined(NO_ASM) || (!defined(__i386__) && !defined(__x86_64__) && !defined(__X86__))
nuclear@2 41 #define USE_FLOAT
nuclear@2 42 #endif
nuclear@2 43
nuclear@2 44
nuclear@2 45 #ifndef M_PI
nuclear@2 46 #define M_PI 3.141593
nuclear@2 47 #endif
nuclear@2 48
nuclear@2 49 struct ss_node {
nuclear@2 50 char *path;
nuclear@2 51 struct image *img;
nuclear@2 52 struct ss_node *next;
nuclear@2 53 };
nuclear@2 54
nuclear@2 55 static void set_image_palette(struct image *img);
nuclear@2 56 static void show_image(struct image *img, long time_msec);
nuclear@2 57 static int load_slideshow(const char *path);
nuclear@2 58 static int load_slide(void);
nuclear@2 59
nuclear@2 60 int fbwidth, fbheight;
nuclear@2 61 unsigned char *fbpixels;
nuclear@2 62
nuclear@2 63 static struct image *img;
nuclear@2 64 static int blend = 1;
nuclear@2 65 static int fade_dir;
nuclear@2 66 static unsigned long fade_start, fade_dur = 600;
nuclear@2 67 static int change_pending;
nuclear@2 68 static unsigned long showing_since, show_time = 15000;
nuclear@2 69
nuclear@2 70 static struct ss_node *sslist;
nuclear@2 71
nuclear@2 72 extern long upd_interval;
nuclear@2 73
nuclear@2 74 int colc_init(int argc, char **argv)
nuclear@2 75 {
nuclear@2 76 if(argv[1]) {
nuclear@2 77 struct stat st;
nuclear@2 78
nuclear@2 79 if(stat(argv[1], &st) == -1) {
nuclear@2 80 fprintf(stderr, "failed to stat path: %s\n", argv[1]);
nuclear@2 81 return -1;
nuclear@2 82 }
nuclear@2 83
nuclear@2 84 if(S_ISDIR(st.st_mode)) {
nuclear@2 85 if(load_slideshow(argv[1]) == -1) {
nuclear@2 86 fprintf(stderr, "failed to load slideshow in dir: %s\n", argv[1]);
nuclear@2 87 return -1;
nuclear@2 88 }
nuclear@2 89 if(load_slide() == -1) {
nuclear@2 90 return -1;
nuclear@2 91 }
nuclear@2 92
nuclear@2 93 } else {
nuclear@2 94 if(!(img = malloc(sizeof *img))) {
nuclear@2 95 perror("failed to allocate image structure");
nuclear@2 96 return -1;
nuclear@2 97 }
nuclear@2 98 if(colc_load_image(img, argv[1]) == -1) {
nuclear@2 99 fprintf(stderr, "failed to load image: %s\n", argv[1]);
nuclear@2 100 return -1;
nuclear@2 101 }
nuclear@2 102 }
nuclear@2 103 } else {
nuclear@2 104 if(!(img = malloc(sizeof *img))) {
nuclear@2 105 perror("failed to allocate image structure");
nuclear@2 106 return -1;
nuclear@2 107 }
nuclear@2 108 if(colc_gen_test_image(img) == -1) {
nuclear@2 109 fprintf(stderr, "failed to generate test image\n");
nuclear@2 110 return -1;
nuclear@2 111 }
nuclear@2 112 }
nuclear@2 113
nuclear@2 114 set_image_palette(img);
nuclear@2 115 show_image(img, 0);
nuclear@2 116 return 0;
nuclear@2 117 }
nuclear@2 118
nuclear@2 119 void colc_cleanup(void)
nuclear@2 120 {
nuclear@2 121 if(sslist) {
nuclear@2 122 struct ss_node *start = sslist;
nuclear@2 123 sslist = sslist->next;
nuclear@2 124 start->next = 0; /* break the circle */
nuclear@2 125
nuclear@2 126 while(sslist) {
nuclear@2 127 struct ss_node *node = sslist;
nuclear@2 128 sslist = sslist->next;
nuclear@2 129 colc_destroy_image(node->img);
nuclear@2 130 free(node->path);
nuclear@2 131 free(node);
nuclear@2 132 }
nuclear@2 133
nuclear@2 134 } else {
nuclear@2 135 colc_destroy_image(img);
nuclear@2 136 free(img);
nuclear@2 137 }
nuclear@2 138 }
nuclear@2 139
nuclear@2 140 /* tx is fixed point with 10 bits decimal */
nuclear@2 141 static void palfade(int dir, long tx)
nuclear@2 142 {
nuclear@2 143 int i;
nuclear@2 144
nuclear@2 145 if(!img) return;
nuclear@2 146
nuclear@2 147 if(dir == -1) {
nuclear@2 148 tx = 1024 - tx;
nuclear@2 149 }
nuclear@2 150
nuclear@2 151 for(i=0; i<256; i++) {
nuclear@2 152 int r = (img->palette[i].r * tx) >> 10;
nuclear@2 153 int g = (img->palette[i].g * tx) >> 10;
nuclear@2 154 int b = (img->palette[i].b * tx) >> 10;
nuclear@2 155 set_palette(i, r, g, b);
nuclear@2 156 }
nuclear@2 157 }
nuclear@2 158
nuclear@2 159
nuclear@2 160 /* modes:
nuclear@2 161 * 1. normal
nuclear@2 162 * 2. reverse
nuclear@2 163 * 3. ping-pong
nuclear@2 164 * 4. sine -> [0, rsize/2]
nuclear@2 165 * 5. sine -> [0, rsize]
nuclear@2 166 *
nuclear@2 167 * returns: offset in 24.8 fixed point
nuclear@2 168 */
nuclear@2 169 #ifdef USE_FLOAT
nuclear@2 170 static int32_t cycle_offset(enum cycle_mode mode, int32_t rate, int32_t rsize, int32_t msec)
nuclear@2 171 {
nuclear@2 172 float offs;
nuclear@2 173 float tm = (rate / 280.0) * (float)msec / 1000.0;
nuclear@2 174
nuclear@2 175 switch(mode) {
nuclear@2 176 case CYCLE_PINGPONG:
nuclear@2 177 offs = fmod(tm, (float)(rsize * 2));
nuclear@2 178 if(offs >= rsize) offs = (rsize * 2) - offs;
nuclear@2 179 break;
nuclear@2 180
nuclear@2 181 case CYCLE_SINE:
nuclear@2 182 case CYCLE_SINE_HALF:
nuclear@2 183 {
nuclear@2 184 float x = fmod(tm, (float)rsize);
nuclear@2 185 offs = sin((x * M_PI * 2.0) / (float)rsize) + 1.0;
nuclear@2 186 offs *= rsize / (mode == CYCLE_SINE_HALF ? 4.0f : 2.0f);
nuclear@2 187 }
nuclear@2 188 break;
nuclear@2 189
nuclear@2 190 default: /* normal or reverse */
nuclear@2 191 offs = tm;
nuclear@2 192 }
nuclear@2 193 return (int32_t)(offs * 256.0);
nuclear@2 194 }
nuclear@2 195
nuclear@2 196 #else /* fixed point variant for specific platforms (currently x86) */
nuclear@2 197
nuclear@2 198 #ifdef __GNUC__
nuclear@2 199 #define CALC_TIME(res, anim_rate, time_msec) \
nuclear@2 200 asm volatile ( \
nuclear@2 201 "\n\tmull %1" /* edx:eax <- eax(rate << 8) * msec */ \
nuclear@2 202 "\n\tmovl $280000, %%ebx" \
nuclear@2 203 "\n\tdivl %%ebx" /* eax <- edx:eax / ebx */ \
nuclear@2 204 : "=a" (res) \
nuclear@2 205 : "g" ((uint32_t)(time_msec)), "a" ((anim_rate) << 8) \
nuclear@2 206 : "ebx", "edx" )
nuclear@2 207 #endif /* __GNUC__ */
nuclear@2 208
nuclear@2 209 #ifdef __WATCOMC__
nuclear@2 210 #define CALC_TIME(res, anim_rate, time_msec) \
nuclear@2 211 (res) = calc_time_offset(anim_rate, time_msec)
nuclear@2 212
nuclear@2 213 int32_t calc_time_offset(int32_t anim_rate, int32_t time_msec);
nuclear@2 214 #pragma aux calc_time_offset = \
nuclear@2 215 "shl eax, 8" /* eax(rate) <<= 8 convert to 24.8 fixed point */ \
nuclear@2 216 "mul ebx" /* edx:eax <- eax(rate<<8) * ebx(msec) */ \
nuclear@2 217 "mov ebx, 280000" \
nuclear@2 218 "div ebx" /* eax <- edx:eax / ebx */ \
nuclear@2 219 modify [eax ebx ecx] \
nuclear@2 220 value [eax] \
nuclear@2 221 parm [eax] [ebx];
nuclear@2 222 #endif /* __WATCOMC__ */
nuclear@2 223
nuclear@2 224 static int32_t cycle_offset(enum cycle_mode mode, int32_t rate, int32_t rsize, int32_t msec)
nuclear@2 225 {
nuclear@2 226 int32_t offs, tm;
nuclear@2 227
nuclear@2 228 CALC_TIME(tm, rate, msec);
nuclear@2 229
nuclear@2 230 switch(mode) {
nuclear@2 231 case CYCLE_PINGPONG:
nuclear@2 232 rsize <<= 8; /* rsize -> 24.8 fixed point */
nuclear@2 233 offs = tm % (rsize * 2);
nuclear@2 234 if(offs > rsize) offs = (rsize * 2) - offs;
nuclear@2 235 rsize >>= 8; /* back to 32.0 */
nuclear@2 236 break;
nuclear@2 237
nuclear@2 238 case CYCLE_SINE:
nuclear@2 239 case CYCLE_SINE_HALF:
nuclear@2 240 {
nuclear@2 241 float t = (float)tm / 256.0; /* convert fixed24.8 -> float */
nuclear@2 242 float x = fmod(t, (float)(rsize * 2));
nuclear@2 243 float foffs = sin((x * M_PI * 2.0) / (float)rsize) + 1.0;
nuclear@2 244 if(mode == CYCLE_SINE_HALF) {
nuclear@2 245 foffs *= rsize / 4.0;
nuclear@2 246 } else {
nuclear@2 247 foffs *= rsize / 2.0;
nuclear@2 248 }
nuclear@2 249 offs = (int32_t)(foffs * 256.0); /* convert float -> fixed24.8 */
nuclear@2 250 }
nuclear@2 251 break;
nuclear@2 252
nuclear@2 253 default: /* normal or reverse */
nuclear@2 254 offs = tm;
nuclear@2 255 }
nuclear@2 256
nuclear@2 257 return offs;
nuclear@2 258 }
nuclear@2 259 #endif /* USE_FLOAT */
nuclear@2 260
nuclear@2 261 #define LERP_FIXED_T(a, b, xt) ((((a) << 8) + ((b) - (a)) * (xt)) >> 8)
nuclear@2 262
nuclear@2 263 void colc_draw(long time_msec)
nuclear@2 264 {
nuclear@2 265 int i, j;
nuclear@2 266
nuclear@2 267 if(!img) return;
nuclear@2 268
nuclear@2 269 if(sslist) {
nuclear@2 270 /* if there is a slideshow list of images, handle switching with fades between them */
nuclear@2 271 if(!fade_dir && (change_pending || time_msec - showing_since > show_time)) {
nuclear@2 272 fade_dir = -1;
nuclear@2 273 fade_start = time_msec;
nuclear@2 274 change_pending = 0;
nuclear@2 275 }
nuclear@2 276
nuclear@2 277 if(fade_dir) {
nuclear@2 278 unsigned long dt = time_msec - fade_start;
nuclear@2 279
nuclear@2 280 if(dt >= fade_dur) {
nuclear@2 281 if(fade_dir == -1) {
nuclear@2 282 sslist = sslist->next;
nuclear@2 283 if(load_slide() == -1) {
nuclear@2 284 return;
nuclear@2 285 }
nuclear@2 286 show_image(img, time_msec);
nuclear@2 287 fade_dir = 1;
nuclear@2 288 time_msec = fade_start = time_msec;
nuclear@2 289 dt = 0;
nuclear@2 290 } else {
nuclear@2 291 set_image_palette(img);
nuclear@2 292 fade_dir = 0;
nuclear@2 293 }
nuclear@2 294 }
nuclear@2 295
nuclear@2 296 if(fade_dir) {
nuclear@2 297 long tx = ((long)dt << 10) / fade_dur;
nuclear@2 298 palfade(fade_dir, tx);
nuclear@2 299 }
nuclear@2 300 showing_since = time_msec;
nuclear@2 301 return;
nuclear@2 302 }
nuclear@2 303 }
nuclear@2 304
nuclear@2 305 /* for each cycling range in the image ... */
nuclear@2 306 for(i=0; i<img->num_ranges; i++) {
nuclear@2 307 int32_t offs, rsize, ioffs;
nuclear@2 308 int rev;
nuclear@2 309
nuclear@2 310 if(!img->range[i].rate) continue;
nuclear@2 311 rsize = img->range[i].high - img->range[i].low + 1;
nuclear@2 312
nuclear@2 313 offs = cycle_offset(img->range[i].cmode, img->range[i].rate, rsize, time_msec);
nuclear@2 314
nuclear@2 315 ioffs = (offs >> 8) % rsize;
nuclear@2 316
nuclear@2 317 /* reverse when rev is 2 */
nuclear@2 318 rev = img->range[i].cmode == CYCLE_REVERSE ? 1 : 0;
nuclear@2 319
nuclear@2 320 for(j=0; j<rsize; j++) {
nuclear@2 321 int pidx, to, next;
nuclear@2 322
nuclear@2 323 pidx = j + img->range[i].low;
nuclear@2 324
nuclear@2 325 if(rev) {
nuclear@2 326 to = (j + ioffs) % rsize;
nuclear@2 327 next = (to + 1) % rsize;
nuclear@2 328 } else {
nuclear@2 329 if((to = (j - ioffs) % rsize) < 0) {
nuclear@2 330 to += rsize;
nuclear@2 331 }
nuclear@2 332 if((next = to - 1) < 0) {
nuclear@2 333 next += rsize;
nuclear@2 334 }
nuclear@2 335 }
nuclear@2 336 to += img->range[i].low;
nuclear@2 337
nuclear@2 338 if(blend) {
nuclear@2 339 int r, g, b;
nuclear@2 340 int32_t frac_offs = offs & 0xff;
nuclear@2 341
nuclear@2 342 next += img->range[i].low;
nuclear@2 343
nuclear@2 344 r = LERP_FIXED_T(img->palette[to].r, img->palette[next].r, frac_offs);
nuclear@2 345 g = LERP_FIXED_T(img->palette[to].g, img->palette[next].g, frac_offs);
nuclear@2 346 b = LERP_FIXED_T(img->palette[to].b, img->palette[next].b, frac_offs);
nuclear@2 347
nuclear@2 348 set_palette(pidx, r, g, b);
nuclear@2 349 } else {
nuclear@2 350 set_palette(pidx, img->palette[to].r, img->palette[to].g, img->palette[to].b);
nuclear@2 351 }
nuclear@2 352 }
nuclear@2 353 }
nuclear@2 354 }
nuclear@2 355
nuclear@2 356
nuclear@2 357 static void set_image_palette(struct image *img)
nuclear@2 358 {
nuclear@2 359 int i;
nuclear@2 360 for(i=0; i<256; i++) {
nuclear@2 361 set_palette(i, img->palette[i].r, img->palette[i].g, img->palette[i].b);
nuclear@2 362 }
nuclear@2 363 }
nuclear@2 364
nuclear@2 365 static void show_image(struct image *img, long time_msec)
nuclear@2 366 {
nuclear@2 367 int i, j;
nuclear@2 368 unsigned char *dptr;
nuclear@2 369 unsigned int max_rate = 0;
nuclear@2 370
nuclear@2 371 resize(img->width, img->height);
nuclear@2 372
nuclear@2 373 dptr = fbpixels;
nuclear@2 374 for(i=0; i<fbheight; i++) {
nuclear@2 375 for(j=0; j<fbwidth; j++) {
nuclear@2 376 unsigned char c = 0;
nuclear@2 377 if(i < img->height && j < img->width) {
nuclear@2 378 c = img->pixels[i * img->width + j];
nuclear@2 379 }
nuclear@2 380 *dptr++ = c;
nuclear@2 381 }
nuclear@2 382 }
nuclear@2 383
nuclear@2 384 showing_since = time_msec;
nuclear@2 385
nuclear@2 386 for(i=0; i<img->num_ranges; i++) {
nuclear@2 387 if(img->range[i].rate > max_rate) {
nuclear@2 388 max_rate = img->range[i].rate;
nuclear@2 389 }
nuclear@2 390 }
nuclear@2 391 upd_interval = max_rate * 10;
nuclear@2 392 }
nuclear@2 393
nuclear@2 394 static int load_slideshow(const char *path)
nuclear@2 395 {
nuclear@2 396 DIR *dir;
nuclear@2 397 struct dirent *dent;
nuclear@2 398 struct ss_node *head = 0, *tail = 0, *node;
nuclear@2 399
nuclear@2 400 if(!(dir = opendir(path))) {
nuclear@2 401 fprintf(stderr, "failed to open directory: %s: %s\n", path, strerror(errno));
nuclear@2 402 return -1;
nuclear@2 403 }
nuclear@2 404
nuclear@2 405 while((dent = readdir(dir))) {
nuclear@2 406 int sz;
nuclear@2 407
nuclear@2 408 if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
nuclear@2 409 continue;
nuclear@2 410 }
nuclear@2 411 sz = strlen(path) + strlen(dent->d_name) + 1; /* +1 for a slash */
nuclear@2 412
nuclear@2 413 if(!(node = malloc(sizeof *node))) {
nuclear@2 414 perror("failed to allocate slideshow node");
nuclear@2 415 goto err;
nuclear@2 416 }
nuclear@2 417 if(!(node->path = malloc(sz + 1))) {
nuclear@2 418 perror("failed to allocate image path");
nuclear@2 419 free(node);
nuclear@2 420 goto err;
nuclear@2 421 }
nuclear@2 422 sprintf(node->path, "%s/%s", path, dent->d_name);
nuclear@2 423 node->img = 0;
nuclear@2 424 node->next = 0;
nuclear@2 425
nuclear@2 426 if(head) {
nuclear@2 427 tail->next = node;
nuclear@2 428 tail = node;
nuclear@2 429 } else {
nuclear@2 430 head = tail = node;
nuclear@2 431 }
nuclear@2 432 }
nuclear@2 433 closedir(dir);
nuclear@2 434
nuclear@2 435 sslist = head;
nuclear@2 436 tail->next = head; /* make circular */
nuclear@2 437 return 0;
nuclear@2 438
nuclear@2 439 err:
nuclear@2 440 closedir(dir);
nuclear@2 441 while(head) {
nuclear@2 442 node = head;
nuclear@2 443 head = head->next;
nuclear@2 444 free(node->path);
nuclear@2 445 free(node);
nuclear@2 446 }
nuclear@2 447 return -1;
nuclear@2 448 }
nuclear@2 449
nuclear@2 450 static int load_slide(void)
nuclear@2 451 {
nuclear@2 452 struct ss_node *start = sslist;
nuclear@2 453
nuclear@2 454 img = 0;
nuclear@2 455 do {
nuclear@2 456 if(sslist->path) {
nuclear@2 457 if(!sslist->img) {
nuclear@2 458 if(!(sslist->img = malloc(sizeof *sslist->img))) {
nuclear@2 459 perror("failed to allocate image structure");
nuclear@2 460 return -1;
nuclear@2 461 }
nuclear@2 462 if(colc_load_image(sslist->img, sslist->path) == -1) {
nuclear@2 463 fprintf(stderr, "failed to load image: %s\n", sslist->path);
nuclear@2 464 free(sslist->path);
nuclear@2 465 sslist->path = 0;
nuclear@2 466 free(sslist->img);
nuclear@2 467 sslist->img = 0;
nuclear@2 468 }
nuclear@2 469 }
nuclear@2 470 img = sslist->img;
nuclear@2 471 }
nuclear@2 472
nuclear@2 473 sslist = sslist->next;
nuclear@2 474 } while(!img && sslist != start);
nuclear@2 475
nuclear@2 476 return img ? 0 : -1;
nuclear@2 477 }