This commit is contained in:
zy 2024-12-29 19:19:38 +01:00
parent 714d9a8187
commit 5a116fa904
25 changed files with 3176 additions and 0 deletions

16
include/c3d/attribs.h Normal file
View file

@ -0,0 +1,16 @@
#pragma once
#include "types.h"
typedef struct
{
u32 flags[2];
u64 permutation;
int attrCount;
} C3D_AttrInfo;
void AttrInfo_Init(C3D_AttrInfo* info);
int AttrInfo_AddLoader(C3D_AttrInfo* info, int regId, GPU_FORMATS format, int count);
int AttrInfo_AddFixed(C3D_AttrInfo* info, int regId);
C3D_AttrInfo* C3D_GetAttrInfo(void);
void C3D_SetAttrInfo(C3D_AttrInfo* info);

46
include/c3d/base.h Normal file
View file

@ -0,0 +1,46 @@
#pragma once
#include "buffers.h"
#include "maths.h"
#define C3D_DEFAULT_CMDBUF_SIZE 0x40000
enum
{
C3D_UNSIGNED_BYTE = 0,
C3D_UNSIGNED_SHORT = 1,
};
bool C3D_Init(size_t cmdBufSize);
void C3D_Fini(void);
float C3D_GetCmdBufUsage(void);
void C3D_BindProgram(shaderProgram_s* program);
void C3D_SetViewport(u32 x, u32 y, u32 w, u32 h);
void C3D_SetScissor(GPU_SCISSORMODE mode, u32 left, u32 top, u32 right, u32 bottom);
void C3D_DrawArrays(GPU_Primitive_t primitive, int first, int size);
void C3D_DrawElements(GPU_Primitive_t primitive, int count, int type, const void* indices);
// Immediate-mode vertex submission
void C3D_ImmDrawBegin(GPU_Primitive_t primitive);
void C3D_ImmSendAttrib(float x, float y, float z, float w);
void C3D_ImmDrawEnd(void);
static inline void C3D_ImmDrawRestartPrim(void)
{
GPUCMD_AddWrite(GPUREG_RESTART_PRIMITIVE, 1);
}
// Fixed vertex attributes
C3D_FVec* C3D_FixedAttribGetWritePtr(int id);
static inline void C3D_FixedAttribSet(int id, float x, float y, float z, float w)
{
C3D_FVec* ptr = C3D_FixedAttribGetWritePtr(id);
ptr->x = x;
ptr->y = y;
ptr->z = z;
ptr->w = w;
}

21
include/c3d/buffers.h Normal file
View file

@ -0,0 +1,21 @@
#pragma once
#include "types.h"
typedef struct
{
u32 offset;
u32 flags[2];
} C3D_BufCfg;
typedef struct
{
u32 base_paddr;
int bufCount;
C3D_BufCfg buffers[12];
} C3D_BufInfo;
void BufInfo_Init(C3D_BufInfo* info);
int BufInfo_Add(C3D_BufInfo* info, const void* data, ptrdiff_t stride, int attribCount, u64 permutation);
C3D_BufInfo* C3D_GetBufInfo(void);
void C3D_SetBufInfo(C3D_BufInfo* info);

15
include/c3d/effect.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include "types.h"
void C3D_DepthMap(bool bIsZBuffer, float zScale, float zOffset);
void C3D_CullFace(GPU_CULLMODE mode);
void C3D_StencilTest(bool enable, GPU_TESTFUNC function, int ref, int inputMask, int writeMask);
void C3D_StencilOp(GPU_STENCILOP sfail, GPU_STENCILOP dfail, GPU_STENCILOP pass);
void C3D_BlendingColor(u32 color);
void C3D_EarlyDepthTest(bool enable, GPU_EARLYDEPTHFUNC function, u32 ref);
void C3D_DepthTest(bool enable, GPU_TESTFUNC function, GPU_WRITEMASK writemask);
void C3D_AlphaTest(bool enable, GPU_TESTFUNC function, int ref);
void C3D_AlphaBlend(GPU_BLENDEQUATION colorEq, GPU_BLENDEQUATION alphaEq, GPU_BLENDFACTOR srcClr, GPU_BLENDFACTOR dstClr, GPU_BLENDFACTOR srcAlpha, GPU_BLENDFACTOR dstAlpha);
void C3D_ColorLogicOp(GPU_LOGICOP op);
void C3D_FragOpMode(GPU_FRAGOPMODE mode);
void C3D_FragOpShadow(float scale, float bias);

39
include/c3d/fog.h Normal file
View file

@ -0,0 +1,39 @@
#pragma once
#include "types.h"
#include <math.h>
typedef struct
{
u32 data[128];
} C3D_FogLut;
typedef struct
{
u32 diff[8];
u32 color[8];
} C3D_GasLut;
static inline float FogLut_CalcZ(float depth, float near, float far)
{
return far*near/(depth*(far-near)+near);
}
void FogLut_FromArray(C3D_FogLut* lut, const float data[256]);
void FogLut_Exp(C3D_FogLut* lut, float density, float gradient, float near, float far);
void C3D_FogGasMode(GPU_FOGMODE fogMode, GPU_GASMODE gasMode, bool zFlip);
void C3D_FogColor(u32 color);
void C3D_FogLutBind(C3D_FogLut* lut);
void GasLut_FromArray(C3D_GasLut* lut, const u32 data[9]);
void C3D_GasBeginAcc(void);
void C3D_GasDeltaZ(float value);
void C3D_GasAccMax(float value);
void C3D_GasAttn(float value);
void C3D_GasLightPlanar(float min, float max, float attn);
void C3D_GasLightView(float min, float max, float attn);
void C3D_GasLightDirection(float dotp);
void C3D_GasLutInput(GPU_GASLUTINPUT input);
void C3D_GasLutBind(C3D_GasLut* lut);

69
include/c3d/framebuffer.h Normal file
View file

@ -0,0 +1,69 @@
#pragma once
#include "texture.h"
typedef struct
{
void* colorBuf;
void* depthBuf;
u16 width;
u16 height;
GPU_COLORBUF colorFmt;
GPU_DEPTHBUF depthFmt;
bool block32;
u8 colorMask : 4;
u8 depthMask : 4;
} C3D_FrameBuf;
// Flags for C3D_FrameBufClear
typedef enum
{
C3D_CLEAR_COLOR = BIT(0),
C3D_CLEAR_DEPTH = BIT(1),
C3D_CLEAR_ALL = C3D_CLEAR_COLOR | C3D_CLEAR_DEPTH,
} C3D_ClearBits;
u32 C3D_CalcColorBufSize(u32 width, u32 height, GPU_COLORBUF fmt);
u32 C3D_CalcDepthBufSize(u32 width, u32 height, GPU_DEPTHBUF fmt);
C3D_FrameBuf* C3D_GetFrameBuf(void);
void C3D_SetFrameBuf(C3D_FrameBuf* fb);
void C3D_FrameBufTex(C3D_FrameBuf* fb, C3D_Tex* tex, GPU_TEXFACE face, int level);
void C3D_FrameBufClear(C3D_FrameBuf* fb, C3D_ClearBits clearBits, u32 clearColor, u32 clearDepth);
void C3D_FrameBufTransfer(C3D_FrameBuf* fb, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags);
static inline void C3D_FrameBufAttrib(C3D_FrameBuf* fb, u16 width, u16 height, bool block32)
{
fb->width = width;
fb->height = height;
fb->block32 = block32;
}
static inline void C3D_FrameBufColor(C3D_FrameBuf* fb, void* buf, GPU_COLORBUF fmt)
{
if (buf)
{
fb->colorBuf = buf;
fb->colorFmt = fmt;
fb->colorMask = 0xF;
} else
{
fb->colorBuf = NULL;
fb->colorFmt = GPU_RB_RGBA8;
fb->colorMask = 0;
}
}
static inline void C3D_FrameBufDepth(C3D_FrameBuf* fb, void* buf, GPU_DEPTHBUF fmt)
{
if (buf)
{
fb->depthBuf = buf;
fb->depthFmt = fmt;
fb->depthMask = fmt == GPU_RB_DEPTH24_STENCIL8 ? 0x3 : 0x2;
} else
{
fb->depthBuf = NULL;
fb->depthFmt = GPU_RB_DEPTH24;
fb->depthMask = 0;
}
}

