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