winlivebg_test1

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