157
include/c3d/light.h Normal file
View file

@ -0,0 +1,157 @@
#pragma once
#include "lightlut.h"
#include "maths.h"
//-----------------------------------------------------------------------------
// Material
//-----------------------------------------------------------------------------
typedef struct
{
float ambient[3];
float diffuse[3];
float specular0[3];
float specular1[3];
float emission[3];
} C3D_Material;
//-----------------------------------------------------------------------------
// Light environment
//-----------------------------------------------------------------------------
// Forward declarations
typedef struct C3D_Light_t C3D_Light;
typedef struct C3D_LightEnv_t C3D_LightEnv;
typedef struct
{
u32 abs, select, scale;
} C3D_LightLutInputConf;
typedef struct
{
u32 ambient;
u32 numLights;
u32 config[2];
C3D_LightLutInputConf lutInput;
u32 permutation;
} C3D_LightEnvConf;
enum
{
C3DF_LightEnv_Dirty = BIT(0),
C3DF_LightEnv_MtlDirty = BIT(1),
C3DF_LightEnv_LCDirty = BIT(2),
#define C3DF_LightEnv_IsCP(n) BIT(18+(n))
#define C3DF_LightEnv_IsCP_Any (0xFF<<18)
#define C3DF_LightEnv_LutDirty(n) BIT(26+(n))
#define C3DF_LightEnv_LutDirtyAll (0x3F<<26)
};
struct C3D_LightEnv_t
{
u32 flags;
C3D_LightLut* luts[6];
float ambient[3];
C3D_Light* lights[8];
C3D_LightEnvConf conf;
C3D_Material material;
};
void C3D_LightEnvInit(C3D_LightEnv* env);
void C3D_LightEnvBind(C3D_LightEnv* env);
void C3D_LightEnvMaterial(C3D_LightEnv* env, const C3D_Material* mtl);
void C3D_LightEnvAmbient(C3D_LightEnv* env, float r, float g, float b);
void C3D_LightEnvLut(C3D_LightEnv* env, GPU_LIGHTLUTID lutId, GPU_LIGHTLUTINPUT input, bool negative, C3D_LightLut* lut);
enum
{
GPU_SHADOW_PRIMARY = BIT(16),
GPU_SHADOW_SECONDARY = BIT(17),
GPU_INVERT_SHADOW = BIT(18),
GPU_SHADOW_ALPHA = BIT(19),
};
void C3D_LightEnvFresnel(C3D_LightEnv* env, GPU_FRESNELSEL selector);
void C3D_LightEnvBumpMode(C3D_LightEnv* env, GPU_BUMPMODE mode);
void C3D_LightEnvBumpSel(C3D_LightEnv* env, int texUnit);
/**
* @brief Configures whether to use the z component of the normal map.
* @param[out] env Pointer to light environment structure.
* @param[in] enable false if the z component is reconstructed from the xy components
* of the normal map, true if the z component is taken from the normal map.
*/
void C3D_LightEnvBumpNormalZ(C3D_LightEnv *env, bool enable);
void C3D_LightEnvShadowMode(C3D_LightEnv* env, u32 mode);
void C3D_LightEnvShadowSel(C3D_LightEnv* env, int texUnit);
void C3D_LightEnvClampHighlights(C3D_LightEnv* env, bool clamp);
//-----------------------------------------------------------------------------
// Light
//-----------------------------------------------------------------------------
typedef struct
{
u32 specular0, specular1, diffuse, ambient;
} C3D_LightMatConf;
typedef struct
{
C3D_LightMatConf material;
u16 position[3]; u16 padding0;
u16 spotDir[3]; u16 padding1;
u32 padding2;
u32 config;
u32 distAttnBias, distAttnScale;
} C3D_LightConf;
enum
{
C3DF_Light_Enabled = BIT(0),
C3DF_Light_Dirty = BIT(1),
C3DF_Light_MatDirty = BIT(2),
//C3DF_Light_Shadow = BIT(3),
//C3DF_Light_Spot = BIT(4),
//C3DF_Light_DistAttn = BIT(5),
C3DF_Light_SPDirty = BIT(14),
C3DF_Light_DADirty = BIT(15),
};
struct C3D_Light_t
{
u16 flags, id;
C3D_LightEnv* parent;
C3D_LightLut *lut_SP, *lut_DA;
float ambient[3];
float diffuse[3];
float specular0[3];
float specular1[3];
C3D_LightConf conf;
};
int C3D_LightInit(C3D_Light* light, C3D_LightEnv* env);
void C3D_LightEnable(C3D_Light* light, bool enable);
void C3D_LightTwoSideDiffuse(C3D_Light* light, bool enable);
void C3D_LightGeoFactor(C3D_Light* light, int id, bool enable);
void C3D_LightAmbient(C3D_Light* light, float r, float g, float b);
void C3D_LightDiffuse(C3D_Light* light, float r, float g, float b);
void C3D_LightSpecular0(C3D_Light* light, float r, float g, float b);
void C3D_LightSpecular1(C3D_Light* light, float r, float g, float b);
void C3D_LightPosition(C3D_Light* light, C3D_FVec* pos);
void C3D_LightShadowEnable(C3D_Light* light, bool enable);
void C3D_LightSpotEnable(C3D_Light* light, bool enable);
void C3D_LightSpotDir(C3D_Light* light, float x, float y, float z);
void C3D_LightSpotLut(C3D_Light* light, C3D_LightLut* lut);
void C3D_LightDistAttnEnable(C3D_Light* light, bool enable);
void C3D_LightDistAttn(C3D_Light* light, C3D_LightLutDA* lut);
static inline void C3D_LightColor(C3D_Light* light, float r, float g, float b)
{
C3D_LightDiffuse(light, r, g, b);
C3D_LightSpecular0(light, r, g, b);
C3D_LightSpecular1(light, r, g, b);
}

35
include/c3d/lightlut.h Normal file
View file

@ -0,0 +1,35 @@
#pragma once
#include "types.h"
#include <math.h>
typedef struct
{
u32 data[256];
} C3D_LightLut;
typedef struct
{
C3D_LightLut lut;
float bias, scale;
} C3D_LightLutDA;
typedef float (* C3D_LightLutFunc)(float x, float param);
typedef float (* C3D_LightLutFuncDA)(float dist, float arg0, float arg1);
static inline float quadratic_dist_attn(float dist, float linear, float quad)
{
return 1.0f / (1.0f + linear*dist + quad*dist*dist);
}
static inline float spot_step(float angle, float cutoff)
{
return angle >= cutoff ? 1.0f : 0.0f;
}
void LightLut_FromArray(C3D_LightLut* lut, float* data);
void LightLut_FromFunc(C3D_LightLut* lut, C3D_LightLutFunc func, float param, bool negative);
void LightLutDA_Create(C3D_LightLutDA* lut, C3D_LightLutFuncDA func, float from, float to, float arg0, float arg1);
#define LightLut_Phong(lut, shininess) LightLut_FromFunc((lut), powf, (shininess), false)
#define LightLut_Spotlight(lut, angle) LightLut_FromFunc((lut), spot_step, cosf(angle), true)
#define LightLutDA_Quadratic(lut, from, to, linear, quad) LightLutDA_Create((lut), quadratic_dist_attn, (from), (to), (linear), (quad))

