Add libgfd.

This commit is contained in:
James Benton 2017-05-07 01:38:01 +01:00
parent d0dab12160
commit fcafa791b3
3 changed files with 1069 additions and 0 deletions

View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.2)
project(libgfd)
add_library(gfd src/libgfd.c)
target_include_directories(gfd PRIVATE "../../include")
target_include_directories(gfd PUBLIC "include")
install(TARGETS gfd ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib")

204
src/libgfd/include/libgfd.h Normal file
View File

@ -0,0 +1,204 @@
#pragma once
#include <wut.h>
#include <gx2/shaders.h>
#include <gx2/texture.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct GFDHeader GFDHeader;
typedef struct GFDBlockHeader GFDBlockHeader;
typedef struct GFDRelocationHeader GFDRelocationHeader;
#define GFD_HEADER_MAGIC (0x47667832)
#define GFD_BLOCK_HEADER_MAGIC (0x424C4B7B)
#define GFD_RELOCATION_HEADER_MAGIC (0x7D424C4B)
#define GFD_FILE_VERSION_MAJOR (7)
#define GFD_FILE_VERSION_MINOR (1)
#define GFD_BLOCK_VERSION_MAJOR (1)
#define GFD_PATCH_MASK (0xFFF00000)
#define GFD_PATCH_DATA (0xD0600000)
#define GFD_PATCH_TEXT (0xCA700000)
typedef enum GFDBlockType
{
GFD_BLOCK_END_OF_FILE = 1,
GFD_BLOCK_PADDING = 2,
GFD_BLOCK_VERTEX_SHADER_HEADER = 3,
GFD_BLOCK_VERTEX_SHADER_PROGRAM = 5,
GFD_BLOCK_PIXEL_SHADER_HEADER = 6,
GFD_BLOCK_PIXEL_SHADER_PROGRAM = 7,
GFD_BLOCK_GEOMETRY_SHADER_HEADER = 8,
GFD_BLOCK_GEOMETRY_SHADER_PROGRAM = 9,
GFD_BLOCK_GEOMETRY_SHADER_COPY_PROGRAM = 10,
GFD_BLOCK_TEXTURE_HEADER = 11,
GFD_BLOCK_TEXTURE_IMAGE = 12,
GFD_BLOCK_TEXTURE_MIPMAP = 13,
GFD_BLOCK_COMPUTE_SHADER_HEADER = 14,
GFD_BLOCK_COMPUTE_SHADER_PROGRAM = 15,
} GFDBlockType;
struct GFDHeader
{
uint32_t magic;
uint32_t headerSize;
uint32_t majorVersion;
uint32_t minorVersion;
uint32_t gpuVersion;
uint32_t align;
uint32_t unk1;
uint32_t unk2;
};
CHECK_OFFSET(GFDHeader, 0x00, magic);
CHECK_OFFSET(GFDHeader, 0x04, headerSize);
CHECK_OFFSET(GFDHeader, 0x08, majorVersion);
CHECK_OFFSET(GFDHeader, 0x0C, minorVersion);
CHECK_OFFSET(GFDHeader, 0x10, gpuVersion);
CHECK_OFFSET(GFDHeader, 0x14, align);
CHECK_OFFSET(GFDHeader, 0x18, unk1);
CHECK_OFFSET(GFDHeader, 0x1C, unk2);
CHECK_SIZE(GFDHeader, 0x20);
struct GFDBlockHeader
{
uint32_t magic;
uint32_t headerSize;
uint32_t majorVersion;
uint32_t minorVersion;
GFDBlockType type;
uint32_t dataSize;
uint32_t id;
uint32_t index;
};
CHECK_OFFSET(GFDBlockHeader, 0x00, magic);
CHECK_OFFSET(GFDBlockHeader, 0x04, headerSize);
CHECK_OFFSET(GFDBlockHeader, 0x08, majorVersion);
CHECK_OFFSET(GFDBlockHeader, 0x0C, minorVersion);
CHECK_OFFSET(GFDBlockHeader, 0x10, type);
CHECK_OFFSET(GFDBlockHeader, 0x14, dataSize);
CHECK_OFFSET(GFDBlockHeader, 0x18, id);
CHECK_OFFSET(GFDBlockHeader, 0x1C, index);
CHECK_SIZE(GFDHeader, 0x20);
struct GFDRelocationHeader
{
uint32_t magic;
uint32_t headerSize;
uint32_t unk1;
uint32_t dataSize;
uint32_t dataOffset;
uint32_t textSize;
uint32_t textOffset;
uint32_t patchBase;
uint32_t patchCount;
uint32_t patchOffset;
};
CHECK_OFFSET(GFDRelocationHeader, 0x00, magic);
CHECK_OFFSET(GFDRelocationHeader, 0x04, headerSize);
CHECK_OFFSET(GFDRelocationHeader, 0x08, unk1);
CHECK_OFFSET(GFDRelocationHeader, 0x0C, dataSize);
CHECK_OFFSET(GFDRelocationHeader, 0x10, dataOffset);
CHECK_OFFSET(GFDRelocationHeader, 0x14, textSize);
CHECK_OFFSET(GFDRelocationHeader, 0x18, textOffset);
CHECK_OFFSET(GFDRelocationHeader, 0x1C, patchBase);
CHECK_OFFSET(GFDRelocationHeader, 0x20, patchCount);
CHECK_OFFSET(GFDRelocationHeader, 0x24, patchOffset);
CHECK_SIZE(GFDRelocationHeader, 0x28);
uint32_t
GFDGetGeometryShaderCount(const void *file);
uint32_t
GFDGetGeometryShaderHeaderSize(uint32_t index,
const void *file);
uint32_t
GFDGetGeometryShaderProgramSize(uint32_t index,
const void *file);
uint32_t
GFDGetGeometryShaderCopyProgramSize(uint32_t index,
const void *file);
BOOL
GFDGetGeometryShader(GX2GeometryShader *shader,
void *program,
void *copyProgram,
uint32_t index,
const void *file);
uint32_t
GFDGetPixelShaderCount(const void *file);
uint32_t
GFDGetPixelShaderHeaderSize(uint32_t index,
const void *file);
uint32_t
GFDGetPixelShaderProgramSize(uint32_t index,
const void *file);
BOOL
GFDGetPixelShader(GX2PixelShader *shader,
void *program,
uint32_t index,
const void *file);
uint32_t
GFDGetVertexShaderCount(const void *file);
uint32_t
GFDGetVertexShaderHeaderSize(uint32_t index,
const void *file);
uint32_t
GFDGetVertexShaderProgramSize(uint32_t index,
const void *file);
BOOL
GFDGetVertexShader(GX2VertexShader *shader,
void *program,
uint32_t index,
const void *file);
uint32_t
GFDGetTextureCount(const void *file);
uint32_t
GFDGetTextureHeaderSize(uint32_t index,
const void *file);
uint32_t
GFDGetTextureImageSize(uint32_t index,
const void *file);
uint32_t
GFDGetTextureMipImageSize(uint32_t index,
const void *file);
uint32_t
GFDGetTextureAlignmentSize(uint32_t index,
const void *file);
BOOL
GFDGetTexture(GX2Texture *texture,
void *image,
void *mipmap,
uint32_t index,
const void *file);
BOOL
GFDGetGX2RTexture(GX2Texture *texture,
uint32_t index,
const void *file);
const GX2Texture *
GFDGetTexturePointer(uint32_t index,
const void *file);
#ifdef __cplusplus
}
#endif

