1 /* LoadDraw.c */
2
3 /* RiscOS Draw file code for InterGif
4 * (K) All Rites Reversed - Copy What You Like (see file Copying)
5 *
6 * Authors:
7 * Peter Hartley <pdh@chaos.org.uk>
8 *
9 * History:
10 * 05-Feb-97 pdh Adapted from aadraw: c.tosprite
11 * 07-Feb-97 *** Release 5.01
12 * 10-Mar-97 pdh Frob a lot for new anim library
13 * 07-Apr-97 *** Release 6beta1
14 * 20-May-97 *** Release 6beta2
15 * 24-Aug-97 *** Release 6
16 * 27-Sep-97 *** Release 6.01
17 * 08-Nov-97 *** Release 6.02
18 * 10-Feb-98 pdh Anti-alias in strips if short of memory
19 * 21-Feb-98 *** Release 6.03
20 * 07-Jun-98 *** Release 6.04
21 * 01-Aug-98 pdh Frob for anim_imagefn stuff
22 * 21-Aug-98 *** Release 6.05
23 * 05-Oct-98 pdh Disable Wimp_CommandWindow; fix error reporting
24 * 05-Oct-98 *** Release 6.06
25 * 19-Feb-99 *** Release 6.07
26 * 26-Mar-00 *** Release 6.10
27 * 10-Dec-00 pdh Fix 8bpp code
28 * 10-Dec-00 *** Release 6.12
29 *
30 * References:
31 * http://utter.chaos.org.uk/~pdh/software/aadraw.htm
32 * pdh's AADraw home page
33 *
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 /* We're allowed to include these headers, 'cos we only compile under RiscOS
41 * anyway
42 */
43 #include "DeskLib:Sprite.h"
44 #include "DeskLib:Str.h"
45 #include "DeskLib:GFX.h"
46 #include "DeskLib:Wimp.h"
47 #include "DeskLib:WimpSWIs.h"
48 #include "DeskLib:SWI.h"
49 #include "DeskLib:ColourTran.h"
50
51 #include "utils.h"
52
53 #include "animlib.h"
54 #include "antialias.h"
55
56 #if 0
57 #define debugf printf
58 #define DEBUG 1
59 #else
60 #define debugf 1?0:printf
61 #define DEBUG 0
62 #endif
63
64
65 typedef struct
66 {
67 int x0,y0;
68 int x1,y1;
69 int x2,y2;
70 } draw_matrix;
71
72
73 /*---------------------------------------------------------------------------*
74 * System calls in riscos.s *
75 *---------------------------------------------------------------------------*/
76
77 os_error *DrawFile_BBox( int flags, const void *pDrawfile, int drawsize,
78 draw_matrix *pDM, wimp_box *pResult );
79 os_error *DrawFile_Render( int flags, const void *pDrawfile, int drawsize,
80 draw_matrix *pDM, wimp_box *pResult );
81
82 BOOL OSModule_Present( char *name );
83 os_error *OSModule_Load( char *pathname );
84
85 int TaskWindow_TaskInfo( int index );
86
87
88 /*---------------------------------------------------------------------------*
89 * Constructor *
90 *---------------------------------------------------------------------------*/
91
Anim_ConvertDraw(const void * data,unsigned int nSize,anim_animfn animfn,anim_imagefn fn,void * handle)92 BOOL Anim_ConvertDraw( const void *data, unsigned int nSize,
93 anim_animfn animfn, anim_imagefn fn, void *handle )
94 {
95 draw_matrix tm = { 0x10000 * ANIM_AAFACTOR, 0,
96 0, 0x10000 * ANIM_AAFACTOR,
97 0, 0 };
98 wimp_box box;
99 int spritex, spritey;
100 int i, r,g,b;
101 sprite_outputstate sos;
102 int areasize;
103 sprite_area area = NULL;
104 sprite_header *pSprite;
105 unsigned int palette[256];
106 unsigned int *pPal;
107 int w,h;
108 int pass, passes, sectiony, basey2;
109 anim_imageinfo pixels;
110 os_error *e = NULL;
111 BOOL bits24 = TRUE;
112
113 /* check it's a Draw file, if not return NULL */
114
115 if ( *(int*)data != 0x77617244 ) /* "Draw" */
116 return NULL;
117
118 if ( TaskWindow_TaskInfo(0) != 0 )
119 {
120 Anim_SetError( "InterGif cannot process Draw files in a taskwindow. "
121 "Please either press F12 or use the desktop front-end." );
122 return NULL;
123 }
124
125 if ( !OSModule_Present( "DrawFile" ) )
126 {
127 os_error *e;
128 e = OSModule_Load( "System:Modules.Drawfile" );
129
130 if ( e )
131 {
132 Anim_SetError( "DrawFile module not loaded: %s", e->errmess );
133 return NULL;
134 }
135 }
136
137 if ( DrawFile_BBox( 0, data, nSize, &tm, &box ) )
138 {
139 Anim_SetError( "Invalid Draw file\n" );
140 return NULL;
141 }
142
143 tm.x2 = 3584-box.min.x;
144 tm.y2 = basey2 = 3584-box.min.y;
145 box.min.x = box.min.x / 256;
146 box.max.x = box.max.x / 256;
147 box.min.y = box.min.y / 256;
148 box.max.y = box.max.y / 256;
149
150 w = (box.max.x - box.min.x)/2 + 16;
151 w = (w + ANIM_AAFACTOR - 1) / ANIM_AAFACTOR;
152
153 h = (box.max.y - box.min.y)/2 + 16;
154 h = (h + ANIM_AAFACTOR - 1) / ANIM_AAFACTOR;
155
156 if ( animfn && !(*animfn)( handle, w, h, 0 ) )
157 {
158 debugf( "convertdraw: animfn returned FALSE, exiting\n" );
159 return FALSE;
160 }
161
162 /* pixels.pBits = NULL;
163 Anim_FlexAllocate( &pixels.pBits, w*h ); */
164
165 debugf( "convertdraw: w=%d h=%d box=(%d,%d)..(%d,%d)\n", w, h,
166 box.min.x, box.min.y, box.max.x, box.max.y );
167
168 tryagain:
169
170 if ( bits24 )
171 pixels.pBits = Anim_Allocate( w*h*4 );
172 else
173 pixels.pBits = Anim_Allocate( w*h ); /* Note not word-aligned */
174
175 if ( !pixels.pBits )
176 {
177 Anim_NoMemory( "fromdraw" );
178 return NULL;
179 }
180
181 #if DEBUG
182 memset( pixels.pBits, 91, w*h );
183 #endif
184
185 spritex = w * ANIM_AAFACTOR;
186 spritey = h * ANIM_AAFACTOR;
187
188 /* Plotting it three times the size and anti-aliasing down produces very
189 * nice results, but needs lllots of memory. If memory's a bit short, we
190 * try doing it in strips in a multi-pass fashion -- not unlike !Printers.
191 */
192
193 for ( passes = 1; passes < 65; passes*=2 )
194 {
195 sectiony = (( h + passes-1 ) / passes) * ANIM_AAFACTOR;
196
197 if ( bits24 )
198 {
199 areasize = sectiony*spritex*4 + sizeof(sprite_header);
200 areasize += sizeof(sprite_areainfo);
201 }
202 else
203 {
204 areasize = sectiony * ( (spritex+3) & ~3) + sizeof(sprite_header);
205 areasize += 256*8 + sizeof(sprite_areainfo);
206 }
207
208 if ( !sectiony )
209 break;
210
211 debugf( "fromdraw: Allocating %d bytes\n", areasize );
212
213 Anim_FlexAllocate( &area, areasize );
214
215 if ( area )
216 break;
217
218 debugf( "fromdraw: Allocate failed, trying smaller\n" );
219 }
220
221 if ( !area )
222 {
223 Anim_NoMemory( "fromdraw2" );
224 Anim_Free( &pixels.pBits );
225 return FALSE;
226 }
227
228 debugf( "fromdraw: Allocate succeeded\n" );
229
230 area->areasize = areasize;
231 area->numsprites = 0;
232 area->firstoffset =
233 area->freeoffset = 16;
234
235 debugf( "Creating big sprite (%dx%d,%d bytes) total size would be %dx%d\n",
236 spritex, sectiony, areasize, spritex, spritey );
237
238 e = Sprite_Create( area, "drawfile", FALSE, spritex, sectiony,
239 bits24 ? ((6<<27)+(90<<14)+(90<<1)+1) : 28 );
240
241 /* Sprite_Create will give an error on old (non-24-bit-capable) machines
242 * so try again in 8bit
243 */
244 if ( e && bits24 )
245 {
246 Anim_Free( &pixels.pBits );
247 Anim_FlexFree( &area );
248 bits24 = FALSE;
249 goto tryagain;
250 }
251
252 #if DEBUG
253 if ( e )
254 {
255 debugf( "fromdraw: spritecreate fails, %s\n", e->errmess );
256 }
257 #endif
258 debugf( "areasize=%d, freeoffset now %d\n", areasize, area->freeoffset );
259
260 pSprite = (sprite_header*)((char*)area + 16);
261
262 if ( !bits24 )
263 {
264 debugf( "Building palette\n" );
265
266 pPal = palette;
267 memset( pPal, 0, 256*4 );
268 pPal[255] = 0xFFFFFF00;
269 for ( r=0; r<6; r++ )
270 for ( g=0; g<6; g++ )
271 for ( b=0; b<6; b++ )
272 *pPal++ = r*0x33000000 + g*0x330000 + b*0x3300;
273
274 debugf( "Copying palette into sprite\n" );
275
276 pPal = (unsigned int*)(pSprite+1);
277
278 for ( i=0; i<255; i++ )
279 {
280 *pPal++ = palette[i];
281 *pPal++ = palette[i];
282 }
283
284 pSprite->imageoffset += 256*8;
285 pSprite->maskoffset += 256*8;
286 pSprite->offset_next += 256*8;
287 area->freeoffset += 256*8;
288 }
289
290 debugf( "areasize=%d, freeoffset now %d\n", areasize, area->freeoffset );
291
292 Wimp_CommandWindow(-1);
293
294 for ( pass=0; pass<passes; pass++ )
295 {
296 int thisy = sectiony/ANIM_AAFACTOR;
297 int offset = (pass*sectiony)/ANIM_AAFACTOR;
298
299 tm.y2 = basey2 - (h-offset-thisy)*256*ANIM_AAFACTOR*2;
300
301 if ( thisy + offset > h )
302 thisy = h - offset;
303
304 debugf( "Pass %d: thisy=%d offset=%d\n", pass, thisy, offset );
305
306 offset *= w;
307
308 debugf( "Blanking sprite\n" );
309
310 memset( ((char*)pSprite) + pSprite->imageoffset, 255,
311 (pSprite->width+1)*sectiony*4 );
312
313 debugf( "Plotting drawfile\n" );
314
315 e = Sprite_Redirect( area, "drawfile", NULL, &sos );
316 if ( !e )
317 {
318 DrawFile_Render( 0, data, nSize, &tm, NULL );
319 Sprite_UnRedirect( &sos );
320 }
321
322 #if DEBUG
323 Sprite_Save( area, "igdebug" );
324 /*{
325 FILE *f = fopen( "igdebug2", "wb" );
326 fwrite( &area->numsprites, 1, area->areasize-4, f );
327 fclose(f);
328 } */
329 #endif
330
331 if ( e )
332 {
333 debugf( "Error: %s\n", e->errmess );
334 break;
335 }
336
337 debugf( "Anti-aliasing\n" );
338
339 if ( bits24 )
340 {
341 Anim_AntiAlias24( (unsigned int*)( (char*)pSprite + pSprite->imageoffset ),
342 spritex,
343 ((unsigned int*)pixels.pBits) + offset,
344 w, thisy );
345 }
346 else
347 {
348 Anim_AntiAlias( (pixel*)pSprite + pSprite->imageoffset,
349 (spritex+3) & ~3,
350 ((pixel*)pixels.pBits) + offset,
351 w, thisy );
352 }
353 }
354
355 Anim_FlexFree( &area );
356
357 if ( e )
358 {
359 Anim_SetError( "fromdraw: plot failed, %s", e->errmess );
360 Anim_Free( &pixels.pBits );
361 return FALSE;
362 }
363
364 Wimp_CommandWindow(-1);
365
366 /* Compress the frame */
367
368 pixels.nWidth = w;
369 pixels.nLineWidthBytes = bits24 ? w*4 : w;
370 pixels.nHeight = h;
371 pixels.nBPP = bits24 ? 32 : 8;
372 pixels.csDelay = 8;
373
374 #if DEBUG
375 {
376 sprite_areainfo sai;
377 int imgsize = h*pixels.nLineWidthBytes;
378 sprite_header sh;
379 FILE *f = fopen("igdebug2", "wb");
380
381 sai.numsprites = 1;
382 sai.firstoffset = 16;
383 sai.freeoffset = 16 + sizeof(sprite_header) + imgsize;
384 fwrite( &sai.numsprites, 1, 12, f );
385 sh.offset_next = sizeof(sprite_header) + imgsize;
386 strncpy( sh.name, "drawfile2", 12 );
387 sh.width = (pixels.nLineWidthBytes/4)-1;
388 sh.height = h-1;
389 sh.leftbit = 0;
390 sh.rightbit = 31;
391 sh.imageoffset = sh.maskoffset = sizeof(sprite_header);
392 sh.screenmode = bits24 ? (6<<27) + (90<<14) + (90<<1) + 1 : 28;
393 fwrite( &sh, 1, sizeof(sprite_header), f );
394 fwrite( pixels.pBits, 1, imgsize, f );
395 fclose( f );
396 }
397 #endif
398
399 if ( !(*fn)( handle, &pixels, bits24 ? -1 : 255, NULL,
400 bits24 ? NULL : palette ) )
401 {
402 debugf("convertdraw: fn returned FALSE, exiting\n" );
403 Anim_Free( &pixels.pBits );
404 return FALSE;
405 }
406
407 Anim_Free( &pixels.pBits );
408
409 return TRUE;
410 }
411
412
413 /*---------------------------------------------------------------------------*
414 * Anti-aliasing routine -- reduces by a scale of ANIM_AAFACTOR in each *
415 * direction. *
416 * Does sensible things with background areas so it's easy to make a true *
417 * transparent GIF from the output. *
418 * Using a regular colour cube to dither into makes the code trivial *
419 * (compared to what ChangeFSI must do, for instance) -- but that's still no *
420 * excuse for not doing Floyd-Steinberg :-( *
421 *---------------------------------------------------------------------------*/
422
Anim_AntiAlias(const pixel * srcBits,unsigned int abwSrc,pixel * destBits,unsigned int w,unsigned int h)423 void Anim_AntiAlias( const pixel *srcBits, unsigned int abwSrc,
424 pixel *destBits, unsigned int w, unsigned int h )
425 {
426 int x,y,i,j;
427 unsigned int r,g,b,t;
428 char byte;
429 char bgbyte;
430 int abwDest = w; /* Dest is byte-packed, NOT sprite format */
431 char ra[256],ga[256],ba[256];
432 char dividebyf2[ANIM_AAFACTOR*ANIM_AAFACTOR*6];
433
434 /* Precalculate divisions by 6 to speed up dither */
435 for (r=0; r<6; r++)
436 for (g=0; g<6; g++)
437 for (b=0; b<6; b++)
438 {
439 ra[r*36+g*6+b] = r;
440 ga[r*36+g*6+b] = g;
441 ba[r*36+g*6+b] = b;
442 }
443
444 /* Precalculate divisions by ANIM_AAFACTOR*ANIM_AAFACTOR */
445 for ( i=0; i < ANIM_AAFACTOR*ANIM_AAFACTOR*6; i++ )
446 {
447 j = (i<<8) / (ANIM_AAFACTOR*ANIM_AAFACTOR);
448 dividebyf2[i] = (j>>8); /* + ((j&128)?1:0);*/
449 }
450
451 bgbyte = 215;
452
453 for ( y=0; y < h; y++ )
454 {
455 for ( x=0; x < w; x++ )
456 {
457 r=g=b=t=0;
458 for (i=0; i<ANIM_AAFACTOR; i++)
459 for (j=0; j<ANIM_AAFACTOR; j++)
460 {
461 byte = srcBits[x*ANIM_AAFACTOR+i+j*abwSrc];
462 if ( byte==255 )
463 {
464 byte=bgbyte;
465 t++;
466 }
467 b += ba[byte]; g += ga[byte]; r += ra[byte];
468 }
469 if ( t == ANIM_AAFACTOR*ANIM_AAFACTOR )
470 destBits[x] = 255;
471 else
472 {
473 destBits[x] = 36 * dividebyf2[r]
474 + 6 * dividebyf2[g]
475 + dividebyf2[b];
476 }
477 }
478 destBits += abwDest;
479 srcBits += abwSrc*ANIM_AAFACTOR;
480 }
481 }
482
Anim_AntiAlias24(const unsigned int * srcBits,unsigned int wSrc,unsigned int * destBits,unsigned int w,unsigned int h)483 void Anim_AntiAlias24( const unsigned int *srcBits, unsigned int wSrc,
484 unsigned int *destBits, unsigned int w, unsigned int h )
485 {
486 int x,y,i,j;
487 unsigned int r,g,b,t,word;
488 char dividebyf2[ANIM_AAFACTOR*ANIM_AAFACTOR*256];
489
490 /* Precalculate divisions by ANIM_AAFACTOR^2 */
491 for ( i=0; i < sizeof(dividebyf2); i++ )
492 {
493 j = (i<<8) / (ANIM_AAFACTOR*ANIM_AAFACTOR);
494 dividebyf2[i] = j>>8;
495 }
496
497 for ( y=0; y<h; y++ )
498 {
499 for ( x=0; x<w; x++ )
500 {
501 r=g=b=t=0;
502 for ( i=0; i<ANIM_AAFACTOR; i++ )
503 for ( j=0; j<ANIM_AAFACTOR; j++ )
504 {
505 word = srcBits[x*ANIM_AAFACTOR+i+j*wSrc];
506 if ( word == (unsigned)-1 )
507 {
508 t++;
509 }
510 r += (word & 0xFF);
511 g += (word & 0xFF00)>>8;
512 b += (word & 0xFF0000)>>16;
513 /*b += (word & 0xFF000000)>>24;*/
514 }
515
516 if ( t == ANIM_AAFACTOR*ANIM_AAFACTOR )
517 destBits[x] = (unsigned)-1;
518 else
519 {
520 destBits[x] = ( dividebyf2[b] << 16 )
521 + ( dividebyf2[g] << 8 )
522 + ( dividebyf2[r] << 0 );
523 }
524 }
525 destBits += w;
526 srcBits += wSrc*ANIM_AAFACTOR;
527 }
528 }
529
530 /* eof */
531