3DMF: Support 'shdr' chunks

This commit is contained in:
Iliyas Jorio 2021-06-24 18:52:31 +02:00
parent f1c5bbae35
commit dfa2fdb0b9
4 changed files with 72 additions and 38 deletions

View File

@ -32,7 +32,9 @@ private:
void Parse_atar(uint32_t chunkSize);
// Parse mipmap/pixmap texture chunk
uint32_t Parse_txmm_or_txpm(uint32_t chunkType, uint32_t chunkSize);
TQ3Pixmap* ParsePixmap(uint32_t chunkType, uint32_t chunkSize);
TQ3TextureShader& GetCurrentTextureShader();
TQ3MetaFile& metaFile;
std::istream& baseStream;

View File

@ -99,8 +99,6 @@ uint32_t Q3MetaFileParser::Parse1Chunk()
case 'endg':
Assert(chunkSize == 0, "illegal endg size");
// Assert(containerEnd == 0, "stray endg");
// containerEnd = f.Tell(); // force while loop to stop
break;
case 'tmsh': // TriMesh
@ -153,22 +151,23 @@ uint32_t Q3MetaFileParser::Parse1Chunk()
break;
case 'txsu': // TextureShader
Assert(chunkSize == 0, "illegal txsu size");
break;
case 'txmm': // MipmapTexture
case 'txpm': // PixmapTexture
{
uint32_t internalTextureID;
Assert(chunkSize == 0, "illegal txsu size");
if (knownTextures.find(chunkOffset) != knownTextures.end())
{
printf("Texture already seen!");
// We've seen this 'txsu' before. We're here because a 'rfrn' refers to it again.
// Don't create a new texture for it.
printf("Already seen this txsu.");
internalTextureID = knownTextures[chunkOffset];
f.Skip(chunkSize);
// TODO: Just skip to end of container
}
else
{
internalTextureID = Parse_txmm_or_txpm(chunkType, chunkSize);
internalTextureID = metaFile.numTextures;
__Q3EnlargeArray(metaFile.textures, metaFile.numTextures, 'TXSU');
knownTextures[chunkOffset] = internalTextureID;
}
@ -184,6 +183,25 @@ uint32_t Q3MetaFileParser::Parse1Chunk()
break;
}
case 'txmm': // MipmapTexture (after a txsu)
case 'txpm': // PixmapTexture (after a txsu)
if (GetCurrentTextureShader().pixmap)
{
printf("Pixmap already set for this txsu\n");
f.Skip(chunkSize);
}
else
{
GetCurrentTextureShader().pixmap = ParsePixmap(chunkType, chunkSize);
}
break;
case 'shdr': // UV clamp/wrap (after a txsu)
Assert(chunkSize == 8, "illegal shdr size");
GetCurrentTextureShader().boundaryU = (TQ3ShaderUVBoundary) f.Read<uint32_t>();
GetCurrentTextureShader().boundaryV = (TQ3ShaderUVBoundary) f.Read<uint32_t>();
break;
case 'rfrn': // Reference (into TOC)
{
Assert(chunkSize == 4, "illegal rfrn size");
@ -276,7 +294,6 @@ void Q3MetaFileParser::Parse3DMF()
printf("\n");
}
void Q3MetaFileParser::Parse_tmsh(uint32_t chunkSize)
{
Assert(chunkSize >= 52, "Illegal tmsh size");
@ -356,7 +373,6 @@ void Q3MetaFileParser::Parse_tmsh(uint32_t chunkSize)
}
}
void Q3MetaFileParser::Parse_atar(uint32_t chunkSize)
{
Assert(chunkSize >= 20, "Illegal atar size");
@ -435,7 +451,7 @@ void Q3MetaFileParser::Parse_atar(uint32_t chunkSize)
}
}
uint32_t Q3MetaFileParser::Parse_txmm_or_txpm(uint32_t chunkType, uint32_t chunkSize)
TQ3Pixmap* Q3MetaFileParser::ParsePixmap(uint32_t chunkType, uint32_t chunkSize)
{
size_t chunkHeaderSize = chunkType == 'txmm'? 8*4: 7*4;
Assert(chunkSize >= chunkHeaderSize, "incorrect chunk header size");
@ -472,7 +488,8 @@ uint32_t Q3MetaFileParser::Parse_txmm_or_txpm(uint32_t chunkType, uint32_t chunk
}
else
{
Assert(false, "Parse_txmm_or_txpm: Illegal chunkType");
Assert(false, "ParsePixmap: Illegal chunkType");
return nullptr;
}
uint32_t imageSize = rowBytes * height;
@ -508,38 +525,38 @@ uint32_t Q3MetaFileParser::Parse_txmm_or_txpm(uint32_t chunkType, uint32_t chunk
int trimmedRowBytes = bytesPerPixel * width;
uint32_t newTextureID = metaFile.numTextures;
TQ3Pixmap* pixmap = __Q3Alloc<TQ3Pixmap>(1, 'PXMP');
__Q3EnlargeArray<TQ3Pixmap*>(metaFile.textures, metaFile.numTextures, 'TLST');
metaFile.textures[newTextureID] = __Q3Alloc<TQ3Pixmap>(1, 'PXMP');
TQ3Pixmap& texture = *metaFile.textures[newTextureID];
texture.pixelType = pixelType;
texture.bitOrder = bitOrder;
texture.byteOrder = byteOrder;
texture.width = width;
texture.height = height;
texture.pixelSize = bytesPerPixel * 8;
texture.rowBytes = trimmedRowBytes;
texture.image = __Q3Alloc<uint8_t>(trimmedRowBytes * height, 'IMAG');
pixmap->pixelType = pixelType;
pixmap->bitOrder = bitOrder;
pixmap->byteOrder = byteOrder;
pixmap->width = width;
pixmap->height = height;
pixmap->pixelSize = bytesPerPixel * 8;
pixmap->rowBytes = trimmedRowBytes;
pixmap->image = __Q3Alloc<uint8_t>(trimmedRowBytes * height, 'IMAG');
// Trim padding at end of rows
for (uint32_t y = 0; y < height; y++)
{
f.Read((Ptr) texture.image + y*texture.rowBytes, texture.rowBytes);
f.Read((Ptr) pixmap->image + y*pixmap->rowBytes, pixmap->rowBytes);
f.Skip(rowBytes - width * bytesPerPixel);
}
// Make every pixel little-endian (especially to avoid breaking 16-bit 1-5-5-5 ARGB textures)
if (byteOrder == kQ3EndianBig)
{
ByteswapInts(bytesPerPixel, width*height, texture.image);
texture.byteOrder = kQ3EndianLittle;
ByteswapInts(bytesPerPixel, width*height, pixmap->image);
pixmap->byteOrder = kQ3EndianLittle;
}
Q3Pixmap_ApplyEdgePadding(pixmap);
Q3Pixmap_ApplyEdgePadding(&texture);
return newTextureID;
return pixmap;
}
TQ3TextureShader& Q3MetaFileParser::GetCurrentTextureShader()
{
Assert(metaFile.numTextures > 0, "txmm/txpm: no txsu opened");
return metaFile.textures[metaFile.numTextures - 1];
}

View File

@ -36,7 +36,7 @@ void Q3MetaFile_Dispose(TQ3MetaFile* metaFile)
__Q3GetCookie(metaFile, '3DMF');
for (int i = 0; i < metaFile->numTextures; i++)
Q3Pixmap_Dispose(metaFile->textures[i]);
Q3Pixmap_Dispose(metaFile->textures[i].pixmap);
for (int i = 0; i < metaFile->numMeshes; i++)
Q3TriMeshData_Dispose(metaFile->meshes[i]);
@ -44,7 +44,7 @@ void Q3MetaFile_Dispose(TQ3MetaFile* metaFile)
for (int i = 0; i < metaFile->numTopLevelGroups; i++)
__Q3Dispose(metaFile->topLevelGroups[i].meshes, 'GMSH');
__Q3Dispose(metaFile->textures, 'TLST');
__Q3Dispose(metaFile->textures, 'TXSU');
__Q3Dispose(metaFile->meshes, 'MLST');
__Q3Dispose(metaFile->topLevelGroups, 'GLST');
__Q3Dispose(metaFile, '3DMF');

View File

@ -46,6 +46,13 @@ typedef enum
kQ3TexturingModeSize32 = 0xFFFFFFFF,
} TQ3TexturingMode;
typedef enum
{
kQ3ShaderUVBoundaryWrap = 0,
kQ3ShaderUVBoundaryClamp = 1,
kQ3ShaderUVBoundarySize32 = 0xFFFFFFFF
} TQ3ShaderUVBoundary;
enum TQ3AttributeTypes
{
kQ3AttributeTypeNone = 0, // N/A
@ -318,11 +325,19 @@ typedef struct TQ3Pixmap
uint32_t byteOrder;
} TQ3Pixmap;
// WARNING: this structure does not exist in QD3D.
typedef struct TQ3TextureShader
{
TQ3Pixmap *pixmap;
TQ3ShaderUVBoundary boundaryU;
TQ3ShaderUVBoundary boundaryV;
} TQ3TextureShader;
// WARNING: this structure does not exist in QD3D.
typedef struct TQ3MetaFile
{
int numTextures;
TQ3Pixmap **textures;
TQ3TextureShader *textures;
int numMeshes;
TQ3TriMeshData **meshes;