mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2026-03-20 00:49:47 +01:00
Initial commit
This commit is contained in:
878
neo/renderer/ImageManager.cpp
Normal file
878
neo/renderer/ImageManager.cpp
Normal file
@@ -0,0 +1,878 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../idlib/precompiled.h"
|
||||
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
// do this with a pointer, in case we want to make the actual manager
|
||||
// a private virtual subclass
|
||||
idImageManager imageManager;
|
||||
idImageManager * globalImages = &imageManager;
|
||||
|
||||
idCVar preLoad_Images( "preLoad_Images", "1", CVAR_SYSTEM | CVAR_BOOL, "preload images during beginlevelload" );
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ReloadImages_f
|
||||
|
||||
Regenerate all images that came directly from files that have changed, so
|
||||
any saved changes will show up in place.
|
||||
|
||||
New r_texturesize/r_texturedepth variables will take effect on reload
|
||||
|
||||
reloadImages <all>
|
||||
===============
|
||||
*/
|
||||
void R_ReloadImages_f( const idCmdArgs &args ) {
|
||||
bool all = false;
|
||||
|
||||
if ( args.Argc() == 2 ) {
|
||||
if ( !idStr::Icmp( args.Argv(1), "all" ) ) {
|
||||
all = true;
|
||||
} else {
|
||||
common->Printf( "USAGE: reloadImages <all>\n" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
globalImages->ReloadImages( all );
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
idImage *image;
|
||||
int size;
|
||||
int index;
|
||||
} sortedImage_t;
|
||||
|
||||
/*
|
||||
=======================
|
||||
R_QsortImageSizes
|
||||
|
||||
=======================
|
||||
*/
|
||||
static int R_QsortImageSizes( const void *a, const void *b ) {
|
||||
const sortedImage_t *ea, *eb;
|
||||
|
||||
ea = (sortedImage_t *)a;
|
||||
eb = (sortedImage_t *)b;
|
||||
|
||||
if ( ea->size > eb->size ) {
|
||||
return -1;
|
||||
}
|
||||
if ( ea->size < eb->size ) {
|
||||
return 1;
|
||||
}
|
||||
return idStr::Icmp( ea->image->GetName(), eb->image->GetName() );
|
||||
}
|
||||
|
||||
/*
|
||||
=======================
|
||||
R_QsortImageName
|
||||
|
||||
=======================
|
||||
*/
|
||||
static int R_QsortImageName( const void* a, const void* b ) {
|
||||
const sortedImage_t *ea, *eb;
|
||||
|
||||
ea = (sortedImage_t *)a;
|
||||
eb = (sortedImage_t *)b;
|
||||
|
||||
return idStr::Icmp( ea->image->GetName(), eb->image->GetName() );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ListImages_f
|
||||
===============
|
||||
*/
|
||||
void R_ListImages_f( const idCmdArgs &args ) {
|
||||
int i, partialSize;
|
||||
idImage *image;
|
||||
int totalSize;
|
||||
int count = 0;
|
||||
bool uncompressedOnly = false;
|
||||
bool unloaded = false;
|
||||
bool failed = false;
|
||||
bool sorted = false;
|
||||
bool duplicated = false;
|
||||
bool overSized = false;
|
||||
bool sortByName = false;
|
||||
|
||||
if ( args.Argc() == 1 ) {
|
||||
|
||||
} else if ( args.Argc() == 2 ) {
|
||||
if ( idStr::Icmp( args.Argv( 1 ), "uncompressed" ) == 0 ) {
|
||||
uncompressedOnly = true;
|
||||
} else if ( idStr::Icmp( args.Argv( 1 ), "sorted" ) == 0 ) {
|
||||
sorted = true;
|
||||
} else if ( idStr::Icmp( args.Argv( 1 ), "namesort" ) == 0 ) {
|
||||
sortByName = true;
|
||||
} else if ( idStr::Icmp( args.Argv( 1 ), "unloaded" ) == 0 ) {
|
||||
unloaded = true;
|
||||
} else if ( idStr::Icmp( args.Argv( 1 ), "duplicated" ) == 0 ) {
|
||||
duplicated = true;
|
||||
} else if ( idStr::Icmp( args.Argv( 1 ), "oversized" ) == 0 ) {
|
||||
sorted = true;
|
||||
overSized = true;
|
||||
} else {
|
||||
failed = true;
|
||||
}
|
||||
} else {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if ( failed ) {
|
||||
common->Printf( "usage: listImages [ sorted | namesort | unloaded | duplicated | showOverSized ]\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
const char *header = " -w-- -h-- filt -fmt-- wrap size --name-------\n";
|
||||
common->Printf( "\n%s", header );
|
||||
|
||||
totalSize = 0;
|
||||
|
||||
sortedImage_t *sortedArray = (sortedImage_t *)alloca( sizeof( sortedImage_t ) * globalImages->images.Num() );
|
||||
|
||||
for ( i = 0 ; i < globalImages->images.Num() ; i++ ) {
|
||||
image = globalImages->images[ i ];
|
||||
|
||||
if ( uncompressedOnly ) {
|
||||
if ( image->IsCompressed() ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ( unloaded == image->IsLoaded() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// only print duplicates (from mismatched wrap / clamp, etc)
|
||||
if ( duplicated ) {
|
||||
int j;
|
||||
for ( j = i+1 ; j < globalImages->images.Num() ; j++ ) {
|
||||
if ( idStr::Icmp( image->GetName(), globalImages->images[ j ]->GetName() ) == 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( j == globalImages->images.Num() ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( sorted || sortByName ) {
|
||||
sortedArray[count].image = image;
|
||||
sortedArray[count].size = image->StorageSize();
|
||||
sortedArray[count].index = i;
|
||||
} else {
|
||||
common->Printf( "%4i:", i );
|
||||
image->Print();
|
||||
}
|
||||
totalSize += image->StorageSize();
|
||||
count++;
|
||||
}
|
||||
|
||||
if ( sorted || sortByName ) {
|
||||
if ( sortByName) {
|
||||
qsort( sortedArray, count, sizeof( sortedImage_t ), R_QsortImageName );
|
||||
} else {
|
||||
qsort( sortedArray, count, sizeof( sortedImage_t ), R_QsortImageSizes );
|
||||
}
|
||||
partialSize = 0;
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
common->Printf( "%4i:", sortedArray[i].index );
|
||||
sortedArray[i].image->Print();
|
||||
partialSize += sortedArray[i].image->StorageSize();
|
||||
if ( ( (i+1) % 10 ) == 0 ) {
|
||||
common->Printf( "-------- %5.1f of %5.1f megs --------\n",
|
||||
partialSize / (1024*1024.0), totalSize / (1024*1024.0) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
common->Printf( "%s", header );
|
||||
common->Printf( " %i images (%i total)\n", count, globalImages->images.Num() );
|
||||
common->Printf( " %5.1f total megabytes of images\n\n\n", totalSize / (1024*1024.0) );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
AllocImage
|
||||
|
||||
Allocates an idImage, adds it to the list,
|
||||
copies the name, and adds it to the hash chain.
|
||||
==============
|
||||
*/
|
||||
idImage *idImageManager::AllocImage( const char *name ) {
|
||||
if (strlen(name) >= MAX_IMAGE_NAME ) {
|
||||
common->Error ("idImageManager::AllocImage: \"%s\" is too long\n", name);
|
||||
}
|
||||
|
||||
int hash = idStr( name ).FileNameHash();
|
||||
|
||||
idImage * image = new (TAG_IMAGE) idImage( name );
|
||||
|
||||
imageHash.Add( hash, images.Append( image ) );
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
AllocStandaloneImage
|
||||
|
||||
Allocates an idImage,does not add it to the list or hash chain
|
||||
|
||||
==============
|
||||
*/
|
||||
idImage *idImageManager::AllocStandaloneImage( const char *name ) {
|
||||
if (strlen(name) >= MAX_IMAGE_NAME ) {
|
||||
common->Error ("idImageManager::AllocImage: \"%s\" is too long\n", name);
|
||||
}
|
||||
|
||||
idImage * image = new (TAG_IMAGE) idImage( name );
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
ImageFromFunction
|
||||
|
||||
Images that are procedurally generated are allways specified
|
||||
with a callback which must work at any time, allowing the OpenGL
|
||||
system to be completely regenerated if needed.
|
||||
==================
|
||||
*/
|
||||
idImage *idImageManager::ImageFromFunction( const char *_name, void (*generatorFunction)( idImage *image ) ) {
|
||||
|
||||
// strip any .tga file extensions from anywhere in the _name
|
||||
idStr name = _name;
|
||||
name.Replace( ".tga", "" );
|
||||
name.BackSlashesToSlashes();
|
||||
|
||||
// see if the image already exists
|
||||
int hash = name.FileNameHash();
|
||||
for ( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) {
|
||||
idImage * image = images[i];
|
||||
if ( name.Icmp( image->GetName() ) == 0 ) {
|
||||
if ( image->generatorFunction != generatorFunction ) {
|
||||
common->DPrintf( "WARNING: reused image %s with mixed generators\n", name.c_str() );
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
// create the image and issue the callback
|
||||
idImage * image = AllocImage( name );
|
||||
|
||||
image->generatorFunction = generatorFunction;
|
||||
|
||||
// check for precompressed, load is from the front end
|
||||
image->referencedOutsideLevelLoad = true;
|
||||
image->ActuallyLoadImage( false );
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
GetImageWithParameters
|
||||
==============
|
||||
*/
|
||||
idImage *idImageManager::GetImageWithParameters( const char *_name, textureFilter_t filter, textureRepeat_t repeat, textureUsage_t usage, cubeFiles_t cubeMap ) const {
|
||||
if ( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) {
|
||||
declManager->MediaPrint( "DEFAULTED\n" );
|
||||
return globalImages->defaultImage;
|
||||
}
|
||||
if ( idStr::Icmpn( _name, "fonts", 5 ) == 0 || idStr::Icmpn( _name, "newfonts", 8 ) == 0 ) {
|
||||
usage = TD_FONT;
|
||||
}
|
||||
if ( idStr::Icmpn( _name, "lights", 6 ) == 0 ) {
|
||||
usage = TD_LIGHT;
|
||||
}
|
||||
// strip any .tga file extensions from anywhere in the _name, including image program parameters
|
||||
idStrStatic< MAX_OSPATH > name = _name;
|
||||
name.Replace( ".tga", "" );
|
||||
name.BackSlashesToSlashes();
|
||||
int hash = name.FileNameHash();
|
||||
for ( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) {
|
||||
idImage * image = images[i];
|
||||
if ( name.Icmp( image->GetName() ) == 0 ) {
|
||||
// the built in's, like _white and _flat always match the other options
|
||||
if ( name[0] == '_' ) {
|
||||
return image;
|
||||
}
|
||||
if ( image->cubeFiles != cubeMap ) {
|
||||
common->Error( "Image '%s' has been referenced with conflicting cube map states", _name );
|
||||
}
|
||||
if ( image->filter != filter || image->repeat != repeat ) {
|
||||
// we might want to have the system reset these parameters on every bind and
|
||||
// share the image data
|
||||
continue;
|
||||
}
|
||||
if ( image->usage != usage ) {
|
||||
// If an image is used differently then we need 2 copies of it because usage affects the way it's compressed and swizzled
|
||||
continue;
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
===============
|
||||
ImageFromFile
|
||||
|
||||
Finds or loads the given image, always returning a valid image pointer.
|
||||
Loading of the image may be deferred for dynamic loading.
|
||||
==============
|
||||
*/
|
||||
idImage *idImageManager::ImageFromFile( const char *_name, textureFilter_t filter,
|
||||
textureRepeat_t repeat, textureUsage_t usage, cubeFiles_t cubeMap ) {
|
||||
|
||||
if ( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) {
|
||||
declManager->MediaPrint( "DEFAULTED\n" );
|
||||
return globalImages->defaultImage;
|
||||
}
|
||||
if ( idStr::Icmpn( _name, "fonts", 5 ) == 0 || idStr::Icmpn( _name, "newfonts", 8 ) == 0 ) {
|
||||
usage = TD_FONT;
|
||||
}
|
||||
if ( idStr::Icmpn( _name, "lights", 6 ) == 0 ) {
|
||||
usage = TD_LIGHT;
|
||||
}
|
||||
|
||||
// strip any .tga file extensions from anywhere in the _name, including image program parameters
|
||||
idStrStatic< MAX_OSPATH > name = _name;
|
||||
name.Replace( ".tga", "" );
|
||||
name.BackSlashesToSlashes();
|
||||
|
||||
//
|
||||
// see if the image is already loaded, unless we
|
||||
// are in a reloadImages call
|
||||
//
|
||||
int hash = name.FileNameHash();
|
||||
for ( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) {
|
||||
idImage * image = images[i];
|
||||
if ( name.Icmp( image->GetName() ) == 0 ) {
|
||||
// the built in's, like _white and _flat always match the other options
|
||||
if ( name[0] == '_' ) {
|
||||
return image;
|
||||
}
|
||||
if ( image->cubeFiles != cubeMap ) {
|
||||
common->Error( "Image '%s' has been referenced with conflicting cube map states", _name );
|
||||
}
|
||||
|
||||
if ( image->filter != filter || image->repeat != repeat ) {
|
||||
// we might want to have the system reset these parameters on every bind and
|
||||
// share the image data
|
||||
continue;
|
||||
}
|
||||
if ( image->usage != usage ) {
|
||||
// If an image is used differently then we need 2 copies of it because usage affects the way it's compressed and swizzled
|
||||
continue;
|
||||
}
|
||||
|
||||
image->usage = usage;
|
||||
image->levelLoadReferenced = true;
|
||||
|
||||
if ( ( !insideLevelLoad || preloadingMapImages ) && !image->IsLoaded() ) {
|
||||
image->referencedOutsideLevelLoad = ( !insideLevelLoad && !preloadingMapImages );
|
||||
image->ActuallyLoadImage( false ); // load is from front end
|
||||
declManager->MediaPrint( "%ix%i %s (reload for mixed referneces)\n", image->GetUploadWidth(), image->GetUploadHeight(), image->GetName() );
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// create a new image
|
||||
//
|
||||
idImage * image = AllocImage( name );
|
||||
image->cubeFiles = cubeMap;
|
||||
image->usage = usage;
|
||||
image->filter = filter;
|
||||
image->repeat = repeat;
|
||||
|
||||
image->levelLoadReferenced = true;
|
||||
|
||||
// load it if we aren't in a level preload
|
||||
if ( !insideLevelLoad || preloadingMapImages ) {
|
||||
image->referencedOutsideLevelLoad = ( !insideLevelLoad && !preloadingMapImages );
|
||||
image->ActuallyLoadImage( false ); // load is from front end
|
||||
declManager->MediaPrint( "%ix%i %s\n", image->GetUploadWidth(), image->GetUploadHeight(), image->GetName() );
|
||||
} else {
|
||||
declManager->MediaPrint( "%s\n", image->GetName() );
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idImageManager::ScratchImage
|
||||
========================
|
||||
*/
|
||||
idImage * idImageManager::ScratchImage( const char *_name, idImageOpts *imgOpts, textureFilter_t filter, textureRepeat_t repeat, textureUsage_t usage ) {
|
||||
if ( !_name || !_name[0] ) {
|
||||
idLib::FatalError( "idImageManager::ScratchImage called with empty name" );
|
||||
}
|
||||
|
||||
if ( imgOpts == NULL ) {
|
||||
idLib::FatalError( "idImageManager::ScratchImage called with NULL imgOpts" );
|
||||
}
|
||||
|
||||
idStr name = _name;
|
||||
|
||||
//
|
||||
// see if the image is already loaded, unless we
|
||||
// are in a reloadImages call
|
||||
//
|
||||
int hash = name.FileNameHash();
|
||||
for ( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) {
|
||||
idImage * image = images[i];
|
||||
if ( name.Icmp( image->GetName() ) == 0 ) {
|
||||
// the built in's, like _white and _flat always match the other options
|
||||
if ( name[0] == '_' ) {
|
||||
return image;
|
||||
}
|
||||
|
||||
if ( image->filter != filter || image->repeat != repeat ) {
|
||||
// we might want to have the system reset these parameters on every bind and
|
||||
// share the image data
|
||||
continue;
|
||||
}
|
||||
if ( image->usage != usage ) {
|
||||
// If an image is used differently then we need 2 copies of it because usage affects the way it's compressed and swizzled
|
||||
continue;
|
||||
}
|
||||
|
||||
image->usage = usage;
|
||||
image->levelLoadReferenced = true;
|
||||
image->referencedOutsideLevelLoad = true;
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
// clamp is the only repeat mode that makes sense for cube maps, but
|
||||
// some platforms let them stay in repeat mode and get border seam issues
|
||||
if ( imgOpts->textureType == TT_CUBIC && repeat != TR_CLAMP ) {
|
||||
repeat = TR_CLAMP;
|
||||
}
|
||||
|
||||
//
|
||||
// create a new image
|
||||
//
|
||||
idImage* newImage = AllocImage( name );
|
||||
if ( newImage != NULL ) {
|
||||
newImage->AllocImage( *imgOpts, filter, repeat );
|
||||
}
|
||||
return newImage;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idImageManager::GetImage
|
||||
===============
|
||||
*/
|
||||
idImage *idImageManager::GetImage( const char *_name ) const {
|
||||
|
||||
if ( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) {
|
||||
declManager->MediaPrint( "DEFAULTED\n" );
|
||||
return globalImages->defaultImage;
|
||||
}
|
||||
|
||||
// strip any .tga file extensions from anywhere in the _name, including image program parameters
|
||||
idStr name = _name;
|
||||
name.Replace( ".tga", "" );
|
||||
name.BackSlashesToSlashes();
|
||||
|
||||
//
|
||||
// look in loaded images
|
||||
//
|
||||
int hash = name.FileNameHash();
|
||||
for ( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) {
|
||||
idImage * image = images[i];
|
||||
if ( name.Icmp( image->GetName() ) == 0 ) {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
PurgeAllImages
|
||||
===============
|
||||
*/
|
||||
void idImageManager::PurgeAllImages() {
|
||||
int i;
|
||||
idImage *image;
|
||||
|
||||
for ( i = 0; i < images.Num() ; i++ ) {
|
||||
image = images[i];
|
||||
image->PurgeImage();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
ReloadImages
|
||||
===============
|
||||
*/
|
||||
void idImageManager::ReloadImages( bool all ) {
|
||||
for ( int i = 0 ; i < globalImages->images.Num() ; i++ ) {
|
||||
globalImages->images[ i ]->Reload( all );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_CombineCubeImages_f
|
||||
|
||||
Used to combine animations of six separate tga files into
|
||||
a serials of 6x taller tga files, for preparation to roq compress
|
||||
===============
|
||||
*/
|
||||
void R_CombineCubeImages_f( const idCmdArgs &args ) {
|
||||
if ( args.Argc() != 2 ) {
|
||||
common->Printf( "usage: combineCubeImages <baseName>\n" );
|
||||
common->Printf( " combines basename[1-6][0001-9999].tga to basenameCM[0001-9999].tga\n" );
|
||||
common->Printf( " 1: forward 2:right 3:back 4:left 5:up 6:down\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
idStr baseName = args.Argv( 1 );
|
||||
common->SetRefreshOnPrint( true );
|
||||
|
||||
for ( int frameNum = 1 ; frameNum < 10000 ; frameNum++ ) {
|
||||
char filename[MAX_IMAGE_NAME];
|
||||
byte *pics[6];
|
||||
int width = 0, height = 0;
|
||||
int side;
|
||||
int orderRemap[6] = { 1,3,4,2,5,6 };
|
||||
for ( side = 0 ; side < 6 ; side++ ) {
|
||||
sprintf( filename, "%s%i%04i.tga", baseName.c_str(), orderRemap[side], frameNum );
|
||||
|
||||
common->Printf( "reading %s\n", filename );
|
||||
R_LoadImage( filename, &pics[side], &width, &height, NULL, true );
|
||||
|
||||
if ( !pics[side] ) {
|
||||
common->Printf( "not found.\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
// convert from "camera" images to native cube map images
|
||||
switch( side ) {
|
||||
case 0: // forward
|
||||
R_RotatePic( pics[side], width);
|
||||
break;
|
||||
case 1: // back
|
||||
R_RotatePic( pics[side], width);
|
||||
R_HorizontalFlip( pics[side], width, height );
|
||||
R_VerticalFlip( pics[side], width, height );
|
||||
break;
|
||||
case 2: // left
|
||||
R_VerticalFlip( pics[side], width, height );
|
||||
break;
|
||||
case 3: // right
|
||||
R_HorizontalFlip( pics[side], width, height );
|
||||
break;
|
||||
case 4: // up
|
||||
R_RotatePic( pics[side], width);
|
||||
break;
|
||||
case 5: // down
|
||||
R_RotatePic( pics[side], width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( side != 6 ) {
|
||||
for ( int i = 0 ; i < side ; side++ ) {
|
||||
Mem_Free( pics[side] );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
idTempArray<byte> buf( width*height*6*4 );
|
||||
byte *combined = (byte *)buf.Ptr();
|
||||
for ( side = 0 ; side < 6 ; side++ ) {
|
||||
memcpy( combined+width*height*4*side, pics[side], width*height*4 );
|
||||
Mem_Free( pics[side] );
|
||||
}
|
||||
sprintf( filename, "%sCM%04i.tga", baseName.c_str(), frameNum );
|
||||
|
||||
common->Printf( "writing %s\n", filename );
|
||||
R_WriteTGA( filename, combined, width, height*6 );
|
||||
}
|
||||
common->SetRefreshOnPrint( false );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
UnbindAll
|
||||
===============
|
||||
*/
|
||||
void idImageManager::UnbindAll() {
|
||||
int oldTMU = backEnd.glState.currenttmu;
|
||||
for ( int i = 0; i < MAX_PROG_TEXTURE_PARMS; ++i ) {
|
||||
backEnd.glState.currenttmu = i;
|
||||
BindNull();
|
||||
}
|
||||
backEnd.glState.currenttmu = oldTMU;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
BindNull
|
||||
===============
|
||||
*/
|
||||
void idImageManager::BindNull() {
|
||||
RENDERLOG_PRINTF( "BindNull()\n" );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Init
|
||||
===============
|
||||
*/
|
||||
void idImageManager::Init() {
|
||||
|
||||
images.Resize( 1024, 1024 );
|
||||
imageHash.ResizeIndex( 1024 );
|
||||
|
||||
CreateIntrinsicImages();
|
||||
|
||||
cmdSystem->AddCommand( "reloadImages", R_ReloadImages_f, CMD_FL_RENDERER, "reloads images" );
|
||||
cmdSystem->AddCommand( "listImages", R_ListImages_f, CMD_FL_RENDERER, "lists images" );
|
||||
cmdSystem->AddCommand( "combineCubeImages", R_CombineCubeImages_f, CMD_FL_RENDERER, "combines six images for roq compression" );
|
||||
|
||||
// should forceLoadImages be here?
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Shutdown
|
||||
===============
|
||||
*/
|
||||
void idImageManager::Shutdown() {
|
||||
images.DeleteContents( true );
|
||||
imageHash.Clear();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idImageManager::BeginLevelLoad
|
||||
Frees all images used by the previous level
|
||||
====================
|
||||
*/
|
||||
void idImageManager::BeginLevelLoad() {
|
||||
insideLevelLoad = true;
|
||||
|
||||
for ( int i = 0 ; i < images.Num() ; i++ ) {
|
||||
idImage *image = images[ i ];
|
||||
|
||||
// generator function images are always kept around
|
||||
if ( image->generatorFunction ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !image->referencedOutsideLevelLoad && image->IsLoaded() ) {
|
||||
image->PurgeImage();
|
||||
//idLib::Printf( "purging %s\n", image->GetName() );
|
||||
} else {
|
||||
//idLib::Printf( "not purging %s\n", image->GetName() );
|
||||
}
|
||||
|
||||
image->levelLoadReferenced = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
idImageManager::ExcludePreloadImage
|
||||
====================
|
||||
*/
|
||||
bool idImageManager::ExcludePreloadImage( const char *name ) {
|
||||
idStrStatic< MAX_OSPATH > imgName = name;
|
||||
imgName.ToLower();
|
||||
if ( imgName.Find( "newfonts/", false ) >= 0 ) {
|
||||
return true;
|
||||
}
|
||||
if ( imgName.Find( "generated/swf/", false ) >= 0 ) {
|
||||
return true;
|
||||
}
|
||||
if ( imgName.Find( "/loadscreens/", false ) >= 0 ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idImageManager::Preload
|
||||
====================
|
||||
*/
|
||||
void idImageManager::Preload( const idPreloadManifest &manifest, const bool & mapPreload ) {
|
||||
if ( preLoad_Images.GetBool() && manifest.NumResources() > 0 ) {
|
||||
// preload this levels images
|
||||
common->Printf( "Preloading images...\n" );
|
||||
preloadingMapImages = mapPreload;
|
||||
int start = Sys_Milliseconds();
|
||||
int numLoaded = 0;
|
||||
|
||||
//fileSystem->StartPreload( preloadImageFiles );
|
||||
for ( int i = 0; i < manifest.NumResources(); i++ ) {
|
||||
const preloadEntry_s & p = manifest.GetPreloadByIndex( i );
|
||||
if ( p.resType == PRELOAD_IMAGE && !ExcludePreloadImage( p.resourceName ) ) {
|
||||
globalImages->ImageFromFile( p.resourceName, ( textureFilter_t )p.imgData.filter, ( textureRepeat_t )p.imgData.repeat, ( textureUsage_t )p.imgData.usage, ( cubeFiles_t )p.imgData.cubeMap );
|
||||
numLoaded++;
|
||||
}
|
||||
}
|
||||
//fileSystem->StopPreload();
|
||||
int end = Sys_Milliseconds();
|
||||
common->Printf( "%05d images preloaded ( or were already loaded ) in %5.1f seconds\n", numLoaded, ( end - start ) * 0.001 );
|
||||
common->Printf( "----------------------------------------\n" );
|
||||
preloadingMapImages = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idImageManager::LoadLevelImages
|
||||
===============
|
||||
*/
|
||||
int idImageManager::LoadLevelImages( bool pacifier ) {
|
||||
int loadCount = 0;
|
||||
for ( int i = 0 ; i < images.Num() ; i++ ) {
|
||||
if ( pacifier ) {
|
||||
common->UpdateLevelLoadPacifier();
|
||||
|
||||
}
|
||||
|
||||
idImage *image = images[ i ];
|
||||
if ( image->generatorFunction ) {
|
||||
continue;
|
||||
}
|
||||
if ( image->levelLoadReferenced && !image->IsLoaded() ) {
|
||||
loadCount++;
|
||||
image->ActuallyLoadImage( false );
|
||||
}
|
||||
}
|
||||
return loadCount;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idImageManager::EndLevelLoad
|
||||
===============
|
||||
*/
|
||||
void idImageManager::EndLevelLoad() {
|
||||
insideLevelLoad = false;
|
||||
|
||||
common->Printf( "----- idImageManager::EndLevelLoad -----\n" );
|
||||
int start = Sys_Milliseconds();
|
||||
int loadCount = LoadLevelImages( true );
|
||||
|
||||
int end = Sys_Milliseconds();
|
||||
common->Printf( "%5i images loaded in %5.1f seconds\n", loadCount, (end-start) * 0.001 );
|
||||
common->Printf( "----------------------------------------\n" );
|
||||
//R_ListImages_f( idCmdArgs( "sorted sorted", false ) );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idImageManager::StartBuild
|
||||
===============
|
||||
*/
|
||||
void idImageManager::StartBuild() {
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idImageManager::FinishBuild
|
||||
===============
|
||||
*/
|
||||
void idImageManager::FinishBuild( bool removeDups ) {
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idImageManager::PrintMemInfo
|
||||
===============
|
||||
*/
|
||||
void idImageManager::PrintMemInfo( MemInfo_t *mi ) {
|
||||
int i, j, total = 0;
|
||||
int *sortIndex;
|
||||
idFile *f;
|
||||
|
||||
f = fileSystem->OpenFileWrite( mi->filebase + "_images.txt" );
|
||||
if ( !f ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// sort first
|
||||
sortIndex = new (TAG_IMAGE) int[images.Num()];
|
||||
|
||||
for ( i = 0; i < images.Num(); i++ ) {
|
||||
sortIndex[i] = i;
|
||||
}
|
||||
|
||||
for ( i = 0; i < images.Num() - 1; i++ ) {
|
||||
for ( j = i + 1; j < images.Num(); j++ ) {
|
||||
if ( images[sortIndex[i]]->StorageSize() < images[sortIndex[j]]->StorageSize() ) {
|
||||
int temp = sortIndex[i];
|
||||
sortIndex[i] = sortIndex[j];
|
||||
sortIndex[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print next
|
||||
for ( i = 0; i < images.Num(); i++ ) {
|
||||
idImage *im = images[sortIndex[i]];
|
||||
int size;
|
||||
|
||||
size = im->StorageSize();
|
||||
total += size;
|
||||
|
||||
f->Printf( "%s %3i %s\n", idStr::FormatNumber( size ).c_str(), im->refCount, im->GetName() );
|
||||
}
|
||||
|
||||
delete [] sortIndex;
|
||||
mi->imageAssetsTotal = total;
|
||||
|
||||
f->Printf( "\nTotal image bytes allocated: %s\n", idStr::FormatNumber( total ).c_str() );
|
||||
fileSystem->CloseFile( f );
|
||||
}
|
||||
Reference in New Issue
Block a user