796
include/c3d/maths.h Normal file
View file

@ -0,0 +1,796 @@
#pragma once
#include "types.h"
#include <math.h>
#include <string.h>
/**
* @addtogroup math_support
* @brief Implementations of matrix, vector, and quaternion operations.
* @{
*/
/**
* The one true circumference-to-radius ratio.
* See http://tauday.com/tau-manifesto
*/
#define M_TAU (6.28318530717958647692528676655900576)
// Define the legacy circle constant as well
#ifndef M_PI
#define M_PI (M_TAU/2)
#endif
/**
* @brief Convert an angle from revolutions to radians
* @param[in] _angle Proportion of a full revolution
* @return Angle in radians
*/
#define C3D_Angle(_angle) ((_angle)*M_TAU)
/**
* @brief Convert an angle from degrees to radians
* @param[in] _angle Angle in degrees
* @return Angle in radians
*/
#define C3D_AngleFromDegrees(_angle) ((_angle)*M_TAU/360.0f)
#define C3D_AspectRatioTop (400.0f / 240.0f) ///< Aspect ratio for 3DS top screen
#define C3D_AspectRatioBot (320.0f / 240.0f) ///< Aspect ratio for 3DS bottom screen
/**
* @name Vector Math
* @{
*/
/**
* @brief Create a new FVec4
* @param[in] x X-component
* @param[in] y Y-component
* @param[in] z Z-component
* @param[in] w W-component
* @return New FVec4
*/
static inline C3D_FVec FVec4_New(float x, float y, float z, float w)
{
return (C3D_FVec){{ w, z, y, x }};
}
/**
* @brief Add two FVec4s
* @param[in] lhs Augend
* @param[in] rhs Addend
* @return lhs+rhs (sum)
*/
static inline C3D_FVec FVec4_Add(C3D_FVec lhs, C3D_FVec rhs)
{
// component-wise addition
return FVec4_New(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z, lhs.w+rhs.w);
}
/**
* @brief Subtract two FVec4s
* @param[in] lhs Minuend
* @param[in] rhs Subtrahend
* @return lhs-rhs (difference)
*/
static inline C3D_FVec FVec4_Subtract(C3D_FVec lhs, C3D_FVec rhs)
{
// component-wise subtraction
return FVec4_New(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z, lhs.w-rhs.w);
}
/**
* @brief Negate a FVec4
* @note This is equivalent to `FVec4_Scale(v, -1)`
* @param[in] v Vector to negate
* @return -v
*/
static inline C3D_FVec FVec4_Negate(C3D_FVec v)
{
// component-wise negation
return FVec4_New(-v.x, -v.y, -v.z, -v.w);
}
/**
* @brief Scale a FVec4
* @param[in] v Vector to scale
* @param[in] s Scale factor
* @return v*s
*/
static inline C3D_FVec FVec4_Scale(C3D_FVec v, float s)
{
// component-wise scaling
return FVec4_New(v.x*s, v.y*s, v.z*s, v.w*s);
}
/**
* @brief Perspective divide
* @param[in] v Vector to divide
* @return v/v.w
*/
static inline C3D_FVec FVec4_PerspDivide(C3D_FVec v)
{
// divide by w
return FVec4_New(v.x/v.w, v.y/v.w, v.z/v.w, 1.0f);
}
/**
* @brief Dot product of two FVec4s
* @param[in] lhs Left-side FVec4
* @param[in] rhs Right-side FVec4
* @return lhsrhs
*/
static inline float FVec4_Dot(C3D_FVec lhs, C3D_FVec rhs)
{
// A∙B = sum of component-wise products
return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z + lhs.w*rhs.w;
}
/**
* @brief Magnitude of a FVec4
* @param[in] v Vector
* @return v
*/
static inline float FVec4_Magnitude(C3D_FVec v)
{
// ‖v‖ = √(v∙v)
return sqrtf(FVec4_Dot(v,v));
}
/**
* @brief Normalize a FVec4
* @param[in] v FVec4 to normalize
* @return v/v
*/
static inline C3D_FVec FVec4_Normalize(C3D_FVec v)
{
// get vector magnitude
float m = FVec4_Magnitude(v);
// scale by inverse magnitude to get a unit vector
return FVec4_New(v.x/m, v.y/m, v.z/m, v.w/m);
}
/**
* @brief Create a new FVec3
* @param[in] x X-component
* @param[in] y Y-component
* @param[in] z Z-component
* @return New FVec3
*/
static inline C3D_FVec FVec3_New(float x, float y, float z)
{
return FVec4_New(x, y, z, 0.0f);
}
/**
* @brief Dot product of two FVec3s
* @param[in] lhs Left-side FVec3
* @param[in] rhs Right-side FVec3
* @return lhsrhs
*/
static inline float FVec3_Dot(C3D_FVec lhs, C3D_FVec rhs)
{
// A∙B = sum of component-wise products
return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z;
}
/**
* @brief Magnitude of a FVec3
* @param[in] v Vector
* @return v
*/
static inline float FVec3_Magnitude(C3D_FVec v)
{
// ‖v‖ = √(v∙v)
return sqrtf(FVec3_Dot(v,v));
}
/**
* @brief Normalize a FVec3
* @param[in] v FVec3 to normalize
* @return v/v
*/
static inline C3D_FVec FVec3_Normalize(C3D_FVec v)
{
// get vector magnitude
float m = FVec3_Magnitude(v);
// scale by inverse magnitude to get a unit vector
return FVec3_New(v.x/m, v.y/m, v.z/m);
}
/**
* @brief Add two FVec3s
* @param[in] lhs Augend
* @param[in] rhs Addend
* @return lhs+rhs (sum)
*/
static inline C3D_FVec FVec3_Add(C3D_FVec lhs, C3D_FVec rhs)
{
// component-wise addition
return FVec3_New(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z);
}
/**
* @brief Subtract two FVec3s
* @param[in] lhs Minuend
* @param[in] rhs Subtrahend
* @return lhs-rhs (difference)
*/
static inline C3D_FVec FVec3_Subtract(C3D_FVec lhs, C3D_FVec rhs)
{
// component-wise subtraction
return FVec3_New(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z);
}
/**
* @brief Distance between two 3D points
* @param[in] lhs Relative origin
* @param[in] rhs Relative point of interest
* @return lhs-rhs
*/
static inline float FVec3_Distance(C3D_FVec lhs, C3D_FVec rhs)
{
// distance = ‖lhs-rhs‖
return FVec3_Magnitude(FVec3_Subtract(lhs, rhs));
}
/**
* @brief Scale a FVec3
* @param[in] v Vector to scale
* @param[in] s Scale factor
* @return v*s
*/
static inline C3D_FVec FVec3_Scale(C3D_FVec v, float s)
{
// component-wise scaling
return FVec3_New(v.x*s, v.y*s, v.z*s);
}
/**
* @brief Negate a FVec3
* @note This is equivalent to `FVec3_Scale(v, -1)`
* @param[in] v Vector to negate
* @return -v
*/
static inline C3D_FVec FVec3_Negate(C3D_FVec v)
{
// component-wise negation
return FVec3_New(-v.x, -v.y, -v.z);
}
/**
* @brief Cross product of two FVec3s
* @note This returns a pseudo-vector which is perpendicular to the plane
* spanned by the two input vectors.
* @param[in] lhs Left-side FVec3
* @param[in] rhs Right-side FVec3
* @return lhs×rhs
*/
static inline C3D_FVec FVec3_Cross(C3D_FVec lhs, C3D_FVec rhs)
{
// A×B = (AyBz - AzBy, AzBx - AxBz, AxBy - AyBx)
return FVec3_New(lhs.y*rhs.z - lhs.z*rhs.y, lhs.z*rhs.x - lhs.x*rhs.z, lhs.x*rhs.y - lhs.y*rhs.x);
}
/** @} */
/**
* @name Matrix Math
* @note All matrices are 4x4 unless otherwise noted.
* @{
*/
/**
* @brief Zero matrix
* @param[out] out Matrix to zero
*/
static inline void Mtx_Zeros(C3D_Mtx* out)
{
memset(out, 0, sizeof(*out));
}
/**
* @brief Copy a matrix
* @param[out] out Output matrix
* @param[in] in Input matrix
*/
static inline void Mtx_Copy(C3D_Mtx* out, const C3D_Mtx* in)
{
*out = *in;
}
/**
* @brief Creates a matrix with the diagonal using the given parameters.
* @param[out] out Output matrix.
* @param[in] x The X component.
* @param[in] y The Y component.
* @param[in] z The Z component.
* @param[in] w The W component.
*/
static inline void Mtx_Diagonal(C3D_Mtx* out, float x, float y, float z, float w)
{
Mtx_Zeros(out);
out->r[0].x = x;
out->r[1].y = y;
out->r[2].z = z;
out->r[3].w = w;
}
/**
* @brief Identity matrix
* @param[out] out Matrix to fill
*/
static inline void Mtx_Identity(C3D_Mtx* out)
{
Mtx_Diagonal(out, 1.0f, 1.0f, 1.0f, 1.0f);
}
/**
*@brief Transposes the matrix. Row => Column, and vice versa.
*@param[in,out] out Output matrix.
*/
void Mtx_Transpose(C3D_Mtx* out);
/**
* @brief Matrix addition
* @param[out] out Output matrix.
* @param[in] lhs Left matrix.
* @param[in] rhs Right matrix.
* @return lhs+rhs (sum)
*/
static inline void Mtx_Add(C3D_Mtx* out, const C3D_Mtx* lhs, const C3D_Mtx* rhs)
{
for (int i = 0; i < 16; i++)
out->m[i] = lhs->m[i] + rhs->m[i];
}
/**
* @brief Matrix subtraction
* @param[out] out Output matrix.
* @param[in] lhs Left matrix.
* @param[in] rhs Right matrix.
* @return lhs-rhs (difference)
*/
static inline void Mtx_Subtract(C3D_Mtx* out, const C3D_Mtx* lhs, const C3D_Mtx* rhs)
{
for (int i = 0; i < 16; i++)
out->m[i] = lhs->m[i] - rhs->m[i];
}
/**
* @brief Multiply two matrices
* @param[out] out Output matrix
* @param[in] a Multiplicand
* @param[in] b Multiplier
*/
void Mtx_Multiply(C3D_Mtx* out, const C3D_Mtx* a, const C3D_Mtx* b);
/**
* @brief Inverse a matrix
* @param[in,out] out Matrix to inverse
* @retval 0.0f Degenerate matrix (no inverse)
* @return determinant
*/
float Mtx_Inverse(C3D_Mtx* out);
/**
* @brief Multiply 3x3 matrix by a FVec3
* @param[in] mtx Matrix
* @param[in] v Vector
* @return mtx*v (product)
*/
C3D_FVec Mtx_MultiplyFVec3(const C3D_Mtx* mtx, C3D_FVec v);
/**
* @brief Multiply 4x4 matrix by a FVec4
* @param[in] mtx Matrix
* @param[in] v Vector
* @return mtx*v (product)
*/
C3D_FVec Mtx_MultiplyFVec4(const C3D_Mtx* mtx, C3D_FVec v);
/**
* @brief Multiply 4x3 matrix by a FVec3
* @param[in] mtx Matrix
* @param[in] v Vector
* @return mtx*v (product)
*/
static inline C3D_FVec Mtx_MultiplyFVecH(const C3D_Mtx* mtx, C3D_FVec v)
{
v.w = 1.0f;
return Mtx_MultiplyFVec4(mtx, v);
}
/**
* @brief Get 4x4 matrix equivalent to Quaternion
* @param[out] m Output matrix
* @param[in] q Input Quaternion
*/
void Mtx_FromQuat(C3D_Mtx* m, C3D_FQuat q);
/** @} */
/**
* @name 3D Transformation Matrix Math
* @note bRightSide is used to determine which side to perform the transformation.
* With an input matrix A and a transformation matrix B, bRightSide being
* true yields AB, while being false yield BA.
* @{
*/
/**
* @brief 3D translation
* @param[in,out] mtx Matrix to translate
* @param[in] x X component to translate
* @param[in] y Y component to translate
* @param[in] z Z component to translate
* @param[in] bRightSide Whether to transform from the right side
*/
void Mtx_Translate(C3D_Mtx* mtx, float x, float y, float z, bool bRightSide);
/**
* @brief 3D Scale
* @param[in,out] mtx Matrix to scale
* @param[in] x X component to scale
* @param[in] y Y component to scale
* @param[in] z Z component to scale
*/
void Mtx_Scale(C3D_Mtx* mtx, float x, float y, float z);
/**
* @brief 3D Rotation
* @param[in,out] mtx Matrix to rotate
* @param[in] axis Axis about which to rotate
* @param[in] angle Radians to rotate
* @param[in] bRightSide Whether to transform from the right side
*/
void Mtx_Rotate(C3D_Mtx* mtx, C3D_FVec axis, float angle, bool bRightSide);
/**
* @brief 3D Rotation about the X axis
* @param[in,out] mtx Matrix to rotate
* @param[in] angle Radians to rotate
* @param[in] bRightSide Whether to transform from the right side
*/
void Mtx_RotateX(C3D_Mtx* mtx, float angle, bool bRightSide);
/**
* @brief 3D Rotation about the Y axis
* @param[in,out] mtx Matrix to rotate
* @param[in] angle Radians to rotate
* @param[in] bRightSide Whether to transform from the right side
*/
void Mtx_RotateY(C3D_Mtx* mtx, float angle, bool bRightSide);
/**
* @brief 3D Rotation about the Z axis
* @param[in,out] mtx Matrix to rotate
* @param[in] angle Radians to rotate
* @param[in] bRightSide Whether to transform from the right side
*/
void Mtx_RotateZ(C3D_Mtx* mtx, float angle, bool bRightSide);
/** @} */
/**
* @name 3D Projection Matrix Math
* @{
*/
/**
* @brief Orthogonal projection
* @param[out] mtx Output matrix
* @param[in] left Left clip plane (X=left)
* @param[in] right Right clip plane (X=right)
* @param[in] bottom Bottom clip plane (Y=bottom)
* @param[in] top Top clip plane (Y=top)
* @param[in] near Near clip plane (Z=near)
* @param[in] far Far clip plane (Z=far)
* @param[in] isLeftHanded Whether to build a LH projection
* @sa Mtx_OrthoTilt
*/
void Mtx_Ortho(C3D_Mtx* mtx, float left, float right, float bottom, float top, float near, float far, bool isLeftHanded);
/**
* @brief Perspective projection
* @param[out] mtx Output matrix
* @param[in] fovy Vertical field of view in radians
* @param[in] aspect Aspect ration of projection plane (width/height)
* @param[in] near Near clip plane (Z=near)
* @param[in] far Far clip plane (Z=far)
* @param[in] isLeftHanded Whether to build a LH projection
* @sa Mtx_PerspTilt
* @sa Mtx_PerspStereo
* @sa Mtx_PerspStereoTilt
*/
void Mtx_Persp(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, bool isLeftHanded);
/**
* @brief Stereo perspective projection
* @note Typically you will use iod to mean the distance between the eyes. Plug
* in -iod for the left eye and iod for the right eye.
* @note The focal length is defined by screen. If objects are further than this,
* they will appear to be inside the screen. If objects are closer than this,
* they will appear to pop out of the screen. Objects at this distance appear
* to be at the screen.
* @param[out] mtx Output matrix
* @param[in] fovy Vertical field of view in radians
* @param[in] aspect Aspect ration of projection plane (width/height)
* @param[in] near Near clip plane (Z=near)
* @param[in] far Far clip plane (Z=far)
* @param[in] iod Interocular distance
* @param[in] screen Focal length
* @param[in] isLeftHanded Whether to build a LH projection
* @sa Mtx_Persp
* @sa Mtx_PerspTilt
* @sa Mtx_PerspStereoTilt
*/
void Mtx_PerspStereo(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, float iod, float screen, bool isLeftHanded);
/**
* @brief Orthogonal projection, tilted to account for the 3DS screen rotation
* @param[out] mtx Output matrix
* @param[in] left Left clip plane (X=left)
* @param[in] right Right clip plane (X=right)
* @param[in] bottom Bottom clip plane (Y=bottom)
* @param[in] top Top clip plane (Y=top)
* @param[in] near Near clip plane (Z=near)
* @param[in] far Far clip plane (Z=far)
* @param[in] isLeftHanded Whether to build a LH projection
* @sa Mtx_Ortho
*/
void Mtx_OrthoTilt(C3D_Mtx* mtx, float left, float right, float bottom, float top, float near, float far, bool isLeftHanded);
/**
* @brief Perspective projection, tilted to account for the 3DS screen rotation
* @param[out] mtx Output matrix
* @param[in] fovy Vertical field of view in radians
* @param[in] aspect Aspect ration of projection plane (width/height)
* @param[in] near Near clip plane (Z=near)
* @param[in] far Far clip plane (Z=far)
* @param[in] isLeftHanded Whether to build a LH projection
* @sa Mtx_Persp
* @sa Mtx_PerspStereo
* @sa Mtx_PerspStereoTilt
*/
void Mtx_PerspTilt(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, bool isLeftHanded);
/**
* @brief Stereo perspective projection, tilted to account for the 3DS screen rotation
* @note See the notes for @ref Mtx_PerspStereo
* @param[out] mtx Output matrix
* @param[in] fovy Vertical field of view in radians
* @param[in] aspect Aspect ration of projection plane (width/height)
* @param[in] near Near clip plane (Z=near)
* @param[in] far Far clip plane (Z=far)
* @param[in] iod Interocular distance
* @param[in] screen Focal length
* @param[in] isLeftHanded Whether to build a LH projection
* @sa Mtx_Persp
* @sa Mtx_PerspTilt
* @sa Mtx_PerspStereo
*/
void Mtx_PerspStereoTilt(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, float iod, float screen, bool isLeftHanded);
/**
* @brief Look-At matrix, based on DirectX implementation
* @note See https://msdn.microsoft.com/en-us/library/windows/desktop/bb205342
* @param[out] out Output matrix.
* @param[in] cameraPosition Position of the intended camera in 3D space.
* @param[in] cameraTarget Position of the intended target the camera is supposed to face in 3D space.
* @param[in] cameraUpVector The vector that points straight up depending on the camera's "Up" direction.
* @param[in] isLeftHanded Whether to build a LH projection
*/
void Mtx_LookAt(C3D_Mtx* out, C3D_FVec cameraPosition, C3D_FVec cameraTarget, C3D_FVec cameraUpVector, bool isLeftHanded);
/** @} */
/**
* @name Quaternion Math
* @{
*/
/**
* @brief Create a new Quaternion
* @param[in] i I-component
* @param[in] j J-component
* @param[in] k K-component
* @param[in] r Real component
* @return New Quaternion
*/
#define Quat_New(i,j,k,r) FVec4_New(i,j,k,r)
/**
* @brief Negate a Quaternion
* @note This is equivalent to `Quat_Scale(v, -1)`
* @param[in] q Quaternion to negate
* @return -q
*/
#define Quat_Negate(q) FVec4_Negate(q)
/**
* @brief Add two Quaternions
* @param[in] lhs Augend
* @param[in] rhs Addend
* @return lhs+rhs (sum)
*/
#define Quat_Add(lhs,rhs) FVec4_Add(lhs,rhs)
/**
* @brief Subtract two Quaternions
* @param[in] lhs Minuend
* @param[in] rhs Subtrahend
* @return lhs-rhs (difference)
*/
#define Quat_Subtract(lhs,rhs) FVec4_Subtract(lhs,rhs)
/**
* @brief Scale a Quaternion
* @param[in] q Quaternion to scale
* @param[in] s Scale factor
* @return q*s
*/
#define Quat_Scale(q,s) FVec4_Scale(q,s)
/**
* @brief Normalize a Quaternion
* @param[in] q Quaternion to normalize
* @return q/q
*/
#define Quat_Normalize(q) FVec4_Normalize(q)
/**
* @brief Dot product of two Quaternions
* @param[in] lhs Left-side Quaternion
* @param[in] rhs Right-side Quaternion
* @return lhsrhs
*/
#define Quat_Dot(lhs,rhs) FVec4_Dot(lhs,rhs)
/**
* @brief Multiply two Quaternions
* @param[in] lhs Multiplicand
* @param[in] rhs Multiplier
* @return lhs*rhs
*/
C3D_FQuat Quat_Multiply(C3D_FQuat lhs, C3D_FQuat rhs);
/**
* @brief Raise Quaternion to a power
* @note If p is 0, this returns the identity Quaternion.
* If p is 1, this returns q.
* @param[in] q Base Quaternion
* @param[in] p Power
* @return q<sup>p</sup>
*/
C3D_FQuat Quat_Pow(C3D_FQuat q, float p);
/**
* @brief Cross product of Quaternion and FVec3
* @param[in] q Base Quaternion
* @param[in] v Vector to cross
* @return q×v
*/
C3D_FVec Quat_CrossFVec3(C3D_FQuat q, C3D_FVec v);
/**
* @brief 3D Rotation
* @param[in] q Quaternion to rotate
* @param[in] axis Axis about which to rotate
* @param[in] r Radians to rotate
* @param[in] bRightSide Whether to transform from the right side
* @return Rotated Quaternion
*/
C3D_FQuat Quat_Rotate(C3D_FQuat q, C3D_FVec axis, float r, bool bRightSide);
/**
* @brief 3D Rotation about the X axis
* @param[in] q Quaternion to rotate
* @param[in] r Radians to rotate
* @param[in] bRightSide Whether to transform from the right side
* @return Rotated Quaternion
*/
C3D_FQuat Quat_RotateX(C3D_FQuat q, float r, bool bRightSide);
/**
* @brief 3D Rotation about the Y axis
* @param[in] q Quaternion to rotate
* @param[in] r Radians to rotate
* @param[in] bRightSide Whether to transform from the right side
* @return Rotated Quaternion
*/
C3D_FQuat Quat_RotateY(C3D_FQuat q, float r, bool bRightSide);
/**
* @brief 3D Rotation about the Z axis
* @param[in] q Quaternion to rotate
* @param[in] r Radians to rotate
* @param[in] bRightSide Whether to transform from the right side
* @return Rotated Quaternion
*/
C3D_FQuat Quat_RotateZ(C3D_FQuat q, float r, bool bRightSide);
/**
* @brief Get Quaternion equivalent to 4x4 matrix
* @note If the matrix is orthogonal or special orthogonal, where determinant(matrix) = +1.0f, then the matrix can be converted.
* @param[in] m Input Matrix
* @return Generated Quaternion
*/
C3D_FQuat Quat_FromMtx(const C3D_Mtx* m);
/**
* @brief Identity Quaternion
* @return Identity Quaternion
*/
static inline C3D_FQuat Quat_Identity(void)
{
// r=1, i=j=k=0
return Quat_New(0.0f, 0.0f, 0.0f, 1.0f);
}
/**
* @brief Quaternion conjugate
* @param[in] q Quaternion of which to get conjugate
* @return q*
*/
static inline C3D_FQuat Quat_Conjugate(C3D_FQuat q)
{
// q* = q.r - q.i - q.j - q.k
return Quat_New(-q.i, -q.j, -q.k, q.r);
}
/**
* @brief Quaternion inverse
* @note This is equivalent to `Quat_Pow(v, -1)`
* @param[in] q Quaternion of which to get inverse
* @return q<sup>-1</sup>
*/
static inline C3D_FQuat Quat_Inverse(C3D_FQuat q)
{
// q^-1 = (q.r - q.i - q.j - q.k) / (q.r^2 + q.i^2 + q.j^2 + q.k^2)
// = q* / (q∙q)
C3D_FQuat c = Quat_Conjugate(q);
float d = Quat_Dot(q, q);
return Quat_New(c.i/d, c.j/d, c.k/d, c.r/d);
}
/**
* @brief Cross product of FVec3 and Quaternion
* @param[in] v Base FVec3
* @param[in] q Quaternion to cross
* @return v×q
*/
static inline C3D_FVec FVec3_CrossQuat(C3D_FVec v, C3D_FQuat q)
{
// v×q = (q^-1)×v
return Quat_CrossFVec3(Quat_Inverse(q), v);
}
/**
* @brief Converting Pitch, Yaw, and Roll to Quaternion equivalent
* @param[in] pitch The pitch angle in radians.
* @param[in] yaw The yaw angle in radians.
* @param[in] roll The roll angle in radians.
* @param[in] bRightSide Whether to transform from the right side
* @return C3D_FQuat The Quaternion equivalent with the pitch, yaw, and roll (in that order) orientations applied.
*/
C3D_FQuat Quat_FromPitchYawRoll(float pitch, float yaw, float roll, bool bRightSide);
/**
* @brief Quaternion Look-At
* @param[in] source C3D_FVec Starting position. Origin of rotation.
* @param[in] target C3D_FVec Target position to orient towards.
* @param[in] forwardVector C3D_FVec The Up vector.
* @param[in] upVector C3D_FVec The Up vector.
* @return Quaternion rotation.
*/
C3D_FQuat Quat_LookAt(C3D_FVec source, C3D_FVec target, C3D_FVec forwardVector, C3D_FVec upVector);
/**
* @brief Quaternion, created from a given axis and angle in radians.
* @param[in] axis C3D_FVec The axis to rotate around at.
* @param[in] angle float The angle to rotate. Unit: Radians
* @return Quaternion rotation based on the axis and angle. Axis doesn't have to be orthogonal.
*/
C3D_FQuat Quat_FromAxisAngle(C3D_FVec axis, float angle);
/** @} */
/** @} */

