mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 17:46:53 -10:00
1065 lines
26 KiB
C++
1065 lines
26 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* $Logfile: /Freespace2/code/Graphics/GrGlideTexture.cpp $
|
|
* $Revision: 2.1 $
|
|
* $Date: 2002-08-01 01:41:05 $
|
|
* $Author: penguin $
|
|
*
|
|
* Code to manage Glide texture RAM
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 2.0 2002/06/03 04:02:22 penguin
|
|
* Warpcore CVS sync
|
|
*
|
|
* Revision 1.1 2002/05/02 18:03:07 mharris
|
|
* Initial checkin - converted filenames and includes to lower case
|
|
*
|
|
*
|
|
* 14 10/13/99 9:22a Daveb
|
|
* Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
|
|
* related to movies. Fixed launcher spawning from PXO screen.
|
|
*
|
|
* 13 7/16/99 1:49p Dave
|
|
* 8 bit aabitmaps. yay.
|
|
*
|
|
* 12 7/13/99 1:15p Dave
|
|
* 32 bit support. Whee!
|
|
*
|
|
* 11 7/09/99 9:51a Dave
|
|
* Added thick polyline code.
|
|
*
|
|
* 10 7/08/99 8:10a Mikek
|
|
* Suppress compiler warning. Now I get an FS2 programming credit! :)
|
|
*
|
|
* 9 6/29/99 4:16p Dave
|
|
* Temporary speedup for tcache init.
|
|
*
|
|
* 8 6/29/99 10:35a Dave
|
|
* Interface polygon bitmaps! Whee!
|
|
*
|
|
* 7 6/16/99 4:06p Dave
|
|
* New pilot info popup. Added new draw-bitmap-as-poly function.
|
|
*
|
|
* 6 2/08/99 5:07p Dave
|
|
* FS2 chat server support. FS2 specific validated missions.
|
|
*
|
|
* 5 1/15/99 11:29a Neilk
|
|
* Fixed D3D screen/texture pixel formatting problem.
|
|
*
|
|
* 4 12/01/98 8:06a Dave
|
|
* Temporary checkin to fix some texture transparency problems in d3d.
|
|
*
|
|
* 3 11/30/98 1:07p Dave
|
|
* 16 bit conversion, first run.
|
|
*
|
|
* 2 10/07/98 10:53a Dave
|
|
* Initial checkin.
|
|
*
|
|
* 1 10/07/98 10:49a Dave
|
|
*
|
|
* 18 5/14/98 5:39p John
|
|
* Added in code for multiple non-dimming lights.
|
|
*
|
|
* 17 4/27/98 9:33p John
|
|
* Removed mprintf
|
|
*
|
|
* 16 4/27/98 9:25p John
|
|
* Made Glide skip any 2MB boundry, not just first one.
|
|
*
|
|
* 15 4/27/98 9:09p John
|
|
* Fixed bug where texture was crossing a 2MB line on Voodoo2. Added code
|
|
* to tell how full VRAM is and how much got paged in each frame.
|
|
*
|
|
* 14 4/27/98 10:44a John
|
|
* Put in a new texture caching algorithm that doesn't flush everything
|
|
* every so oftem.
|
|
*
|
|
* 13 4/26/98 12:02p John
|
|
* Made glide texturing do its own allocation rather than using the gu_
|
|
* functions.
|
|
*
|
|
* 12 4/26/98 11:14a John
|
|
* Restructured/Cleaned up the caching code in preparation for the new
|
|
* improved caching system.
|
|
*
|
|
* 11 4/22/98 9:13p John
|
|
* Added code to replace frames of animations in vram if so desired.
|
|
*
|
|
* 10 4/21/98 9:16a John
|
|
* Fixed bug with directives display in Glide.
|
|
*
|
|
* 9 4/20/98 8:41p John
|
|
* Made debris culling actually reduce Glide texture resolution.
|
|
*
|
|
* 8 4/09/98 4:38p John
|
|
* Made non-darkening and transparent textures work under Glide. Fixed
|
|
* bug with Jim's computer not drawing any bitmaps.
|
|
*
|
|
* 7 4/09/98 2:21p John
|
|
* Fixed transparency bug with Glide
|
|
*
|
|
* 6 4/08/98 9:16p John
|
|
* Made transparency work for textures in Glide by using chromakey. Made
|
|
* nondarkening colors work.
|
|
*
|
|
* 5 4/08/98 8:47a John
|
|
* Moved all texture caching into a new module
|
|
*
|
|
* 4 4/06/98 4:45p John
|
|
* Removed some debug code that made textures 2x too small.
|
|
*
|
|
* 3 3/04/98 5:43p Hoffoss
|
|
* Fixed warning.
|
|
*
|
|
* 2 3/04/98 3:50p John
|
|
* Made the Glide texture cache manager of Leighton's work with 256x256
|
|
* maps.
|
|
*
|
|
* 1 3/03/98 4:42p John
|
|
* Added in Leighton's code to do texture caching on Glide.
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
//#define USE_8BPP_TEXTURES
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include "glide/glide.h"
|
|
#include "glide/glideutl.h"
|
|
|
|
#include "osapi/osapi.h"
|
|
#include "graphics/2d.h"
|
|
#include "bmpman/bmpman.h"
|
|
#include "math/floating.h"
|
|
#include "palman/palman.h"
|
|
#include "graphics/grinternal.h"
|
|
#include "graphics/grglide.h"
|
|
#include "graphics/line.h"
|
|
#include "graphics/font.h"
|
|
#include "io/mouse.h"
|
|
#include "io/key.h"
|
|
#include "globalincs/systemvars.h"
|
|
#include "graphics/grglideinternal.h"
|
|
|
|
#define TEXMEM_2MB_EDGE (2*1024*1024)
|
|
|
|
// Hardware specific values
|
|
typedef struct tcache_data {
|
|
GrLOD_t lod;
|
|
GrAspectRatio_t aspect;
|
|
GrTextureFormat_t format;
|
|
uint vram_offset;
|
|
int vram_size;
|
|
} tcache_data;
|
|
|
|
typedef struct tcache_slot {
|
|
int bitmap_id;
|
|
float uscale;
|
|
float vscale;
|
|
|
|
tcache_data data;
|
|
tcache_slot *data_sections[MAX_BMAP_SECTIONS_X][MAX_BMAP_SECTIONS_Y]; // NULL if no subsections are present.
|
|
tcache_slot *parent;
|
|
} tcache_slot;
|
|
|
|
#define MAX_AUX_TEXTURES 200
|
|
#define MAX_TEXTURES MAX_BITMAPS
|
|
|
|
// search for AUX to find all instancees of aux textures which can be put back in.
|
|
|
|
// AUX
|
|
// static tcache_slot *Textures_aux = NULL; // auxiliary textures for storing sections of a texture
|
|
static void *Texture_sections = NULL;
|
|
static tcache_slot *Textures = NULL;
|
|
ubyte *Glide_tmp_ram = NULL;
|
|
|
|
int Glide_last_bitmap_id = -1;
|
|
int Glide_last_bitmap_type = -1;
|
|
int Glide_last_section_x = -1;
|
|
int Glide_last_section_y = -1;
|
|
float Glide_last_u_ratio, Glide_last_v_ratio;
|
|
|
|
static int Glide_last_detail = -1;
|
|
|
|
uint Glide_total_memory;
|
|
uint Glide_start_address;
|
|
uint Glide_end_address;
|
|
uint Glide_current_address;
|
|
|
|
int Glide_textures_in_frame = 0;
|
|
|
|
int Glide_explosion_vram = 0;
|
|
|
|
//=======================================================
|
|
// Code to manage texture memory.
|
|
// This basically allocates until out of VRAM, and then starts freeing
|
|
// blocks at the start of VRAM to make room for new textures.
|
|
// Based on code from Jason Scannell's webpage.
|
|
// http://members.home.net/jscannell.
|
|
|
|
typedef struct {
|
|
int next;
|
|
uint start_address;
|
|
int size;
|
|
tcache_slot *texture_ptr;
|
|
} tblock;
|
|
|
|
tblock *Tblocks = NULL; // Memory tracking blocks
|
|
int Tblock_num_blocks = 0; // How many blocks to use
|
|
|
|
int Tblock_freelist_start; // First block in free list
|
|
int Tblock_usedlist_start; // First block in allocation list
|
|
int Tblock_usedlist_head; // Last block in allocation list
|
|
|
|
uint Tblock_min_address; // Lowest address in texture memory
|
|
uint Tblock_max_address; // Highest address in texture memory
|
|
|
|
void FlushBlocks()
|
|
{
|
|
int i;
|
|
|
|
memset(Tblocks,0,sizeof(tblock)*Tblock_num_blocks);
|
|
|
|
for(i = 0; i < Tblock_num_blocks - 1; i++) {
|
|
Tblocks[i].next = i + 1;
|
|
}
|
|
|
|
Tblocks[Tblock_num_blocks - 1].next = -1;
|
|
|
|
Tblock_usedlist_start = -1;
|
|
Tblock_usedlist_head = -1;
|
|
Tblock_freelist_start = 0;
|
|
}
|
|
|
|
void InitBlocks(uint min, uint max, int num_blocks)
|
|
{
|
|
Tblock_num_blocks = num_blocks;
|
|
Tblock_min_address = min;
|
|
Tblock_max_address = max;
|
|
|
|
if(Tblocks == NULL){
|
|
Tblocks = (tblock *)malloc(Tblock_num_blocks*sizeof(tblock));
|
|
Assert(Tblocks!=NULL);
|
|
}
|
|
|
|
FlushBlocks();
|
|
}
|
|
|
|
void ReleaseBlocks()
|
|
{
|
|
if ( Tblocks ) {
|
|
free(Tblocks);
|
|
Tblocks = NULL;
|
|
}
|
|
Tblock_num_blocks = 0;
|
|
}
|
|
|
|
void ReleaseSlotSub(tcache_slot *t)
|
|
{
|
|
int idx, s_idx;
|
|
|
|
if(t == NULL){
|
|
return;
|
|
}
|
|
|
|
t->bitmap_id = -1;
|
|
for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
|
|
for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
|
|
// recurse
|
|
if(t->data_sections[idx][s_idx] != NULL){
|
|
ReleaseSlotSub(t->data_sections[idx][s_idx]);
|
|
t->data_sections[idx][s_idx] = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReleaseSlot(int nBlock)
|
|
{
|
|
if ( Tblocks[nBlock].texture_ptr != NULL ) {
|
|
// if this guy has a parent (in the case of a sectioned bitmap), unset his bitmap
|
|
if(Tblocks[nBlock].texture_ptr->parent != NULL){
|
|
Tblocks[nBlock].texture_ptr->parent->bitmap_id = -1;
|
|
}
|
|
Tblocks[nBlock].texture_ptr->bitmap_id = -1;
|
|
|
|
// AUX
|
|
// ReleaseSlotSub(Tblocks[nBlock].texture_ptr);
|
|
Tblocks[nBlock].texture_ptr = NULL;
|
|
|
|
|
|
Glide_textures_in -= Tblocks[nBlock].size;
|
|
}
|
|
}
|
|
|
|
void FreeBlock(int nBlock)
|
|
{
|
|
int nFreeNext;
|
|
|
|
ReleaseSlot(nBlock);
|
|
|
|
//---- Save next indices ----
|
|
nFreeNext = Tblock_freelist_start;
|
|
|
|
//---- Move alloc list block to start of free list ----
|
|
Tblock_freelist_start = nBlock;
|
|
Tblocks[nBlock].next = nFreeNext;
|
|
|
|
}
|
|
|
|
int AllocBlock(void)
|
|
{
|
|
int nNewBlock;
|
|
|
|
//---- Get block from free list ----
|
|
nNewBlock = Tblock_freelist_start;
|
|
|
|
//**** DOS NOT HANDLE EMPTY FREE LIST ****
|
|
Tblock_freelist_start = Tblocks[Tblock_freelist_start].next;
|
|
|
|
if(Tblock_usedlist_head < 0) {
|
|
//---- Alloc list is empty, add to start ----
|
|
Tblock_usedlist_start = nNewBlock;
|
|
Tblocks[nNewBlock].next = -1;
|
|
} else {
|
|
//---- Insert at head of alloc list ----
|
|
Tblocks[nNewBlock].next = Tblocks[Tblock_usedlist_head].next;
|
|
Tblocks[Tblock_usedlist_head].next = nNewBlock;
|
|
}
|
|
|
|
//---- Set new head index ----
|
|
Tblock_usedlist_head = nNewBlock;
|
|
|
|
return nNewBlock;
|
|
}
|
|
|
|
// Macro to compute ending address of block
|
|
#define BLOCK_END(b) (Tblocks[b].start_address + Tblocks[b].size)
|
|
|
|
uint AllocateTexture(uint size, tcache_slot *texture_ptr)
|
|
{
|
|
int nNewBlock;
|
|
int next;
|
|
|
|
if (Tblock_usedlist_start < 0) {
|
|
|
|
//---- Alloc list is empty ----
|
|
nNewBlock = AllocBlock();
|
|
Tblocks[nNewBlock].start_address = Tblock_min_address;
|
|
} else {
|
|
|
|
uint dwAddress = BLOCK_END(Tblock_usedlist_head);
|
|
if ( dwAddress + size < Tblock_max_address ) {
|
|
int a1 = dwAddress / TEXMEM_2MB_EDGE;
|
|
int a2 = (dwAddress+size) / TEXMEM_2MB_EDGE;
|
|
|
|
if ( a2 > a1 ) {
|
|
//mprintf(( "GrGlideTexture: Skipping a 2MB edge!\n" ));
|
|
dwAddress = a2*TEXMEM_2MB_EDGE;
|
|
}
|
|
}
|
|
|
|
if( (dwAddress + size > Tblock_max_address) || (Tblocks[Tblock_freelist_start].next<0) ) {
|
|
#ifndef NDEBUG
|
|
if ( Tblocks[Tblock_freelist_start].next < 0 ) {
|
|
mprintf(( "GrGlideTexture: AllocateTexture out of blocks! Get John.\n" ));
|
|
}
|
|
#endif
|
|
|
|
//---- No room left, go back to start ----
|
|
ReleaseSlot(Tblock_usedlist_start);
|
|
|
|
nNewBlock = Tblock_usedlist_head = Tblock_usedlist_start;
|
|
dwAddress = Tblock_min_address;
|
|
} else {
|
|
|
|
//---- Make new block ----
|
|
nNewBlock = AllocBlock();
|
|
}
|
|
|
|
next = Tblocks[Tblock_usedlist_head].next;
|
|
|
|
//---- Unlink blocks being overwritten ----
|
|
while((next >= 0) && (dwAddress + size > Tblocks[next].start_address)) {
|
|
|
|
int nTemp = Tblocks[next].next;
|
|
|
|
FreeBlock(next);
|
|
next = nTemp;
|
|
}
|
|
|
|
//---- Init new block ----
|
|
Tblocks[nNewBlock].next = next;
|
|
Tblocks[nNewBlock].start_address = dwAddress;
|
|
}
|
|
|
|
Tblocks[nNewBlock].size = size;
|
|
Tblocks[nNewBlock].texture_ptr = texture_ptr;
|
|
|
|
return Tblocks[nNewBlock].start_address;
|
|
}
|
|
|
|
void glide_tcache_set_initial_texture_mode()
|
|
{
|
|
grTexMipMapMode( GR_TMU0, GR_MIPMAP_DISABLE, FXFALSE);
|
|
grTexLodBiasValue( GR_TMU0, .5f);
|
|
grTexClampMode( GR_TMU0, GR_TEXTURECLAMP_WRAP, GR_TEXTURECLAMP_WRAP);
|
|
grTexFilterMode( GR_TMU0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR);
|
|
}
|
|
|
|
void glide_tcache_init()
|
|
{
|
|
// if we're already inited, allocate nothing new)
|
|
if(Textures == NULL){
|
|
Textures = (tcache_slot *)malloc((MAX_TEXTURES)*sizeof(tcache_slot));
|
|
if ( !Textures ) {
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// AUX
|
|
/*
|
|
Textures_aux = (tcache_slot*)malloc((MAX_TEXTURES) * MAX_BMAP_SECTIONS_X * MAX_BMAP_SECTIONS_Y sizeof(tcache_slot));
|
|
if( !Textures_aux){
|
|
exit(1);
|
|
}
|
|
*/
|
|
// if we're already inited, allocate nothing new)
|
|
if(Texture_sections == NULL){
|
|
Texture_sections = malloc(MAX_TEXTURES * MAX_BMAP_SECTIONS_X * MAX_BMAP_SECTIONS_Y * sizeof(tcache_slot));
|
|
if(!Texture_sections){
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// if we're already inited, allocate nothing new)
|
|
if(Glide_tmp_ram == NULL){
|
|
Glide_tmp_ram = (ubyte *)malloc(256*256*2);
|
|
if ( !Glide_tmp_ram ) {
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
Glide_total_memory = guTexMemQueryAvail(GR_TMU0);
|
|
Glide_start_address = grTexMinAddress(GR_TMU0);
|
|
Glide_end_address = grTexMaxAddress(GR_TMU0);
|
|
Glide_current_address = Glide_start_address;
|
|
|
|
mprintf(( "Total texture memory on 3dfx card=%d bytes\n", Glide_total_memory ));
|
|
|
|
glide_tcache_set_initial_texture_mode();
|
|
|
|
InitBlocks(Glide_start_address,Glide_end_address, MAX_TEXTURES);
|
|
|
|
// Init the texture structures
|
|
int i, idx, s_idx, count;
|
|
count = 0;
|
|
for( i=0; i<MAX_TEXTURES; i++ ) {
|
|
Textures[i].bitmap_id = -1;
|
|
Textures[i].parent = NULL;
|
|
|
|
for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
|
|
for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
|
|
// AUX
|
|
// Textures[i].data_sections[idx][s_idx] = NULL;
|
|
// Textures[i].data_sections[idx][s_idx] = (tcache_slot*)malloc(sizeof(tcache_slot));
|
|
Textures[i].data_sections[idx][s_idx] = &((tcache_slot*)Texture_sections)[count++];
|
|
Textures[i].data_sections[idx][s_idx]->parent = &Textures[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// AUX
|
|
/*
|
|
for( i=0; i<MAX_AUX_TEXTURES; i++){
|
|
Textures_aux[i].bitmap_id = -1;
|
|
|
|
for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
|
|
for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
|
|
Textures_aux[i].data_sections[idx][s_idx] = NULL;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
Glide_textures_in = 0;
|
|
Glide_last_bitmap_id = -1;
|
|
Glide_last_section_x = -1;
|
|
Glide_last_section_y = -1;
|
|
|
|
Glide_last_detail = Detail.hardware_textures;
|
|
}
|
|
|
|
void glide_tcache_cleanup()
|
|
{
|
|
if ( Textures ) {
|
|
free(Textures);
|
|
Textures = NULL;
|
|
}
|
|
|
|
// AUX
|
|
/*
|
|
if ( Textures_aux ) {
|
|
free(Textures_aux);
|
|
Textures_aux = NULL;
|
|
}
|
|
*/
|
|
if(Texture_sections){
|
|
free(Texture_sections);
|
|
Texture_sections = NULL;
|
|
}
|
|
|
|
if ( Glide_tmp_ram ) {
|
|
free(Glide_tmp_ram);
|
|
Glide_tmp_ram = NULL;
|
|
}
|
|
|
|
ReleaseBlocks();
|
|
}
|
|
|
|
void glide_tcache_flush()
|
|
{
|
|
if ( grSstIsBusy() ) {
|
|
//mprintf(( "Pausing until 3DFX is idle before clearing texture RAM...\n" ));
|
|
grSstIdle(); // Wait for idle
|
|
}
|
|
|
|
Glide_current_address = Glide_start_address;
|
|
|
|
// Init the texture structures
|
|
int i; //, idx, s_idx;
|
|
for( i=0; i<MAX_TEXTURES; i++ ) {
|
|
Textures[i].bitmap_id = -1;
|
|
|
|
// AUX
|
|
/*
|
|
for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
|
|
for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
|
|
Textures[i].data_sections[idx][s_idx] = NULL;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
// AUX
|
|
/*
|
|
for( i=0; i<MAX_AUX_TEXTURES; i++){
|
|
Textures_aux[i].bitmap_id = -1;
|
|
|
|
for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
|
|
for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
|
|
Textures_aux[i].data_sections[idx][s_idx] = NULL;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
Glide_textures_in = 0;
|
|
Glide_last_bitmap_id = -1;
|
|
Glide_last_section_x = -1;
|
|
Glide_last_section_y = -1;
|
|
|
|
|
|
Glide_explosion_vram = 0;
|
|
|
|
FlushBlocks();
|
|
}
|
|
|
|
// get a free aux texture
|
|
// AUX
|
|
/*
|
|
int ga_reentrant = 0;
|
|
tcache_slot *glide_get_aux_slot()
|
|
{
|
|
int idx;
|
|
int index = -1;
|
|
tcache_slot *ret;
|
|
|
|
// never go in here more than twice
|
|
if(ga_reentrant > 1){
|
|
return NULL;
|
|
}
|
|
|
|
ga_reentrant++;
|
|
|
|
for(idx=0; idx<MAX_AUX_TEXTURES; idx++){
|
|
if(Textures_aux[idx].bitmap_id == -1){
|
|
index = idx;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// OH NO. This means we've run out of slots for bitmap sections. Let's just blast all of them free. whee!
|
|
if(index == -1){
|
|
mprintf(("AIEEEE! FLUSHIN SECTIONED BITMAPS!\n"));
|
|
for(idx=0; idx<MAX_TEXTURES; idx++){
|
|
if((Textures[idx].bitmap_id > -1) && (Textures[idx].data_sections[0][0] != NULL)){
|
|
ReleaseSlot(&Textures[idx] - Textures);
|
|
}
|
|
}
|
|
|
|
ret = glide_get_aux_slot();
|
|
|
|
ga_reentrant--;
|
|
return ret;
|
|
}
|
|
|
|
// hmm
|
|
int s_idx;
|
|
Textures_aux[index].bitmap_id = -1;
|
|
Textures_aux[index].data.vram_offset = 0;
|
|
Textures_aux[index].data.vram_size = 0;
|
|
for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
|
|
for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
|
|
Textures_aux[index].data_sections[idx][s_idx] = NULL;
|
|
}
|
|
}
|
|
|
|
ret = &Textures_aux[index];
|
|
ga_reentrant--;
|
|
return ret;
|
|
}
|
|
*/
|
|
|
|
void glide_tcache_frame()
|
|
{
|
|
Glide_textures_in_frame = 0;
|
|
}
|
|
|
|
extern int palman_is_nondarkening(int r,int g, int b);
|
|
|
|
// data == start of bitmap data
|
|
// sx == x offset into bitmap
|
|
// sy == y offset into bitmap
|
|
// src_w == absolute width of section on source bitmap
|
|
// src_h == absolute height of section on source bitmap
|
|
// bmap_w == width of source bitmap
|
|
// bmap_h == height of source bitmap
|
|
// tex_w == width of final texture
|
|
// tex_h == height of final texture
|
|
int glide_create_texture_sub(int bitmap_type, int bitmap_handle, ushort *data, int sx, int sy, int src_w, int src_h, int bmap_w, int bmap_h, int tex_w, int tex_h, tcache_slot *tslot)
|
|
{
|
|
int i, j;
|
|
|
|
// sanity - make sure we're not going to run off the end of the bitmap
|
|
#ifndef NDEBUG
|
|
Assert(src_w <= (bmap_w - sx));
|
|
Assert(src_h <= (bmap_h - sy));
|
|
#endif
|
|
|
|
if ( tex_w <= 16 ) tex_w = 16;
|
|
else if ( tex_w <= 32 ) tex_w = 32;
|
|
else if ( tex_w <= 64 ) tex_w = 64;
|
|
else if ( tex_w <= 128 ) tex_w = 128;
|
|
else {
|
|
tex_w = 256;
|
|
}
|
|
|
|
if ( tex_h <= 16 ) tex_h = 16;
|
|
else if ( tex_h <= 32 ) tex_h = 32;
|
|
else if ( tex_h <= 64 ) tex_h = 64;
|
|
else if ( tex_h <= 128 ) tex_h = 128;
|
|
else {
|
|
tex_h = 256;
|
|
}
|
|
|
|
// these can never be shrunk. meaning, the texture _must_ be big enough to hold every pixel
|
|
if ( (bitmap_type == TCACHE_TYPE_AABITMAP) || (bitmap_type == TCACHE_TYPE_BITMAP_SECTION) ) {
|
|
// W & H must be within 8x of each other.
|
|
if ( (tex_w==16) && (tex_h==256) ) {
|
|
tex_w = 32;
|
|
} else if ( (tex_w==256) && (tex_h==16) ) {
|
|
tex_h = 32;
|
|
}
|
|
} else {
|
|
// W & H must be within 8x of each other.
|
|
if ( (tex_w==16) && (tex_h==256) ) {
|
|
tex_h = 128;
|
|
} else if ( (tex_w==256) && (tex_h==16) ) {
|
|
tex_w = 128;
|
|
}
|
|
}
|
|
|
|
ushort *bmp_data = data;
|
|
ubyte *bmp_data_byte = (ubyte*)data;
|
|
|
|
GrTextureFormat_t tex_format;
|
|
|
|
if ( bitmap_type == TCACHE_TYPE_AABITMAP ) {
|
|
tex_format = GR_TEXFMT_ALPHA_8;
|
|
|
|
ubyte *lpSP;
|
|
ubyte pix;
|
|
ubyte xlat[256];
|
|
|
|
for (i=0; i<16; i++ ) {
|
|
xlat[i] = ubyte(Gr_gamma_lookup[(i*255)/15]);
|
|
}
|
|
xlat[15] = xlat[1];
|
|
pix = 255;
|
|
for ( ; i<256; i++ ) {
|
|
xlat[i] = pix;
|
|
}
|
|
|
|
// upload to temp ram
|
|
for (j = 0; j < tex_h; j++) {
|
|
// the proper line in the temp ram
|
|
lpSP = (ubyte*)(Glide_tmp_ram + tex_w * j);
|
|
|
|
// upload the line of texture from the source bitmap
|
|
for (i = 0; i < tex_w; i++) {
|
|
// if we're within the bounds of the section we're copying
|
|
if ( (j < src_h) && (i < src_w) ) {
|
|
*lpSP++ = xlat[(ubyte)bmp_data_byte[(j * bmap_w) + i + sx]];
|
|
}
|
|
// otherwise just copy black
|
|
else {
|
|
*lpSP++ = 0;
|
|
}
|
|
}
|
|
}
|
|
} else if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
|
|
tex_format = GR_TEXFMT_ARGB_1555;
|
|
ushort *lpSP;
|
|
|
|
for (j = 0; j < src_h; j++) {
|
|
// the proper line in the temp ram
|
|
lpSP = (unsigned short*)(Glide_tmp_ram + tex_w * 2 * j);
|
|
|
|
// nice and clean
|
|
for (i = 0; i < src_w; i++) {
|
|
// stuff the texture into vram
|
|
*lpSP++ = bmp_data[((j+sy) * bmap_w) + sx + i];
|
|
}
|
|
}
|
|
} else {
|
|
tex_format = GR_TEXFMT_ARGB_1555;
|
|
fix u, utmp, v, du, dv;
|
|
ushort *lpSP;
|
|
|
|
u = 0;
|
|
|
|
// source line on the bitmap;
|
|
v = i2f(sy);
|
|
|
|
// scale through the texture
|
|
du = (src_w * F1_0) / tex_w;
|
|
dv = (src_h * F1_0) / tex_h;
|
|
|
|
for (j = 0; j < tex_h; j++) {
|
|
// the proper line in the temp ram
|
|
lpSP = (unsigned short*)(Glide_tmp_ram + tex_w * 2 * j);
|
|
|
|
// pixel offset on this individual line of the source bitmap
|
|
utmp = u + i2f(sx);
|
|
|
|
// nice and clean
|
|
for (i = 0; i < tex_w; i++) {
|
|
// stuff the texture into vram
|
|
*lpSP++ = bmp_data[f2i(v) * bmap_w + f2i(utmp)];
|
|
|
|
// next pixel
|
|
utmp += du;
|
|
}
|
|
|
|
// next line in the source bitmap
|
|
v += dv;
|
|
}
|
|
}
|
|
|
|
GrLOD_t lod=GR_LOD_16;
|
|
|
|
int longest = max(tex_w, tex_h);
|
|
|
|
float uscale, vscale;
|
|
if ( bitmap_type == TCACHE_TYPE_AABITMAP ) {
|
|
uscale = i2fl(bmap_w)*256.0f / i2fl(longest);
|
|
vscale = i2fl(bmap_h)*256.0f / i2fl(longest);
|
|
} else if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
|
|
uscale = i2fl(src_w)*256.0f / i2fl(longest);
|
|
vscale = i2fl(src_h)*256.0f / i2fl(longest);
|
|
} else {
|
|
uscale = i2fl(tex_w)*256.0f / i2fl(longest);
|
|
vscale = i2fl(tex_h)*256.0f / i2fl(longest);
|
|
}
|
|
|
|
switch( longest ) {
|
|
case 16: lod = GR_LOD_16; break;
|
|
case 32: lod = GR_LOD_32; break;
|
|
case 64: lod = GR_LOD_64; break;
|
|
case 128: lod = GR_LOD_128; break;
|
|
case 256: lod = GR_LOD_256; break;
|
|
default: Int3();
|
|
}
|
|
|
|
// GR_ASPECT_2x1
|
|
GrAspectRatio_t aspect = GR_ASPECT_1x1; // aspect is widthxheight
|
|
|
|
if ( tex_w < tex_h ) {
|
|
int ratio = tex_h / tex_w;
|
|
switch(ratio) {
|
|
case 1: aspect = GR_ASPECT_1x1; break;
|
|
case 2: aspect = GR_ASPECT_1x2; break;
|
|
case 4: aspect = GR_ASPECT_1x4; break;
|
|
case 8: aspect = GR_ASPECT_1x8; break;
|
|
default: Int3();
|
|
}
|
|
} else {
|
|
int ratio = tex_w / tex_h;
|
|
switch(ratio) {
|
|
case 1: aspect = GR_ASPECT_1x1; break;
|
|
case 2: aspect = GR_ASPECT_2x1; break;
|
|
case 4: aspect = GR_ASPECT_4x1; break;
|
|
case 8: aspect = GR_ASPECT_8x1; break;
|
|
default: Int3();
|
|
}
|
|
}
|
|
|
|
|
|
GrTexInfo info;
|
|
|
|
info.smallLod = lod; //GR_LOD_256;
|
|
info.largeLod = lod; //GR_LOD_256;
|
|
info.aspectRatio = aspect; //GR_ASPECT_1x1;
|
|
info.format = tex_format; //GR_TEXFMT_ARGB_1555;
|
|
info.data = Glide_tmp_ram; //source data
|
|
|
|
int bytes_needed = grTexTextureMemRequired( GR_MIPMAPLEVELMASK_BOTH, &info );
|
|
|
|
// if ( (tslot->data.vram_offset == 0) || ((tslot->data.vram_offset>0)&&(bytes_needed>tslot->data.vram_size))) {
|
|
tslot->data.vram_offset = AllocateTexture( bytes_needed, tslot );
|
|
tslot->data.vram_size = bytes_needed;
|
|
Glide_textures_in += bytes_needed;
|
|
// }
|
|
|
|
tslot->data.format = tex_format;
|
|
tslot->data.lod = lod;
|
|
tslot->data.aspect = aspect;
|
|
tslot->bitmap_id = bitmap_handle;
|
|
tslot->uscale = uscale;
|
|
tslot->vscale = vscale;
|
|
|
|
grTexDownloadMipMap(GR_TMU0, tslot->data.vram_offset, GR_MIPMAPLEVELMASK_BOTH, &info);
|
|
Glide_textures_in_frame += bytes_needed;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int glide_create_texture( int bitmap_handle, int bitmap_type, tcache_slot *tslot )
|
|
{
|
|
int ret;
|
|
ubyte flags;
|
|
bitmap *bmp;
|
|
ubyte bpp = 16;
|
|
|
|
// setup texture/bitmap flags
|
|
flags = 0;
|
|
switch(bitmap_type){
|
|
case TCACHE_TYPE_AABITMAP:
|
|
flags |= BMP_AABITMAP;
|
|
bpp = 8;
|
|
break;
|
|
case TCACHE_TYPE_XPARENT:
|
|
case TCACHE_TYPE_BITMAP_SECTION:
|
|
flags |= BMP_TEX_XPARENT;
|
|
break;
|
|
case TCACHE_TYPE_NORMAL:
|
|
flags |= BMP_TEX_OTHER;
|
|
break;
|
|
case TCACHE_TYPE_NONDARKENING:
|
|
flags |= BMP_TEX_NONDARK;
|
|
break;
|
|
}
|
|
|
|
// lock the bitmap in the proper format
|
|
bmp = bm_lock(bitmap_handle, bpp, flags);
|
|
if ( bmp == NULL ) {
|
|
mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
|
|
return 0;
|
|
}
|
|
|
|
int max_w = bmp->w;
|
|
int max_h = bmp->h;
|
|
|
|
if ( bitmap_type != TCACHE_TYPE_AABITMAP ) {
|
|
// Detail.debris_culling goes from 0 to 4.
|
|
max_w /= 16>>Detail.hardware_textures;
|
|
max_h /= 16>>Detail.hardware_textures;
|
|
}
|
|
|
|
// call the helper
|
|
ret = glide_create_texture_sub(bitmap_type, bitmap_handle, (ushort*)bmp->data, 0, 0, bmp->w, bmp->h, bmp->w, bmp->h, max_w, max_h, tslot);
|
|
|
|
// unlock the bitmap
|
|
bm_unlock(bitmap_handle);
|
|
|
|
// return
|
|
return ret;
|
|
}
|
|
|
|
// create a sectioned texture
|
|
int glide_create_texture_sectioned(int bitmap_handle, int bitmap_type, tcache_slot *tslot, int sx, int sy)
|
|
{
|
|
int ret;
|
|
ubyte flags;
|
|
bitmap *bmp;
|
|
int section_x, section_y;
|
|
|
|
// setup texture/bitmap flags
|
|
Assert(bitmap_type == TCACHE_TYPE_BITMAP_SECTION);
|
|
if(bitmap_type != TCACHE_TYPE_BITMAP_SECTION){
|
|
bitmap_type = TCACHE_TYPE_BITMAP_SECTION;
|
|
}
|
|
flags = BMP_TEX_XPARENT;
|
|
|
|
// lock the bitmap in the proper format
|
|
bmp = bm_lock(bitmap_handle, 16, flags);
|
|
if ( bmp == NULL ) {
|
|
mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
|
|
return 0;
|
|
}
|
|
|
|
// determine the width and height of this section
|
|
bm_get_section_size(bitmap_handle, sx, sy, §ion_x, §ion_y);
|
|
|
|
// call the helper
|
|
ret = glide_create_texture_sub(bitmap_type, bitmap_handle, (ushort*)bmp->data, bmp->sections.sx[sx], bmp->sections.sy[sy], section_x, section_y, bmp->w, bmp->h, section_x, section_y, tslot);
|
|
|
|
// unlock the bitmap
|
|
bm_unlock(bitmap_handle);
|
|
|
|
// return
|
|
return ret;
|
|
}
|
|
|
|
|
|
DCF(exp_flush, "")
|
|
{
|
|
Glide_explosion_vram = 0;
|
|
}
|
|
|
|
extern int bm_get_cache_slot( int bitmap_id, int separate_ani_frames );
|
|
|
|
// Returns FALSE if error
|
|
int glide_tcache_set( int bitmap_id, int bitmap_type, float *u_ratio, float *v_ratio, int fail_on_full, int sx, int sy, int force )
|
|
{
|
|
bitmap *bmp;
|
|
int idx, s_idx;
|
|
|
|
if ( Glide_last_detail != Detail.hardware_textures ) {
|
|
Glide_last_detail = Detail.hardware_textures;
|
|
glide_tcache_flush();
|
|
}
|
|
|
|
// Check if this is the same as the last one... if so, we don't need to
|
|
// do anything.
|
|
if ( (Glide_last_bitmap_id == bitmap_id) && (Glide_last_bitmap_type==bitmap_type) && (Glide_last_section_x == sx) && (Glide_last_section_y == sy) && !force) {
|
|
*u_ratio = Glide_last_u_ratio;
|
|
*v_ratio = Glide_last_v_ratio;
|
|
return 1;
|
|
}
|
|
|
|
int n;
|
|
n = bm_get_cache_slot( bitmap_id, 1 );
|
|
|
|
tcache_slot * t = &Textures[n];
|
|
|
|
// if this is a sectioned bitmap
|
|
if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
|
|
// if the texture sections haven't been created yet
|
|
if((t->bitmap_id < 0) || (t->bitmap_id != bitmap_id) || force){
|
|
|
|
if(t->bitmap_id < 0){
|
|
t->data.vram_offset = 0;
|
|
}
|
|
|
|
// lock the bitmap in the proper format
|
|
bmp = bm_lock(bitmap_id, 16, BMP_TEX_XPARENT);
|
|
bm_unlock(bitmap_id);
|
|
|
|
// first we need to get enough free aux textures
|
|
// AUX
|
|
/*
|
|
for(idx=0; idx<bmp->sections.num_x; idx++){
|
|
for(s_idx=0; s_idx<bmp->sections.num_y; s_idx++){
|
|
// try and get a feww slot
|
|
t->data_sections[idx][s_idx] = glide_get_aux_slot();
|
|
if(t->data_sections[idx][s_idx] == NULL){
|
|
Int3();
|
|
return 0;
|
|
}
|
|
t->data_sections[idx][s_idx]->bitmap_id = bitmap_id;
|
|
}
|
|
}
|
|
*/
|
|
|
|
// now lets do something for each texture
|
|
for(idx=0; idx<bmp->sections.num_x; idx++){
|
|
for(s_idx=0; s_idx<bmp->sections.num_y; s_idx++){
|
|
if(t->bitmap_id < 0){
|
|
t->data_sections[idx][s_idx]->data.vram_offset = 0;
|
|
}
|
|
|
|
t->data_sections[idx][s_idx]->bitmap_id = bitmap_id;
|
|
glide_create_texture_sectioned( bitmap_id, bitmap_type, t->data_sections[idx][s_idx], idx, s_idx);
|
|
}
|
|
}
|
|
|
|
t->bitmap_id = bitmap_id;
|
|
}
|
|
|
|
// swap in the texture we want
|
|
t = t->data_sections[sx][sy];
|
|
}
|
|
// all other "normal" textures
|
|
else {
|
|
// no texture yet
|
|
if ( t->bitmap_id < 0) {
|
|
t->data.vram_offset = 0;
|
|
glide_create_texture( bitmap_id, bitmap_type, t );
|
|
}
|
|
// different bitmap altogether
|
|
else if ( (t->bitmap_id != bitmap_id) || force) {
|
|
glide_create_texture( bitmap_id, bitmap_type, t );
|
|
}
|
|
}
|
|
|
|
*u_ratio = t->uscale;
|
|
*v_ratio = t->vscale;
|
|
|
|
GrTexInfo info;
|
|
|
|
info.smallLod = t->data.lod; //GR_LOD_256;
|
|
info.largeLod = t->data.lod; //GR_LOD_256;
|
|
info.aspectRatio = t->data.aspect; //GR_ASPECT_1x1;
|
|
info.format = t->data.format; //GR_TEXFMT_ARGB_1555;
|
|
info.data = 0; //source data
|
|
|
|
grTexSource( GR_TMU0, t->data.vram_offset, GR_MIPMAPLEVELMASK_BOTH, &info );
|
|
|
|
// Save current state so we don't have to do anything time consuming next time
|
|
// we set this exact same texture
|
|
Glide_last_bitmap_id = bitmap_id;
|
|
Glide_last_bitmap_type = bitmap_type;
|
|
Glide_last_section_x = sx;
|
|
Glide_last_section_y = sy;
|
|
Glide_last_u_ratio = t->uscale;
|
|
Glide_last_v_ratio = t->vscale;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
|
|
|