mirror of
https://github.com/wiiu-env/wut.git
synced 2024-12-13 11:32:38 +01:00
Add libgfd.
This commit is contained in:
parent
d0dab12160
commit
fcafa791b3
7
src/libgfd/CMakeLists.txt
Normal file
7
src/libgfd/CMakeLists.txt
Normal 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
204
src/libgfd/include/libgfd.h
Normal 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
858
src/libgfd/src/libgfd.c
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user