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