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;
}
+13
View File
@@ -0,0 +1,13 @@
numlayers 2
layer_0
{
albedo megagen/test/dirt_albedo.tga
mask megagen/white.tga
}
layer_1
{
albedo megagen/test/stones_albedo.tga
mask megagen/test_box/mountain_layer.tga
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

+124
View File
@@ -0,0 +1,124 @@
/*
===========================================================================
IcedTech GPL Source Code
Copyright (C) 2019 Real Vector Math Studios(Justin Marshall).
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 "global.inc"
uniform sampler2D samp0 : register(s0);
uniform sampler2D samp1 : register(s1);
uniform sampler2D samp2 : register(s2);
uniform sampler2D samp3 : register(s3);
uniform sampler2D samp4 : register(s4);
uniform sampler2D samp5 : register(s5);
uniform sampler2D samp6 : register(s6);
uniform sampler2D samp7 : register(s7);
struct PS_IN {
float4 position : VPOS;
float2 texcoord0 : TEXCOORD0;
float2 texcoord1 : TEXCOORD1;
float2 texcoord2 : TEXCOORD2;
float2 texcoord3 : TEXCOORD3;
float2 texcoord4 : TEXCOORD4;
float2 texcoord5 : TEXCOORD5;
float2 texcoord6 : TEXCOORD6;
float4 texcoord7 : TEXCOORD7;
};
struct PS_OUT {
float4 color : COLOR;
};
void main( PS_IN fragment, out PS_OUT result ) {
float4 mask1, mask2;
float4 invMask1, invMask2;
float4 combined;
float2 scaled;
float4 R2;
mask1.x = tex2D(samp0, fragment.texcoord0.xy).x;
mask1.y = tex2D(samp0, fragment.texcoord1.xy).x;
mask1.z = tex2D(samp0, fragment.texcoord2.xy).x;
mask1.w = tex2D(samp0, fragment.texcoord3.xy).x;
mask2.x = tex2D(samp0, fragment.texcoord4.xy).x;
mask2.y = tex2D(samp0, fragment.texcoord5.xy).x;
mask2.z = tex2D(samp0, fragment.texcoord6.xy).x;
mask2.w = 1.0;
invMask1 = 1 - mask1;
invMask2 = 1 - mask2;
combined = float4(0, 0, 0, 0);
scaled = fragment.texcoord7.zw;
// Sample the lowest quality first.
R2 = tex2D(samp1, scaled.xy);
R2.xyz = ConvertYCoCgToRGB(R2);
scaled = scaled * 2;
combined = combined * invMask1.x;
combined = (R2 * mask1.x) + combined;
R2 = tex2D(samp2, scaled.xy);
R2.xyz = ConvertYCoCgToRGB(R2);
scaled = scaled * 2;
combined = combined * invMask1.y;
combined = (R2 * mask1.y) + combined;
R2 = tex2D(samp3, scaled.xy);
R2.xyz = ConvertYCoCgToRGB(R2);
scaled = scaled * 2;
combined = combined * invMask1.z;
combined = (R2 * mask1.z) + combined;
R2 = tex2D(samp4, scaled.xy);
R2.xyz = ConvertYCoCgToRGB(R2);
scaled = scaled * 2;
combined = combined * invMask1.w;
combined = (R2 * mask1.w) + combined;
R2 = tex2D(samp5, scaled.xy);
R2.xyz = ConvertYCoCgToRGB(R2);
scaled = scaled * 2;
combined = combined * invMask2.x;
combined = (R2 * mask2.x) + combined;
R2 = tex2D(samp6, scaled.xy);
R2.xyz = ConvertYCoCgToRGB(R2);
scaled = scaled * 2;
combined = combined * invMask2.y;
combined = (R2 * mask2.y) + combined;
//R2 = tex2D(samp7, scaled.xy);
//R2.xyz = ConvertYCoCgToRGB(R2);
//scaled = scaled * 2;
//combined = combined * invMask2.z;
//combined = (R2 * mask2.z) + combined;
result.color = combined;
}
+70
View File
@@ -0,0 +1,70 @@
/*
===========================================================================
IcedTech GPL Source Code
Copyright (C) 2019 Real Vector Math Studios(Justin Marshall).
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 "global.inc"
struct VS_IN {
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float4 color : COLOR0;
};
struct VS_OUT {
float4 position : POSITION;
float2 texcoord0 : TEXCOORD0;
float2 texcoord1 : TEXCOORD1;
float2 texcoord2 : TEXCOORD2;
float2 texcoord3 : TEXCOORD3;
float2 texcoord4 : TEXCOORD4;
float2 texcoord5 : TEXCOORD5;
float2 texcoord6 : TEXCOORD6;
float4 texcoord7 : TEXCOORD7;
};
void main( VS_IN vertex, out VS_OUT result ) {
result.position.x = dot4( vertex.position, rpMVPmatrixX );
result.position.y = dot4( vertex.position, rpMVPmatrixY );
result.position.z = dot4( vertex.position, rpMVPmatrixZ );
result.position.w = dot4( vertex.position, rpMVPmatrixW );
// Megatexture masks, (texCoord * scale) + offset.
result.texcoord0.xy = (vertex.texcoord * rpMegaTextureLevel0.w) + rpMegaTextureLevel0.xy;
result.texcoord1.xy = (vertex.texcoord * rpMegaTextureLevel1.w) + rpMegaTextureLevel1.xy;
result.texcoord2.xy = (vertex.texcoord * rpMegaTextureLevel2.w) + rpMegaTextureLevel2.xy;
result.texcoord3.xy = (vertex.texcoord * rpMegaTextureLevel3.w) + rpMegaTextureLevel3.xy;
result.texcoord4.xy = (vertex.texcoord * rpMegaTextureLevel4.w) + rpMegaTextureLevel4.xy;
result.texcoord5.xy = (vertex.texcoord * rpMegaTextureLevel5.w) + rpMegaTextureLevel5.xy;
result.texcoord6.xy = (vertex.texcoord * rpMegaTextureLevel6.w) + rpMegaTextureLevel6.xy;
// Images only have scale.
result.texcoord7.xy = vertex.texcoord * rpMegaTextureLevel6.w;
result.texcoord7.zw = vertex.texcoord;
}
+14
View File
@@ -0,0 +1,14 @@
Some people have been asking for the finished Doom 3 megatexture code, so here it is.
Things that still need to be done:
ZLib compression.
Multithreading.
I'm switching over to virtual texturing, so before I remove this code from my codebase, I'm simply archiving it.
This ONLY contains the files related to the Doom 3 MegaTexture implementation I finished.
This will take some effort to get to compile in either vanilla or BFG(in branch I moved a lot of BFG code over to vanilla). but you will have an easier time putting this into the BFG edition.
This depot also contains the MegaGen tool I wrote that allows you to build megatextures pretty easily, but it does need work!
See the megaproject: dkbase/megagen/test_box.megagen