24
include/c3d/mtxstack.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include "maths.h"
#define C3D_MTXSTACK_SIZE 8
typedef struct
{
C3D_Mtx m[C3D_MTXSTACK_SIZE];
int pos;
u8 unifType, unifPos, unifLen;
bool isDirty;
} C3D_MtxStack;
static inline C3D_Mtx* MtxStack_Cur(C3D_MtxStack* stk)
{
stk->isDirty = true;
return &stk->m[stk->pos];
}
void MtxStack_Init(C3D_MtxStack* stk);
void MtxStack_Bind(C3D_MtxStack* stk, GPU_SHADER_TYPE unifType, int unifPos, int unifLen);
C3D_Mtx* MtxStack_Push(C3D_MtxStack* stk);
C3D_Mtx* MtxStack_Pop(C3D_MtxStack* stk);
void MtxStack_Update(C3D_MtxStack* stk);

125
include/c3d/proctex.h Normal file
View file

@ -0,0 +1,125 @@
#pragma once
#include "types.h"
typedef struct
{
u32 color[256];
u32 diff[256];
} C3D_ProcTexColorLut;
typedef struct
{
union
{
u32 proctex0;
struct
{
u32 uClamp : 3;
u32 vClamp : 3;
u32 rgbFunc : 4;
u32 alphaFunc : 4;
bool alphaSeparate : 1;
bool enableNoise : 1;
u32 uShift : 2;
u32 vShift : 2;
u32 lodBiasLow : 8;
};
};
union
{
u32 proctex1;
struct
{
u16 uNoiseAmpl;
u16 uNoisePhase;
};
};
union
{
u32 proctex2;
struct
{
u16 vNoiseAmpl;
u16 vNoisePhase;
};
};
union
{
u32 proctex3;
struct
{
u16 uNoiseFreq;
u16 vNoiseFreq;
};
};
union
{
u32 proctex4;
struct
{
u32 minFilter : 3;
u32 unknown1 : 8;
u32 width : 8;
u32 lodBiasHigh : 8;
};
};
union
{
u32 proctex5;
struct
{
u32 offset : 8;
u32 unknown2 : 24;
};
};
} C3D_ProcTex;
enum
{
C3D_ProcTex_U = BIT(0),
C3D_ProcTex_V = BIT(1),
C3D_ProcTex_UV = C3D_ProcTex_U | C3D_ProcTex_V,
};
void C3D_ProcTexInit(C3D_ProcTex* pt, int offset, int length);
void C3D_ProcTexNoiseCoefs(C3D_ProcTex* pt, int mode, float amplitude, float frequency, float phase);
void C3D_ProcTexLodBias(C3D_ProcTex* pt, float bias);
void C3D_ProcTexBind(int texCoordId, C3D_ProcTex* pt);
// GPU_LUT_NOISE, GPU_LUT_RGBMAP, GPU_LUT_ALPHAMAP
typedef u32 C3D_ProcTexLut[128];
void C3D_ProcTexLutBind(GPU_PROCTEX_LUTID id, C3D_ProcTexLut* lut);
void ProcTexLut_FromArray(C3D_ProcTexLut* lut, const float in[129]);
void C3D_ProcTexColorLutBind(C3D_ProcTexColorLut* lut);
void ProcTexColorLut_Write(C3D_ProcTexColorLut* out, const u32* in, int offset, int length);
static inline void C3D_ProcTexClamp(C3D_ProcTex* pt, GPU_PROCTEX_CLAMP u, GPU_PROCTEX_CLAMP v)
{
pt->uClamp = u;
pt->vClamp = v;
}
static inline void C3D_ProcTexCombiner(C3D_ProcTex* pt, bool separate, GPU_PROCTEX_MAPFUNC rgb, GPU_PROCTEX_MAPFUNC alpha)
{
pt->alphaSeparate = separate;
pt->rgbFunc = rgb;
if (separate)
pt->alphaFunc = alpha;
}
static inline void C3D_ProcTexNoiseEnable(C3D_ProcTex* pt, bool enable)
{
pt->enableNoise = enable;
}
static inline void C3D_ProcTexShift(C3D_ProcTex* pt, GPU_PROCTEX_SHIFT u, GPU_PROCTEX_SHIFT v)
{
pt->uShift = u;
pt->vShift = v;
}
static inline void C3D_ProcTexFilter(C3D_ProcTex* pt, GPU_PROCTEX_FILTER min)
{
pt->minFilter = min;
}

