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); void Parse_atar(uint32_t chunkSize);
// Parse mipmap/pixmap texture chunk // 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; TQ3MetaFile& metaFile;
std::istream& baseStream; std::istream& baseStream;

View File

@ -99,8 +99,6 @@ uint32_t Q3MetaFileParser::Parse1Chunk()
case 'endg': case 'endg':
Assert(chunkSize == 0, "illegal endg size"); Assert(chunkSize == 0, "illegal endg size");
// Assert(containerEnd == 0, "stray endg");
// containerEnd = f.Tell(); // force while loop to stop
break; break;
case 'tmsh': // TriMesh case 'tmsh': // TriMesh
@ -153,22 +151,23 @@ uint32_t Q3MetaFileParser::Parse1Chunk()
break; break;
case 'txsu': // TextureShader case 'txsu': // TextureShader
Assert(chunkSize == 0, "illegal txsu size");
break;
case 'txmm': // MipmapTexture
case 'txpm': // PixmapTexture
{ {
uint32_t internalTextureID; uint32_t internalTextureID;
Assert(chunkSize == 0, "illegal txsu size");
if (knownTextures.find(chunkOffset) != knownTextures.end()) 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]; internalTextureID = knownTextures[chunkOffset];
f.Skip(chunkSize); // TODO: Just skip to end of container
} }
else else
{ {
internalTextureID = Parse_txmm_or_txpm(chunkType, chunkSize); internalTextureID = metaFile.numTextures;
__Q3EnlargeArray(metaFile.textures, metaFile.numTextures, 'TXSU');
knownTextures[chunkOffset] = internalTextureID; knownTextures[chunkOffset] = internalTextureID;
} }
@ -184,6 +183,25 @@ uint32_t Q3MetaFileParser::Parse1Chunk()
break; 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) case 'rfrn': // Reference (into TOC)
{ {
Assert(chunkSize == 4, "illegal rfrn size"); Assert(chunkSize == 4, "illegal rfrn size");
@ -276,7 +294,6 @@ void Q3MetaFileParser::Parse3DMF()
printf("\n"); printf("\n");
} }
void Q3MetaFileParser::Parse_tmsh(uint32_t chunkSize) void Q3MetaFileParser::Parse_tmsh(uint32_t chunkSize)
{ {
Assert(chunkSize >= 52, "Illegal tmsh size"); Assert(chunkSize >= 52, "Illegal tmsh size");
@ -356,7 +373,6 @@ void Q3MetaFileParser::Parse_tmsh(uint32_t chunkSize)
} }
} }
void Q3MetaFileParser::Parse_atar(uint32_t chunkSize) void Q3MetaFileParser::Parse_atar(uint32_t chunkSize)
{ {
Assert(chunkSize >= 20, "Illegal atar size"); 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; size_t chunkHeaderSize = chunkType == 'txmm'? 8*4: 7*4;
Assert(chunkSize >= chunkHeaderSize, "incorrect chunk header size"); 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 else
{ {
Assert(false, "Parse_txmm_or_txpm: Illegal chunkType"); Assert(false, "ParsePixmap: Illegal chunkType");
return nullptr;
} }
uint32_t imageSize = rowBytes * height; 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; int trimmedRowBytes = bytesPerPixel * width;
uint32_t newTextureID = metaFile.numTextures; TQ3Pixmap* pixmap = __Q3Alloc<TQ3Pixmap>(1, 'PXMP');
__Q3EnlargeArray<TQ3Pixmap*>(metaFile.textures, metaFile.numTextures, 'TLST'); pixmap->pixelType = pixelType;
pixmap->bitOrder = bitOrder;
metaFile.textures[newTextureID] = __Q3Alloc<TQ3Pixmap>(1, 'PXMP'); pixmap->byteOrder = byteOrder;
TQ3Pixmap& texture = *metaFile.textures[newTextureID]; pixmap->width = width;
pixmap->height = height;
texture.pixelType = pixelType; pixmap->pixelSize = bytesPerPixel * 8;
texture.bitOrder = bitOrder; pixmap->rowBytes = trimmedRowBytes;
texture.byteOrder = byteOrder; pixmap->image = __Q3Alloc<uint8_t>(trimmedRowBytes * height, 'IMAG');
texture.width = width;
texture.height = height;
texture.pixelSize = bytesPerPixel * 8;
texture.rowBytes = trimmedRowBytes;
texture.image = __Q3Alloc<uint8_t>(trimmedRowBytes * height, 'IMAG');
// Trim padding at end of rows // Trim padding at end of rows
for (uint32_t y = 0; y < height; y++) 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); f.Skip(rowBytes - width * bytesPerPixel);
} }
// Make every pixel little-endian (especially to avoid breaking 16-bit 1-5-5-5 ARGB textures) // Make every pixel little-endian (especially to avoid breaking 16-bit 1-5-5-5 ARGB textures)
if (byteOrder == kQ3EndianBig) if (byteOrder == kQ3EndianBig)
{ {
ByteswapInts(bytesPerPixel, width*height, texture.image); ByteswapInts(bytesPerPixel, width*height, pixmap->image);
texture.byteOrder = kQ3EndianLittle; pixmap->byteOrder = kQ3EndianLittle;
} }
Q3Pixmap_ApplyEdgePadding(pixmap);
Q3Pixmap_ApplyEdgePadding(&texture); return pixmap;
}
return newTextureID;
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'); __Q3GetCookie(metaFile, '3DMF');
for (int i = 0; i < metaFile->numTextures; i++) 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++) for (int i = 0; i < metaFile->numMeshes; i++)
Q3TriMeshData_Dispose(metaFile->meshes[i]); Q3TriMeshData_Dispose(metaFile->meshes[i]);
@ -44,7 +44,7 @@ void Q3MetaFile_Dispose(TQ3MetaFile* metaFile)
for (int i = 0; i < metaFile->numTopLevelGroups; i++) for (int i = 0; i < metaFile->numTopLevelGroups; i++)
__Q3Dispose(metaFile->topLevelGroups[i].meshes, 'GMSH'); __Q3Dispose(metaFile->topLevelGroups[i].meshes, 'GMSH');
__Q3Dispose(metaFile->textures, 'TLST'); __Q3Dispose(metaFile->textures, 'TXSU');
__Q3Dispose(metaFile->meshes, 'MLST'); __Q3Dispose(metaFile->meshes, 'MLST');
__Q3Dispose(metaFile->topLevelGroups, 'GLST'); __Q3Dispose(metaFile->topLevelGroups, 'GLST');
__Q3Dispose(metaFile, '3DMF'); __Q3Dispose(metaFile, '3DMF');

View File

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