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