79
include/c3d/renderqueue.h Normal file
View file

@ -0,0 +1,79 @@
#pragma once
#include "framebuffer.h"
typedef struct C3D_RenderTarget_tag C3D_RenderTarget;
struct C3D_RenderTarget_tag
{
C3D_RenderTarget *next, *prev;
C3D_FrameBuf frameBuf;
bool used;
bool ownsColor, ownsDepth;
bool linked;
gfxScreen_t screen;
gfx3dSide_t side;
u32 transferFlags;
};
// Flags for C3D_FrameBegin
enum
{
C3D_FRAME_SYNCDRAW = BIT(0), // Perform C3D_FrameSync before checking the GPU status
C3D_FRAME_NONBLOCK = BIT(1), // Return false instead of waiting if the GPU is busy
};
float C3D_FrameRate(float fps);
void C3D_FrameSync(void);
u32 C3D_FrameCounter(int id);
bool C3D_FrameBegin(u8 flags);
bool C3D_FrameDrawOn(C3D_RenderTarget* target);
void C3D_FrameSplit(u8 flags);
void C3D_FrameEnd(u8 flags);
void C3D_FrameEndHook(void (* hook)(void*), void* param);
float C3D_GetDrawingTime(void);
float C3D_GetProcessingTime(void);
#if defined(__GNUC__) && !defined(__cplusplus)
typedef union __attribute__((__transparent_union__))
{
int __i;
GPU_DEPTHBUF __e;
} C3D_DEPTHTYPE;
#else
union C3D_DEPTHTYPE
{
private:
int __i;
GPU_DEPTHBUF __e;
public:
C3D_DEPTHTYPE(GPU_DEPTHBUF e) : __e(e) {}
C3D_DEPTHTYPE(int i) : __i(-1) { (void)i; }
};
#endif
#define C3D_DEPTHTYPE_OK(_x) ((_x).__i >= 0)
#define C3D_DEPTHTYPE_VAL(_x) ((_x).__e)
C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF colorFmt, C3D_DEPTHTYPE depthFmt);
C3D_RenderTarget* C3D_RenderTargetCreateFromTex(C3D_Tex* tex, GPU_TEXFACE face, int level, C3D_DEPTHTYPE depthFmt);
void C3D_RenderTargetDelete(C3D_RenderTarget* target);
void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags);
static inline void C3D_RenderTargetDetachOutput(C3D_RenderTarget* target)
{
C3D_RenderTargetSetOutput(NULL, target->screen, target->side, 0);
}
static inline void C3D_RenderTargetClear(C3D_RenderTarget* target, C3D_ClearBits clearBits, u32 clearColor, u32 clearDepth)
{
C3D_FrameBufClear(&target->frameBuf, clearBits, clearColor, clearDepth);
}
void C3D_SyncDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags);
void C3D_SyncTextureCopy(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 size, u32 flags);
void C3D_SyncMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1);

