3DMF: Parse txpm chunks

This commit is contained in:
Iliyas Jorio
2021-02-21 17:14:34 +01:00
parent 19ece0fc17
commit 00f4b36f5d
3 changed files with 70 additions and 32 deletions

View File

@@ -11,6 +11,7 @@
#define POMME_DEBUG_FILES false #define POMME_DEBUG_FILES false
#define POMME_DEBUG_RESOURCES false #define POMME_DEBUG_RESOURCES false
#define POMME_DEBUG_INPUT false #define POMME_DEBUG_INPUT false
#define POMME_DEBUG_3DMF false
#define POMME_GENLOG(define, prefix) if (!define) {} else std::cout << "[" << prefix << "] " << __func__ << ":\t" #define POMME_GENLOG(define, prefix) if (!define) {} else std::cout << "[" << prefix << "] " << __func__ << ":\t"
#define POMME_GENLOG_NOPREFIX(define) if (!define) {} else std::cout #define POMME_GENLOG_NOPREFIX(define) if (!define) {} else std::cout

View File

@@ -9,6 +9,12 @@
#include <QD3D/QD3D.h> #include <QD3D/QD3D.h>
#include "Utilities/BigEndianIStream.h" #include "Utilities/BigEndianIStream.h"
struct Q3MetaFileTOCEntry
{
uint64_t offset;
uint32_t chunkType;
};
class Q3MetaFileParser class Q3MetaFileParser
{ {
public: public:
@@ -25,8 +31,8 @@ private:
// Parse attribute array chunk // Parse attribute array chunk
void Parse_atar(uint32_t chunkSize); void Parse_atar(uint32_t chunkSize);
// Parse mipmap texture chunk // Parse mipmap/pixmap texture chunk
uint32_t Parse_txmm(uint32_t chunkSize); uint32_t Parse_txmm_or_txpm(uint32_t chunkType, uint32_t chunkSize);
TQ3MetaFile& metaFile; TQ3MetaFile& metaFile;
std::istream& baseStream; std::istream& baseStream;
@@ -36,7 +42,7 @@ private:
TQ3TriMeshData* currentMesh; TQ3TriMeshData* currentMesh;
std::map<uint32_t, uint64_t> referenceTOC; std::map<uint32_t, Q3MetaFileTOCEntry> referenceTOC;
std::map<std::streampos, uint32_t> knownTextures; std::map<std::streampos, uint32_t> knownTextures;
}; };

View File