858
src/libgfd/src/libgfd.c Normal file
View File

@ -0,0 +1,858 @@
#include "libgfd.h"
#include <coreinit/debug.h>
#include <gx2r/surface.h>
#include <string.h>
static uint32_t _GFDCleanTag(uint32_t tag);
static BOOL _GFDCheckTagDAT(uint32_t tag);
static BOOL _GFDCheckTagSTR(uint32_t tag);
static BOOL _GFDRelocateBlock(const GFDBlockHeader *blockHeader, void *dst);
static BOOL _GFDRelocateBlockEx(const GFDRelocationHeader *relocationHeader, const uint32_t *patchTable, uint8_t *dst);
static uint32_t _GFDGetBlockDataSize(GFDBlockType type, uint32_t index, const void *file);
static uint32_t _GFDGetBlockCount(GFDBlockType type, const void *file);
static BOOL _GFDCheckBlockHeaderMagicVersions(const GFDBlockHeader *header);
static BOOL _GFDCheckHeaderVersions(const void *file);
static BOOL _GFDGetHeaderVersions(uint32_t *majorVersion, uint32_t *minorVersion, uint32_t *gpuVersion, const void *file);
static BOOL _GFDGetBlockPointer(GFDBlockType type, uint32_t index, void *file, GFDBlockHeader **blockHeaderOut, void **blockDataOut);
static BOOL _GFDGetBlockPointerConst(GFDBlockType type, uint32_t index, const void *file, const GFDBlockHeader **blockHeaderOut, const void **blockDataOut);
static BOOL
_GFDGetHeaderVersions(uint32_t *majorVersion,
uint32_t *minorVersion,
uint32_t *gpuVersion,
const void *file)
{
GFDHeader *header = (GFDHeader *)file;
*majorVersion = 0;
*minorVersion = 0;
*gpuVersion = 0;
if (header->magic != GFD_HEADER_MAGIC) {
return FALSE;
}
*majorVersion = header->majorVersion;
*minorVersion = header->minorVersion;
*gpuVersion = header->gpuVersion;
return TRUE;
}
static BOOL
_GFDCheckHeaderVersions(const void *file)
{
uint32_t majorVersion, minorVersion, gpuVersion;
if (!_GFDGetHeaderVersions(&majorVersion, &minorVersion, &gpuVersion, file)) {
return FALSE;
}
if (majorVersion != GFD_FILE_VERSION_MAJOR) {
return FALSE;
}
if (minorVersion != GFD_FILE_VERSION_MINOR) {
return FALSE;
}
if (gpuVersion != GX2TempGetGPUVersion()) {
return FALSE;
}
return TRUE;
}
static BOOL
_GFDCheckBlockHeaderMagicVersions(const GFDBlockHeader *header)
{
if (header->magic != GFD_BLOCK_HEADER_MAGIC) {
return FALSE;
}
if (header->majorVersion != GFD_BLOCK_VERSION_MAJOR) {
return FALSE;
}
return TRUE;
}
static uint32_t
_GFDGetBlockCount(GFDBlockType type,
const void *file)
{
const uint8_t *ptr = (const uint8_t *)file;
const GFDHeader *fileHeader = (const GFDHeader *)file;
const GFDBlockHeader *blockHeader;
uint32_t count = 0;
if (!file) {
return 0;
}
if (!_GFDCheckHeaderVersions(file)) {
return 0;
}
ptr += fileHeader->headerSize;
blockHeader = (const GFDBlockHeader *)ptr;
while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) {
if (blockHeader->type == type) {
count++;
} else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) {
break;
}
ptr += blockHeader->headerSize + blockHeader->dataSize;
blockHeader = (const GFDBlockHeader *)ptr;
}
return count;
}
static uint32_t
_GFDGetBlockDataSize(GFDBlockType type,
uint32_t index,
const void *file)
{
const uint8_t *ptr = (const uint8_t *)file;
const GFDHeader *fileHeader = (const GFDHeader *)file;
const GFDBlockHeader *blockHeader;
uint32_t count = 0;
if (!file) {
return 0;
}
if (!_GFDCheckHeaderVersions(file)) {
return 0;
}
ptr += fileHeader->headerSize;
blockHeader = (const GFDBlockHeader *)ptr;
while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) {
if (blockHeader->type == type) {
if (count == index) {
return blockHeader->dataSize;
}
count++;
} else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) {
break;
}
ptr += blockHeader->headerSize + blockHeader->dataSize;
blockHeader = (const GFDBlockHeader *)ptr;
}
return 0;
}
static BOOL
_GFDGetBlockPointerConst(GFDBlockType type,
uint32_t index,
const void *file,
const GFDBlockHeader **blockHeaderOut,
const void **blockDataOut)
{
const uint8_t *ptr = (const uint8_t *)file;
const GFDHeader *fileHeader = (const GFDHeader *)file;
const GFDBlockHeader *blockHeader;
uint32_t count = 0;
if (!file) {
return FALSE;
}
if (!_GFDCheckHeaderVersions(file)) {
return FALSE;
}
ptr += fileHeader->headerSize;
blockHeader = (const GFDBlockHeader *)ptr;
while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) {
if (blockHeader->type == type) {
if (count == index) {
*blockHeaderOut = blockHeader;
*blockDataOut = ptr + blockHeader->headerSize;
return TRUE;
}
count++;
} else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) {
break;
}
ptr += blockHeader->headerSize + blockHeader->dataSize;
blockHeader = (const GFDBlockHeader *)ptr;
}
return FALSE;
}
static BOOL
_GFDGetBlockPointer(GFDBlockType type,
uint32_t index,
void *file,
GFDBlockHeader **blockHeaderOut,
void **blockDataOut)
{
uint8_t *ptr = (uint8_t *)file;
GFDHeader *fileHeader = (GFDHeader *)file;
GFDBlockHeader *blockHeader;
uint32_t count = 0;
if (!file) {
return FALSE;
}
if (!_GFDCheckHeaderVersions(file)) {
return FALSE;
}
ptr += fileHeader->headerSize;
blockHeader = (GFDBlockHeader *)ptr;
while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) {
if (blockHeader->type == type) {
if (count == index) {
*blockHeaderOut = blockHeader;
*blockDataOut = ptr + blockHeader->headerSize;
if (type == GFD_BLOCK_VERTEX_SHADER_HEADER
|| type == GFD_BLOCK_PIXEL_SHADER_HEADER
|| type == GFD_BLOCK_GEOMETRY_SHADER_HEADER
|| type == GFD_BLOCK_COMPUTE_SHADER_HEADER) {
_GFDRelocateBlock(blockHeader, blockHeader);
}
return TRUE;
}
count++;
} else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) {
break;
}
ptr += blockHeader->headerSize + blockHeader->dataSize;
blockHeader = (GFDBlockHeader *)ptr;
}
return FALSE;
}
static uint32_t
_GFDCleanTag(uint32_t tag)
{
return tag & ~GFD_PATCH_MASK;
}
static BOOL
_GFDCheckTagDAT(uint32_t tag)
{
return (tag & GFD_PATCH_MASK) == GFD_PATCH_DATA;
}
static BOOL
_GFDCheckTagSTR(uint32_t tag)
{
return (tag & GFD_PATCH_MASK) == GFD_PATCH_TEXT;
}
// This method differs from the official because they made poor design decisions.
static BOOL
_GFDRelocateBlockEx(const GFDRelocationHeader *relocationHeader,
const uint32_t *patchTable,
uint8_t *dst)
{
uint32_t patchOffset = _GFDCleanTag(relocationHeader->patchOffset);
uint32_t i;
for (i = 0; i < relocationHeader->patchCount; ++i) {
uint32_t *target;
uint32_t offset = patchTable[i];
if (offset == 0) {
continue;
}
if (!_GFDCheckTagDAT(offset) && !_GFDCheckTagSTR(offset)) {
return FALSE;
}
target = (uint32_t *)(dst + _GFDCleanTag(offset));
if (!_GFDCheckTagDAT(*target) && !_GFDCheckTagSTR(*target)) {
return FALSE;
}
*target = (uintptr_t)(dst + _GFDCleanTag(*target));
}
return TRUE;
}
static BOOL
_GFDRelocateBlock(const GFDBlockHeader *blockHeader,
void *dst)
{
const uint8_t *blockData = ((const uint8_t *)blockHeader) + blockHeader->headerSize;
const GFDRelocationHeader *relocationHeader;
const uint32_t *patchTable;
if (!blockHeader || !dst) {
return FALSE;
}
relocationHeader = (const GFDRelocationHeader *)(blockData
+ blockHeader->dataSize
- sizeof(GFDRelocationHeader));
if (relocationHeader->magic != GFD_RELOCATION_HEADER_MAGIC) {
return FALSE;
}
if (!_GFDCheckTagDAT(relocationHeader->patchOffset)) {
return FALSE;
}
patchTable = (const uint32_t *)(blockData + relocationHeader->patchOffset);
return _GFDRelocateBlockEx(relocationHeader, patchTable, (uint8_t *)dst);
}
static BOOL
_GFDCheckShaderAlign(void *program)
{
return (((uintptr_t)program) & (GX2_SHADER_PROGRAM_ALIGNMENT - 1)) == 0;
}
static BOOL
_GFDGetGenericBlock(GFDBlockType blockTypeHeader,
void *header,
uint32_t headerSize,
GFDBlockType blockTypeProgram1,
void **outProgramPtr1,
void *program1,
GFDBlockType blockTypeProgram2,
void **outProgramPtr2,
void *program2,
uint32_t index,
const void *file)
{
const uint8_t *ptr = (const uint8_t *)file;
const GFDHeader *fileHeader = (const GFDHeader *)file;
const GFDBlockHeader *blockHeader;
uint32_t headerCount = 0;
uint32_t program1Count = 0;
uint32_t program2Count = 0;
BOOL result = FALSE;
if (!header || !file) {
return FALSE;
}
ptr += fileHeader->headerSize;
blockHeader = (const GFDBlockHeader *)ptr;
while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) {
ptr += blockHeader->headerSize;
if (blockHeader->type == blockTypeHeader) {
if (headerCount == index) {
if (blockHeader->dataSize < headerSize) {
return FALSE;
}
memcpy(header, ptr, headerSize);
// Process relocations for all headers except a texture header.
if (blockTypeHeader != GFD_BLOCK_TEXTURE_HEADER) {
if (!_GFDRelocateBlock(blockHeader, header)) {
return FALSE;
}
}
}
headerCount++;
} else if (blockHeader->type == blockTypeProgram1) {
if (program1Count == index) {
*outProgramPtr1 = program1;
memcpy(program1, ptr, blockHeader->dataSize);
}
program1Count++;
} else if (program2 && blockHeader->type == blockTypeProgram2) {
if (program2Count == index) {
*outProgramPtr2 = program2;
memcpy(program2, ptr, blockHeader->dataSize);
}
program2Count++;
} else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) {
break;
}
if (headerCount > index && program1Count > index) {
if (!program2 || program2Count > index) {
result = TRUE;
break;
}
}
ptr += blockHeader->dataSize;
blockHeader = (const GFDBlockHeader *)ptr;
}
return result;
}
/*
BOOL
GFDGetVertexShader(GX2VertexShader *shader,
void *program,
uint32_t index,
const void *file)
{
const uint8_t *ptr = (const uint8_t *)file;
const GFDHeader *fileHeader = (const GFDHeader *)file;
const GFDBlockHeader *blockHeader;
uint32_t headerCount = 0;
uint32_t programCount = 0;
BOOL result = FALSE;
if (!shader || !program || !file) {
return FALSE;
}
if ((uintptr_t)program & (GX2_SHADER_PROGRAM_ALIGNMENT - 1)) {
return FALSE;
}
ptr += fileHeader->headerSize;
blockHeader = (const GFDBlockHeader *)ptr;
while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) {
ptr += blockHeader->headerSize;
if (blockHeader->type == GFD_BLOCK_VERTEX_SHADER_HEADER) {
if (headerCount == index) {
if (blockHeader->dataSize < sizeof(GX2VertexShader)) {
return FALSE;
}
memcpy(shader, ptr, sizeof(GX2VertexShader));
if (!_GFDRelocateBlock(blockHeader, shader)) {
return FALSE;
}
}
headerCount++;
} else if (blockHeader->type == GFD_BLOCK_VERTEX_SHADER_PROGRAM) {
if (programCount == index) {
shader->program = program;
memcpy(program, ptr, blockHeader->dataSize);
}
programCount++;
} else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) {
break;
}
if (headerCount > index && programCount > index) {
result = TRUE;
break;
}
ptr += blockHeader->dataSize;
blockHeader = (const GFDBlockHeader *)ptr;
}
return result;
}
*/
uint32_t
GFDGetComputeShaderCount(const void *file)
{
return _GFDGetBlockCount(GFD_BLOCK_COMPUTE_SHADER_HEADER,
file);
}
uint32_t
GFDGetComputeShaderHeaderSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_COMPUTE_SHADER_HEADER,
index,
file);
}
uint32_t
GFDGetComputeShaderProgramSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_COMPUTE_SHADER_PROGRAM,
index,
file);
}
/*
BOOL
GFDGetComputeShader(GX2ComputeShader *shader,
void *program,
uint32_t index,
const void *file)
{
return _GFDGetGenericBlock(GFD_BLOCK_COMPUTE_SHADER_HEADER,
shader,
sizeof(GX2ComputeShader),
GFD_BLOCK_COMPUTE_SHADER_PROGRAM,
&shader->program,
program,
0,
NULL,
NULL,
index,
file);
}
*/
uint32_t
GFDGetGeometryShaderCount(const void *file)
{
return _GFDGetBlockCount(GFD_BLOCK_GEOMETRY_SHADER_HEADER,
file);
}
uint32_t
GFDGetGeometryShaderHeaderSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_GEOMETRY_SHADER_HEADER,
index,
file);
}
uint32_t
GFDGetGeometryShaderProgramSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_GEOMETRY_SHADER_PROGRAM,
index,
file);
}
uint32_t
GFDGetGeometryShaderCopyProgramSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_GEOMETRY_SHADER_COPY_PROGRAM,
index,
file);
}
BOOL
GFDGetGeometryShader(GX2GeometryShader *shader,
void *program,
void *copyProgram,
uint32_t index,
const void *file)
{
if (!_GFDCheckShaderAlign(program) || !_GFDCheckShaderAlign(copyProgram)) {
return FALSE;
}
return _GFDGetGenericBlock(GFD_BLOCK_GEOMETRY_SHADER_HEADER,
shader,
sizeof(GX2GeometryShader),
GFD_BLOCK_GEOMETRY_SHADER_PROGRAM,
&shader->program,
program,
GFD_BLOCK_GEOMETRY_SHADER_COPY_PROGRAM,
&shader->vertexProgram,
copyProgram,
index,
file);
}
uint32_t
GFDGetPixelShaderCount(const void *file)
{
return _GFDGetBlockCount(GFD_BLOCK_PIXEL_SHADER_HEADER,
file);
}
uint32_t
GFDGetPixelShaderHeaderSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_PIXEL_SHADER_HEADER,
index,
file);
}
uint32_t
GFDGetPixelShaderProgramSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_PIXEL_SHADER_PROGRAM,
index,
file);
}
BOOL
GFDGetPixelShader(GX2PixelShader *shader,
void *program,
uint32_t index,
const void *file)
{
if (!_GFDCheckShaderAlign(program)) {
return FALSE;
}
return _GFDGetGenericBlock(GFD_BLOCK_PIXEL_SHADER_HEADER,
shader,
sizeof(GX2PixelShader),
GFD_BLOCK_PIXEL_SHADER_PROGRAM,
&shader->program,
program,
0,
NULL,
NULL,
index,
file);
}
uint32_t
GFDGetVertexShaderCount(const void *file)
{
return _GFDGetBlockCount(GFD_BLOCK_VERTEX_SHADER_HEADER,
file);
}
uint32_t
GFDGetVertexShaderHeaderSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_VERTEX_SHADER_HEADER,
index,
file);
}
uint32_t
GFDGetVertexShaderProgramSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_VERTEX_SHADER_PROGRAM,
index,
file);
}
BOOL
GFDGetVertexShader(GX2VertexShader *shader,
void *program,
uint32_t index,
const void *file)
{
return _GFDGetGenericBlock(GFD_BLOCK_VERTEX_SHADER_HEADER,
shader,
sizeof(GX2VertexShader),
GFD_BLOCK_VERTEX_SHADER_PROGRAM,
&shader->program,
program,
0,
NULL,
NULL,
index,
file);
}
uint32_t
GFDGetTextureCount(const void *file)
{
return _GFDGetBlockCount(GFD_BLOCK_TEXTURE_HEADER,
file);
}
uint32_t
GFDGetTextureHeaderSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_TEXTURE_HEADER,
index,
file);
}
uint32_t
GFDGetTextureImageSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_TEXTURE_IMAGE,
index,
file);
}
uint32_t
GFDGetTextureMipImageSize(uint32_t index,
const void *file)
{
return _GFDGetBlockDataSize(GFD_BLOCK_TEXTURE_MIPMAP,
index,
file);
}
uint32_t
GFDGetTextureAlignmentSize(uint32_t index,
const void *file)
{
const GFDBlockHeader *blockHeader;
const GX2Texture *texture;
if (!_GFDGetBlockPointerConst(GFD_BLOCK_TEXTURE_HEADER,
index,
file,
&blockHeader,
(const void **)&texture)) {
return 0;
}
return texture->surface.alignment;
}
BOOL
GFDGetTexture(GX2Texture *texture,
void *image,
void *mipmap,
uint32_t index,
const void *file)
{
return _GFDGetGenericBlock(GFD_BLOCK_TEXTURE_HEADER,
texture,
sizeof(GX2Texture),
GFD_BLOCK_TEXTURE_IMAGE,
&texture->surface.image,
image,
GFD_BLOCK_TEXTURE_MIPMAP,
&texture->surface.mipmaps,
mipmap,
index,
file);
}
BOOL
GFDGetGX2RTexture(GX2Texture *texture,
uint32_t index,
const void *file)
{
const uint8_t *ptr = (const uint8_t *)file;
const GFDHeader *fileHeader = (const GFDHeader *)file;
const GFDBlockHeader *blockHeader;
uint32_t headerCount = 0;
BOOL created = FALSE;
if (!texture || !file) {
return FALSE;
}
ptr += fileHeader->headerSize;
blockHeader = (const GFDBlockHeader *)ptr;
while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) {
ptr += blockHeader->headerSize;
if (blockHeader->type == GFD_BLOCK_TEXTURE_HEADER) {
if (headerCount == index) {
if (blockHeader->dataSize < sizeof(GX2Texture)) {
goto error;
}
memcpy(texture, ptr, sizeof(GX2Texture));
texture->surface.image = NULL;
texture->surface.mipmaps = NULL;
GX2RCreateSurface(&texture->surface,
GX2R_RESOURCE_BIND_TEXTURE
| GX2R_RESOURCE_USAGE_CPU_WRITE
| GX2R_RESOURCE_USAGE_GPU_READ);
created = TRUE;
} else if (created) {
break;
}
headerCount++;
} else if (blockHeader->type == GFD_BLOCK_TEXTURE_IMAGE) {
if (created) {
void *image = GX2RLockSurfaceEx(&texture->surface, 0, 0);
if (!image) {
goto error;
}
memcpy(image, ptr, blockHeader->dataSize);
GX2RUnlockSurfaceEx(&texture->surface, 0,
GX2R_RESOURCE_DISABLE_CPU_INVALIDATE
| GX2R_RESOURCE_DISABLE_GPU_INVALIDATE);
}
} else if (blockHeader->type == GFD_BLOCK_TEXTURE_MIPMAP) {
if (created) {
void *mipmap = GX2RLockSurfaceEx(&texture->surface, -1, 0);
if (!mipmap) {
goto error;
}
memcpy(mipmap, ptr, blockHeader->dataSize);
GX2RUnlockSurfaceEx(&texture->surface, -1,
GX2R_RESOURCE_DISABLE_CPU_INVALIDATE
| GX2R_RESOURCE_DISABLE_GPU_INVALIDATE);
}
} else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) {
break;
}
ptr += blockHeader->dataSize;
blockHeader = (const GFDBlockHeader *)ptr;
}
if (created && (texture->surface.image || texture->surface.mipmaps)) {
if (texture->surface.image) {
GX2RInvalidateSurface(&texture->surface, 0, 0);
}
if (texture->surface.mipmaps) {
GX2RInvalidateSurface(&texture->surface, -1, 0);
}
return TRUE;
}
error:
GX2RDestroySurface(&texture->surface);
return FALSE;
}
const GX2Texture *
GFDGetTexturePointer(uint32_t index,
const void *file)
{
const GFDBlockHeader *blockHeader;
const GX2Texture *texture;
if (!_GFDGetBlockPointerConst(GFD_BLOCK_TEXTURE_HEADER,
index,
file,
&blockHeader,
(const void **)&texture)) {
return NULL;
}
if (blockHeader->dataSize < sizeof(GX2Texture)) {
return NULL;
}
return texture;
}