98
include/c3d/texenv.h Normal file
View file

@ -0,0 +1,98 @@
#pragma once
#include "types.h"
typedef struct
{
u16 srcRgb, srcAlpha;
union
{
u32 opAll;
struct { u32 opRgb:12, opAlpha:12; };
};
u16 funcRgb, funcAlpha;
u32 color;
u16 scaleRgb, scaleAlpha;
} C3D_TexEnv;
typedef enum
{
C3D_RGB = BIT(0),
C3D_Alpha = BIT(1),
C3D_Both = C3D_RGB | C3D_Alpha,
} C3D_TexEnvMode;
C3D_TexEnv* C3D_GetTexEnv(int id);
void C3D_SetTexEnv(int id, C3D_TexEnv* env);
void C3D_DirtyTexEnv(C3D_TexEnv* env);
void C3D_TexEnvBufUpdate(int mode, int mask);
void C3D_TexEnvBufColor(u32 color);
static inline void C3D_TexEnvInit(C3D_TexEnv* env)
{
env->srcRgb = GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0);
env->srcAlpha = env->srcRgb;
env->opAll = 0;
env->funcRgb = GPU_REPLACE;
env->funcAlpha = env->funcRgb;
env->color = 0xFFFFFFFF;
env->scaleRgb = GPU_TEVSCALE_1;
env->scaleAlpha = GPU_TEVSCALE_1;
}
#ifdef __cplusplus
#define _C3D_DEFAULT(x) = x
#else
#define _C3D_DEFAULT(x)
#endif
static inline void C3D_TexEnvSrc(C3D_TexEnv* env, C3D_TexEnvMode mode,
GPU_TEVSRC s1,
GPU_TEVSRC s2 _C3D_DEFAULT(GPU_PRIMARY_COLOR),
GPU_TEVSRC s3 _C3D_DEFAULT(GPU_PRIMARY_COLOR))
{
int param = GPU_TEVSOURCES((int)s1, (int)s2, (int)s3);
if ((int)mode & C3D_RGB)
env->srcRgb = param;
if ((int)mode & C3D_Alpha)
env->srcAlpha = param;
}
static inline void C3D_TexEnvOpRgb(C3D_TexEnv* env,
GPU_TEVOP_RGB o1,
GPU_TEVOP_RGB o2 _C3D_DEFAULT(GPU_TEVOP_RGB_SRC_COLOR),
GPU_TEVOP_RGB o3 _C3D_DEFAULT(GPU_TEVOP_RGB_SRC_COLOR))
{
env->opRgb = GPU_TEVOPERANDS((int)o1, (int)o2, (int)o3);
}
static inline void C3D_TexEnvOpAlpha(C3D_TexEnv* env,
GPU_TEVOP_A o1,
GPU_TEVOP_A o2 _C3D_DEFAULT(GPU_TEVOP_A_SRC_ALPHA),
GPU_TEVOP_A o3 _C3D_DEFAULT(GPU_TEVOP_A_SRC_ALPHA))
{
env->opAlpha = GPU_TEVOPERANDS((int)o1, (int)o2, (int)o3);
}
static inline void C3D_TexEnvFunc(C3D_TexEnv* env, C3D_TexEnvMode mode, GPU_COMBINEFUNC param)
{
if ((int)mode & C3D_RGB)
env->funcRgb = param;
if ((int)mode & C3D_Alpha)
env->funcAlpha = param;
}
static inline void C3D_TexEnvColor(C3D_TexEnv* env, u32 color)
{
env->color = color;
}
static inline void C3D_TexEnvScale(C3D_TexEnv* env, int mode, GPU_TEVSCALE param)
{
if (mode & C3D_RGB)
env->scaleRgb = param;
if (mode & C3D_Alpha)
env->scaleAlpha = param;
}
#undef _C3D_DEFAULT

