]> icculus.org git repositories - taylor/freespace2.git/blob - src/bmpman/bmpman.cpp
Initial revision
[taylor/freespace2.git] / src / bmpman / bmpman.cpp
1 /*
2  * $Logfile: /Freespace2/code/Bmpman/BmpMan.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Code to load and manage all bitmaps for the game
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:08  root
11  * Initial revision
12  *
13  * 
14  * 37    9/13/99 11:26p Andsager
15  * Add debug code to check for poorly sized anis
16  * 
17  * 36    9/05/99 11:19p Dave
18  * Made d3d texture cache much more safe. Fixed training scoring bug where
19  * it would backout scores without ever having applied them in the first
20  * place.
21  * 
22  * 35    8/20/99 2:09p Dave
23  * PXO banner cycling.
24  * 
25  * 34    8/10/99 6:54p Dave
26  * Mad optimizations. Added paging to the nebula effect.
27  * 
28  * 33    8/06/99 1:52p Dave
29  * Bumped up MAX_BITMAPS for the demo.
30  * 
31  * 32    8/02/99 1:49p Dave
32  * Fixed low-mem animation problem. Whee!
33  * 
34  * 31    7/16/99 1:49p Dave
35  * 8 bit aabitmaps. yay.
36  * 
37  * 30    7/13/99 1:15p Dave
38  * 32 bit support. Whee!
39  * 
40  * 29    6/29/99 10:35a Dave
41  * Interface polygon bitmaps! Whee!
42  * 
43  * 28    6/16/99 4:06p Dave
44  * New pilot info popup. Added new draw-bitmap-as-poly function.
45  * 
46  * 27    5/05/99 9:02p Dave
47  * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
48  * rotations, tweaked values, made bitmap selection more random). Fixed
49  * D3D beam weapon clipping problem. Added D3d frame dumping.
50  * 
51  * 26    4/27/99 12:16a Dave
52  * Fixed beam weapon muzzle glow problem. Fixed premature timeout on the
53  * pxo server list screen. Fixed secondary firing for hosts on a
54  * standalone. Fixed wacky multiplayer weapon "shuddering" problem.
55  * 
56  * 25    4/09/99 2:21p Dave
57  * Multiplayer beta stuff. CD checking.
58  * 
59  * 24    4/08/99 10:42a Johnson
60  * Don't try to swizzle a texture to transparent in Fred.
61  * 
62  * 23    3/31/99 8:24p Dave
63  * Beefed up all kinds of stuff, incluging beam weapons, nebula effects
64  * and background nebulae. Added per-ship non-dimming pixel colors.
65  * 
66  * 22    3/20/99 3:46p Dave
67  * Added support for model-based background nebulae. Added 3 new
68  * sexpressions.
69  * 
70  * 21    2/11/99 3:08p Dave
71  * PXO refresh button. Very preliminary squad war support.
72  * 
73  * 20    2/08/99 5:07p Dave
74  * FS2 chat server support. FS2 specific validated missions.
75  * 
76  * 19    2/05/99 12:52p Dave
77  * Fixed Glide nondarkening textures.
78  * 
79  * 18    2/04/99 6:29p Dave
80  * First full working rev of FS2 PXO support.  Fixed Glide lighting
81  * problems.
82  * 
83  * 17    2/03/99 11:44a Dave
84  * Fixed d3d transparent textures.
85  * 
86  * 16    1/15/99 11:29a Neilk
87  * Fixed D3D screen/texture pixel formatting problem. 
88  * 
89  * 15    1/14/99 12:48a Dave
90  * Todo list bug fixes. Made a pass at putting briefing icons back into
91  * FRED. Sort of works :(
92  * 
93  * 14    1/12/99 12:53a Dave
94  * More work on beam weapons - made collision detection very efficient -
95  * collide against all object types properly - made 3 movement types
96  * smooth. Put in test code to check for possible non-darkening pixels on
97  * object textures.
98  * 
99  * 13    1/08/99 2:08p Dave
100  * Fixed software rendering for pofview. Super early support for AWACS and
101  * beam weapons.
102  * 
103  * 12    1/06/99 2:24p Dave
104  * Stubs and release build fixes.
105  * 
106  * 11    12/14/98 4:01p Dave
107  * Got multi_data stuff working well with new xfer stuff. 
108  * 
109  * 10    12/06/98 2:36p Dave
110  * Drastically improved nebula fogging.
111  * 
112  * 9     12/01/98 5:53p Dave
113  * Simplified the way pixel data is swizzled. Fixed tga bitmaps to work
114  * properly in D3D and Glide.
115  * 
116  * 8     12/01/98 4:46p Dave
117  * Put in targa bitmap support (16 bit).
118  * 
119  * 7     12/01/98 10:32a Johnson
120  * Fixed direct3d font problems. Fixed sun bitmap problem. Fixed direct3d
121  * starfield problem.
122  * 
123  * 6     12/01/98 8:06a Dave
124  * Temporary checkin to fix some texture transparency problems in d3d.
125  * 
126  * 5     11/30/98 5:31p Dave
127  * Fixed up Fred support for software mode.
128  * 
129  * 4     11/30/98 1:07p Dave
130  * 16 bit conversion, first run.
131  * 
132  * 3     10/22/98 6:14p Dave
133  * Optimized some #includes in Anim folder. Put in the beginnings of
134  * parse/localization support for externalized strings and tstrings.tbl
135  * 
136  * 2     10/07/98 10:52a Dave
137  * Initial checkin.
138  * 
139  * 1     10/07/98 10:48a Dave
140  * 
141  * 106   5/23/98 4:43p John
142  * Took out debugging sleep
143  * 
144  * 105   5/23/98 4:14p John
145  * Added code to preload textures to video card for AGP.   Added in code
146  * to page in some bitmaps that weren't getting paged in at level start.
147  * 
148  * 104   5/20/98 12:59p John
149  * Turned optimizations on for debug builds.   Also turning on automatic
150  * function inlining.  Turned off the unreachable code warning.
151  * 
152  * 103   5/20/98 10:20a Hoffoss
153  * Fixed warning in the code.
154  * 
155  * 102   5/19/98 3:45p John
156  * fixed bug causing lowmem to drop half of the frames. Also halved fps
157  * during lowmem.
158  * 
159  * 101   5/14/98 3:38p John
160  * Added in more non-darkening colors for Adam.  Had to fix some bugs in
161  * BmpMan and Ani stuff to get this to work.
162  * 
163  * 100   4/22/98 9:13p John
164  * Added code to replace frames of animations in vram if so desired.
165  * 
166  * 99    4/17/98 6:56a John
167  * Fixed bug where RLE'd user bitmaps caused data to not get freed.
168  * (Turned off RLE for use bitmaps).   Made lossy animations reduce
169  * resolution by a factor of 2 in low memory conditions.
170  * 
171  * 98    4/16/98 6:31p Hoffoss
172  * Added function to get filename of a bitmap handle, which we don't have
173  * yet and I need.
174  * 
175  * 97    4/01/98 9:27p John
176  * Fixed debug info in bmpman.
177  * 
178  * 96    4/01/98 5:34p John
179  * Made only the used POFs page in for a level.   Reduced some interp
180  * arrays.    Made custom detail level work differently.
181  * 
182  * 95    3/31/98 9:55a Lawrance
183  * JOHN: get xparency working for user bitmaps
184  * 
185  * 94    3/30/98 4:02p John
186  * Made machines with < 32 MB of RAM use every other frame of certain
187  * bitmaps.   Put in code to keep track of how much RAM we've malloc'd.
188  * 
189  * 93    3/29/98 4:05p John
190  * New paging code that loads everything necessary at level startup.
191  * 
192  * 92    3/27/98 11:20a John
193  * commented back in some debug code.
194  * 
195  * 91    3/26/98 5:21p John
196  * Added new code to preload all bitmaps at the start of a level.
197  * Commented it out, though.
198  * 
199  * 90    3/26/98 4:56p Jasen
200  * AL: Allow find_block_of() to allocate a series of bitmaps from index 0
201  * 
202  * 89    3/26/98 10:21a John
203  * Made no palette-mapped bitmaps use 0,255,0 as transparent.
204  * 
205  * 88    3/24/98 5:39p John
206  * Added debug code to show bitmap fragmentation.  Made user bitmaps
207  * allocate from top of array.
208  * 
209  * 87    3/22/98 3:28p John
210  * Added in stippled alpha for lower details.  Made medium detail use
211  * engine glow.
212  * 
213  * 86    3/11/98 1:55p John
214  * Fixed warnings
215  * 
216  * 85    3/06/98 4:09p John
217  * Changed the way we do bitmap RLE'ing... this speds up HUD bitmaps by
218  * about 2x
219  * 
220  * 84    3/02/98 6:00p John
221  * Moved MAX_BITMAPS into BmpMan.h so the stuff in the graphics code that
222  * is dependent on it won't break if it changes.   Made ModelCache slots
223  * be equal to MAX_OBJECTS which is what it is.
224  * 
225  * 83    3/02/98 9:51a John
226  * Added code to print the number of bitmap slots in use between levels.
227  * 
228  * 82    2/16/98 3:54p John
229  * Changed a bunch of mprintfs to catagorize to BmpInfo
230  * 
231  * 81    2/13/98 5:00p John
232  * Made user bitmaps not get wrote to level cache file.
233  * 
234  * 80    2/06/98 8:25p John
235  * Added code for new bitmaps since last frame
236  * 
237  * 79    2/06/98 8:10p John
238  * Added code to show amout of texture usage each frame.
239  * 
240  * 78    2/05/98 9:21p John
241  * Some new Direct3D code.   Added code to monitor a ton of stuff in the
242  * game.
243  * 
244  * 77    1/29/98 11:48a John
245  * Added new counter measure rendering as model code.   Made weapons be
246  * able to have impact explosion.
247  * 
248  * 76    1/28/98 6:19p Dave
249  * Reduced standalone memory usage ~8 megs. Put in support for handling
250  * multiplayer submenu handling for endgame, etc.
251  * 
252  * 75    1/17/98 12:55p John
253  * Fixed bug that I just created that loaded all ani frames.
254  * 
255  * 74    1/17/98 12:33p John
256  * Made the game_busy function be called a constant amount of times per
257  * level load, making the bar prediction easier.
258  * 
259  * 73    1/17/98 12:14p John
260  * Added loading... bar to freespace.
261  * 
262  * 72    1/11/98 3:20p John
263  * Made so that if no .clt exists, it will load all the bitmaps
264  * 
265  * 71    1/11/98 3:06p John
266  * Made bitmap loading stop when cache gets full.
267  * 
268  * 70    1/11/98 2:45p John
269  * Changed .lst to .clt
270  * 
271  * 69    1/11/98 2:14p John
272  * Changed a lot of stuff that had to do with bitmap loading.   Made cfile
273  * not do callbacks, I put that in global code.   Made only bitmaps that
274  * need to load for a level load.
275  * 
276  * 67    1/09/98 4:07p John
277  * Made all bitmap functions return a bitmap "Handle" not number.  This
278  * helps to find bm_release errors.
279  * 
280  * 66    1/09/98 1:38p John
281  * Fixed some bugs from previous comment
282  * 
283  * 65    1/09/98 1:32p John
284  * Added some debugging code to track down a weird error.  Namely I fill
285  * in the be structure with bogus values when someone frees it.
286  * 
287  * 64    12/28/97 2:00p John
288  * put in another assert checking for invalid lock/unlock sequencing
289  * 
290  * 63    12/24/97 2:02p John
291  * Changed palette translation to be a little faster for unoptimized
292  * builds
293  * 
294  * 62    12/18/97 8:59p Dave
295  * Finished putting in basic support for weapon select and ship select in
296  * multiplayer.
297  * 
298  * 61    12/15/97 10:27p John
299  * fixed bug where 2 bm_loads of same file both open the header.
300  * 
301  * 60    12/08/97 2:17p John
302  * fixed bug with bmpman and cf_callback.
303  * made cf_callback in Freespace set small font back when done.
304  * 
305  * 59    12/03/97 5:01p Lawrance
306  * bump up MAX_BITMAPS to 1500.  People have reached 1000 bitmaps while
307  * playing multiple missions.
308  * 
309  * 58    12/02/97 3:59p John
310  * Added first rev of thruster glow, along with variable levels of
311  * translucency, which retquired some restructing of palman.
312  * 
313  * 57    11/30/97 3:57p John
314  * Made fixed 32-bpp translucency.  Made BmpMan always map translucent
315  * color into 255 even if you aren't supposed to remap and make it's
316  * palette black.
317  * 
318  * 56    10/05/97 10:39a John
319  * fixed bug with palette on unmapped bitmaps.  Made unmapped bitmaps get
320  * marked with xparent.
321  * 
322  * 55    9/23/97 11:46a Lawrance
323  * fixed bug with rle'ing with spans get big
324  * 
325  * 54    9/23/97 10:45a John
326  * made so you can tell bitblt code to rle a bitmap by passing flag to
327  * gr_set_bitmap
328  * 
329  * 53    9/19/97 10:18a John
330  * fixed bug with aa animations being re-rle'd every 
331  * frame.
332  * 
333  * 
334  * 52    9/09/97 10:08a Sandeep
335  * Fixed Compiler Level 4 warnings
336  * 
337  * 51    9/08/97 2:02p John
338  * fixed typo in nprintf
339  * 
340  * 50    9/08/97 1:56p John
341  * fixed some memory housekeeping bugs 
342  * 
343  * 49    9/03/97 4:19p John
344  * changed bmpman to only accept ani and pcx's.  made passing .pcx or .ani
345  * to bm_load functions not needed.   Made bmpman keep track of palettes
346  * for bitmaps not mapped into game palettes.
347  * 
348  * 48    8/29/97 7:35p Lawrance
349  * check if .ani animation is already loaded in bm_load_animation()
350  * 
351  * 47    8/25/97 11:14p Lawrance
352  * added support for .ani files in bm_load_animation()
353  * 
354  * 46    8/17/97 2:42p Lawrance
355  * only flag PCX files as xparent if they have xparent pixels in them
356  * 
357  * 45    8/15/97 9:57a Lawrance
358  * support multiple xparent entries for PCX files
359  * 
360  * 44    8/05/97 10:18a Lawrance
361  * my_rand() being used temporarily instead of rand()
362  * 
363  * 43    8/01/97 4:30p John
364  * 
365  * 42    7/29/97 8:34a John
366  * took out png stuff
367  * 
368  * 41    7/18/97 3:27p Lawrance
369  * have pcx files use (0,255,0) for transparency
370  * 
371  * 40    7/16/97 3:07p John
372  * 
373  * 39    7/10/97 8:34a John
374  * Added code to read TGA files.
375  * 
376  * 38    6/20/97 1:50p John
377  * added rle code to bmpman.  made gr8_aabitmap use it.
378  * 
379  * 37    6/18/97 12:07p John
380  * fixed some color bugs
381  * 
382  * 36    6/17/97 8:58p Lawrance
383  * fixed bug with not nulling bm.data with USER bitmaps
384  * 
385  * 35    6/12/97 2:44a Lawrance
386  * changed bm_unlock() to take an index into bm_bitmaps().  Added
387  * ref_count to bitmap_entry struct
388  * 
389  * 34    5/20/97 10:36a John
390  * Fixed problem with user bitmaps and direct3d caching.
391  * 
392  * 33    5/14/97 1:59p John
393  * fixed a palette bug with vclips.
394  * 
395  * 32    3/24/97 4:43p John
396  * speed up chunked collision detection by only checking cubes the vector
397  * goes through.
398  * 
399  * 31    3/24/97 3:25p John
400  * Cleaned up and restructured model_collide code and fvi code.  In fvi
401  * made code that finds uvs work..  Added bm_get_pixel to BmpMan.
402  * 
403  * 30    3/11/97 2:49p Allender
404  * 
405  * 29    2/18/97 9:43a Lawrance
406  * added Assert() in bm_release
407  * 
408  * 28    1/22/97 4:29p John
409  * maybe fixed bug with code that counts total bytes of texture ram used.
410  * 
411  * 27    1/22/97 4:19p Lawrance
412  * added flags to bm_create to allow transparency
413  * 
414  * 26    1/21/97 5:24p John
415  * fixed another bug with bm_release.
416  * 
417  * 25    1/21/97 5:12p John
418  * fixed bug with case
419  * 
420  * 24    1/21/97 5:02p John
421  * Added code for 8bpp user bitmaps.
422  * 
423  * 23    1/09/97 11:35a John
424  * Added some 2d functions to get/put screen images.
425  * 
426  * 22    11/26/96 6:50p John
427  * Added some more hicolor primitives.  Made windowed mode run as current
428  * bpp, if bpp is 8,16,or 32.
429  * 
430  * 21    11/26/96 9:44a Allender
431  * Allow for use of different bitmap palettes
432  * 
433  * 20    11/25/96 10:36a Allender
434  * started working on 32 bpp support.  Added 15 bpp.
435  * 
436  * 19    11/18/96 1:51p Allender
437  * fix up manager code to reread bitmaps if needed in newer bit depth
438  * 
439  * 18    11/15/96 4:24p Allender
440  * more bmpman stuff -- only free bitmap slots when releasing copied
441  * texture -- otherwise, only release the data for the bitmap
442  * 
443  * 17    11/15/96 3:33p Allender
444  * added support for converting to 16 bit textures when requested with
445  * bm_load.  Added some other management functions
446  * 
447  * 16    11/13/96 4:51p Allender
448  * started overhaul of bitmap manager.  bm_load no longer actually load
449  * the data, only the info for the bitmap.  Locking the bitmap now forces
450  * load when no data present (or will if bpp changes)
451  *
452  * $NoKeywords: $
453  */
454
455 #include <ctype.h>
456 #include "pstypes.h"
457 #include "pcxutils.h"
458 #include "bmpman.h"
459 #include "palman.h"
460 #include "2d.h"
461 #include "animplay.h"
462 #include "timer.h"
463 #include "systemvars.h"
464 #include "key.h"
465 #include "packunpack.h"
466 #include "cfile.h"
467 #include "grinternal.h"
468 #include "tgautils.h"
469 #include "ship.h"
470
471 #ifndef NDEBUG
472 #define BMPMAN_NDEBUG
473 #endif
474
475 // keep this defined to use per-ship nondarkening pixels
476 #define BMPMAN_SPECIAL_NONDARK
477
478 int bm_inited = 0;
479
480 #define BM_TYPE_NONE            0
481 #define BM_TYPE_PCX                     1
482 #define BM_TYPE_USER            2
483 #define BM_TYPE_ANI                     3               // in-house ANI format
484 #define BM_TYPE_TGA                     4               // 16 bit targa
485
486 typedef union bm_extra_info     {
487         struct {
488                 // Stuff needed for animations
489                 int             first_frame;                                                            // used for animations -- points to index of first frame
490                 ubyte           num_frames;                                                                     // used for animation -- number of frames in the animation
491                 ubyte           fps;                                                                                    // used for animation -- frames per second
492         } ani;
493         struct {
494                 // Stuff needed for user bitmaps
495                 void            *data;                                                                  // For user bitmaps, this is where the data comes from
496                 ubyte           bpp;                                                                    // For user bitmaps, this is what format the data is
497                 ubyte           flags;                                                                  // Flags passed to bm_create
498         } user;
499 } bm_extra_info;
500
501 typedef struct bitmap_entry     {
502         // identification
503         char            filename[MAX_FILENAME_LEN];                     // filename for this bitmap
504
505         uint            signature;                                                                      // a unique signature identifying the data
506         uint            palette_checksum;                                                       // checksum used to be sure bitmap is in current palette
507         int             handle;                                                                         // Handle = id*MAX_BITMAPS + bitmapnum
508         int             last_used;                                                                      // When this bitmap was last used
509
510         ubyte           type;                                                                                   // PCX, USER, ANI, etc
511         signed char     ref_count;                                                              // Number of locks on bitmap.  Can't unload unless ref_count is 0.
512
513         // Stuff to keep track of usage
514         ubyte           preloaded;                                                                      // If set, then this was loaded from the lst file
515         ubyte           used_flags;                                                                     // What flags it was accessed thru
516
517         // Bitmap info
518         bitmap  bm;
519
520         // Data for animations and user bitmaps
521         bm_extra_info   info;           
522
523 #ifdef BMPMAN_NDEBUG
524         // bookeeping
525         ubyte           used_last_frame;                                                        // If set, then it was used last frame
526         ubyte           used_this_frame;                                                        // If set, then it was used this frame
527         int             data_size;                                                                      // How much data this bitmap uses
528         int             used_count;                                                                     // How many times it was accessed
529 #endif
530 } bitmap_entry;
531
532 uint Bm_next_signature = 0x1234;
533
534 bitmap_entry bm_bitmaps[MAX_BITMAPS];
535
536 int bm_texture_ram = 0;
537
538 // Bm_max_ram - How much RAM bmpman can use for textures.
539 // Set to <1 to make it use all it wants.
540 int Bm_max_ram = 0;             //16*1024*1024;                 // Only use 16 MB for textures
541
542 int bm_next_handle = 1;
543
544 int Bm_paging = 0;
545
546 static int Bm_low_mem = 0;                      
547
548 // 16 bit pixel formats
549 int Bm_pixel_format = BM_PIXEL_FORMAT_ARGB;
550
551 // get and put functions for 16 bit pixels - neat bit slinging, huh?
552 #define BM_SET_R_ARGB(p, r)     { p[1] &= ~(0x7c); p[1] |= ((r & 0x1f) << 2); }
553 #define BM_SET_G_ARGB(p, g)     { p[0] &= ~(0xe0); p[1] &= ~(0x03); p[0] |= ((g & 0x07) << 5); p[1] |= ((g & 0x18) >> 3); }
554 #define BM_SET_B_ARGB(p, b)     { p[0] &= ~(0x1f); p[0] |= b & 0x1f; }
555 #define BM_SET_A_ARGB(p, a)     { p[1] &= ~(0x80); p[1] |= ((a & 0x01) << 7); }
556
557 #define BM_SET_R_D3D(p, r)              { *p |= (ushort)(( (int)r / Gr_current_red->scale ) << Gr_current_red->shift); }
558 #define BM_SET_G_D3D(p, g)              { *p |= (ushort)(( (int)g / Gr_current_green->scale ) << Gr_current_green->shift); }
559 #define BM_SET_B_D3D(p, b)              { *p |= (ushort)(( (int)b / Gr_current_blue->scale ) << Gr_current_blue->shift); }
560 #define BM_SET_A_D3D(p, a)              { if(a == 0){ *p = (ushort)Gr_current_green->mask; } }
561
562 #define BM_SET_R(p, r)  { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_R_ARGB(((char*)p), r); break; case BM_PIXEL_FORMAT_D3D: BM_SET_R_D3D(p, r); break; default: Int3(); } }
563 #define BM_SET_G(p, g)  { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_G_ARGB(((char*)p), g); break; case BM_PIXEL_FORMAT_D3D: BM_SET_G_D3D(p, g); break; default: Int3(); } }
564 #define BM_SET_B(p, b)  { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_B_ARGB(((char*)p), b); break; case BM_PIXEL_FORMAT_D3D: BM_SET_B_D3D(p, b); break;  default: Int3(); } }
565 #define BM_SET_A(p, a)  { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_A_ARGB(((char*)p), a); break; case BM_PIXEL_FORMAT_D3D: BM_SET_A_D3D(p, a); break;  default: Int3(); } }
566
567 // ===========================================
568 // Mode: 0 = High memory
569 //       1 = Low memory ( every other frame of ani's)
570 //       2 = Debug low memory ( only use first frame of each ani )
571 void bm_set_low_mem( int mode )
572 {
573         Assert( (mode >= 0)  && (mode<=2 ));
574         Bm_low_mem = mode;
575 }
576
577
578 static int bm_get_next_handle()
579 {
580         int n = bm_next_handle;
581         bm_next_handle++;
582         if ( bm_next_handle > 30000 )   {
583                 bm_next_handle = 1;
584         }
585         return n;
586 }
587
588 // Frees a bitmaps data if it should, and
589 // Returns true if bitmap n can free it's data.
590 static void bm_free_data(int n)
591 {
592         bitmap_entry    *be;
593         bitmap                  *bmp;
594
595         Assert( n >= 0 && n < MAX_BITMAPS );
596
597         be = &bm_bitmaps[n];
598         bmp = &be->bm;
599
600         // If there isn't a bitmap in this structure, don't
601         // do anything but clear out the bitmap info
602         if ( be->type==BM_TYPE_NONE) 
603                 goto SkipFree;
604
605         // If this bitmap doesn't have any data to free, skip
606         // the freeing it part of this.
607         if ( bmp->data == 0 ) 
608                 goto SkipFree;
609
610         // Don't free up memory for user defined bitmaps, since
611         // BmpMan isn't the one in charge of allocating/deallocing them.
612         if ( ( be->type==BM_TYPE_USER ) )       
613                 goto SkipFree;
614
615         // Free up the data now!
616
617         //      mprintf(( "Bitmap %d freed %d bytes\n", n, bm_bitmaps[n].data_size ));
618         #ifdef BMPMAN_NDEBUG
619                 bm_texture_ram -= be->data_size;
620         #endif
621         free((void *)bmp->data);
622
623 SkipFree:
624
625         // Clear out & reset the bitmap data structure
626         bmp->flags = 0;
627         bmp->bpp = 0;
628         bmp->data = 0;
629         bmp->palette = NULL;
630         #ifdef BMPMAN_NDEBUG
631                 be->data_size = 0;
632         #endif
633         be->signature = Bm_next_signature++; 
634 }
635
636
637 #ifdef BMPMAN_NDEBUG
638
639 int Bm_ram_freed = 0;
640
641 static void bm_free_some_ram( int n, int size )
642 {
643 /*
644         if ( Bm_max_ram < 1 ) return;
645         if ( bm_texture_ram + size < Bm_max_ram ) return;
646
647         int current_time = timer_get_milliseconds();
648
649         while( bm_texture_ram + size > Bm_max_ram )     {
650                 Bm_ram_freed++;
651
652                 // Need to free some RAM up!
653                 int i, oldest=-1, best_val=0;
654                 for (i = 0; i < MAX_BITMAPS; i++)       {
655                         if ( (bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].first_frame!=bm_bitmaps[n].first_frame) && (bm_bitmaps[i].ref_count==0) && (bm_bitmaps[i].data_size>0) )    {
656                                 int page_func = ( current_time-bm_bitmaps[i].last_used)*bm_bitmaps[i].data_size;
657                                 if ( (oldest==-1) || (page_func>best_val) )     {
658                                         oldest=i;
659                                         best_val = page_func;
660                                 }
661                         }
662                 }
663
664                 if ( oldest > -1 )      {
665                         //mprintf(( "Freeing bitmap '%s'\n", bm_bitmaps[oldest].filename ));
666                         for (i=0; i<bm_bitmaps[oldest].num_frames; i++ )        {
667                                 bm_free_data(bm_bitmaps[oldest].first_frame+i);
668                         }
669                 } else {
670                         //mprintf(( "Couldn't free enough! %d\n", bm_texture_ram ));
671                         break;
672                 }
673         }       
674 */
675 }
676
677 #endif
678
679 static void *bm_malloc( int n, int size )
680 {
681         Assert( n >= 0 && n < MAX_BITMAPS );
682 //      mprintf(( "Bitmap %d allocated %d bytes\n", n, size ));
683         #ifdef BMPMAN_NDEBUG
684         bm_free_some_ram( n, size );
685         Assert( bm_bitmaps[n].data_size == 0 );
686         bm_bitmaps[n].data_size += size;
687         bm_texture_ram += size;
688         #endif
689         return malloc(size);
690 }
691
692 void bm_close()
693 {
694         int i;
695         if ( bm_inited )        {
696                 for (i=0; i<MAX_BITMAPS; i++ )  {
697                         bm_free_data(i);                        // clears flags, bbp, data, etc
698                 }
699                 bm_inited = 0;
700         }
701 }
702
703
704 void bm_init()
705 {
706         int i;
707
708         mprintf(( "Size of bitmap info = %d KB\n", sizeof( bm_bitmaps )/1024 ));
709         mprintf(( "Size of bitmap extra info = %d bytes\n", sizeof( bm_extra_info ) ));
710         
711         if (!bm_inited) {
712                 bm_inited = 1;
713                 atexit(bm_close);
714         }
715         
716         for (i=0; i<MAX_BITMAPS; i++ ) {
717                 bm_bitmaps[i].filename[0] = '\0';
718                 bm_bitmaps[i].type = BM_TYPE_NONE;
719                 bm_bitmaps[i].info.user.data = NULL;
720                 bm_bitmaps[i].bm.data = 0;
721                 bm_bitmaps[i].bm.palette = NULL;
722                 #ifdef BMPMAN_NDEBUG
723                         bm_bitmaps[i].data_size = 0;
724                         bm_bitmaps[i].used_count = 0;
725                         bm_bitmaps[i].used_last_frame = 0;
726                         bm_bitmaps[i].used_this_frame = 0;
727                 #endif
728                 bm_free_data(i);        // clears flags, bbp, data, etc
729         }
730
731
732 }
733
734 #ifdef BMPMAN_NDEBUG
735
736 // Returns number of bytes of bitmaps locked this frame
737 // ntotal = number of bytes of bitmaps locked this frame
738 // nnew = number of bytes of bitmaps locked this frame that weren't locked last frame
739 void bm_get_frame_usage(int *ntotal, int *nnew)
740 {
741         int i;
742         
743         *ntotal = 0;
744         *nnew = 0;
745
746         for (i=0; i<MAX_BITMAPS; i++ ) {
747                 if ( (bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].used_this_frame))   {
748                         if ( !bm_bitmaps[i].used_last_frame )   {
749                                 *nnew += bm_bitmaps[i].bm.w*bm_bitmaps[i].bm.h; 
750                         }
751                         *ntotal += bm_bitmaps[i].bm.w*bm_bitmaps[i].bm.h;
752                 }
753                 bm_bitmaps[i].used_last_frame = bm_bitmaps[i].used_this_frame;
754                 bm_bitmaps[i].used_this_frame = 0;
755         }
756
757 }
758 #else
759 void bm_get_frame_usage(int *ntotal, int *nnew)
760 {
761 }
762 #endif
763
764 // given a loaded bitmap with valid info, calculate sections
765 void bm_calc_sections(bitmap *be)
766 {
767         int idx;
768
769         // number of x and y sections
770         be->sections.num_x = (ubyte)(be->w / MAX_BMAP_SECTION_SIZE);
771         if((be->sections.num_x * MAX_BMAP_SECTION_SIZE) < be->w){
772                 be->sections.num_x++;
773         }
774         be->sections.num_y = (ubyte)(be->h / MAX_BMAP_SECTION_SIZE);
775         if((be->sections.num_y * MAX_BMAP_SECTION_SIZE) < be->h){
776                 be->sections.num_y++;
777         }
778
779         // calculate the offsets for each section
780         for(idx=0; idx<be->sections.num_x; idx++){
781                 be->sections.sx[idx] = (ushort)(MAX_BMAP_SECTION_SIZE * idx);
782         }
783         for(idx=0; idx<be->sections.num_y; idx++){
784                 be->sections.sy[idx] = (ushort)(MAX_BMAP_SECTION_SIZE * idx);
785         }
786 }
787
788 // Creates a bitmap that exists in RAM somewhere, instead
789 // of coming from a disk file.  You pass in a pointer to a
790 // block of 32 (or 8)-bit-per-pixel data.  Right now, the only
791 // bpp you can pass in is 32 or 8.  On success, it returns the
792 // bitmap number.  You cannot free that RAM until bm_release
793 // is called on that bitmap.
794 int bm_create( int bpp, int w, int h, void * data, int flags )
795 {
796         int i, n, first_slot = MAX_BITMAPS;
797
798         // Assert((bpp==32)||(bpp==8));
799         if(bpp != 16){
800                 Assert(flags & BMP_AABITMAP);
801         } else {
802                 Assert(bpp == 16);
803         }
804
805         if ( !bm_inited ) bm_init();
806
807         for (i = MAX_BITMAPS-1; i >= 0; i-- ) {
808                 if ( bm_bitmaps[i].type == BM_TYPE_NONE )       {
809                         first_slot = i;
810                         break;
811                 }
812         }
813
814         n = first_slot;
815         Assert( n > -1 );
816
817         // Out of bitmap slots
818         if ( n == -1 ) return -1;
819
820         memset( &bm_bitmaps[n], 0, sizeof(bitmap_entry) );
821
822         sprintf( bm_bitmaps[n].filename, "TMP%dx%d", w, h );
823         bm_bitmaps[n].type = BM_TYPE_USER;
824         bm_bitmaps[n].palette_checksum = 0;
825
826         bm_bitmaps[n].bm.w = short(w);
827         bm_bitmaps[n].bm.h = short(h);
828         bm_bitmaps[n].bm.rowsize = short(w);
829         bm_bitmaps[n].bm.bpp = (unsigned char)(bpp);
830         bm_bitmaps[n].bm.flags = 0;
831         bm_bitmaps[n].bm.flags |= flags;
832         bm_bitmaps[n].bm.data = 0;
833         bm_bitmaps[n].bm.palette = NULL;
834
835         bm_bitmaps[n].info.user.bpp = ubyte(bpp);
836         bm_bitmaps[n].info.user.data = data;
837         bm_bitmaps[n].info.user.flags = ubyte(flags);
838
839         bm_bitmaps[n].signature = Bm_next_signature++;
840
841         bm_bitmaps[n].handle = bm_get_next_handle()*MAX_BITMAPS + n;
842         bm_bitmaps[n].last_used = -1;
843
844         // fill in section info
845         bm_calc_sections(&bm_bitmaps[n].bm);
846         
847         return bm_bitmaps[n].handle;
848 }
849
850 // sub helper function. Given a raw filename and an extension, try and find the bitmap
851 // returns -1 if it could not be found
852 //          0 if it was found as a file
853 //          1 if it already exists, fills in handle
854 int Bm_ignore_duplicates = 0;
855 int bm_load_sub(char *real_filename, char *ext, int *handle)
856 {       
857         int i;
858         char filename[MAX_FILENAME_LEN] = "";
859         
860         strcpy( filename, real_filename );
861         strcat( filename, ext );        
862         for (i=0; i<(int)strlen(filename); i++ ){
863                 filename[i] = char(tolower(filename[i]));
864         }               
865
866         // try to find given filename to see if it has been loaded before
867         if(!Bm_ignore_duplicates){
868                 for (i = 0; i < MAX_BITMAPS; i++) {
869                         if ( (bm_bitmaps[i].type != BM_TYPE_NONE) && !stricmp(filename, bm_bitmaps[i].filename) ) {
870                                 nprintf (("BmpMan", "Found bitmap %s -- number %d\n", filename, i));
871                                 *handle = bm_bitmaps[i].handle;
872                                 return 1;
873                         }
874                 }       
875         }
876
877         // try and find the file
878         /*
879         CFILE *test = cfopen(filename, "rb");
880         if(test != NULL){
881                 cfclose(test);
882                 return 0;
883         }
884         */
885
886         // could not be found
887         return 0;
888 }
889
890 // This loads a bitmap so we can draw with it later.
891 // It returns a negative number if it couldn't load
892 // the bitmap.   On success, it returns the bitmap
893 // number.  Function doesn't acutally load the data, only
894 // width, height, and possibly flags.
895 int bm_load( char * real_filename )
896 {
897         int i, n, first_slot = MAX_BITMAPS;
898         int w, h, bpp;
899         char filename[MAX_FILENAME_LEN];
900         int tga = 0;
901         int handle;
902         int found = 0;
903
904         if ( !bm_inited ) bm_init();
905
906         // nice little trick for keeping standalone memory usage way low - always return a bogus bitmap 
907         if(Game_mode & GM_STANDALONE_SERVER){
908                 strcpy(filename,"test128");
909         }
910
911         // make sure no one passed an extension
912         strcpy( filename, real_filename );
913         char *p = strchr( filename, '.' );
914         if ( p ) {
915                 mprintf(( "Someone passed an extension to bm_load for file '%s'\n", real_filename ));
916                 //Int3();
917                 *p = 0;
918         }
919          
920         // try and find the pcx file            
921         switch(bm_load_sub(filename, ".pcx", &handle)){
922         // error
923         case -1:
924                 break;
925
926         // found as a file
927         case 0:
928                 found = 1;
929                 strcat(filename, ".pcx");
930                 break;
931
932         // found as pre-existing
933         case 1:
934                 found = 1;
935                 return handle;          
936         }
937
938         if(!found){
939                 // try and find the tga file
940                 switch(bm_load_sub(filename, ".tga", &handle)){
941                 // error
942                 case -1:                        
943                         return -1;
944                         break;
945
946                 // found as a file
947                 case 0:                 
948                         strcat(filename, ".tga");
949                         tga = 1;
950                         break;
951
952                 // found as pre-existing
953                 case 1:                                         
954                         return handle;                                  
955                 }
956         }
957
958         // if its a tga file
959         if(tga){
960                 int tga_error=targa_read_header( filename, &w, &h, &bpp, NULL );
961                 if ( tga_error != TARGA_ERROR_NONE )    {
962                         mprintf(( "Couldn't open '%s'\n", filename ));
963                         return -1;
964                 }
965         }
966         // if its a pcx file
967         else {
968                 int pcx_error=pcx_read_header( filename, &w, &h, NULL );                
969                 if ( pcx_error != PCX_ERROR_NONE )      {
970                         mprintf(( "Couldn't open '%s'\n", filename ));
971                         return -1;
972                 }
973         }
974
975         // Error( LOCATION, "Unknown bitmap type %s\n", filename );
976                 
977         // Find an open slot
978         for (i = 0; i < MAX_BITMAPS; i++) {
979                 if ( (bm_bitmaps[i].type == BM_TYPE_NONE) && (first_slot == MAX_BITMAPS) ){
980                         first_slot = i;
981                 }
982         }
983
984         n = first_slot;
985         Assert( n < MAX_BITMAPS );      
986
987         if ( n == MAX_BITMAPS ) return -1;      
988
989         // ensure fields are cleared out from previous bitmap
990 //      Assert(bm_bitmaps[n].bm.data == 0);
991 //      Assert(bm_bitmaps[n].bm.palette == NULL);
992 //      Assert(bm_bitmaps[n].ref_count == 0 );
993 //      Assert(bm_bitmaps[n].user_data == NULL);
994         memset( &bm_bitmaps[n], 0, sizeof(bitmap_entry) );
995         
996         // Mark the slot as filled, because cf_read might load a new bitmap
997         // into this slot.
998         bm_bitmaps[n].type = tga ? (ubyte)BM_TYPE_TGA : (ubyte)BM_TYPE_PCX;
999         bm_bitmaps[n].signature = Bm_next_signature++;
1000         Assert ( strlen(filename) < MAX_FILENAME_LEN );
1001         strncpy(bm_bitmaps[n].filename, filename, MAX_FILENAME_LEN-1 );
1002         bm_bitmaps[n].bm.w = short(w);
1003         bm_bitmaps[n].bm.rowsize = short(w);
1004         bm_bitmaps[n].bm.h = short(h);
1005         bm_bitmaps[n].bm.bpp = 0;
1006         bm_bitmaps[n].bm.flags = 0;
1007         bm_bitmaps[n].bm.data = 0;
1008         bm_bitmaps[n].bm.palette = NULL;
1009
1010         bm_bitmaps[n].palette_checksum = 0;
1011         bm_bitmaps[n].handle = bm_get_next_handle()*MAX_BITMAPS + n;
1012         bm_bitmaps[n].last_used = -1;
1013
1014         // fill in section info
1015         bm_calc_sections(&bm_bitmaps[n].bm);
1016
1017         return bm_bitmaps[n].handle;
1018 }
1019
1020 // special load function. basically allows you to load a bitmap which already exists (by filename). 
1021 // this is useful because in some cases we need to have a bitmap which is locked in screen format
1022 // _and_ texture format, such as pilot pics and squad logos
1023 int bm_load_duplicate(char *filename)
1024 {
1025         int ret;
1026
1027         // ignore duplicates
1028         Bm_ignore_duplicates = 1;
1029         
1030         // load
1031         ret = bm_load(filename);
1032
1033         // back to normal
1034         Bm_ignore_duplicates = 0;
1035
1036         return ret;
1037 }
1038
1039 DCF(bm_frag,"Shows BmpMan fragmentation")
1040 {
1041         if ( Dc_command )       {
1042
1043                 gr_clear();
1044
1045                 int x=0, y=0;
1046                 int xs=2, ys=2;
1047                 int w=4, h=4;
1048
1049                 for (int i=0; i<MAX_BITMAPS; i++ )      {
1050                         switch( bm_bitmaps[i].type )    {
1051                         case BM_TYPE_NONE:
1052                                 gr_set_color(128,128,128);
1053                                 break;
1054                         case BM_TYPE_PCX:
1055                                 gr_set_color(255,0,0);
1056                                 break;
1057                         case BM_TYPE_USER:
1058                                 gr_set_color(0,255,0);
1059                                 break;
1060                         case BM_TYPE_ANI:
1061                                 gr_set_color(0,0,255);
1062                                 break;
1063                         }
1064
1065                         gr_rect( x+xs, y+ys, w, h );
1066                         x += w+xs+xs;
1067                         if ( x > 639 )  {
1068                                 x = 0;
1069                                 y += h + ys + ys;
1070                         }
1071
1072                 }
1073
1074                 gr_flip();
1075                 key_getch();
1076         }
1077 }
1078
1079 static int find_block_of(int n)
1080 {
1081         int i, cnt, nstart;
1082
1083         cnt=0;
1084         nstart = 0;
1085         for (i=0; i<MAX_BITMAPS; i++ )  {
1086                 if ( bm_bitmaps[i].type == BM_TYPE_NONE )       {
1087                         if (cnt==0) nstart = i;
1088                         cnt++;
1089                 } else
1090                         cnt=0;
1091                 if ( cnt == n ) return nstart;
1092         }
1093
1094         // Error( LOCATION, "Couldn't find block of %d frames\n", n );
1095         return -1;
1096 }
1097
1098 // ------------------------------------------------------------------
1099 // bm_load_animation()
1100 //
1101 //      input:          filename                =>              filename of animation
1102 //                                      nframes         =>              OUTPUT parameter:       number of frames in the animation
1103 //                                      fps                     =>              OUTPUT/OPTIONAL parameter: intended fps for the animation
1104 //
1105 // returns:             bitmap number of first frame in the animation
1106 //
1107 int bm_load_animation( char *real_filename, int *nframes, int *fps, int can_drop_frames)
1108 {
1109         int     i, n;
1110         anim    the_anim;
1111         CFILE   *fp;
1112         char filename[MAX_FILENAME_LEN];
1113
1114         if ( !bm_inited ) bm_init();
1115
1116         strcpy( filename, real_filename );
1117         char *p = strchr( filename, '.' );
1118         if ( p ) {
1119                 mprintf(( "Someone passed an extension to bm_load_animation for file '%s'\n", real_filename ));
1120                 //Int3();
1121                 *p = 0;
1122         }
1123         strcat( filename, ".ani" );
1124
1125         if ( (fp = cfopen(filename, "rb")) == NULL ) {
1126 //              Error(LOCATION,"Could not open filename %s in bm_load_ani()\n", filename);
1127                 return -1;
1128         }
1129
1130         int reduced = 0;
1131 #ifndef NDEBUG
1132         // for debug of ANI sizes
1133         strcpy(the_anim.name, real_filename);
1134 #endif
1135         anim_read_header(&the_anim, fp);
1136         if ( can_drop_frames )  {
1137                 if ( Bm_low_mem == 1 )  {
1138                         reduced = 1;
1139                         the_anim.total_frames = ( the_anim.total_frames+1)/2;
1140                 } else if ( Bm_low_mem == 2 )   {
1141                         the_anim.total_frames = 1;      
1142                 }
1143         }
1144         cfclose(fp);
1145
1146         *nframes = the_anim.total_frames;
1147         if ( fps != NULL )      {
1148                 if ( reduced )  {
1149                         *fps = the_anim.fps / 2;
1150                 } else {
1151                         *fps = the_anim.fps;
1152                 }
1153         }
1154
1155         // first check to see if this ani already has it's frames loaded
1156         for (i = 0; i < MAX_BITMAPS; i++) {
1157                 if ( (bm_bitmaps[i].type == BM_TYPE_ANI) && !stricmp(filename, bm_bitmaps[i].filename) ) {
1158                         break;
1159                 }
1160         }
1161         
1162         if ( i < MAX_BITMAPS ) {
1163                 // in low memory modes this can happen
1164                 if(!Bm_low_mem){
1165                         Assert(bm_bitmaps[i].info.ani.num_frames == *nframes);
1166                 }
1167                 return bm_bitmaps[i].handle;
1168         }
1169
1170         n = find_block_of(*nframes);
1171         if(n < 0){
1172                 return -1;
1173         }
1174         // Assert( n >= 0 );
1175
1176         int first_handle = bm_get_next_handle();
1177
1178         Assert ( strlen(filename) < MAX_FILENAME_LEN );
1179         for ( i = 0; i < *nframes; i++ ) {
1180                 memset( &bm_bitmaps[n+i], 0, sizeof(bitmap_entry) );
1181                 bm_bitmaps[n+i].info.ani.first_frame = n;
1182                 bm_bitmaps[n+i].info.ani.num_frames = ubyte(the_anim.total_frames);
1183                 bm_bitmaps[n+i].info.ani.fps = ubyte(the_anim.fps);
1184                 bm_bitmaps[n+i].bm.w = short(the_anim.width);
1185                 bm_bitmaps[n+i].bm.rowsize = short(the_anim.width);
1186                 bm_bitmaps[n+i].bm.h = short(the_anim.height);
1187                 if ( reduced )  {
1188                         bm_bitmaps[n+i].bm.w /= 2;
1189                         bm_bitmaps[n+i].bm.rowsize /= 2;
1190                         bm_bitmaps[n+i].bm.h /= 2;
1191                 }
1192                 bm_bitmaps[n+i].bm.flags = 0;
1193                 bm_bitmaps[n+i].bm.bpp = 0;
1194                 bm_bitmaps[n+i].bm.data = 0;
1195                 bm_bitmaps[n+i].bm.palette = NULL;
1196                 bm_bitmaps[n+i].type = BM_TYPE_ANI;
1197                 bm_bitmaps[n+i].palette_checksum = 0;
1198                 bm_bitmaps[n+i].signature = Bm_next_signature++;
1199                 bm_bitmaps[n+i].handle = first_handle*MAX_BITMAPS + n+i;
1200                 bm_bitmaps[n+i].last_used = -1;
1201
1202                 // fill in section info
1203                 bm_calc_sections(&bm_bitmaps[n+i].bm);
1204
1205                 if ( i == 0 )   {
1206                         sprintf( bm_bitmaps[n+i].filename, "%s", filename );
1207                 } else {
1208                         sprintf( bm_bitmaps[n+i].filename, "%s[%d]", filename, i );
1209                 }
1210         }
1211
1212         return bm_bitmaps[n].handle;
1213 }
1214
1215 // Gets info.   w,h,or flags,nframes or fps can be NULL if you don't care.
1216 void bm_get_info( int handle, int *w, int * h, ubyte * flags, int *nframes, int *fps, bitmap_section_info **sections )
1217 {
1218         bitmap * bmp;
1219
1220         if ( !bm_inited ) return;
1221
1222         int bitmapnum = handle % MAX_BITMAPS;
1223         Assert( bm_bitmaps[bitmapnum].handle == handle );               // INVALID BITMAP HANDLE!       
1224         
1225         if ( (bm_bitmaps[bitmapnum].type == BM_TYPE_NONE) || (bm_bitmaps[bitmapnum].handle != handle) ) {
1226                 if (w) *w = 0;
1227                 if (h) *h = 0;
1228                 if (flags) *flags = 0;
1229                 if (nframes) *nframes=0;
1230                 if (fps) *fps=0;
1231                 if (sections != NULL) *sections = NULL;
1232                 return;
1233         }
1234
1235         bmp = &(bm_bitmaps[bitmapnum].bm);
1236
1237         if (w) *w = bmp->w;
1238         if (h) *h = bmp->h;
1239         if (flags) *flags = bmp->flags;
1240         if ( bm_bitmaps[bitmapnum].type == BM_TYPE_ANI )        {
1241                 if (nframes) {
1242                         *nframes = bm_bitmaps[bitmapnum].info.ani.num_frames;
1243                 } 
1244                 if (fps) {
1245                         *fps= bm_bitmaps[bitmapnum].info.ani.fps;
1246                 }
1247         } else {
1248                 if (nframes) {
1249                         *nframes = 1;
1250                 } 
1251                 if (fps) {
1252                         *fps= 0;
1253                 }
1254         }
1255         if(sections != NULL){
1256                 *sections = &bm_bitmaps[bitmapnum].bm.sections;
1257         }
1258 }
1259
1260 uint bm_get_signature( int handle )
1261 {
1262         if ( !bm_inited ) bm_init();
1263
1264         int bitmapnum = handle % MAX_BITMAPS;
1265         Assert( bm_bitmaps[bitmapnum].handle == handle );               // INVALID BITMAP HANDLE
1266
1267         return bm_bitmaps[bitmapnum].signature;
1268 }
1269
1270 extern int palman_is_nondarkening(int r,int g, int b);
1271 static void bm_convert_format( int bitmapnum, bitmap *bmp, ubyte bpp, ubyte flags )
1272 {       
1273         int idx;        
1274         int r, g, b, a;
1275
1276         if(Fred_running || Pofview_running || Is_standalone){
1277                 Assert(bmp->bpp == 8);
1278
1279                 return;
1280         } else {
1281                 if(flags & BMP_AABITMAP){
1282                         Assert(bmp->bpp == 8);
1283                 } else {
1284                         Assert(bmp->bpp == 16);
1285                 }
1286         }
1287
1288         // maybe swizzle to be an xparent texture
1289         if(!(bmp->flags & BMP_TEX_XPARENT) && (flags & BMP_TEX_XPARENT)){
1290                 for(idx=0; idx<bmp->w*bmp->h; idx++){                   
1291                         
1292                         // if the pixel is transparent
1293                         if ( ((ushort*)bmp->data)[idx] == Gr_t_green.mask)      {
1294                                 switch(Bm_pixel_format){
1295                                 // 1555, all we need to do is zero the whole thing
1296                                 case BM_PIXEL_FORMAT_ARGB:
1297                                 case BM_PIXEL_FORMAT_ARGB_D3D:
1298                                         ((ushort*)bmp->data)[idx] = 0;
1299                                         break;
1300                                 // d3d format
1301                                 case BM_PIXEL_FORMAT_D3D:                                                                       
1302                                         r = g = b = a = 0;
1303                                         r /= Gr_t_red.scale;
1304                                         g /= Gr_t_green.scale;
1305                                         b /= Gr_t_blue.scale;
1306                                         a /= Gr_t_alpha.scale;
1307                                         ((ushort*)bmp->data)[idx] = (unsigned short)((a<<Gr_t_alpha.shift) | (r << Gr_t_red.shift) | (g << Gr_t_green.shift) |  (b << Gr_t_blue.shift));
1308                                         break;
1309                                 default:
1310                                         Int3();
1311                                 }
1312                         }
1313                 }
1314
1315                 bmp->flags |= BMP_TEX_XPARENT;
1316         }       
1317 }
1318
1319 // basically, map the bitmap into the current palette. used to be done for all pcx's, now just for
1320 // Fred, since its the only thing that uses the software tmapper
1321 void bm_swizzle_8bit_for_fred(bitmap_entry *be, bitmap *bmp, ubyte *data, ubyte *palette)
1322 {               
1323         int pcx_xparent_index = -1;
1324         int i;
1325         int r, g, b;
1326         ubyte palxlat[256];
1327
1328         for (i=0; i<256; i++ ) {
1329                 r = palette[i*3];
1330                 g = palette[i*3+1];
1331                 b = palette[i*3+2];
1332                 if ( g == 255 && r == 0 && b == 0 ) {
1333                         palxlat[i] = 255;
1334                         pcx_xparent_index = i;
1335                 } else {                        
1336                         palxlat[i] = (ubyte)(palette_find( r, g, b ));                  
1337                 }
1338         }               
1339         for (i=0; i<bmp->w * bmp->h; i++ ) {            
1340                 ubyte c = palxlat[data[i]];                     
1341                 data[i] = c;            
1342         }                       
1343         be->palette_checksum = gr_palette_checksum;     
1344 }
1345
1346 void bm_lock_pcx( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1347 {       
1348         ubyte *data, *palette;
1349         ubyte pal[768];
1350         palette = NULL;
1351
1352         // Unload any existing data
1353         bm_free_data( bitmapnum );      
1354
1355         // allocate bitmap data
1356         if(bpp == 8){
1357                 // Assert(Fred_running || Pofview_running || Is_standalone);            
1358                         data = (ubyte *)bm_malloc(bitmapnum, bmp->w * bmp->h );
1359                 #ifdef BMPMAN_NDEBUG
1360                         Assert( be->data_size == bmp->w * bmp->h );
1361                 #endif
1362                 palette = pal;
1363                 bmp->data = (uint)data;
1364                 bmp->bpp = 8;
1365                 bmp->palette = gr_palette;
1366                 memset( data, 0, bmp->w * bmp->h);
1367         } else {
1368                 data = (ubyte*)bm_malloc(bitmapnum, bmp->w * bmp->h * 2);       
1369                 bmp->bpp = 16;
1370                 bmp->data = (uint)data;
1371                 bmp->palette = NULL;
1372                 memset( data, 0, bmp->w * bmp->h * 2);
1373         }       
1374
1375         Assert( &be->bm == bmp );
1376         #ifdef BMPMAN_NDEBUG
1377                 Assert( be->data_size > 0 );
1378         #endif
1379
1380         // some sanity checks on flags
1381         Assert(!((flags & BMP_AABITMAP) && (flags & BMP_TEX_ANY)));                                             // no aabitmap textures
1382         Assert(!((flags & BMP_TEX_XPARENT) && (flags & BMP_TEX_NONDARK)));                      // can't be a transparent texture and a nondarkening texture 
1383         Assert(!((flags & BMP_TEX_NONDARK) && (gr_screen.mode == GR_DIRECT3D)));        // D3D should never be trying to get nondarkening textures
1384
1385         if(bpp == 8){
1386                 int pcx_error=pcx_read_bitmap_8bpp( be->filename, data, palette );
1387                 if ( pcx_error != PCX_ERROR_NONE )      {
1388                         // Error( LOCATION, "Couldn't open '%s'\n", be->filename );
1389                         //Error( LOCATION, "Couldn't open '%s'\n", filename );
1390                         //return -1;
1391                 }
1392
1393                 // now swizzle the thing into the proper format
1394                 if(Fred_running || Pofview_running){
1395                         bm_swizzle_8bit_for_fred(be, bmp, data, palette);
1396                 }
1397         } else {        
1398                 int pcx_error;
1399
1400                 // load types
1401                 if(flags & BMP_AABITMAP){
1402                         pcx_error = pcx_read_bitmap_16bpp_aabitmap( be->filename, data );
1403                 } else if(flags & BMP_TEX_NONDARK){
1404                         pcx_error = pcx_read_bitmap_16bpp_nondark( be->filename, data );
1405                 } else {
1406                         pcx_error = pcx_read_bitmap_16bpp( be->filename, data );
1407                 }
1408                 if ( pcx_error != PCX_ERROR_NONE )      {
1409                         // Error( LOCATION, "Couldn't open '%s'\n", be->filename );
1410                         //Error( LOCATION, "Couldn't open '%s'\n", filename );
1411                         //return -1;
1412                 }
1413         }
1414
1415         #ifdef BMPMAN_NDEBUG
1416         Assert( be->data_size > 0 );
1417         #endif          
1418         
1419         bmp->flags = 0; 
1420         bm_convert_format( bitmapnum, bmp, bpp, flags );
1421 }
1422
1423 void bm_lock_ani( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1424 {       
1425         anim                            *the_anim;
1426         anim_instance   *the_anim_instance;
1427         bitmap                  *bm;
1428         ubyte                           *frame_data;
1429         int                             size, i;
1430         int                             first_frame, nframes;   
1431
1432         first_frame = be->info.ani.first_frame;
1433         nframes = bm_bitmaps[first_frame].info.ani.num_frames;
1434
1435         if ( (the_anim = anim_load(bm_bitmaps[first_frame].filename)) == NULL ) {
1436                 // Error(LOCATION, "Error opening %s in bm_lock\n", be->filename);
1437         }
1438
1439         if ( (the_anim_instance = init_anim_instance(the_anim, bpp)) == NULL ) {
1440                 // Error(LOCATION, "Error opening %s in bm_lock\n", be->filename);
1441                 anim_free(the_anim);
1442         }
1443
1444         int can_drop_frames = 0;
1445
1446         if ( the_anim->total_frames != bm_bitmaps[first_frame].info.ani.num_frames )    {
1447                 can_drop_frames = 1;
1448         }
1449         bm = &bm_bitmaps[first_frame].bm;
1450         if(bpp == 16){
1451                 size = bm->w * bm->h * 2;
1452         } else {
1453                 size = bm->w * bm->h;
1454         }
1455                 
1456         for ( i=0; i<nframes; i++ )     {
1457                 be = &bm_bitmaps[first_frame+i];
1458                 bm = &bm_bitmaps[first_frame+i].bm;
1459
1460                 // Unload any existing data
1461                 bm_free_data( first_frame+i );
1462
1463                 bm->flags = 0;
1464                 // briefing editor in Fred2 uses aabitmaps (ani's) - force to 8 bit
1465                 if(Fred_running || Is_standalone){
1466                         bm->bpp = 8;
1467                 } else {
1468                         bm->bpp = bpp;
1469                 }
1470                 bm->data = (uint)bm_malloc(first_frame + i, size);
1471
1472                 frame_data = anim_get_next_raw_buffer(the_anim_instance, 0 ,flags & BMP_AABITMAP ? 1 : 0, bm->bpp);
1473
1474                 if ( frame_data == NULL ) {
1475                         // Error(LOCATION,"Fatal error locking .ani file: %s\n", be->filename);
1476                 }               
1477                 
1478                 ubyte *dptr, *sptr;
1479
1480                 sptr = frame_data;
1481                 dptr = (ubyte *)bm->data;
1482
1483                 if ( (bm->w!=the_anim->width) || (bm->h!=the_anim->height) )    {
1484                         // Scale it down
1485                         // Int3();                      // not ready yet - should only be ingame
1486         
1487                         // 8 bit
1488                         if(bpp == 8){
1489                                 int w,h;
1490                                 fix u, utmp, v, du, dv;
1491
1492                                 u = v = 0;
1493
1494                                 du = ( the_anim->width*F1_0 ) / bm->w;
1495                                 dv = ( the_anim->height*F1_0 ) / bm->h;
1496                                                                                                 
1497                                 for (h = 0; h < bm->h; h++) {
1498                                         ubyte *drow = &dptr[bm->w * h];
1499                                         ubyte *srow = &sptr[f2i(v)*the_anim->width];
1500
1501                                         utmp = u;
1502
1503                                         for (w = 0; w < bm->w; w++) {
1504                                                 *drow++ = srow[f2i(utmp)];
1505                                                 utmp += du;
1506                                         }
1507                                         v += dv;
1508                                 }                       
1509                         }
1510                         // 16 bpp
1511                         else {
1512                                 int w,h;
1513                                 fix u, utmp, v, du, dv;
1514
1515                                 u = v = 0;
1516
1517                                 du = ( the_anim->width*F1_0 ) / bm->w;
1518                                 dv = ( the_anim->height*F1_0 ) / bm->h;
1519                                                                                                 
1520                                 for (h = 0; h < bm->h; h++) {
1521                                         ushort *drow = &((ushort*)dptr)[bm->w * h];
1522                                         ushort *srow = &((ushort*)sptr)[f2i(v)*the_anim->width];
1523
1524                                         utmp = u;
1525
1526                                         for (w = 0; w < bm->w; w++) {
1527                                                 *drow++ = srow[f2i(utmp)];
1528                                                 utmp += du;
1529                                         }
1530                                         v += dv;
1531                                 }                       
1532                         }                       
1533                 } else {
1534                         // 1-to-1 mapping
1535                         memcpy(dptr, sptr, size);
1536                 }               
1537
1538                 bm_convert_format( first_frame+i, bm, bpp, flags );
1539
1540                 // Skip a frame
1541                 if ( (i < nframes-1)  && can_drop_frames )      {
1542                         frame_data = anim_get_next_raw_buffer(the_anim_instance, 0, flags & BMP_AABITMAP ? 1 : 0, bm->bpp);
1543                 }
1544
1545                 //mprintf(( "Checksum = %d\n", be->palette_checksum ));
1546         }
1547
1548         free_anim_instance(the_anim_instance);
1549         anim_free(the_anim);
1550 }
1551
1552
1553 void bm_lock_user( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1554 {
1555         // int idx;     
1556         // ushort bit_16;
1557
1558         // Unload any existing data
1559         bm_free_data( bitmapnum );      
1560
1561         switch( be->info.user.bpp )     {
1562         case 16:                        // user 16 bit bitmap
1563                 bmp->bpp = bpp;
1564                 bmp->flags = be->info.user.flags;               
1565                 bmp->data = (uint)be->info.user.data;                                                           
1566                 break;  
1567         
1568         case 8:                 // Going from 8 bpp to something (probably only for aabitmaps)
1569                 /*
1570                 Assert(flags & BMP_AABITMAP);
1571                 bmp->bpp = 16;
1572                 bmp->data = (uint)malloc(bmp->w * bmp->h * 2);
1573                 bmp->flags = be->info.user.flags;
1574                 bmp->palette = NULL;
1575
1576                 // go through and map the pixels
1577                 for(idx=0; idx<bmp->w * bmp->h; idx++){                 
1578                         bit_16 = (ushort)((ubyte*)be->info.user.data)[idx];                     
1579                         Assert(bit_16 <= 255);
1580
1581                         // stuff the final result
1582                         memcpy((char*)bmp->data + (idx * 2), &bit_16, sizeof(ushort));
1583                 }
1584                 */              
1585                 Assert(flags & BMP_AABITMAP);
1586                 bmp->bpp = bpp;
1587                 bmp->flags = be->info.user.flags;               
1588                 bmp->data = (uint)be->info.user.data;                                                           
1589                 break;
1590                 
1591         // default:
1592                 // Error( LOCATION, "Unhandled user bitmap conversion from %d to %d bpp", be->info.user.bpp, bmp->bpp );
1593         }
1594
1595         bm_convert_format( bitmapnum, bmp, bpp, flags );
1596 }
1597
1598 void bm_lock_tga( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1599 {
1600         ubyte *data;    
1601
1602         // Unload any existing data
1603         bm_free_data( bitmapnum );      
1604
1605         if(Fred_running || Is_standalone){
1606                 Assert(bpp == 8);
1607         } else {
1608                 Assert(bpp == 16);
1609         }
1610
1611         // should never try to make an aabitmap out of a targa
1612         Assert(!(flags & BMP_AABITMAP));
1613
1614         // allocate bitmap data 
1615         if(bpp == 16){
1616                 data = (ubyte*)bm_malloc(bitmapnum, bmp->w * bmp->h * 2);       
1617         } else {
1618                 data = (ubyte*)bm_malloc(bitmapnum, bmp->w * bmp->h);   
1619         }
1620         bmp->bpp = bpp;
1621         bmp->data = (uint)data;
1622         bmp->palette = NULL;
1623         if(bpp == 16){
1624                 memset( data, 0, bmp->w * bmp->h * 2);  
1625         } else {
1626                 memset( data, 0, bmp->w * bmp->h );     
1627         }
1628
1629         Assert( &be->bm == bmp );
1630         #ifdef BMPMAN_NDEBUG
1631         Assert( be->data_size > 0 );
1632         #endif
1633         
1634         int tga_error=targa_read_bitmap( be->filename, data, NULL, (bpp == 16) ? 2 : 1);
1635         if ( tga_error != TARGA_ERROR_NONE )    {
1636                 // Error( LOCATION, "Couldn't open '%s'\n", be->filename );
1637                 //Error( LOCATION, "Couldn't open '%s'\n", filename );
1638                 //return -1;
1639         }
1640
1641         #ifdef BMPMAN_NDEBUG
1642         Assert( be->data_size > 0 );
1643         #endif          
1644         
1645         bmp->flags = 0; 
1646         bm_convert_format( bitmapnum, bmp, bpp, flags );
1647 }
1648
1649 MONITOR( NumBitmapPage );
1650 MONITOR( SizeBitmapPage );
1651
1652 // This locks down a bitmap and returns a pointer to a bitmap
1653 // that can be accessed until you call bm_unlock.   Only lock
1654 // a bitmap when you need it!  This will convert it into the 
1655 // appropriate format also.
1656 bitmap * bm_lock( int handle, ubyte bpp, ubyte flags )
1657 {
1658         bitmap                  *bmp;
1659         bitmap_entry    *be;
1660
1661
1662         if ( !bm_inited ) bm_init();
1663
1664         int bitmapnum = handle % MAX_BITMAPS;
1665         Assert( bm_bitmaps[bitmapnum].handle == handle );               // INVALID BITMAP HANDLE
1666
1667 //      flags &= (~BMP_RLE);
1668
1669         // if we're on a standalone server, aways for it to lock to 8 bits
1670         if(Is_standalone){
1671                 bpp = 8;
1672                 flags = 0;
1673         } 
1674         // otherwise do it as normal
1675         else {
1676                 if(Fred_running || Pofview_running){
1677                         Assert( bpp == 8 );
1678                         Assert( (bm_bitmaps[bitmapnum].type == BM_TYPE_PCX) || (bm_bitmaps[bitmapnum].type == BM_TYPE_ANI) || (bm_bitmaps[bitmapnum].type == BM_TYPE_TGA));
1679                 } else {
1680                         if(flags & BMP_AABITMAP){
1681                                 Assert( bpp == 8 );
1682                         } else {
1683                                 Assert( bpp == 16 );
1684                         }
1685                 }
1686         }
1687
1688         be = &bm_bitmaps[bitmapnum];
1689         bmp = &be->bm;
1690
1691         // If you hit this assert, chances are that someone freed the
1692         // wrong bitmap and now someone is trying to use that bitmap.
1693         // See John.
1694         Assert( be->type != BM_TYPE_NONE );             
1695
1696         // Increment ref count for bitmap since lock was made on it.
1697         Assert(be->ref_count >= 0);
1698         be->ref_count++;                                        // Lock it before we page in data; this prevents a callback from freeing this
1699                                                                                         // as it gets read in
1700
1701         // Mark this bitmap as used this frame
1702         #ifdef BMPMAN_NDEBUG
1703         if ( be->used_this_frame < 255 )        {
1704                 be->used_this_frame++;
1705         }
1706         #endif
1707
1708         // if bitmap hasn't been loaded yet, then load it from disk
1709         // reread the bitmap from disk under certain conditions
1710         int pal_changed = 0;
1711         int rle_changed = 0;
1712         int fake_xparent_changed = 0;   
1713         if ( (bmp->data == NULL) || (bpp != bmp->bpp) || pal_changed || rle_changed || fake_xparent_changed ) {
1714                 Assert(be->ref_count == 1);
1715
1716                 if ( be->type != BM_TYPE_USER ) {
1717                         if ( bmp->data == NULL ) {
1718                                 nprintf (("BmpMan","Loading %s for the first time.\n", be->filename));
1719                         } else if ( bpp != bmp->bpp ) {
1720                                 nprintf (("BmpMan","Reloading %s from bitdepth %d to bitdepth %d\n", be->filename, bmp->bpp, bpp));
1721                         } else if ( pal_changed ) {
1722                                 nprintf (("BmpMan","Reloading %s to remap palette\n", be->filename));
1723                         } else if ( rle_changed )       {
1724                                 nprintf (("BmpMan","Reloading %s to change RLE.\n", be->filename));
1725                         } else if ( fake_xparent_changed )      {
1726                                 nprintf (("BmpMan","Reloading %s to change fake xparency.\n", be->filename));
1727                         }
1728                 }
1729
1730                 MONITOR_INC( NumBitmapPage, 1 );
1731                 MONITOR_INC( SizeBitmapPage, bmp->w*bmp->h );
1732
1733                 if ( !Bm_paging )       {
1734                         if ( be->type != BM_TYPE_USER ) {
1735                                 char flag_text[64];
1736                                 strcpy( flag_text, "--" );                                                      
1737                                 nprintf(( "Paging", "Loading %s (%dx%dx%dx%s)\n", be->filename, bmp->w, bmp->h, bpp, flag_text ));
1738                         }
1739                 }
1740
1741                 // select proper format
1742                 if(flags & BMP_AABITMAP){
1743                         BM_SELECT_ALPHA_TEX_FORMAT();
1744                 } else if(flags & BMP_TEX_ANY){
1745                         BM_SELECT_TEX_FORMAT();                                 
1746                 } else {
1747                         BM_SELECT_SCREEN_FORMAT();
1748                 }
1749
1750                 switch ( be->type ) {
1751                 case BM_TYPE_PCX:
1752                         bm_lock_pcx( handle, bitmapnum, be, bmp, bpp, flags );
1753                         break;
1754
1755                 case BM_TYPE_ANI: 
1756                         bm_lock_ani( handle, bitmapnum, be, bmp, bpp, flags );
1757                         break;
1758
1759                 case BM_TYPE_USER:      
1760                         bm_lock_user( handle, bitmapnum, be, bmp, bpp, flags );
1761                         break;
1762
1763                 case BM_TYPE_TGA:
1764                         bm_lock_tga( handle, bitmapnum, be, bmp, bpp, flags );
1765                         break;
1766
1767                 default:
1768                         Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", be->type );
1769                         return NULL;
1770                 }               
1771
1772                 // always go back to screen format
1773                 BM_SELECT_SCREEN_FORMAT();
1774         }
1775
1776         if ( be->type == BM_TYPE_ANI ) {
1777                 int i,first = bm_bitmaps[bitmapnum].info.ani.first_frame;
1778
1779                 for ( i=0; i< bm_bitmaps[first].info.ani.num_frames; i++ )      {
1780                         // Mark all the bitmaps in this bitmap or animation as recently used
1781                         bm_bitmaps[first+i].last_used = timer_get_milliseconds();
1782
1783                         // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
1784                         #ifdef BMPMAN_NDEBUG
1785                                 bm_bitmaps[first+i].used_count++;
1786                         #endif
1787                         bm_bitmaps[first+i].used_flags = flags;
1788                 }
1789         } else {
1790                 // Mark all the bitmaps in this bitmap or animation as recently used
1791                 be->last_used = timer_get_milliseconds();
1792
1793                 // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
1794                 #ifdef BMPMAN_NDEBUG
1795                         be->used_count++;
1796                 #endif
1797                 be->used_flags = flags;
1798         }
1799
1800         return bmp;
1801 }
1802
1803 // Unlocks a bitmap
1804 //
1805 // Decrements the ref_count member of the bitmap_entry struct.  A bitmap can only be unloaded
1806 // when the ref_count is 0.
1807 //
1808 void bm_unlock( int handle )
1809 {
1810         bitmap_entry    *be;
1811         bitmap                  *bmp;
1812
1813         int bitmapnum = handle % MAX_BITMAPS;
1814         Assert( bm_bitmaps[bitmapnum].handle == handle );       // INVALID BITMAP HANDLE
1815
1816         Assert(bitmapnum >= 0 && bitmapnum < MAX_BITMAPS);
1817         if ( !bm_inited ) bm_init();
1818
1819         be = &bm_bitmaps[bitmapnum];
1820         bmp = &be->bm;
1821
1822         be->ref_count--;
1823         Assert(be->ref_count >= 0);             // Trying to unlock data more times than lock was called!!!
1824
1825 }
1826
1827
1828 void bm_update()
1829 {
1830 }
1831
1832 char *bm_get_filename(int handle)
1833 {
1834         int n;
1835
1836         n = handle % MAX_BITMAPS;
1837         Assert(bm_bitmaps[n].handle == handle);         // INVALID BITMAP HANDLE
1838         return bm_bitmaps[n].filename;
1839 }
1840
1841 void bm_get_palette(int handle, ubyte *pal, char *name)
1842 {
1843         char *filename;
1844         int w,h;
1845
1846         int n= handle % MAX_BITMAPS;
1847         Assert( bm_bitmaps[n].handle == handle );               // INVALID BITMAP HANDLE
1848
1849         filename = bm_bitmaps[n].filename;
1850
1851         if (name)       {
1852                 strcpy( name, filename );
1853         }
1854
1855         int pcx_error=pcx_read_header( filename, &w, &h, pal );
1856         if ( pcx_error != PCX_ERROR_NONE ){
1857                 // Error(LOCATION, "Couldn't open '%s'\n", filename );
1858         }
1859 }
1860
1861 // --------------------------------------------------------------------------------------
1862 // bm_release()  - unloads the bitmap's data and entire slot, so bitmap 'n' won't be valid anymore
1863 //
1864 // parameters:          n               =>              index into bm_bitmaps ( index returned from bm_load() or bm_create() )
1865 //
1866 // returns:                     nothing
1867
1868 void bm_release(int handle)
1869 {
1870         bitmap_entry    *be;
1871
1872         int n = handle % MAX_BITMAPS;
1873
1874         Assert(n >= 0 && n < MAX_BITMAPS);
1875         be = &bm_bitmaps[n];
1876
1877         if ( bm_bitmaps[n].type == BM_TYPE_NONE ) {
1878                 return; // Already been released?
1879         }
1880
1881         if ( bm_bitmaps[n].type != BM_TYPE_USER )       {
1882                 return;
1883         }
1884
1885         Assert( be->handle == handle );         // INVALID BITMAP HANDLE
1886
1887         // If it is locked, cannot free it.
1888         if (be->ref_count != 0) {
1889                 nprintf(("BmpMan", "tried to unload %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
1890                 return;
1891         }
1892
1893         bm_free_data(n);
1894
1895         if ( bm_bitmaps[n].type == BM_TYPE_USER )       {
1896                 bm_bitmaps[n].info.user.data = NULL;
1897                 bm_bitmaps[n].info.user.bpp = 0;
1898         }
1899
1900
1901         bm_bitmaps[n].type = BM_TYPE_NONE;
1902
1903         // Fill in bogus structures!
1904
1905         // For debugging:
1906         strcpy( bm_bitmaps[n].filename, "IVE_BEEN_RELEASED!" );
1907         bm_bitmaps[n].signature = 0xDEADBEEF;                                                                   // a unique signature identifying the data
1908         bm_bitmaps[n].palette_checksum = 0xDEADBEEF;                                                    // checksum used to be sure bitmap is in current palette
1909
1910         // bookeeping
1911         #ifdef BMPMAN_NDEBUG
1912         bm_bitmaps[n].data_size = -1;                                                                   // How much data this bitmap uses
1913         #endif
1914         bm_bitmaps[n].ref_count = -1;                                                                   // Number of locks on bitmap.  Can't unload unless ref_count is 0.
1915
1916         // Bitmap info
1917         bm_bitmaps[n].bm.w = bm_bitmaps[n].bm.h = -1;
1918         
1919         // Stuff needed for animations
1920         // Stuff needed for user bitmaps
1921         memset( &bm_bitmaps[n].info, 0, sizeof(bm_extra_info) );
1922
1923         bm_bitmaps[n].handle = -1;
1924 }
1925
1926
1927
1928
1929
1930
1931 // --------------------------------------------------------------------------------------
1932 // bm_unload()  - unloads the data, but not the bitmap info.
1933 //
1934 // parameters:          n               =>              index into bm_bitmaps ( index returned from bm_load() or bm_create() )
1935 //
1936 // returns:                     0               =>              unload failed
1937 //                                              1               =>              unload successful
1938 //
1939 int bm_unload( int handle )
1940 {
1941         bitmap_entry    *be;
1942         bitmap                  *bmp;
1943
1944         int n = handle % MAX_BITMAPS;
1945
1946         Assert(n >= 0 && n < MAX_BITMAPS);
1947         be = &bm_bitmaps[n];
1948         bmp = &be->bm;
1949
1950         if ( be->type == BM_TYPE_NONE ) {
1951                 return 0;               // Already been released
1952         }
1953
1954         Assert( be->handle == handle );         // INVALID BITMAP HANDLE!
1955
1956         // If it is locked, cannot free it.
1957         if (be->ref_count != 0) {
1958                 nprintf(("BmpMan", "tried to unload %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
1959                 return 0;
1960         }
1961
1962         nprintf(("BmpMan", "unloading %s.  %dx%dx%d\n", be->filename, bmp->w, bmp->h, bmp->bpp));
1963         bm_free_data(n);                // clears flags, bbp, data, etc
1964
1965         return 1;
1966 }
1967
1968
1969 // unload all used bitmaps
1970 void bm_unload_all()
1971 {
1972         int i;
1973
1974         for (i = 0; i < MAX_BITMAPS; i++)       {
1975                 if ( bm_bitmaps[i].type != BM_TYPE_NONE )       {
1976                         bm_unload(bm_bitmaps[i].handle);
1977                 }
1978         }
1979 }
1980
1981
1982 DCF(bmpman,"Shows/changes bitmap caching parameters and usage")
1983 {
1984         if ( Dc_command )       {
1985                 dc_get_arg(ARG_STRING);
1986                 if ( !strcmp( Dc_arg, "flush" ))        {
1987                         dc_printf( "Total RAM usage before flush: %d bytes\n", bm_texture_ram );
1988                         int i;
1989                         for (i = 0; i < MAX_BITMAPS; i++)       {
1990                                 if ( bm_bitmaps[i].type != BM_TYPE_NONE )       {
1991                                         bm_free_data(i);
1992                                 }
1993                         }
1994                         dc_printf( "Total RAM after flush: %d bytes\n", bm_texture_ram );
1995                 } else if ( !strcmp( Dc_arg, "ram" ))   {
1996                         dc_get_arg(ARG_INT);
1997                         Bm_max_ram = Dc_arg_int*1024*1024;
1998                 } else {
1999                         // print usage, not stats
2000                         Dc_help = 1;
2001                 }
2002         }
2003
2004         if ( Dc_help )  {
2005                 dc_printf( "Usage: BmpMan keyword\nWhere keyword can be in the following forms:\n" );
2006                 dc_printf( "BmpMan flush    Unloads all bitmaps.\n" );
2007                 dc_printf( "BmpMan ram x    Sets max mem usage to x MB. (Set to 0 to have no limit.)\n" );
2008                 dc_printf( "\nUse '? BmpMan' to see status of Bitmap manager.\n" );
2009                 Dc_status = 0;  // don't print status if help is printed.  Too messy.
2010         }
2011
2012         if ( Dc_status )        {
2013                 dc_printf( "Total RAM usage: %d bytes\n", bm_texture_ram );
2014
2015
2016                 if ( Bm_max_ram > 1024*1024 )
2017                         dc_printf( "Max RAM allowed: %.1f MB\n", i2fl(Bm_max_ram)/(1024.0f*1024.0f) );
2018                 else if ( Bm_max_ram > 1024 )
2019                         dc_printf( "Max RAM allowed: %.1f KB\n", i2fl(Bm_max_ram)/(1024.0f) );
2020                 else if ( Bm_max_ram > 0 )
2021                         dc_printf( "Max RAM allowed: %d bytes\n", Bm_max_ram );
2022                 else
2023                         dc_printf( "No RAM limit\n" );
2024
2025
2026         }
2027 }
2028
2029 // Marks a texture as being used for this level
2030 void bm_page_in_texture( int bitmapnum, int nframes )
2031 {
2032         int i;
2033         for (i=0; i<nframes;i++ )       {
2034                 int n = bitmapnum % MAX_BITMAPS;
2035
2036                 bm_bitmaps[n+i].preloaded = 1;
2037
2038                 if ( D3D_enabled )      {
2039                         bm_bitmaps[n+i].used_flags = BMP_TEX_OTHER;
2040                 } else {                        
2041                         bm_bitmaps[n+i].used_flags = 0;
2042                 }
2043         }
2044 }
2045
2046 // Marks a texture as being used for this level
2047 // If num_frames is passed, assume this is an animation
2048 void bm_page_in_nondarkening_texture( int bitmapnum, int nframes )
2049 {
2050         int i;
2051         for (i=0; i<nframes;i++ )       {
2052                 int n = bitmapnum % MAX_BITMAPS;
2053
2054                 bm_bitmaps[n+i].preloaded = 4;
2055
2056                 if ( D3D_enabled )      {                       
2057                         bm_bitmaps[n+i].used_flags = BMP_TEX_NONDARK;
2058                 } else {
2059                         bm_bitmaps[n+i].used_flags = 0;
2060                 }
2061         }
2062 }
2063
2064 // marks a texture as being a transparent textyre used for this level
2065 // Marks a texture as being used for this level
2066 // If num_frames is passed, assume this is an animation
2067 void bm_page_in_xparent_texture( int bitmapnum, int nframes)
2068 {
2069         int i;
2070         for (i=0; i<nframes;i++ )       {
2071                 int n = bitmapnum % MAX_BITMAPS;
2072
2073                 bm_bitmaps[n+i].preloaded = 3;
2074
2075                 if ( D3D_enabled )      {
2076                         // bm_bitmaps[n+i].used_flags = BMP_NO_PALETTE_MAP;
2077                         bm_bitmaps[n+i].used_flags = BMP_TEX_XPARENT;
2078                 } else {
2079                         bm_bitmaps[n+i].used_flags = 0;
2080                 }
2081         }
2082 }
2083
2084 // Marks an aabitmap as being used for this level
2085 void bm_page_in_aabitmap( int bitmapnum, int nframes )
2086 {
2087         int i;
2088
2089         for (i=0; i<nframes;i++ )       {
2090                 int n = bitmapnum % MAX_BITMAPS;
2091
2092                 bm_bitmaps[n+i].preloaded = 2;
2093         
2094                 if ( D3D_enabled )      {
2095                         bm_bitmaps[n+i].used_flags = BMP_AABITMAP;
2096                 } else {
2097                         bm_bitmaps[n+i].used_flags = 0;
2098                 }
2099         }
2100 }
2101
2102
2103
2104 // Tell the bitmap manager to start keeping track of what bitmaps are used where.
2105 void bm_page_in_start()
2106 {
2107         int i;
2108
2109         Bm_paging = 1;
2110
2111         // Mark all as inited
2112         for (i = 0; i < MAX_BITMAPS; i++)       {
2113                 if ( bm_bitmaps[i].type != BM_TYPE_NONE )       {
2114                         bm_unload(bm_bitmaps[i].handle);
2115                 }
2116                 bm_bitmaps[i].preloaded = 0;
2117                 #ifdef BMPMAN_NDEBUG
2118                         bm_bitmaps[i].used_count = 0;
2119                 #endif
2120                 bm_bitmaps[i].used_flags = 0;
2121         }
2122
2123 }
2124
2125 extern void gr_d3d_preload_init();
2126 extern int gr_d3d_preload(int bitmap_num, int is_aabitmap );
2127
2128 void bm_page_in_stop()
2129 {       
2130         int i;  
2131         int ship_info_index;
2132
2133         nprintf(( "BmpInfo","BMPMAN: Loading all used bitmaps.\n" ));
2134
2135         // Load all the ones that are supposed to be loaded for this level.
2136         int n = 0;
2137
2138         #ifdef BMPMAN_NDEBUG
2139         Bm_ram_freed = 0;
2140         #endif
2141
2142         int d3d_preloading = 1;
2143
2144         gr_d3d_preload_init();
2145
2146         for (i = 0; i < MAX_BITMAPS; i++)       {
2147                 if ( bm_bitmaps[i].type != BM_TYPE_NONE )       {
2148                         if ( bm_bitmaps[i].preloaded )  {
2149 #ifdef BMPMAN_SPECIAL_NONDARK
2150                                 // if this is a texture, check to see if a ship uses it
2151                                 ship_info_index = ship_get_texture(bm_bitmaps[i].handle);
2152                                 // use the colors from this ship
2153                                 if((ship_info_index >= 0) && (Ship_info[ship_info_index].num_nondark_colors > 0)){
2154                                         // mprintf(("Using custom pixels for %s\n", Ship_info[ship_info_index].name));
2155                                         palman_set_nondarkening(Ship_info[ship_info_index].nondark_colors, Ship_info[ship_info_index].num_nondark_colors);
2156                                 }
2157                                 // use the colors from the default table
2158                                 else {
2159                                         // mprintf(("Using default pixels\n"));
2160                                         palman_set_nondarkening(Palman_non_darkening_default, Palman_num_nondarkening_default);
2161                                 }
2162 #endif
2163
2164                                 // if preloaded == 3, load it as an xparent texture                             
2165                                 if(bm_bitmaps[i].used_flags == BMP_AABITMAP){
2166                                         bm_lock( bm_bitmaps[i].handle, 8, bm_bitmaps[i].used_flags );
2167                                 } else {
2168                                         bm_lock( bm_bitmaps[i].handle, 16, bm_bitmaps[i].used_flags );
2169                                 }
2170                                 bm_unlock( bm_bitmaps[i].handle );
2171
2172                                 if ( d3d_preloading )   {
2173                                         if ( !gr_d3d_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded==2) ) )     {
2174                                                 mprintf(( "Out of VRAM.  Done preloading.\n" ));
2175                                                 d3d_preloading = 0;
2176                                         }
2177                                 }
2178
2179                                 n++;
2180                                 #ifdef BMPMAN_NDEBUG
2181                                 if ( Bm_ram_freed )     {
2182                                         nprintf(( "BmpInfo","BMPMAN: Not enough cache memory to load all level bitmaps\n" ));
2183                                         break;
2184                                 }
2185                                 #endif
2186                         } 
2187                 }
2188                 game_busy();
2189         }
2190         nprintf(( "BmpInfo","BMPMAN: Loaded %d bitmaps that are marked as used for this level.\n", n ));
2191
2192         int total_bitmaps = 0;
2193         for (i = 0; i < MAX_BITMAPS; i++)       {
2194                 if ( bm_bitmaps[i].type != BM_TYPE_NONE )       {
2195                         total_bitmaps++;
2196                 }
2197                 if ( bm_bitmaps[i].type == BM_TYPE_USER )       {
2198                         mprintf(( "User bitmap '%s'\n", bm_bitmaps[i].filename ));
2199                 }
2200         }       
2201
2202         mprintf(( "Bmpman: %d/%d bitmap slots in use.\n", total_bitmaps, MAX_BITMAPS ));
2203         //mprintf(( "Bmpman: Usage went from %d KB to %d KB.\n", usage_before/1024, usage_after/1024 ));
2204
2205         Bm_paging = 0;
2206 }
2207
2208 int bm_get_cache_slot( int bitmap_id, int separate_ani_frames )
2209 {
2210         int n = bitmap_id % MAX_BITMAPS;
2211
2212         Assert( bm_bitmaps[n].handle == bitmap_id );            // INVALID BITMAP HANDLE
2213
2214         bitmap_entry    *be = &bm_bitmaps[n];
2215
2216         if ( (!separate_ani_frames) && (be->type == BM_TYPE_ANI) )      {
2217                 return be->info.ani.first_frame;
2218         } 
2219
2220         return n;
2221
2222 }
2223
2224 // convert a 24 bit value to a 16 bit value
2225 void bm_24_to_16(int bit_24, ushort *bit_16)
2226 {
2227         ubyte *pixel = (ubyte*)&bit_24;
2228         ubyte alpha = 1;
2229
2230         bm_set_components((ubyte*)bit_16, (ubyte*)&pixel[0], (ubyte*)&pixel[1], (ubyte*)&pixel[2], &alpha);     
2231 }
2232
2233 extern int D3D_32bit;
2234
2235 void (*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
2236
2237 void bm_set_components_argb(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2238 {
2239         // rgba 
2240         *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2241         *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2242         *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2243         *((ushort*)pixel) &= ~(0x8000);
2244         if(*av){
2245                 *((ushort*)pixel) |= 0x8000;
2246         }
2247 }
2248
2249 void bm_set_components_d3d(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2250 {
2251         // rgba 
2252         *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2253         *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2254         *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2255         if(*av == 0){ 
2256                 *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2257         }
2258 }
2259
2260 void bm_set_components_argb_d3d_16_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2261 {
2262         *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2263         *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2264         *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2265         if(*av == 0){                           
2266                 *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2267         }                       
2268 }
2269
2270 void bm_set_components_argb_d3d_32_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2271 {
2272         *((uint*)pixel) |= (uint)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2273         *((uint*)pixel) |= (uint)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2274         *((uint*)pixel) |= (uint)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2275         if(*av == 0){                           
2276                 *((uint*)pixel) = (uint)Gr_current_green->mask;         
2277         }
2278 }
2279
2280 void bm_set_components_argb_d3d_16_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2281 {
2282         *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2283         *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2284         *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2285         *((ushort*)pixel) &= ~(Gr_current_alpha->mask);
2286         if(*av){
2287                 *((ushort*)pixel) |= (ushort)(Gr_current_alpha->mask);
2288         } else {
2289                 *((ushort*)pixel) = 0;
2290         }
2291 }
2292
2293 void bm_set_components_argb_d3d_32_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2294 {
2295         *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2296         *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2297         *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2298         *((ushort*)pixel) &= ~(Gr_current_alpha->mask);
2299         if(*av){
2300                 *((ushort*)pixel) |= (ushort)(Gr_current_alpha->mask);
2301         } else {
2302                 *((ushort*)pixel) = 0;
2303         }
2304 }
2305
2306 // for selecting pixel formats
2307 void BM_SELECT_SCREEN_FORMAT()
2308 {
2309         Gr_current_red = &Gr_red;
2310         Gr_current_green = &Gr_green;
2311         Gr_current_blue = &Gr_blue;
2312         Gr_current_alpha = &Gr_alpha;
2313
2314         // setup pointers
2315         if(gr_screen.mode == GR_GLIDE){
2316                 bm_set_components = bm_set_components_argb;
2317         } else if(gr_screen.mode == GR_DIRECT3D){
2318                 if(Bm_pixel_format == BM_PIXEL_FORMAT_D3D){
2319                         bm_set_components = bm_set_components_d3d;
2320                 } else {
2321                         if(D3D_32bit){
2322                                 bm_set_components = bm_set_components_argb_d3d_32_screen;
2323                         } else {
2324                                 bm_set_components = bm_set_components_argb_d3d_16_screen;
2325                         }
2326                 }
2327         }
2328 }
2329
2330 void BM_SELECT_TEX_FORMAT()
2331 {
2332         Gr_current_red = &Gr_t_red; 
2333         Gr_current_green = &Gr_t_green; 
2334         Gr_current_blue = &Gr_t_blue; 
2335         Gr_current_alpha = &Gr_t_alpha;
2336
2337         // setup pointers
2338         if(gr_screen.mode == GR_GLIDE){
2339                 bm_set_components = bm_set_components_argb;
2340         } else if(gr_screen.mode == GR_DIRECT3D){
2341                 if(Bm_pixel_format == BM_PIXEL_FORMAT_D3D){
2342                         bm_set_components = bm_set_components_d3d;
2343                 } else {
2344                         if(D3D_32bit){
2345                                 bm_set_components = bm_set_components_argb_d3d_32_tex;
2346                         } else {
2347                                 bm_set_components = bm_set_components_argb_d3d_16_tex;
2348                         }
2349                 }
2350         }
2351 }
2352
2353 void BM_SELECT_ALPHA_TEX_FORMAT()
2354 {
2355         Gr_current_red = &Gr_ta_red; 
2356         Gr_current_green = &Gr_ta_green; 
2357         Gr_current_blue = &Gr_ta_blue; 
2358         Gr_current_alpha = &Gr_ta_alpha;
2359
2360         // setup pointers
2361         if(gr_screen.mode == GR_GLIDE){
2362                 bm_set_components = bm_set_components_argb;
2363         } else if(gr_screen.mode == GR_DIRECT3D){
2364                 if(Bm_pixel_format == BM_PIXEL_FORMAT_D3D){
2365                         bm_set_components = bm_set_components_d3d;
2366                 } else {
2367                         if(D3D_32bit){
2368                                 bm_set_components = bm_set_components_argb_d3d_32_tex;
2369                         } else {
2370                                 bm_set_components = bm_set_components_argb_d3d_16_tex;
2371                         }
2372                 }
2373         }
2374 }
2375
2376 // set the rgba components of a pixel, any of the parameters can be -1
2377 /*
2378 void bm_set_components(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2379 {
2380         int bit_32 = 0;
2381
2382         // pick a byte size - 32 bits only if 32 bit mode d3d and screen format
2383         if(D3D_32bit && (Gr_current_red == &Gr_red)){
2384                 bit_32 = 1;
2385         }       
2386         
2387         if(bit_32){
2388                 *((uint*)pixel) |= (uint)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2389         } else {
2390                 *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2391         }               
2392         if(bit_32){
2393                 *((uint*)pixel) |= (uint)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2394         } else {
2395                 *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2396         }               
2397         if(bit_32){
2398                 *((uint*)pixel) |= (uint)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2399         } else {
2400                 *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2401         }
2402         
2403         // NOTE - this is a semi-hack. For direct3d we don't use an alpha bit, so if *av == 0, we just set the whole pixel to be Gr_green.mask
2404         //        ergo, we need to do this _last_
2405         switch(Bm_pixel_format){
2406         // glide has an alpha channel so we have to unset ir or set it each time
2407         case BM_PIXEL_FORMAT_ARGB:
2408                 Assert(!bit_32);
2409                 *((ushort*)pixel) &= ~(0x8000);
2410                 if(*av){
2411                         *((ushort*)pixel) |= 0x8000;
2412                 }
2413                 break;
2414         
2415         // this d3d format has no alpha channel, so only make it "transparent", never make it "non-transparent"
2416         case BM_PIXEL_FORMAT_D3D:                       
2417                 Assert(!bit_32);
2418                 if(*av == 0){ 
2419                         *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2420                 }
2421                 break;
2422
2423         // nice 1555 texture format
2424         case BM_PIXEL_FORMAT_ARGB_D3D:                                          
2425                 // if we're writing to normal texture format
2426                 if(Gr_current_red == &Gr_t_red){                                        
2427                         Assert(!bit_32);
2428                         *((ushort*)pixel) &= ~(Gr_current_alpha->mask);
2429                         if(*av){
2430                                 *((ushort*)pixel) |= (ushort)(Gr_current_alpha->mask);
2431                         } else {
2432                                 *((ushort*)pixel) = 0;
2433                         }
2434                 }
2435                 // otherwise if we're writing to screen format, still do it the green mask way
2436                 else {                  
2437                         if(*av == 0){
2438                                 if(bit_32){
2439                                         *((uint*)pixel) = (uint)Gr_current_green->mask;
2440                                 } else {
2441                                         *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2442                                 }
2443                         }
2444                 }                       
2445                 break;
2446         }       
2447 }
2448 */
2449
2450 // get the rgba components of a pixel, any of the parameters can be NULL
2451 void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a)
2452 {
2453         int bit_32 = 0;
2454
2455         // pick a byte size - 32 bits only if 32 bit mode d3d and screen format
2456         if(D3D_32bit && (Gr_current_red == &Gr_red)){
2457                 bit_32 = 1;
2458         }
2459
2460         if(r != NULL){
2461                 if(bit_32){
2462                         *r = ubyte(( (*((uint*)pixel) & Gr_current_red->mask)>>Gr_current_red->shift)*Gr_current_red->scale);
2463                 } else {
2464                         *r = ubyte(( ( ((ushort*)pixel)[0] & Gr_current_red->mask)>>Gr_current_red->shift)*Gr_current_red->scale);
2465                 }
2466         }
2467         if(g != NULL){
2468                 if(bit_32){
2469                         *g = ubyte(( (*((uint*)pixel) & Gr_current_green->mask) >>Gr_current_green->shift)*Gr_current_green->scale);
2470                 } else {
2471                         *g = ubyte(( ( ((ushort*)pixel)[0] & Gr_current_green->mask) >>Gr_current_green->shift)*Gr_current_green->scale);
2472                 }
2473         }
2474         if(b != NULL){
2475                 if(bit_32){
2476                         *b = ubyte(( (*((uint*)pixel) & Gr_current_blue->mask)>>Gr_current_blue->shift)*Gr_current_blue->scale);
2477                 } else {
2478                         *b = ubyte(( ( ((ushort*)pixel)[0] & Gr_current_blue->mask)>>Gr_current_blue->shift)*Gr_current_blue->scale);
2479                 }
2480         }
2481
2482         // get the alpha value
2483         if(a != NULL){          
2484                 *a = 1;
2485
2486                 switch(Bm_pixel_format){
2487                 // glide has an alpha channel so we have to unset ir or set it each time
2488                 case BM_PIXEL_FORMAT_ARGB:                      
2489                         Assert(!bit_32);
2490                         if(!( ((ushort*)pixel)[0] & 0x8000)){
2491                                 *a = 0;
2492                         } 
2493                         break;
2494
2495                 // this d3d format has no alpha channel, so only make it "transparent", never make it "non-transparent"
2496                 case BM_PIXEL_FORMAT_D3D:
2497                         Assert(!bit_32);
2498                         if( *((ushort*)pixel) == Gr_current_green->mask){ 
2499                                 *a = 0;
2500                         }
2501                         break;
2502
2503                 // nice 1555 texture format mode
2504                 case BM_PIXEL_FORMAT_ARGB_D3D:  
2505                         // if we're writing to a normal texture, use nice alpha bits
2506                         if(Gr_current_red == &Gr_t_red){                                
2507                                 Assert(!bit_32);
2508
2509                                 if(!(*((ushort*)pixel) & Gr_current_alpha->mask)){
2510                                         *a = 0;
2511                                 }
2512                         }
2513                         // otherwise do it as normal
2514                         else {
2515                                 if(bit_32){
2516                                         if(*((int*)pixel) == Gr_current_green->mask){ 
2517                                                 *a = 0;
2518                                         }
2519                                 } else {
2520                                         if(*((ushort*)pixel) == Gr_current_green->mask){ 
2521                                                 *a = 0;
2522                                         }
2523                                 }
2524                         }
2525                 }
2526         }
2527 }
2528
2529 // get filename
2530 void bm_get_filename(int bitmapnum, char *filename)
2531 {
2532         int n = bitmapnum % MAX_BITMAPS;
2533
2534         // return filename
2535         strcpy(filename, bm_bitmaps[n].filename);
2536 }
2537
2538 // given a bitmap and a section, return the size (w, h)
2539 void bm_get_section_size(int bitmapnum, int sx, int sy, int *w, int *h)
2540 {
2541         int bw, bh;
2542         bitmap_section_info *sections;
2543
2544         // bogus input?
2545         Assert((w != NULL) && (h != NULL));
2546         if((w == NULL) || (h == NULL)){
2547                 return;
2548         }
2549
2550         // get bitmap info
2551         bm_get_info(bitmapnum, &bw, &bh, NULL, NULL, NULL, &sections);
2552
2553         // determine the width and height of this section
2554         *w = sx < (sections->num_x - 1) ? MAX_BMAP_SECTION_SIZE : bw - sections->sx[sx];
2555         *h = sy < (sections->num_y - 1) ? MAX_BMAP_SECTION_SIZE : bh - sections->sy[sy];                                                                                
2556 }