Initial commit.

This commit is contained in:
Justin Marshall
2019-09-27 07:04:44 +01:00
commit 3be9600a12
13 changed files with 2020 additions and 0 deletions
+318
View File
@@ -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;
}
}
}
+195
View File
@@ -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
};
+587
View File
@@ -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
}
+245
View File
@@ -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 );
}
+195
View File
@@ -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);
}
+90
View File
@@ -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;
}