183
include/c3d/texture.h Normal file
View file

@ -0,0 +1,183 @@
#pragma once
#include "types.h"
typedef struct
{
void* data[6];
} C3D_TexCube;
typedef struct
{
union
{
void* data;
C3D_TexCube* cube;
};
GPU_TEXCOLOR fmt : 4;
size_t size : 28;
union
{
u32 dim;
struct
{
u16 height;
u16 width;
};
};
u32 param;
u32 border;
union
{
u32 lodParam;
struct
{
u16 lodBias;
u8 maxLevel;
u8 minLevel;
};
};
} C3D_Tex;
typedef struct CTR_ALIGN(8)
{
u16 width;
u16 height;
u8 maxLevel : 4;
GPU_TEXCOLOR format : 4;
GPU_TEXTURE_MODE_PARAM type : 3;
bool onVram : 1;
} C3D_TexInitParams;
bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexCube* cube, C3D_TexInitParams p);
void C3D_TexLoadImage(C3D_Tex* tex, const void* data, GPU_TEXFACE face, int level);
void C3D_TexGenerateMipmap(C3D_Tex* tex, GPU_TEXFACE face);
void C3D_TexBind(int unitId, C3D_Tex* tex);
void C3D_TexFlush(C3D_Tex* tex);
void C3D_TexDelete(C3D_Tex* tex);
void C3D_TexShadowParams(bool perspective, float bias);
static inline int C3D_TexCalcMaxLevel(u32 width, u32 height)
{
return (31-__builtin_clz(width < height ? width : height)) - 3; // avoid sizes smaller than 8
}
static inline u32 C3D_TexCalcLevelSize(u32 size, int level)
{
return size >> (2*level);
}
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;
}
static inline bool C3D_TexInit(C3D_Tex* tex, u16 width, u16 height, GPU_TEXCOLOR format)
{
return C3D_TexInitWithParams(tex, NULL,
(C3D_TexInitParams){ width, height, 0, format, GPU_TEX_2D, false });
}
static inline bool C3D_TexInitMipmap(C3D_Tex* tex, u16 width, u16 height, GPU_TEXCOLOR format)
{
return C3D_TexInitWithParams(tex, NULL,
(C3D_TexInitParams){ width, height, (u8)C3D_TexCalcMaxLevel(width, height), format, GPU_TEX_2D, false });
}
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 });
}
static inline bool C3D_TexInitVRAM(C3D_Tex* tex, u16 width, u16 height, GPU_TEXCOLOR format)
{
return C3D_TexInitWithParams(tex, NULL,
(C3D_TexInitParams){ width, height, 0, format, GPU_TEX_2D, true });
}
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 });
}
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 });
}
static inline GPU_TEXTURE_MODE_PARAM C3D_TexGetType(C3D_Tex* tex)
{
return (GPU_TEXTURE_MODE_PARAM)((tex->param>>28)&0x7);
}
static inline void* C3D_TexGetImagePtr(C3D_Tex* tex, void* data, int level, u32* size)
{
if (size) *size = level >= 0 ? C3D_TexCalcLevelSize(tex->size, level) : C3D_TexCalcTotalSize(tex->size, tex->maxLevel);
if (!level) return data;
return (u8*)data + (level > 0 ? C3D_TexCalcTotalSize(tex->size, level-1) : 0);
}
static inline void* C3D_Tex2DGetImagePtr(C3D_Tex* tex, int level, u32* size)
{
return C3D_TexGetImagePtr(tex, tex->data, level, size);
}
static inline void* C3D_TexCubeGetImagePtr(C3D_Tex* tex, GPU_TEXFACE face, int level, u32* size)
{
return C3D_TexGetImagePtr(tex, tex->cube->data[face], level, size);
}
static inline void C3D_TexUpload(C3D_Tex* tex, const void* data)
{
C3D_TexLoadImage(tex, data, GPU_TEXFACE_2D, 0);
}
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);
}
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);
}
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);
}
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;
}

