Add tex3ds.h interface for loading assets converted by tex3ds
This commit is contained in:
parent
ac1fad7107
commit
8764804dd5
3
Makefile
3
Makefile
@ -22,8 +22,7 @@ VERSION := $(CITRO3D_MAJOR).$(CITRO3D_MINOR).$(CITRO3D_PATCH)
|
||||
# INCLUDES is a list of directories containing header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := citro3d
|
||||
SOURCES := source \
|
||||
source/maths
|
||||
SOURCES := source source/maths
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
|
||||
|
215
include/tex3ds.h
Normal file
215
include/tex3ds.h
Normal file
@ -0,0 +1,215 @@
|
||||
/*------------------------------------------------------------------------------
|
||||
* Copyright (c) 2017
|
||||
* Michael Theall (mtheall)
|
||||
*
|
||||
* This file is part of citro3d.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*----------------------------------------------------------------------------*/
|
||||
/** @file tex3ds.h
|
||||
* @brief tex3ds support
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef CITRO3D_BUILD
|
||||
#include "c3d/texture.h"
|
||||
#else
|
||||
#include <citro3d.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Subtexture
|
||||
* @note If top > bottom, the subtexture is rotated 1/4 revolution counter-clockwise
|
||||
*/
|
||||
typedef struct Tex3DS_SubTexture
|
||||
{
|
||||
u16 width; ///< Sub-texture width (pixels)
|
||||
u16 height; ///< Sub-texture height (pixels)
|
||||
float left; ///< Left u-coordinate
|
||||
float top; ///< Top v-coordinate
|
||||
float right; ///< Right u-coordinate
|
||||
float bottom; ///< Bottom v-coordinate
|
||||
} Tex3DS_SubTexture;
|
||||
|
||||
/** @brief Texture */
|
||||
typedef struct Tex3DS_Texture_s* Tex3DS_Texture;
|
||||
|
||||
/** @brief Import Tex3DS texture
|
||||
* @param[in] input Input data
|
||||
* @param[in] insize Size of the input data
|
||||
* @param[out] tex citro3d texture
|
||||
* @param[out] texcube citro3d texcube
|
||||
* @param[in] vram Whether to store textures in VRAM
|
||||
* @returns Tex3DS texture
|
||||
*/
|
||||
Tex3DS_Texture Tex3DS_TextureImport(const void* input, size_t insize, C3D_Tex* tex, C3D_TexCube* texcube, bool vram);
|
||||
|
||||
/** @brief Import Tex3DS texture
|
||||
*
|
||||
* @description
|
||||
* For example, use this if you want to import from a large file without
|
||||
* pulling the entire file into memory.
|
||||
*
|
||||
* @param[out] tex citro3d texture
|
||||
* @param[out] texcube citro3d texcube
|
||||
* @param[in] vram Whether to store textures in VRAM
|
||||
* @param[in] callback Data callback
|
||||
* @param[in] userdata User data passed to callback
|
||||
* @returns Tex3DS texture
|
||||
*/
|
||||
Tex3DS_Texture Tex3DS_TextureImportCallback(C3D_Tex* tex, C3D_TexCube* texcube, bool vram, decompressCallback callback, void* userdata);
|
||||
|
||||
/** @brief Import Tex3DS texture
|
||||
*
|
||||
* Starts reading at the current file descriptor's offset. The file
|
||||
* descriptor's position is left at the end of the decoded data. On error, the
|
||||
* file descriptor's position is indeterminate.
|
||||
*
|
||||
* @param[in] fd Open file descriptor
|
||||
* @param[out] tex citro3d texture
|
||||
* @param[out] texcube citro3d texcube
|
||||
* @param[in] vram Whether to store textures in VRAM
|
||||
* @returns Tex3DS texture
|
||||
*/
|
||||
Tex3DS_Texture Tex3DS_TextureImportFD(int fd, C3D_Tex* tex, C3D_TexCube* texcube, bool vram);
|
||||
|
||||
/** @brief Import Tex3DS texture
|
||||
*
|
||||
* Starts reading at the current file stream's offset. The file stream's
|
||||
* position is left at the end of the decoded data. On error, the file
|
||||
* stream's position is indeterminate.
|
||||
*
|
||||
* @param[in] fp Open file stream
|
||||
* @param[out] tex citro3d texture
|
||||
* @param[out] texcube citro3d texcube
|
||||
* @param[in] vram Whether to store textures in VRAM
|
||||
* @returns Tex3DS texture
|
||||
*/
|
||||
Tex3DS_Texture Tex3DS_TextureImportStdio(FILE* fp, C3D_Tex* tex, C3D_TexCube* texcube, bool vram);
|
||||
|
||||
/** @brief Get number of subtextures
|
||||
* @param[in] texture Tex3DS texture
|
||||
* @returns Number of subtextures
|
||||
*/
|
||||
const size_t Tex3DS_GetNumSubTextures(const Tex3DS_Texture texture);
|
||||
|
||||
/** @brief Get subtexture
|
||||
* @param[in] texture Tex3DS texture
|
||||
* @param[in] index Subtexture index
|
||||
* @returns Subtexture info
|
||||
*/
|
||||
const Tex3DS_SubTexture* Tex3DS_GetSubTexture(const Tex3DS_Texture texture, size_t index);
|
||||
|
||||
/** @brief Check if subtexture is rotated
|
||||
* @param[in] subtex Subtexture to check
|
||||
* @returns whether subtexture is rotated
|
||||
*/
|
||||
static inline bool
|
||||
Tex3DS_SubTextureRotated(const Tex3DS_SubTexture* subtex)
|
||||
{
|
||||
return subtex->top < subtex->bottom;
|
||||
}
|
||||
|
||||
/** @brief Get bottom-left texcoords
|
||||
* @param[in] subtex Subtexture
|
||||
* @param[out] u u-coordinate
|
||||
* @param[out] v v-coordinate
|
||||
*/
|
||||
static inline void
|
||||
Tex3DS_SubTextureBottomLeft(const Tex3DS_SubTexture* subtex, float* u, float* v)
|
||||
{
|
||||
if (!Tex3DS_SubTextureRotated(subtex))
|
||||
{
|
||||
*u = subtex->left;
|
||||
*v = subtex->bottom;
|
||||
} else
|
||||
{
|
||||
*u = subtex->bottom;
|
||||
*v = subtex->left;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Get bottom-right texcoords
|
||||
* @param[in] subtex Subtexture
|
||||
* @param[out] u u-coordinate
|
||||
* @param[out] v v-coordinate
|
||||
*/
|
||||
static inline void
|
||||
Tex3DS_SubTextureBottomRight(const Tex3DS_SubTexture* subtex, float* u, float* v)
|
||||
{
|
||||
if (!Tex3DS_SubTextureRotated(subtex))
|
||||
{
|
||||
*u = subtex->right;
|
||||
*v = subtex->bottom;
|
||||
} else
|
||||
{
|
||||
*u = subtex->bottom;
|
||||
*v = subtex->right;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Get top-left texcoords
|
||||
* @param[in] subtex Subtexture
|
||||
* @param[out] u u-coordinate
|
||||
* @param[out] v v-coordinate
|
||||
*/
|
||||
static inline void
|
||||
Tex3DS_SubTextureTopLeft(const Tex3DS_SubTexture* subtex, float* u, float* v)
|
||||
{
|
||||
if (!Tex3DS_SubTextureRotated(subtex))
|
||||
{
|
||||
*u = subtex->left;
|
||||
*v = subtex->top;
|
||||
} else
|
||||
{
|
||||
*u = subtex->top;
|
||||
*v = subtex->left;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Get top-right texcoords
|
||||
* @param[in] subtex Subtexture
|
||||
* @param[out] u u-coordinate
|
||||
* @param[out] v v-coordinate
|
||||
*/
|
||||
static inline void
|
||||
Tex3DS_SubTextureTopRight(const Tex3DS_SubTexture* subtex, float* u, float* v)
|
||||
{
|
||||
if (!Tex3DS_SubTextureRotated(subtex))
|
||||
{
|
||||
*u = subtex->right;
|
||||
*v = subtex->top;
|
||||
} else
|
||||
{
|
||||
*u = subtex->top;
|
||||
*v = subtex->right;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Free Tex3DS texture
|
||||
* @param[in] texture Tex3DS texture to free
|
||||
*/
|
||||
void Tex3DS_TextureFree(Tex3DS_Texture texture);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
241
source/tex3ds.c
Normal file
241
source/tex3ds.c
Normal file
@ -0,0 +1,241 @@
|
||||
/*------------------------------------------------------------------------------
|
||||
* Copyright (c) 2017
|
||||
* Michael Theall (mtheall)
|
||||
*
|
||||
* This file is part of citro3d.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from the
|
||||
* use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*----------------------------------------------------------------------------*/
|
||||
/** @file tex3ds.c
|
||||
* @brief Tex3DS routines
|
||||
*/
|
||||
#include <tex3ds.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/** @brief Tex3DS texture
|
||||
*/
|
||||
struct Tex3DS_Texture_s
|
||||
{
|
||||
u16 numSubTextures; ///< Number of subtextures
|
||||
u16 width; ///< Texture width
|
||||
u16 height; ///< Texture height
|
||||
u8 format; ///< Texture format
|
||||
u8 mipmapLevels; ///< Number of mipmaps
|
||||
Tex3DS_SubTexture subTextures[]; ///< Subtextures
|
||||
};
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
u16 numSubTextures;
|
||||
u8 width_log2 : 3;
|
||||
u8 height_log2 : 3;
|
||||
u8 type : 1;
|
||||
u8 format;
|
||||
u8 mipmapLevels;
|
||||
} Tex3DSi_Header;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16 width, height;
|
||||
u16 left, top, right, bottom;
|
||||
} Tex3DSi_SubTexture;
|
||||
|
||||
static inline bool Tex3DSi_ReadData(decompressCallback callback, void** userdata, void* buffer, size_t size, size_t* insize)
|
||||
{
|
||||
if (callback)
|
||||
return callback(*userdata, buffer, size) == size;
|
||||
if (size > *insize)
|
||||
return false;
|
||||
|
||||
memcpy(buffer, *userdata, size);
|
||||
*userdata = (u8*)*userdata + size;
|
||||
*insize -= size;
|
||||
return true;
|
||||
}
|
||||
|
||||
static Tex3DS_Texture
|
||||
Tex3DSi_ImportCommon(C3D_Tex* tex, C3D_TexCube* texcube, bool vram, decompressCallback callback, void* userdata, size_t insize)
|
||||
{
|
||||
// Read header
|
||||
Tex3DSi_Header hdr;
|
||||
if (!Tex3DSi_ReadData(callback, &userdata, &hdr, sizeof(hdr), &insize))
|
||||
return NULL;
|
||||
|
||||
// Allocate space for header + subtextures
|
||||
Tex3DS_Texture texture = (Tex3DS_Texture)malloc(sizeof(struct Tex3DS_Texture_s) + hdr.numSubTextures*sizeof(Tex3DS_SubTexture));
|
||||
if (!texture)
|
||||
return NULL;
|
||||
|
||||
// Fill texture metadata structure
|
||||
texture->numSubTextures = hdr.numSubTextures;
|
||||
texture->width = 1 << (hdr.width_log2 + 3);
|
||||
texture->height = 1 << (hdr.height_log2 + 3);
|
||||
texture->format = hdr.format;
|
||||
texture->mipmapLevels = hdr.mipmapLevels;
|
||||
|
||||
// Read subtexture info
|
||||
for (size_t i = 0; i < hdr.numSubTextures; i ++)
|
||||
{
|
||||
Tex3DSi_SubTexture subtex;
|
||||
if (!Tex3DSi_ReadData(callback, &userdata, &subtex, sizeof(Tex3DSi_SubTexture), &insize))
|
||||
{
|
||||
free(texture);
|
||||
return NULL;
|
||||
}
|
||||
texture->subTextures[i].width = subtex.width;
|
||||
texture->subTextures[i].height = subtex.height;
|
||||
texture->subTextures[i].left = subtex.left / 1024.0f;
|
||||
texture->subTextures[i].top = subtex.top / 1024.0f;
|
||||
texture->subTextures[i].right = subtex.right / 1024.0f;
|
||||
texture->subTextures[i].bottom = subtex.bottom / 1024.0f;
|
||||
}
|
||||
|
||||
// Allocate texture memory
|
||||
C3D_TexInitParams params;
|
||||
params.width = texture->width;
|
||||
params.height = texture->height;
|
||||
params.maxLevel = texture->mipmapLevels;
|
||||
params.format = texture->format;
|
||||
params.type = (GPU_TEXTURE_MODE_PARAM)hdr.type;
|
||||
params.onVram = vram;
|
||||
if (!C3D_TexInitWithParams(tex, texcube, params))
|
||||
{
|
||||
free(texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get texture size, including mipmaps
|
||||
size_t base_texsize = C3D_TexCalcTotalSize(tex->size, texture->mipmapLevels);
|
||||
size_t texsize = base_texsize;
|
||||
|
||||
// If this is a cubemap/skybox, there are 6 textures
|
||||
if (params.type == GPU_TEX_CUBE_MAP)
|
||||
texsize *= 6;
|
||||
|
||||
if (vram)
|
||||
{
|
||||
// Allocate staging buffer in linear memory
|
||||
void* texdata = linearAlloc(texsize);
|
||||
if (!texdata)
|
||||
{
|
||||
C3D_TexDelete(tex);
|
||||
free(texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Decompress into staging buffer for VRAM upload
|
||||
if (!decompress(texdata, texsize, callback, userdata, insize))
|
||||
{
|
||||
linearFree(texdata);
|
||||
C3D_TexDelete(tex);
|
||||
free(texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Flush buffer to prepare DMA to VRAM
|
||||
GSPGPU_FlushDataCache(texdata, texsize);
|
||||
|
||||
size_t texcount = 1;
|
||||
if (params.type == GPU_TEX_CUBE_MAP)
|
||||
texcount = 6;
|
||||
|
||||
// Upload texture(s) to VRAM
|
||||
for (size_t i = 0; i < texcount; ++i)
|
||||
C3D_TexLoadImage(tex, (u8*)texdata + i * base_texsize, i, -1);
|
||||
|
||||
linearFree(texdata);
|
||||
} else if (params.type == GPU_TEX_CUBE_MAP)
|
||||
{
|
||||
decompressIOVec iov[6];
|
||||
|
||||
// Setup IO vectors
|
||||
for (size_t i = 0; i < 6; ++i)
|
||||
{
|
||||
u32 size;
|
||||
iov[i].data = C3D_TexCubeGetImagePtr(tex, i, -1, &size);
|
||||
iov[i].size = size;
|
||||
}
|
||||
|
||||
// Decompress into texture memory
|
||||
if (!decompressV(iov, 6, callback, userdata, insize))
|
||||
{
|
||||
C3D_TexDelete(tex);
|
||||
free(texture);
|
||||
return NULL;
|
||||
}
|
||||
} else
|
||||
{
|
||||
u32 size;
|
||||
void* data = C3D_Tex2DGetImagePtr(tex, -1, &size);
|
||||
|
||||
// Decompress into texture memory
|
||||
if (!decompress(data, size, callback, userdata, insize))
|
||||
{
|
||||
C3D_TexDelete(tex);
|
||||
free(texture);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
Tex3DS_Texture
|
||||
Tex3DS_TextureImport(const void* input, size_t insize, C3D_Tex* tex, C3D_TexCube* texcube, bool vram)
|
||||
{
|
||||
return Tex3DSi_ImportCommon(tex, texcube, vram, NULL, (void*)input, insize);
|
||||
}
|
||||
|
||||
Tex3DS_Texture
|
||||
Tex3DS_TextureImportCallback(C3D_Tex* tex, C3D_TexCube* texcube, bool vram, decompressCallback callback, void* userdata)
|
||||
{
|
||||
return Tex3DSi_ImportCommon(tex, texcube, vram, callback, userdata, 0);
|
||||
}
|
||||
|
||||
Tex3DS_Texture
|
||||
Tex3DS_TextureImportFD(int fd, C3D_Tex* tex, C3D_TexCube* texcube, bool vram)
|
||||
{
|
||||
return Tex3DSi_ImportCommon(tex, texcube, vram, decompressCallback_FD, &fd, 0);
|
||||
}
|
||||
|
||||
Tex3DS_Texture
|
||||
Tex3DS_TextureImportStdio(FILE* fp, C3D_Tex* tex, C3D_TexCube* texcube, bool vram)
|
||||
{
|
||||
return Tex3DSi_ImportCommon(tex, texcube, vram, decompressCallback_Stdio, fp, 0);
|
||||
}
|
||||
|
||||
const size_t
|
||||
Tex3DS_GetNumSubTextures(const Tex3DS_Texture texture)
|
||||
{
|
||||
return texture->numSubTextures;
|
||||
}
|
||||
|
||||
const Tex3DS_SubTexture*
|
||||
Tex3DS_GetSubTexture(const Tex3DS_Texture texture, size_t index)
|
||||
{
|
||||
if (index < texture->numSubTextures)
|
||||
return &texture->subTextures[index];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Tex3DS_TextureFree(Tex3DS_Texture texture)
|
||||
{
|
||||
free(texture);
|
||||
}
|
Loading…
Reference in New Issue
Block a user