Initial commit
This commit is contained in:
commit
e7d0632224
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
*~
|
||||
*.3dsx
|
||||
*.elf
|
||||
*.smdh
|
||||
Thumbs.db
|
||||
build/
|
||||
lib/
|
135
Makefile
Normal file
135
Makefile
Normal file
@ -0,0 +1,135 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/3ds_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := source \
|
||||
source/maths
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp
|
||||
|
||||
CFLAGS := -g -Wall -O2 -mword-relocations \
|
||||
-fomit-frame-pointer -ffast-math \
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -DCITRO3D_BUILD
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
ASFLAGS := -g $(ARCH) $(DEFINES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(CTRULIB)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/lib/lib$(TARGET).a
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
VSHFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.vsh)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES := $(addsuffix .o,$(BINFILES)) $(VSHFILES:.vsh=.shbin.o) \
|
||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
lib:
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
$(BUILD): lib
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) lib
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT) : $(OFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.shbin.o: %.vsh
|
||||
@echo $(notdir $<)
|
||||
$(eval CURBIN := $(patsubst %.vsh,%.shbin,$(notdir $<)))
|
||||
$(eval CURH := $(patsubst %.vsh,%.vsh.h,$(notdir $<)))
|
||||
@picasso $(CURBIN) $< $(CURH)
|
||||
@bin2s $(CURBIN) | $(AS) -o $@
|
||||
@echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h
|
||||
@echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h
|
||||
@echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
31
include/c3d/attribs.h
Normal file
31
include/c3d/attribs.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 offset;
|
||||
u32 flags[2];
|
||||
} C3D_AttrBufCfg;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Base physical address intentionally left out
|
||||
// Write to 0x0201 instead of 0x0200
|
||||
u32 flags[2];
|
||||
C3D_AttrBufCfg buffers[12];
|
||||
} C3D_AttrCfg;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
C3D_AttrCfg cfg;
|
||||
u64 permutation;
|
||||
int attrCount;
|
||||
int bufCount;
|
||||
} C3D_AttrInfo;
|
||||
|
||||
void AttrInfo_Init(C3D_AttrInfo* info);
|
||||
bool AttrInfo_AddParam(C3D_AttrInfo* info, GPU_FORMATS format, int count);
|
||||
bool AttrInfo_AddBuffer(C3D_AttrInfo* info, ptrdiff_t offset, ptrdiff_t stride, int attribCount, u64 permutation);
|
||||
|
||||
C3D_AttrInfo* C3D_GetAttrInfo(void);
|
||||
void C3D_SetAttrInfo(C3D_AttrInfo* info);
|
22
include/c3d/base.h
Normal file
22
include/c3d/base.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "buffers.h"
|
||||
#define C3D_DEFAULT_CMDBUF_SIZE 0x40000
|
||||
|
||||
bool C3D_Init(size_t cmdBufSize);
|
||||
void C3D_FlushAsync(void);
|
||||
void C3D_Fini(void);
|
||||
|
||||
void C3D_DrawArray(C3D_VBO* vbo, GPU_Primitive_t primitive);
|
||||
void C3D_DrawElements(C3D_IBO* ibo, GPU_Primitive_t primitive);
|
||||
|
||||
static inline void C3D_FlushAwait(void)
|
||||
{
|
||||
gspWaitForP3D();
|
||||
}
|
||||
|
||||
static inline void C3D_Flush(void)
|
||||
{
|
||||
C3D_FlushAsync();
|
||||
C3D_FlushAwait();
|
||||
}
|
35
include/c3d/buffers.h
Normal file
35
include/c3d/buffers.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* data;
|
||||
size_t capacity;
|
||||
size_t size;
|
||||
int vertexCount;
|
||||
} C3D_VBO;
|
||||
|
||||
bool C3D_VBOInit(C3D_VBO* vbo, size_t capacity);
|
||||
bool C3D_VBOAddData(C3D_VBO* vbo, const void* data, size_t size, int vertexCount);
|
||||
void C3D_VBOFlush(C3D_VBO* vbo);
|
||||
void C3D_VBOBind(C3D_VBO* vbo);
|
||||
void C3D_VBODelete(C3D_VBO* vbo);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* data;
|
||||
int capacity;
|
||||
int indexCount;
|
||||
int format;
|
||||
} C3D_IBO;
|
||||
|
||||
enum
|
||||
{
|
||||
C3D_UNSIGNED_BYTE = 0,
|
||||
C3D_UNSIGNED_SHORT = 1,
|
||||
};
|
||||
|
||||
bool C3D_IBOInit(C3D_IBO* ibo, int capacity, int format);
|
||||
bool C3D_IBOAddData(C3D_IBO* ibo, const void* data, int indexCount);
|
||||
void C3D_IBOFlush(C3D_IBO* ibo);
|
||||
void C3D_IBODelete(C3D_IBO* ibo);
|
11
include/c3d/effect.h
Normal file
11
include/c3d/effect.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
void C3D_DepthRange(float near, float far);
|
||||
void C3D_CullFace(GPU_CULLMODE mode);
|
||||
void C3D_StencilTest(bool enable, GPU_TESTFUNC function, int ref, int mask, int replace);
|
||||
void C3D_StencilOp(GPU_STENCILOP sfail, GPU_STENCILOP dfail, GPU_STENCILOP pass);
|
||||
void C3D_BlendingColor(u32 color);
|
||||
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);
|
73
include/c3d/maths.h
Normal file
73
include/c3d/maths.h
Normal file
@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
// See http://tauday.com/tau-manifesto
|
||||
//#define M_TAU 6.28318530717958647693
|
||||
#define M_TAU (2*M_PI)
|
||||
|
||||
#define C3D_Angle(_angle) ((_angle)*M_TAU)
|
||||
#define C3D_AspectRatioTop (400.0f / 240.0f)
|
||||
#define C3D_AspectRatioBot (320.0f / 240.0f)
|
||||
|
||||
static inline float FVec_DP4(const C3D_FVec* a, const C3D_FVec* b)
|
||||
{
|
||||
return a->x*b->x + a->y*b->y + a->z*b->z + a->w*b->w;
|
||||
}
|
||||
|
||||
static inline float FVec_Mod4(const C3D_FVec* a)
|
||||
{
|
||||
return sqrtf(FVec_DP4(a,a));
|
||||
}
|
||||
|
||||
static inline void FVec_Norm4(C3D_FVec* vec)
|
||||
{
|
||||
float m = FVec_Mod4(vec);
|
||||
vec->x /= m;
|
||||
vec->y /= m;
|
||||
vec->z /= m;
|
||||
vec->w /= m;
|
||||
}
|
||||
|
||||
static inline float FVec_DP3(const C3D_FVec* a, const C3D_FVec* b)
|
||||
{
|
||||
return a->x*b->x + a->y*b->y + a->z*b->z;
|
||||
}
|
||||
|
||||
static inline float FVec_Mod3(const C3D_FVec* a)
|
||||
{
|
||||
return sqrtf(FVec_DP3(a,a));
|
||||
}
|
||||
|
||||
static inline void FVec_Norm3(C3D_FVec* vec)
|
||||
{
|
||||
float m = FVec_Mod3(vec);
|
||||
vec->x /= m;
|
||||
vec->y /= m;
|
||||
vec->z /= m;
|
||||
vec->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void Mtx_Zeros(C3D_Mtx* out)
|
||||
{
|
||||
memset(out, 0, sizeof(*out));
|
||||
}
|
||||
|
||||
static inline void Mtx_Copy(C3D_Mtx* out, const C3D_Mtx* in)
|
||||
{
|
||||
memcpy(out, in, sizeof(*out));
|
||||
}
|
||||
|
||||
void Mtx_Identity(C3D_Mtx* out);
|
||||
void Mtx_Multiply(C3D_Mtx* out, const C3D_Mtx* a, const C3D_Mtx* b);
|
||||
|
||||
void Mtx_Translate(C3D_Mtx* mtx, float x, float y, float z);
|
||||
void Mtx_Scale(C3D_Mtx* mtx, float x, float y, float z);
|
||||
void Mtx_RotateX(C3D_Mtx* mtx, float angle, bool bRightSide);
|
||||
void Mtx_RotateY(C3D_Mtx* mtx, float angle, bool bRightSide);
|
||||
void Mtx_RotateZ(C3D_Mtx* mtx, float angle, bool bRightSide);
|
||||
|
||||
// Special versions of the projection matrices that take the 3DS' screen orientation into account
|
||||
void Mtx_OrthoTilt(C3D_Mtx* mtx, float left, float right, float bottom, float top, float near, float far);
|
||||
void Mtx_PerspTilt(C3D_Mtx* mtx, float fovy, float aspect, float near, float far);
|
23
include/c3d/mtxstack.h
Normal file
23
include/c3d/mtxstack.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "maths.h"
|
||||
#define C3D_MTXSTACK_SIZE 8
|
||||
|
||||
typedef struct
|
||||
{
|
||||
C3D_Mtx m[C3D_MTXSTACK_SIZE];
|
||||
int pos;
|
||||
u8 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, int unifPos, int unifLen);
|
||||
void MtxStack_Push(C3D_MtxStack* stk);
|
||||
void MtxStack_Pop(C3D_MtxStack* stk);
|
||||
void MtxStack_Update(C3D_MtxStack* stk);
|
54
include/c3d/texenv.h
Normal file
54
include/c3d/texenv.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16 srcRgb, srcAlpha;
|
||||
u16 opRgb, opAlpha;
|
||||
u16 funcRgb, funcAlpha;
|
||||
u32 color;
|
||||
u32 unknown;
|
||||
} C3D_TexEnv;
|
||||
|
||||
enum
|
||||
{
|
||||
C3D_RGB = BIT(0),
|
||||
C3D_Alpha = BIT(1),
|
||||
C3D_Both = C3D_RGB | C3D_Alpha,
|
||||
};
|
||||
|
||||
void TexEnv_Init(C3D_TexEnv* env);
|
||||
|
||||
C3D_TexEnv* C3D_GetTexEnv(int id);
|
||||
void C3D_SetTexEnv(int id, C3D_TexEnv* env);
|
||||
|
||||
static inline void C3D_TexEnvSrc(C3D_TexEnv* env, int mode, int s1, int s2, int s3)
|
||||
{
|
||||
int param = GPU_TEVSOURCES(s1, s2, s3);
|
||||
if (mode & C3D_RGB)
|
||||
env->srcRgb = param;
|
||||
if (mode & C3D_Alpha)
|
||||
env->srcAlpha = param;
|
||||
}
|
||||
|
||||
static inline void C3D_TexEnvOp(C3D_TexEnv* env, int mode, int o1, int o2, int o3)
|
||||
{
|
||||
int param = GPU_TEVOPERANDS(o1, o2, o3);
|
||||
if (mode & C3D_RGB)
|
||||
env->opRgb = param;
|
||||
if (mode & C3D_Alpha)
|
||||
env->opAlpha = param;
|
||||
}
|
||||
|
||||
static inline void C3D_TexEnvFunc(C3D_TexEnv* env, int mode, int param)
|
||||
{
|
||||
if (mode & C3D_RGB)
|
||||
env->funcRgb = param;
|
||||
if (mode & C3D_Alpha)
|
||||
env->funcAlpha = param;
|
||||
}
|
||||
|
||||
static inline void C3D_TexEnvColor(C3D_TexEnv* env, u32 color)
|
||||
{
|
||||
env->color = color;
|
||||
}
|
20
include/c3d/texture.h
Normal file
20
include/c3d/texture.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* data;
|
||||
size_t size;
|
||||
|
||||
u16 width, height;
|
||||
u32 param;
|
||||
GPU_TEXCOLOR fmt;
|
||||
} C3D_Tex;
|
||||
|
||||
bool C3D_TexInit(C3D_Tex* tex, int width, int height, GPU_TEXCOLOR format);
|
||||
void C3D_TexUpload(C3D_Tex* tex, const void* data);
|
||||
void C3D_TexSetFilter(C3D_Tex* tex, GPU_TEXTURE_FILTER_PARAM magFilter, GPU_TEXTURE_FILTER_PARAM minFilter);
|
||||
void C3D_TexSetWrap(C3D_Tex* tex, GPU_TEXTURE_WRAP_PARAM wrapS, GPU_TEXTURE_WRAP_PARAM wrapT);
|
||||
void C3D_TexBind(int unitId, C3D_Tex* tex);
|
||||
void C3D_TexFlush(C3D_Tex* tex);
|
||||
void C3D_TexDelete(C3D_Tex* tex);
|
28
include/c3d/types.h
Normal file
28
include/c3d/types.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <3ds.h>
|
||||
|
||||
typedef u32 C3D_IVec;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
struct { float w, z, y, x; };
|
||||
float c[4];
|
||||
};
|
||||
} C3D_FVec;
|
||||
|
||||
// Row-major 4x4 matrix
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
C3D_FVec r[4]; // Rows are vectors
|
||||
float m[4*4];
|
||||
};
|
||||
} C3D_Mtx;
|
||||
|
||||
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);
|
||||
}
|
43
include/c3d/uniforms.h
Normal file
43
include/c3d/uniforms.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#define C3D_FVUNIF_COUNT 96
|
||||
#define C3D_IVUNIF_COUNT 4
|
||||
|
||||
extern C3D_FVec C3D_FVUnif[C3D_FVUNIF_COUNT];
|
||||
extern C3D_IVec C3D_IVUnif[C3D_IVUNIF_COUNT];
|
||||
extern u16 C3D_BoolUnifs;
|
||||
|
||||
extern bool C3D_FVUnifDirty[C3D_FVUNIF_COUNT];
|
||||
extern bool C3D_IVUnifDirty[C3D_IVUNIF_COUNT];
|
||||
extern bool C3D_BoolUnifsDirty;
|
||||
|
||||
static inline C3D_FVec* C3D_FVUnifWritePtr(int id, int size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i ++)
|
||||
C3D_FVUnifDirty[id+i] = true;
|
||||
return &C3D_FVUnif[id];
|
||||
}
|
||||
|
||||
static inline C3D_IVec* C3D_IVUnifWritePtr(int id)
|
||||
{
|
||||
C3D_IVUnifDirty[id] = true;
|
||||
return &C3D_IVUnif[id];
|
||||
}
|
||||
|
||||
static inline void C3D_FVUnifSet(int id, float x, float y, float z, float w)
|
||||
{
|
||||
C3D_FVec* ptr = C3D_FVUnifWritePtr(id, 1);
|
||||
ptr->x = x;
|
||||
ptr->y = y;
|
||||
ptr->z = z;
|
||||
ptr->w = w;
|
||||
}
|
||||
|
||||
static inline void C3D_IVUnifSet(int id, int x, int y, int z, int w)
|
||||
{
|
||||
C3D_IVec* ptr = C3D_IVUnifWritePtr(id);
|
||||
*ptr = IVec_Pack(x, y, z, w);
|
||||
}
|
||||
|
||||
void C3D_UpdateUniforms(void);
|
26
include/citro3d.h
Normal file
26
include/citro3d.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef CITRO3D_BUILD
|
||||
#error "This header file is only for external users of citro3d."
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "c3d/types.h"
|
||||
#include "c3d/maths.h"
|
||||
#include "c3d/mtxstack.h"
|
||||
|
||||
#include "c3d/uniforms.h"
|
||||
#include "c3d/attribs.h"
|
||||
#include "c3d/buffers.h"
|
||||
#include "c3d/base.h"
|
||||
|
||||
#include "c3d/texenv.h"
|
||||
#include "c3d/effect.h"
|
||||
#include "c3d/texture.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
65
source/attribs.c
Normal file
65
source/attribs.c
Normal file
@ -0,0 +1,65 @@
|
||||
#include <c3d/attribs.h>
|
||||
#include <string.h>
|
||||
#include "context.h"
|
||||
|
||||
void AttrInfo_Init(C3D_AttrInfo* info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->cfg.flags[1] = 0xFFF << 16;
|
||||
}
|
||||
|
||||
bool AttrInfo_AddParam(C3D_AttrInfo* info, GPU_FORMATS format, int count)
|
||||
{
|
||||
if (info->attrCount == 12) return false;
|
||||
int id = info->attrCount++;
|
||||
if (id < 8)
|
||||
info->cfg.flags[0] |= GPU_ATTRIBFMT(id, count, format);
|
||||
else
|
||||
info->cfg.flags[1] |= GPU_ATTRIBFMT(id-8, count, format);
|
||||
info->cfg.flags[1] &= ~BIT(id+16);
|
||||
info->cfg.flags[1] = (info->cfg.flags[1] &~ 0xF0000000) | (id << 28);
|
||||
info->permutation |= id << (id*4);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AttrInfo_AddBuffer(C3D_AttrInfo* info, ptrdiff_t offset, ptrdiff_t stride, int attribCount, u64 permutation)
|
||||
{
|
||||
if (info->bufCount == 12) return false;
|
||||
int id = info->bufCount++;
|
||||
C3D_AttrBufCfg* buf = &info->cfg.buffers[id];
|
||||
buf->offset = offset;
|
||||
buf->flags[0] = permutation & 0xFFFFFFFF;
|
||||
buf->flags[1] = (permutation >> 32) | (stride << 16) | (attribCount << 28);
|
||||
return true;
|
||||
}
|
||||
|
||||
C3D_AttrInfo* C3D_GetAttrInfo(void)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return NULL;
|
||||
|
||||
ctx->flags |= C3DiF_AttrBuf;
|
||||
return &ctx->attrInfo;
|
||||
}
|
||||
|
||||
void C3D_SetAttrInfo(C3D_AttrInfo* info)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
memcpy(&ctx->attrInfo, info, sizeof(*info));
|
||||
ctx->flags |= C3DiF_AttrBuf;
|
||||
}
|
||||
|
||||
void C3Di_AttrInfoBind(C3D_AttrInfo* info)
|
||||
{
|
||||
GPUCMD_Add(0x800F0201, (u32*)&info->cfg, sizeof(C3D_AttrCfg)/sizeof(u32));
|
||||
GPUCMD_AddSingleParam(0x000B02B9, 0xA0000000 | (info->attrCount - 1));
|
||||
GPUCMD_AddSingleParam(0x000F0242, info->attrCount - 1);
|
||||
GPUCMD_AddSingleParam(0x000F02BB, info->permutation & 0xFFFFFFFF);
|
||||
GPUCMD_AddSingleParam(0x000F02BC, info->permutation >> 32);
|
||||
}
|
167
source/base.c
Normal file
167
source/base.c
Normal file
@ -0,0 +1,167 @@
|
||||
#include "context.h"
|
||||
|
||||
C3D_Context __C3D_Context;
|
||||
|
||||
u32 C3Di_Float24(float f)
|
||||
{
|
||||
if (!f) return 0;
|
||||
union { float t; u32 v; } u;
|
||||
u.t = f;
|
||||
u32 s = u.v >> 31;
|
||||
u32 exp = ((u.v >> 23) & 0xFF) - 0x40;
|
||||
u32 man = (u.v >> 7) & 0xFFFF;
|
||||
|
||||
return (exp >= 0) ? (man | (exp << 16) | (s << 23)) : (s << 23);
|
||||
}
|
||||
|
||||
static void C3Di_SetTex(GPU_TEXUNIT unit, C3D_Tex* tex)
|
||||
{
|
||||
u32 reg[4];
|
||||
reg[0] = tex->fmt;
|
||||
reg[1] = osConvertVirtToPhys((u32)tex->data) >> 3;
|
||||
reg[2] = (u32)tex->width | ((u32)tex->height << 16);
|
||||
reg[3] = tex->param;
|
||||
|
||||
switch (unit)
|
||||
{
|
||||
case GPU_TEXUNIT0:
|
||||
GPUCMD_AddSingleParam(0x000F008E, reg[0]);
|
||||
GPUCMD_AddSingleParam(0x000F0085, reg[1]);
|
||||
GPUCMD_AddSingleParam(0x000F0082, reg[2]);
|
||||
GPUCMD_AddSingleParam(0x000F0083, reg[3]);
|
||||
break;
|
||||
case GPU_TEXUNIT1:
|
||||
GPUCMD_AddSingleParam(0x000F0096, reg[0]);
|
||||
GPUCMD_AddSingleParam(0x000F0095, reg[1]);
|
||||
GPUCMD_AddSingleParam(0x000F0092, reg[2]);
|
||||
GPUCMD_AddSingleParam(0x000F0093, reg[3]);
|
||||
break;
|
||||
case GPU_TEXUNIT2:
|
||||
GPUCMD_AddSingleParam(0x000F009E, reg[0]);
|
||||
GPUCMD_AddSingleParam(0x000F009D, reg[1]);
|
||||
GPUCMD_AddSingleParam(0x000F009A, reg[2]);
|
||||
GPUCMD_AddSingleParam(0x000F009B, reg[3]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool C3D_Init(size_t cmdBufSize)
|
||||
{
|
||||
int i;
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (ctx->flags & C3DiF_Active)
|
||||
return false;
|
||||
|
||||
ctx->cmdBufSize = cmdBufSize;
|
||||
ctx->cmdBuf = linearAlloc(cmdBufSize);
|
||||
if (!ctx->cmdBuf) return false;
|
||||
|
||||
GPU_Reset(NULL, ctx->cmdBuf, ctx->cmdBufSize);
|
||||
GPUCMD_SetBuffer(ctx->cmdBuf, ctx->cmdBufSize, 0);
|
||||
|
||||
ctx->flags = C3DiF_Active | C3DiF_TexEnvAll | C3DiF_Effect | C3DiF_TexAll;
|
||||
|
||||
// TODO: replace with direct struct access
|
||||
C3D_DepthRange(-1.0f, 0.0f);
|
||||
C3D_CullFace(GPU_CULL_BACK_CCW);
|
||||
C3D_StencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00);
|
||||
C3D_StencilOp(GPU_KEEP, GPU_KEEP, GPU_KEEP);
|
||||
C3D_BlendingColor(0);
|
||||
C3D_DepthTest(true, GPU_GREATER, GPU_WRITE_ALL);
|
||||
C3D_AlphaTest(false, GPU_ALWAYS, 0x00);
|
||||
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
for (i = 0; i < 3; i ++)
|
||||
ctx->tex[i] = NULL;
|
||||
|
||||
for (i = 0; i < 6; i ++)
|
||||
TexEnv_Init(&ctx->texEnv[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void C3Di_UpdateContext(void)
|
||||
{
|
||||
int i;
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (ctx->flags & C3DiF_NeedFinishDrawing)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_NeedFinishDrawing;
|
||||
//GPU_FinishDrawing();
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_AttrBuf)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_AttrBuf;
|
||||
C3Di_AttrInfoBind(&ctx->attrInfo);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_Effect)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_Effect;
|
||||
C3Di_EffectBind(&ctx->effect);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_TexAll)
|
||||
{
|
||||
GPU_TEXUNIT units = 0;
|
||||
|
||||
for (i = 0; i < 3; i ++)
|
||||
{
|
||||
static const u8 parm[] = { GPU_TEXUNIT0, GPU_TEXUNIT1, GPU_TEXUNIT2 };
|
||||
|
||||
if (ctx->tex[i])
|
||||
{
|
||||
units |= parm[i];
|
||||
if (ctx->flags & C3DiF_Tex(i))
|
||||
C3Di_SetTex(parm[i], ctx->tex[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->flags &= ~C3DiF_TexAll;
|
||||
GPU_SetTextureEnable(units);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_TexEnvAll)
|
||||
{
|
||||
for (i = 0; i < 6; i ++)
|
||||
{
|
||||
if (!(ctx->flags & C3DiF_TexEnv(i))) continue;
|
||||
C3Di_TexEnvBind(i, &ctx->texEnv[i]);
|
||||
}
|
||||
ctx->flags &= ~C3DiF_TexEnvAll;
|
||||
}
|
||||
|
||||
C3D_UpdateUniforms();
|
||||
}
|
||||
|
||||
void C3D_FlushAsync(void)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
if (ctx->flags & C3DiF_NeedFinishDrawing)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_NeedFinishDrawing;
|
||||
GPU_FinishDrawing();
|
||||
}
|
||||
|
||||
GPUCMD_Finalize();
|
||||
GPUCMD_FlushAndRun(NULL);
|
||||
GPUCMD_SetBuffer(ctx->cmdBuf, ctx->cmdBufSize, 0);
|
||||
}
|
||||
|
||||
void C3D_Fini(void)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
linearFree(ctx->cmdBuf);
|
||||
ctx->flags = 0;
|
||||
}
|
63
source/context.h
Normal file
63
source/context.h
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#include <c3d/base.h>
|
||||
#include <c3d/uniforms.h>
|
||||
#include <c3d/buffers.h>
|
||||
#include <c3d/attribs.h>
|
||||
#include <c3d/texenv.h>
|
||||
#include <c3d/effect.h>
|
||||
#include <c3d/texture.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 drNear, drFar;
|
||||
GPU_CULLMODE cullMode;
|
||||
|
||||
u32 alphaTest;
|
||||
u32 stencilMode, stencilOp;
|
||||
u32 depthTest;
|
||||
|
||||
u32 blendClr;
|
||||
u32 alphaBlend;
|
||||
} C3D_Effect;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* cmdBuf;
|
||||
size_t cmdBufSize;
|
||||
|
||||
u32 flags;
|
||||
|
||||
u32 vboPos;
|
||||
C3D_AttrInfo attrInfo;
|
||||
C3D_Effect effect;
|
||||
|
||||
C3D_Tex* tex[3];
|
||||
C3D_TexEnv texEnv[6];
|
||||
|
||||
} C3D_Context;
|
||||
|
||||
enum
|
||||
{
|
||||
C3DiF_Active = BIT(0),
|
||||
C3DiF_NeedFinishDrawing = BIT(1),
|
||||
C3DiF_AttrBuf = BIT(2),
|
||||
C3DiF_Effect = BIT(3),
|
||||
|
||||
#define C3DiF_Tex(n) BIT(23+(n))
|
||||
C3DiF_TexAll = 7 << 23,
|
||||
#define C3DiF_TexEnv(n) BIT(26+(n))
|
||||
C3DiF_TexEnvAll = 0x3F << 26,
|
||||
};
|
||||
|
||||
static inline C3D_Context* C3Di_GetContext(void)
|
||||
{
|
||||
extern C3D_Context __C3D_Context;
|
||||
return &__C3D_Context;
|
||||
}
|
||||
|
||||
u32 C3Di_Float24(float f);
|
||||
void C3Di_UpdateContext(void);
|
||||
void C3Di_IBOBind(C3D_IBO* ibo);
|
||||
void C3Di_AttrInfoBind(C3D_AttrInfo* info);
|
||||
void C3Di_TexEnvBind(int id, C3D_TexEnv* env);
|
||||
void C3Di_EffectBind(C3D_Effect* effect);
|
25
source/drawArray.c
Normal file
25
source/drawArray.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include "context.h"
|
||||
|
||||
void C3D_DrawArray(C3D_VBO* vbo, GPU_Primitive_t primitive)
|
||||
{
|
||||
C3D_VBOBind(vbo);
|
||||
C3Di_UpdateContext();
|
||||
|
||||
// Set primitive type
|
||||
GPUCMD_AddSingleParam(0x0002025E, primitive);
|
||||
GPUCMD_AddSingleParam(0x0002025F, 0x00000001);
|
||||
// The index buffer is not used, but 0x000F0227 is still required
|
||||
GPUCMD_AddSingleParam(0x000F0227, 0x80000000);
|
||||
// Number of vertices
|
||||
GPUCMD_AddSingleParam(0x000F0228, vbo->vertexCount);
|
||||
|
||||
// Unknown commands
|
||||
GPUCMD_AddSingleParam(0x00010253, 0x00000001);
|
||||
|
||||
GPUCMD_AddSingleParam(0x00010245, 0x00000000);
|
||||
GPUCMD_AddSingleParam(0x000F022E, 0x00000001);
|
||||
GPUCMD_AddSingleParam(0x00010245, 0x00000001);
|
||||
GPUCMD_AddSingleParam(0x000F0231, 0x00000001);
|
||||
|
||||
C3Di_GetContext()->flags |= C3DiF_NeedFinishDrawing;
|
||||
}
|
25
source/drawElements.c
Normal file
25
source/drawElements.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include "context.h"
|
||||
|
||||
void C3D_DrawElements(C3D_IBO* ibo, GPU_Primitive_t primitive)
|
||||
{
|
||||
C3Di_UpdateContext();
|
||||
|
||||
// Set primitive type
|
||||
GPUCMD_AddSingleParam(0x0002025E, primitive);
|
||||
GPUCMD_AddSingleParam(0x0002025F, 0x00000001);
|
||||
// Bind the IBO
|
||||
C3Di_IBOBind(ibo);
|
||||
// Number of vertices
|
||||
GPUCMD_AddSingleParam(0x000F0228, ibo->indexCount);
|
||||
|
||||
// Unknown commands
|
||||
GPUCMD_AddSingleParam(0x00020229, 0x00000100);
|
||||
GPUCMD_AddSingleParam(0x00020253, 0x00000100);
|
||||
|
||||
GPUCMD_AddSingleParam(0x00010245, 0x00000000);
|
||||
GPUCMD_AddSingleParam(0x000F022F, 0x00000001);
|
||||
GPUCMD_AddSingleParam(0x00010245, 0x00000001);
|
||||
GPUCMD_AddSingleParam(0x000F0231, 0x00000001);
|
||||
|
||||
C3Di_GetContext()->flags |= C3DiF_NeedFinishDrawing;
|
||||
}
|
72
source/effect.c
Normal file
72
source/effect.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include "context.h"
|
||||
|
||||
static inline C3D_Effect* getEffect()
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
ctx->flags |= C3DiF_Effect;
|
||||
return &ctx->effect;
|
||||
}
|
||||
|
||||
void C3D_DepthRange(float near, float far)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->drNear = C3Di_Float24(near);
|
||||
e->drFar = C3Di_Float24(far);
|
||||
}
|
||||
|
||||
void C3D_CullFace(GPU_CULLMODE mode)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->cullMode = mode;
|
||||
}
|
||||
|
||||
void C3D_StencilTest(bool enable, GPU_TESTFUNC function, int ref, int mask, int replace)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->stencilMode = (!!enable) | ((function & 7) << 4) | (replace << 8) | (ref << 16) | (mask << 24);
|
||||
}
|
||||
|
||||
void C3D_StencilOp(GPU_STENCILOP sfail, GPU_STENCILOP dfail, GPU_STENCILOP pass)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->stencilOp = sfail | (dfail << 4) | (pass << 8);
|
||||
}
|
||||
|
||||
void C3D_BlendingColor(u32 color)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->blendClr = color;
|
||||
}
|
||||
|
||||
void C3D_DepthTest(bool enable, GPU_TESTFUNC function, GPU_WRITEMASK writemask)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->depthTest = (!!enable) | ((function & 7) << 4) | (writemask << 8);
|
||||
}
|
||||
|
||||
void C3D_AlphaTest(bool enable, GPU_TESTFUNC function, int ref)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->alphaTest = (!!enable) | ((function & 7) << 4) | (ref << 8);
|
||||
}
|
||||
|
||||
void C3D_AlphaBlend(GPU_BLENDEQUATION colorEq, GPU_BLENDEQUATION alphaEq, GPU_BLENDFACTOR srcClr, GPU_BLENDFACTOR dstClr, GPU_BLENDFACTOR srcAlpha, GPU_BLENDFACTOR dstAlpha)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->alphaBlend = colorEq | (alphaEq << 8) | (srcClr << 16) | (dstClr << 20) | (srcAlpha << 24) | (dstAlpha << 28);
|
||||
}
|
||||
|
||||
void C3Di_EffectBind(C3D_Effect* e)
|
||||
{
|
||||
GPUCMD_AddSingleParam(0x000F006D, 0x00000001);
|
||||
GPUCMD_AddSingleParam(0x000F0040, e->cullMode & 0x3);
|
||||
GPUCMD_Add(0x800F004D, (u32*)&e->drNear, 2);
|
||||
GPUCMD_Add(0x800F0104, (u32*)&e->alphaTest, 4);
|
||||
GPUCMD_AddSingleParam(0x000F0103, e->blendClr);
|
||||
GPUCMD_AddSingleParam(0x000F0101, e->alphaBlend);
|
||||
GPUCMD_AddSingleParam(0x00020100, 0x00000100);
|
||||
|
||||
// Wat
|
||||
GPUCMD_AddSingleParam(0x00010062, 0);
|
||||
GPUCMD_AddSingleParam(0x000F0118, 0);
|
||||
}
|
47
source/ibo.c
Normal file
47
source/ibo.c
Normal file
@ -0,0 +1,47 @@
|
||||
#include <c3d/buffers.h>
|
||||
#include <string.h>
|
||||
#include "context.h"
|
||||
|
||||
bool C3D_IBOCreate(C3D_IBO* ibo, int capacity, int format)
|
||||
{
|
||||
if (ibo->data) return false;
|
||||
|
||||
ibo->data = linearAlloc(capacity * (format+1));
|
||||
if (!ibo->data) return false;
|
||||
ibo->capacity = capacity;
|
||||
ibo->indexCount = 0;
|
||||
ibo->format = format;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C3D_IBOAddData(C3D_IBO* ibo, const void* data, int indexCount)
|
||||
{
|
||||
int remaining = ibo->capacity - ibo->indexCount;
|
||||
if (remaining < indexCount) return false;
|
||||
int stride = ibo->format+1;
|
||||
memcpy((u8*)ibo->data + ibo->indexCount*stride, data, indexCount*stride);
|
||||
ibo->indexCount += indexCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
void C3D_IBOFlush(C3D_IBO* ibo)
|
||||
{
|
||||
int stride = ibo->format+1;
|
||||
GSPGPU_FlushDataCache(NULL, ibo->data, ibo->indexCount*stride);
|
||||
}
|
||||
|
||||
void C3Di_IBOBind(C3D_IBO* ibo)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
u32 pa = osConvertVirtToPhys((u32)ibo->data);
|
||||
u32 offset = (pa - ctx->vboPos) &~ BIT(31);
|
||||
GPUCMD_AddSingleParam(0x000F0227, offset | (ibo->format << 31));
|
||||
}
|
||||
|
||||
void C3D_IBODelete(C3D_IBO* ibo)
|
||||
{
|
||||
if (!ibo->data) return;
|
||||
linearFree(ibo->data);
|
||||
ibo->data = NULL;
|
||||
}
|
7
source/maths/mtx_identity.c
Normal file
7
source/maths/mtx_identity.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Identity(C3D_Mtx* out)
|
||||
{
|
||||
Mtx_Zeros(out);
|
||||
out->r[0].x = out->r[1].y = out->r[2].z = out->r[3].w = 1.0f;
|
||||
}
|
9
source/maths/mtx_multiply.c
Normal file
9
source/maths/mtx_multiply.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Multiply(C3D_Mtx* out, const C3D_Mtx* a, const C3D_Mtx* b)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < 4; i ++)
|
||||
for (j = 0; j < 4; j ++)
|
||||
out->r[j].c[i] = a->r[j].x*b->r[0].c[i] + a->r[j].y*b->r[1].c[i] + a->r[j].z*b->r[2].c[i] + a->r[j].w*b->r[3].c[i];
|
||||
}
|
30
source/maths/mtx_orthotilt.c
Normal file
30
source/maths/mtx_orthotilt.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_OrthoTilt(C3D_Mtx* mtx, float top, float bottom, float left, float right, float near, float far)
|
||||
{
|
||||
// Notes:
|
||||
// The 3DS screens are sideways and so are the top/bottom/left/right parameters
|
||||
// that the caller passed. Hence why the parameter names are swapped in the implementation.
|
||||
|
||||
C3D_Mtx mp;
|
||||
Mtx_Zeros(&mp);
|
||||
|
||||
// Build standard orthogonal projection matrix
|
||||
mp.r[0].x = 2.0f / (right - left);
|
||||
mp.r[0].w = (left + right) / (left - right);
|
||||
mp.r[1].y = 2.0f / (top - bottom);
|
||||
mp.r[1].w = (bottom + top) / (bottom - top);
|
||||
mp.r[2].z = 2.0f / (far - near);
|
||||
mp.r[2].w = (near + far) / (near - far);
|
||||
mp.r[3].w = 1.0f;
|
||||
|
||||
// Fix depth range to [-1, 0]
|
||||
C3D_Mtx mp2;
|
||||
Mtx_Identity(&mp2);
|
||||
mp2.r[2].z = 0.5;
|
||||
mp2.r[2].w = -0.5;
|
||||
Mtx_Multiply(mtx, &mp2, &mp);
|
||||
|
||||
// Rotate the matrix one quarter of a turn CCW in order to fix the 3DS screens' orientation
|
||||
Mtx_RotateZ(mtx, M_TAU/4, true);
|
||||
}
|
44
source/maths/mtx_persptilt.c
Normal file
44
source/maths/mtx_persptilt.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_PerspTilt(C3D_Mtx* mtx, float fovx, float invaspect, float near, float far)
|
||||
{
|
||||
// Notes:
|
||||
// We are passed "fovy" and the "aspect ratio". However, the 3DS screens are sideways,
|
||||
// and so are these parameters -- in fact, they are actually the fovx and the inverse
|
||||
// of the aspect ratio. Therefore the formula for the perspective projection matrix
|
||||
// had to be modified to be expressed in these terms instead.
|
||||
|
||||
// Notes:
|
||||
// fovx = 2 atan(tan(fovy/2)*w/h)
|
||||
// fovy = 2 atan(tan(fovx/2)*h/w)
|
||||
// invaspect = h/w
|
||||
|
||||
// a0,0 = h / (w*tan(fovy/2)) =
|
||||
// = h / (w*tan(2 atan(tan(fovx/2)*h/w) / 2)) =
|
||||
// = h / (w*tan( atan(tan(fovx/2)*h/w) )) =
|
||||
// = h / (w * tan(fovx/2)*h/w) =
|
||||
// = 1 / tan(fovx/2)
|
||||
|
||||
// a1,1 = 1 / tan(fovy/2) = (...) = w / (h*tan(fovx/2))
|
||||
|
||||
float fovx_tan = tanf(fovx/2);
|
||||
C3D_Mtx mp;
|
||||
Mtx_Zeros(&mp);
|
||||
|
||||
// Build standard perspective projection matrix
|
||||
mp.r[0].x = 1.0f / fovx_tan;
|
||||
mp.r[1].y = 1.0f / (fovx_tan*invaspect);
|
||||
mp.r[2].z = (near + far) / (near - far);
|
||||
mp.r[2].w = (2 * near * far) / (near - far);
|
||||
mp.r[3].z = -1.0f;
|
||||
|
||||
// Fix depth range to [-1, 0]
|
||||
C3D_Mtx mp2;
|
||||
Mtx_Identity(&mp2);
|
||||
mp2.r[2].z = 0.5;
|
||||
mp2.r[2].w = -0.5;
|
||||
Mtx_Multiply(mtx, &mp2, &mp);
|
||||
|
||||
// Rotate the matrix one quarter of a turn CCW in order to fix the 3DS screens' orientation
|
||||
Mtx_RotateZ(mtx, M_TAU/4, true);
|
||||
}
|
21
source/maths/mtx_rotatex.c
Normal file
21
source/maths/mtx_rotatex.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_RotateX(C3D_Mtx* mtx, float angle, bool bRightSide)
|
||||
{
|
||||
C3D_Mtx rm, om;
|
||||
|
||||
float cosAngle = cosf(angle);
|
||||
float sinAngle = sinf(angle);
|
||||
|
||||
Mtx_Zeros(&rm);
|
||||
rm.r[0].x = 1.0f;
|
||||
rm.r[1].y = cosAngle;
|
||||
rm.r[1].z = sinAngle;
|
||||
rm.r[2].y = -sinAngle;
|
||||
rm.r[2].z = cosAngle;
|
||||
rm.r[3].w = 1.0f;
|
||||
|
||||
if (bRightSide) Mtx_Multiply(&om, mtx, &rm);
|
||||
else Mtx_Multiply(&om, &rm, mtx);
|
||||
Mtx_Copy(mtx, &om);
|
||||
}
|
21
source/maths/mtx_rotatey.c
Normal file
21
source/maths/mtx_rotatey.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_RotateY(C3D_Mtx* mtx, float angle, bool bRightSide)
|
||||
{
|
||||
C3D_Mtx rm, om;
|
||||
|
||||
float cosAngle = cosf(angle);
|
||||
float sinAngle = sinf(angle);
|
||||
|
||||
Mtx_Zeros(&rm);
|
||||
rm.r[0].x = cosAngle;
|
||||
rm.r[0].z = sinAngle;
|
||||
rm.r[1].y = 1.0f;
|
||||
rm.r[2].x = -sinAngle;
|
||||
rm.r[2].z = cosAngle;
|
||||
rm.r[3].w = 1.0f;
|
||||
|
||||
if (bRightSide) Mtx_Multiply(&om, mtx, &rm);
|
||||
else Mtx_Multiply(&om, &rm, mtx);
|
||||
Mtx_Copy(mtx, &om);
|
||||
}
|
21
source/maths/mtx_rotatez.c
Normal file
21
source/maths/mtx_rotatez.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_RotateZ(C3D_Mtx* mtx, float angle, bool bRightSide)
|
||||
{
|
||||
C3D_Mtx rm, om;
|
||||
|
||||
float cosAngle = cosf(angle);
|
||||
float sinAngle = sinf(angle);
|
||||
|
||||
Mtx_Zeros(&rm);
|
||||
rm.r[0].x = cosAngle;
|
||||
rm.r[0].y = sinAngle;
|
||||
rm.r[1].x = -sinAngle;
|
||||
rm.r[1].y = cosAngle;
|
||||
rm.r[2].z = 1.0f;
|
||||
rm.r[3].w = 1.0f;
|
||||
|
||||
if (bRightSide) Mtx_Multiply(&om, mtx, &rm);
|
||||
else Mtx_Multiply(&om, &rm, mtx);
|
||||
Mtx_Copy(mtx, &om);
|
||||
}
|
12
source/maths/mtx_scale.c
Normal file
12
source/maths/mtx_scale.c
Normal file
@ -0,0 +1,12 @@
|
||||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Scale(C3D_Mtx* mtx, float x, float y, float z)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; i ++)
|
||||
{
|
||||
mtx->r[i].x *= x;
|
||||
mtx->r[i].y *= y;
|
||||
mtx->r[i].z *= z;
|
||||
}
|
||||
}
|
14
source/maths/mtx_translate.c
Normal file
14
source/maths/mtx_translate.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Translate(C3D_Mtx* mtx, float x, float y, float z)
|
||||
{
|
||||
C3D_Mtx tm, om;
|
||||
|
||||
Mtx_Identity(&tm);
|
||||
tm.r[0].w = x;
|
||||
tm.r[1].w = y;
|
||||
tm.r[2].w = z;
|
||||
|
||||
Mtx_Multiply(&om, &tm, mtx);
|
||||
Mtx_Copy(mtx, &om);
|
||||
}
|
44
source/mtxstack.c
Normal file
44
source/mtxstack.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include <c3d/mtxstack.h>
|
||||
#include <c3d/uniforms.h>
|
||||
|
||||
void MtxStack_Init(C3D_MtxStack* stk)
|
||||
{
|
||||
stk->pos = 0;
|
||||
stk->unifPos = 0xFF;
|
||||
stk->isDirty = true;
|
||||
Mtx_Identity(&stk->m[0]);
|
||||
}
|
||||
|
||||
void MtxStack_Bind(C3D_MtxStack* stk, int unifPos, int unifLen)
|
||||
{
|
||||
stk->unifPos = unifPos;
|
||||
stk->unifLen = unifLen;
|
||||
stk->isDirty = true;
|
||||
}
|
||||
|
||||
void MtxStack_Push(C3D_MtxStack* stk)
|
||||
{
|
||||
if (stk->pos == (C3D_MTXSTACK_SIZE-1)) return;
|
||||
stk->pos ++;
|
||||
Mtx_Copy(&stk->m[stk->pos], &stk->m[stk->pos-1]);
|
||||
}
|
||||
|
||||
void MtxStack_Pop(C3D_MtxStack* stk)
|
||||
{
|
||||
if (stk->pos == 0) return;
|
||||
stk->pos --;
|
||||
stk->isDirty = true;
|
||||
}
|
||||
|
||||
void MtxStack_Update(C3D_MtxStack* stk)
|
||||
{
|
||||
if (!stk->isDirty) return;
|
||||
|
||||
if (stk->unifPos != 0xFF)
|
||||
{
|
||||
C3D_FVec* out = C3D_FVUnifWritePtr(stk->unifPos, stk->unifLen);
|
||||
memcpy(out, &stk->m[stk->pos], (u32)stk->unifLen * sizeof(C3D_FVec));
|
||||
}
|
||||
|
||||
stk->isDirty = false;
|
||||
}
|
43
source/texenv.c
Normal file
43
source/texenv.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include <c3d/texenv.h>
|
||||
#include <string.h>
|
||||
#include "context.h"
|
||||
|
||||
void TexEnv_Init(C3D_TexEnv* env)
|
||||
{
|
||||
env->srcRgb = GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0);
|
||||
env->srcAlpha = env->srcRgb;
|
||||
env->opRgb = GPU_TEVOPERANDS(0,0,0);
|
||||
env->opAlpha = env->opRgb;
|
||||
env->funcRgb = GPU_REPLACE;
|
||||
env->funcAlpha = env->funcRgb;
|
||||
env->color = 0xFFFFFFFF;
|
||||
env->unknown = 0;
|
||||
}
|
||||
|
||||
C3D_TexEnv* C3D_GetTexEnv(int id)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return NULL;
|
||||
|
||||
ctx->flags |= C3DiF_TexEnv(id);
|
||||
return &ctx->texEnv[id];
|
||||
}
|
||||
|
||||
void C3D_SetTexEnv(int id, C3D_TexEnv* env)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
memcpy(&ctx->texEnv[id], env, sizeof(*env));
|
||||
ctx->flags |= C3DiF_TexEnv(id);
|
||||
}
|
||||
|
||||
void C3Di_TexEnvBind(int id, C3D_TexEnv* env)
|
||||
{
|
||||
if (id >= 4) id += 2;
|
||||
GPUCMD_Add(0x800F00C0 + id*8, (u32*)env, sizeof(C3D_TexEnv)/sizeof(u32));
|
||||
}
|
80
source/texture.c
Normal file
80
source/texture.c
Normal file
@ -0,0 +1,80 @@
|
||||
#include "context.h"
|
||||
#include <string.h>
|
||||
|
||||
static inline size_t fmtSize(GPU_TEXCOLOR fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case GPU_RGBA8:
|
||||
return 4;
|
||||
case GPU_RGB8:
|
||||
return 3;
|
||||
case GPU_RGBA5551:
|
||||
case GPU_RGB565:
|
||||
case GPU_RGBA4:
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool C3D_TexInit(C3D_Tex* tex, int width, int height, GPU_TEXCOLOR format)
|
||||
{
|
||||
if (tex->data) return false;
|
||||
|
||||
tex->size = fmtSize(format);
|
||||
if (!tex->size) return false;
|
||||
tex->size *= width * height;
|
||||
|
||||
tex->data = linearMemAlign(tex->size, 0x80);
|
||||
if (!tex->data) return false;
|
||||
|
||||
tex->width = width;
|
||||
tex->height = height;
|
||||
tex->param = GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST);
|
||||
tex->fmt = format;
|
||||
return true;
|
||||
}
|
||||
|
||||
void C3D_TexUpload(C3D_Tex* tex, const void* data)
|
||||
{
|
||||
if (tex->data)
|
||||
memcpy(tex->data, data, tex->size);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void C3D_TexBind(int unitId, C3D_Tex* tex)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
ctx->flags |= C3DiF_Tex(unitId);
|
||||
ctx->tex[unitId] = tex;
|
||||
}
|
||||
|
||||
void C3D_TexFlush(C3D_Tex* tex)
|
||||
{
|
||||
if (tex->data)
|
||||
GSPGPU_FlushDataCache(NULL, tex->data, tex->size);
|
||||
}
|
||||
|
||||
void C3D_TexDelete(C3D_Tex* tex)
|
||||
{
|
||||
if (!tex->data) return;
|
||||
|
||||
linearFree(tex->data);
|
||||
tex->data = NULL;
|
||||
}
|
63
source/uniforms.c
Normal file
63
source/uniforms.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include <c3d/uniforms.h>
|
||||
//#include <stdio.h>
|
||||
|
||||
C3D_FVec C3D_FVUnif[C3D_FVUNIF_COUNT];
|
||||
C3D_IVec C3D_IVUnif[C3D_IVUNIF_COUNT];
|
||||
u16 C3D_BoolUnifs;
|
||||
|
||||
bool C3D_FVUnifDirty[C3D_FVUNIF_COUNT];
|
||||
bool C3D_IVUnifDirty[C3D_IVUNIF_COUNT];
|
||||
bool C3D_BoolUnifsDirty;
|
||||
|
||||
void C3D_UpdateUniforms(void)
|
||||
{
|
||||
// Update FVec uniforms
|
||||
int i = 0;
|
||||
while (i < C3D_FVUNIF_COUNT)
|
||||
{
|
||||
if (!C3D_FVUnifDirty[i])
|
||||
{
|
||||
i ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the number of consecutive dirty uniforms
|
||||
int j;
|
||||
for (j = i; j < C3D_FVUNIF_COUNT && C3D_FVUnifDirty[j]; j ++);
|
||||
|
||||
/*
|
||||
consoleClear();
|
||||
printf("FVEC Uniform %02X--%02X\n", i, j-1);
|
||||
int pp;
|
||||
for (pp = i; pp < j; pp ++)
|
||||
printf("%02X: (%f, %f, %f, %f)\n", pp, C3D_FVUnif[pp].x, C3D_FVUnif[pp].y, C3D_FVUnif[pp].z, C3D_FVUnif[pp].w);
|
||||
*/
|
||||
|
||||
// Upload the uniforms
|
||||
GPU_SetUniform(i, (u32*)&C3D_FVUnif[i], j-i);
|
||||
|
||||
// Clear the dirty flag
|
||||
int k;
|
||||
for (k = i; k < j; k ++)
|
||||
C3D_FVUnifDirty[k] = false;
|
||||
|
||||
// Advance
|
||||
i += j;
|
||||
}
|
||||
|
||||
// Update IVec uniforms
|
||||
for (i = 0; i < C3D_IVUNIF_COUNT; i ++)
|
||||
{
|
||||
if (!C3D_IVUnifDirty[i]) continue;
|
||||
|
||||
GPUCMD_AddSingleParam(0x000F02B1+i, C3D_IVUnif[i]);
|
||||
C3D_IVUnifDirty[i] = false;
|
||||
}
|
||||
|
||||
// Update bool uniforms
|
||||
if (C3D_BoolUnifsDirty)
|
||||
{
|
||||
GPUCMD_AddSingleParam(0x000F02B0, 0x7FFF0000 | (u32)C3D_BoolUnifs);
|
||||
C3D_BoolUnifsDirty = false;
|
||||
}
|
||||
}
|
49
source/vbo.c
Normal file
49
source/vbo.c
Normal file
@ -0,0 +1,49 @@
|
||||
#include <c3d/buffers.h>
|
||||
#include <string.h>
|
||||
#include "context.h"
|
||||
|
||||
bool C3D_VBOInit(C3D_VBO* vbo, size_t capacity)
|
||||
{
|
||||
if (vbo->data) return false;
|
||||
|
||||
vbo->data = linearAlloc(capacity);
|
||||
if (!vbo->data) return false;
|
||||
vbo->capacity = capacity;
|
||||
vbo->size = 0;
|
||||
vbo->vertexCount = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C3D_VBOAddData(C3D_VBO* vbo, const void* data, size_t size, int vertexCount)
|
||||
{
|
||||
size_t remaining = vbo->capacity - vbo->size;
|
||||
if (remaining < size) return false;
|
||||
memcpy((u8*)vbo->data + vbo->size, data, size);
|
||||
vbo->size += size;
|
||||
vbo->vertexCount += vertexCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
void C3D_VBOFlush(C3D_VBO* vbo)
|
||||
{
|
||||
if (vbo->data)
|
||||
GSPGPU_FlushDataCache(NULL, vbo->data, vbo->size);
|
||||
}
|
||||
|
||||
void C3D_VBOBind(C3D_VBO* vbo)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
ctx->vboPos = osConvertVirtToPhys((u32)vbo->data);
|
||||
GPUCMD_AddSingleParam(0x000F0200, ctx->vboPos >> 3);
|
||||
}
|
||||
|
||||
void C3D_VBODelete(C3D_VBO* vbo)
|
||||
{
|
||||
if (!vbo->data) return;
|
||||
linearFree(vbo->data);
|
||||
vbo->data = NULL;
|
||||
}
|
Loading…
Reference in New Issue
Block a user