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