2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @file texture.h
|
|
|
|
* @brief Create and manipulate textures
|
|
|
|
*/
|
2014-12-20 21:34:19 +01:00
|
|
|
#pragma once
|
|
|
|
#include "types.h"
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/// Cubemap texture data
|
2014-12-20 21:34:19 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
2017-02-12 00:14:04 +01:00
|
|
|
void* data[6];
|
|
|
|
} C3D_TexCube;
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/// Texture data
|
2017-02-12 00:14:04 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
union
|
|
|
|
{
|
|
|
|
void* data;
|
|
|
|
C3D_TexCube* cube;
|
|
|
|
};
|
2015-07-23 22:22:28 +02:00
|
|
|
|
|
|
|
GPU_TEXCOLOR fmt : 4;
|
|
|
|
size_t size : 28;
|
2014-12-20 21:34:19 +01:00
|
|
|
|
2017-02-12 00:14:04 +01:00
|
|
|
union
|
|
|
|
{
|
|
|
|
u32 dim;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
u16 height;
|
|
|
|
u16 width;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2014-12-20 21:34:19 +01:00
|
|
|
u32 param;
|
2017-02-09 20:07:37 +01:00
|
|
|
u32 border;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
u32 lodParam;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
u16 lodBias;
|
|
|
|
u8 maxLevel;
|
|
|
|
u8 minLevel;
|
|
|
|
};
|
|
|
|
};
|
2014-12-20 21:34:19 +01:00
|
|
|
} C3D_Tex;
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/// Parameters for \ref C3D_TexInitWithParams()
|
2023-10-28 21:57:00 +02:00
|
|
|
typedef struct CTR_ALIGN(8)
|
2017-02-09 20:07:37 +01:00
|
|
|
{
|
2024-01-17 03:31:31 +01:00
|
|
|
u16 width; ///< Width of texture in pixels. (must be a power of 2)
|
|
|
|
u16 height; ///< Height of texture in pixels. (must be a power of 2)
|
|
|
|
u8 maxLevel : 4; ///< Maximum mipmap level.
|
|
|
|
GPU_TEXCOLOR format : 4; ///< GPU texture format.
|
|
|
|
GPU_TEXTURE_MODE_PARAM type : 3; ///< Texture type
|
|
|
|
bool onVram : 1; ///< Specifies whether to allocate texture data in Vram or linearMemory
|
2017-02-09 20:07:37 +01:00
|
|
|
} C3D_TexInitParams;
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Initializes texture with specified parameters
|
|
|
|
* @param[out] tex Pointer to uninitialized \ref C3D_Tex.
|
|
|
|
* @param[out] cube Pointer to \ref C3D_TexCube. (Only used if texture type is cubemap)
|
|
|
|
* @param[in] p Parameters. See \ref C3D_TexInitParams.
|
|
|
|
* @return True if texture was initialized successfully, otherwise false.
|
|
|
|
*/
|
2017-02-12 00:14:04 +01:00
|
|
|
bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexCube* cube, C3D_TexInitParams p);
|
2024-01-17 03:31:31 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Copies raw texture data into \ref C3D_Tex
|
|
|
|
* @param[out] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @param[in] data Pointer to raw texture data.
|
|
|
|
* @param[in] face Specifies texture face.
|
|
|
|
* @param[in] level Specifies mipmap level.
|
|
|
|
*/
|
2017-02-12 00:14:04 +01:00
|
|
|
void C3D_TexLoadImage(C3D_Tex* tex, const void* data, GPU_TEXFACE face, int level);
|
2024-01-17 03:31:31 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Generates mipmaps for \ref C3D_Tex using previously specified max level
|
|
|
|
* The max level should have been specified using \ref C3D_TexInitMipmap() or \ref C3D_TexInitWithParams()
|
|
|
|
* @note Does not support generating mipmaps for VRAM textures.
|
|
|
|
* @param[in,out] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @param[in] face Specifies texture face.
|
|
|
|
*/
|
2017-02-12 00:14:04 +01:00
|
|
|
void C3D_TexGenerateMipmap(C3D_Tex* tex, GPU_TEXFACE face);
|
2024-01-17 03:31:31 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Binds C3D_Tex to texture unit
|
|
|
|
* @note The 3DS has 3 normal texture units (IDs 0 through 2).
|
|
|
|
* @param[in] unitId Specifies texture unit.
|
|
|
|
* @param[in] tex Pointer to \ref C3D_Tex.
|
|
|
|
*/
|
2014-12-20 21:34:19 +01:00
|
|
|
void C3D_TexBind(int unitId, C3D_Tex* tex);
|
2024-01-17 03:31:31 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Flushes texture data from cache into memory
|
|
|
|
* @param[in] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @sa GSPGPU_FlushDataCache()
|
|
|
|
*/
|
2014-12-20 21:34:19 +01:00
|
|
|
void C3D_TexFlush(C3D_Tex* tex);
|
2024-01-17 03:31:31 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Deletes texture data
|
|
|
|
* @param[in] tex Pointer to \ref C3D_Tex.
|
|
|
|
*/
|
2014-12-20 21:34:19 +01:00
|
|
|
void C3D_TexDelete(C3D_Tex* tex);
|
2017-02-09 20:07:37 +01:00
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Configues texunit0 shadow depth texture properties
|
|
|
|
* @param[in] perspective true if the shadow texture was generated with perspective projection,
|
|
|
|
* false if the shadow texture was generated with orthogonal projection.
|
|
|
|
* @param[in] bias Bias subtracted from the texture0w value in the shader.
|
|
|
|
*/
|
2017-02-14 19:40:07 +01:00
|
|
|
void C3D_TexShadowParams(bool perspective, float bias);
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Calculates maximum mipmap level for given texture size
|
|
|
|
* @param[in] width Width of texture.
|
|
|
|
* @param[in] height Height of texture.
|
|
|
|
* @returns Calculated maximum mipmap level.
|
|
|
|
*/
|
2017-02-09 20:07:37 +01:00
|
|
|
static inline int C3D_TexCalcMaxLevel(u32 width, u32 height)
|
|
|
|
{
|
|
|
|
return (31-__builtin_clz(width < height ? width : height)) - 3; // avoid sizes smaller than 8
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Calculates size of mipmap level
|
|
|
|
* @param[in] size Size of original texture.
|
|
|
|
* @param[in] level Mipmap level.
|
|
|
|
* @returns Calculated level size.
|
|
|
|
*/
|
2017-02-11 18:29:41 +01:00
|
|
|
static inline u32 C3D_TexCalcLevelSize(u32 size, int level)
|
|
|
|
{
|
|
|
|
return size >> (2*level);
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Calculates total size of mipmap texture data
|
|
|
|
* @param[in] size Size of original texture.
|
|
|
|
* @param[in] maxLevel Maximum mipmap level.
|
|
|
|
* @returns Calculated total size.
|
|
|
|
*/
|
2017-02-11 18:29:41 +01:00
|
|
|
static inline u32 C3D_TexCalcTotalSize(u32 size, int maxLevel)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
S = s + sr + sr^2 + sr^3 + ... + sr^n
|
|
|
|
Sr = sr + sr^2 + sr^3 + ... + sr^(n+1)
|
|
|
|
S-Sr = s - sr^(n+1)
|
|
|
|
S(1-r) = s(1 - r^(n+1))
|
|
|
|
S = s (1 - r^(n+1)) / (1-r)
|
|
|
|
|
|
|
|
r = 1/4
|
|
|
|
1-r = 3/4
|
|
|
|
|
|
|
|
S = 4s (1 - (1/4)^(n+1)) / 3
|
|
|
|
S = 4s (1 - 1/4^(n+1)) / 3
|
|
|
|
S = (4/3) (s - s/4^(n+1))
|
|
|
|
S = (4/3) (s - s/(1<<(2n+2)))
|
|
|
|
S = (4/3) (s - s>>(2n+2))
|
|
|
|
*/
|
|
|
|
return (size - C3D_TexCalcLevelSize(size,maxLevel+1)) * 4 / 3;
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Initializes standard 2D texture
|
|
|
|
* @param[out] tex Pointer to uninitialized \ref C3D_Tex.
|
|
|
|
* @param[in] width Specifies width of texture. (must be a power of 2)
|
|
|
|
* @param[in] height Specifies height of texture. (must be a power of 2)
|
|
|
|
* @param[in] format Specifies texture format.
|
|
|
|
* @return True if texture was initialized successfully, otherwise false.
|
|
|
|
*/
|
2017-02-09 20:07:37 +01:00
|
|
|
static inline bool C3D_TexInit(C3D_Tex* tex, u16 width, u16 height, GPU_TEXCOLOR format)
|
|
|
|
{
|
2017-02-12 00:14:04 +01:00
|
|
|
return C3D_TexInitWithParams(tex, NULL,
|
2017-02-09 20:07:37 +01:00
|
|
|
(C3D_TexInitParams){ width, height, 0, format, GPU_TEX_2D, false });
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Initializes standard 2D texture with mipmap
|
|
|
|
* Maximum miplevel is calculated using \ref C3D_TexCalcMaxLevel()
|
|
|
|
* @param[out] tex Pointer to uninitialized \ref C3D_Tex.
|
|
|
|
* @param[in] width Specifies width of texture. (must be a power of 2)
|
|
|
|
* @param[in] height Specifies height of texture. (must be a power of 2)
|
|
|
|
* @param[in] format Specifies texture format.
|
|
|
|
* @return True if texture was initialized successfully, otherwise false.
|
|
|
|
*/
|
2017-02-09 20:07:37 +01:00
|
|
|
static inline bool C3D_TexInitMipmap(C3D_Tex* tex, u16 width, u16 height, GPU_TEXCOLOR format)
|
|
|
|
{
|
2017-02-12 00:14:04 +01:00
|
|
|
return C3D_TexInitWithParams(tex, NULL,
|
2017-02-09 20:07:37 +01:00
|
|
|
(C3D_TexInitParams){ width, height, (u8)C3D_TexCalcMaxLevel(width, height), format, GPU_TEX_2D, false });
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Initializes cubemap texture
|
|
|
|
* @param[out] tex Pointer to uninitialized \ref C3D_Tex.
|
|
|
|
* @param[out] cube Pointer to \ref C3D_TexCube.
|
|
|
|
* @param[in] width Specifies width of texture. (must be a power of 2)
|
|
|
|
* @param[in] height Specifies height of texture. (must be a power of 2)
|
|
|
|
* @param[in] format Specifies texture format.
|
|
|
|
* @return True if texture was initialized successfully, otherwise false.
|
|
|
|
*/
|
2017-02-12 00:14:04 +01:00
|
|
|
static inline bool C3D_TexInitCube(C3D_Tex* tex, C3D_TexCube* cube, u16 width, u16 height, GPU_TEXCOLOR format)
|
|
|
|
{
|
|
|
|
return C3D_TexInitWithParams(tex, cube,
|
|
|
|
(C3D_TexInitParams){ width, height, 0, format, GPU_TEX_CUBE_MAP, false });
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Initializes 2D texture in VRAM
|
|
|
|
* @param[out] tex Pointer to uninitialized \ref C3D_Tex.
|
|
|
|
* @param[in] width Specifies width of texture. (must be a power of 2)
|
|
|
|
* @param[in] height Specifies height of texture. (must be a power of 2)
|
|
|
|
* @param[in] format Specifies texture format.
|
|
|
|
* @return True if texture was initialized successfully, otherwise false.
|
|
|
|
*/
|
2017-02-09 20:07:37 +01:00
|
|
|
static inline bool C3D_TexInitVRAM(C3D_Tex* tex, u16 width, u16 height, GPU_TEXCOLOR format)
|
|
|
|
{
|
2017-02-12 00:14:04 +01:00
|
|
|
return C3D_TexInitWithParams(tex, NULL,
|
2017-02-09 20:07:37 +01:00
|
|
|
(C3D_TexInitParams){ width, height, 0, format, GPU_TEX_2D, true });
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Initializes 2D shadowmap texture
|
|
|
|
* @param[out] tex Pointer to uninitialized \ref C3D_Tex.
|
|
|
|
* @param[in] width Specifies width of texture. (must be a power of 2)
|
|
|
|
* @param[in] height Specifies height of texture. (must be a power of 2)
|
|
|
|
* @return True if texture was initialized successfully, otherwise false.
|
|
|
|
*/
|
2017-02-14 19:40:07 +01:00
|
|
|
static inline bool C3D_TexInitShadow(C3D_Tex* tex, u16 width, u16 height)
|
|
|
|
{
|
|
|
|
return C3D_TexInitWithParams(tex, NULL,
|
|
|
|
(C3D_TexInitParams){ width, height, 0, GPU_RGBA8, GPU_TEX_SHADOW_2D, true });
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Initializes shadowmap cubemap texture
|
|
|
|
* @param[out] tex Pointer to uninitialized \ref C3D_Tex.
|
|
|
|
* @param[out] cube Pointer to \ref C3D_TexCube.
|
|
|
|
* @param[in] width Specifies width of texture. (must be a power of 2)
|
|
|
|
* @param[in] height Specifies height of texture. (must be a power of 2)
|
|
|
|
* @return True if texture was initialized successfully, otherwise false.
|
|
|
|
*/
|
2017-02-14 19:40:07 +01:00
|
|
|
static inline bool C3D_TexInitShadowCube(C3D_Tex* tex, C3D_TexCube* cube, u16 width, u16 height)
|
|
|
|
{
|
|
|
|
return C3D_TexInitWithParams(tex, cube,
|
|
|
|
(C3D_TexInitParams){ width, height, 0, GPU_RGBA8, GPU_TEX_SHADOW_CUBE, true });
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Gets type of texture
|
|
|
|
* @param[in] tex Pointer to \ref C3D_Tex.
|
|
|
|
*/
|
2017-02-12 00:14:04 +01:00
|
|
|
static inline GPU_TEXTURE_MODE_PARAM C3D_TexGetType(C3D_Tex* tex)
|
|
|
|
{
|
|
|
|
return (GPU_TEXTURE_MODE_PARAM)((tex->param>>28)&0x7);
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Gets pointer to texture image
|
|
|
|
* @param[in] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @param[in] data Pointer texture face.
|
|
|
|
* @param[in] level Specifies mipmap level.
|
|
|
|
* @param[out] size Can be used to get the size of the image data.
|
|
|
|
* @returns Pointer to raw image data.
|
|
|
|
*/
|
2017-02-12 00:14:04 +01:00
|
|
|
static inline void* C3D_TexGetImagePtr(C3D_Tex* tex, void* data, int level, u32* size)
|
|
|
|
{
|
2017-03-10 17:21:59 +01:00
|
|
|
if (size) *size = level >= 0 ? C3D_TexCalcLevelSize(tex->size, level) : C3D_TexCalcTotalSize(tex->size, tex->maxLevel);
|
2017-02-12 00:14:04 +01:00
|
|
|
if (!level) return data;
|
|
|
|
return (u8*)data + (level > 0 ? C3D_TexCalcTotalSize(tex->size, level-1) : 0);
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Gets pointer to 2D texture image
|
|
|
|
* @param[in] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @param[in] level Specifies mipmap level.
|
|
|
|
* @param[out] size Can be used to get the size of the image data.
|
|
|
|
* @returns Pointer to raw image data.
|
|
|
|
*/
|
2017-02-12 00:14:04 +01:00
|
|
|
static inline void* C3D_Tex2DGetImagePtr(C3D_Tex* tex, int level, u32* size)
|
|
|
|
{
|
|
|
|
return C3D_TexGetImagePtr(tex, tex->data, level, size);
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Gets pointer to cubemap texture image
|
|
|
|
* @param[in] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @param[in] face Specifies the cubemap texture face.
|
|
|
|
* @param[in] level Specifies mipmap level.
|
|
|
|
* @param[out] size Can be used to get the size of the image data.
|
|
|
|
* @returns Pointer to raw image data.
|
|
|
|
*/
|
2017-02-12 00:14:04 +01:00
|
|
|
static inline void* C3D_TexCubeGetImagePtr(C3D_Tex* tex, GPU_TEXFACE face, int level, u32* size)
|
2017-02-11 18:29:41 +01:00
|
|
|
{
|
2017-02-12 00:14:04 +01:00
|
|
|
return C3D_TexGetImagePtr(tex, tex->cube->data[face], level, size);
|
2017-02-11 18:29:41 +01:00
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Copies raw texture data into standard 2D texture
|
|
|
|
* @param[out] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @param[in] data Pointer to raw texture data.
|
|
|
|
*/
|
2017-02-09 20:07:37 +01:00
|
|
|
static inline void C3D_TexUpload(C3D_Tex* tex, const void* data)
|
|
|
|
{
|
2017-02-12 00:14:04 +01:00
|
|
|
C3D_TexLoadImage(tex, data, GPU_TEXFACE_2D, 0);
|
2017-02-09 20:07:37 +01:00
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Configures texture magnification and minification filters
|
|
|
|
* @param[out] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @param[in] magFilter Specifies the filtering to use when magnifying the the texture.
|
|
|
|
* @param[in] minFilter Specifies the filtering to use when minifying the the texture.
|
|
|
|
*/
|
2017-02-09 20:07:37 +01:00
|
|
|
static inline void C3D_TexSetFilter(C3D_Tex* tex, GPU_TEXTURE_FILTER_PARAM magFilter, GPU_TEXTURE_FILTER_PARAM minFilter)
|
|
|
|
{
|
|
|
|
tex->param &= ~(GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR));
|
|
|
|
tex->param |= GPU_TEXTURE_MAG_FILTER(magFilter) | GPU_TEXTURE_MIN_FILTER(minFilter);
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Configures texture mipmap minification filters
|
|
|
|
* @param[out] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @param[in] filter Specifies the filtering to use when minifying the the mipmap.
|
|
|
|
*/
|
2017-02-09 20:07:37 +01:00
|
|
|
static inline void C3D_TexSetFilterMipmap(C3D_Tex* tex, GPU_TEXTURE_FILTER_PARAM filter)
|
|
|
|
{
|
|
|
|
tex->param &= ~GPU_TEXTURE_MIP_FILTER(GPU_LINEAR);
|
|
|
|
tex->param |= GPU_TEXTURE_MIP_FILTER(filter);
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Configures texture wrapping options
|
|
|
|
* @param[out] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @param[in] wrapS Specifies the texture wrapping mode for texture coordinate S (aka U).
|
|
|
|
* @param[in] wrapT Specifies the texture wrapping mode for texture coordinate T (aka V).
|
|
|
|
*/
|
2017-02-09 20:07:37 +01:00
|
|
|
static inline void C3D_TexSetWrap(C3D_Tex* tex, GPU_TEXTURE_WRAP_PARAM wrapS, GPU_TEXTURE_WRAP_PARAM wrapT)
|
|
|
|
{
|
|
|
|
tex->param &= ~(GPU_TEXTURE_WRAP_S(3) | GPU_TEXTURE_WRAP_T(3));
|
|
|
|
tex->param |= GPU_TEXTURE_WRAP_S(wrapS) | GPU_TEXTURE_WRAP_T(wrapT);
|
|
|
|
}
|
|
|
|
|
2024-01-17 03:31:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Configures texture level of detail bias used to select the correct mipmap during sampling
|
|
|
|
* @param[out] tex Pointer to \ref C3D_Tex.
|
|
|
|
* @param[in] lodBias Specifies the texture level of detail bias.
|
|
|
|
*/
|
2017-02-09 20:07:37 +01:00
|
|
|
static inline void C3D_TexSetLodBias(C3D_Tex* tex, float lodBias)
|
|
|
|
{
|
|
|
|
int iLodBias = (int)(lodBias*0x100);
|
|
|
|
if (iLodBias > 0xFFF)
|
|
|
|
iLodBias = 0xFFF;
|
|
|
|
else if (iLodBias < -0x1000)
|
|
|
|
iLodBias = -0x1000;
|
|
|
|
tex->lodBias = iLodBias & 0x1FFF;
|
|
|
|
}
|