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