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