@@ -3,8 +3,9 @@
#include "Pomme.h" #include "Pomme.h"
#include "3DMFInternal.h" #include "3DMFInternal.h"
// Comment out the line below to get debug output from the 3DMF parser on stdout #if !(POMME_DEBUG_3DMF)
#define printf(...) do{}while(0) #define printf(...) do{}while(0)
#endif
class Q3MetaFile_EarlyEOFException : public std::exception class Q3MetaFile_EarlyEOFException : public std::exception
{ {
@@ -155,7 +156,8 @@ uint32_t Q3MetaFileParser::Parse1Chunk()
Assert(chunkSize == 0, "illegal txsu size"); Assert(chunkSize == 0, "illegal txsu size");
break; break;
case 'txmm': // MipmapTexture case 'txmm': // MipmapTexture
case 'txpm': // PixmapTexture
{ {
uint32_t internalTextureID; uint32_t internalTextureID;
if (knownTextures.find(chunkOffset) != knownTextures.end()) if (knownTextures.find(chunkOffset) != knownTextures.end())
@@ -166,7 +168,7 @@ uint32_t Q3MetaFileParser::Parse1Chunk()
} }
else else
{ {
internalTextureID = Parse_txmm(chunkSize); internalTextureID = Parse_txmm_or_txpm(chunkType, chunkSize);
knownTextures[chunkOffset] = internalTextureID; knownTextures[chunkOffset] = internalTextureID;
} }
@@ -188,7 +190,7 @@ uint32_t Q3MetaFileParser::Parse1Chunk()
uint32_t target = f.Read<uint32_t>(); uint32_t target = f.Read<uint32_t>();
printf("TOC#%d -----> %08lx", target, referenceTOC.at(target)); printf("TOC#%d -----> %08lx", target, referenceTOC.at(target));
auto jumpBackTo = f.Tell(); auto jumpBackTo = f.Tell();
f.Goto(referenceTOC.at(target)); f.Goto(referenceTOC.at(target).offset);
Parse1Chunk(); Parse1Chunk();
f.Goto(jumpBackTo); f.Goto(jumpBackTo);
break; break;
@@ -217,6 +219,7 @@ void Q3MetaFileParser::Parse3DMF()
uint16_t versionMajor = f.Read<uint16_t>(); uint16_t versionMajor = f.Read<uint16_t>();
uint16_t versionMinor = f.Read<uint16_t>(); uint16_t versionMinor = f.Read<uint16_t>();
Assert(versionMajor == 1 && (versionMinor == 5 || versionMinor == 6), "Unsupported 3DMF version");
uint32_t flags = f.Read<uint32_t>(); uint32_t flags = f.Read<uint32_t>();
Assert(flags == 0, "Database or Stream aren't supported"); Assert(flags == 0, "Database or Stream aren't supported");
@@ -251,7 +254,7 @@ void Q3MetaFileParser::Parse3DMF()
printf("TOC: refID %d '%s' at %08lx\n", refID, Pomme::FourCCString(objType).c_str(), objLocation); printf("TOC: refID %d '%s' at %08lx\n", refID, Pomme::FourCCString(objType).c_str(), objLocation);
referenceTOC[refID] = objLocation; referenceTOC[refID] = {objLocation, objType};
} }
} }
@@ -425,37 +428,67 @@ void Q3MetaFileParser::Parse_atar(uint32_t chunkSize)
} }
} }
uint32_t Q3MetaFileParser::Parse_txmm(uint32_t chunkSize) uint32_t Q3MetaFileParser::Parse_txmm_or_txpm(uint32_t chunkType, uint32_t chunkSize)
{ {
Assert(chunkSize >= 8*4, "incorrect chunk header size"); size_t chunkHeaderSize = chunkType == 'txmm'? 8*4: 7*4;
Assert(chunkSize >= chunkHeaderSize, "incorrect chunk header size");
uint32_t useMipmapping = f.Read<uint32_t>(); uint32_t pixelType;
uint32_t pixelType = f.Read<uint32_t>(); uint32_t bitOrder;
uint32_t bitOrder = f.Read<uint32_t>(); uint32_t byteOrder;
uint32_t byteOrder = f.Read<uint32_t>(); uint32_t width;
uint32_t width = f.Read<uint32_t>(); uint32_t height;
uint32_t height = f.Read<uint32_t>(); uint32_t rowBytes;
uint32_t rowBytes = f.Read<uint32_t>();
uint32_t offset = f.Read<uint32_t>(); if (chunkType == 'txmm')
{
uint32_t useMipmapping = f.Read<uint32_t>();
pixelType = f.Read<uint32_t>();
bitOrder = f.Read<uint32_t>();
byteOrder = f.Read<uint32_t>();
width = f.Read<uint32_t>();
height = f.Read<uint32_t>();
rowBytes = f.Read<uint32_t>();
uint32_t offset = f.Read<uint32_t>();
Assert(!useMipmapping, "mipmapping not supported");
Assert(offset == 0, "unsupported texture offset");
}
else if (chunkType == 'txpm')
{
width = f.Read<uint32_t>();
height = f.Read<uint32_t>();
rowBytes = f.Read<uint32_t>();
f.Skip(4); //pixelSize = f.Read<uint32_t>();
pixelType = f.Read<uint32_t>();
bitOrder = f.Read<uint32_t>();
byteOrder = f.Read<uint32_t>();
}
else
{
Assert(false, "Parse_txmm_or_txpm: Illegal chunkType");
}
uint32_t imageSize = rowBytes * height; uint32_t imageSize = rowBytes * height;
if ((imageSize & 3) != 0) if ((imageSize & 3) != 0)
imageSize = (imageSize & 0xFFFFFFFC) + 4; imageSize = (imageSize & 0xFFFFFFFC) + 4;
Assert(chunkSize == 8*4 + imageSize, "incorrect chunk size"); Assert(chunkSize == chunkHeaderSize + imageSize, "incorrect chunk size");
Assert(bitOrder == kQ3EndianBig, "unsupported bit order");
#if POMME_DEBUG_3DMF
Assert(!useMipmapping, "mipmapping not supported");
printf("%d*%d rb=%d", width, height, rowBytes); printf("%d*%d rb=%d", width, height, rowBytes);
static const char* pixelTypeDescriptions[] = { "RGB32", "ARGB32", "RGB16", "ARGB16", "RGB16_565", "RGB24" }; switch (pixelType)
if (pixelType < kQ3PixelTypeRGB24) {
printf(" %s", pixelTypeDescriptions[pixelType]); case kQ3PixelTypeRGB32: printf(" RGB32"); break;
else case kQ3PixelTypeARGB32: printf(" ARGB32"); break;
printf(" UNKNOWN_PIXELTYPE"); case kQ3PixelTypeRGB16: printf(" RGB16"); break;
case kQ3PixelTypeARGB16: printf(" ARGB16"); break;
Assert(offset == 0, "unsupported texture offset"); case kQ3PixelTypeRGB16_565: printf(" RGB16_565"); break;
Assert(bitOrder == kQ3EndianBig, "unsupported bit order"); case kQ3PixelTypeRGB24: printf(" RGB24"); break;
default: printf(" UnknownPixelType"); break;
}
#endif
// Find bytes per pixel // Find bytes per pixel
int bytesPerPixel = 0; int bytesPerPixel = 0;
@@ -468,8 +501,6 @@ uint32_t Q3MetaFileParser::Parse_txmm(uint32_t chunkSize)
int trimmedRowBytes = bytesPerPixel * width; int trimmedRowBytes = bytesPerPixel * width;
uint32_t newTextureID = metaFile.numTextures; uint32_t newTextureID = metaFile.numTextures;
__Q3EnlargeArray<TQ3Pixmap*>(metaFile.textures, metaFile.numTextures, 'TLST'); __Q3EnlargeArray<TQ3Pixmap*>(metaFile.textures, metaFile.numTextures, 'TLST');