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