mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-23 03:58:59 +00:00
1925 lines
45 KiB
C++
1925 lines
45 KiB
C++
/*
|
|
* $Logfile: /DescentIII/Main/bitmap/bitmain.cpp $
|
|
* $Revision: 70 $
|
|
* $Date: 5/10/00 5:09p $
|
|
* $Author: Matt $
|
|
*
|
|
* Bitmap handling functions
|
|
*
|
|
* $Log: /DescentIII/Main/bitmap/bitmain.cpp $
|
|
*
|
|
* 70 5/10/00 5:09p Matt
|
|
* Added casts so code would compile under Visual C++.
|
|
*
|
|
* 69 5/10/00 4:34p Jeff
|
|
* handle buggy tablefile editors that put the full path name to a
|
|
* primative instead of just the filename
|
|
*
|
|
* 68 4/19/00 5:29p Matt
|
|
* From Duane for 1.4
|
|
* Added Mac-only error handling
|
|
* Added checks & asserts for error return values
|
|
*
|
|
* 67 4/04/00 6:09p Matt
|
|
* Fixed two problems in the hash code: the hash values were
|
|
* case-sensitive, which caused misses with mixed-case filenames, and hash
|
|
* table nodes were not freed when a bitmap was freed.
|
|
*
|
|
* 66 3/20/00 12:23p Matt
|
|
* Merge of Duane's post-1.3 changes.
|
|
* Small optimization
|
|
* Error check
|
|
*
|
|
* 65 2/06/00 3:41a Jason
|
|
* fixed memory overrun error in bm_ChangeEndName function
|
|
*
|
|
* 64 10/21/99 9:27p Jeff
|
|
* B.A. Macintosh code merge
|
|
*
|
|
* 63 8/10/99 5:10p Jeff
|
|
* delete the hash table on bitmap lib shutdown...just to be clean
|
|
*
|
|
* 62 7/28/99 5:18p Kevin
|
|
* Mac merge fixes
|
|
*
|
|
* 61 7/28/99 3:37p Kevin
|
|
* Mac!
|
|
*
|
|
* 60 4/29/99 4:59p Jason
|
|
* fixed some preuploaded texture problems
|
|
*
|
|
* 59 4/23/99 10:45p Jeff
|
|
* fixed crash with freeing hash table, set it to NULL to prevent double
|
|
* free
|
|
*
|
|
* 58 4/21/99 11:05a Kevin
|
|
* new ps_rand and ps_srand to replace rand & srand
|
|
*
|
|
* 57 4/16/99 11:51p Jeff
|
|
* renamed strcmpi to stricmp to be linux nice
|
|
*
|
|
* 56 4/15/99 2:56p Kevin
|
|
* Removed unneeded mprintf and unused variable
|
|
*
|
|
* 55 4/15/99 12:36p Kevin
|
|
* Changed bm_FindBitmapName to use a hash table.
|
|
*
|
|
* 54 4/14/99 1:07a Jeff
|
|
* fixed case mismatched #includes
|
|
*
|
|
* 53 3/23/99 10:24a Samir
|
|
* NULL pointer in bm_DestroyChunkedBitmap.
|
|
*
|
|
* 52 2/12/99 12:14p Jason
|
|
* fixed memory scaling problem
|
|
*
|
|
* 51 1/19/99 11:17a Jason
|
|
* fixed another scaling problem
|
|
*
|
|
* 50 1/14/99 2:26p Jason
|
|
* made data tracking more reliable
|
|
*
|
|
* 49 1/04/99 6:19p Jason
|
|
* fixed bitmap format problem
|
|
*
|
|
* 48 12/21/98 11:47a Jason
|
|
* fixed bitmap problem with 4444 mipping
|
|
*
|
|
* 47 12/21/98 11:21a Josh
|
|
* FROM JASON: Fixed format/mip problem
|
|
*
|
|
* 46 11/30/98 5:50p Jason
|
|
* added 4444 bitmap support
|
|
*
|
|
* 45 10/21/98 4:36p Jason
|
|
* more changes for renderering speedups
|
|
*
|
|
* 44 10/19/98 4:22p Jason
|
|
* more fixes for Beta5
|
|
*
|
|
* 43 10/08/98 2:27p Jason
|
|
* sped up table file loading
|
|
*
|
|
* 42 9/25/98 12:01p Samir
|
|
* for ndebug builds, removed the return immediately case in
|
|
* bm_AllocLoadFileBitmap.
|
|
*
|
|
* 41 8/21/98 5:14p Jason
|
|
* made better memory use of primitives
|
|
*
|
|
* 40 7/14/98 10:58a Jason
|
|
* fixed transparency bug in error texture
|
|
*
|
|
* 39 5/27/98 5:17p Jason
|
|
* fixed some bugs for the E3 Demo
|
|
*
|
|
* 38 5/20/98 5:43p Jason
|
|
* incremental checkin for bumpmapping
|
|
*
|
|
* 37 5/07/98 3:30p Jeff
|
|
* optimized CreateChunkBitmap a bit
|
|
*
|
|
* 36 5/05/98 1:01p Jeff
|
|
* improved on Chunk bitmaps
|
|
*
|
|
* 35 4/23/98 6:38p Jason
|
|
* made bitmaps use 1555 format
|
|
*
|
|
* 34 4/22/98 12:10p Chris
|
|
* Fixed path length problems
|
|
*
|
|
* 33 4/03/98 12:23p Jason
|
|
* dealt with overlay types being loaded from disk more than once
|
|
*
|
|
* 32 3/31/98 3:48p Jason
|
|
* added memory lib
|
|
*
|
|
* 31 3/23/98 4:42p Jason
|
|
* took out dumb ifdef
|
|
*
|
|
* 30 3/19/98 3:18p Samir
|
|
* enforce constant char* arguments when needed. done in CFILE and bitmap
|
|
* libraries as well as ddio.
|
|
*
|
|
* 29 3/17/98 4:33p Jason
|
|
* Added size changing to bitmaps/textures
|
|
*
|
|
* 28 2/17/98 4:57p Jason
|
|
* upped bitmap counts
|
|
*
|
|
* 27 2/13/98 7:23p Brent
|
|
* fixed mipping bug
|
|
*
|
|
* 26 2/12/98 1:32p Jason
|
|
* got mipmapping working
|
|
*
|
|
* 25 2/11/98 7:08p Jason
|
|
* took out dumb mprintf
|
|
*
|
|
* 24 2/09/98 3:38p Jason
|
|
* fixed potential problem with overlay bitmaps
|
|
*
|
|
* 23 2/06/98 7:20p Jason
|
|
* made duplicate bitmaps replace themselves in memory
|
|
*
|
|
* 22 1/26/98 4:32p Jason
|
|
* took out some goofy mprintfs
|
|
*
|
|
* 21 1/16/98 3:14p Samir
|
|
* Now store pixel width and height of chunked bitmap.
|
|
*
|
|
* 20 1/16/98 11:46a Samir
|
|
* Added functions to allocate and destroy chunked bitmaps.
|
|
*
|
|
* 19 1/14/98 12:45p Jeff
|
|
* Added a 'clear bitmap' function. Clears to transparent color.
|
|
*
|
|
* 18 12/23/97 6:32p Mark
|
|
* fixed problem with trying to save a bitmap that hasn't been paged in.
|
|
*
|
|
* 17 12/19/97 5:59p Jason
|
|
* sped up bitmap loading
|
|
*
|
|
* 16 12/19/97 3:36p Jason
|
|
* bug fixes for bitmap paging stuff
|
|
*
|
|
* 15 12/19/97 2:46p Jason
|
|
* implemented bitmap paging routines
|
|
*
|
|
* 14 12/18/97 4:03p Jason
|
|
* added error checking for bitmaps initting
|
|
*
|
|
* 13 11/11/97 1:07p Jason
|
|
* fixed multiple names problem in bitmap naming
|
|
*
|
|
* 12 11/10/97 4:53p Jason
|
|
* added warning for names that are too long
|
|
*
|
|
* 11 10/16/97 4:55p Jason
|
|
* fixed stupid off-by-one bug
|
|
*
|
|
* 10 10/16/97 10:48a Jason
|
|
* added bm_set_priority
|
|
*
|
|
* 9 10/15/97 5:20p Jason
|
|
* did a HUGE overhaul of the bitmap system
|
|
*
|
|
* 8 9/17/97 10:48a Jason
|
|
* added cache_slot variable
|
|
*
|
|
* 7 9/16/97 5:04p Matt
|
|
* Changed conditional for debug code
|
|
*
|
|
* 6 9/12/97 6:06p Samir
|
|
* Added function to get bitmap pixel.
|
|
*
|
|
* 5 9/10/97 12:13p Samir
|
|
* Added function to check if a pixel is transparent.
|
|
*
|
|
* 4 9/02/97 11:18a Jason
|
|
* got rid of compiler warnings
|
|
*
|
|
* 3 8/29/97 1:22p Jason
|
|
* added tga screenshots
|
|
*
|
|
* 2 8/05/97 10:18a Jason
|
|
* added lightmap system
|
|
*
|
|
* 46 6/24/97 12:41p Jason
|
|
* checked in for safety
|
|
*
|
|
* 45 6/06/97 3:57p Jason
|
|
* implemented changes for small textures and automatic tmap2 recognition
|
|
*
|
|
* 44 6/03/97 12:19p Jason
|
|
* cleaned up the bitmap library a bit
|
|
*
|
|
* 43 5/19/97 5:10p Jason
|
|
* changes for our new abstracted renderer code
|
|
*
|
|
* 42 5/12/97 11:41a Jason
|
|
* made game work (default) to 16bit no mip maps mode
|
|
* Saves us alot of memory
|
|
*
|
|
* 41 5/08/97 1:16p Jason
|
|
* made ChangeEndName work with device independant calls
|
|
*
|
|
* 40 5/02/97 5:22p Jason
|
|
* added bm_rowsize to return bytes per row
|
|
*
|
|
* 39 5/01/97 4:37p Jason
|
|
* made bitmaps clear their settings when alloced (bug fixed)
|
|
*
|
|
* 38 4/30/97 3:15p Jason
|
|
* changes to support both 8bit and 16bit rendering in software
|
|
*
|
|
* 37 4/25/97 3:31p Jason
|
|
* implemented better memory management for vclips and bitmaps
|
|
*
|
|
* 36 4/8/97 5:23 PM Jeremy
|
|
* #ifdef editor around calls to decrement bitmap_memory_used by checking
|
|
* _msize of an array location. _msize is microsoft specific, not cross
|
|
* platform, but this is only used by the editor anyway, thus the ifdef
|
|
* editor.
|
|
*
|
|
* 35 3/31/97 7:18p Jason
|
|
* made bitmaps easier on memory if not in editor mode
|
|
*
|
|
* 34 3/28/97 12:22p Jason
|
|
* implemented memory sharing scheme between 8 bit bitmaps
|
|
*
|
|
* 33 3/13/97 1:05p Matt
|
|
* Fixed extra-stupid bug
|
|
*
|
|
* 32 3/13/97 12:35p Matt
|
|
* Look for error1.ogf in current directory (explicitely)
|
|
*
|
|
* 31 3/03/97 6:20p Matt
|
|
* Changed cfile functions to use D3 naming convention
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "CFILE.H"
|
|
#include "texture.h"
|
|
#include "bitmap.h"
|
|
#include "pstypes.h"
|
|
#include "pserror.h"
|
|
#include "mono.h"
|
|
#include "iff.h"
|
|
#include "ddio.h"
|
|
#include "lightmap.h"
|
|
#include "bumpmap.h"
|
|
#include "mem.h"
|
|
#include "psrand.h"
|
|
|
|
#include "Macros.h"
|
|
|
|
#define BM_FILETYPE_TGA 1
|
|
#define BM_FILETYPE_PCX 2
|
|
#define BM_FILETYPE_IFF 3
|
|
int Num_of_bitmaps=0;
|
|
bms_bitmap GameBitmaps[MAX_BITMAPS];
|
|
ulong Bitmap_memory_used=0;
|
|
ubyte Bitmaps_initted=0;
|
|
/* modify these lines to establish data type */
|
|
typedef bms_bitmap * bm_T; /* type of item to be stored */
|
|
typedef int bm_hashTableIndex; /* index into hash table */
|
|
#define compEQ(a,b) (stricmp((a)->name,(b)->name)==0)
|
|
typedef struct bm_Node_ {
|
|
struct bm_Node_ *next; /* next bm_Node */
|
|
bm_T data; /* data stored in bm_Node */
|
|
} bm_Node;
|
|
bm_Node *bm_findNode (bm_T data);
|
|
void bm_deleteNode(bm_T data);
|
|
bm_Node *bm_insertNode(bm_T data);
|
|
bm_hashTableIndex bm_hash(bm_T data);
|
|
bm_Node **bm_hashTable = NULL;
|
|
int bm_hashTableSize = (MAX_BITMAPS/2);
|
|
void bm_InitHashTable()
|
|
{
|
|
bm_hashTable = (bm_Node **)mem_malloc(bm_hashTableSize * sizeof(bm_Node *));
|
|
for(int a=0;a<bm_hashTableSize;a++)
|
|
{
|
|
bm_hashTable[a] = NULL;
|
|
}
|
|
}
|
|
void bm_DeleteHashTable()
|
|
{
|
|
if(bm_hashTable)
|
|
{
|
|
int idx;
|
|
for(idx=0;idx<bm_hashTableSize;idx++)
|
|
{
|
|
if(bm_hashTable[idx])
|
|
{
|
|
bm_Node *curr,*next;
|
|
curr = bm_hashTable[idx];
|
|
while(curr)
|
|
{
|
|
next = curr->next;
|
|
mem_free(curr);
|
|
curr = next;
|
|
}
|
|
bm_hashTable[idx] = NULL;
|
|
}
|
|
}
|
|
|
|
mem_free(bm_hashTable);
|
|
bm_hashTable = NULL;
|
|
}
|
|
}
|
|
|
|
bm_hashTableIndex bm_hash(bm_T data) {
|
|
/***********************************
|
|
* hash function applied to data *
|
|
***********************************/
|
|
char *p = data->name;
|
|
unsigned int hval = strlen(p);
|
|
|
|
while(*p)
|
|
{
|
|
hval += tolower(*p);
|
|
p++;
|
|
}
|
|
|
|
return (hval % (MAX_BITMAPS/2));
|
|
}
|
|
bm_Node *bm_insertNode(bm_T data)
|
|
{
|
|
bm_Node *p, *p0;
|
|
bm_hashTableIndex bucket;
|
|
/************************************************
|
|
* allocate bm_Node for data and insert in table *
|
|
************************************************/
|
|
/* insert bm_Node at beginning of list */
|
|
bucket = bm_hash(data);
|
|
if ((p = (bm_Node *)mem_malloc(sizeof(bm_Node))) == 0) {
|
|
exit(1);
|
|
}
|
|
p0 = bm_hashTable[bucket];
|
|
bm_hashTable[bucket] = p;
|
|
p->next = p0;
|
|
p->data = data;
|
|
return p;
|
|
}
|
|
void bm_deleteNode(bm_T data)
|
|
{
|
|
bm_Node *p0, *p;
|
|
bm_hashTableIndex bucket;
|
|
/********************************************
|
|
* delete bm_Node containing data from table *
|
|
********************************************/
|
|
/* find bm_Node */
|
|
p0 = 0;
|
|
bucket = bm_hash(data);
|
|
p = bm_hashTable[bucket];
|
|
while (p && !compEQ(p->data, data)) {
|
|
p0 = p;
|
|
p = p->next;
|
|
}
|
|
if (!p) return;
|
|
/* p designates bm_Node to delete, remove it from list */
|
|
if (p0)
|
|
/* not first bm_Node, p0 points to previous bm_Node */
|
|
p0->next = p->next;
|
|
else
|
|
/* first bm_Node on chain */
|
|
bm_hashTable[bucket] = p->next;
|
|
mem_free (p);
|
|
}
|
|
bm_Node *bm_findNode (bm_T data)
|
|
{
|
|
bm_Node *p;
|
|
if(!bm_hashTable)
|
|
return NULL;
|
|
/*******************************
|
|
* find bm_Node containing data *
|
|
*******************************/
|
|
p = bm_hashTable[bm_hash(data)];
|
|
while (p && !compEQ(p->data, data))
|
|
p = p->next;
|
|
return p;
|
|
}
|
|
// simply frees up a bitmap
|
|
void bm_FreeBitmapMain(int handle);
|
|
// Sets all the bitmaps to unused
|
|
void bm_InitBitmaps()
|
|
{
|
|
int i,ret;
|
|
bm_InitHashTable();
|
|
Bitmaps_initted=1;
|
|
for (i=0;i<MAX_BITMAPS;i++)
|
|
{
|
|
GameBitmaps[i].used=0;
|
|
GameBitmaps[i].data16=NULL;
|
|
GameBitmaps[i].format=BITMAP_FORMAT_STANDARD;
|
|
GameBitmaps[i].cache_slot=-1;
|
|
GameBitmaps[i].flags=0;
|
|
}
|
|
int bm=bm_AllocBitmap (128,128,0);
|
|
ASSERT (bm==BAD_BITMAP_HANDLE);
|
|
if (cfexist(".\\error1.ogf"))
|
|
ret=bm_AllocLoadFileBitmap (".\\error1.ogf",0);
|
|
else
|
|
ret=-1;
|
|
if (ret==-1)
|
|
bm_MakeBad (bm);
|
|
else
|
|
{
|
|
bm_ScaleBitmapToBitmap (bm,ret);
|
|
bm_FreeBitmap (ret);
|
|
}
|
|
|
|
//bm_GenerateMipMaps (bm);
|
|
atexit (bm_ShutdownBitmaps);
|
|
// Initialize lightmaps and bumpmaps
|
|
lm_InitLightmaps();
|
|
bump_InitBumpmaps();
|
|
}
|
|
void bm_ShutdownBitmaps (void)
|
|
{
|
|
int i;
|
|
mprintf ((0,"Freeing all bitmap memory.\n"));
|
|
bm_FreeBitmapMain(0);
|
|
for (i=0;i<MAX_BITMAPS;i++)
|
|
{
|
|
while (GameBitmaps[i].used>0)
|
|
bm_FreeBitmap (i);
|
|
}
|
|
bm_DeleteHashTable();
|
|
|
|
}
|
|
int bm_AllocateMemoryForIndex(int n,int w,int h,int add_mem)
|
|
{
|
|
// If no go on the malloc, bail out with -1
|
|
|
|
int size = (w*h*2)+(add_mem)+2;
|
|
GameBitmaps[n].data16=(ushort *)mem_malloc (size);
|
|
if (!GameBitmaps[n].data16)
|
|
{
|
|
Int3(); // Ran out of memory!
|
|
return -1;
|
|
}
|
|
Bitmap_memory_used+=(size);
|
|
memset(GameBitmaps[n].data16,0xAA,size);
|
|
|
|
GameBitmaps[n].format=BITMAP_FORMAT_STANDARD;
|
|
GameBitmaps[n].width=w;
|
|
GameBitmaps[n].height=h;
|
|
GameBitmaps[n].flags=BF_CHANGED|BF_BRAND_NEW;
|
|
|
|
#ifdef USE_OPENGL
|
|
for(int tmp=w;tmp>0;tmp=tmp>>1)
|
|
GameBitmaps[n].mip_levels++;
|
|
#else
|
|
GameBitmaps[n].mip_levels = NUM_MIP_LEVELS;
|
|
#endif
|
|
|
|
Num_of_bitmaps++;
|
|
return n;
|
|
}
|
|
// Allocs a bitmap of w x h size
|
|
// If add_mem is nonzero, adds that to the amount alloced
|
|
// Returns bitmap handle if successful, -1 if otherwise
|
|
int bm_AllocBitmap (int w,int h,int add_mem)
|
|
{
|
|
int n,i;
|
|
if (!Bitmaps_initted)
|
|
{
|
|
Int3();
|
|
mprintf ((0,"Bitmaps not initted!!!\n"));
|
|
return -1;
|
|
}
|
|
|
|
for (i=0;i<MAX_BITMAPS;i++)
|
|
{
|
|
if (GameBitmaps[i].used==0)
|
|
{
|
|
n=i;
|
|
break;
|
|
}
|
|
}
|
|
// If we can't find a free slot in which to alloc, bail out
|
|
if (i==MAX_BITMAPS)
|
|
{
|
|
#ifdef MACINTOSH
|
|
Error("Couldn't find a free bitmap to alloc!\n");
|
|
#else
|
|
Int3();
|
|
mprintf ((0,"ERROR! Couldn't find a free bitmap to alloc!\n"));
|
|
return -1;
|
|
#endif
|
|
}
|
|
memset (&GameBitmaps[n],0,sizeof(bms_bitmap));
|
|
int ret=bm_AllocateMemoryForIndex (n,w,h,add_mem);
|
|
if (ret>=0)
|
|
{
|
|
GameBitmaps[n].used=1;
|
|
GameBitmaps[n].cache_slot=-1;
|
|
}
|
|
return ret;
|
|
}
|
|
// Just like bm_AllocBitmap but doesn't actually allocate memory. Useful for paging!
|
|
int bm_AllocNoMemBitmap (int w,int h)
|
|
{
|
|
int n,i;
|
|
if (!Bitmaps_initted)
|
|
{
|
|
Int3();
|
|
mprintf ((0,"Bitmaps not initted!!!\n"));
|
|
return -1;
|
|
}
|
|
|
|
for (i=0;i<MAX_BITMAPS;i++)
|
|
{
|
|
if (GameBitmaps[i].used==0)
|
|
{
|
|
n=i;
|
|
break;
|
|
}
|
|
}
|
|
// If we can't find a free slot in which to alloc, bail out
|
|
if (i==MAX_BITMAPS)
|
|
{
|
|
#ifdef MACINTOSH
|
|
Error("Couldn't find a free bitmap to alloc!\n");
|
|
#else
|
|
Int3();
|
|
mprintf ((0,"ERROR! Couldn't find a free bitmap to alloc!\n"));
|
|
return -1;
|
|
#endif
|
|
}
|
|
// If no go on the malloc, bail out with -1
|
|
|
|
memset (&GameBitmaps[n],0,sizeof(bms_bitmap));
|
|
|
|
GameBitmaps[n].width=w;
|
|
GameBitmaps[n].height=h;
|
|
GameBitmaps[n].used=1;
|
|
GameBitmaps[n].format=BITMAP_FORMAT_STANDARD;
|
|
GameBitmaps[n].flags=BF_NOT_RESIDENT|BF_CHANGED|BF_BRAND_NEW;
|
|
GameBitmaps[n].cache_slot=-1;
|
|
|
|
Num_of_bitmaps++;
|
|
return n;
|
|
}
|
|
// Searches thru all bitmaps for a specific name, returns -1 if not found
|
|
// or index of bitmap with name
|
|
int bm_FindBitmapName (const char *name)
|
|
{
|
|
int num_counted=0;
|
|
|
|
bms_bitmap fbmp;
|
|
strcpy(fbmp.name,name);
|
|
bm_Node * fnode = bm_findNode (&fbmp);
|
|
if(fnode)
|
|
{
|
|
//mprintf((0,"Hash table found bitmap %d\n",fnode->data - GameBitmaps));
|
|
return fnode->data - GameBitmaps;
|
|
}
|
|
else
|
|
return -1;
|
|
/*
|
|
for (i=0;i<MAX_BITMAPS && num_counted<Num_of_bitmaps;i++)
|
|
{
|
|
if (GameBitmaps[i].used)
|
|
{
|
|
num_counted++;
|
|
if(!stricmp (GameBitmaps[i].name,name))
|
|
return i;
|
|
}
|
|
}
|
|
*/
|
|
return -1;
|
|
}
|
|
// Given a handle, frees the bitmap memory and flags this bitmap as unused
|
|
void bm_FreeBitmap (int handle)
|
|
{
|
|
if (!Bitmaps_initted)
|
|
{
|
|
Int3();
|
|
mprintf ((0,"Bitmaps not initted!!!\n"));
|
|
return;
|
|
}
|
|
if (handle == BAD_BITMAP_HANDLE)
|
|
return;
|
|
if (GameBitmaps[handle].used<1)
|
|
return;
|
|
GameBitmaps[handle].used--;
|
|
if (GameBitmaps[handle].used==0)
|
|
{
|
|
bm_FreeBitmapMain(handle);
|
|
}
|
|
}
|
|
// simply frees up a bitmap
|
|
void bm_FreeBitmapData(int handle)
|
|
{
|
|
if (GameBitmaps[handle].data16!=NULL && !(GameBitmaps[handle].flags & BF_NOT_RESIDENT))
|
|
{
|
|
if (!(GameBitmaps[handle].flags & BF_NOT_RESIDENT))
|
|
{
|
|
int mem_used=(GameBitmaps[handle].width*GameBitmaps[handle].height*2);
|
|
Bitmap_memory_used-=mem_used;
|
|
if (GameBitmaps[handle].flags & BF_MIPMAPPED)
|
|
Bitmap_memory_used-=(mem_used/3);
|
|
}
|
|
mem_free (GameBitmaps[handle].data16);
|
|
}
|
|
GameBitmaps[handle].cache_slot=-1;
|
|
GameBitmaps[handle].flags|=BF_NOT_RESIDENT;
|
|
if (GameBitmaps[handle].flags & BF_MIPMAPPED)
|
|
GameBitmaps[handle].flags|=BF_WANTS_MIP;
|
|
GameBitmaps[handle].data16=NULL;
|
|
}
|
|
// simply frees up a bitmap
|
|
void bm_FreeBitmapMain(int handle)
|
|
{
|
|
bm_deleteNode(&GameBitmaps[handle]);
|
|
bm_FreeBitmapData (handle);
|
|
GameBitmaps[handle].data16=NULL;
|
|
GameBitmaps[handle].cache_slot=-1;
|
|
GameBitmaps[handle].used=0;
|
|
Num_of_bitmaps--;
|
|
}
|
|
// Returns -1 if this name is not already in use, else index of bitmap that is using name
|
|
int bm_TestName (const char *src)
|
|
{
|
|
unsigned int i,limit;
|
|
|
|
char namedest[256];
|
|
char path[256],ext[256],filename[256];
|
|
|
|
ddio_SplitPath (src,path,filename,ext);
|
|
limit=BITMAP_NAME_LEN-7;
|
|
// Make sure we don't go over our name length limit
|
|
strncpy (namedest,filename,limit);
|
|
namedest[limit]=0;
|
|
|
|
int cur_len=strlen (namedest);
|
|
|
|
// Now, make sure there are no other bitmaps with this name
|
|
strcat (namedest,".ogf");
|
|
if ( (i=bm_FindBitmapName(namedest))==-1)
|
|
return -1;
|
|
return i;
|
|
}
|
|
// gets the filename from a path, plus appends our .ogf extension
|
|
void bm_ChangeEndName (const char *src,char *dest)
|
|
{
|
|
unsigned int i,limit;
|
|
int last=-1;
|
|
int curnum=-1;
|
|
char namedest[256];
|
|
char path[256],ext[256],filename[256];
|
|
|
|
ddio_SplitPath (src,path,filename,ext);
|
|
limit=BITMAP_NAME_LEN-7;
|
|
// Make sure we don't go over our name length limit
|
|
strncpy (filename,filename,limit);
|
|
filename[limit]=0;
|
|
Start:
|
|
if (curnum!=-1)
|
|
sprintf (namedest,"%s%d",filename,curnum);
|
|
else
|
|
strcpy (namedest,filename);
|
|
// Now, make sure there are no other bitmaps with this name
|
|
strcat (namedest,".ogf");
|
|
if ((i=bm_FindBitmapName(namedest))!=-1)
|
|
{
|
|
curnum++;
|
|
// This name is already taken. Try same name with different number
|
|
// appended
|
|
goto Start;
|
|
}
|
|
strcpy (dest,namedest);
|
|
|
|
}
|
|
// Checks to see if this file is a kind we can read
|
|
int bm_GetFileType (CFILE *infile,const char *dest)
|
|
{
|
|
char iffcheck[4];
|
|
int i;
|
|
// First, check if its a pcx
|
|
i=strlen (dest);
|
|
if (dest[i-4]=='.' && (dest[i-3]=='p' || dest[i-3]=='P') && (dest[i-2]=='c' || dest[i-2]=='C') && (dest[i-1]=='x' || dest[i-1]=='X'))
|
|
return BM_FILETYPE_PCX;
|
|
// How about an IFF?
|
|
for (i=0;i<4;i++)
|
|
iffcheck[i]=cf_ReadByte (infile);
|
|
cfseek (infile,0,SEEK_SET);
|
|
if (!strncmp ("FORM",iffcheck,4))
|
|
return BM_FILETYPE_IFF;
|
|
// Lastly, just default to possible TGA or OGF
|
|
return BM_FILETYPE_TGA;
|
|
}
|
|
// Allocs and loads a bitmap
|
|
// Returns the handle of the loaded bitmap
|
|
// Returns -1 if something is wrong
|
|
// If mipped is non-zero, allocs extra space for mips and computes them
|
|
int bm_AllocLoadFileBitmap (const char *fname,int mipped,int format)
|
|
{
|
|
CFILE *infile;
|
|
if (!Bitmaps_initted)
|
|
{
|
|
Int3();
|
|
mprintf ((0,"Bitmaps not initted!!!\n"));
|
|
return -1;
|
|
}
|
|
|
|
char name[BITMAP_NAME_LEN];
|
|
int n,src_bm;
|
|
int old_used;
|
|
int overlay=0;
|
|
|
|
char *filename = (char *)fname;
|
|
|
|
// due to a bug in some people's tablefile editors, we got to make sure there is
|
|
// no path if there shouldn't be
|
|
if(!cfexist(filename))
|
|
{
|
|
// generate a possible new filename
|
|
char *end_ptr,*start_ptr;
|
|
start_ptr = (char *) fname;
|
|
end_ptr = start_ptr + strlen(start_ptr) - 1;
|
|
while( (end_ptr >= start_ptr) && (*end_ptr!='\\') ) end_ptr--;
|
|
if(end_ptr < start_ptr)
|
|
{
|
|
mprintf((0,"Unable to find bitmap %s\n",fname));
|
|
return -1;
|
|
}
|
|
ASSERT(*end_ptr=='\\');
|
|
end_ptr++;
|
|
filename = end_ptr;
|
|
mprintf((0,"Couldn't find %s, so gonna try %s\n",fname,filename));
|
|
}
|
|
|
|
// Check to see if this bitmap is already in memory, if so, just return that
|
|
// bitmaps handle
|
|
if ((n=bm_TestName(filename))!=-1)
|
|
{
|
|
mprintf ((1,"Found duplicate bitmap %s.\n",GameBitmaps[n].name));
|
|
old_used=GameBitmaps[n].used;
|
|
GameBitmaps[n].used=1;
|
|
bm_FreeBitmap (n);
|
|
GameBitmaps[n].used=old_used+1;
|
|
|
|
overlay=1;
|
|
}
|
|
if (!overlay)
|
|
bm_ChangeEndName (filename,name);
|
|
else
|
|
{
|
|
strcpy (name,GameBitmaps[n].name);
|
|
}
|
|
if (strlen(name)>33)
|
|
{
|
|
mprintf ((0,"ERROR!! This bitmaps name is too long, try shortening it and retry!\n"));
|
|
return -1;
|
|
}
|
|
// Try to open the file. If we can't load it from the network if possible
|
|
infile=(CFILE *)cfopen (filename,"rb");
|
|
if( !infile)
|
|
{
|
|
mprintf ((0,"bm_AllocLoadFileBitmap: Can't open file named %s.\n",filename));
|
|
|
|
return BAD_BITMAP_HANDLE; // return the bad texture
|
|
|
|
}
|
|
// Check to see if this is IFF. If so, call the IFF reader. If not,
|
|
// rewind the file and read as a TGA
|
|
|
|
int filetype=bm_GetFileType (infile,filename);
|
|
|
|
switch (filetype)
|
|
{
|
|
case BM_FILETYPE_IFF:
|
|
src_bm=bm_iff_alloc_file(infile);
|
|
break;
|
|
case BM_FILETYPE_TGA:
|
|
// reads a tga or an outrage graphics file (ogf)
|
|
src_bm=bm_tga_alloc_file(infile,name,format);
|
|
break;
|
|
case BM_FILETYPE_PCX:
|
|
src_bm=bm_pcx_alloc_file(infile);
|
|
break;
|
|
default:
|
|
Int3(); // Can't read this type
|
|
break;
|
|
}
|
|
cfclose (infile);
|
|
if (src_bm<0)
|
|
{
|
|
mprintf ((0,"Couldn't load %s.",filename));
|
|
return -1;
|
|
}
|
|
|
|
// Allocate space for our bitmap.
|
|
if (mipped)
|
|
{
|
|
if ((bm_mipped(src_bm))==0) // If we want a mipped but we don't have one
|
|
{
|
|
int w=bm_w(src_bm,0);
|
|
int h=bm_h(src_bm,0);
|
|
|
|
if (overlay)
|
|
{
|
|
bm_AllocateMemoryForIndex (n,w,h,mipped*(((w*h*2)/3)));
|
|
GameBitmaps[n].format=GameBitmaps[src_bm].format;
|
|
}
|
|
else
|
|
{
|
|
n=bm_AllocBitmap (w,h,mipped*(((w*h*2)/3)));
|
|
GameBitmaps[n].format=GameBitmaps[src_bm].format;
|
|
}
|
|
|
|
ASSERT (n>=0);
|
|
bm_ScaleBitmapToBitmap (n,src_bm);
|
|
bm_FreeBitmap (src_bm);
|
|
|
|
bm_GenerateMipMaps (n);
|
|
}
|
|
else
|
|
{
|
|
if (!overlay)
|
|
n=src_bm;
|
|
else
|
|
{
|
|
int w=bm_w(src_bm,0);
|
|
int h=bm_h(src_bm,0);
|
|
bm_AllocateMemoryForIndex (n,w,h,mipped*(((w*h*2)/3)));
|
|
GameBitmaps[n].flags|=BF_MIPMAPPED;
|
|
GameBitmaps[n].format=GameBitmaps[src_bm].format;
|
|
bm_ScaleBitmapToBitmap (n,src_bm);
|
|
bm_FreeBitmap (src_bm);
|
|
}
|
|
}
|
|
}
|
|
else // If we don't want a mipped
|
|
{
|
|
if ((bm_mipped(src_bm))==0)
|
|
{
|
|
if (!overlay)
|
|
n=src_bm;
|
|
else
|
|
{
|
|
int w=bm_w(src_bm,0);
|
|
int h=bm_h(src_bm,0);
|
|
bm_AllocateMemoryForIndex (n,w,h,mipped*(((w*h*2)/3)));
|
|
GameBitmaps[n].format=GameBitmaps[src_bm].format;
|
|
bm_ScaleBitmapToBitmap (n,src_bm);
|
|
bm_FreeBitmap (src_bm);
|
|
}
|
|
}
|
|
else // And this is already mipped
|
|
{
|
|
int w=bm_w(src_bm,0);
|
|
int h=bm_h(src_bm,0);
|
|
ushort *src_data,*dest_data;
|
|
|
|
if (overlay)
|
|
{
|
|
bm_AllocateMemoryForIndex (n,w,h,mipped*(((w*h*2)/3)));
|
|
GameBitmaps[n].format=GameBitmaps[src_bm].format;
|
|
}
|
|
else
|
|
{
|
|
n=bm_AllocBitmap (w,h,mipped*(((w*h*2)/3)));
|
|
GameBitmaps[n].format=GameBitmaps[src_bm].format;
|
|
}
|
|
ASSERT (n>=0);
|
|
src_data=(ushort *)bm_data(src_bm,0);
|
|
dest_data=(ushort *)bm_data(n,0);
|
|
memcpy (dest_data,src_data,w*h*2);
|
|
|
|
bm_FreeBitmap (src_bm);
|
|
}
|
|
}
|
|
|
|
strcpy (GameBitmaps[n].name,name);
|
|
|
|
|
|
//Insert into the hash table!
|
|
bm_insertNode(&GameBitmaps[n]);
|
|
return n; // We made it!
|
|
}
|
|
// Allocs and loads a bitmap but doesn't actually load texel data!
|
|
// Returns the handle of the loaded bitmap
|
|
// Returns -1 if something is wrong
|
|
/*
|
|
int bm_AllocLoadFileNoMemBitmap (char *fname,int mipped)
|
|
{
|
|
CFILE *infile;
|
|
if (!Bitmaps_initted)
|
|
{
|
|
Int3();
|
|
mprintf ((0,"Bitmaps not initted!!!\n"));
|
|
return -1;
|
|
}
|
|
|
|
char *filename,name[BITMAP_NAME_LEN];
|
|
int n,src_bm;
|
|
|
|
filename = fname;
|
|
|
|
// due to a bug in some people's tablefile editors, we got to make sure there is
|
|
// no path if there shouldn't be
|
|
if(!cfexist(filename))
|
|
{
|
|
// generate a possible new filename
|
|
char *end_ptr,*start_ptr;
|
|
start_ptr = fname;
|
|
end_ptr = start_ptr + strlen(start_ptr) - 1;
|
|
while( (end_ptr >= start_ptr) && (*end_ptr!='\\') ) end_ptr--;
|
|
if(end_ptr < start_ptr)
|
|
{
|
|
mprintf((0,"Unable to find bitmap %s\n",fname));
|
|
return -1;
|
|
}
|
|
ASSERT(*end_ptr=='\\');
|
|
end_ptr++;
|
|
filename = end_ptr;
|
|
mprintf((0,"Couldn't find %s, so gonna try %s\n",fname,filename));
|
|
}
|
|
|
|
|
|
// Check to see if this bitmap is already in memory, if so, just return that
|
|
// bitmaps handle
|
|
if ((n=bm_TestName(filename))!=-1)
|
|
{
|
|
GameBitmaps[n].used++;
|
|
mprintf ((0,"Found duplicate bitmap %s.\n",GameBitmaps[n].name));
|
|
return n;
|
|
}
|
|
|
|
bm_ChangeEndName (filename,name);
|
|
if (strlen(name)>33)
|
|
{
|
|
mprintf ((0,"ERROR!! This bitmaps name is too long, try shortening it and retry!\n"));
|
|
return -1;
|
|
}
|
|
// Try to open the file. If we can't load it from the network if possible
|
|
infile=(CFILE *)cfopen (filename,"rb");
|
|
if( !infile)
|
|
{
|
|
mprintf ((0,"bm_AllocLoadFileBitmap: Can't open file named %s.\n",filename));
|
|
|
|
#ifdef _DEBUG
|
|
return BAD_BITMAP_HANDLE; // return the bad texture
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
// Check to see if this is IFF. If so, call the IFF reader. If not,
|
|
// rewind the file and read as a TGA
|
|
|
|
int filetype=bm_GetFileType (infile,filename);
|
|
|
|
switch (filetype)
|
|
{
|
|
case BM_FILETYPE_TGA:
|
|
// reads a tga or an outrage graphics file (ogf)
|
|
src_bm=bm_tga_load_short_file(infile,name);
|
|
break;
|
|
default:
|
|
Int3(); // Can't read this type
|
|
break;
|
|
}
|
|
cfclose (infile);
|
|
if (src_bm<0)
|
|
{
|
|
mprintf ((0,"Couldn't load %s.",filename));
|
|
return -1;
|
|
}
|
|
|
|
return src_bm; // We made it!
|
|
}*/
|
|
// Allocs and loads a bitmap but doesn't actually load texel data!
|
|
// Returns the handle of the loaded bitmap
|
|
// Returns -1 if something is wrong
|
|
int bm_AllocLoadFileNoMemBitmap (const char *fname,int mipped,int format)
|
|
{
|
|
if (!Bitmaps_initted)
|
|
{
|
|
Int3();
|
|
mprintf ((0,"Bitmaps not initted!!!\n"));
|
|
return -1;
|
|
}
|
|
|
|
char name[BITMAP_NAME_LEN];
|
|
int n;
|
|
char *filename = (char *)fname;
|
|
|
|
// due to a bug in some people's tablefile editors, we got to make sure there is
|
|
// no path if there shouldn't be
|
|
if(!cfexist(filename))
|
|
{
|
|
// generate a possible new filename
|
|
char *end_ptr,*start_ptr;
|
|
start_ptr = (char *) fname;
|
|
end_ptr = start_ptr + strlen(start_ptr) - 1;
|
|
while( (end_ptr >= start_ptr) && (*end_ptr!='\\') ) end_ptr--;
|
|
if(end_ptr < start_ptr)
|
|
{
|
|
mprintf((0,"Unable to find bitmap %s\n",fname));
|
|
return -1;
|
|
}
|
|
ASSERT(*end_ptr=='\\');
|
|
end_ptr++;
|
|
filename = end_ptr;
|
|
mprintf((0,"Couldn't find %s, so gonna try %s\n",fname,filename));
|
|
}
|
|
|
|
// Check to see if this bitmap is already in memory, if so, just return that
|
|
// bitmaps handle
|
|
if ((n=bm_TestName(filename))!=-1)
|
|
{
|
|
GameBitmaps[n].used++;
|
|
mprintf ((1,"Found duplicate bitmap %s.\n",GameBitmaps[n].name));
|
|
return n;
|
|
}
|
|
|
|
bm_ChangeEndName (filename,name);
|
|
if (strlen(name)>33)
|
|
{
|
|
mprintf ((0,"ERROR!! This bitmaps name is too long, try shortening it and retry!\n"));
|
|
return -1;
|
|
}
|
|
n=bm_AllocNoMemBitmap (1,1);
|
|
strcpy (GameBitmaps[n].name,name);
|
|
if (mipped)
|
|
GameBitmaps[n].flags |=BF_WANTS_MIP;
|
|
if (format==BITMAP_FORMAT_4444)
|
|
GameBitmaps[n].flags |=BF_WANTS_4444;
|
|
|
|
return n; // We made it!
|
|
}
|
|
// Allocs and loads a bitmap from an open file
|
|
// Returns the handle of the loaded bitmap
|
|
// Returns -1 if something is wrong
|
|
// If mipped is non-zero, allocs extra space for mips and computes them
|
|
int bm_AllocLoadBitmap (CFILE *infile,int mipped,int format)
|
|
{
|
|
char name[BITMAP_NAME_LEN];
|
|
int n,src_bm;
|
|
if (!Bitmaps_initted)
|
|
{
|
|
Int3();
|
|
mprintf ((0,"Bitmaps not initted!!!\n"));
|
|
return -1;
|
|
}
|
|
|
|
// Assume this is an ogf
|
|
|
|
src_bm=bm_tga_alloc_file(infile,name,format);
|
|
if (src_bm<0)
|
|
{
|
|
mprintf ((0,"Couldn't load %s.",name));
|
|
return -1;
|
|
}
|
|
|
|
// Allocate space for our bitmap
|
|
if (mipped)
|
|
{
|
|
if ((bm_mipped(src_bm))==0) // If we want a mipped but we don't have one
|
|
{
|
|
int w=bm_w(src_bm,0);
|
|
int h=bm_h(src_bm,0);
|
|
|
|
n=bm_AllocBitmap (w,h,mipped*(((w*h*2)/3)));
|
|
|
|
ASSERT (n>=0);
|
|
GameBitmaps[n].format=GameBitmaps[src_bm].format;
|
|
bm_ScaleBitmapToBitmap (n,src_bm);
|
|
bm_FreeBitmap (src_bm);
|
|
|
|
bm_GenerateMipMaps (n);
|
|
}
|
|
else
|
|
n=src_bm;
|
|
}
|
|
else // If we don't want a mipped
|
|
{
|
|
if ((bm_mipped(src_bm))==0)
|
|
n=src_bm;
|
|
else // And this is already mipped
|
|
{
|
|
int w=bm_w(src_bm,0);
|
|
int h=bm_h(src_bm,0);
|
|
ushort *src_data,*dest_data;
|
|
|
|
n=bm_AllocBitmap (w,h,mipped*(((w*h*2)/3)));
|
|
ASSERT (n>=0);
|
|
src_data=(ushort *)bm_data(src_bm,0);
|
|
dest_data=(ushort *)bm_data(n,0);
|
|
memcpy (dest_data,src_data,w*h*2);
|
|
|
|
bm_FreeBitmap (src_bm);
|
|
}
|
|
}
|
|
strcpy (GameBitmaps[n].name,name);
|
|
return n; // We made it!
|
|
}
|
|
// Given a handle, makes a big random shape to let you know you are screwed.
|
|
void bm_MakeBad (int handle)
|
|
{
|
|
int i,t,limit;
|
|
ushort *dest;
|
|
ASSERT (GameBitmaps[handle].used);
|
|
if (handle!=BAD_BITMAP_HANDLE)
|
|
Int3(); // hmm, you're assigning a random bitmap to something other than
|
|
// the default.
|
|
if (bm_mipped(handle))
|
|
limit=bm_miplevels(handle);
|
|
else
|
|
limit=1;
|
|
for (i=0;i<limit;i++)
|
|
{
|
|
dest=bm_data (handle,i);
|
|
|
|
for (t=0;t<bm_h(handle,i)*bm_w(handle,i);t++)
|
|
*dest++=(OPAQUE_FLAG|ps_rand());
|
|
}
|
|
}
|
|
|
|
// Saves a bitmap to an open file. Saves the bitmap as an OUTRAGE_COMPRESSED_OGF.
|
|
// Returns -1 if something is wrong.
|
|
int bm_SaveBitmap (CFILE *fp,int handle)
|
|
{
|
|
ubyte dumbbyte=0,image_type=OUTRAGE_1555_COMPRESSED_MIPPED,pixsize=32,desc=8+32;
|
|
int i,done=0;
|
|
int num_mips;
|
|
mprintf ((0,"Saving bitmap %s...\n",GameBitmaps[handle].name));
|
|
if (!GameBitmaps[handle].used)
|
|
{
|
|
mprintf ((0,"bm_SaveBitmap: Trying to save a bitmap that isn't used!\n"));
|
|
Int3();
|
|
return -1;
|
|
}
|
|
if (handle==BAD_BITMAP_HANDLE)
|
|
{
|
|
Int3(); // Hey, you shouldn't be saving this bitmap!
|
|
return -1;
|
|
}
|
|
if (GameBitmaps[handle].format==BITMAP_FORMAT_4444)
|
|
image_type=OUTRAGE_4444_COMPRESSED_MIPPED;
|
|
if (!fp)
|
|
{
|
|
mprintf ((0,"bm_SaveBitmap: Trying to save a bitmap to a closed file!\n"));
|
|
Int3();
|
|
return -1;
|
|
}
|
|
cf_WriteByte (fp,dumbbyte);
|
|
cf_WriteByte (fp,dumbbyte);
|
|
cf_WriteByte (fp,image_type);
|
|
cf_WriteString (fp,GameBitmaps[handle].name);
|
|
|
|
if ((bm_mipped(handle)))
|
|
num_mips=bm_miplevels(handle);
|
|
else
|
|
num_mips=1;
|
|
cf_WriteByte (fp,num_mips);
|
|
for (i=0;i<9;i++)
|
|
cf_WriteByte (fp,0);
|
|
cf_WriteShort (fp,GameBitmaps[handle].width);
|
|
cf_WriteShort (fp,GameBitmaps[handle].height);
|
|
cf_WriteByte (fp,pixsize);
|
|
cf_WriteByte (fp,desc);
|
|
|
|
|
|
// write compressed info
|
|
for (int m=0;m<num_mips;m++)
|
|
{
|
|
int curptr=0;
|
|
int total=bm_w(handle,m)*bm_h(handle,m);
|
|
ushort *src_data=(ushort *)bm_data(handle,m);
|
|
done=0;
|
|
while (!done)
|
|
{
|
|
if (curptr==total)
|
|
{
|
|
done=1;
|
|
continue;
|
|
}
|
|
ASSERT (curptr<total);
|
|
ushort curpix=src_data[curptr];
|
|
ubyte count=1;
|
|
while (src_data[curptr+count]==curpix && count<250 && (curptr+count)<total)
|
|
count++;
|
|
if (count==1)
|
|
{
|
|
cf_WriteByte (fp,0);
|
|
cf_WriteShort (fp,curpix);
|
|
}
|
|
else
|
|
{
|
|
cf_WriteByte (fp,count);
|
|
cf_WriteShort (fp,curpix);
|
|
}
|
|
curptr+=count;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
// Makes sure a bitmap is in memory...if not it attempts to page it in
|
|
int bm_MakeBitmapResident (int handle)
|
|
{
|
|
if (GameBitmaps[handle].flags & BF_NOT_RESIDENT)
|
|
{
|
|
if (bm_page_in_file (handle) > 0) //DAJ -1FIX
|
|
{
|
|
GameBitmaps[handle].flags&=~BF_NOT_RESIDENT;
|
|
GameBitmaps[handle].flags|=BF_CHANGED|BF_BRAND_NEW;
|
|
}
|
|
else
|
|
{
|
|
mprintf ((0,"Error paging in bitmap %s!\n",GameBitmaps[handle].name));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
// Saves a bitmap to a file. Saves the bitmap as an OUTRAGE_COMPRESSED_OGF.
|
|
// Returns -1 if something is wrong.
|
|
int bm_SaveFileBitmap (const char *filename,int handle)
|
|
{
|
|
int ret;
|
|
CFILE *fp;
|
|
if (!GameBitmaps[handle].used)
|
|
{
|
|
mprintf ((0,"bm_SaveBitmap: Trying to save a bitmap that isn't used!\n"));
|
|
Int3();
|
|
return -1;
|
|
}
|
|
if (handle==BAD_BITMAP_HANDLE)
|
|
{
|
|
Int3(); // Hey, you shouldn't be saving this bitmap!
|
|
return -1;
|
|
}
|
|
if (!bm_MakeBitmapResident(handle))
|
|
{
|
|
mprintf ((0,"There was a problem paging this bitmap in!\n"));
|
|
return -1;
|
|
}
|
|
fp=(CFILE *)cfopen (filename,"wb");
|
|
|
|
if (!fp)
|
|
{
|
|
mprintf ((0,"bm_SaveBitmap: Trying to save a bitmap to a closed file!\n"));
|
|
Int3();
|
|
return -1;
|
|
}
|
|
ret=bm_SaveBitmap (fp,handle);
|
|
|
|
cfclose (fp);
|
|
return ret;
|
|
}
|
|
// returns a bitmaps width (based on miplevel), else -1 if something is wrong
|
|
int bm_w (int handle,int miplevel)
|
|
{
|
|
int w;
|
|
if (!GameBitmaps[handle].used)
|
|
{
|
|
Int3();
|
|
return -1;
|
|
}
|
|
if (GameBitmaps[handle].flags & BF_NOT_RESIDENT)
|
|
if (!bm_MakeBitmapResident(handle))
|
|
return NULL;
|
|
if (!(GameBitmaps[handle].flags & BF_MIPMAPPED))
|
|
miplevel=0;
|
|
w=GameBitmaps[handle].width;
|
|
w>>=miplevel;
|
|
return (w);
|
|
}
|
|
// returns a bitmaps height (based on miplevel), else -1 if something is wrong
|
|
int bm_h (int handle,int miplevel)
|
|
{
|
|
int h;
|
|
if (!GameBitmaps[handle].used)
|
|
{
|
|
Int3();
|
|
return -1;
|
|
}
|
|
// If this bitmap is not page in, do so!
|
|
if (GameBitmaps[handle].flags & BF_NOT_RESIDENT)
|
|
if (!bm_MakeBitmapResident(handle))
|
|
return NULL;
|
|
if (!(GameBitmaps[handle].flags & BF_MIPMAPPED))
|
|
miplevel=0;
|
|
h=GameBitmaps[handle].height;
|
|
h>>=miplevel;
|
|
return (h);
|
|
}
|
|
|
|
// returns the number of levels of mips a bitmap should have
|
|
int bm_miplevels (int handle)
|
|
{
|
|
int levels = 0;
|
|
if (!GameBitmaps[handle].used)
|
|
{
|
|
Int3();
|
|
return -1;
|
|
}
|
|
if(GameBitmaps[handle].mip_levels)
|
|
return GameBitmaps[handle].mip_levels;
|
|
|
|
// If this bitmap is not page in, do so!
|
|
if (GameBitmaps[handle].flags & BF_NOT_RESIDENT)
|
|
if (!bm_MakeBitmapResident(handle))
|
|
return NULL;
|
|
if (GameBitmaps[handle].flags & BF_MIPMAPPED) {
|
|
for(int tmp = GameBitmaps[handle].width; tmp > 0; tmp = tmp >> 1) {
|
|
levels++;
|
|
}
|
|
return levels;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// returns a bitmaps mipped status, else -1 if something is wrong
|
|
int bm_mipped (int handle)
|
|
{
|
|
if (!GameBitmaps[handle].used)
|
|
{
|
|
Int3();
|
|
return -1;
|
|
}
|
|
// If this bitmap is not page in, do so!
|
|
if (GameBitmaps[handle].flags & BF_NOT_RESIDENT)
|
|
if (!bm_MakeBitmapResident(handle))
|
|
return NULL;
|
|
if (GameBitmaps[handle].flags & BF_MIPMAPPED)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
// returns a bitmaps data (based on given miplevel), else NULL if something is wrong
|
|
ushort *bm_data (int handle,int miplevel)
|
|
{
|
|
ushort *d;
|
|
int i;
|
|
if (!GameBitmaps[handle].used)
|
|
{
|
|
Int3();
|
|
return NULL;
|
|
}
|
|
|
|
// If this bitmap is not page in, do so!
|
|
if (GameBitmaps[handle].flags & BF_NOT_RESIDENT)
|
|
if (!bm_MakeBitmapResident(handle))
|
|
return NULL;
|
|
|
|
d=GameBitmaps[handle].data16;
|
|
for (i=0;i<miplevel;i++){
|
|
d+=(GameBitmaps[handle].width>>i) * (GameBitmaps[handle].height>>i);
|
|
}
|
|
return (d);
|
|
}
|
|
// Given a source bitmap, generates mipmaps for it
|
|
void bm_GenerateMipMaps (int handle)
|
|
{
|
|
int width=bm_w(handle,0);
|
|
int height=bm_h(handle,0);
|
|
int jump=2; // how many pixels to jump in x and y on source
|
|
|
|
//mprintf ((0,"We got a mipper! %d \n",handle));
|
|
|
|
ASSERT (GameBitmaps[handle].used);
|
|
GameBitmaps[handle].flags|=BF_MIPMAPPED;
|
|
|
|
int levels = bm_miplevels(handle);
|
|
|
|
ushort *destdata;
|
|
for (int miplevel=1;miplevel<levels;miplevel++)
|
|
{
|
|
width/=2; height/=2;
|
|
|
|
for (int i=0;i<height;i++)
|
|
{
|
|
int adjheight=(i*jump)*bm_w(handle,miplevel-1); // find our y offset
|
|
|
|
for (int t=0;t<width;t++)
|
|
{
|
|
int adjwidth=(t*jump); // find our x offset
|
|
ushort *srcptr=bm_data (handle,miplevel-1);
|
|
srcptr+=(adjheight+adjwidth);
|
|
|
|
int rsum,gsum,bsum,asum;
|
|
rsum=gsum=bsum=asum=0;
|
|
ushort destpix;
|
|
if (GameBitmaps[handle].format==BITMAP_FORMAT_1555)
|
|
{
|
|
for (int y=0;y<2;y++)
|
|
for (int x=0;x<2;x++)
|
|
{
|
|
ushort pix=srcptr[y*bm_w(handle,miplevel-1)+x];
|
|
int r=(pix>>10) & 0x1f;
|
|
int g=(pix>>5) & 0x1f;
|
|
int b=(pix & 0x1f);
|
|
|
|
if (!(pix & OPAQUE_FLAG))
|
|
asum++;
|
|
else
|
|
{
|
|
rsum+=r;
|
|
gsum+=g;
|
|
bsum+=b;
|
|
}
|
|
}
|
|
// Average our source pixels
|
|
rsum/=4;
|
|
gsum/=4;
|
|
bsum/=4;
|
|
destpix=OPAQUE_FLAG | (rsum<<10) | (gsum<<5) | bsum;
|
|
|
|
if (asum>2)
|
|
destpix=NEW_TRANSPARENT_COLOR;
|
|
}
|
|
else if (GameBitmaps[handle].format==BITMAP_FORMAT_4444)
|
|
{
|
|
for (int y=0;y<2;y++)
|
|
for (int x=0;x<2;x++)
|
|
{
|
|
ushort pix=srcptr[y*bm_w(handle,miplevel-1)+x];
|
|
int a=(pix>>12) & 0x0f;
|
|
int r=(pix>>8) & 0x0f;
|
|
int g=(pix>>4) & 0x0f;
|
|
int b=(pix & 0x0f);
|
|
|
|
asum+=a;
|
|
rsum+=r;
|
|
gsum+=g;
|
|
bsum+=b;
|
|
|
|
}
|
|
// Average our source pixels
|
|
rsum/=4;
|
|
gsum/=4;
|
|
bsum/=4;
|
|
asum/=4;
|
|
destpix=(asum<<12) | (rsum<<8) | (gsum<<4) | bsum;
|
|
}
|
|
else
|
|
{
|
|
Int3();
|
|
}
|
|
destdata=bm_data (handle,miplevel);
|
|
int sw=bm_w(handle,miplevel);
|
|
destdata[(i*sw)+t]=destpix;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
// Gets bits per pixel for a particular bitmap
|
|
// As of 12/30/96 always returns 16
|
|
int bm_bpp (int handle)
|
|
{
|
|
return BPP_16;
|
|
}
|
|
// Given two bitmaps, scales the data from src to the size of dest
|
|
// Not a particularly fast implementation
|
|
void bm_ScaleBitmapToBitmap (int dest,int src)
|
|
{
|
|
ushort *dp=bm_data(dest,0);
|
|
ushort *sp=bm_data(src,0);
|
|
ASSERT (GameBitmaps[dest].used && dp);
|
|
ASSERT (GameBitmaps[src].used && sp);
|
|
int smipped=bm_mipped(src);
|
|
int dmipped=bm_mipped(dest);
|
|
int limit;
|
|
ASSERT (smipped==dmipped);
|
|
ASSERT (GameBitmaps[dest].format==GameBitmaps[src].format);
|
|
|
|
int sw=bm_w(src,0);
|
|
int sh=bm_h(src,0);
|
|
int dw=bm_w(dest,0);
|
|
int dh=bm_h(dest,0);
|
|
int i,t;
|
|
ushort *sdata;
|
|
ushort *ddata;
|
|
if (sw==dw && sh==dh)
|
|
{
|
|
if (smipped)
|
|
limit=bm_miplevels(src);
|
|
else
|
|
limit=1;
|
|
for (i=0;i<limit;i++)
|
|
{
|
|
sdata=(ushort *)bm_data (src,i);
|
|
ddata=(ushort *)bm_data (dest,i);
|
|
dw=bm_w(dest,i);
|
|
dh=bm_h(dest,i);
|
|
memcpy (ddata,sdata,dw*dh*sizeof(ushort));
|
|
}
|
|
return;
|
|
}
|
|
if (smipped)
|
|
limit=bm_miplevels(src);
|
|
else
|
|
limit=1;
|
|
for (int m=0;m<limit;m++)
|
|
{
|
|
sw=bm_w(src,m);
|
|
sh=bm_h(src,m);
|
|
dw=bm_w(dest,m);
|
|
dh=bm_h(dest,m);
|
|
|
|
sdata=(ushort *)bm_data (src,m);
|
|
ddata=(ushort *)bm_data (dest,m);
|
|
// These are our interpolant variables
|
|
float xstep=(float)sw/(float)dw;
|
|
float ystep=(float)sh/(float)dh;
|
|
float xoff=0;
|
|
float yoff=0;
|
|
for (i=0;i<dh;i++,yoff+=ystep)
|
|
{
|
|
for (xoff=0,t=0;t<dw;t++,xoff+=xstep)
|
|
{
|
|
ddata[i*dw+t]=sdata [(int)yoff*sw+(int)xoff];
|
|
}
|
|
}
|
|
}
|
|
GameBitmaps[dest].flags|=BF_CHANGED;
|
|
}
|
|
// Returns whether or not this bitmap is in use
|
|
int bm_used (int n)
|
|
{
|
|
ASSERT (n>=0 && n<MAX_BITMAPS);
|
|
return GameBitmaps[n].used;
|
|
}
|
|
// Loads a series of bitmaps from an IFF file
|
|
int bm_AllocLoadIFFAnim (const char *filename,int *dest_index,int mipped)
|
|
{
|
|
char name[BITMAP_NAME_LEN];
|
|
char str[BITMAP_NAME_LEN];
|
|
int num_bitmaps,i,src_bm,n;
|
|
int bm_index[200];
|
|
bm_ChangeEndName (filename,name);
|
|
|
|
num_bitmaps=bm_iff_read_animbrush(filename,bm_index);
|
|
if (num_bitmaps<0)
|
|
{
|
|
mprintf ((0,"Couldn't load %s.",filename));
|
|
return -1;
|
|
}
|
|
|
|
// Allocate space for our bitmap. If its mipped it must mean its a texture,
|
|
// so make it TEXTURE_WIDTH x TEXTURE_SIZE
|
|
for (i=0;i<num_bitmaps;i++)
|
|
{
|
|
src_bm=bm_index[i];
|
|
ASSERT (GameBitmaps[src_bm].used);
|
|
if (mipped)
|
|
{
|
|
if ((bm_mipped(src_bm))==0) // If we want a mipped but we don't have one
|
|
{
|
|
int w=bm_w(src_bm,0);
|
|
int h=bm_h(src_bm,0);
|
|
|
|
n=bm_AllocBitmap (w,h,mipped*(((w*h*2)/3)));
|
|
|
|
ASSERT (n>=0);
|
|
bm_ScaleBitmapToBitmap (n,src_bm);
|
|
bm_FreeBitmap (src_bm);
|
|
|
|
bm_GenerateMipMaps (n);
|
|
}
|
|
else
|
|
n=src_bm;
|
|
}
|
|
else // If we don't want a mipped
|
|
{
|
|
if ((bm_mipped(src_bm))==0)
|
|
n=src_bm;
|
|
else // And this is already mipped
|
|
{
|
|
int w=bm_w(src_bm,0);
|
|
int h=bm_h(src_bm,0);
|
|
ushort *src_data,*dest_data;
|
|
|
|
n=bm_AllocBitmap (w,h,mipped*(((w*h*2)/3)));
|
|
ASSERT (n>=0);
|
|
src_data=(ushort *)bm_data(src_bm,0);
|
|
dest_data=(ushort *)bm_data(n,0);
|
|
memcpy (dest_data,src_data,w*h*2);
|
|
|
|
bm_FreeBitmap (src_bm);
|
|
}
|
|
}
|
|
sprintf (str,"%s%d",name,i);
|
|
strcpy (GameBitmaps[n].name,str);
|
|
dest_index[i]=n;
|
|
bm_FreeBitmap (src_bm);
|
|
}
|
|
return num_bitmaps; // We made it!
|
|
}
|
|
// given a handle and a miplevel, returns the bytes per bitmap row
|
|
int bm_rowsize (int handle,int miplevel)
|
|
{
|
|
int w;
|
|
ASSERT (GameBitmaps[handle].used>0);
|
|
w=bm_w(handle,miplevel);
|
|
w*=2;
|
|
return w;
|
|
}
|
|
// a function to determine if a pixel in a bitmap is transparent
|
|
bool bm_pixel_transparent(int bm_handle,int x,int y)
|
|
{
|
|
if ((bm_data(bm_handle,0))==NULL)
|
|
return 0; // only check 16bit stuff
|
|
ushort *data=bm_data(bm_handle,0);
|
|
data = data + (bm_w(bm_handle,0)*y) + x;
|
|
if (GameBitmaps[bm_handle].format==BITMAP_FORMAT_4444)
|
|
{
|
|
int pix=*data;
|
|
if (!(pix>>12))
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (! (*data & OPAQUE_FLAG))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
// a function to determine if a pixel in a bitmap is transparent
|
|
ushort bm_pixel(int bm_handle,int x,int y)
|
|
{
|
|
if ((bm_data(bm_handle,0))==NULL)
|
|
return 0; // only check 16bit stuff
|
|
ushort *data=bm_data(bm_handle,0);
|
|
data = data + (bm_w(bm_handle,0)*y) + x;
|
|
return *data;
|
|
}
|
|
// Goes through the bitmap and sees if there is any transparency...if so, flag it!
|
|
int bm_SetBitmapIfTransparent (int handle)
|
|
{
|
|
if ((bm_data(handle,0))==NULL)
|
|
return 0; // only check 16bit stuff
|
|
int w=bm_w(handle,0);
|
|
int h=bm_h(handle,0);
|
|
ushort *data=bm_data(handle,0);
|
|
if (GameBitmaps[handle].format==BITMAP_FORMAT_4444)
|
|
{
|
|
for (int i=0;i<w*h;i++)
|
|
{
|
|
int pix=data[i]>>12;
|
|
if (!pix)
|
|
{
|
|
GameBitmaps[handle].flags|=BF_TRANSPARENT;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i=0;i<w*h;i++)
|
|
{
|
|
if (!(data[i] & OPAQUE_FLAG))
|
|
{
|
|
GameBitmaps[handle].flags|=BF_TRANSPARENT;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Saves the passed bitmap handle as a 32 bit uncompressed tga
|
|
int bm_SaveBitmapTGA (const char *filename,int handle)
|
|
{
|
|
int height,width;
|
|
int i,t;
|
|
CFILE *fp;
|
|
fp=(CFILE *)cfopen (filename,"wb");
|
|
if (fp==NULL)
|
|
{
|
|
mprintf ((0,"SaveTGA:couldn't open %s!\n",filename));
|
|
return 0;
|
|
}
|
|
ASSERT (GameBitmaps[handle].format==BITMAP_FORMAT_1555); // Can only save 1555
|
|
width=bm_w(handle,0);
|
|
height=bm_h(handle,0);
|
|
cf_WriteByte (fp,0); // image_id_len
|
|
cf_WriteByte (fp,0); // color map type
|
|
cf_WriteByte (fp,2); // image type: 2= uncompressed tga
|
|
|
|
for (i=0;i<9;i++) // ingore next 9 bytes
|
|
cf_WriteByte (fp,0);
|
|
|
|
cf_WriteShort (fp,width);
|
|
cf_WriteShort (fp,height);
|
|
cf_WriteByte (fp,32);
|
|
cf_WriteByte (fp,32+8);
|
|
|
|
//for (i=0;i<image_id_len;i++)
|
|
//cf_ReadByte (infile);
|
|
//upside_down=(descriptor & 0x20)>>5;
|
|
//upside_down=1-upside_down;
|
|
ushort *src_data=(ushort *)bm_data(handle,0);
|
|
for (i=0;i<height;i++)
|
|
{
|
|
for (t=0;t<width;t++)
|
|
{
|
|
ushort pix;
|
|
ddgr_color color;
|
|
pix=src_data[i*width+t];
|
|
color=GR_16_TO_COLOR (pix);
|
|
color |=0xFF000000;
|
|
|
|
cf_WriteInt (fp,color);
|
|
|
|
}
|
|
}
|
|
// Finis!
|
|
cfclose (fp);
|
|
return 1;
|
|
}
|
|
// clears bitmap
|
|
void bm_ClearBitmap(int handle)
|
|
{
|
|
int dx, dy;
|
|
//DAJ int rowsize_w = bm_rowsize(handle,0) >> 1;
|
|
ushort *bmpdata = bm_data(handle, 0);
|
|
int w = bm_w(handle, 0);
|
|
int h = bm_h(handle, 0);
|
|
for(dy = 0; dy < h; dy++)
|
|
{
|
|
for (dx = 0; dx < w; dx++)
|
|
bmpdata[dx] = NEW_TRANSPARENT_COLOR;
|
|
|
|
bmpdata += w;
|
|
}
|
|
}
|
|
// Given a bitmap handle, breaks a bitmap into smaller pieces.
|
|
// Note, this routine isn't terrible fast or efficient, and you
|
|
// must free the bitmaps returned to you in the bm_array
|
|
bool bm_CreateChunkedBitmap(int bm_handle, chunked_bitmap *chunk)
|
|
{
|
|
int i;
|
|
int *bm_array;
|
|
int bw=bm_w(bm_handle,0);
|
|
int bh=bm_h(bm_handle,0);
|
|
//determine optimal size of the square bitmaps
|
|
float fopt=128.0f;
|
|
int iopt;
|
|
//find the smallest dimension and base off that
|
|
int smallest = min(bw,bh);
|
|
if(smallest<=32)
|
|
fopt=32;
|
|
else
|
|
if(smallest<=64)
|
|
fopt=64;
|
|
else
|
|
fopt=128;
|
|
iopt=(int)fopt;
|
|
// Get how many pieces we need across and down
|
|
float temp=bw/fopt;
|
|
int how_many_across=temp;
|
|
if ((temp-how_many_across)>0)
|
|
how_many_across++;
|
|
temp=bh/fopt;
|
|
int how_many_down=temp;
|
|
if ((temp-how_many_down)>0)
|
|
how_many_down++;
|
|
ASSERT (how_many_across>0);
|
|
ASSERT (how_many_down>0);
|
|
// Allocate memory to hold our list of pieces
|
|
bm_array=(int *)mem_malloc (how_many_down*how_many_across*sizeof(int));
|
|
ASSERT(bm_array);
|
|
for (i=0;i<how_many_down*how_many_across;i++)
|
|
{
|
|
bm_array[i]=bm_AllocBitmap (iopt,iopt,0);
|
|
ASSERT (bm_array[i]>-1);
|
|
// Fill our new pieces with transparency
|
|
bm_ClearBitmap(bm_array[i]);
|
|
}
|
|
// Now go through our big bitmap and partition it into pieces
|
|
ushort *src_data=bm_data(bm_handle,0);
|
|
ushort *sdata;
|
|
ushort *ddata;
|
|
int shift;
|
|
switch(iopt)
|
|
{
|
|
case 32:
|
|
shift = 5;
|
|
break;
|
|
case 64:
|
|
shift = 6;
|
|
break;
|
|
case 128:
|
|
shift = 7;
|
|
break;
|
|
default:
|
|
Int3(); //Get Jeff
|
|
break;
|
|
}
|
|
int maxx,maxy;
|
|
int windex,hindex;
|
|
int s_y,s_x,d_y,d_x;
|
|
for(hindex=0;hindex<how_many_down;hindex++){
|
|
for(windex=0;windex<how_many_across;windex++){
|
|
//loop through the chunks
|
|
//find end x and y
|
|
if(windex<how_many_across-1)
|
|
maxx=iopt;
|
|
else
|
|
maxx = bw - (windex<<shift);
|
|
if(hindex<how_many_down-1)
|
|
maxy=iopt;
|
|
else
|
|
maxy = bh - (hindex<<shift);
|
|
//find the starting source x and y
|
|
s_x = (windex<<shift);
|
|
s_y = (hindex<<shift);
|
|
//get the pointers pointing to the right spot
|
|
ddata = bm_data(bm_array[hindex*how_many_across+windex],0);
|
|
sdata = &src_data[s_y * bw + s_x];
|
|
//copy the data
|
|
for(d_y=0;d_y<maxy;d_y++){
|
|
for(d_x=0;d_x<maxx;d_x++){
|
|
ddata[d_x] = sdata[d_x];
|
|
}//end for d_x
|
|
sdata += bw;
|
|
ddata += iopt;
|
|
}//end for d_y
|
|
}//end for windex
|
|
}//end for hindex
|
|
// Sirrah, we're done!
|
|
// Tell the calling function how many pieces we have in x and y
|
|
chunk->pw = bw;
|
|
chunk->ph = bh;
|
|
chunk->w = how_many_across;
|
|
chunk->h = how_many_down;
|
|
chunk->bm_array = bm_array;
|
|
return true;
|
|
}
|
|
// destroys a chunked bitmap.
|
|
void bm_DestroyChunkedBitmap(chunked_bitmap *chunk)
|
|
{
|
|
int i, num_bmps = chunk->w*chunk->h;
|
|
for (i = 0; i < num_bmps; i++)
|
|
bm_FreeBitmap(chunk->bm_array[i]);
|
|
mem_free(chunk->bm_array);
|
|
chunk->bm_array = NULL;
|
|
}
|
|
// Changes the size of a bitmap to a new size
|
|
void bm_ChangeSize(int handle,int new_w,int new_h)
|
|
{
|
|
int mipped=bm_mipped(handle);
|
|
int n;
|
|
int mem_used=(GameBitmaps[handle].width*GameBitmaps[handle].height*2);
|
|
n=bm_AllocBitmap (new_w,new_h,mipped*((new_w*new_h*2)/3));
|
|
ASSERT (n>=0);
|
|
if (mipped)
|
|
GameBitmaps[n].flags|=BF_MIPMAPPED;
|
|
if (GameBitmaps[handle].format==BITMAP_FORMAT_4444)
|
|
GameBitmaps[n].format=BITMAP_FORMAT_4444;
|
|
|
|
bm_ScaleBitmapToBitmap (n,handle);
|
|
Bitmap_memory_used-=mem_used+(mipped*(mem_used/3));
|
|
mem_free (GameBitmaps[handle].data16);
|
|
GameBitmaps[handle].data16=GameBitmaps[n].data16;
|
|
GameBitmaps[handle].width=new_w;
|
|
GameBitmaps[handle].height=new_h;
|
|
GameBitmaps[n].used=0;
|
|
Num_of_bitmaps--;
|
|
}
|
|
// Returns the format of this bitmap
|
|
int bm_format (int handle)
|
|
{
|
|
if (!GameBitmaps[handle].used)
|
|
{
|
|
Int3();
|
|
return -1;
|
|
}
|
|
if (GameBitmaps[handle].flags & BF_NOT_RESIDENT)
|
|
if (!bm_MakeBitmapResident(handle))
|
|
return NULL;
|
|
return (GameBitmaps[handle].format);
|
|
}
|