81
include/c3d/types.h Normal file
View file

@ -0,0 +1,81 @@
#pragma once
#if defined(__3DS__) || defined(_3DS)
#include <3ds.h>
#else
#include <stdbool.h>
#include <stdint.h>
typedef uint8_t u8;
typedef uint32_t u32;
#endif
#ifndef CITRO3D_NO_DEPRECATION
#define C3D_DEPRECATED __attribute__ ((deprecated))
#else
#define C3D_DEPRECATED
#endif
typedef u32 C3D_IVec;
static inline C3D_IVec IVec_Pack(u8 x, u8 y, u8 z, u8 w)
{
return (u32)x | ((u32)y << 8) | ((u32)z << 16) | ((u32)w << 24);
}
/**
* @defgroup math_support Math Support Library
* @brief Implementations of matrix, vector, and quaternion operations.
* @{
*/
/**
* @struct C3D_FVec
* @brief Float vector
*
* Matches PICA layout
*/
typedef union
{
/**
* @brief Vector access
*/
struct
{
float w; ///< W-component
float z; ///< Z-component
float y; ///< Y-component
float x; ///< X-component
};
/**
* @brief Quaternion access
*/
struct
{
float r; ///< Real component
float k; ///< K-component
float j; ///< J-component
float i; ///< I-component
};
/**
* @brief Raw access
*/
float c[4];
} C3D_FVec;
/**
* @struct C3D_FQuat
* @brief Float quaternion. See @ref C3D_FVec.
*/
typedef C3D_FVec C3D_FQuat;
/**
* @struct C3D_Mtx
* @brief Row-major 4x4 matrix
*/
typedef union
{
C3D_FVec r[4]; ///< Rows are vectors
float m[4*4]; ///< Raw access
} C3D_Mtx;
/** @} */

78
include/c3d/uniforms.h Normal file
View file

@ -0,0 +1,78 @@
#pragma once
#include "maths.h"
#define C3D_FVUNIF_COUNT 96
#define C3D_IVUNIF_COUNT 4
extern C3D_FVec C3D_FVUnif[2][C3D_FVUNIF_COUNT];
extern C3D_IVec C3D_IVUnif[2][C3D_IVUNIF_COUNT];
extern u16 C3D_BoolUnifs[2];
extern bool C3D_FVUnifDirty[2][C3D_FVUNIF_COUNT];
extern bool C3D_IVUnifDirty[2][C3D_IVUNIF_COUNT];
extern bool C3D_BoolUnifsDirty[2];
static inline C3D_FVec* C3D_FVUnifWritePtr(GPU_SHADER_TYPE type, int id, int size)
{
int i;
for (i = 0; i < size; i ++)
C3D_FVUnifDirty[type][id+i] = true;
return &C3D_FVUnif[type][id];
}
static inline C3D_IVec* C3D_IVUnifWritePtr(GPU_SHADER_TYPE type, int id)
{
id -= 0x60;
C3D_IVUnifDirty[type][id] = true;
return &C3D_IVUnif[type][id];
}
static inline void C3D_FVUnifMtxNx4(GPU_SHADER_TYPE type, int id, const C3D_Mtx* mtx, int num)
{
int i;
C3D_FVec* ptr = C3D_FVUnifWritePtr(type, id, num);
for (i = 0; i < num; i ++)
ptr[i] = mtx->r[i]; // Struct copy.
}
static inline void C3D_FVUnifMtx4x4(GPU_SHADER_TYPE type, int id, const C3D_Mtx* mtx)
{
C3D_FVUnifMtxNx4(type, id, mtx, 4);
}
static inline void C3D_FVUnifMtx3x4(GPU_SHADER_TYPE type, int id, const C3D_Mtx* mtx)
{
C3D_FVUnifMtxNx4(type, id, mtx, 3);
}
static inline void C3D_FVUnifMtx2x4(GPU_SHADER_TYPE type, int id, const C3D_Mtx* mtx)
{
C3D_FVUnifMtxNx4(type, id, mtx, 2);
}
static inline void C3D_FVUnifSet(GPU_SHADER_TYPE type, int id, float x, float y, float z, float w)
{
C3D_FVec* ptr = C3D_FVUnifWritePtr(type, id, 1);
ptr->x = x;
ptr->y = y;
ptr->z = z;
ptr->w = w;
}
static inline void C3D_IVUnifSet(GPU_SHADER_TYPE type, int id, int x, int y, int z, int w)
{
C3D_IVec* ptr = C3D_IVUnifWritePtr(type, id);
*ptr = IVec_Pack(x, y, z, w);
}
static inline void C3D_BoolUnifSet(GPU_SHADER_TYPE type, int id, bool value)
{
id -= 0x68;
C3D_BoolUnifsDirty[type] = true;
if (value)
C3D_BoolUnifs[type] |= BIT(id);
else
C3D_BoolUnifs[type] &= ~BIT(id);
}
void C3D_UpdateUniforms(GPU_SHADER_TYPE type);