]> icculus.org git repositories - btb/d2x.git/blob - 2d/bitmap.c
fixed opengl menu font bug, caused by doing arithmetic on signed chars.
[btb/d2x.git] / 2d / bitmap.c
1 /* $Id: bitmap.c,v 1.7 2004-08-28 23:17:45 schaffner 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  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24
25 #include <stdlib.h>
26 #include <stdio.h>
27
28 #include "u_mem.h"
29
30
31 #include "gr.h"
32 #include "grdef.h"
33 #include "u_dpmi.h"
34 #include "error.h"
35
36 #if defined(POLY_ACC)
37 #include "poly_acc.h"
38 #endif
39
40 #ifdef OGL
41 #include "ogl_init.h"
42 #endif
43
44 void gr_set_bitmap_data (grs_bitmap *bm, unsigned char *data)
45 {
46 #ifdef OGL
47 //      if (bm->bm_data!=data)
48                 ogl_freebmtexture(bm);
49 #endif
50         bm->bm_data = data;
51 #ifdef D1XD3D
52         Assert (bm->iMagic == BM_MAGIC_NUMBER);
53         Win32_SetTextureBits (bm, data, bm->bm_flags & BM_FLAG_RLE);
54 #endif
55 }
56
57 grs_bitmap *gr_create_bitmap(int w, int h )
58 {
59         return gr_create_bitmap_raw (w, h, d_malloc( MAX_BMP_SIZE(w, h) ));
60 }
61
62 grs_bitmap *gr_create_bitmap_raw(int w, int h, unsigned char * raw_data )
63 {
64     grs_bitmap *new;
65
66     new = (grs_bitmap *)d_malloc( sizeof(grs_bitmap) );
67         gr_init_bitmap (new, 0, 0, 0, w, h, w, raw_data);
68
69     return new;
70 }
71
72
73 #if defined(POLY_ACC)
74 //
75 //  Creates a bitmap of the requested size and type.
76 //    w, and h are in pixels.
77 //    type is a BM_... and is used to set the rowsize.
78 //    if data is NULL, memory is allocated, otherwise data is used for bm_data.
79 //
80 //  This function is used only by the polygon accelerator code to handle the mixture of 15bit and
81 //  8bit bitmaps.
82 //
83 grs_bitmap *gr_create_bitmap2(int w, int h, int type, void *data )
84 {
85         grs_bitmap *new;
86
87         new = (grs_bitmap *)malloc( sizeof(grs_bitmap) );
88         new->bm_x = 0;
89         new->bm_y = 0;
90         new->bm_w = w;
91         new->bm_h = h;
92         new->bm_flags = 0;
93     new->bm_type = type;
94     switch(type)
95     {
96         case BM_LINEAR:     new->bm_rowsize = w;            break;
97         case BM_LINEAR15:   new->bm_rowsize = w*PA_BPP;     break;
98         default: Int3();    // unsupported type.
99     }
100     if(data)
101         new->bm_data = data;
102     else
103         new->bm_data = malloc(new->bm_rowsize * new->bm_h);
104         new->bm_handle = 0;
105
106         return new;
107 }
108 #endif
109
110 void gr_init_bitmap( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline, unsigned char * data ) // TODO: virtualize
111 {
112 #ifdef D1XD3D
113         Assert (bm->iMagic != BM_MAGIC_NUMBER || bm->pvSurface == NULL);
114 #endif
115
116         bm->bm_x = x;
117         bm->bm_y = y;
118         bm->bm_w = w;
119         bm->bm_h = h;
120         bm->bm_flags = 0;
121         bm->bm_type = mode;
122         bm->bm_rowsize = bytesperline;
123
124         bm->bm_data = NULL;
125 #ifdef D1XD3D
126         bm->iMagic = BM_MAGIC_NUMBER;
127         bm->pvSurface = NULL;
128 #endif
129
130 #ifdef D1XD3D
131         Win32_CreateTexture (bm);
132 #endif
133 #ifdef OGL
134         bm->bm_parent=NULL;bm->gltexture=NULL;
135 #endif
136
137 //      if (data != 0)
138                 gr_set_bitmap_data (bm, data);
139 /*
140         else
141                 gr_set_bitmap_data (bm, d_malloc( MAX_BMP_SIZE(w, h) ));
142 */
143
144 #ifdef BITMAP_SELECTOR
145         bm->bm_selector = 0;
146 #endif
147 }
148
149 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline)
150 {
151         gr_init_bitmap(bm, mode, x, y, w, h, bytesperline, 0);
152         gr_set_bitmap_data(bm, d_malloc( MAX_BMP_SIZE(w, h) ));
153 }
154
155 void gr_init_bitmap_data (grs_bitmap *bm) // TODO: virtulize
156 {
157         bm->bm_data = NULL;
158 #ifdef D1XD3D
159         Assert (bm->iMagic != BM_MAGIC_NUMBER);
160         bm->iMagic = BM_MAGIC_NUMBER;
161         bm->pvSurface = NULL;
162 #endif
163 #ifdef OGL
164 //      ogl_freebmtexture(bm);//not what we want here.
165         bm->bm_parent=NULL;bm->gltexture=NULL;
166 #endif
167 }
168
169 grs_bitmap *gr_create_sub_bitmap(grs_bitmap *bm, int x, int y, int w, int h )
170 {
171     grs_bitmap *new;
172
173     new = (grs_bitmap *)d_malloc( sizeof(grs_bitmap) );
174         gr_init_sub_bitmap (new, bm, x, y, w, h);
175
176         return new;
177 }
178
179 void gr_free_bitmap(grs_bitmap *bm )
180 {
181         gr_free_bitmap_data (bm);
182         if (bm!=NULL)
183                 d_free(bm);
184 }
185
186 void gr_free_sub_bitmap(grs_bitmap *bm )
187 {
188         if (bm!=NULL)
189         {
190 #ifdef D1XD3D
191                 bm->iMagic = 0;
192 #endif
193                 d_free(bm);
194         }
195 }
196
197
198 void gr_free_bitmap_data (grs_bitmap *bm) // TODO: virtulize
199 {
200 #ifdef D1XD3D
201         Assert (bm->iMagic == BM_MAGIC_NUMBER);
202
203         Win32_FreeTexture (bm);
204         bm->iMagic = 0;
205         if (bm->bm_data == BM_D3D_RENDER)
206                 bm->bm_data = NULL;
207 #endif
208 #ifdef OGL
209         ogl_freebmtexture(bm);
210 #endif
211         if (bm->bm_data != NULL)
212                 d_free (bm->bm_data);
213         bm->bm_data = NULL;
214 }
215
216 void gr_init_sub_bitmap (grs_bitmap *bm, grs_bitmap *bmParent, int x, int y, int w, int h )     // TODO: virtualize
217 {
218         bm->bm_x = x + bmParent->bm_x;
219         bm->bm_y = y + bmParent->bm_y;
220         bm->bm_w = w;
221         bm->bm_h = h;
222         bm->bm_flags = bmParent->bm_flags;
223         bm->bm_type = bmParent->bm_type;
224         bm->bm_rowsize = bmParent->bm_rowsize;
225
226 #ifdef OGL
227         bm->gltexture=bmParent->gltexture;
228         bm->bm_parent=bmParent;
229 #endif
230 #ifdef D1XD3D
231         Assert (bmParent->iMagic == BM_MAGIC_NUMBER);
232         bm->iMagic = BM_MAGIC_NUMBER;
233         bm->pvSurface = bmParent->pvSurface;
234         if (bm->bm_type == BM_DIRECTX)
235         {
236                 bm->bm_data = bmParent->bm_data;
237         }
238         else
239 #endif
240         {
241                 bm->bm_data = bmParent->bm_data+(unsigned int)((y*bmParent->bm_rowsize)+x);
242         }
243
244 }
245
246 void decode_data_asm(ubyte *data, int num_pixels, ubyte * colormap, int * count );
247
248 #if !defined(NO_ASM) && defined(__WATCOMC__)
249
250 #pragma aux decode_data_asm parm [esi] [ecx] [edi] [ebx] modify exact [esi edi eax ebx ecx] = \
251 "again_ddn:"                                                    \
252         "xor    eax,eax"                                \
253         "mov    al,[esi]"                       \
254         "inc    dword ptr [ebx+eax*4]"          \
255         "mov    al,[edi+eax]"           \
256         "mov    [esi],al"                       \
257         "inc    esi"                                    \
258         "dec    ecx"                                    \
259         "jne    again_ddn"
260
261 #elif !defined(NO_ASM) && defined(__GNUC__)
262
263 inline void decode_data_asm(ubyte *data, int num_pixels, ubyte * colormap, int * count ) {
264         int dummy[4];
265    __asm__ __volatile__ (
266     "xorl   %%eax,%%eax;"
267 "0:;"
268     "movb   (%%esi), %%al;"
269     "incl   (%%ebx, %%eax, 4);"
270     "movb   (%%edi, %%eax), %%al;"
271     "movb   %%al, (%%esi);"
272     "incl   %%esi;"
273     "decl   %%ecx;"
274     "jne    0b"
275     : "=S" (dummy[0]), "=c" (dummy[1]), "=D" (dummy[2]), "=b" (dummy[3])
276         : "0" (data), "1" (num_pixels), "2" (colormap), "3" (count)
277         : "%eax");
278 }
279
280 #elif !defined(NO_ASM) && defined(_MSC_VER)
281
282 __inline void decode_data_asm(ubyte *data, int num_pixels, ubyte * colormap, int * count )
283 {
284   __asm {
285         mov esi,[data]
286         mov ecx,[num_pixels]
287         mov edi,[colormap]
288         mov ebx,[count]
289 again_ddn:
290         xor eax,eax
291         mov al,[esi]
292         inc dword ptr [ebx+eax*4]
293         mov al,[edi+eax]
294         mov [esi],al
295         inc esi
296         dec ecx
297         jne again_ddn
298   }
299 }
300
301 #else // NO_ASM or unknown compiler
302
303 void decode_data_asm(ubyte *data, int num_pixels, ubyte *colormap, int *count)
304 {
305         int i;
306         ubyte mapped;
307
308         for (i = 0; i < num_pixels; i++) {
309                 count[*data]++;
310                 mapped = *data;
311                 *data = colormap[mapped];
312                 data++;
313         }
314 }
315
316 #endif
317
318 void gr_set_bitmap_flags (grs_bitmap *pbm, int flags)
319 {
320 #ifdef D1XD3D
321         Assert (pbm->iMagic == BM_MAGIC_NUMBER);
322
323         if (pbm->pvSurface)
324         {
325                 if ((flags & BM_FLAG_TRANSPARENT) != (pbm->bm_flags & BM_FLAG_TRANSPARENT))
326                 {
327                         Win32_SetTransparent (pbm->pvSurface, flags & BM_FLAG_TRANSPARENT);
328                 }
329         }
330 #endif
331         pbm->bm_flags = flags;
332 }
333
334 void gr_set_transparent (grs_bitmap *pbm, int bTransparent)
335 {
336         if (bTransparent)
337         {
338                 gr_set_bitmap_flags (pbm, pbm->bm_flags | BM_FLAG_TRANSPARENT);
339         }
340         else
341         {
342                 gr_set_bitmap_flags (pbm, pbm->bm_flags & ~BM_FLAG_TRANSPARENT);
343         }
344 }
345
346 void gr_set_super_transparent (grs_bitmap *pbm, int bTransparent)
347 {
348         if (bTransparent)
349         {
350                 gr_set_bitmap_flags (pbm, pbm->bm_flags & ~BM_FLAG_SUPER_TRANSPARENT);
351         }
352         else
353         {
354                 gr_set_bitmap_flags (pbm, pbm->bm_flags | BM_FLAG_SUPER_TRANSPARENT);
355         }
356 }
357
358 void build_colormap_good( ubyte * palette, ubyte * colormap, int * freq )
359 {
360         int i, r, g, b;
361
362         for (i=0; i<256; i++ )  {
363                 r = *palette++;
364                 g = *palette++;
365                 b = *palette++;
366                 *colormap++ = gr_find_closest_color( r, g, b );
367                 *freq++ = 0;
368         }
369 }
370
371 void gr_remap_bitmap( grs_bitmap * bmp, ubyte * palette, int transparent_color, int super_transparent_color )
372 {
373         ubyte colormap[256];
374         int freq[256];
375
376         if (bmp->bm_type != BM_LINEAR)
377                 return;  //can't do it
378
379         // This should be build_colormap_asm, but we're not using invert table, so...
380         build_colormap_good( palette, colormap, freq );
381
382         if ( (super_transparent_color>=0) && (super_transparent_color<=255))
383                 colormap[super_transparent_color] = 254;
384
385         if ( (transparent_color>=0) && (transparent_color<=255))
386                 colormap[transparent_color] = TRANSPARENCY_COLOR;
387
388         decode_data_asm(bmp->bm_data, bmp->bm_w * bmp->bm_h, colormap, freq );
389
390         if ( (transparent_color>=0) && (transparent_color<=255) && (freq[transparent_color]>0) )
391                 gr_set_transparent (bmp, 1);
392
393         if ( (super_transparent_color>=0) && (super_transparent_color<=255) && (freq[super_transparent_color]>0) )
394                 gr_set_super_transparent (bmp, 0);
395 }
396
397 void gr_remap_bitmap_good( grs_bitmap * bmp, ubyte * palette, int transparent_color, int super_transparent_color )
398 {
399         ubyte colormap[256];
400         int freq[256];
401         build_colormap_good( palette, colormap, freq );
402
403         if ( (super_transparent_color>=0) && (super_transparent_color<=255))
404                 colormap[super_transparent_color] = 254;
405
406         if ( (transparent_color>=0) && (transparent_color<=255))
407                 colormap[transparent_color] = TRANSPARENCY_COLOR;
408
409         if (bmp->bm_w == bmp->bm_rowsize)
410                 decode_data_asm(bmp->bm_data, bmp->bm_w * bmp->bm_h, colormap, freq );
411         else {
412                 int y;
413                 ubyte *p = bmp->bm_data;
414                 for (y=0;y<bmp->bm_h;y++,p+=bmp->bm_rowsize)
415                         decode_data_asm(p, bmp->bm_w, colormap, freq );
416         }
417
418         if ( (transparent_color>=0) && (transparent_color<=255) && (freq[transparent_color]>0) )
419                 gr_set_transparent (bmp, 1);
420
421         if ( (super_transparent_color>=0) && (super_transparent_color<=255) && (freq[super_transparent_color]>0) )
422                 gr_set_super_transparent (bmp, 1);
423 }
424
425 #ifdef BITMAP_SELECTOR
426 int gr_bitmap_assign_selector( grs_bitmap * bmp )
427 {
428         if (!dpmi_allocate_selector( bmp->bm_data, bmp->bm_w*bmp->bm_h, &bmp->bm_selector )) {
429                 bmp->bm_selector = 0;
430                 return 1;
431         }
432         return 0;
433 }
434 #endif
435
436 void gr_bitmap_check_transparency( grs_bitmap * bmp )
437 {
438         int x, y;
439         ubyte * data;
440
441         data = bmp->bm_data;
442
443         for (y=0; y<bmp->bm_h; y++ )    {
444                 for (x=0; x<bmp->bm_w; x++ )    {
445                         if (*data++ == TRANSPARENCY_COLOR )     {
446                                 gr_set_transparent (bmp, 1);
447                                 return;
448                         }
449                 }
450                 data += bmp->bm_rowsize - bmp->bm_w;
451         }
452
453         bmp->bm_flags = 0;
454
455 }