94660cb94a1c4778934dd84f075029306ac316aa
[btb/d2x.git] / 2d / bitmap.c
1 /* $Id: bitmap.c,v 1.5 2002-10-10 19:11:23 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Graphical routines for manipulating grs_bitmaps.
18  *
19  * Old Log:
20  * Revision 1.11  1995/08/23  18:46:06  allender
21  * fixed compiler warning
22  *
23  * Revision 1.10  1995/08/14  14:25:45  allender
24  * changed transparency color to 0
25  *
26  * Revision 1.9  1995/07/05  16:04:51  allender
27  * transparency/game kitchen changes
28  *
29  * Revision 1.8  1995/06/15  09:50:48  allender
30  * new malloc to align bitmap on 8 byte bountry
31  *
32  * Revision 1.7  1995/05/12  11:52:19  allender
33  * changed memory stuff again
34  *
35  * Revision 1.6  1995/05/11  12:48:34  allender
36  * nge transparency color
37  *
38  * Revision 1.5  1995/05/04  19:59:21  allender
39  * use NewPtr instead of malloc
40  *
41  * Revision 1.4  1995/04/27  07:33:04  allender
42  * rearrange functions
43  *
44  * Revision 1.3  1995/04/19  14:37:17  allender
45  * removed dead asm code
46  *
47  * Revision 1.2  1995/04/18  12:04:51  allender
48  * *** empty log message ***
49  *
50  * Revision 1.1  1995/03/09  08:48:06  allender
51  * Initial revision
52  *
53  *
54  * -------  PC version RCS information
55  * Revision 1.17  1994/11/18  22:50:25  john
56  * Changed shorts to ints in parameters.
57  *
58  * Revision 1.16  1994/11/10  15:59:46  john
59  * Fixed bugs with canvas's being created with bogus bm_flags.
60  *
61  * Revision 1.15  1994/10/26  23:55:53  john
62  * Took out roller; Took out inverse table.
63  *
64  * Revision 1.14  1994/09/19  14:40:21  john
65  * Changed dpmi stuff.
66  *
67  * Revision 1.13  1994/09/19  11:44:04  john
68  * Changed call to allocate selector to the dpmi module.
69  *
70  * Revision 1.12  1994/06/09  13:14:57  john
71  * Made selectors zero our
72  * out, I meant.
73  *
74  * Revision 1.11  1994/05/06  12:50:07  john
75  * Added supertransparency; neatend things up; took out warnings.
76  *
77  * Revision 1.10  1994/04/08  16:59:39  john
78  * Add fading poly's; Made palette fade 32 instead of 16.
79  *
80  * Revision 1.9  1994/03/16  17:21:09  john
81  * Added slow palette searching options.
82  *
83  * Revision 1.8  1994/03/14  17:59:35  john
84  * Added function to check bitmap's transparency.
85  *
86  * Revision 1.7  1994/03/14  17:16:21  john
87  * fixed bug with counting freq of pixels.
88  *
89  * Revision 1.6  1994/03/14  16:55:47  john
90  * Changed grs_bitmap structure to include bm_flags.
91  *
92  * Revision 1.5  1994/02/18  15:32:22  john
93  * *** empty log message ***
94  *
95  * Revision 1.4  1993/10/15  16:22:49  john
96  * *** empty log message ***
97  *
98  * Revision 1.3  1993/09/08  17:37:11  john
99  * Checking for errors with Yuan...
100  *
101  * Revision 1.2  1993/09/08  14:46:27  john
102  * looking for possible bugs...
103  *
104  * Revision 1.1  1993/09/08  11:43:05  john
105  * Initial revision
106  *
107  */
108
109 #ifdef HAVE_CONFIG_H
110 #include <conf.h>
111 #endif
112
113 #include <stdlib.h>
114 #include <stdio.h>
115
116 #include "u_mem.h"
117
118
119 #include "gr.h"
120 #include "grdef.h"
121 #include "u_dpmi.h"
122 #include "error.h"
123
124 #if defined(POLY_ACC)
125 #include "poly_acc.h"
126 #endif
127
128 #ifdef OGL
129 #include "ogl_init.h"
130 #endif
131
132 void gr_set_bitmap_data (grs_bitmap *bm, unsigned char *data)
133 {
134 #ifdef OGL
135 //      if (bm->bm_data!=data)
136                 ogl_freebmtexture(bm);
137 #endif
138         bm->bm_data = data;
139 #ifdef D1XD3D
140         Assert (bm->iMagic == BM_MAGIC_NUMBER);
141         Win32_SetTextureBits (bm, data, bm->bm_flags & BM_FLAG_RLE);
142 #endif
143 }
144
145 grs_bitmap *gr_create_bitmap(int w, int h )
146 {
147         return gr_create_bitmap_raw (w, h, d_malloc(w * h));
148 }
149
150 grs_bitmap *gr_create_bitmap_raw(int w, int h, unsigned char * raw_data )
151 {
152     grs_bitmap *new;
153
154     new = (grs_bitmap *)d_malloc( sizeof(grs_bitmap) );
155         gr_init_bitmap (new, 0, 0, 0, w, h, w, raw_data);
156
157     return new;
158 }
159
160
161 #if defined(POLY_ACC)
162 //
163 //  Creates a bitmap of the requested size and type.
164 //    w, and h are in pixels.
165 //    type is a BM_... and is used to set the rowsize.
166 //    if data is NULL, memory is allocated, otherwise data is used for bm_data.
167 //
168 //  This function is used only by the polygon accelerator code to handle the mixture of 15bit and
169 //  8bit bitmaps.
170 //
171 grs_bitmap *gr_create_bitmap2(int w, int h, int type, void *data )
172 {
173         grs_bitmap *new;
174
175         new = (grs_bitmap *)malloc( sizeof(grs_bitmap) );
176         new->bm_x = 0;
177         new->bm_y = 0;
178         new->bm_w = w;
179         new->bm_h = h;
180         new->bm_flags = 0;
181     new->bm_type = type;
182     switch(type)
183     {
184         case BM_LINEAR:     new->bm_rowsize = w;            break;
185         case BM_LINEAR15:   new->bm_rowsize = w*PA_BPP;     break;
186         default: Int3();    // unsupported type.
187     }
188     if(data)
189         new->bm_data = data;
190     else
191         new->bm_data = malloc(new->bm_rowsize * new->bm_h);
192         new->bm_handle = 0;
193
194         return new;
195 }
196 #endif
197
198 void gr_init_bitmap( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline, unsigned char * data ) // TODO: virtualize
199 {
200 #ifdef D1XD3D
201         Assert (bm->iMagic != BM_MAGIC_NUMBER || bm->pvSurface == NULL);
202 #endif
203
204         bm->bm_x = x;
205         bm->bm_y = y;
206         bm->bm_w = w;
207         bm->bm_h = h;
208         bm->bm_flags = 0;
209         bm->bm_type = mode;
210         bm->bm_rowsize = bytesperline;
211
212         bm->bm_data = NULL;
213 #ifdef D1XD3D
214         bm->iMagic = BM_MAGIC_NUMBER;
215         bm->pvSurface = NULL;
216 #endif
217
218 #ifdef D1XD3D
219         Win32_CreateTexture (bm);
220 #endif
221 #ifdef OGL
222         bm->bm_parent=NULL;bm->gltexture=NULL;
223 #endif
224
225 //      if (data != 0)
226                 gr_set_bitmap_data (bm, data);
227 /*
228         else
229                 gr_set_bitmap_data (bm, d_malloc (w * h));
230 */
231
232 #ifdef BITMAP_SELECTOR
233         bm->bm_selector = 0;
234 #endif
235 }
236
237 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline)
238 {
239         gr_init_bitmap(bm, mode, x, y, w, h, bytesperline, 0);
240         gr_set_bitmap_data(bm, d_malloc(w * h));
241 }
242
243 void gr_init_bitmap_data (grs_bitmap *bm) // TODO: virtulize
244 {
245         bm->bm_data = NULL;
246 #ifdef D1XD3D
247         Assert (bm->iMagic != BM_MAGIC_NUMBER);
248         bm->iMagic = BM_MAGIC_NUMBER;
249         bm->pvSurface = NULL;
250 #endif
251 #ifdef OGL
252 //      ogl_freebmtexture(bm);//not what we want here.
253         bm->bm_parent=NULL;bm->gltexture=NULL;
254 #endif
255 }
256
257 grs_bitmap *gr_create_sub_bitmap(grs_bitmap *bm, int x, int y, int w, int h )
258 {
259     grs_bitmap *new;
260
261     new = (grs_bitmap *)d_malloc( sizeof(grs_bitmap) );
262         gr_init_sub_bitmap (new, bm, x, y, w, h);
263
264         return new;
265 }
266
267 void gr_free_bitmap(grs_bitmap *bm )
268 {
269         gr_free_bitmap_data (bm);
270         if (bm!=NULL)
271                 d_free(bm);
272 }
273
274 void gr_free_sub_bitmap(grs_bitmap *bm )
275 {
276         if (bm!=NULL)
277         {
278 #ifdef D1XD3D
279                 bm->iMagic = 0;
280 #endif
281                 d_free(bm);
282         }
283 }
284
285
286 void gr_free_bitmap_data (grs_bitmap *bm) // TODO: virtulize
287 {
288 #ifdef D1XD3D
289         Assert (bm->iMagic == BM_MAGIC_NUMBER);
290
291         Win32_FreeTexture (bm);
292         bm->iMagic = 0;
293         if (bm->bm_data == BM_D3D_RENDER)
294                 bm->bm_data = NULL;
295 #endif
296 #ifdef OGL
297         ogl_freebmtexture(bm);
298 #endif
299         if (bm->bm_data != NULL)
300                 d_free (bm->bm_data);
301         bm->bm_data = NULL;
302 }
303
304 void gr_init_sub_bitmap (grs_bitmap *bm, grs_bitmap *bmParent, int x, int y, int w, int h )     // TODO: virtualize
305 {
306         bm->bm_x = x + bmParent->bm_x;
307         bm->bm_y = y + bmParent->bm_y;
308         bm->bm_w = w;
309         bm->bm_h = h;
310         bm->bm_flags = bmParent->bm_flags;
311         bm->bm_type = bmParent->bm_type;
312         bm->bm_rowsize = bmParent->bm_rowsize;
313
314 #ifdef OGL
315         bm->gltexture=bmParent->gltexture;
316         bm->bm_parent=bmParent;
317 #endif
318 #ifdef D1XD3D
319         Assert (bmParent->iMagic == BM_MAGIC_NUMBER);
320         bm->iMagic = BM_MAGIC_NUMBER;
321         bm->pvSurface = bmParent->pvSurface;
322         if (bm->bm_type == BM_DIRECTX)
323         {
324                 bm->bm_data = bmParent->bm_data;
325         }
326         else
327 #endif
328         {
329                 bm->bm_data = bmParent->bm_data+(unsigned int)((y*bmParent->bm_rowsize)+x);
330         }
331
332 }
333
334 void decode_data_asm(ubyte *data, int num_pixels, ubyte * colormap, int * count );
335
336 #if !defined(NO_ASM) && defined(__WATCOMC__)
337
338 #pragma aux decode_data_asm parm [esi] [ecx] [edi] [ebx] modify exact [esi edi eax ebx ecx] = \
339 "again_ddn:"                                                    \
340         "xor    eax,eax"                                \
341         "mov    al,[esi]"                       \
342         "inc    dword ptr [ebx+eax*4]"          \
343         "mov    al,[edi+eax]"           \
344         "mov    [esi],al"                       \
345         "inc    esi"                                    \
346         "dec    ecx"                                    \
347         "jne    again_ddn"
348
349 #elif !defined(NO_ASM) && defined(__GNUC__)
350
351 inline void decode_data_asm(ubyte *data, int num_pixels, ubyte * colormap, int * count ) {
352         int dummy[4];
353    __asm__ __volatile__ (
354     "xorl   %%eax,%%eax;"
355 "0:;"
356     "movb   (%%esi), %%al;"
357     "incl   (%%ebx, %%eax, 4);"
358     "movb   (%%edi, %%eax), %%al;"
359     "movb   %%al, (%%esi);"
360     "incl   %%esi;"
361     "decl   %%ecx;"
362     "jne    0b"
363     : "=S" (dummy[0]), "=c" (dummy[1]), "=D" (dummy[2]), "=b" (dummy[3])
364         : "0" (data), "1" (num_pixels), "2" (colormap), "3" (count)
365         : "%eax");
366 }
367
368 #elif !defined(NO_ASM) && defined(_MSC_VER)
369
370 __inline void decode_data_asm(ubyte *data, int num_pixels, ubyte * colormap, int * count )
371 {
372   __asm {
373         mov esi,[data]
374         mov ecx,[num_pixels]
375         mov edi,[colormap]
376         mov ebx,[count]
377 again_ddn:
378         xor eax,eax
379         mov al,[esi]
380         inc dword ptr [ebx+eax*4]
381         mov al,[edi+eax]
382         mov [esi],al
383         inc esi
384         dec ecx
385         jne again_ddn
386   }
387 }
388
389 #else // NO_ASM or unknown compiler
390
391 void decode_data_asm(ubyte *data, int num_pixels, ubyte *colormap, int *count)
392 {
393         int i;
394         ubyte mapped;
395
396         for (i = 0; i < num_pixels; i++) {
397                 count[*data]++;
398                 mapped = *data;
399                 *data = colormap[mapped];
400                 data++;
401         }
402 }
403
404 #endif
405
406 void gr_set_bitmap_flags (grs_bitmap *pbm, int flags)
407 {
408 #ifdef D1XD3D
409         Assert (pbm->iMagic == BM_MAGIC_NUMBER);
410
411         if (pbm->pvSurface)
412         {
413                 if ((flags & BM_FLAG_TRANSPARENT) != (pbm->bm_flags & BM_FLAG_TRANSPARENT))
414                 {
415                         Win32_SetTransparent (pbm->pvSurface, flags & BM_FLAG_TRANSPARENT);
416                 }
417         }
418 #endif
419         pbm->bm_flags = flags;
420 }
421
422 void gr_set_transparent (grs_bitmap *pbm, int bTransparent)
423 {
424         if (bTransparent)
425         {
426                 gr_set_bitmap_flags (pbm, pbm->bm_flags | BM_FLAG_TRANSPARENT);
427         }
428         else
429         {
430                 gr_set_bitmap_flags (pbm, pbm->bm_flags & ~BM_FLAG_TRANSPARENT);
431         }
432 }
433
434 void gr_set_super_transparent (grs_bitmap *pbm, int bTransparent)
435 {
436         if (bTransparent)
437         {
438                 gr_set_bitmap_flags (pbm, pbm->bm_flags & ~BM_FLAG_SUPER_TRANSPARENT);
439         }
440         else
441         {
442                 gr_set_bitmap_flags (pbm, pbm->bm_flags | BM_FLAG_SUPER_TRANSPARENT);
443         }
444 }
445
446 void build_colormap_good( ubyte * palette, ubyte * colormap, int * freq )
447 {
448         int i, r, g, b;
449
450         for (i=0; i<256; i++ )  {
451                 r = *palette++;
452                 g = *palette++;
453                 b = *palette++;
454                 *colormap++ = gr_find_closest_color( r, g, b );
455                 *freq++ = 0;
456         }
457 }
458
459 void gr_remap_bitmap( grs_bitmap * bmp, ubyte * palette, int transparent_color, int super_transparent_color )
460 {
461         ubyte colormap[256];
462         int freq[256];
463
464         if (bmp->bm_type != BM_LINEAR)
465                 return;  //can't do it
466
467         // This should be build_colormap_asm, but we're not using invert table, so...
468         build_colormap_good( palette, colormap, freq );
469
470         if ( (super_transparent_color>=0) && (super_transparent_color<=255))
471                 colormap[super_transparent_color] = 254;
472
473         if ( (transparent_color>=0) && (transparent_color<=255))
474                 colormap[transparent_color] = TRANSPARENCY_COLOR;
475
476         decode_data_asm(bmp->bm_data, bmp->bm_w * bmp->bm_h, colormap, freq );
477
478         if ( (transparent_color>=0) && (transparent_color<=255) && (freq[transparent_color]>0) )
479                 gr_set_transparent (bmp, 1);
480
481         if ( (super_transparent_color>=0) && (super_transparent_color<=255) && (freq[super_transparent_color]>0) )
482                 gr_set_super_transparent (bmp, 0);
483 }
484
485 void gr_remap_bitmap_good( grs_bitmap * bmp, ubyte * palette, int transparent_color, int super_transparent_color )
486 {
487         ubyte colormap[256];
488         int freq[256];
489         build_colormap_good( palette, colormap, freq );
490
491         if ( (super_transparent_color>=0) && (super_transparent_color<=255))
492                 colormap[super_transparent_color] = 254;
493
494         if ( (transparent_color>=0) && (transparent_color<=255))
495                 colormap[transparent_color] = TRANSPARENCY_COLOR;
496
497         if (bmp->bm_w == bmp->bm_rowsize)
498                 decode_data_asm(bmp->bm_data, bmp->bm_w * bmp->bm_h, colormap, freq );
499         else {
500                 int y;
501                 ubyte *p = bmp->bm_data;
502                 for (y=0;y<bmp->bm_h;y++,p+=bmp->bm_rowsize)
503                         decode_data_asm(p, bmp->bm_w, colormap, freq );
504         }
505
506         if ( (transparent_color>=0) && (transparent_color<=255) && (freq[transparent_color]>0) )
507                 gr_set_transparent (bmp, 1);
508
509         if ( (super_transparent_color>=0) && (super_transparent_color<=255) && (freq[super_transparent_color]>0) )
510                 gr_set_super_transparent (bmp, 1);
511 }
512
513 #ifdef BITMAP_SELECTOR
514 int gr_bitmap_assign_selector( grs_bitmap * bmp )
515 {
516         if (!dpmi_allocate_selector( bmp->bm_data, bmp->bm_w*bmp->bm_h, &bmp->bm_selector )) {
517                 bmp->bm_selector = 0;
518                 return 1;
519         }
520         return 0;
521 }
522 #endif
523
524 void gr_bitmap_check_transparency( grs_bitmap * bmp )
525 {
526         int x, y;
527         ubyte * data;
528
529         data = bmp->bm_data;
530
531         for (y=0; y<bmp->bm_h; y++ )    {
532                 for (x=0; x<bmp->bm_w; x++ )    {
533                         if (*data++ == TRANSPARENCY_COLOR )     {
534                                 gr_set_transparent (bmp, 1);
535                                 return;
536                         }
537                 }
538                 data += bmp->bm_rowsize - bmp->bm_w;
539         }
540
541         bmp->bm_flags = 0;
542
543 }