mirror of
https://github.com/jmarshall23/Doom3MegaTexture.git
synced 2026-08-12 08:00:58 +02:00
Initial commit.
This commit is contained in:
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
IcedTech GPL Source Code
|
||||
|
||||
Copyright (C) 2019 Real Vector Math Studios(Justin Marshall).
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the IcedTech GPL Source Code ("IcedTech GPL Source Code").
|
||||
|
||||
IcedTech GPL 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.
|
||||
|
||||
IcedTech GPL 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 IcedTech GPL Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the IcedTech GPL 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 IcedTech GPL 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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
idCVar idMegaTexture::r_megaTextureLevel( "r_megaTextureLevel", "0", CVAR_RENDERER | CVAR_INTEGER, "draw only a specific level" );
|
||||
idCVar idMegaTexture::r_showMegaTexture( "r_showMegaTexture", "0", CVAR_RENDERER | CVAR_BOOL, "display all the level images" );
|
||||
idCVar idMegaTexture::r_showMegaTextureLabels( "r_showMegaTextureLabels", "0", CVAR_RENDERER | CVAR_BOOL, "draw colored blocks in each tile" );
|
||||
idCVar idMegaTexture::r_skipMegaTexture( "r_skipMegaTexture", "0", CVAR_RENDERER | CVAR_INTEGER, "only use the lowest level image" );
|
||||
idCVar idMegaTexture::r_terrainScale( "r_terrainScale", "3", CVAR_RENDERER | CVAR_INTEGER, "vertically scale USGS data" );
|
||||
/*
|
||||
====================
|
||||
idMegaTexture::idMegaTexture
|
||||
====================
|
||||
*/
|
||||
idMegaTexture::idMegaTexture() {
|
||||
albedoLitMegaTextureFile = nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idMegaTexture::~idMegaTexture
|
||||
====================
|
||||
*/
|
||||
idMegaTexture::~idMegaTexture() {
|
||||
if (albedoLitMegaTextureFile != nullptr) {
|
||||
delete albedoLitMegaTextureFile;
|
||||
albedoLitMegaTextureFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
InitFromMegaFile
|
||||
====================
|
||||
*/
|
||||
bool idMegaTexture::InitFromMegaFile( const char *fileBase ) {
|
||||
idStr name = "megaTextures/";
|
||||
idStr megaMaskName;
|
||||
|
||||
name += fileBase;
|
||||
name.StripFileExtension();
|
||||
megaMaskName = name;
|
||||
|
||||
name += ".mega";
|
||||
megaMaskName += "_mask.tga";
|
||||
|
||||
// Open the mega mask image.
|
||||
megaNormalMaskImage = globalImages->ImageFromFile(megaMaskName.c_str(), TF_LINEAR, TR_REPEAT, TD_DIFFUSE, CF_2D);
|
||||
if (megaNormalMaskImage == nullptr) {
|
||||
common->Printf("idMegaTexture: failed to open mega mask %s\n", megaMaskName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load in the megatexture file.
|
||||
albedoLitMegaTextureFile = rvmMegaTextureFile::LoadMegaTextureFile(name);
|
||||
if (albedoLitMegaTextureFile == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
currentTriMapping = NULL;
|
||||
|
||||
// force first bind to load everything
|
||||
currentViewOrigin[0] = -99999999.0f;
|
||||
currentViewOrigin[1] = -99999999.0f;
|
||||
currentViewOrigin[2] = -99999999.0f;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
SetMappingForSurface
|
||||
|
||||
analyzes xyz and st to create a mapping
|
||||
This is not very robust, but works for rectangular grids
|
||||
====================
|
||||
*/
|
||||
void idMegaTexture::SetMappingForSurface( const srfTriangles_t *tri ) {
|
||||
if ( tri == currentTriMapping ) {
|
||||
return;
|
||||
}
|
||||
currentTriMapping = tri;
|
||||
|
||||
if ( !tri->verts ) {
|
||||
return;
|
||||
}
|
||||
// jmarshall - heavily modified this, basically all we care about here is the min/max of the terrain.
|
||||
surfaceBounds = tri->bounds;
|
||||
// jmarshall end
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
BindForViewOrigin
|
||||
====================
|
||||
*/
|
||||
void idMegaTexture::BindForViewOrigin( const idVec3 viewOrigin ) {
|
||||
|
||||
SetViewOrigin( viewOrigin );
|
||||
|
||||
albedoLitMegaTextureFile->BindForViewOrigin(viewOrigin);
|
||||
|
||||
// Bind the mega normal mask image.
|
||||
GL_SelectTexture(7);
|
||||
megaNormalMaskImage->Bind();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
Unbind
|
||||
|
||||
This can go away once everything uses fragment programs so the enable states don't
|
||||
need tracking
|
||||
====================
|
||||
*/
|
||||
void idMegaTexture::Unbind( void ) {
|
||||
for ( int i = 0 ; i < MAX_LEVELS; i++ ) {
|
||||
GL_SelectTexture( 1+i );
|
||||
globalImages->BindNull();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
SetViewOrigin
|
||||
====================
|
||||
*/
|
||||
void idMegaTexture::SetViewOrigin( const idVec3 viewOrigin ) {
|
||||
if ( r_showMegaTextureLabels.IsModified() ) {
|
||||
r_showMegaTextureLabels.ClearModified();
|
||||
currentViewOrigin[0] = viewOrigin[0] + 0.1; // force a change
|
||||
albedoLitMegaTextureFile->Invalidate();
|
||||
}
|
||||
|
||||
if ( viewOrigin == currentViewOrigin ) {
|
||||
return;
|
||||
}
|
||||
if ( r_skipMegaTexture.GetBool() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentViewOrigin = viewOrigin;
|
||||
// jmarshall
|
||||
float texCenter[2];
|
||||
|
||||
// convert the viewOrigin to a texture center, which will
|
||||
// be a different conversion for each megaTexture
|
||||
//for ( int i = 0 ; i < 2 ; i++ ) {
|
||||
// texCenter[i] =
|
||||
// viewOrigin[0] * localViewToTextureCenter[i][0] +
|
||||
// viewOrigin[1] * localViewToTextureCenter[i][1] +
|
||||
// viewOrigin[2] * localViewToTextureCenter[i][2] +
|
||||
// localViewToTextureCenter[i][3];
|
||||
//}
|
||||
|
||||
// TexCenter should be the normalized position between the min and max based on the player position.
|
||||
idVec3 center = surfaceBounds.GetCenter();
|
||||
idVec3 megaViewOrigin = currentViewOrigin - center;
|
||||
idBounds megaBounds;
|
||||
megaBounds[0] = surfaceBounds[0] - center;
|
||||
megaBounds[1] = surfaceBounds[1] - center;
|
||||
|
||||
// Normalize megaViewOrigin between megabounds.
|
||||
texCenter[0] = ((megaViewOrigin[0] - megaBounds[0][0]) / (megaBounds[1][0] - megaBounds[0][0]));
|
||||
texCenter[1] = ((megaViewOrigin[1] - megaBounds[0][1]) / (megaBounds[1][1] - megaBounds[0][1]));
|
||||
|
||||
albedoLitMegaTextureFile->UpdateForCenter(texCenter);
|
||||
// jmarshall end
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
UpdateTile
|
||||
|
||||
A local tile will only be mapped to globalTile[ localTile + X * TILE_PER_LEVEL ] for some x
|
||||
====================
|
||||
*/
|
||||
void idTextureLevel::UpdateTile( int localX, int localY, int globalX, int globalY ) {
|
||||
idTextureTile *tile = &tileMap[localX][localY];
|
||||
|
||||
if ( tile->x == globalX && tile->y == globalY ) {
|
||||
return;
|
||||
}
|
||||
if ( (globalX & (TILE_PER_LEVEL-1)) != localX || (globalY & (TILE_PER_LEVEL-1)) != localY ) {
|
||||
common->Error( "idTextureLevel::UpdateTile: bad coordinate mod" );
|
||||
}
|
||||
|
||||
tile->x = globalX;
|
||||
tile->y = globalY;
|
||||
|
||||
byte data[ TILE_SIZE * TILE_SIZE ];
|
||||
|
||||
if ( globalX >= tilesWide || globalX < 0 || globalY >= tilesHigh || globalY < 0 ) {
|
||||
// off the map
|
||||
memset( data, 0, sizeof( data ) );
|
||||
} else {
|
||||
// extract the data from the full image (FIXME: background load from disk)
|
||||
int tileNum = tileOffset + tile->y * tilesWide + tile->x;
|
||||
|
||||
mega->ReadTile(data, tileNum);
|
||||
}
|
||||
|
||||
if ( idMegaTexture::r_showMegaTextureLabels.GetBool() ) {
|
||||
// put a color marker in it
|
||||
byte color[4] = { 255 * localX / TILE_PER_LEVEL, 255 * localY / TILE_PER_LEVEL, 0, 0 };
|
||||
for ( int x = 0 ; x < 8 ; x++ ) {
|
||||
for ( int y = 0 ; y < 8 ; y++ ) {
|
||||
*(int *)&data[ ( ( y + TILE_SIZE/2 - 4 ) * TILE_SIZE + x + TILE_SIZE/2 - 4 ) ] = *(int *)color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// upload all the mip-map levels
|
||||
int level = 0;
|
||||
int size = TILE_SIZE;
|
||||
glCompressedTexSubImage2D(GL_TEXTURE_2D, level, localX * size, localY * size, size, size, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, size * size, data);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
UpdateForCenter
|
||||
|
||||
Center is in the 0.0 to 1.0 range
|
||||
====================
|
||||
*/
|
||||
void idTextureLevel::UpdateForCenter( float center[2] ) {
|
||||
int globalTileCorner[2];
|
||||
int localTileOffset[2];
|
||||
|
||||
if ( tilesWide <= TILE_PER_LEVEL && tilesHigh <= TILE_PER_LEVEL ) {
|
||||
globalTileCorner[0] = 0;
|
||||
globalTileCorner[1] = 0;
|
||||
localTileOffset[0] = 0;
|
||||
localTileOffset[1] = 0;
|
||||
// orient the mask so that it doesn't mask anything at all
|
||||
parms[0] = 0.25;
|
||||
parms[1] = 0.25;
|
||||
parms[3] = 0.25;
|
||||
} else {
|
||||
for ( int i = 0 ; i < 2 ; i++ ) {
|
||||
float global[2];
|
||||
|
||||
// this value will be outside the 0.0 to 1.0 range unless
|
||||
// we are in the corner of the megaTexture
|
||||
global[i] = ( center[i] * parms[3] - 0.5 ) * TILE_PER_LEVEL;
|
||||
|
||||
globalTileCorner[i] = (int)( global[i] + 0.5 );
|
||||
|
||||
localTileOffset[i] = globalTileCorner[i] & (TILE_PER_LEVEL-1);
|
||||
|
||||
// scaling for the mask texture to only allow the proper window
|
||||
// of tiles to show through
|
||||
parms[i] = -globalTileCorner[i] / (float)TILE_PER_LEVEL;
|
||||
}
|
||||
}
|
||||
|
||||
image->Bind();
|
||||
|
||||
for ( int x = 0 ; x < TILE_PER_LEVEL ; x++ ) {
|
||||
for ( int y = 0 ; y < TILE_PER_LEVEL ; y++ ) {
|
||||
int globalTile[2];
|
||||
|
||||
globalTile[0] = globalTileCorner[0] + ( ( x - localTileOffset[0] ) & (TILE_PER_LEVEL-1) );
|
||||
globalTile[1] = globalTileCorner[1] + ( ( y - localTileOffset[1] ) & (TILE_PER_LEVEL-1) );
|
||||
|
||||
UpdateTile( x, y, globalTile[0], globalTile[1] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
Invalidate
|
||||
|
||||
Forces all tiles to be regenerated
|
||||
=====================
|
||||
*/
|
||||
void idTextureLevel::Invalidate() {
|
||||
for ( int x = 0 ; x < TILE_PER_LEVEL ; x++ ) {
|
||||
for ( int y = 0 ; y < TILE_PER_LEVEL ; y++ ) {
|
||||
tileMap[x][y].x =
|
||||
tileMap[x][y].y = -99999;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
IcedTech GPL Source Code
|
||||
|
||||
Copyright (C) 2019 Real Vector Math Studios(Justin Marshall).
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the IcedTech GPL Source Code ("IcedTech GPL Source Code").
|
||||
|
||||
IcedTech GPL 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.
|
||||
|
||||
IcedTech GPL 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 IcedTech GPL Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the IcedTech GPL 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 IcedTech GPL 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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
struct rvmMegaTextureSourceFile_t
|
||||
{
|
||||
rvmMegaTextureSourceFile_t()
|
||||
{
|
||||
scratch = nullptr;
|
||||
scratch_position = 0;
|
||||
file = nullptr;
|
||||
}
|
||||
~rvmMegaTextureSourceFile_t()
|
||||
{
|
||||
if (scratch)
|
||||
{
|
||||
delete scratch;
|
||||
scratch = nullptr;
|
||||
}
|
||||
if (file)
|
||||
{
|
||||
fileSystem->CloseFile(file);
|
||||
file = nullptr;
|
||||
}
|
||||
|
||||
scratch_position = 0;
|
||||
}
|
||||
|
||||
void AllocScratch(int len)
|
||||
{
|
||||
scratch = new byte[len];
|
||||
scratch_position = 0;
|
||||
}
|
||||
|
||||
void ResetScratch()
|
||||
{
|
||||
scratch_position = 0;
|
||||
}
|
||||
|
||||
byte ReadByte()
|
||||
{
|
||||
return scratch[scratch_position++];
|
||||
}
|
||||
|
||||
idFile *file;
|
||||
int columns;
|
||||
int rows;
|
||||
int fileSize;
|
||||
int numBytes;
|
||||
byte *scratch;
|
||||
int scratch_position;
|
||||
|
||||
TargaHeader targa_header;
|
||||
};
|
||||
|
||||
class idTextureTile {
|
||||
public:
|
||||
int x, y;
|
||||
};
|
||||
|
||||
static const int TILE_PER_LEVEL = 4;
|
||||
static const int MAX_MEGA_CHANNELS = 3; // normal, diffuse, specular
|
||||
static const int MAX_LEVELS = 12;
|
||||
static const int MAX_LEVEL_WIDTH = 1024;
|
||||
static const int TILE_SIZE = MAX_LEVEL_WIDTH / TILE_PER_LEVEL;
|
||||
|
||||
class idMegaTexture;
|
||||
class rvmMegaTextureFile;
|
||||
|
||||
class idTextureLevel {
|
||||
public:
|
||||
rvmMegaTextureFile *mega;
|
||||
|
||||
int tileOffset;
|
||||
int tilesWide;
|
||||
int tilesHigh;
|
||||
|
||||
idImage *image;
|
||||
idTextureTile tileMap[TILE_PER_LEVEL][TILE_PER_LEVEL];
|
||||
|
||||
float parms[4];
|
||||
|
||||
void UpdateForCenter( float center[2] );
|
||||
void UpdateTile( int localX, int localY, int globalX, int globalY );
|
||||
void Invalidate();
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int tileSize;
|
||||
int tilesWide;
|
||||
int tilesHigh;
|
||||
} megaTextureHeader_t;
|
||||
|
||||
// jmarshall
|
||||
class rvmMegaTextureFile {
|
||||
public:
|
||||
~rvmMegaTextureFile();
|
||||
|
||||
// Loads in a mega texture file.
|
||||
static rvmMegaTextureFile *LoadMegaTextureFile(const char *name);
|
||||
|
||||
void UpdateForCenter(float texCenter[2]);
|
||||
void BindForViewOrigin(const idVec3 viewOrigin); // binds images and sets program parameters
|
||||
void Invalidate(void);
|
||||
|
||||
void ReadTile(byte *tileBuffer, int tileNum);
|
||||
public:
|
||||
int numLevels;
|
||||
idTextureLevel levels[MAX_LEVELS]; // 0 is the highest resolution
|
||||
megaTextureHeader_t header;
|
||||
private:
|
||||
rvmMegaTextureFile();
|
||||
|
||||
idFile *fileHandle;
|
||||
};
|
||||
// jmarshall end
|
||||
|
||||
class idMegaTexture {
|
||||
public:
|
||||
idMegaTexture();
|
||||
~idMegaTexture();
|
||||
|
||||
bool InitFromMegaFile( const char *fileBase );
|
||||
void SetMappingForSurface( const srfTriangles_t *tri ); // analyzes xyz and st to create a mapping
|
||||
void BindForViewOrigin( const idVec3 origin ); // binds images and sets program parameters
|
||||
void Unbind(); // removes texture bindings
|
||||
|
||||
static void MakeMegaTexture_f( const idCmdArgs &args );
|
||||
private:
|
||||
friend class idTextureLevel;
|
||||
// jmarshall
|
||||
friend class rvmMegaTextureFile;
|
||||
// jmarshall end
|
||||
void SetViewOrigin( const idVec3 origin );
|
||||
static void GenerateMegaMipMaps( megaTextureHeader_t *header, idFile *file );
|
||||
static void GenerateMegaPreview( const char *fileName );
|
||||
// jmarshall
|
||||
static void ProcessTGABlock(rvmMegaTextureSourceFile_t *file, byte *targa_rgba, TargaHeader &targa_header, int columns, int rows, int scale);
|
||||
static idFile *LoadTGA(const char *name, TargaHeader &targa_header, int &columns, int &rows, int &fileSize, int &numBytes);
|
||||
// jmarshall end
|
||||
|
||||
const srfTriangles_t *currentTriMapping;
|
||||
|
||||
idVec3 currentViewOrigin;
|
||||
// jmarshall
|
||||
// float localViewToTextureCenter[2][4];
|
||||
idBounds surfaceBounds;
|
||||
// jmarshall end
|
||||
|
||||
// jmarshall
|
||||
idImage *megaNormalMaskImage;
|
||||
// jmarshall end
|
||||
|
||||
// jmarshall
|
||||
rvmMegaTextureFile *albedoLitMegaTextureFile;
|
||||
// jmarshall end
|
||||
|
||||
|
||||
static idCVar r_megaTextureLevel;
|
||||
static idCVar r_showMegaTexture;
|
||||
static idCVar r_showMegaTextureLabels;
|
||||
static idCVar r_skipMegaTexture;
|
||||
static idCVar r_terrainScale;
|
||||
|
||||
// jmarshall
|
||||
static idCVar r_megatexture_ambient;
|
||||
// jmarshall end
|
||||
};
|
||||
|
||||
@@ -0,0 +1,587 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
IcedTech GPL Source Code
|
||||
|
||||
Copyright (C) 2019 Real Vector Math Studios(Justin Marshall).
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the IcedTech GPL Source Code ("IcedTech GPL Source Code").
|
||||
|
||||
IcedTech GPL 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.
|
||||
|
||||
IcedTech GPL 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 IcedTech GPL Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the IcedTech GPL 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 IcedTech GPL 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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "tr_local.h"
|
||||
#include "DXT/DXTCodec.h"
|
||||
#include "Color/ColorSpace.h"
|
||||
|
||||
// https://gist.github.com/Alhadis/455346f35286745d8562d24a8764dfa1
|
||||
#define ChannelBlend_Add(B,L) ((byte)(min(255, (B + L))))
|
||||
#define ChannelBlend_Multiply(A,B) ((byte)((A * B) / 255))
|
||||
|
||||
idCVar idMegaTexture::r_megatexture_ambient("r_megatexture_ambient", "20", CVAR_RENDERER | CVAR_INTEGER, "amount of lighting to add to the lit megatexture during building");
|
||||
|
||||
static byte ReadByte(idFile *f) {
|
||||
byte b;
|
||||
|
||||
f->Read(&b, 1);
|
||||
return b;
|
||||
}
|
||||
|
||||
static short ReadShort(idFile *f) {
|
||||
byte b[2];
|
||||
|
||||
f->Read(&b, 2);
|
||||
|
||||
return b[0] + (b[1] << 8);
|
||||
}
|
||||
|
||||
int RoundDownToPowerOfTwo(int num) {
|
||||
int pot;
|
||||
for (pot = 1; (pot * 2) <= num; pot <<= 1) {
|
||||
}
|
||||
return pot;
|
||||
}
|
||||
|
||||
int R_GetTargaBPP(TargaHeader &header) {
|
||||
switch (header.pixel_size)
|
||||
{
|
||||
case 8:
|
||||
return 1;
|
||||
|
||||
case 24:
|
||||
return 3;
|
||||
|
||||
case 32:
|
||||
return 4;
|
||||
}
|
||||
common->FatalError("Mega GetTargetBPP: Unknown BPP\n");
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
GenerateMegaMipMaps
|
||||
====================
|
||||
*/
|
||||
void idMegaTexture::GenerateMegaMipMaps(megaTextureHeader_t *header, idFile *outFile) {
|
||||
outFile->Flush();
|
||||
|
||||
// out fileSystem doesn't allow read / write access...
|
||||
idFile *inFile = fileSystem->OpenFileRead(outFile->GetName());
|
||||
|
||||
int tileOffset = 1;
|
||||
int width = header->tilesWide;
|
||||
int height = header->tilesHigh;
|
||||
|
||||
int tileSize = header->tileSize * header->tileSize * 4;
|
||||
int tileSizeCompressed = header->tileSize * header->tileSize;
|
||||
byte *oldBlock = (byte *)_alloca(tileSize);
|
||||
byte *oldBlockCompressed = (byte *)_alloca(tileSizeCompressed);
|
||||
byte *newBlock = (byte *)_alloca(tileSize);
|
||||
byte *newBlockCompressed = (byte *)_alloca(tileSizeCompressed);
|
||||
|
||||
while (width > 1 || height > 1) {
|
||||
int newHeight = (height + 1) >> 1;
|
||||
if (newHeight < 1) {
|
||||
newHeight = 1;
|
||||
}
|
||||
int newWidth = (width + 1) >> 1;
|
||||
if (width < 1) {
|
||||
width = 1;
|
||||
}
|
||||
common->Printf("generating %i x %i block mip level\n", newWidth, newHeight);
|
||||
|
||||
int tileNum;
|
||||
|
||||
for (int y = 0; y < newHeight; y++) {
|
||||
common->Printf("row %i\n", y);
|
||||
session->UpdateScreen();
|
||||
|
||||
for (int x = 0; x < newWidth; x++) {
|
||||
// mip map four original blocks down into a single new block
|
||||
for (int yy = 0; yy < 2; yy++) {
|
||||
for (int xx = 0; xx < 2; xx++) {
|
||||
int tx = x * 2 + xx;
|
||||
int ty = y * 2 + yy;
|
||||
|
||||
if (tx > width || ty > height) {
|
||||
// off edge, zero fill
|
||||
memset(newBlock, 0, sizeof(newBlock));
|
||||
}
|
||||
else {
|
||||
tileNum = tileOffset + ty * width + tx;
|
||||
inFile->Seek(tileNum * tileSizeCompressed, FS_SEEK_SET);
|
||||
inFile->Read(oldBlockCompressed, tileSizeCompressed);
|
||||
|
||||
idDxtDecoder decoder;
|
||||
decoder.DecompressYCoCgDXT5(oldBlockCompressed, oldBlock, TILE_SIZE, TILE_SIZE);
|
||||
//idColorSpace::ConvertCoCg_YToRGB(oldBlockCompressed, oldBlockCompressed, tileSize, tileSize);
|
||||
|
||||
// R_WriteTGA("test.tga", (const byte *)oldBlock, TILE_SIZE, TILE_SIZE);
|
||||
}
|
||||
// mip map the new pixels
|
||||
for (int yyy = 0; yyy < TILE_SIZE / 2; yyy++) {
|
||||
for (int xxx = 0; xxx < TILE_SIZE / 2; xxx++) {
|
||||
byte *in = &oldBlock[(yyy * 2 * TILE_SIZE + xxx * 2) * 4];
|
||||
byte *out = &newBlock[(((TILE_SIZE / 2 * yy) + yyy) * TILE_SIZE + (TILE_SIZE / 2 * xx) + xxx) * 4];
|
||||
out[0] = (in[0] + in[4] + in[0 + TILE_SIZE * 4] + in[4 + TILE_SIZE * 4]) >> 2;
|
||||
out[1] = (in[1] + in[5] + in[1 + TILE_SIZE * 4] + in[5 + TILE_SIZE * 4]) >> 2;
|
||||
out[2] = (in[2] + in[6] + in[2 + TILE_SIZE * 4] + in[6 + TILE_SIZE * 4]) >> 2;
|
||||
out[3] = (in[3] + in[7] + in[3 + TILE_SIZE * 4] + in[7 + TILE_SIZE * 4]) >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
// write the block out
|
||||
tileNum = tileOffset + width * height + y * newWidth + x;
|
||||
|
||||
|
||||
idDxtEncoder encoder;
|
||||
//idColorSpace::ConvertRGBToCoCg_Y(newBlock, newBlock, TILE_SIZE, TILE_SIZE);
|
||||
encoder.CompressYCoCgDXT5Fast((const byte *)newBlock, newBlockCompressed, TILE_SIZE, TILE_SIZE);
|
||||
outFile->Seek(tileNum * tileSizeCompressed, FS_SEEK_SET);
|
||||
outFile->Write(newBlockCompressed, tileSizeCompressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tileOffset += width * height;
|
||||
width = newWidth;
|
||||
height = newHeight;
|
||||
}
|
||||
|
||||
delete inFile;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
GenerateMegaPreview
|
||||
|
||||
Make a 2k x 2k preview image for a mega texture that can be used in modeling programs
|
||||
====================
|
||||
*/
|
||||
void idMegaTexture::GenerateMegaPreview(const char *fileName) {
|
||||
idFile *fileHandle = fileSystem->OpenFileRead(fileName);
|
||||
if (!fileHandle) {
|
||||
common->Printf("idMegaTexture: failed to open %s\n", fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
idStr outName = fileName;
|
||||
outName.StripFileExtension();
|
||||
outName += "_preview.tga";
|
||||
|
||||
common->Printf("Creating %s.\n", outName.c_str());
|
||||
|
||||
megaTextureHeader_t header;
|
||||
|
||||
fileHandle->Read(&header, sizeof(header));
|
||||
if (header.tileSize < 64 || header.tilesWide < 1 || header.tilesHigh < 1) {
|
||||
common->Printf("idMegaTexture: bad header on %s\n", fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
int tileSize = header.tileSize;
|
||||
int width = header.tilesWide;
|
||||
int height = header.tilesHigh;
|
||||
int tileOffset = 1;
|
||||
int tileBytes = tileSize * tileSize;
|
||||
// find the level that fits
|
||||
while (width * tileSize > 2048 || height * tileSize > 2048) {
|
||||
tileOffset += width * height;
|
||||
width >>= 1;
|
||||
if (width < 1) {
|
||||
width = 1;
|
||||
}
|
||||
height >>= 1;
|
||||
if (height < 1) {
|
||||
height = 1;
|
||||
}
|
||||
}
|
||||
|
||||
byte *pic = (byte *)R_StaticAlloc(width * height * (tileBytes * 4));
|
||||
byte *oldBlock = (byte *)_alloca(tileBytes);
|
||||
byte *oldBlockUncompressed = (byte *)R_StaticAlloc(tileSize * tileSize * 4);
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int tileNum = tileOffset + y * width + x;
|
||||
fileHandle->Seek(tileNum * tileBytes, FS_SEEK_SET);
|
||||
fileHandle->Read(oldBlock, tileBytes);
|
||||
|
||||
idDxtDecoder decoder;
|
||||
decoder.DecompressYCoCgDXT5(oldBlock, oldBlockUncompressed, tileSize, tileSize);
|
||||
idColorSpace::ConvertCoCg_YToRGB(oldBlockUncompressed, oldBlockUncompressed, tileSize, tileSize);
|
||||
|
||||
for (int yy = 0; yy < tileSize; yy++) {
|
||||
memcpy(pic + ((y * tileSize + yy) * width * tileSize + x * tileSize) * 4,
|
||||
oldBlockUncompressed + yy * tileSize * 4, tileSize * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
R_WriteTGA(outName.c_str(), pic, width * tileSize, height * tileSize, false);
|
||||
|
||||
R_StaticFree(oldBlockUncompressed);
|
||||
R_StaticFree(pic);
|
||||
|
||||
delete fileHandle;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idMegaTexture::LoadTGA
|
||||
====================
|
||||
*/
|
||||
idFile *idMegaTexture::LoadTGA(const char *name, TargaHeader &targa_header, int &columns, int &rows, int &fileSize, int &numBytes)
|
||||
{
|
||||
//
|
||||
// open the file
|
||||
//
|
||||
common->Printf("Opening %s.\n", name);
|
||||
fileSize = fileSystem->ReadFile(name, NULL, NULL);
|
||||
idFile *file = fileSystem->OpenFileRead(name);
|
||||
|
||||
if (!file) {
|
||||
common->Printf("Couldn't open %s\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
targa_header.id_length = ReadByte(file);
|
||||
targa_header.colormap_type = ReadByte(file);
|
||||
targa_header.image_type = ReadByte(file);
|
||||
|
||||
targa_header.colormap_index = ReadShort(file);
|
||||
targa_header.colormap_length = ReadShort(file);
|
||||
targa_header.colormap_size = ReadByte(file);
|
||||
targa_header.x_origin = ReadShort(file);
|
||||
targa_header.y_origin = ReadShort(file);
|
||||
targa_header.width = ReadShort(file);
|
||||
targa_header.height = ReadShort(file);
|
||||
targa_header.pixel_size = ReadByte(file);
|
||||
targa_header.attributes = ReadByte(file);
|
||||
|
||||
if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3) {
|
||||
common->Error("LoadTGA( %s ): Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n", name);
|
||||
}
|
||||
|
||||
if (targa_header.colormap_type != 0) {
|
||||
common->Error("LoadTGA( %s ): colormaps not supported\n", name);
|
||||
}
|
||||
|
||||
if ((targa_header.pixel_size != 32 && targa_header.pixel_size != 24) && targa_header.image_type != 3) {
|
||||
common->Error("LoadTGA( %s ): Only 32 or 24 bit images supported (no colormaps)\n", name);
|
||||
}
|
||||
|
||||
//if (targa_header.image_type == 2 || targa_header.image_type == 3) {
|
||||
// numBytes = targa_header.width * targa_header.height * (targa_header.pixel_size >> 3);
|
||||
// if (numBytes > fileSize - 18 - targa_header.id_length) {
|
||||
// common->Error("LoadTGA( %s ): incomplete file\n", name);
|
||||
// }
|
||||
//}
|
||||
|
||||
columns = targa_header.width;
|
||||
rows = targa_header.height;
|
||||
|
||||
// skip TARGA image comment
|
||||
if (targa_header.id_length != 0) {
|
||||
file->Seek(targa_header.id_length, FS_SEEK_CUR);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
idMegaTexture::ProcessTGABlock
|
||||
====================
|
||||
*/
|
||||
void idMegaTexture::ProcessTGABlock(rvmMegaTextureSourceFile_t *file, byte *targa_rgba, TargaHeader &targa_header, int columns, int rows, int scale)
|
||||
{
|
||||
int row, column;
|
||||
byte *pixbuf;
|
||||
byte *startRowPixBuf;
|
||||
|
||||
if (targa_header.image_type == 2 || targa_header.image_type == 3) {
|
||||
// Uncompressed RGB or gray scale image
|
||||
for (row = 0; row < TILE_SIZE * scale; row++) {
|
||||
pixbuf = targa_rgba + row * (columns * scale) * 4;
|
||||
startRowPixBuf = pixbuf;
|
||||
|
||||
for (column = 0; column < columns; column++) {
|
||||
unsigned char red, green, blue, alphabyte;
|
||||
switch (targa_header.pixel_size) {
|
||||
case 8:
|
||||
blue = file->ReadByte();
|
||||
green = blue;
|
||||
red = blue;
|
||||
|
||||
for (int f = 0; f < scale; f++)
|
||||
{
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
}
|
||||
break;
|
||||
|
||||
case 24:
|
||||
blue = file->ReadByte();
|
||||
green = file->ReadByte();
|
||||
red = file->ReadByte();
|
||||
for (int f = 0; f < scale; f++)
|
||||
{
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
blue = file->ReadByte();
|
||||
green = file->ReadByte();
|
||||
red = file->ReadByte();
|
||||
alphabyte = file->ReadByte();
|
||||
for (int f = 0; f < scale; f++)
|
||||
{
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
common->Error("LoadTGA: illegal pixel_size '%d'\n", targa_header.pixel_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are scaling, just duplicate the row!
|
||||
int scale_loop = scale;
|
||||
while (scale_loop > 1)
|
||||
{
|
||||
int64_t rowlength = pixbuf - startRowPixBuf;
|
||||
|
||||
memcpy(pixbuf, startRowPixBuf, rowlength);
|
||||
pixbuf += rowlength;
|
||||
|
||||
row++;
|
||||
scale_loop--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targa_header.image_type == 10) { // Runlength encoded RGB images
|
||||
// jmarshall: I'm not supporting RLE so we can pre-load as much as the image as possible off disc during baking.
|
||||
common->FatalError("MegaTexture ProcessTGABlock: RLE not supported!");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
MakeMegaTexture_f
|
||||
|
||||
Incrementally load a giant tga file and process into the mega texture block format
|
||||
====================
|
||||
*/
|
||||
void idMegaTexture::MakeMegaTexture_f(const idCmdArgs &args) {
|
||||
rvmMegaTextureSourceFile_t albedoSource, litSource;
|
||||
|
||||
if (args.Argc() != 2) {
|
||||
common->Printf("USAGE: makeMegaTexture <filebase>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
idStr name = "megaTextures/";
|
||||
name += args.Argv(1);
|
||||
name.StripFileExtension();
|
||||
name += ".tga";
|
||||
|
||||
idStr albedoName = "megagen/bin/";
|
||||
albedoName += args.Argv(1);
|
||||
albedoName.StripFileExtension();
|
||||
albedoName += ".tga";
|
||||
|
||||
idStr lit_name = "megaTextures/";
|
||||
lit_name += args.Argv(1);
|
||||
lit_name.StripFileExtension();
|
||||
lit_name += "_lit.tga";
|
||||
|
||||
albedoSource.file = idMegaTexture::LoadTGA(albedoName, albedoSource.targa_header, albedoSource.columns, albedoSource.rows, albedoSource.fileSize, albedoSource.numBytes);
|
||||
if (albedoSource.file == nullptr)
|
||||
return;
|
||||
|
||||
litSource.file = idMegaTexture::LoadTGA(lit_name, litSource.targa_header, litSource.columns, litSource.rows, litSource.fileSize, litSource.numBytes);
|
||||
if (litSource.file == nullptr)
|
||||
return;
|
||||
|
||||
megaTextureHeader_t mtHeader;
|
||||
|
||||
mtHeader.tileSize = TILE_SIZE;
|
||||
mtHeader.tilesWide = RoundDownToPowerOfTwo(albedoSource.targa_header.width) / TILE_SIZE;
|
||||
mtHeader.tilesHigh = RoundDownToPowerOfTwo(albedoSource.targa_header.height) / TILE_SIZE;
|
||||
|
||||
idStr outName = name;
|
||||
outName.StripFileExtension();
|
||||
outName += ".mega";
|
||||
|
||||
common->Printf("Writing %i x %i size %i tiles to %s.\n", mtHeader.tilesWide, mtHeader.tilesHigh, mtHeader.tileSize, outName.c_str());
|
||||
|
||||
// open the output megatexture file
|
||||
idFile *out = fileSystem->OpenFileWrite(outName.c_str());
|
||||
|
||||
out->Write(&mtHeader, sizeof(mtHeader));
|
||||
out->Seek(TILE_SIZE * TILE_SIZE, FS_SEEK_SET);
|
||||
|
||||
// we will process this one row of tiles at a time, since the entire thing
|
||||
// won't fit in memory
|
||||
byte *targa_rgba = (byte *)R_StaticAlloc(TILE_SIZE * albedoSource.targa_header.width * 4);
|
||||
byte *targa_compose = (byte *)R_StaticAlloc(TILE_SIZE * albedoSource.targa_header.width * 4);
|
||||
|
||||
int len = (TILE_SIZE * TILE_SIZE + 1) * 4;
|
||||
byte *megaMemory = (byte *)Mem_Alloc(len);
|
||||
//idFile_Memory *megaMemoryTile = new idFile_Memory("mega_memory", (char *)megaMemory, len);
|
||||
|
||||
int currentMegaTilePosition = 0;
|
||||
byte *megaMemoryTile = new byte[len];
|
||||
|
||||
byte *compressed_tile_buffer = (byte *)R_StaticAlloc(TILE_SIZE * TILE_SIZE);
|
||||
|
||||
int albedoSourcebpp = R_GetTargaBPP(albedoSource.targa_header);
|
||||
int litSourcebpp = R_GetTargaBPP(litSource.targa_header);
|
||||
|
||||
int albedoSourceLen = (albedoSource.columns * albedoSourcebpp);
|
||||
albedoSourceLen = albedoSourceLen * TILE_SIZE;
|
||||
|
||||
int litSourceLen = (litSource.columns * litSourcebpp);
|
||||
litSourceLen = litSourceLen * TILE_SIZE;
|
||||
|
||||
albedoSource.AllocScratch(albedoSourceLen);
|
||||
|
||||
int numLitBlocksToSkip = albedoSource.targa_header.width / litSource.targa_header.width;
|
||||
int litSkippedBlocks = 0;
|
||||
|
||||
// Lit source will contain numLitBlocksToSkip if we are scaling!
|
||||
litSource.AllocScratch(litSourceLen);
|
||||
byte *targa_lit = new byte[((TILE_SIZE* numLitBlocksToSkip) * albedoSource.targa_header.width) * 4];
|
||||
|
||||
int blockRowsRemaining = mtHeader.tilesHigh;
|
||||
while (blockRowsRemaining--) {
|
||||
common->Printf("%i blockRowsRemaining\n", blockRowsRemaining);
|
||||
session->UpdateScreen();
|
||||
|
||||
// Do a single big read here, small byte reads off disc are just slow.
|
||||
albedoSource.file->Read(albedoSource.scratch, albedoSourceLen);
|
||||
|
||||
// Process the lit and albedo source images.
|
||||
albedoSource.ResetScratch();
|
||||
ProcessTGABlock(&albedoSource, targa_rgba, albedoSource.targa_header, albedoSource.columns, albedoSource.rows, 1);
|
||||
|
||||
|
||||
// Only load litSource if we need another block.
|
||||
if (numLitBlocksToSkip == 1 || litSkippedBlocks == 0)
|
||||
{
|
||||
litSource.file->Read(litSource.scratch, litSourceLen);
|
||||
|
||||
litSource.ResetScratch();
|
||||
ProcessTGABlock(&litSource, targa_lit, litSource.targa_header, litSource.columns, litSource.rows, numLitBlocksToSkip);
|
||||
}
|
||||
|
||||
// This is to support MegaLight not outputing lightmaps 1:1 with the size of the megatexture albedo.
|
||||
int lightmap_start = ((TILE_SIZE * albedoSource.targa_header.width)) * litSkippedBlocks; //litSourceLen * litSkippedBlocks;
|
||||
for (int i = 0; i < TILE_SIZE * albedoSource.targa_header.width; i++)
|
||||
{
|
||||
int lightmapPosition = lightmap_start + i;
|
||||
|
||||
byte litR = ChannelBlend_Add(targa_lit[(lightmapPosition * 4) + 0], r_megatexture_ambient.GetInteger());
|
||||
byte litG = ChannelBlend_Add(targa_lit[(lightmapPosition * 4) + 1], r_megatexture_ambient.GetInteger());
|
||||
byte litB = ChannelBlend_Add(targa_lit[(lightmapPosition * 4) + 2], r_megatexture_ambient.GetInteger());
|
||||
|
||||
targa_compose[(i * 4) + 0] = ChannelBlend_Multiply(targa_rgba[(i * 4) + 0], litR);
|
||||
targa_compose[(i * 4) + 1] = ChannelBlend_Multiply(targa_rgba[(i * 4) + 1], litG);
|
||||
targa_compose[(i * 4) + 2] = ChannelBlend_Multiply(targa_rgba[(i * 4) + 2], litB);
|
||||
targa_compose[(i * 4) + 3] = 255;
|
||||
}
|
||||
|
||||
if (litSkippedBlocks >= numLitBlocksToSkip - 1) {
|
||||
litSkippedBlocks = 0;
|
||||
}
|
||||
else {
|
||||
litSkippedBlocks++;
|
||||
}
|
||||
|
||||
//
|
||||
// write out individual blocks from the full row block buffer
|
||||
//
|
||||
for (int rowBlock = 0; rowBlock < mtHeader.tilesWide; rowBlock++) {
|
||||
idDxtEncoder encoder;
|
||||
|
||||
//megaMemoryTile->Seek(0, FS_SEEK_SET);
|
||||
currentMegaTilePosition = 0;
|
||||
for (int y = 0; y < TILE_SIZE; y++) {
|
||||
memcpy(&megaMemoryTile[currentMegaTilePosition], targa_compose + (y * albedoSource.targa_header.width + rowBlock * TILE_SIZE) * 4, TILE_SIZE * 4);
|
||||
currentMegaTilePosition += TILE_SIZE * 4;
|
||||
}
|
||||
|
||||
int fileWriteAddress = out->Tell();
|
||||
|
||||
// convert the image data to YCoCg and use the YCoCgDXT5 compressor
|
||||
idColorSpace::ConvertRGBToCoCg_Y((byte *)megaMemoryTile, (byte *)megaMemoryTile, TILE_SIZE, TILE_SIZE);
|
||||
|
||||
encoder.CompressYCoCgDXT5Fast_Generic((const byte *)megaMemoryTile, compressed_tile_buffer, TILE_SIZE, TILE_SIZE);
|
||||
|
||||
//{
|
||||
// idDxtDecoder decoder;
|
||||
// byte *uncompress_test_me = (byte *)_alloca(TILE_SIZE * TILE_SIZE * 4);
|
||||
//
|
||||
// decoder.DecompressImageDXT5(compressed_tile_buffer, uncompress_test_me, TILE_SIZE, TILE_SIZE);
|
||||
// R_WriteTGA("test_compression.tga", uncompress_test_me, TILE_SIZE, TILE_SIZE);
|
||||
//}
|
||||
|
||||
out->Write(compressed_tile_buffer, TILE_SIZE * TILE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
delete megaMemoryTile;
|
||||
delete targa_lit;
|
||||
|
||||
R_StaticFree(targa_rgba);
|
||||
R_StaticFree(targa_compose);
|
||||
R_StaticFree(compressed_tile_buffer);
|
||||
|
||||
GenerateMegaMipMaps(&mtHeader, out);
|
||||
|
||||
delete out;
|
||||
delete albedoSource.file;
|
||||
delete litSource.file;
|
||||
|
||||
GenerateMegaPreview(outName.c_str());
|
||||
#if 0
|
||||
if ((targa_header.attributes & (1 << 5))) { // image flp bit
|
||||
R_VerticalFlip(*pic, *width, *height);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
IcedTech GPL Source Code
|
||||
|
||||
Copyright (C) 2019 Real Vector Math Studios(Justin Marshall).
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the IcedTech GPL Source Code ("IcedTech GPL Source Code").
|
||||
|
||||
IcedTech GPL 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.
|
||||
|
||||
IcedTech GPL 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 IcedTech GPL Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the IcedTech GPL 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 IcedTech GPL 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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
static union {
|
||||
int intVal;
|
||||
byte color[4];
|
||||
} fillColor;
|
||||
|
||||
static byte colors[8][4] = {
|
||||
{ 0, 0, 0, 255 },
|
||||
{ 255, 0, 0, 255 },
|
||||
{ 0, 255, 0, 255 },
|
||||
{ 255, 255, 0, 255 },
|
||||
{ 0, 0, 255, 255 },
|
||||
{ 255, 0, 255, 255 },
|
||||
{ 0, 255, 255, 255 },
|
||||
{ 255, 255, 255, 255 }
|
||||
};
|
||||
|
||||
/*
|
||||
===========================
|
||||
rvmMegaTextureFile::rvmMegaTextureFile
|
||||
===========================
|
||||
*/
|
||||
rvmMegaTextureFile::rvmMegaTextureFile()
|
||||
{
|
||||
fileHandle = nullptr;
|
||||
numLevels = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===========================
|
||||
rvmMegaTextureFile::~rvmMegaTextureFile
|
||||
===========================
|
||||
*/
|
||||
rvmMegaTextureFile::~rvmMegaTextureFile() {
|
||||
if (fileHandle != nullptr) {
|
||||
fileSystem->CloseFile(fileHandle);
|
||||
fileHandle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===========================
|
||||
rvmMegaTextureFile::LoadMegaTextureFile
|
||||
===========================
|
||||
*/
|
||||
rvmMegaTextureFile *rvmMegaTextureFile::LoadMegaTextureFile(const char *name) {
|
||||
int width, height;
|
||||
rvmMegaTextureFile *megaTextureFile = new rvmMegaTextureFile();
|
||||
|
||||
megaTextureFile->fileHandle = fileSystem->OpenFileRead(name);
|
||||
if (!megaTextureFile->fileHandle) {
|
||||
common->Printf("rvmMegaTextureFile: failed to open %s\n", name);
|
||||
delete megaTextureFile;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
megaTextureFile->fileHandle->Read(&megaTextureFile->header, sizeof(megaTextureFile->header));
|
||||
if (megaTextureFile->header.tileSize < 64 || megaTextureFile->header.tilesWide < 1 || megaTextureFile->header.tilesHigh < 1) {
|
||||
common->Printf("idMegaTexture: bad header on %s\n", name);
|
||||
delete megaTextureFile;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
megaTextureFile->numLevels = 0;
|
||||
width = megaTextureFile->header.tilesWide;
|
||||
height = megaTextureFile->header.tilesHigh;
|
||||
|
||||
int tileOffset = 1; // just past the header
|
||||
|
||||
memset(megaTextureFile->levels, 0, sizeof(levels));
|
||||
while (1) {
|
||||
idTextureLevel *level = &megaTextureFile->levels[megaTextureFile->numLevels];
|
||||
|
||||
level->mega = megaTextureFile;
|
||||
level->tileOffset = tileOffset;
|
||||
level->tilesWide = width;
|
||||
level->tilesHigh = height;
|
||||
level->parms[0] = -1; // initially mask everything
|
||||
level->parms[1] = 0;
|
||||
level->parms[2] = 0;
|
||||
level->parms[3] = (float)width / (float)TILE_PER_LEVEL;
|
||||
level->Invalidate();
|
||||
|
||||
tileOffset += level->tilesWide * level->tilesHigh;
|
||||
|
||||
char str[1024];
|
||||
sprintf(str, "_mega_%i", megaTextureFile->numLevels);
|
||||
|
||||
// give each level a default fill color
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fillColor.color[i] = colors[megaTextureFile->numLevels + 1][i];
|
||||
}
|
||||
|
||||
idImageOpts opts;
|
||||
opts.format = FMT_DXT5;
|
||||
opts.colorFormat = CFM_DEFAULT;
|
||||
opts.gammaMips = 0;
|
||||
opts.width = MAX_LEVEL_WIDTH;
|
||||
opts.height = MAX_LEVEL_WIDTH;
|
||||
opts.textureType = TT_2D;
|
||||
opts.isPersistant = true;
|
||||
opts.numMSAASamples = 0;
|
||||
opts.numLevels = 1;
|
||||
|
||||
idTempArray<byte> data(MAX_LEVEL_WIDTH * MAX_LEVEL_WIDTH * 4);
|
||||
|
||||
for (int i = 0; i < MAX_LEVEL_WIDTH * MAX_LEVEL_WIDTH; i++) {
|
||||
((int *)data.Ptr())[i] = fillColor.intVal;
|
||||
}
|
||||
|
||||
megaTextureFile->levels[megaTextureFile->numLevels].image = globalImages->ScratchImage(str, &opts, TF_LINEAR, TR_REPEAT, TD_DIFFUSE);
|
||||
megaTextureFile->levels[megaTextureFile->numLevels].image->UploadScratch(data.Ptr(), MAX_LEVEL_WIDTH, MAX_LEVEL_WIDTH);
|
||||
megaTextureFile->numLevels++;
|
||||
|
||||
if (width <= TILE_PER_LEVEL && height <= TILE_PER_LEVEL) {
|
||||
break;
|
||||
}
|
||||
width = (width + 1) >> 1;
|
||||
height = (height + 1) >> 1;
|
||||
}
|
||||
|
||||
return megaTextureFile;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
rvmMegaTextureFile::ReadTile
|
||||
========================
|
||||
*/
|
||||
void rvmMegaTextureFile::ReadTile(byte *tileBuffer, int tileNum) {
|
||||
int tileSize = TILE_SIZE * TILE_SIZE;
|
||||
|
||||
fileHandle->Seek(tileNum * tileSize, FS_SEEK_SET);
|
||||
//memset(data, 128, sizeof(data));
|
||||
fileHandle->Read(tileBuffer, tileSize);
|
||||
}
|
||||
|
||||
/*
|
||||
===========================
|
||||
rvmMegaTextureFile::UpdateForCenter
|
||||
===========================
|
||||
*/
|
||||
void rvmMegaTextureFile::UpdateForCenter(float texCenter[2]) {
|
||||
for (int i = 0; i < numLevels; i++) {
|
||||
levels[i].UpdateForCenter(texCenter);
|
||||
}
|
||||
}
|
||||
/*
|
||||
===========================
|
||||
rvmMegaTextureFile::Invalidate
|
||||
===========================
|
||||
*/
|
||||
void rvmMegaTextureFile::Invalidate(void) {
|
||||
for (int i = 0; i < numLevels; i++) {
|
||||
levels[i].Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===========================
|
||||
rvmMegaTextureFile::BindForViewOrigin
|
||||
===========================
|
||||
*/
|
||||
void rvmMegaTextureFile::BindForViewOrigin(const idVec3 viewOrigin) {
|
||||
// borderClamp image goes in texture 0
|
||||
GL_SelectTexture(0);
|
||||
globalImages->borderClampImage->Bind();
|
||||
|
||||
// level images in higher textures, blurriest first
|
||||
for (int i = 0; i < 7; i++) {
|
||||
GL_SelectTexture(1 + i);
|
||||
|
||||
if (i >= numLevels) {
|
||||
globalImages->whiteImage->Bind();
|
||||
|
||||
static float parms[4] = { -2, -2, 0, 1 }; // no contribution
|
||||
//glProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, i, parms );
|
||||
renderProgManager.SetUniformValue((const renderParm_t)(RENDERPARM_MEGALEVEL0 + i), parms);
|
||||
}
|
||||
else {
|
||||
idTextureLevel *level = &levels[numLevels - 1 - i];
|
||||
|
||||
if (idMegaTexture::r_showMegaTexture.GetBool()) {
|
||||
if (i & 1) {
|
||||
globalImages->blackImage->Bind();
|
||||
}
|
||||
else {
|
||||
globalImages->whiteImage->Bind();
|
||||
}
|
||||
}
|
||||
else {
|
||||
level->image->Bind();
|
||||
}
|
||||
//glProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, i, level->parms );
|
||||
renderProgManager.SetUniformValue((const renderParm_t)(RENDERPARM_MEGALEVEL0 + i), level->parms);
|
||||
}
|
||||
}
|
||||
|
||||
float parms[4];
|
||||
parms[0] = 0;
|
||||
parms[1] = 0;
|
||||
parms[2] = 0;
|
||||
parms[3] = 1;
|
||||
renderProgManager.SetUniformValue((const renderParm_t)(RENDERPARM_MEGALEVEL0 + 7), parms);
|
||||
//glProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 7, parms );
|
||||
|
||||
//parms[0] = 1;
|
||||
//parms[1] = 1;
|
||||
//parms[2] = r_terrainScale.GetFloat();
|
||||
//parms[3] = 1;
|
||||
//glProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 8, parms );
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
IcedTech GPL Source Code
|
||||
|
||||
Copyright (C) 2019 Real Vector Math Studios(Justin Marshall).
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the IcedTech GPL Source Code ("IcedTech GPL Source Code").
|
||||
|
||||
IcedTech GPL 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.
|
||||
|
||||
IcedTech GPL 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 IcedTech GPL Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the IcedTech GPL 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 IcedTech GPL 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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "MegaGen.h"
|
||||
|
||||
/*
|
||||
===============================================
|
||||
|
||||
MegaGen Tool
|
||||
|
||||
Builds the megatexture source. Why? Because doing it in Photoshop causes computers to explode :).
|
||||
|
||||
===============================================
|
||||
*/
|
||||
|
||||
/*
|
||||
===================
|
||||
WriteTargaHeader
|
||||
===================
|
||||
*/
|
||||
void WriteTargaHeader(idFile *megaTarga, int width, int height)
|
||||
{
|
||||
byte buffer[18];
|
||||
int i;
|
||||
|
||||
memset(buffer, 0, 18);
|
||||
buffer[2] = 2; // uncompressed type
|
||||
buffer[12] = width & 255;
|
||||
buffer[13] = width >> 8;
|
||||
buffer[14] = height & 255;
|
||||
buffer[15] = height >> 8;
|
||||
buffer[16] = 32; // pixel size
|
||||
|
||||
megaTarga->Write(buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
LerpPixel
|
||||
===================
|
||||
*/
|
||||
byte LerpPixel(byte start, byte end, byte mask) {
|
||||
float t = ((float)mask) / 255.0f;
|
||||
|
||||
return (byte)((1 - t)*start + t * end);
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
R_GetMegaLayerImagePixel
|
||||
===================
|
||||
*/
|
||||
byte *R_GetMegaLayerImagePixel(MegaLayerImage_t *layer, int x, int y) {
|
||||
return &layer->data[(y * layer->width * 4) + (x * 4)];
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
EvaluateMegaLayer
|
||||
===================
|
||||
*/
|
||||
void EvaluateMegaLayer(int megaSize, int megaScanLine, MegaLayer *megaLayer, byte *megaScratch) {
|
||||
float maskScanlineScale = (float)megaScanLine / (float)megaSize;
|
||||
|
||||
for (int i = 0; i < megaSize; i++)
|
||||
{
|
||||
int albedoX = i % megaLayer->albedoImage.width;
|
||||
int albedoY = megaScanLine % megaLayer->albedoImage.height;
|
||||
|
||||
float maskColumnScale = (float)i / (float)megaSize;
|
||||
|
||||
int maskX = maskColumnScale * (float)megaLayer->maskImage.width;
|
||||
int maskY = maskScanlineScale * (float)megaLayer->maskImage.height;
|
||||
|
||||
byte *megaLayerAlbedoData = R_GetMegaLayerImagePixel(&megaLayer->albedoImage, albedoX, albedoY);
|
||||
byte *megaLayerMaskData = R_GetMegaLayerImagePixel(&megaLayer->maskImage, maskX, maskY);
|
||||
|
||||
byte mask = megaLayerMaskData[0];
|
||||
|
||||
// Lerp MegaPixel against the current megaScalinePixel based on the mask.
|
||||
megaScratch[(i * 4) + 0] = LerpPixel(megaScratch[(i * 4) + 0], megaLayerAlbedoData[2], mask);
|
||||
megaScratch[(i * 4) + 1] = LerpPixel(megaScratch[(i * 4) + 1], megaLayerAlbedoData[1], mask);
|
||||
megaScratch[(i * 4) + 2] = LerpPixel(megaScratch[(i * 4) + 2], megaLayerAlbedoData[0], mask);
|
||||
megaScratch[(i * 4) + 3] = LerpPixel(megaScratch[(i * 4) + 3], megaLayerAlbedoData[3], mask);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
BuildMegaProject
|
||||
===================
|
||||
*/
|
||||
void BuildMegaProject(int megaSize, idFile *megaTarga, rvmMegaProject &megaProject) {
|
||||
idTempArray<byte> megaTextureScanLine(megaSize * 4);
|
||||
idTempArray<byte> scratchScanLine(megaSize * 4);
|
||||
|
||||
// Write out the targa header
|
||||
WriteTargaHeader(megaTarga, megaSize, megaSize);
|
||||
|
||||
// Walk through each scanline for evaluation.
|
||||
for (int i = 0; i < megaSize; i++)
|
||||
{
|
||||
//common->Printf("Writing scanline %d/%d\n", i, megaSize);
|
||||
|
||||
// Iterate over all the layers.
|
||||
for (int layerId = 0; layerId < megaProject.GetNumMegaLayers(); layerId++)
|
||||
{
|
||||
// Evaluate the mega layer.
|
||||
EvaluateMegaLayer(megaSize, i, megaProject.GetMegaLayer(layerId), scratchScanLine.Ptr());
|
||||
}
|
||||
|
||||
megaTarga->Write(scratchScanLine.Ptr(), megaSize * 4);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
RunMegaGen_f
|
||||
===================
|
||||
*/
|
||||
void RunMegaGen_f(const idCmdArgs &args) {
|
||||
rvmMegaProject megaProject;
|
||||
|
||||
common->SetRefreshOnPrint(true);
|
||||
|
||||
if (args.Argc() < 3) {
|
||||
common->Warning("Usage: megagen <mega_project> <mega_size>\n");
|
||||
common->SetRefreshOnPrint(false);
|
||||
return;
|
||||
}
|
||||
|
||||
idStr megaProjectName = va("megagen/%s.megagen", args.Argv(1));
|
||||
idStr megaTargaName = va("megagen/bin/%s.tga", args.Argv(1));
|
||||
|
||||
idFileScoped megaTarga(fileSystem->OpenFileWrite(megaTargaName));
|
||||
|
||||
int megaSize = atoi(args.Argv(2));
|
||||
|
||||
idParser parser;
|
||||
|
||||
// Read the entire mega project off disk.
|
||||
if (!parser.LoadFile(megaProjectName))
|
||||
{
|
||||
common->Warning("Failed to load megaproject %s\n", megaProjectName.c_str());
|
||||
common->SetRefreshOnPrint(false);
|
||||
return;
|
||||
}
|
||||
|
||||
parser.SetFlags(DECL_LEXER_FLAGS);
|
||||
|
||||
// Parse the mega project.
|
||||
if (!megaProject.ParseProject(parser))
|
||||
{
|
||||
// ParseProject should return what went wrong.
|
||||
common->SetRefreshOnPrint(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Build it!!!!
|
||||
BuildMegaProject(megaSize, megaTarga, megaProject);
|
||||
|
||||
common->Printf("MegaProject built successfully!");
|
||||
|
||||
common->SetRefreshOnPrint(false);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
IcedTech GPL Source Code
|
||||
|
||||
Copyright (C) 2019 Real Vector Math Studios(Justin Marshall).
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the IcedTech GPL Source Code ("IcedTech GPL Source Code").
|
||||
|
||||
IcedTech GPL 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.
|
||||
|
||||
IcedTech GPL 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 IcedTech GPL Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the IcedTech GPL 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 IcedTech GPL 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 once
|
||||
|
||||
//
|
||||
// MegaLayerImage_t
|
||||
//
|
||||
struct MegaLayerImage_t {
|
||||
MegaLayerImage_t()
|
||||
{
|
||||
width = -1;
|
||||
height = -1;
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
~MegaLayerImage_t()
|
||||
{
|
||||
if (data != nullptr)
|
||||
{
|
||||
Mem_Free(data);
|
||||
data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int width;
|
||||
int height;
|
||||
byte *data;
|
||||
};
|
||||
|
||||
//
|
||||
// MegaLayer
|
||||
//
|
||||
struct MegaLayer {
|
||||
MegaLayerImage_t albedoImage;
|
||||
MegaLayerImage_t maskImage;
|
||||
};
|
||||
|
||||
//
|
||||
// rvmMegaProject
|
||||
//
|
||||
class rvmMegaProject {
|
||||
public:
|
||||
rvmMegaProject();
|
||||
~rvmMegaProject();
|
||||
|
||||
// Parsers the project.
|
||||
bool ParseProject(idParser &parser);
|
||||
|
||||
// Returns the megalayer given idx.
|
||||
MegaLayer *GetMegaLayer(int idx) { return megaLayers[idx]; }
|
||||
|
||||
// Returns the number of mega layers in the project.
|
||||
int GetNumMegaLayers(void) const { return megaLayers.Num(); }
|
||||
private:
|
||||
// Parses each layer.
|
||||
bool ParseLayer(MegaLayer *layer, idStr &layerStr);
|
||||
|
||||
private:
|
||||
idList<MegaLayer *> megaLayers;
|
||||
};
|
||||
|
||||
void R_LoadTGA(const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp);
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
IcedTech GPL Source Code
|
||||
|
||||
Copyright (C) 2019 Real Vector Math Studios(Justin Marshall).
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the IcedTech GPL Source Code ("IcedTech GPL Source Code").
|
||||
|
||||
IcedTech GPL 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.
|
||||
|
||||
IcedTech GPL 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 IcedTech GPL Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the IcedTech GPL 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 IcedTech GPL 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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "MegaGen.h"
|
||||
|
||||
/*
|
||||
======================
|
||||
rvmMegaProject::rvmMegaProject
|
||||
======================
|
||||
*/
|
||||
rvmMegaProject::rvmMegaProject()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
======================
|
||||
rvmMegaProject::~rvmMegaProject
|
||||
======================
|
||||
*/
|
||||
rvmMegaProject::~rvmMegaProject()
|
||||
{
|
||||
for (int i = 0; i < megaLayers.Num(); i++)
|
||||
{
|
||||
delete megaLayers[i];
|
||||
}
|
||||
megaLayers.Clear();
|
||||
}
|
||||
|
||||
/*
|
||||
======================
|
||||
rvmMegaProject::ParseLayer
|
||||
======================
|
||||
*/
|
||||
bool rvmMegaProject::ParseLayer(MegaLayer *layer, idStr &layerStr) {
|
||||
idParser parser;
|
||||
idToken token;
|
||||
|
||||
if (!parser.LoadMemory(layerStr, layerStr.Size(), "MegaLayer"))
|
||||
return false;
|
||||
|
||||
parser.SetFlags(DECL_LEXER_FLAGS);
|
||||
|
||||
if (!parser.ExpectTokenString("{")) {
|
||||
common->Warning("MegaLayer expected opening {");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse until EOF
|
||||
while (true)
|
||||
{
|
||||
if (parser.EndOfFile())
|
||||
{
|
||||
common->Warning("Unexpected EOF in MegaLayer!");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.ReadToken(&token);
|
||||
|
||||
if (token == "}")
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Load in the albedo image for this layer.
|
||||
if (token == "albedo")
|
||||
{
|
||||
parser.ReadToken(&token);
|
||||
R_LoadTGA(token, &layer->albedoImage.data, &layer->albedoImage.width, &layer->albedoImage.height, nullptr);
|
||||
if (layer->albedoImage.data == NULL)
|
||||
{
|
||||
common->Warning("Failed to load albedo image %s\n", token.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (token == "mask")
|
||||
{
|
||||
parser.ReadToken(&token);
|
||||
R_LoadTGA(token, &layer->maskImage.data, &layer->maskImage.width, &layer->maskImage.height, nullptr);
|
||||
if (layer->maskImage.data == NULL)
|
||||
{
|
||||
common->Warning("Failed to load albedo image %s\n", token.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
common->Warning("While parsing layer, unknown token %s\n", token.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
======================
|
||||
rvmMegaProject::ParseProject
|
||||
======================
|
||||
*/
|
||||
bool rvmMegaProject::ParseProject(idParser &parser) {
|
||||
int numLayers;
|
||||
|
||||
// Check how many layers we have.
|
||||
if (!parser.ExpectTokenString("numlayers"))
|
||||
{
|
||||
parser.Warning("Expected numlayers token");
|
||||
return false;
|
||||
}
|
||||
numLayers = parser.ParseInt();
|
||||
|
||||
// Parse the layers.
|
||||
for (int i = 0; i < numLayers; i++)
|
||||
{
|
||||
MegaLayer *megaLayer = new MegaLayer();
|
||||
idStr layerStr;
|
||||
|
||||
// Check the layer name.
|
||||
if (!parser.ExpectTokenString(va("layer_%d", i)))
|
||||
{
|
||||
parser.Warning("Layer name invalid or unexpected token!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract the text in the braced section.
|
||||
parser.ParseBracedSectionExact(layerStr);
|
||||
|
||||
// Parse the layer.
|
||||
if (!ParseLayer(megaLayer, layerStr))
|
||||
{
|
||||
parser.Warning("Failed to parse megalayer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the layer to the list.
|
||||
megaLayers.Append(megaLayer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user