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 }
|