mirror of
				https://github.com/ctruLua/ctruLua.git
				synced 2025-10-28 16:59:30 +00:00 
			
		
		
		
	Updated all the libs, added citro3d, added ctr.swkbd (WIP, untested)
This commit is contained in:
		
							parent
							
								
									68a44645f7
								
							
						
					
					
						commit
						49c87e5526
					
				
					 97 changed files with 7341 additions and 944 deletions
				
			
		
							
								
								
									
										10
									
								
								libs/citro3d/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								libs/citro3d/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| *~ | ||||
| *.3dsx | ||||
| *.elf | ||||
| *.exe | ||||
| *.smdh | ||||
| *.tar.bz2 | ||||
| Thumbs.db | ||||
| build/ | ||||
| lib/ | ||||
| bin/ | ||||
							
								
								
									
										141
									
								
								libs/citro3d/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								libs/citro3d/Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,141 @@ | |||
| #---------------------------------------------------------------------------------
 | ||||
| .SUFFIXES: | ||||
| #---------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| ifeq ($(strip $(DEVKITARM)),) | ||||
| $(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM") | ||||
| endif | ||||
| 
 | ||||
| include $(DEVKITARM)/3ds_rules | ||||
| 
 | ||||
| export CITRO3D_MAJOR	:= 1 | ||||
| export CITRO3D_MINOR	:= 1 | ||||
| export CITRO3D_PATCH	:= 0 | ||||
| 
 | ||||
| VERSION	:=	$(CITRO3D_MAJOR).$(CITRO3D_MINOR).$(CITRO3D_PATCH) | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| # 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=hard -mtp=soft | ||||
| 
 | ||||
| CFLAGS	:=	-g -Wall -Werror -O2 -mword-relocations \
 | ||||
| 			-fomit-frame-pointer -ffunction-sections \
 | ||||
| 			$(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))) | ||||
| 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)) \
 | ||||
| 			$(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) | ||||
| 
 | ||||
| dist-bin: all | ||||
| 	@tar --exclude=*~ -cjf citro3d-$(VERSION).tar.bz2 include lib | ||||
| 
 | ||||
| dist-src: | ||||
| 	@tar --exclude=*~ -cjf citro3d-src-$(VERSION).tar.bz2 include source Makefile | ||||
| 
 | ||||
| dist: dist-src dist-bin | ||||
| 
 | ||||
| install: dist-bin | ||||
| 	mkdir -p $(DEVKITPRO)/libctru | ||||
| 	bzip2 -cd citro3d-$(VERSION).tar.bz2 | tar -xf - -C $(DEVKITPRO)/libctru | ||||
| 
 | ||||
| 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) | ||||
| 
 | ||||
| -include $(DEPENDS) | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------------
 | ||||
| endif | ||||
| #---------------------------------------------------------------------------------------
 | ||||
							
								
								
									
										28
									
								
								libs/citro3d/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								libs/citro3d/README.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| # citro3d | ||||
| 
 | ||||
| citro3d is a library that provides an easy to use stateful interface to the PICA200 GPU of the Nintendo 3DS. It tries to expose hardware functionality in the way that is most natural and convenient to the GPU and the user, therefore deviating from openGL. | ||||
| 
 | ||||
| # Setup | ||||
| 
 | ||||
| citro3d can be built and installed using the following command: | ||||
| 
 | ||||
|     make install | ||||
| 
 | ||||
| # License | ||||
| 
 | ||||
|   This software is provided 'as-is', without any express or implied | ||||
|   warranty.  In no event will the authors be held liable for any | ||||
|   damages arising from the use of this software. | ||||
| 
 | ||||
|   Permission is granted to anyone to use this software for any | ||||
|   purpose, including commercial applications, and to alter it and | ||||
|   redistribute it freely, subject to the following restrictions: | ||||
| 
 | ||||
|   1. The origin of this software must not be misrepresented; you | ||||
|      must not claim that you wrote the original software. If you use | ||||
|      this software in a product, an acknowledgment in the product | ||||
|      documentation would be appreciated but is not required. | ||||
|   2. Altered source versions must be plainly marked as such, and | ||||
|      must not be misrepresented as being the original software. | ||||
|   3. This notice may not be removed or altered from any source | ||||
|      distribution. | ||||
							
								
								
									
										16
									
								
								libs/citro3d/include/c3d/attribs.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								libs/citro3d/include/c3d/attribs.h
									
										
									
									
									
										Normal 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); | ||||
							
								
								
									
										63
									
								
								libs/citro3d/include/c3d/base.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								libs/citro3d/include/c3d/base.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| #pragma once | ||||
| #include "types.h" | ||||
| #include "buffers.h" | ||||
| #define C3D_DEFAULT_CMDBUF_SIZE 0x40000 | ||||
| 
 | ||||
| enum | ||||
| { | ||||
| 	C3D_UNSIGNED_BYTE = 0, | ||||
| 	C3D_UNSIGNED_SHORT = 1, | ||||
| }; | ||||
| 
 | ||||
| bool C3D_Init(size_t cmdBufSize); | ||||
| void C3D_FlushAsync(void); | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| static inline void C3D_FlushAwait(void) | ||||
| { | ||||
| 	gspWaitForP3D(); | ||||
| } | ||||
| 
 | ||||
| static inline void C3D_Flush(void) | ||||
| { | ||||
| 	C3D_FlushAsync(); | ||||
| 	C3D_FlushAwait(); | ||||
| } | ||||
| 
 | ||||
| static inline void C3D_VideoSync(void) | ||||
| { | ||||
| 	gspWaitForEvent(GSPGPU_EVENT_VBlank0, false); | ||||
| 	gfxSwapBuffersGpu(); | ||||
| } | ||||
| 
 | ||||
| // 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
									
								
								libs/citro3d/include/c3d/buffers.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								libs/citro3d/include/c3d/buffers.h
									
										
									
									
									
										Normal 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); | ||||
							
								
								
									
										13
									
								
								libs/citro3d/include/c3d/effect.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								libs/citro3d/include/c3d/effect.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| #pragma once | ||||
| #include "types.h" | ||||
| 
 | ||||
| void C3D_DepthMap(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_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); | ||||
							
								
								
									
										136
									
								
								libs/citro3d/include/c3d/light.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								libs/citro3d/include/c3d/light.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,136 @@ | |||
| #pragma once | ||||
| #include "types.h" | ||||
| #include "lightlut.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_LutDirty(n) BIT(26+(n)) | ||||
| #define C3DF_LightEnv_LutDirtyAll (0x3F<<26) | ||||
| }; | ||||
| 
 | ||||
| struct C3D_LightEnv_t | ||||
| { | ||||
| 	void (* Update)(C3D_LightEnv* env); | ||||
| 	void (* Dirty)(C3D_LightEnv* env); | ||||
| 	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, int lutId, int input, bool abs, 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); | ||||
| 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 color[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_LightColor(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); | ||||
							
								
								
									
										29
									
								
								libs/citro3d/include/c3d/lightlut.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								libs/citro3d/include/c3d/lightlut.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| #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); | ||||
| } | ||||
| 
 | ||||
| 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 LightLutDA_Quadratic(lut, from, to, linear, quad) LightLutDA_Create((lut), quadratic_dist_attn, (from), (to), (linear), (quad)) | ||||
							
								
								
									
										671
									
								
								libs/citro3d/include/c3d/maths.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										671
									
								
								libs/citro3d/include/c3d/maths.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,671 @@ | |||
| #pragma once | ||||
| #include "types.h" | ||||
| #include <math.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| // See http://tauday.com/tau-manifesto
 | ||||
| //#define M_TAU 6.28318530717958647693
 | ||||
| /// The one true circumference-to-radius ratio
 | ||||
| #define M_TAU (2*M_PI) | ||||
| 
 | ||||
| /**
 | ||||
|  * @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 the same as scaling by -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 lhs∙rhs | ||||
|  */ | ||||
| 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 lhs∙rhs | ||||
|  */ | ||||
| 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 FVec4 | ||||
|  * @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 FVec4 | ||||
|  * @note This is the same as scaling by -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 Identity matrix | ||||
|  * @param[out] out Matrix to fill | ||||
|  */ | ||||
| void Mtx_Identity(C3D_Mtx* out); | ||||
| 
 | ||||
| /**
 | ||||
|  * @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 | ||||
|  * @note returns 0.0f if the matrix is degenerate; i.e. no inverse | ||||
|  * @param[in,out] out Matrix to 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 Product of mtx and v | ||||
|  */ | ||||
| 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 Product of mtx and v | ||||
|  */ | ||||
| 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 Product of mtx and v | ||||
|  */ | ||||
| static inline C3D_FVec Mtx_MultiplyFVecH(const C3D_Mtx* mtx, C3D_FVec v) | ||||
| { | ||||
| 	v.w = 1.0f; | ||||
| 
 | ||||
| 	return Mtx_MultiplyFVec4(mtx, v); | ||||
| } | ||||
| ///@}
 | ||||
| 
 | ||||
| /**
 | ||||
|  * @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 | ||||
|  */ | ||||
| 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 | ||||
|  */ | ||||
| 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 | ||||
|  */ | ||||
| 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[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 | ||||
|  */ | ||||
| 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 | ||||
|  */ | ||||
| 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 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 | ||||
|  */ | ||||
| void Mtx_PerspStereoTilt(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, float iod, float screen, bool isLeftHanded); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Left-handed Look-At matrix, using 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      If true, output matrix is left-handed. If false, output matrix is right-handed. | ||||
|  */ | ||||
| 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 R-component | ||||
|  * @return New Quaternion | ||||
|  */ | ||||
| #define Quat_New(i,j,k,r) FVec4_New(i,j,k,r) | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Negate a Quaternion | ||||
|  * @note This is the same as scaling by -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 lhs∙rhs | ||||
|  */ | ||||
| #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^p | ||||
|  */ | ||||
| C3D_FQuat Quat_Pow(C3D_FQuat q, float p); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Cross product of Quaternion and FVec3 | ||||
|  * @param[in] lhs Left-side Quaternion | ||||
|  * @param[in] rhs Right-side FVec3 | ||||
|  * @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 4x4 matrix equivalent to Quaternion | ||||
|  * @param[out] m Output matrix | ||||
|  * @param[in]  q Input Quaternion | ||||
|  */ | ||||
| void Mtx_FromQuat(C3D_Mtx* m, C3D_FQuat q); | ||||
| 
 | ||||
| /**
 | ||||
|  * @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 Conjugate of 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 the same as raising to the power of -1 | ||||
|  * @param[in] q Quaternion of which to get inverse | ||||
|  * @return Inverse of q | ||||
|  */ | ||||
| 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] lhs Left-side FVec3 | ||||
|  * @param[in] rhs Right-side Quaternion | ||||
|  * @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); | ||||
| } | ||||
| ///@}
 | ||||
							
								
								
									
										23
									
								
								libs/citro3d/include/c3d/mtxstack.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								libs/citro3d/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 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); | ||||
							
								
								
									
										28
									
								
								libs/citro3d/include/c3d/renderbuffer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								libs/citro3d/include/c3d/renderbuffer.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| #pragma once | ||||
| #include "types.h" | ||||
| #include "texture.h" | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
| 	C3D_Tex colorBuf, depthBuf; | ||||
| 	u32 clearColor, clearDepth; | ||||
| 	int depthFmt; | ||||
| } C3D_RenderBuf; | ||||
| 
 | ||||
| bool C3D_RenderBufInit(C3D_RenderBuf* rb, int width, int height, int colorFmt, int depthFmt); | ||||
| void C3D_RenderBufClearAsync(C3D_RenderBuf* rb); | ||||
| void C3D_RenderBufTransferAsync(C3D_RenderBuf* rb, u32* frameBuf, u32 flags); | ||||
| void C3D_RenderBufBind(C3D_RenderBuf* rb); | ||||
| void C3D_RenderBufDelete(C3D_RenderBuf* rb); | ||||
| 
 | ||||
| static inline void C3D_RenderBufClear(C3D_RenderBuf* rb) | ||||
| { | ||||
| 	C3D_RenderBufClearAsync(rb); | ||||
| 	gspWaitForPSC0(); | ||||
| } | ||||
| 
 | ||||
| static inline void C3D_RenderBufTransfer(C3D_RenderBuf* rb, u32* frameBuf, u32 flags) | ||||
| { | ||||
| 	C3D_RenderBufTransferAsync(rb, frameBuf, flags); | ||||
| 	gspWaitForPPF(); | ||||
| } | ||||
							
								
								
									
										46
									
								
								libs/citro3d/include/c3d/renderqueue.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								libs/citro3d/include/c3d/renderqueue.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| #pragma once | ||||
| #include "renderbuffer.h" | ||||
| 
 | ||||
| typedef struct C3D_RenderTarget_tag C3D_RenderTarget; | ||||
| 
 | ||||
| struct C3D_RenderTarget_tag | ||||
| { | ||||
| 	C3D_RenderTarget *next, *prev, *link, *frame[2]; | ||||
| 	C3D_RenderBuf renderBuf; | ||||
| 	u32 transferFlags; | ||||
| 
 | ||||
| 	u8 clearBits; | ||||
| 	bool drawOk, transferOk; | ||||
| 
 | ||||
| 	bool linked; | ||||
| 	gfxScreen_t screen; | ||||
| 	gfx3dSide_t side; | ||||
| }; | ||||
| 
 | ||||
| // Flags for C3D_FrameBegin
 | ||||
| enum | ||||
| { | ||||
| 	C3D_FRAME_SYNCDRAW = BIT(0), // Do not render the frame until the previous has finished rendering
 | ||||
| 	C3D_FRAME_NONBLOCK = BIT(1), // Return false instead of waiting for the GPU to finish rendering
 | ||||
| }; | ||||
| 
 | ||||
| bool C3D_FrameBegin(u8 flags); | ||||
| bool C3D_FrameDrawOn(C3D_RenderTarget* target); | ||||
| void C3D_FrameEnd(u8 flags); | ||||
| 
 | ||||
| // Flags for C3D_RenderTargetSetClear (only C3D_CLEAR_ALL implemented atm)
 | ||||
| enum | ||||
| { | ||||
| 	C3D_CLEAR_COLOR = BIT(0), | ||||
| 	C3D_CLEAR_DEPTH = BIT(1), | ||||
| 	C3D_CLEAR_ALL   = C3D_CLEAR_COLOR | C3D_CLEAR_DEPTH, | ||||
| }; | ||||
| 
 | ||||
| C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, int colorFmt, int depthFmt); | ||||
| void C3D_RenderTargetDelete(C3D_RenderTarget* target); | ||||
| void C3D_RenderTargetSetClear(C3D_RenderTarget* target, u32 clearBits, u32 clearColor, u32 clearDepth); | ||||
| void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags); | ||||
| 
 | ||||
| void C3D_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags); | ||||
| void C3D_SafeTextureCopy(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 size, u32 flags); | ||||
| void C3D_SafeMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1); | ||||
							
								
								
									
										65
									
								
								libs/citro3d/include/c3d/texenv.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								libs/citro3d/include/c3d/texenv.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | |||
| #pragma once | ||||
| #include "types.h" | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
| 	u16 srcRgb, srcAlpha; | ||||
| 	u16 opRgb, opAlpha; | ||||
| 	u16 funcRgb, funcAlpha; | ||||
| 	u32 color; | ||||
| 	u16 scaleRgb, scaleAlpha; | ||||
| } 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); | ||||
| 
 | ||||
| void C3D_TexEnvBufUpdate(int mode, int mask); | ||||
| void C3D_TexEnvBufColor(u32 color); | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
| static inline void C3D_TexEnvScale(C3D_TexEnv* env, int mode, int param) | ||||
| { | ||||
| 	if (mode & C3D_RGB) | ||||
| 		env->scaleRgb = param; | ||||
| 	if (mode & C3D_Alpha) | ||||
| 		env->scaleAlpha = param; | ||||
| } | ||||
							
								
								
									
										22
									
								
								libs/citro3d/include/c3d/texture.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								libs/citro3d/include/c3d/texture.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| #pragma once | ||||
| #include "types.h" | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
| 	void* data; | ||||
| 
 | ||||
| 	GPU_TEXCOLOR fmt : 4; | ||||
| 	size_t size : 28; | ||||
| 
 | ||||
| 	u16 width, height; | ||||
| 	u32 param; | ||||
| } C3D_Tex; | ||||
| 
 | ||||
| bool C3D_TexInit(C3D_Tex* tex, int width, int height, GPU_TEXCOLOR format); | ||||
| bool C3D_TexInitVRAM(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); | ||||
							
								
								
									
										32
									
								
								libs/citro3d/include/c3d/types.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								libs/citro3d/include/c3d/types.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| #pragma once | ||||
| #ifdef _3DS | ||||
| #include <3ds.h> | ||||
| #else | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| typedef uint8_t u8; | ||||
| typedef uint32_t u32; | ||||
| #endif | ||||
| 
 | ||||
| typedef u32 C3D_IVec; | ||||
| 
 | ||||
| typedef union | ||||
| { | ||||
| 	struct { float w, z, y, x; }; | ||||
| 	struct { float r, k, j, i; }; | ||||
| 	float c[4]; | ||||
| } C3D_FVec; | ||||
| 
 | ||||
| typedef C3D_FVec C3D_FQuat; | ||||
| 
 | ||||
| // Row-major 4x4 matrix
 | ||||
| typedef 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); | ||||
| } | ||||
							
								
								
									
										77
									
								
								libs/citro3d/include/c3d/uniforms.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								libs/citro3d/include/c3d/uniforms.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| #pragma once | ||||
| #include "types.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); | ||||
							
								
								
									
										30
									
								
								libs/citro3d/include/citro3d.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								libs/citro3d/include/citro3d.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| #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" | ||||
| #include "c3d/light.h" | ||||
| 
 | ||||
| #include "c3d/renderbuffer.h" | ||||
| #include "c3d/renderqueue.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										66
									
								
								libs/citro3d/source/attribs.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								libs/citro3d/source/attribs.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | |||
| #include <c3d/attribs.h> | ||||
| #include <string.h> | ||||
| #include "context.h" | ||||
| 
 | ||||
| void AttrInfo_Init(C3D_AttrInfo* info) | ||||
| { | ||||
| 	memset(info, 0, sizeof(*info)); | ||||
| 	info->flags[1] = 0xFFF << 16; | ||||
| } | ||||
| 
 | ||||
| int AttrInfo_AddLoader(C3D_AttrInfo* info, int regId, GPU_FORMATS format, int count) | ||||
| { | ||||
| 	if (info->attrCount == 12) return -1; | ||||
| 	int id = info->attrCount++; | ||||
| 	if (regId < 0) regId = id; | ||||
| 	if (id < 8) | ||||
| 		info->flags[0] |= GPU_ATTRIBFMT(id, count, format); | ||||
| 	else | ||||
| 		info->flags[1] |= GPU_ATTRIBFMT(id-8, count, format); | ||||
| 
 | ||||
| 	info->flags[1] = (info->flags[1] &~ (0xF0000000 | BIT(id+16))) | (id << 28); | ||||
| 	info->permutation |= regId << (id*4); | ||||
| 	return id; | ||||
| } | ||||
| 
 | ||||
| int AttrInfo_AddFixed(C3D_AttrInfo* info, int regId) | ||||
| { | ||||
| 	if (info->attrCount == 12) return -1; | ||||
| 	int id = info->attrCount++; | ||||
| 	if (regId < 0) regId = id; | ||||
| 
 | ||||
| 	info->flags[1] = (info->flags[1] &~ 0xF0000000) | (id << 28); | ||||
| 	info->permutation |= regId << (id*4); | ||||
| 	return id; | ||||
| } | ||||
| 
 | ||||
| C3D_AttrInfo* C3D_GetAttrInfo(void) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	ctx->flags |= C3DiF_AttrInfo; | ||||
| 	return &ctx->attrInfo; | ||||
| } | ||||
| 
 | ||||
| void C3D_SetAttrInfo(C3D_AttrInfo* info) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (info != &ctx->attrInfo) | ||||
| 		memcpy(&ctx->attrInfo, info, sizeof(*info)); | ||||
| 	ctx->flags |= C3DiF_AttrInfo; | ||||
| } | ||||
| 
 | ||||
| void C3Di_AttrInfoBind(C3D_AttrInfo* info) | ||||
| { | ||||
| 	GPUCMD_AddIncrementalWrites(GPUREG_ATTRIBBUFFERS_FORMAT_LOW, (u32*)info->flags, sizeof(info->flags)/sizeof(u32)); | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_VSH_INPUTBUFFER_CONFIG, 0xB, 0xA0000000 | (info->attrCount - 1)); | ||||
| 	GPUCMD_AddWrite(GPUREG_VSH_NUM_ATTR, info->attrCount - 1); | ||||
| 	GPUCMD_AddIncrementalWrites(GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW, (u32*)&info->permutation, 2); | ||||
| } | ||||
							
								
								
									
										365
									
								
								libs/citro3d/source/base.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										365
									
								
								libs/citro3d/source/base.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,365 @@ | |||
| #include "context.h" | ||||
| 
 | ||||
| C3D_Context __C3D_Context; | ||||
| 
 | ||||
| static void C3Di_SetTex(GPU_TEXUNIT unit, C3D_Tex* tex) | ||||
| { | ||||
| 	u32 reg[4]; | ||||
| 	reg[0] = tex->fmt; | ||||
| 	reg[1] = osConvertVirtToPhys(tex->data) >> 3; | ||||
| 	reg[2] = (u32)tex->height | ((u32)tex->width << 16); | ||||
| 	reg[3] = tex->param; | ||||
| 
 | ||||
| 	switch (unit) | ||||
| 	{ | ||||
| 		case GPU_TEXUNIT0: | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT0_TYPE, reg[0]); | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT0_ADDR1, reg[1]); | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT0_DIM, reg[2]); | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT0_PARAM, reg[3]); | ||||
| 			break; | ||||
| 		case GPU_TEXUNIT1: | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT1_TYPE, reg[0]); | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT1_ADDR, reg[1]); | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT1_DIM, reg[2]); | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT1_PARAM, reg[3]); | ||||
| 			break; | ||||
| 		case GPU_TEXUNIT2: | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT2_TYPE, reg[0]); | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT2_ADDR, reg[1]); | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT2_DIM, reg[2]); | ||||
| 			GPUCMD_AddWrite(GPUREG_TEXUNIT2_PARAM, reg[3]); | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static aptHookCookie hookCookie; | ||||
| 
 | ||||
| static void C3Di_AptEventHook(APT_HookType hookType, void* param) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	switch (hookType) | ||||
| 	{ | ||||
| 		case APTHOOK_ONSUSPEND: | ||||
| 		{ | ||||
| 			if (ctx->renderQueueWaitDone) | ||||
| 				ctx->renderQueueWaitDone(); | ||||
| 			break; | ||||
| 		} | ||||
| 		case APTHOOK_ONRESTORE: | ||||
| 		{ | ||||
| 			ctx->flags |= C3DiF_AttrInfo | C3DiF_BufInfo | C3DiF_Effect | C3DiF_RenderBuf | ||||
| 				| C3DiF_Viewport | C3DiF_Scissor | C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode | ||||
| 				| C3DiF_TexAll | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_LightEnv; | ||||
| 
 | ||||
| 			C3Di_DirtyUniforms(GPU_VERTEX_SHADER); | ||||
| 			C3Di_DirtyUniforms(GPU_GEOMETRY_SHADER); | ||||
| 
 | ||||
| 			ctx->fixedAttribDirty |= ctx->fixedAttribEverDirty; | ||||
| 
 | ||||
| 			C3D_LightEnv* env = ctx->lightEnv; | ||||
| 			if (env) | ||||
| 				env->Dirty(env); | ||||
| 			break; | ||||
| 		} | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool C3D_Init(size_t cmdBufSize) | ||||
| { | ||||
| 	int i; | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (ctx->flags & C3DiF_Active) | ||||
| 		return false; | ||||
| 
 | ||||
| 	ctx->cmdBufSize = cmdBufSize/8; // Half of the size of the cmdbuf, in words
 | ||||
| 	ctx->cmdBuf = (u32*)linearAlloc(cmdBufSize); | ||||
| 	ctx->cmdBufUsage = 0; | ||||
| 	if (!ctx->cmdBuf) return false; | ||||
| 
 | ||||
| 	GPUCMD_SetBuffer(ctx->cmdBuf, ctx->cmdBufSize, 0); | ||||
| 
 | ||||
| 	ctx->flags = C3DiF_Active | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_Effect | C3DiF_TexAll; | ||||
| 	ctx->renderQueueExit = NULL; | ||||
| 
 | ||||
| 	// TODO: replace with direct struct access
 | ||||
| 	C3D_DepthMap(-1.0f, 0.0f); | ||||
| 	C3D_CullFace(GPU_CULL_BACK_CCW); | ||||
| 	C3D_StencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00); | ||||
| 	C3D_StencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_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); | ||||
| 	C3D_FragOpMode(GPU_FRAGOPMODE_GL); | ||||
| 
 | ||||
| 	ctx->texEnvBuf = 0; | ||||
| 	ctx->texEnvBufClr = 0xFFFFFFFF; | ||||
| 
 | ||||
| 	for (i = 0; i < 3; i ++) | ||||
| 		ctx->tex[i] = NULL; | ||||
| 
 | ||||
| 	for (i = 0; i < 6; i ++) | ||||
| 		TexEnv_Init(&ctx->texEnv[i]); | ||||
| 
 | ||||
| 	ctx->fixedAttribDirty = 0; | ||||
| 	ctx->fixedAttribEverDirty = 0; | ||||
| 
 | ||||
| 	aptHook(&hookCookie, C3Di_AptEventHook, NULL); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void C3D_SetViewport(u32 x, u32 y, u32 w, u32 h) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 	ctx->flags |= C3DiF_Viewport | C3DiF_Scissor; | ||||
| 	ctx->viewport[0] = f32tof24(w / 2.0f); | ||||
| 	ctx->viewport[1] = f32tof31(2.0f / w) << 1; | ||||
| 	ctx->viewport[2] = f32tof24(h / 2.0f); | ||||
| 	ctx->viewport[3] = f32tof31(2.0f / h) << 1; | ||||
| 	ctx->viewport[4] = (y << 16) | (x & 0xFFFF); | ||||
| 	ctx->scissor[0] = GPU_SCISSOR_DISABLE; | ||||
| } | ||||
| 
 | ||||
| void C3D_SetScissor(GPU_SCISSORMODE mode, u32 left, u32 top, u32 right, u32 bottom) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 	ctx->flags |= C3DiF_Scissor; | ||||
| 	ctx->scissor[0] = mode; | ||||
| 	if (mode == GPU_SCISSOR_DISABLE) return; | ||||
| 	ctx->scissor[1] = (top << 16) | (left & 0xFFFF); | ||||
| 	ctx->scissor[2] = ((bottom-1) << 16) | ((right-1) & 0xFFFF); | ||||
| } | ||||
| 
 | ||||
| void C3Di_UpdateContext(void) | ||||
| { | ||||
| 	int i; | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (ctx->flags & C3DiF_Program) | ||||
| 	{ | ||||
| 		shaderProgramConfigure(ctx->program, (ctx->flags & C3DiF_VshCode) != 0, (ctx->flags & C3DiF_GshCode) != 0); | ||||
| 		ctx->flags &= ~(C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode); | ||||
| 	} | ||||
| 
 | ||||
| 	if (ctx->flags & C3DiF_RenderBuf) | ||||
| 	{ | ||||
| 		ctx->flags &= ~C3DiF_RenderBuf; | ||||
| 		if (ctx->flags & C3DiF_DrawUsed) | ||||
| 		{ | ||||
| 			ctx->flags &= ~C3DiF_DrawUsed; | ||||
| 			GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 1); | ||||
| 			GPUCMD_AddWrite(GPUREG_EARLYDEPTH_CLEAR, 1); | ||||
| 		} | ||||
| 		C3Di_RenderBufBind(ctx->rb); | ||||
| 	} | ||||
| 
 | ||||
| 	if (ctx->flags & C3DiF_Viewport) | ||||
| 	{ | ||||
| 		ctx->flags &= ~C3DiF_Viewport; | ||||
| 		GPUCMD_AddIncrementalWrites(GPUREG_VIEWPORT_WIDTH, ctx->viewport, 4); | ||||
| 		GPUCMD_AddWrite(GPUREG_VIEWPORT_XY, ctx->viewport[4]); | ||||
| 	} | ||||
| 
 | ||||
| 	if (ctx->flags & C3DiF_Scissor) | ||||
| 	{ | ||||
| 		ctx->flags &= ~C3DiF_Scissor; | ||||
| 		GPUCMD_AddIncrementalWrites(GPUREG_SCISSORTEST_MODE, ctx->scissor, 3); | ||||
| 	} | ||||
| 
 | ||||
| 	if (ctx->flags & C3DiF_AttrInfo) | ||||
| 	{ | ||||
| 		ctx->flags &= ~C3DiF_AttrInfo; | ||||
| 		C3Di_AttrInfoBind(&ctx->attrInfo); | ||||
| 	} | ||||
| 
 | ||||
| 	if (ctx->flags & C3DiF_BufInfo) | ||||
| 	{ | ||||
| 		ctx->flags &= ~C3DiF_BufInfo; | ||||
| 		C3Di_BufInfoBind(&ctx->bufInfo); | ||||
| 	} | ||||
| 
 | ||||
| 	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; | ||||
| 		GPUCMD_AddWrite(GPUREG_TEXUNIT_CONFIG, 0x00011000|units); // Enable texture units
 | ||||
| 	} | ||||
| 
 | ||||
| 	if (ctx->flags & C3DiF_TexEnvBuf) | ||||
| 	{ | ||||
| 		ctx->flags &= ~C3DiF_TexEnvBuf; | ||||
| 		GPUCMD_AddMaskedWrite(GPUREG_TEXENV_UPDATE_BUFFER, 0x2, ctx->texEnvBuf); | ||||
| 		GPUCMD_AddWrite(GPUREG_TEXENV_BUFFER_COLOR, ctx->texEnvBufClr); | ||||
| 	} | ||||
| 
 | ||||
| 	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_LightEnv* env = ctx->lightEnv; | ||||
| 
 | ||||
| 	if (ctx->flags & C3DiF_LightEnv) | ||||
| 	{ | ||||
| 		u32 enable = env != NULL; | ||||
| 		GPUCMD_AddWrite(GPUREG_LIGHTING_ENABLE0, enable); | ||||
| 		GPUCMD_AddWrite(GPUREG_LIGHTING_ENABLE1, !enable); | ||||
| 		ctx->flags &= ~C3DiF_LightEnv; | ||||
| 	} | ||||
| 
 | ||||
| 	if (env) | ||||
| 		env->Update(env); | ||||
| 
 | ||||
| 	if (ctx->fixedAttribDirty) | ||||
| 	{ | ||||
| 		for (i = 0; i < 12; i ++) | ||||
| 		{ | ||||
| 			if (!(ctx->fixedAttribDirty & BIT(i))) continue; | ||||
| 			C3D_FVec* v = &ctx->fixedAttribs[i]; | ||||
| 
 | ||||
| 			GPUCMD_AddWrite(GPUREG_FIXEDATTRIB_INDEX, i); | ||||
| 			C3D_ImmSendAttrib(v->x, v->y, v->z, v->w); | ||||
| 		} | ||||
| 		ctx->fixedAttribDirty = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	C3D_UpdateUniforms(GPU_VERTEX_SHADER); | ||||
| 	C3D_UpdateUniforms(GPU_GEOMETRY_SHADER); | ||||
| } | ||||
| 
 | ||||
| void C3Di_FinalizeFrame(u32** pBuf, u32* pSize) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (ctx->flags & C3DiF_DrawUsed) | ||||
| 	{ | ||||
| 		ctx->flags &= ~C3DiF_DrawUsed; | ||||
| 		GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 1); | ||||
| 		GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 1); | ||||
| 		GPUCMD_AddWrite(GPUREG_EARLYDEPTH_CLEAR, 1); | ||||
| 	} | ||||
| 
 | ||||
| 	GPUCMD_Finalize(); | ||||
| 	GPUCMD_GetBuffer(pBuf, NULL, pSize); | ||||
| 	ctx->cmdBufUsage = (float)(*pSize) / ctx->cmdBufSize; | ||||
| 	*pSize *= 4; | ||||
| 
 | ||||
| 	ctx->flags ^= C3DiF_CmdBuffer; | ||||
| 	u32* buf = ctx->cmdBuf; | ||||
| 	if (ctx->flags & C3DiF_CmdBuffer) | ||||
| 		buf += ctx->cmdBufSize; | ||||
| 	GPUCMD_SetBuffer(buf, ctx->cmdBufSize, 0); | ||||
| } | ||||
| 
 | ||||
| void C3D_FlushAsync(void) | ||||
| { | ||||
| 	if (!(C3Di_GetContext()->flags & C3DiF_Active)) | ||||
| 		return; | ||||
| 
 | ||||
| 	u32* cmdBuf; | ||||
| 	u32 cmdBufSize; | ||||
| 	C3Di_FinalizeFrame(&cmdBuf, &cmdBufSize); | ||||
| 
 | ||||
| 	//take advantage of GX_FlushCacheRegions to flush gsp heap
 | ||||
| 	extern u32 __ctru_linear_heap; | ||||
| 	extern u32 __ctru_linear_heap_size; | ||||
| 	GX_FlushCacheRegions(cmdBuf, cmdBufSize, (u32 *) __ctru_linear_heap, __ctru_linear_heap_size, NULL, 0); | ||||
| 	GX_ProcessCommandList(cmdBuf, cmdBufSize, 0x0); | ||||
| } | ||||
| 
 | ||||
| float C3D_GetCmdBufUsage(void) | ||||
| { | ||||
| 	return C3Di_GetContext()->cmdBufUsage; | ||||
| } | ||||
| 
 | ||||
| void C3D_Fini(void) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (ctx->renderQueueExit) | ||||
| 		ctx->renderQueueExit(); | ||||
| 
 | ||||
| 	aptUnhook(&hookCookie); | ||||
| 	linearFree(ctx->cmdBuf); | ||||
| 	ctx->flags = 0; | ||||
| } | ||||
| 
 | ||||
| void C3D_BindProgram(shaderProgram_s* program) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return; | ||||
| 
 | ||||
| 	shaderProgram_s* oldProg = ctx->program; | ||||
| 	shaderInstance_s* newGsh = program->geometryShader; | ||||
| 	if (oldProg != program) | ||||
| 	{ | ||||
| 		ctx->program = program; | ||||
| 		ctx->flags |= C3DiF_Program; | ||||
| 
 | ||||
| 		if (oldProg) | ||||
| 		{ | ||||
| 			if (oldProg->vertexShader->dvle->dvlp != program->vertexShader->dvle->dvlp) | ||||
| 				ctx->flags |= C3DiF_VshCode; | ||||
| 			shaderInstance_s* oldGsh = oldProg->geometryShader; | ||||
| 			if (newGsh && (!oldGsh || oldGsh->dvle->dvlp != newGsh->dvle->dvlp)) | ||||
| 				ctx->flags |= C3DiF_GshCode; | ||||
| 		} else | ||||
| 			ctx->flags |= C3DiF_VshCode | C3DiF_GshCode; | ||||
| 	} | ||||
| 
 | ||||
| 	C3Di_LoadShaderUniforms(program->vertexShader); | ||||
| 	if (newGsh) | ||||
| 		C3Di_LoadShaderUniforms(newGsh); | ||||
| 	else | ||||
| 		C3Di_ClearShaderUniforms(GPU_GEOMETRY_SHADER); | ||||
| } | ||||
| 
 | ||||
| C3D_FVec* C3D_FixedAttribGetWritePtr(int id) | ||||
| { | ||||
| 	if (id < 0 || id >= 12) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	ctx->fixedAttribDirty     |= BIT(id); | ||||
| 	ctx->fixedAttribEverDirty |= BIT(id); | ||||
| 	return &ctx->fixedAttribs[id]; | ||||
| } | ||||
							
								
								
									
										55
									
								
								libs/citro3d/source/buffers.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								libs/citro3d/source/buffers.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | |||
| #include <c3d/buffers.h> | ||||
| #include <string.h> | ||||
| #include "context.h" | ||||
| 
 | ||||
| #define BUFFER_BASE_PADDR 0x18000000 | ||||
| 
 | ||||
| void BufInfo_Init(C3D_BufInfo* info) | ||||
| { | ||||
| 	memset(info, 0, sizeof(*info)); | ||||
| 	info->base_paddr = BUFFER_BASE_PADDR; | ||||
| } | ||||
| 
 | ||||
| int BufInfo_Add(C3D_BufInfo* info, const void* data, ptrdiff_t stride, int attribCount, u64 permutation) | ||||
| { | ||||
| 	if (info->bufCount == 12) return -1; | ||||
| 	int id = info->bufCount++; | ||||
| 
 | ||||
| 	u32 pa = osConvertVirtToPhys(data); | ||||
| 	if (pa < info->base_paddr) return -2; | ||||
| 
 | ||||
| 	C3D_BufCfg* buf = &info->buffers[id]; | ||||
| 	buf->offset = pa - info->base_paddr; | ||||
| 	buf->flags[0] = permutation & 0xFFFFFFFF; | ||||
| 	buf->flags[1] = (permutation >> 32) | (stride << 16) | (attribCount << 28); | ||||
| 	return id; | ||||
| } | ||||
| 
 | ||||
| C3D_BufInfo* C3D_GetBufInfo(void) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	ctx->flags |= C3DiF_BufInfo; | ||||
| 	return &ctx->bufInfo; | ||||
| } | ||||
| 
 | ||||
| void C3D_SetBufInfo(C3D_BufInfo* info) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (info != &ctx->bufInfo) | ||||
| 		memcpy(&ctx->bufInfo, info, sizeof(*info)); | ||||
| 	ctx->flags |= C3DiF_BufInfo; | ||||
| } | ||||
| 
 | ||||
| void C3Di_BufInfoBind(C3D_BufInfo* info) | ||||
| { | ||||
| 	GPUCMD_AddWrite(GPUREG_ATTRIBBUFFERS_LOC, info->base_paddr >> 3); | ||||
| 	GPUCMD_AddIncrementalWrites(GPUREG_ATTRIBBUFFER0_OFFSET, (u32*)info->buffers, sizeof(info->buffers)/sizeof(u32)); | ||||
| } | ||||
							
								
								
									
										100
									
								
								libs/citro3d/source/context.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								libs/citro3d/source/context.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | |||
| #pragma once | ||||
| #include <c3d/base.h> | ||||
| #include <c3d/uniforms.h> | ||||
| #include <c3d/attribs.h> | ||||
| #include <c3d/buffers.h> | ||||
| #include <c3d/texenv.h> | ||||
| #include <c3d/effect.h> | ||||
| #include <c3d/texture.h> | ||||
| #include <c3d/light.h> | ||||
| #include <c3d/renderbuffer.h> | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
| 	u32 fragOpMode; | ||||
| 	u32 zScale, zOffset; | ||||
| 	GPU_CULLMODE cullMode; | ||||
| 
 | ||||
| 	u32 alphaTest; | ||||
| 	u32 stencilMode, stencilOp; | ||||
| 	u32 depthTest; | ||||
| 
 | ||||
| 	u32 blendClr; | ||||
| 	u32 alphaBlend; | ||||
| 	GPU_LOGICOP clrLogicOp; | ||||
| } C3D_Effect; | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
| 	u32* cmdBuf; | ||||
| 	size_t cmdBufSize; | ||||
| 	float cmdBufUsage; | ||||
| 
 | ||||
| 	u32 flags; | ||||
| 	shaderProgram_s* program; | ||||
| 
 | ||||
| 	C3D_AttrInfo attrInfo; | ||||
| 	C3D_BufInfo bufInfo; | ||||
| 	C3D_Effect effect; | ||||
| 	C3D_LightEnv* lightEnv; | ||||
| 
 | ||||
| 	C3D_Tex* tex[3]; | ||||
| 	C3D_TexEnv texEnv[6]; | ||||
| 
 | ||||
| 	u32 texEnvBuf, texEnvBufClr; | ||||
| 
 | ||||
| 	C3D_RenderBuf* rb; | ||||
| 	u32 viewport[5]; | ||||
| 	u32 scissor[3]; | ||||
| 
 | ||||
| 	u16 fixedAttribDirty, fixedAttribEverDirty; | ||||
| 	C3D_FVec fixedAttribs[12]; | ||||
| 
 | ||||
| 	void (* renderQueueWaitDone)(void); | ||||
| 	void (* renderQueueExit)(void); | ||||
| 
 | ||||
| } C3D_Context; | ||||
| 
 | ||||
| enum | ||||
| { | ||||
| 	C3DiF_Active = BIT(0), | ||||
| 	C3DiF_DrawUsed = BIT(1), | ||||
| 	C3DiF_AttrInfo = BIT(2), | ||||
| 	C3DiF_BufInfo = BIT(3), | ||||
| 	C3DiF_Effect = BIT(4), | ||||
| 	C3DiF_RenderBuf = BIT(5), | ||||
| 	C3DiF_Viewport = BIT(6), | ||||
| 	C3DiF_Scissor = BIT(7), | ||||
| 	C3DiF_Program = BIT(8), | ||||
| 	C3DiF_TexEnvBuf = BIT(9), | ||||
| 	C3DiF_LightEnv = BIT(10), | ||||
| 	C3DiF_VshCode = BIT(11), | ||||
| 	C3DiF_GshCode = BIT(12), | ||||
| 	C3DiF_CmdBuffer = BIT(13), | ||||
| 
 | ||||
| #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; | ||||
| } | ||||
| 
 | ||||
| void C3Di_UpdateContext(void); | ||||
| void C3Di_AttrInfoBind(C3D_AttrInfo* info); | ||||
| void C3Di_BufInfoBind(C3D_BufInfo* info); | ||||
| void C3Di_TexEnvBind(int id, C3D_TexEnv* env); | ||||
| void C3Di_EffectBind(C3D_Effect* effect); | ||||
| void C3Di_RenderBufBind(C3D_RenderBuf* rb); | ||||
| 
 | ||||
| void C3Di_LightMtlBlend(C3D_Light* light); | ||||
| 
 | ||||
| void C3Di_DirtyUniforms(GPU_SHADER_TYPE type); | ||||
| void C3Di_LoadShaderUniforms(shaderInstance_s* si); | ||||
| void C3Di_ClearShaderUniforms(GPU_SHADER_TYPE type); | ||||
| 
 | ||||
| void C3Di_FinalizeFrame(u32** pBuf, u32* pSize); | ||||
							
								
								
									
										31
									
								
								libs/citro3d/source/drawArrays.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								libs/citro3d/source/drawArrays.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | |||
| #include "context.h" | ||||
| 
 | ||||
| void C3D_DrawArrays(GPU_Primitive_t primitive, int first, int size) | ||||
| { | ||||
| 	C3Di_UpdateContext(); | ||||
| 
 | ||||
| 	// Set primitive type
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 2, primitive); | ||||
| 	// Start a new primitive (breaks off a triangle strip/fan)
 | ||||
| 	GPUCMD_AddWrite(GPUREG_RESTART_PRIMITIVE, 1); | ||||
| 	// The index buffer is not used, but this command is still required
 | ||||
| 	GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, 0x80000000); | ||||
| 	// Number of vertices
 | ||||
| 	GPUCMD_AddWrite(GPUREG_NUMVERTICES, size); | ||||
| 	// First vertex
 | ||||
| 	GPUCMD_AddWrite(GPUREG_VERTEX_OFFSET, first); | ||||
| 	// Enable array drawing mode
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 1, 1); | ||||
| 	// Enable drawing mode
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 0); | ||||
| 	// Trigger array drawing
 | ||||
| 	GPUCMD_AddWrite(GPUREG_DRAWARRAYS, 1); | ||||
| 	// Go back to configuration mode
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 1); | ||||
| 	// Disable array drawing mode
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 1, 0); | ||||
| 	// Clear the post-vertex cache
 | ||||
| 	GPUCMD_AddWrite(GPUREG_VTX_FUNC, 1); | ||||
| 
 | ||||
| 	C3Di_GetContext()->flags |= C3DiF_DrawUsed; | ||||
| } | ||||
							
								
								
									
										44
									
								
								libs/citro3d/source/drawElements.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								libs/citro3d/source/drawElements.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| #include "context.h" | ||||
| 
 | ||||
| void C3D_DrawElements(GPU_Primitive_t primitive, int count, int type, const void* indices) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 	u32 pa = osConvertVirtToPhys(indices); | ||||
| 	u32 base = ctx->bufInfo.base_paddr; | ||||
| 	if (pa < base) return; | ||||
| 
 | ||||
| 	C3Di_UpdateContext(); | ||||
| 
 | ||||
| 	// Set primitive type
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 2, primitive); | ||||
| 	// Start a new primitive (breaks off a triangle strip/fan)
 | ||||
| 	GPUCMD_AddWrite(GPUREG_RESTART_PRIMITIVE, 1); | ||||
| 	// Configure the index buffer
 | ||||
| 	GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, (pa - base) | (type << 31)); | ||||
| 	// Number of vertices
 | ||||
| 	GPUCMD_AddWrite(GPUREG_NUMVERTICES, count); | ||||
| 	// First vertex
 | ||||
| 	GPUCMD_AddWrite(GPUREG_VERTEX_OFFSET, 0); | ||||
| 	// Enable triangle element drawing mode if necessary
 | ||||
| 	if (primitive == GPU_TRIANGLES) | ||||
| 	{ | ||||
| 		GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 2, 0x100); | ||||
| 		GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 2, 0x100); | ||||
| 	} | ||||
| 	// Enable drawing mode
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 0); | ||||
| 	// Trigger element drawing
 | ||||
| 	GPUCMD_AddWrite(GPUREG_DRAWELEMENTS, 1); | ||||
| 	// Go back to configuration mode
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 1); | ||||
| 	// Disable triangle element drawing mode if necessary
 | ||||
| 	if (primitive == GPU_TRIANGLES) | ||||
| 	{ | ||||
| 		GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 2, 0); | ||||
| 		GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 2, 0); | ||||
| 	} | ||||
| 	// Clear the post-vertex cache
 | ||||
| 	GPUCMD_AddWrite(GPUREG_VTX_FUNC, 1); | ||||
| 
 | ||||
| 	C3Di_GetContext()->flags |= C3DiF_DrawUsed; | ||||
| } | ||||
							
								
								
									
										89
									
								
								libs/citro3d/source/effect.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								libs/citro3d/source/effect.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,89 @@ | |||
| #include "context.h" | ||||
| 
 | ||||
| static inline C3D_Effect* getEffect() | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 	ctx->flags |= C3DiF_Effect; | ||||
| 	return &ctx->effect; | ||||
| } | ||||
| 
 | ||||
| void C3D_DepthMap(float zScale, float zOffset) | ||||
| { | ||||
| 	C3D_Effect* e = getEffect(); | ||||
| 	e->zScale  = f32tof24(zScale); | ||||
| 	e->zOffset = f32tof24(zOffset); | ||||
| } | ||||
| 
 | ||||
| void C3D_CullFace(GPU_CULLMODE mode) | ||||
| { | ||||
| 	C3D_Effect* e = getEffect(); | ||||
| 	e->cullMode = mode; | ||||
| } | ||||
| 
 | ||||
| void C3D_StencilTest(bool enable, GPU_TESTFUNC function, int ref, int inputMask, int writeMask) | ||||
| { | ||||
| 	C3D_Effect* e = getEffect(); | ||||
| 	e->stencilMode = (!!enable) | ((function & 7) << 4) | (writeMask << 8) | (ref << 16) | (inputMask << 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); | ||||
| 	e->fragOpMode &= ~0xFF00; | ||||
| 	e->fragOpMode |= 0x0100; | ||||
| } | ||||
| 
 | ||||
| void C3D_ColorLogicOp(GPU_LOGICOP op) | ||||
| { | ||||
| 	C3D_Effect* e = getEffect(); | ||||
| 	e->fragOpMode &= ~0xFF00; | ||||
| 	e->clrLogicOp = op; | ||||
| } | ||||
| 
 | ||||
| void C3D_FragOpMode(GPU_FRAGOPMODE mode) | ||||
| { | ||||
| 	C3D_Effect* e = getEffect(); | ||||
| 	e->fragOpMode &= ~0xFF00FF; | ||||
| 	e->fragOpMode |= 0xE40000 | mode; | ||||
| } | ||||
| 
 | ||||
| void C3Di_EffectBind(C3D_Effect* e) | ||||
| { | ||||
| 	GPUCMD_AddWrite(GPUREG_DEPTHMAP_ENABLE, 1); | ||||
| 	GPUCMD_AddWrite(GPUREG_FACECULLING_CONFIG, e->cullMode & 0x3); | ||||
| 	GPUCMD_AddIncrementalWrites(GPUREG_DEPTHMAP_SCALE, (u32*)&e->zScale, 2); | ||||
| 	GPUCMD_AddIncrementalWrites(GPUREG_FRAGOP_ALPHA_TEST, (u32*)&e->alphaTest, 4); | ||||
| 	GPUCMD_AddWrite(GPUREG_BLEND_COLOR, e->blendClr); | ||||
| 	GPUCMD_AddWrite(GPUREG_BLEND_FUNC, e->alphaBlend); | ||||
| 	GPUCMD_AddWrite(GPUREG_LOGIC_OP, e->clrLogicOp); | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_COLOR_OPERATION, 7, e->fragOpMode); | ||||
| 
 | ||||
| 	// Disable early depth test?
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_EARLYDEPTH_TEST1, 1, 0); | ||||
| 	GPUCMD_AddWrite(GPUREG_EARLYDEPTH_TEST2, 0); | ||||
| } | ||||
							
								
								
									
										67
									
								
								libs/citro3d/source/immediate.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								libs/citro3d/source/immediate.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,67 @@ | |||
| #include "context.h" | ||||
| 
 | ||||
| void C3D_ImmDrawBegin(GPU_Primitive_t primitive) | ||||
| { | ||||
| 	C3Di_UpdateContext(); | ||||
| 
 | ||||
| 	// Set primitive type
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 2, primitive); | ||||
| 	// Start a new primitive (breaks off a triangle strip/fan)
 | ||||
| 	GPUCMD_AddWrite(GPUREG_RESTART_PRIMITIVE, 1); | ||||
| 	// Not sure if this command is necessary
 | ||||
| 	GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, 0x80000000); | ||||
| 	// Enable vertex submission mode
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 1, 1); | ||||
| 	// Enable drawing mode
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 0); | ||||
| 	// Begin immediate-mode vertex submission
 | ||||
| 	GPUCMD_AddWrite(GPUREG_FIXEDATTRIB_INDEX, 0xF); | ||||
| } | ||||
| 
 | ||||
| static inline void write24(u8* p, u32 val) | ||||
| { | ||||
| 	p[0] = val; | ||||
| 	p[1] = val>>8; | ||||
| 	p[2] = val>>16; | ||||
| } | ||||
| 
 | ||||
| void C3D_ImmSendAttrib(float x, float y, float z, float w) | ||||
| { | ||||
| 	union | ||||
| 	{ | ||||
| 		u32 packed[3]; | ||||
| 		struct | ||||
| 		{ | ||||
| 			u8 x[3]; | ||||
| 			u8 y[3]; | ||||
| 			u8 z[3]; | ||||
| 			u8 w[3]; | ||||
| 		}; | ||||
| 	} param; | ||||
| 
 | ||||
| 	// Convert the values to float24
 | ||||
| 	write24(param.x, f32tof24(x)); | ||||
| 	write24(param.y, f32tof24(y)); | ||||
| 	write24(param.z, f32tof24(z)); | ||||
| 	write24(param.w, f32tof24(w)); | ||||
| 
 | ||||
| 	// Reverse the packed words
 | ||||
| 	u32 p = param.packed[0]; | ||||
| 	param.packed[0] = param.packed[2]; | ||||
| 	param.packed[2] = p; | ||||
| 
 | ||||
| 	// Send the attribute
 | ||||
| 	GPUCMD_AddIncrementalWrites(GPUREG_FIXEDATTRIB_DATA0, param.packed, 3); | ||||
| } | ||||
| 
 | ||||
| void C3D_ImmDrawEnd(void) | ||||
| { | ||||
| 	// Go back to configuration mode
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 1); | ||||
| 	// Disable vertex submission mode
 | ||||
| 	GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 1, 0); | ||||
| 	// Clear the post-vertex cache
 | ||||
| 	GPUCMD_AddWrite(GPUREG_VTX_FUNC, 1); | ||||
| 
 | ||||
| 	C3Di_GetContext()->flags |= C3DiF_DrawUsed; | ||||
| } | ||||
							
								
								
									
										157
									
								
								libs/citro3d/source/light.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								libs/citro3d/source/light.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,157 @@ | |||
| #include <string.h> | ||||
| #include "context.h" | ||||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void C3Di_LightMtlBlend(C3D_Light* light) | ||||
| { | ||||
| 	int i; | ||||
| 	C3D_Material* mtl = &light->parent->material; | ||||
| 	C3D_LightMatConf* conf = &light->conf.material; | ||||
| 	memset(conf, 0, sizeof(*conf)); | ||||
| 
 | ||||
| 	for (i = 0; i < 3; i ++) | ||||
| 	{ | ||||
| 		conf->specular0 |= ((u32)(255*(mtl->specular0[i]*light->color[i]))) << (i*10); | ||||
| 		conf->specular1 |= ((u32)(255*(mtl->specular1[i]*light->color[i]))) << (i*10); | ||||
| 		conf->diffuse   |= ((u32)(255*(mtl->diffuse[i]  *light->color[i]))) << (i*10); | ||||
| 		conf->ambient   |= ((u32)(255*(mtl->ambient[i]  *light->color[i]))) << (i*10); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int C3D_LightInit(C3D_Light* light, C3D_LightEnv* env) | ||||
| { | ||||
| 	int i; | ||||
| 	memset(light, 0, sizeof(*light)); | ||||
| 
 | ||||
| 	for (i = 0; i < 8; i ++) | ||||
| 		if (!env->lights[i]) | ||||
| 			break; | ||||
| 	if (i == 8) return -1; | ||||
| 
 | ||||
| 	env->lights[i] = light; | ||||
| 	light->flags = C3DF_Light_Enabled | C3DF_Light_Dirty | C3DF_Light_MatDirty; | ||||
| 	light->id = i; | ||||
| 	light->parent = env; | ||||
| 
 | ||||
| 	env->flags |= C3DF_LightEnv_LCDirty; | ||||
| 	return i; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnable(C3D_Light* light, bool enable) | ||||
| { | ||||
| 	if ((light->flags & C3DF_Light_Enabled) == (enable?C3DF_Light_Enabled:0)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (enable) | ||||
| 		light->flags |= C3DF_Light_Enabled; | ||||
| 	else | ||||
| 		light->flags &= ~C3DF_Light_Enabled; | ||||
| 
 | ||||
| 	light->parent->flags |= C3DF_LightEnv_LCDirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightTwoSideDiffuse(C3D_Light* light, bool enable) | ||||
| { | ||||
| 	if (enable) | ||||
| 		light->conf.config |= BIT(1); | ||||
| 	else | ||||
| 		light->conf.config &= ~BIT(1); | ||||
| 	light->flags |= C3DF_Light_Dirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightGeoFactor(C3D_Light* light, int id, bool enable) | ||||
| { | ||||
| 	id = 2 + (id&1); | ||||
| 	if (enable) | ||||
| 		light->conf.config |= BIT(id); | ||||
| 	else | ||||
| 		light->conf.config &= ~BIT(id); | ||||
| 	light->flags |= C3DF_Light_Dirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightColor(C3D_Light* light, float r, float g, float b) | ||||
| { | ||||
| 	light->color[0] = b; | ||||
| 	light->color[1] = g; | ||||
| 	light->color[2] = r; | ||||
| 	light->flags |= C3DF_Light_MatDirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightPosition(C3D_Light* light, C3D_FVec* pos) | ||||
| { | ||||
| 	// Enable/disable positional light depending on W coordinate
 | ||||
| 	light->conf.config &= ~BIT(0); | ||||
| 	light->conf.config |= (pos->w == 0.0); | ||||
| 	light->conf.position[0] = f32tof16(pos->x); | ||||
| 	light->conf.position[1] = f32tof16(pos->y); | ||||
| 	light->conf.position[2] = f32tof16(pos->z); | ||||
| 	light->flags |= C3DF_Light_Dirty; | ||||
| } | ||||
| 
 | ||||
| static void C3Di_EnableCommon(C3D_Light* light, bool enable, u32 bit) | ||||
| { | ||||
| 	C3D_LightEnv* env = light->parent; | ||||
| 	u32* var = &env->conf.config[1]; | ||||
| 
 | ||||
| 	if (enable == !(*var & bit)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!enable) | ||||
| 		*var |= bit; | ||||
| 	else | ||||
| 		*var &= ~bit; | ||||
| 
 | ||||
| 	env->flags |= C3DF_LightEnv_Dirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightShadowEnable(C3D_Light* light, bool enable) | ||||
| { | ||||
| 	C3Di_EnableCommon(light, enable, GPU_LC1_SHADOWBIT(light->id)); | ||||
| } | ||||
| 
 | ||||
| void C3D_LightSpotEnable(C3D_Light* light, bool enable) | ||||
| { | ||||
| 	C3Di_EnableCommon(light, enable, GPU_LC1_SPOTBIT(light->id)); | ||||
| } | ||||
| 
 | ||||
| static inline u16 floattofix2_11(float x) | ||||
| { | ||||
| 	return (u16)((s32)(x * (1U<<11)) & 0x1FFF); | ||||
| } | ||||
| 
 | ||||
| void C3D_LightSpotDir(C3D_Light* light, float x, float y, float z) | ||||
| { | ||||
| 	C3Di_EnableCommon(light, true, GPU_LC1_SPOTBIT(light->id)); | ||||
| 	C3D_FVec vec = FVec3_New(-x, -y, -z); | ||||
| 	vec = FVec3_Normalize(vec); | ||||
| 	light->conf.spotDir[0] = floattofix2_11(vec.x); | ||||
| 	light->conf.spotDir[1] = floattofix2_11(vec.y); | ||||
| 	light->conf.spotDir[2] = floattofix2_11(vec.z); | ||||
| 	light->flags |= C3DF_Light_Dirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightSpotLut(C3D_Light* light, C3D_LightLut* lut) | ||||
| { | ||||
| 	bool hasLut = lut != NULL; | ||||
| 	C3Di_EnableCommon(light, hasLut, GPU_LC1_SPOTBIT(light->id)); | ||||
| 	light->lut_SP = lut; | ||||
| 	if (hasLut) | ||||
| 		light->flags |= C3DF_Light_SPDirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightDistAttnEnable(C3D_Light* light, bool enable) | ||||
| { | ||||
| 	C3Di_EnableCommon(light, enable, GPU_LC1_ATTNBIT(light->id)); | ||||
| } | ||||
| 
 | ||||
| void C3D_LightDistAttn(C3D_Light* light, C3D_LightLutDA* lut) | ||||
| { | ||||
| 	bool hasLut = lut != NULL; | ||||
| 	C3Di_EnableCommon(light, hasLut, GPU_LC1_ATTNBIT(light->id)); | ||||
| 	if (!hasLut) return; | ||||
| 
 | ||||
| 	light->conf.distAttnBias  = f32tof20(lut->bias); | ||||
| 	light->conf.distAttnScale = f32tof20(lut->scale); | ||||
| 	light->lut_DA = &lut->lut; | ||||
| 	light->flags |= C3DF_Light_Dirty | C3DF_Light_DADirty; | ||||
| } | ||||
							
								
								
									
										270
									
								
								libs/citro3d/source/lightenv.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								libs/citro3d/source/lightenv.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,270 @@ | |||
| #include <string.h> | ||||
| #include "context.h" | ||||
| 
 | ||||
| static void C3Di_LightEnvMtlBlend(C3D_LightEnv* env) | ||||
| { | ||||
| 	int i; | ||||
| 	C3D_Material* mtl = &env->material; | ||||
| 	u32 color = 0; | ||||
| 	for (i = 0; i < 3; i ++) | ||||
| 	{ | ||||
| 		int v = 255*(mtl->emission[i] + mtl->ambient[i]*env->ambient[i]); | ||||
| 		if (v < 0) v = 0; | ||||
| 		else if (v > 255) v = 255; | ||||
| 		color |= v << (i*10); | ||||
| 	} | ||||
| 	env->conf.ambient = color; | ||||
| } | ||||
| 
 | ||||
| static void C3Di_LightLutUpload(u32 config, C3D_LightLut* lut) | ||||
| { | ||||
| 	int i; | ||||
| 	GPUCMD_AddWrite(GPUREG_LIGHTING_LUT_INDEX, config); | ||||
| 	for (i = 0; i < 256; i += 8) | ||||
| 		GPUCMD_AddWrites(GPUREG_LIGHTING_LUT_DATA0, &lut->data[i], 8); | ||||
| } | ||||
| 
 | ||||
| static void C3Di_LightEnvSelectLayer(C3D_LightEnv* env) | ||||
| { | ||||
| 	static const u8 layer_enabled[] = | ||||
| 	{ | ||||
| 		BIT(GPU_LUT_D0) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_SP) | BIT(GPU_LUT_DA), | ||||
| 		BIT(GPU_LUT_FR) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_SP) | BIT(GPU_LUT_DA), | ||||
| 		BIT(GPU_LUT_D0) | BIT(GPU_LUT_D1) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_DA), | ||||
| 		BIT(GPU_LUT_D0) | BIT(GPU_LUT_D1) | BIT(GPU_LUT_FR) | BIT(GPU_LUT_DA), | ||||
| 		0xFF &~ BIT(GPU_LUT_FR), | ||||
| 		0xFF &~ BIT(GPU_LUT_D1), | ||||
| 		0xFF &~ (BIT(GPU_LUT_RB) | BIT(GPU_LUT_RG)), | ||||
| 	}; | ||||
| 
 | ||||
| 	u32 reg = ~env->conf.config[1]; | ||||
| 	if (reg & (0xFF<< 8)) reg |= GPU_LC1_LUTBIT(GPU_LUT_SP); | ||||
| 	if (reg & (0xFF<<24)) reg |= GPU_LC1_LUTBIT(GPU_LUT_DA); | ||||
| 	reg = (reg >> 16) & 0xFF; | ||||
| 	int i; | ||||
| 	for (i = 0; i < 7; i ++) | ||||
| 		if ((layer_enabled[i] & reg) == reg) // Check if the layer supports all LUTs we need
 | ||||
| 			break; | ||||
| 	env->conf.config[0] = (env->conf.config[0] &~ (0xF<<4)) | (GPU_LIGHT_ENV_LAYER_CONFIG(i)<<4); | ||||
| } | ||||
| 
 | ||||
| static void C3Di_LightEnvUpdate(C3D_LightEnv* env) | ||||
| { | ||||
| 	int i; | ||||
| 	C3D_LightEnvConf* conf = &env->conf; | ||||
| 
 | ||||
| 	if (env->flags & C3DF_LightEnv_LCDirty) | ||||
| 	{ | ||||
| 		conf->numLights = 0; | ||||
| 		conf->permutation = 0; | ||||
| 		for (i = 0; i < 8; i ++) | ||||
| 		{ | ||||
| 			C3D_Light* light = env->lights[i]; | ||||
| 			if (!light) continue; | ||||
| 			if (!(light->flags & C3DF_Light_Enabled)) continue; | ||||
| 			conf->permutation |= GPU_LIGHTPERM(conf->numLights++, i); | ||||
| 		} | ||||
| 		if (conf->numLights > 0) conf->numLights --; | ||||
| 		env->flags &= ~C3DF_LightEnv_LCDirty; | ||||
| 		env->flags |= C3DF_LightEnv_Dirty; | ||||
| 	} | ||||
| 
 | ||||
| 	if (env->flags & C3DF_LightEnv_MtlDirty) | ||||
| 	{ | ||||
| 		C3Di_LightEnvMtlBlend(env); | ||||
| 		env->flags &= ~C3DF_LightEnv_MtlDirty; | ||||
| 		env->flags |= C3DF_LightEnv_Dirty; | ||||
| 	} | ||||
| 
 | ||||
| 	if (env->flags & C3DF_LightEnv_Dirty) | ||||
| 	{ | ||||
| 		C3Di_LightEnvSelectLayer(env); | ||||
| 		GPUCMD_AddWrite(GPUREG_LIGHTING_AMBIENT, conf->ambient); | ||||
| 		GPUCMD_AddIncrementalWrites(GPUREG_LIGHTING_NUM_LIGHTS, (u32*)&conf->numLights, 3); | ||||
| 		GPUCMD_AddIncrementalWrites(GPUREG_LIGHTING_LUTINPUT_ABS, (u32*)&conf->lutInput, 3); | ||||
| 		GPUCMD_AddWrite(GPUREG_LIGHTING_LIGHT_PERMUTATION, conf->permutation); | ||||
| 		env->flags &= ~C3DF_LightEnv_Dirty; | ||||
| 	} | ||||
| 
 | ||||
| 	if (env->flags & C3DF_LightEnv_LutDirtyAll) | ||||
| 	{ | ||||
| 		for (i = 0; i < 6; i ++) | ||||
| 		{ | ||||
| 			static const u8 lutIds[] = { 0, 1, 3, 4, 5, 6 }; | ||||
| 			if (!(env->flags & C3DF_LightEnv_LutDirty(i))) continue; | ||||
| 			C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_COMMON, (u32)lutIds[i], 0), env->luts[i]); | ||||
| 		} | ||||
| 
 | ||||
| 		env->flags &= ~C3DF_LightEnv_LutDirtyAll; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < 8; i ++) | ||||
| 	{ | ||||
| 		C3D_Light* light = env->lights[i]; | ||||
| 		if (!light) continue; | ||||
| 
 | ||||
| 		if (light->flags & C3DF_Light_MatDirty) | ||||
| 		{ | ||||
| 			C3Di_LightMtlBlend(light); | ||||
| 			light->flags &= ~C3DF_Light_MatDirty; | ||||
| 			light->flags |= C3DF_Light_Dirty; | ||||
| 		} | ||||
| 
 | ||||
| 		if (light->flags & C3DF_Light_Dirty) | ||||
| 		{ | ||||
| 			GPUCMD_AddIncrementalWrites(GPUREG_LIGHT0_SPECULAR0 + i*0x10, (u32*)&light->conf, 12); | ||||
| 			light->flags &= ~C3DF_Light_Dirty; | ||||
| 		} | ||||
| 
 | ||||
| 		if (light->flags & C3DF_Light_SPDirty) | ||||
| 		{ | ||||
| 			C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_SP, i, 0), light->lut_SP); | ||||
| 			light->flags &= ~C3DF_Light_SPDirty; | ||||
| 		} | ||||
| 
 | ||||
| 		if (light->flags & C3DF_Light_DADirty) | ||||
| 		{ | ||||
| 			C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_DA, i, 0), light->lut_DA); | ||||
| 			light->flags &= ~C3DF_Light_DADirty; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void C3Di_LightEnvDirty(C3D_LightEnv* env) | ||||
| { | ||||
| 	env->flags |= C3DF_LightEnv_Dirty; | ||||
| 	int i; | ||||
| 	for (i = 0; i < 6; i ++) | ||||
| 		if (env->luts[i]) | ||||
| 			env->flags |= C3DF_LightEnv_LutDirty(i); | ||||
| 	for (i = 0; i < 8; i ++) | ||||
| 	{ | ||||
| 		C3D_Light* light = env->lights[i]; | ||||
| 		if (!light) continue; | ||||
| 
 | ||||
| 		light->flags |= C3DF_Light_Dirty; | ||||
| 		if (light->lut_SP) | ||||
| 			light->flags |= C3DF_Light_SPDirty; | ||||
| 		if (light->lut_DA) | ||||
| 			light->flags |= C3DF_Light_DADirty; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvInit(C3D_LightEnv* env) | ||||
| { | ||||
| 	memset(env, 0, sizeof(*env)); | ||||
| 	env->Update = C3Di_LightEnvUpdate; | ||||
| 	env->Dirty = C3Di_LightEnvDirty; | ||||
| 
 | ||||
| 	env->flags = C3DF_LightEnv_Dirty; | ||||
| 	env->conf.config[0] = (4<<8) | BIT(27) | BIT(31); | ||||
| 	env->conf.config[1] = ~0; | ||||
| 	env->conf.lutInput.abs = 0x2222222; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvBind(C3D_LightEnv* env) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (ctx->lightEnv == env) | ||||
| 		return; | ||||
| 
 | ||||
| 	ctx->flags |= C3DiF_LightEnv; | ||||
| 	ctx->lightEnv = env; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvMaterial(C3D_LightEnv* env, const C3D_Material* mtl) | ||||
| { | ||||
| 	int i; | ||||
| 	memcpy(&env->material, mtl, sizeof(*mtl)); | ||||
| 	env->flags |= C3DF_LightEnv_MtlDirty; | ||||
| 	for (i = 0; i < 8; i ++) | ||||
| 	{ | ||||
| 		C3D_Light* light = env->lights[i]; | ||||
| 		if (light) light->flags |= C3DF_Light_MatDirty; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvAmbient(C3D_LightEnv* env, float r, float g, float b) | ||||
| { | ||||
| 	env->ambient[0] = b; | ||||
| 	env->ambient[1] = g; | ||||
| 	env->ambient[2] = r; | ||||
| 	env->flags |= C3DF_LightEnv_MtlDirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvLut(C3D_LightEnv* env, int lutId, int input, bool abs, C3D_LightLut* lut) | ||||
| { | ||||
| 	static const s8 ids[] = { 0, 1, -1, 2, 3, 4, 5, -1 }; | ||||
| 	int id = ids[lutId]; | ||||
| 	if (id >= 0) | ||||
| 	{ | ||||
| 		env->luts[id] = lut; | ||||
| 		if (lut) | ||||
| 		{ | ||||
| 			env->conf.config[1] &= ~GPU_LC1_LUTBIT(lutId); | ||||
| 			env->flags |= C3DF_LightEnv_LutDirty(id); | ||||
| 		} else | ||||
| 			env->luts[id] = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	env->conf.lutInput.select &= ~GPU_LIGHTLUTINPUT(lutId, 0xF); | ||||
| 	env->conf.lutInput.select |=  GPU_LIGHTLUTINPUT(lutId, input); | ||||
| 
 | ||||
| 	u32 absbit = 1 << (lutId*4 + 1); | ||||
| 	env->conf.lutInput.abs &= ~absbit; | ||||
| 	if (!abs) | ||||
| 		env->conf.lutInput.abs |= absbit; | ||||
| 
 | ||||
| 	env->flags |= C3DF_LightEnv_Dirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvFresnel(C3D_LightEnv* env, GPU_FRESNELSEL selector) | ||||
| { | ||||
| 	env->conf.config[0] &= ~(3<<2); | ||||
| 	env->conf.config[0] |= (selector&3)<<2; | ||||
| 	env->flags |= C3DF_LightEnv_Dirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvBumpMode(C3D_LightEnv* env, GPU_BUMPMODE mode) | ||||
| { | ||||
| 	env->conf.config[0] &= ~(3<<28); | ||||
| 	env->conf.config[0] |= (mode&3)<<28; | ||||
| 	env->flags |= C3DF_LightEnv_Dirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvBumpSel(C3D_LightEnv* env, int texUnit) | ||||
| { | ||||
| 	env->conf.config[0] &= ~(3<<22); | ||||
| 	env->conf.config[0] |= (texUnit&3)<<22; | ||||
| 	env->flags |= C3DF_LightEnv_Dirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvShadowMode(C3D_LightEnv* env, u32 mode) | ||||
| { | ||||
| 	mode &= 0xF<<16; | ||||
| 	if (mode & (GPU_SHADOW_PRIMARY | GPU_INVERT_SHADOW | GPU_SHADOW_ALPHA)) | ||||
| 		mode |= BIT(0); | ||||
| 	env->conf.config[0] &= ~((3<<28) | BIT(0)); | ||||
| 	env->conf.config[0] |= mode; | ||||
| 	env->flags |= C3DF_LightEnv_Dirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvShadowSel(C3D_LightEnv* env, int texUnit) | ||||
| { | ||||
| 	env->conf.config[0] &= ~(3<<24); | ||||
| 	env->conf.config[0] |= (texUnit&3)<<24; | ||||
| 	env->flags |= C3DF_LightEnv_Dirty; | ||||
| } | ||||
| 
 | ||||
| void C3D_LightEnvClampHighlights(C3D_LightEnv* env, bool clamp) | ||||
| { | ||||
| 	if (clamp) | ||||
| 		env->conf.config[0] |= BIT(27); | ||||
| 	else | ||||
| 		env->conf.config[0] &= ~BIT(27); | ||||
| 	env->flags |= C3DF_LightEnv_Dirty; | ||||
| } | ||||
							
								
								
									
										66
									
								
								libs/citro3d/source/lightlut.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								libs/citro3d/source/lightlut.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | |||
| #include <string.h> | ||||
| #include "context.h" | ||||
| 
 | ||||
| void LightLut_FromArray(C3D_LightLut* lut, float* data) | ||||
| { | ||||
| 	int i; | ||||
| 	for (i = 0; i < 256; i ++) | ||||
| 	{ | ||||
| 		float in = data[i], diff = data[i+256]; | ||||
| 
 | ||||
| 		u32 val = 0; | ||||
| 		if (in > 0.0) | ||||
| 		{ | ||||
| 			in *= 0x1000; | ||||
| 			val = (in < 0x1000) ? (u32)in : 0xFFF; | ||||
| 		} | ||||
| 
 | ||||
| 		u32 val2 = 0; | ||||
| 		if (diff != 0.0) | ||||
| 		{ | ||||
| 			if (diff < 0) | ||||
| 			{ | ||||
| 				diff = -diff; | ||||
| 				val2 = 0x800; | ||||
| 			} | ||||
| 			diff *= 0x800; | ||||
| 			val2 |= (diff < 0x800) ? (u32)diff : 0x7FF; | ||||
| 		} | ||||
| 
 | ||||
| 		lut->data[i] = val | (val2 << 12); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void LightLut_FromFunc(C3D_LightLut* lut, C3D_LightLutFunc func, float param, bool negative) | ||||
| { | ||||
| 	int i; | ||||
| 	float data[512]; | ||||
| 	memset(data, 0, sizeof(data)); | ||||
| 	int start = negative ? (-127) : 0; | ||||
| 	for (i = start; i < 128; i ++) | ||||
| 	{ | ||||
| 		data[i & 0xFF] = func((float)i / 127.0f, param); | ||||
| 		if (i != start) data[(i & 0xFF) + 255] = data[i & 0xFF] - data[(i-1) & 0xFF]; | ||||
| 	} | ||||
| 	LightLut_FromArray(lut, data); | ||||
| } | ||||
| 
 | ||||
| void LightLutDA_Create(C3D_LightLutDA* lut, C3D_LightLutFuncDA func, float from, float to, float arg0, float arg1) | ||||
| { | ||||
| 	int i; | ||||
| 	float data[512]; | ||||
| 	data[511] = 0; | ||||
| 
 | ||||
| 	lut->scale = 1.0f / (to-from); | ||||
| 	lut->bias = -from*lut->scale; | ||||
| 
 | ||||
| 	for (i = 0; i < 256; i ++) | ||||
| 	{ | ||||
| 		float dist = ((float)i/255 - lut->bias) / lut->scale; | ||||
| 		data[i] = func(dist, arg0, arg1); | ||||
| 		if (i > 0) | ||||
| 			data[i+255] = data[i]-data[i-1]; | ||||
| 	} | ||||
| 
 | ||||
| 	LightLut_FromArray(&lut->lut, data); | ||||
| } | ||||
							
								
								
									
										2
									
								
								libs/citro3d/source/maths/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								libs/citro3d/source/maths/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| *.d | ||||
| *.o | ||||
							
								
								
									
										34
									
								
								libs/citro3d/source/maths/mtx_fromquat.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								libs/citro3d/source/maths/mtx_fromquat.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_FromQuat(C3D_Mtx* m, C3D_FQuat q) | ||||
| { | ||||
| 	float ii = q.i*q.i; | ||||
| 	float ij = q.i*q.j; | ||||
| 	float ik = q.i*q.k; | ||||
| 	float jj = q.j*q.j; | ||||
| 	float jk = q.j*q.k; | ||||
| 	float kk = q.k*q.k; | ||||
| 	float ri = q.r*q.i; | ||||
| 	float rj = q.r*q.j; | ||||
| 	float rk = q.r*q.k; | ||||
| 
 | ||||
| 	m->r[0].x = 1.0f - (2.0f * (jj + kk)); | ||||
| 	m->r[1].x = 2.0f * (ij + rk); | ||||
| 	m->r[2].x = 2.0f * (ik - rj); | ||||
| 	m->r[3].x = 0.0f; | ||||
| 
 | ||||
| 	m->r[0].y = 2.0f * (ij - rk); | ||||
| 	m->r[1].y = 1.0f - (2.0f * (ii + kk)); | ||||
| 	m->r[2].y = 2.0f * (jk + ri); | ||||
| 	m->r[3].y = 0.0f; | ||||
| 
 | ||||
| 	m->r[0].z = 2.0f * (ik + rj); | ||||
| 	m->r[1].z = 2.0f * (jk - ri); | ||||
| 	m->r[2].z = 1.0f - (2.0f * (ii + jj)); | ||||
| 	m->r[3].z = 0.0f; | ||||
| 
 | ||||
| 	m->r[0].w = 0.0f; | ||||
| 	m->r[1].w = 0.0f; | ||||
| 	m->r[2].w = 0.0f; | ||||
| 	m->r[3].w = 1.0f; | ||||
| } | ||||
							
								
								
									
										10
									
								
								libs/citro3d/source/maths/mtx_identity.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								libs/citro3d/source/maths/mtx_identity.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_Identity(C3D_Mtx* out) | ||||
| { | ||||
| 	// http://www.wolframalpha.com/input/?i={{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}
 | ||||
| 	int i; | ||||
| 	for (i = 0; i < 16; ++i) | ||||
| 		out->m[i] = 0.0f; | ||||
| 	out->r[0].x = out->r[1].y = out->r[2].z = out->r[3].w = 1.0f; | ||||
| } | ||||
							
								
								
									
										135
									
								
								libs/citro3d/source/maths/mtx_inverse.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								libs/citro3d/source/maths/mtx_inverse.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,135 @@ | |||
| #include <float.h> | ||||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| float Mtx_Inverse(C3D_Mtx* out) | ||||
| { | ||||
| 	//Mtx_Inverse can be used to calculate the determinant and the inverse of the matrix.
 | ||||
| 
 | ||||
| 	C3D_Mtx inv; | ||||
| 	float   det; | ||||
| 	int     i; | ||||
| 
 | ||||
| 	inv.r[0].x =  out->r[1].y * out->r[2].z * out->r[3].w - | ||||
| 	              out->r[1].y * out->r[2].w * out->r[3].z - | ||||
| 	              out->r[2].y * out->r[1].z * out->r[3].w + | ||||
| 	              out->r[2].y * out->r[1].w * out->r[3].z + | ||||
| 	              out->r[3].y * out->r[1].z * out->r[2].w - | ||||
| 	              out->r[3].y * out->r[1].w * out->r[2].z; | ||||
| 
 | ||||
| 	inv.r[1].x = -out->r[1].x * out->r[2].z * out->r[3].w + | ||||
| 	              out->r[1].x * out->r[2].w * out->r[3].z + | ||||
| 	              out->r[2].x * out->r[1].z * out->r[3].w - | ||||
| 	              out->r[2].x * out->r[1].w * out->r[3].z - | ||||
| 	              out->r[3].x * out->r[1].z * out->r[2].w + | ||||
| 	              out->r[3].x * out->r[1].w * out->r[2].z; | ||||
| 
 | ||||
| 	inv.r[2].x =  out->r[1].x * out->r[2].y * out->r[3].w - | ||||
| 	              out->r[1].x * out->r[2].w * out->r[3].y - | ||||
| 	              out->r[2].x * out->r[1].y * out->r[3].w + | ||||
| 	              out->r[2].x * out->r[1].w * out->r[3].y + | ||||
| 	              out->r[3].x * out->r[1].y * out->r[2].w - | ||||
| 	              out->r[3].x * out->r[1].w * out->r[2].y; | ||||
| 
 | ||||
| 	inv.r[3].x = -out->r[1].x * out->r[2].y * out->r[3].z + | ||||
| 	              out->r[1].x * out->r[2].z * out->r[3].y + | ||||
| 	              out->r[2].x * out->r[1].y * out->r[3].z - | ||||
| 	              out->r[2].x * out->r[1].z * out->r[3].y - | ||||
| 	              out->r[3].x * out->r[1].y * out->r[2].z + | ||||
| 	              out->r[3].x * out->r[1].z * out->r[2].y; | ||||
| 
 | ||||
| 	det = out->r[0].x * inv.r[0].x + out->r[0].y * inv.r[1].x + | ||||
| 	      out->r[0].z * inv.r[2].x + out->r[0].w * inv.r[3].x; | ||||
| 
 | ||||
| 	if (fabsf(det) < FLT_EPSILON) | ||||
| 		//Returns 0.0f if we find the determinant is less than +/- FLT_EPSILON.
 | ||||
| 		return 0.0f; | ||||
| 
 | ||||
| 	inv.r[0].y = -out->r[0].y * out->r[2].z * out->r[3].w + | ||||
| 	              out->r[0].y * out->r[2].w * out->r[3].z + | ||||
| 	              out->r[2].y * out->r[0].z * out->r[3].w - | ||||
| 	              out->r[2].y * out->r[0].w * out->r[3].z - | ||||
| 	              out->r[3].y * out->r[0].z * out->r[2].w + | ||||
| 	              out->r[3].y * out->r[0].w * out->r[2].z; | ||||
| 
 | ||||
| 	inv.r[1].y =  out->r[0].x * out->r[2].z * out->r[3].w - | ||||
| 	              out->r[0].x * out->r[2].w * out->r[3].z - | ||||
| 	              out->r[2].x * out->r[0].z * out->r[3].w + | ||||
| 	              out->r[2].x * out->r[0].w * out->r[3].z + | ||||
| 	              out->r[3].x * out->r[0].z * out->r[2].w - | ||||
| 	              out->r[3].x * out->r[0].w * out->r[2].z; | ||||
| 
 | ||||
| 	inv.r[2].y = -out->r[0].x * out->r[2].y * out->r[3].w + | ||||
| 	              out->r[0].x * out->r[2].w * out->r[3].y + | ||||
| 	              out->r[2].x * out->r[0].y * out->r[3].w - | ||||
| 	              out->r[2].x * out->r[0].w * out->r[3].y - | ||||
| 	              out->r[3].x * out->r[0].y * out->r[2].w + | ||||
| 	              out->r[3].x * out->r[0].w * out->r[2].y; | ||||
| 
 | ||||
| 	inv.r[3].y =  out->r[0].x * out->r[2].y * out->r[3].z - | ||||
| 	              out->r[0].x * out->r[2].z * out->r[3].y - | ||||
| 	              out->r[2].x * out->r[0].y * out->r[3].z + | ||||
| 	              out->r[2].x * out->r[0].z * out->r[3].y + | ||||
| 	              out->r[3].x * out->r[0].y * out->r[2].z - | ||||
| 	              out->r[3].x * out->r[0].z * out->r[2].y; | ||||
| 
 | ||||
| 	inv.r[0].z =  out->r[0].y * out->r[1].z * out->r[3].w - | ||||
| 	              out->r[0].y * out->r[1].w * out->r[3].z - | ||||
| 	              out->r[1].y * out->r[0].z * out->r[3].w + | ||||
| 	              out->r[1].y * out->r[0].w * out->r[3].z + | ||||
| 	              out->r[3].y * out->r[0].z * out->r[1].w - | ||||
| 	              out->r[3].y * out->r[0].w * out->r[1].z; | ||||
| 
 | ||||
| 	inv.r[1].z = -out->r[0].x * out->r[1].z * out->r[3].w + | ||||
| 	              out->r[0].x * out->r[1].w * out->r[3].z + | ||||
| 	              out->r[1].x * out->r[0].z * out->r[3].w - | ||||
| 	              out->r[1].x * out->r[0].w * out->r[3].z - | ||||
| 	              out->r[3].x * out->r[0].z * out->r[1].w + | ||||
| 	              out->r[3].x * out->r[0].w * out->r[1].z; | ||||
| 
 | ||||
| 	inv.r[2].z =  out->r[0].x * out->r[1].y * out->r[3].w - | ||||
| 	              out->r[0].x * out->r[1].w * out->r[3].y - | ||||
| 	              out->r[1].x * out->r[0].y * out->r[3].w + | ||||
| 	              out->r[1].x * out->r[0].w * out->r[3].y + | ||||
| 	              out->r[3].x * out->r[0].y * out->r[1].w - | ||||
| 	              out->r[3].x * out->r[0].w * out->r[1].y; | ||||
| 
 | ||||
| 	inv.r[3].z = -out->r[0].x * out->r[1].y * out->r[3].z + | ||||
| 	              out->r[0].x * out->r[1].z * out->r[3].y + | ||||
| 	              out->r[1].x * out->r[0].y * out->r[3].z - | ||||
| 	              out->r[1].x * out->r[0].z * out->r[3].y - | ||||
| 	              out->r[3].x * out->r[0].y * out->r[1].z + | ||||
| 	              out->r[3].x * out->r[0].z * out->r[1].y; | ||||
| 
 | ||||
| 	inv.r[0].w = -out->r[0].y * out->r[1].z * out->r[2].w + | ||||
| 	              out->r[0].y * out->r[1].w * out->r[2].z + | ||||
| 	              out->r[1].y * out->r[0].z * out->r[2].w - | ||||
| 	              out->r[1].y * out->r[0].w * out->r[2].z - | ||||
| 	              out->r[2].y * out->r[0].z * out->r[1].w + | ||||
| 	              out->r[2].y * out->r[0].w * out->r[1].z; | ||||
| 
 | ||||
| 	inv.r[1].w =  out->r[0].x * out->r[1].z * out->r[2].w - | ||||
| 	              out->r[0].x * out->r[1].w * out->r[2].z - | ||||
| 	              out->r[1].x * out->r[0].z * out->r[2].w + | ||||
| 	              out->r[1].x * out->r[0].w * out->r[2].z + | ||||
| 	              out->r[2].x * out->r[0].z * out->r[1].w - | ||||
| 	              out->r[2].x * out->r[0].w * out->r[1].z; | ||||
| 
 | ||||
| 	inv.r[2].w = -out->r[0].x * out->r[1].y * out->r[2].w + | ||||
| 	              out->r[0].x * out->r[1].w * out->r[2].y + | ||||
| 	              out->r[1].x * out->r[0].y * out->r[2].w - | ||||
| 	              out->r[1].x * out->r[0].w * out->r[2].y - | ||||
| 	              out->r[2].x * out->r[0].y * out->r[1].w + | ||||
| 	              out->r[2].x * out->r[0].w * out->r[1].y; | ||||
| 
 | ||||
| 	inv.r[3].w =  out->r[0].x * out->r[1].y * out->r[2].z - | ||||
| 	              out->r[0].x * out->r[1].z * out->r[2].y - | ||||
| 	              out->r[1].x * out->r[0].y * out->r[2].z + | ||||
| 	              out->r[1].x * out->r[0].z * out->r[2].y + | ||||
| 	              out->r[2].x * out->r[0].y * out->r[1].z - | ||||
| 	              out->r[2].x * out->r[0].z * out->r[1].y; | ||||
| 
 | ||||
| 	for (i = 0; i < 16; i++) | ||||
| 		out->m[i] = inv.m[i] / det; | ||||
| 
 | ||||
| 	return det; | ||||
| } | ||||
							
								
								
									
										37
									
								
								libs/citro3d/source/maths/mtx_lookat.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								libs/citro3d/source/maths/mtx_lookat.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_LookAt(C3D_Mtx* out, C3D_FVec cameraPosition, C3D_FVec cameraTarget, C3D_FVec cameraUpVector, bool isLeftHanded) | ||||
| { | ||||
| 	//Left-handed and Right-handed Look-At matrix functions are DirectX implementations.
 | ||||
| 	//Left-handed: https://msdn.microsoft.com/en-us/library/windows/desktop/bb281710
 | ||||
| 	//Right-handed: https://msdn.microsoft.com/en-us/library/windows/desktop/bb281711
 | ||||
| 	C3D_FVec xaxis, yaxis, zaxis; | ||||
| 	 | ||||
| 	//Order of operations is crucial.
 | ||||
| 	if (isLeftHanded) | ||||
| 		zaxis = FVec3_Normalize(FVec3_Subtract(cameraTarget, cameraPosition)); | ||||
| 	else | ||||
| 		zaxis = FVec3_Normalize(FVec3_Subtract(cameraPosition, cameraTarget)); | ||||
| 	xaxis = FVec3_Normalize(FVec3_Cross(cameraUpVector, zaxis)); | ||||
| 	yaxis = FVec3_Cross(zaxis, xaxis); | ||||
| 	 | ||||
| 	out->r[0].x = xaxis.x; | ||||
| 	out->r[0].y = xaxis.y; | ||||
| 	out->r[0].z = xaxis.z; | ||||
| 	out->r[0].w = -FVec3_Dot(xaxis, cameraPosition); | ||||
| 
 | ||||
| 	out->r[1].x = yaxis.x; | ||||
| 	out->r[1].y = yaxis.y; | ||||
| 	out->r[1].z = yaxis.z; | ||||
| 	out->r[1].w = -FVec3_Dot(yaxis, cameraPosition); | ||||
| 
 | ||||
| 	out->r[2].x = zaxis.x; | ||||
| 	out->r[2].y = zaxis.y; | ||||
| 	out->r[2].z = zaxis.z; | ||||
| 	out->r[2].w = -FVec3_Dot(zaxis, cameraPosition); | ||||
| 
 | ||||
| 	out->r[3].x = 0.0f; | ||||
| 	out->r[3].y = 0.0f; | ||||
| 	out->r[3].z = 0.0f; | ||||
| 	out->r[3].w = 1.0f; | ||||
| } | ||||
							
								
								
									
										19
									
								
								libs/citro3d/source/maths/mtx_multiply.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								libs/citro3d/source/maths/mtx_multiply.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_Multiply(C3D_Mtx* out, const C3D_Mtx* a, const C3D_Mtx* b) | ||||
| { | ||||
| 	// if out is a or b, then we need to avoid overwriting them
 | ||||
| 	if(out == a || out == b) | ||||
| 	{ | ||||
| 		C3D_Mtx tmp; | ||||
| 		Mtx_Multiply(&tmp, a, b); | ||||
| 		Mtx_Copy(out, &tmp); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	// http://www.wolframalpha.com/input/?i={{a,b,c,d},{e,f,g,h},{i,j,k,l},{m,n,o,p}}{{α,β,γ,δ},{ε,θ,ι,κ},{λ,μ,ν,ξ},{ο,π,ρ,σ}}
 | ||||
| 	int i, j; | ||||
| 	for (j = 0; j < 4; ++j) | ||||
| 		for (i = 0; i < 4; ++i) | ||||
| 			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]; | ||||
| } | ||||
							
								
								
									
										11
									
								
								libs/citro3d/source/maths/mtx_multiplyfvec3.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								libs/citro3d/source/maths/mtx_multiplyfvec3.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| C3D_FVec Mtx_MultiplyFVec3(const C3D_Mtx* mtx, C3D_FVec v) | ||||
| { | ||||
| 	// http://www.wolframalpha.com/input/?i={{a,b,c},{d,e,f},{g,h,i}}{x,y,z}
 | ||||
| 	float x = FVec3_Dot(mtx->r[0], v); | ||||
| 	float y = FVec3_Dot(mtx->r[1], v); | ||||
| 	float z = FVec3_Dot(mtx->r[2], v); | ||||
| 
 | ||||
| 	return FVec3_New(x, y, z); | ||||
| } | ||||
							
								
								
									
										12
									
								
								libs/citro3d/source/maths/mtx_multiplyfvec4.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								libs/citro3d/source/maths/mtx_multiplyfvec4.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| C3D_FVec Mtx_MultiplyFVec4(const C3D_Mtx* mtx, C3D_FVec v) | ||||
| { | ||||
| 	// http://www.wolframalpha.com/input/?i={{a,b,c,d},{e,f,g,h},{i,j,k,l},{m,n,o,p}}{x,y,z,w}
 | ||||
| 	float x = FVec4_Dot(mtx->r[0], v); | ||||
| 	float y = FVec4_Dot(mtx->r[1], v); | ||||
| 	float z = FVec4_Dot(mtx->r[2], v); | ||||
| 	float w = FVec4_Dot(mtx->r[3], v); | ||||
| 
 | ||||
| 	return FVec4_New(x, y, z, w); | ||||
| } | ||||
							
								
								
									
										20
									
								
								libs/citro3d/source/maths/mtx_ortho.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								libs/citro3d/source/maths/mtx_ortho.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_Ortho(C3D_Mtx* mtx, float left, float right, float bottom, float top, float near, float far, bool isLeftHanded) | ||||
| { | ||||
| 	Mtx_Zeros(mtx); | ||||
| 
 | ||||
| 	// Standard orthogonal projection matrix, with a fixed depth range of [-1,0] (required by PICA)
 | ||||
| 	// http://www.wolframalpha.com/input/?i={{1,0,0,0},{0,1,0,0},{0,0,0.5,-0.5},{0,0,0,1}}{{2/(r-l),0,0,(l%2Br)/(l-r)},{0,2/(t-b),0,(b%2Bt)/(b-t)},{0,0,2/(n-f),(n%2Bf)/(n-f)},{0,0,0,1}}
 | ||||
| 
 | ||||
| 	mtx->r[0].x = 2.0f / (right - left); | ||||
| 	mtx->r[0].w = (left + right) / (left - right); | ||||
| 	mtx->r[1].y = 2.0f / (top - bottom); | ||||
| 	mtx->r[1].w = (bottom + top) / (bottom - top); | ||||
| 	if (isLeftHanded) | ||||
| 		mtx->r[2].z = 1.0f / (far - near); | ||||
| 	else | ||||
| 		mtx->r[2].z = 1.0f / (near - far); | ||||
| 	mtx->r[2].w = 0.5f*(near + far) / (near - far) - 0.5f; | ||||
| 	mtx->r[3].w = 1.0f; | ||||
| } | ||||
							
								
								
									
										21
									
								
								libs/citro3d/source/maths/mtx_orthotilt.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								libs/citro3d/source/maths/mtx_orthotilt.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_OrthoTilt(C3D_Mtx* mtx, float left, float right, float bottom, float top, float near, float far, bool isLeftHanded) | ||||
| { | ||||
| 	Mtx_Zeros(mtx); | ||||
| 
 | ||||
| 	// Standard orthogonal projection matrix, with a fixed depth range of [-1,0] (required by PICA) and rotated τ/4 radians counterclockwise around the Z axis (due to 3DS screen orientation)
 | ||||
| 	// http://www.wolframalpha.com/input/?i={{0,1,0,0},{-1,0,0,0},{0,0,1,0},{0,0,0,1}}{{1,0,0,0},{0,1,0,0},{0,0,0.5,-0.5},{0,0,0,1}}
 | ||||
| 	// http://www.wolframalpha.com/input/?i={{0,1,0,0},{-1,0,0,0},{0,0,0.5,-0.5},{0,0,0,1}}{{2/(r-l),0,0,(l%2Br)/(l-r)},{0,2/(t-b),0,(b%2Bt)/(b-t)},{0,0,2/(n-f),(n%2Bf)/(n-f)},{0,0,0,1}}
 | ||||
| 
 | ||||
| 	mtx->r[0].y = 2.0f / (top - bottom); | ||||
| 	mtx->r[0].w = (bottom + top) / (bottom - top); | ||||
| 	mtx->r[1].x = 2.0f / (left - right); | ||||
| 	mtx->r[1].w = (left + right) / (right - left); | ||||
| 	if (isLeftHanded) | ||||
| 		mtx->r[2].z = 1.0f / (far - near); | ||||
| 	else | ||||
| 		mtx->r[2].z = 1.0f / (near - far); | ||||
| 	mtx->r[2].w = 0.5f*(near + far) / (near - far) - 0.5f; | ||||
| 	mtx->r[3].w = 1.0f; | ||||
| } | ||||
							
								
								
									
										26
									
								
								libs/citro3d/source/maths/mtx_persp.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								libs/citro3d/source/maths/mtx_persp.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_Persp(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, bool isLeftHanded) | ||||
| { | ||||
| 	float fovy_tan = tanf(fovy/2.0f); | ||||
| 
 | ||||
| 	Mtx_Zeros(mtx); | ||||
| 
 | ||||
| 	// Standard perspective projection matrix, with a fixed depth range of [-1,0] (required by PICA)
 | ||||
| 	// http://www.wolframalpha.com/input/?i={{1,0,0,0},{0,1,0,0},{0,0,0.5,-0.5},{0,0,0,1}}{{1/(a*tan(v)),0,0,0},{0,1/tan(v),0,0},{0,0,(n%2Bf)/(n-f),(fn)/(n-f)},{0,0,0,-1}}
 | ||||
| 
 | ||||
| 	mtx->r[0].x = 1.0f / (aspect * fovy_tan); | ||||
| 	mtx->r[1].y = 1.0f / fovy_tan; | ||||
| 	mtx->r[2].w = far*near / (near - far); | ||||
| 
 | ||||
| 	if (isLeftHanded) | ||||
| 	{ | ||||
| 		mtx->r[2].z = 0.5f*(far + near) / (far - near) - 0.5f; | ||||
| 		mtx->r[3].z = 1.0f; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		mtx->r[2].z = 0.5f*(far + near) / (near - far) + 0.5f; | ||||
| 		mtx->r[3].z = -1.0f; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										28
									
								
								libs/citro3d/source/maths/mtx_perspstereo.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								libs/citro3d/source/maths/mtx_perspstereo.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_PerspStereo(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, float iod, float screen, bool isLeftHanded) | ||||
| { | ||||
| 	float fovy_tan = tanf(fovy/2.0f); | ||||
| 	float fovy_tan_aspect = fovy_tan*aspect; | ||||
| 	float shift = iod / (2.0f*screen); // 'near' not in the numerator because it cancels out in mp.r[1].z
 | ||||
| 
 | ||||
| 	Mtx_Zeros(mtx); | ||||
| 
 | ||||
| 	mtx->r[0].x = 1.0f / fovy_tan_aspect; | ||||
| 	mtx->r[0].w = -iod / 2.0f; | ||||
| 	mtx->r[1].y = 1.0f / fovy_tan; | ||||
| 	mtx->r[2].w = near * far / (near - far); | ||||
| 
 | ||||
| 	if (isLeftHanded) | ||||
| 	{ | ||||
| 		mtx->r[0].z = shift / fovy_tan_aspect; | ||||
| 		mtx->r[2].z = 0.5f*(near + far) / (far - near) - 0.5f; | ||||
| 		mtx->r[3].z = 1.0f; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		mtx->r[0].z = -shift / fovy_tan_aspect; | ||||
| 		mtx->r[2].z = 0.5f*(near + far) / (near - far) + 0.5f; | ||||
| 		mtx->r[3].z = -1.0f; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										33
									
								
								libs/citro3d/source/maths/mtx_perspstereotilt.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								libs/citro3d/source/maths/mtx_perspstereotilt.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_PerspStereoTilt(C3D_Mtx* mtx, float fovx, float invaspect, float near, float far, float iod, float screen, bool isLeftHanded) | ||||
| { | ||||
| 	// Notes:
 | ||||
| 	// Once again, we are passed "fovy" and the "aspect ratio"; however the 3DS screens are sideways,
 | ||||
| 	// and the formula had to be tweaked. With stereo, left/right separation becomes top/bottom separation.
 | ||||
| 	// The detailed mathematical explanation is in mtx_persptilt.c.
 | ||||
| 
 | ||||
| 	float fovx_tan = tanf(fovx/2.0f); | ||||
| 	float fovx_tan_invaspect = fovx_tan*invaspect; | ||||
| 	float shift = iod / (2.0f*screen); // 'near' not in the numerator because it cancels out in mp.r[1].z
 | ||||
| 
 | ||||
| 	Mtx_Zeros(mtx); | ||||
| 
 | ||||
| 	mtx->r[0].y = 1.0f / fovx_tan; | ||||
| 	mtx->r[1].x = -1.0f / fovx_tan_invaspect; | ||||
| 	mtx->r[1].w = iod / 2.0f; | ||||
| 	mtx->r[2].w = near * far / (near - far); | ||||
| 
 | ||||
| 	if (isLeftHanded) | ||||
| 	{ | ||||
| 		mtx->r[1].z = -shift / fovx_tan_invaspect; | ||||
| 		mtx->r[2].z = 0.5f*(near + far) / (far - near) - 0.5f; | ||||
| 		mtx->r[3].z = 1.0f; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		mtx->r[1].z = shift / fovx_tan_invaspect; | ||||
| 		mtx->r[2].z = 0.5f*(near + far) / (near - far) + 0.5f; | ||||
| 		mtx->r[3].z = -1.0f; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										46
									
								
								libs/citro3d/source/maths/mtx_persptilt.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								libs/citro3d/source/maths/mtx_persptilt.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_PerspTilt(C3D_Mtx* mtx, float fovx, float invaspect, float near, float far, bool isLeftHanded) | ||||
| { | ||||
| 	// 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:
 | ||||
| 	// Includes adjusting depth range from [-1,1] to [-1,0]
 | ||||
| 	// Includes rotation of the matrix one quarter of a turn clockwise in order to fix the 3DS screens' orientation
 | ||||
| 
 | ||||
| 	// 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.0f); | ||||
| 
 | ||||
| 	Mtx_Zeros(mtx); | ||||
| 
 | ||||
| 	mtx->r[0].y = 1.0f / fovx_tan; | ||||
| 	mtx->r[1].x = -1.0f / (fovx_tan*invaspect); | ||||
| 	mtx->r[2].w = far*near / (near - far); | ||||
| 
 | ||||
| 	if (isLeftHanded) | ||||
| 	{ | ||||
| 		mtx->r[2].z = 0.5f*(far + near) / (far - near) - 0.5f; | ||||
| 		mtx->r[3].z = 1.0f; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		mtx->r[2].z = 0.5f*(far + near) / (near - far) + 0.5f; | ||||
| 		mtx->r[3].z = -1.0f; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										72
									
								
								libs/citro3d/source/maths/mtx_rotate.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								libs/citro3d/source/maths/mtx_rotate.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_Rotate(C3D_Mtx* mtx, C3D_FVec axis, float angle, bool bRightSide) | ||||
| { | ||||
| 	size_t  i; | ||||
| 	C3D_Mtx om; | ||||
| 
 | ||||
| 	float s = sinf(angle); | ||||
| 	float c = cosf(angle); | ||||
| 	float t = 1.0f - c; | ||||
| 
 | ||||
| 	axis = FVec3_Normalize(axis); | ||||
| 
 | ||||
| 	float x = axis.x; | ||||
| 	float y = axis.y; | ||||
| 	float z = axis.z; | ||||
| 	float w; | ||||
| 
 | ||||
| 	om.r[0].x = t*x*x + c; | ||||
| 	om.r[1].x = t*x*y + s*z; | ||||
| 	om.r[2].x = t*x*z - s*y; | ||||
| 	//om.r[3].x = 0.0f; //optimized out
 | ||||
| 
 | ||||
| 	om.r[0].y = t*y*x - s*z; | ||||
| 	om.r[1].y = t*y*y + c; | ||||
| 	om.r[2].y = t*y*z + s*x; | ||||
| 	//om.r[3].y = 0.0f; //optimized out
 | ||||
| 
 | ||||
| 	om.r[0].z = t*z*x + s*y; | ||||
| 	om.r[1].z = t*z*y - s*x; | ||||
| 	om.r[2].z = t*z*z + c; | ||||
| 	//om.r[3].z = 0.0f; //optimized out
 | ||||
| 
 | ||||
| 	/* optimized out
 | ||||
| 	om.r[0].w = 0.0f; | ||||
| 	om.r[1].w = 0.0f; | ||||
| 	om.r[2].w = 0.0f; | ||||
| 	om.r[3].w = 1.0f; | ||||
| 	*/ | ||||
| 
 | ||||
| 	if (bRightSide) | ||||
| 	{ | ||||
| 		for (i = 0; i < 4; ++i) | ||||
| 		{ | ||||
| 			x = mtx->r[i].x*om.r[0].x + mtx->r[i].y*om.r[1].x + mtx->r[i].z*om.r[2].x; | ||||
| 			y = mtx->r[i].x*om.r[0].y + mtx->r[i].y*om.r[1].y + mtx->r[i].z*om.r[2].y; | ||||
| 			z = mtx->r[i].x*om.r[0].z + mtx->r[i].y*om.r[1].z + mtx->r[i].z*om.r[2].z; | ||||
| 
 | ||||
| 			mtx->r[i].x = x; | ||||
| 			mtx->r[i].y = y; | ||||
| 			mtx->r[i].z = z; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		for (i = 0; i < 3; ++i) | ||||
| 		{ | ||||
| 			x = mtx->r[0].x*om.r[i].x + mtx->r[1].x*om.r[i].y + mtx->r[2].x*om.r[i].z; | ||||
| 			y = mtx->r[0].y*om.r[i].x + mtx->r[1].y*om.r[i].y + mtx->r[2].y*om.r[i].z; | ||||
| 			z = mtx->r[0].z*om.r[i].x + mtx->r[1].z*om.r[i].y + mtx->r[2].z*om.r[i].z; | ||||
| 			w = mtx->r[0].w*om.r[i].x + mtx->r[1].w*om.r[i].y + mtx->r[2].w*om.r[i].z; | ||||
| 
 | ||||
| 			om.r[i].x = x; | ||||
| 			om.r[i].y = y; | ||||
| 			om.r[i].z = z; | ||||
| 			om.r[i].w = w; | ||||
| 		} | ||||
| 
 | ||||
| 		for (i = 0; i < 3; ++i) | ||||
| 			mtx->r[i] = om.r[i]; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										30
									
								
								libs/citro3d/source/maths/mtx_rotatex.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								libs/citro3d/source/maths/mtx_rotatex.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_RotateX(C3D_Mtx* mtx, float angle, bool bRightSide) | ||||
| { | ||||
| 	float  a, b; | ||||
| 	float  cosAngle = cosf(angle); | ||||
| 	float  sinAngle = sinf(angle); | ||||
| 	size_t i; | ||||
| 
 | ||||
| 	if (bRightSide) | ||||
| 	{ | ||||
| 		for (i = 0; i < 4; ++i) | ||||
| 		{ | ||||
| 			a = mtx->r[i].y*cosAngle + mtx->r[i].z*sinAngle; | ||||
| 			b = mtx->r[i].z*cosAngle - mtx->r[i].y*sinAngle; | ||||
| 			mtx->r[i].y = a; | ||||
| 			mtx->r[i].z = b; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		for (i = 0; i < 4; ++i) | ||||
| 		{ | ||||
| 			a = mtx->r[1].c[i]*cosAngle - mtx->r[2].c[i]*sinAngle; | ||||
| 			b = mtx->r[2].c[i]*cosAngle + mtx->r[1].c[i]*sinAngle; | ||||
| 			mtx->r[1].c[i] = a; | ||||
| 			mtx->r[2].c[i] = b; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										30
									
								
								libs/citro3d/source/maths/mtx_rotatey.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								libs/citro3d/source/maths/mtx_rotatey.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_RotateY(C3D_Mtx* mtx, float angle, bool bRightSide) | ||||
| { | ||||
| 	float  a, b; | ||||
| 	float  cosAngle = cosf(angle); | ||||
| 	float  sinAngle = sinf(angle); | ||||
| 	size_t i; | ||||
| 
 | ||||
| 	if (bRightSide) | ||||
| 	{ | ||||
| 		for (i = 0; i < 4; ++i) | ||||
| 		{ | ||||
| 			a = mtx->r[i].x*cosAngle - mtx->r[i].z*sinAngle; | ||||
| 			b = mtx->r[i].z*cosAngle + mtx->r[i].x*sinAngle; | ||||
| 			mtx->r[i].x = a; | ||||
| 			mtx->r[i].z = b; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		for (i = 0; i < 4; ++i) | ||||
| 		{ | ||||
| 			a = mtx->r[0].c[i]*cosAngle + mtx->r[2].c[i]*sinAngle; | ||||
| 			b = mtx->r[2].c[i]*cosAngle - mtx->r[0].c[i]*sinAngle; | ||||
| 			mtx->r[0].c[i] = a; | ||||
| 			mtx->r[2].c[i] = b; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										30
									
								
								libs/citro3d/source/maths/mtx_rotatez.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								libs/citro3d/source/maths/mtx_rotatez.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_RotateZ(C3D_Mtx* mtx, float angle, bool bRightSide) | ||||
| { | ||||
| 	float  a, b; | ||||
| 	float  cosAngle = cosf(angle); | ||||
| 	float  sinAngle = sinf(angle); | ||||
| 	size_t i; | ||||
| 
 | ||||
| 	if (bRightSide) | ||||
| 	{ | ||||
| 		for (i = 0; i < 4; ++i) | ||||
| 		{ | ||||
| 			a = mtx->r[i].x*cosAngle + mtx->r[i].y*sinAngle; | ||||
| 			b = mtx->r[i].y*cosAngle - mtx->r[i].x*sinAngle; | ||||
| 			mtx->r[i].x = a; | ||||
| 			mtx->r[i].y = b; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		for (i = 0; i < 4; ++i) | ||||
| 		{ | ||||
| 			a = mtx->r[0].c[i]*cosAngle - mtx->r[1].c[i]*sinAngle; | ||||
| 			b = mtx->r[1].c[i]*cosAngle + mtx->r[0].c[i]*sinAngle; | ||||
| 			mtx->r[0].c[i] = a; | ||||
| 			mtx->r[1].c[i] = b; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										12
									
								
								libs/citro3d/source/maths/mtx_scale.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								libs/citro3d/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; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										21
									
								
								libs/citro3d/source/maths/mtx_translate.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								libs/citro3d/source/maths/mtx_translate.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| void Mtx_Translate(C3D_Mtx* mtx, float x, float y, float z, bool bRightSide) | ||||
| { | ||||
| 
 | ||||
| 	C3D_FVec v = FVec4_New(x, y, z, 1.0f); | ||||
| 	int i, j; | ||||
| 
 | ||||
| 	if (bRightSide) | ||||
| 	{ | ||||
| 		for (i = 0; i < 4; ++i) | ||||
| 			mtx->r[i].w = FVec4_Dot(mtx->r[i], v); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		for (j = 0; j < 3; ++j) | ||||
| 			for (i = 0; i < 4; ++i) | ||||
| 				mtx->r[j].c[i] += mtx->r[3].c[i] * v.c[3-j]; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										13
									
								
								libs/citro3d/source/maths/quat_crossfvec3.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								libs/citro3d/source/maths/quat_crossfvec3.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| C3D_FVec Quat_CrossFVec3(C3D_FQuat q, C3D_FVec  v) | ||||
| { | ||||
| 	C3D_FVec qv  = FVec3_New(q.i, q.j, q.k); | ||||
| 	C3D_FVec uv  = FVec3_Cross(qv, v); | ||||
| 	C3D_FVec uuv = FVec3_Cross(qv, uv); | ||||
| 
 | ||||
| 	uv  = FVec3_Scale(uv,  2.0f * q.r); | ||||
| 	uuv = FVec3_Scale(uuv, 2.0f); | ||||
| 
 | ||||
| 	return FVec3_Add(v, FVec3_Add(uv, uuv)); | ||||
| } | ||||
							
								
								
									
										11
									
								
								libs/citro3d/source/maths/quat_multiply.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								libs/citro3d/source/maths/quat_multiply.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| C3D_FQuat Quat_Multiply(C3D_FQuat lhs, C3D_FQuat rhs) | ||||
| { | ||||
| 	float i = lhs.r*rhs.i + lhs.i*rhs.r + lhs.j*rhs.k - lhs.k*rhs.j; | ||||
| 	float j = lhs.r*rhs.j + lhs.j*rhs.r + lhs.k*rhs.i - lhs.i*rhs.k; | ||||
| 	float k = lhs.r*rhs.k + lhs.k*rhs.r + lhs.i*rhs.j - lhs.j*rhs.i; | ||||
| 	float r = lhs.r*rhs.r - lhs.i*rhs.i - lhs.j*rhs.j - lhs.k*rhs.k; | ||||
| 
 | ||||
| 	return Quat_New(i, j, k, r); | ||||
| } | ||||
							
								
								
									
										23
									
								
								libs/citro3d/source/maths/quat_pow.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								libs/citro3d/source/maths/quat_pow.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| #include <float.h> | ||||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| C3D_FQuat Quat_Pow(C3D_FQuat q, float p) | ||||
| { | ||||
| 	// if the power is very near to zero, return the identity quaternion to avoid blowing up with division
 | ||||
| 	if (p > -FLT_EPSILON && p < FLT_EPSILON) | ||||
| 		return Quat_Identity(); | ||||
| 
 | ||||
| 	float mag = FVec4_Magnitude(q); | ||||
| 
 | ||||
| 	// if the magnitude is very near to one, this is equivalent to raising the real component by the power
 | ||||
| 	// also, acosf(1) == 0 and sinf(0) == 0 so you would get a divide-by-zero anyway
 | ||||
| 	if (fabsf(q.r / mag) > 1.0f - FLT_EPSILON && fabsf(q.r / mag) < 1.0f + FLT_EPSILON) | ||||
| 		return Quat_New(0.0f, 0.0f, 0.0f, powf(q.r, p)); | ||||
| 
 | ||||
| 	float angle    = acosf(q.r / mag); | ||||
| 	float newAngle = angle * p; | ||||
| 	float div      = sinf(newAngle) / sinf(angle); | ||||
| 	float Mag      = powf(mag, p - 1.0f); | ||||
| 
 | ||||
| 	return Quat_New(q.i*div*Mag, q.j*div*Mag, q.k*div*Mag, cosf(newAngle)*mag*Mag); | ||||
| } | ||||
							
								
								
									
										16
									
								
								libs/citro3d/source/maths/quat_rotate.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								libs/citro3d/source/maths/quat_rotate.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| C3D_FQuat Quat_Rotate(C3D_FQuat q, C3D_FVec axis, float r, bool bRightSide) | ||||
| { | ||||
| 	float halfAngle = r/2.0f; | ||||
| 	float s         = sinf(halfAngle); | ||||
| 
 | ||||
| 	axis = FVec3_Normalize(axis); | ||||
| 
 | ||||
| 	C3D_FQuat tmp = Quat_New(axis.x*s, axis.y*s, axis.z*s, cosf(halfAngle)); | ||||
| 
 | ||||
| 	if (bRightSide) | ||||
| 		return Quat_Multiply(tmp, q); | ||||
| 	else | ||||
| 		return Quat_Multiply(q, tmp); | ||||
| } | ||||
							
								
								
									
										12
									
								
								libs/citro3d/source/maths/quat_rotatex.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								libs/citro3d/source/maths/quat_rotatex.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| C3D_FQuat Quat_RotateX(C3D_FQuat q, float r, bool bRightSide) | ||||
| { | ||||
| 	float c = cosf(r/2.0f); | ||||
| 	float s = sinf(r/2.0f); | ||||
| 
 | ||||
| 	if (bRightSide) | ||||
| 		return Quat_New(q.r*s + q.i*c, q.j*c - q.k*s, q.k*c + q.j*s, q.r*c - q.i*s); | ||||
| 	else | ||||
| 		return Quat_New(q.r*s + q.i*c, q.j*c + q.k*s, q.k*c - q.j*s, q.r*c - q.i*s); | ||||
| } | ||||
							
								
								
									
										12
									
								
								libs/citro3d/source/maths/quat_rotatey.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								libs/citro3d/source/maths/quat_rotatey.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| C3D_FQuat Quat_RotateY(C3D_FQuat q, float r, bool bRightSide) | ||||
| { | ||||
| 	float c = cosf(r/2.0f); | ||||
| 	float s = sinf(r/2.0f); | ||||
| 
 | ||||
| 	if (bRightSide) | ||||
| 		return Quat_New(q.i*c + q.k*s, q.r*s + q.j*c, q.k*c - q.i*s, q.r*c - q.j*s); | ||||
| 	else | ||||
| 		return Quat_New(q.i*c - q.k*s, q.r*s + q.j*c, q.k*c + q.i*s, q.r*c - q.j*s); | ||||
| } | ||||
							
								
								
									
										12
									
								
								libs/citro3d/source/maths/quat_rotatez.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								libs/citro3d/source/maths/quat_rotatez.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #include <c3d/maths.h> | ||||
| 
 | ||||
| C3D_FQuat Quat_RotateZ(C3D_FQuat q, float r, bool bRightSide) | ||||
| { | ||||
| 	float c = cosf(r/2.0f); | ||||
| 	float s = sinf(r/2.0f); | ||||
| 
 | ||||
| 	if (bRightSide) | ||||
| 		return Quat_New(q.i*c - q.j*s, q.j*c + q.i*s, q.r*s + q.k*c, q.r*c - q.k*s); | ||||
| 	else | ||||
| 		return Quat_New(q.i*c + q.j*s, q.j*c - q.i*s, q.r*s + q.k*c, q.r*c - q.k*s); | ||||
| } | ||||
							
								
								
									
										43
									
								
								libs/citro3d/source/mtxstack.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								libs/citro3d/source/mtxstack.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| #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, GPU_SHADER_TYPE unifType, int unifPos, int unifLen) | ||||
| { | ||||
| 	stk->unifType = unifType; | ||||
| 	stk->unifPos = unifPos; | ||||
| 	stk->unifLen = unifLen; | ||||
| 	stk->isDirty = true; | ||||
| } | ||||
| 
 | ||||
| C3D_Mtx* MtxStack_Push(C3D_MtxStack* stk) | ||||
| { | ||||
| 	if (stk->pos == (C3D_MTXSTACK_SIZE-1)) return NULL; | ||||
| 	stk->pos ++; | ||||
| 	Mtx_Copy(&stk->m[stk->pos], &stk->m[stk->pos-1]); | ||||
| 	return MtxStack_Cur(stk); | ||||
| } | ||||
| 
 | ||||
| C3D_Mtx* MtxStack_Pop(C3D_MtxStack* stk) | ||||
| { | ||||
| 	if (stk->pos == 0) return NULL; | ||||
| 	stk->pos --; | ||||
| 	return MtxStack_Cur(stk); | ||||
| } | ||||
| 
 | ||||
| void MtxStack_Update(C3D_MtxStack* stk) | ||||
| { | ||||
| 	if (!stk->isDirty) return; | ||||
| 
 | ||||
| 	if (stk->unifPos != 0xFF) | ||||
| 		C3D_FVUnifMtxNx4(stk->unifType, stk->unifPos, &stk->m[stk->pos], stk->unifLen); | ||||
| 
 | ||||
| 	stk->isDirty = false; | ||||
| } | ||||
							
								
								
									
										110
									
								
								libs/citro3d/source/renderbuffer.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								libs/citro3d/source/renderbuffer.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,110 @@ | |||
| #include "context.h" | ||||
| #include <string.h> | ||||
| 
 | ||||
| static const u8 colorFmtSizes[] = {2,1,0,0,0}; | ||||
| static const u8 depthFmtSizes[] = {0,0,1,2}; | ||||
| 
 | ||||
| static inline u16 getColorBufFillFlag(int fmt) | ||||
| { | ||||
| 	if (fmt < 0) return 0; | ||||
| 	return BIT(0) | ((u32)colorFmtSizes[fmt] << 8); | ||||
| } | ||||
| 
 | ||||
| static inline u16 getDepthBufFillFlag(int fmt) | ||||
| { | ||||
| 	if (fmt < 0) return 0; | ||||
| 	return BIT(0) | ((u32)depthFmtSizes[fmt] << 8); | ||||
| } | ||||
| 
 | ||||
| static inline u32 getColorBufFormatReg(int fmt) | ||||
| { | ||||
| 	return (fmt << 16) | colorFmtSizes[fmt]; | ||||
| } | ||||
| 
 | ||||
| static inline GPU_TEXCOLOR colorFmtFromDepthFmt(int fmt) | ||||
| { | ||||
| 	switch (fmt) | ||||
| 	{ | ||||
| 		case GPU_RB_DEPTH16: | ||||
| 			return GPU_RGB565; | ||||
| 		case GPU_RB_DEPTH24: | ||||
| 			return GPU_RGB8; | ||||
| 		case GPU_RB_DEPTH24_STENCIL8: | ||||
| 			return GPU_RGBA8; | ||||
| 		default: | ||||
| 			return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool C3D_RenderBufInit(C3D_RenderBuf* rb, int width, int height, int colorFmt, int depthFmt) | ||||
| { | ||||
| 	memset(rb, 0, sizeof(*rb)); | ||||
| 
 | ||||
| 	rb->depthFmt = depthFmt; | ||||
| 	rb->clearColor = rb->clearDepth = 0; | ||||
| 
 | ||||
| 	if (colorFmt < 0) | ||||
| 		return false; | ||||
| 	if (!C3D_TexInitVRAM(&rb->colorBuf, width, height, colorFmt)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	if (depthFmt >= 0) | ||||
| 	{ | ||||
| 		if (!C3D_TexInitVRAM(&rb->depthBuf, width, height, colorFmtFromDepthFmt(depthFmt))) | ||||
| 		{ | ||||
| 			C3D_TexDelete(&rb->colorBuf); | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void C3D_RenderBufClearAsync(C3D_RenderBuf* rb) | ||||
| { | ||||
| 	GX_MemoryFill( | ||||
| 		(u32*)rb->colorBuf.data, rb->clearColor, (u32*)((u8*)rb->colorBuf.data+rb->colorBuf.size), getColorBufFillFlag(rb->colorBuf.fmt), | ||||
| 		(u32*)rb->depthBuf.data, rb->clearDepth, (u32*)((u8*)rb->depthBuf.data+rb->depthBuf.size), getDepthBufFillFlag(rb->depthFmt)); | ||||
| } | ||||
| 
 | ||||
| void C3D_RenderBufTransferAsync(C3D_RenderBuf* rb, u32* frameBuf, u32 flags) | ||||
| { | ||||
| 	u32 dim = GX_BUFFER_DIM((u32)rb->colorBuf.width, (u32)rb->colorBuf.height); | ||||
| 	GX_DisplayTransfer((u32*)rb->colorBuf.data, dim, frameBuf, dim, flags); | ||||
| } | ||||
| 
 | ||||
| void C3D_RenderBufBind(C3D_RenderBuf* rb) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 	ctx->flags |= C3DiF_RenderBuf; | ||||
| 	ctx->rb = rb; | ||||
| 	C3D_SetViewport(0, 0, rb->colorBuf.width, rb->colorBuf.height); | ||||
| } | ||||
| 
 | ||||
| void C3Di_RenderBufBind(C3D_RenderBuf* rb) | ||||
| { | ||||
| 	u32 param[4] = { 0, 0, 0, 0 }; | ||||
| 
 | ||||
| 	GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 1); | ||||
| 
 | ||||
| 	param[0] = osConvertVirtToPhys(rb->depthBuf.data) >> 3; | ||||
| 	param[1] = osConvertVirtToPhys(rb->colorBuf.data) >> 3; | ||||
| 	param[2] = 0x01000000 | (((u32)(rb->colorBuf.height-1) & 0xFFF) << 12) | (rb->colorBuf.width & 0xFFF); | ||||
| 	GPUCMD_AddIncrementalWrites(GPUREG_DEPTHBUFFER_LOC, param, 3); | ||||
| 
 | ||||
| 	GPUCMD_AddWrite(GPUREG_RENDERBUF_DIM, param[2]); | ||||
| 	GPUCMD_AddWrite(GPUREG_DEPTHBUFFER_FORMAT, rb->depthFmt >= 0 ? rb->depthFmt : GPU_RB_DEPTH16); | ||||
| 	GPUCMD_AddWrite(GPUREG_COLORBUFFER_FORMAT, getColorBufFormatReg(rb->colorBuf.fmt)); | ||||
| 	GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_BLOCK32, 0x00000000); //?
 | ||||
| 
 | ||||
| 	// Enable or disable color/depth buffers
 | ||||
| 	param[0] = param[1] = rb->colorBuf.data ? 0xF : 0; | ||||
| 	param[2] = param[3] = rb->depthBuf.data ? 0x2 : 0; | ||||
| 	GPUCMD_AddIncrementalWrites(GPUREG_COLORBUFFER_READ, param, 4); | ||||
| } | ||||
| 
 | ||||
| void C3D_RenderBufDelete(C3D_RenderBuf* rb) | ||||
| { | ||||
| 	C3D_TexDelete(&rb->colorBuf); | ||||
| 	C3D_TexDelete(&rb->depthBuf); | ||||
| } | ||||
							
								
								
									
										404
									
								
								libs/citro3d/source/renderqueue.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										404
									
								
								libs/citro3d/source/renderqueue.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,404 @@ | |||
| #include "context.h" | ||||
| #include <c3d/renderqueue.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| static C3D_RenderTarget *firstTarget, *lastTarget; | ||||
| static C3D_RenderTarget *linkedTarget[3]; | ||||
| static C3D_RenderTarget *transferQueue, *clearQueue; | ||||
| 
 | ||||
| static struct | ||||
| { | ||||
| 	C3D_RenderTarget* targetList; | ||||
| 	u32* cmdBuf; | ||||
| 	u32 cmdBufSize; | ||||
| 	u8 flags; | ||||
| } queuedFrame[2]; | ||||
| static u8 queueSwap, queuedCount, queuedState; | ||||
| 
 | ||||
| static bool inFrame, inSafeTransfer, inSafeClear; | ||||
| 
 | ||||
| static void onRenderFinish(void* unused); | ||||
| static void onTransferFinish(void* unused); | ||||
| static void onClearDone(void* unused); | ||||
| 
 | ||||
| static void performDraw(void) | ||||
| { | ||||
| 	gspSetEventCallback(GSPGPU_EVENT_P3D, onRenderFinish, NULL, true); | ||||
| 	GX_ProcessCommandList(queuedFrame[queueSwap].cmdBuf, queuedFrame[queueSwap].cmdBufSize, queuedFrame[queueSwap].flags); | ||||
| } | ||||
| 
 | ||||
| static void performTransfer(void) | ||||
| { | ||||
| 	if (inSafeTransfer) return; // Let the safe transfer finish handler retry this
 | ||||
| 	C3D_RenderBuf* renderBuf = &transferQueue->renderBuf; | ||||
| 	u32* frameBuf = (u32*)gfxGetFramebuffer(transferQueue->screen, transferQueue->side, NULL, NULL); | ||||
| 	if (transferQueue->side == GFX_LEFT) | ||||
| 		gfxConfigScreen(transferQueue->screen, false); | ||||
| 	gspSetEventCallback(GSPGPU_EVENT_PPF, onTransferFinish, NULL, true); | ||||
| 	C3D_RenderBufTransferAsync(renderBuf, frameBuf, transferQueue->transferFlags); | ||||
| } | ||||
| 
 | ||||
| static void performClear(void) | ||||
| { | ||||
| 	if (inSafeClear) return; // Let the safe clear finish handler retry this
 | ||||
| 	C3D_RenderBuf* renderBuf = &clearQueue->renderBuf; | ||||
| 	// TODO: obey renderBuf->clearBits
 | ||||
| 	gspSetEventCallback(renderBuf->colorBuf.data ? GSPGPU_EVENT_PSC0 : GSPGPU_EVENT_PSC1, onClearDone, NULL, true); | ||||
| 	C3D_RenderBufClearAsync(renderBuf); | ||||
| } | ||||
| 
 | ||||
| static void updateFrameQueue(void) | ||||
| { | ||||
| 	C3D_RenderTarget* a; | ||||
| 	if (queuedState>0) return; // Still rendering
 | ||||
| 
 | ||||
| 	// Check that all targets are OK to be drawn on
 | ||||
| 	for (a = queuedFrame[queueSwap].targetList; a; a = a->frame[queueSwap]) | ||||
| 		if (!a->drawOk) | ||||
| 			return; // Nope, we can't start rendering yet
 | ||||
| 
 | ||||
| 	// Start rendering the frame
 | ||||
| 	queuedState=1; | ||||
| 	for (a = queuedFrame[queueSwap].targetList; a; a = a->frame[queueSwap]) | ||||
| 		a->drawOk = false; | ||||
| 	performDraw(); | ||||
| } | ||||
| 
 | ||||
| static void transferTarget(C3D_RenderTarget* target) | ||||
| { | ||||
| 	C3D_RenderTarget* a; | ||||
| 	target->transferOk = false; | ||||
| 	target->link = NULL; | ||||
| 	if (!transferQueue) | ||||
| 	{ | ||||
| 		transferQueue = target; | ||||
| 		performTransfer(); | ||||
| 		return; | ||||
| 	} | ||||
| 	for (a = transferQueue; a->link; a = a->link); | ||||
| 	a->link = target; | ||||
| } | ||||
| 
 | ||||
| static void clearTarget(C3D_RenderTarget* target) | ||||
| { | ||||
| 	C3D_RenderTarget* a; | ||||
| 	target->link = NULL; | ||||
| 	if (!clearQueue) | ||||
| 	{ | ||||
| 		clearQueue = target; | ||||
| 		performClear(); | ||||
| 		return; | ||||
| 	} | ||||
| 	for (a = clearQueue; a->link; a = a->link); | ||||
| 	a->link = target; | ||||
| } | ||||
| 
 | ||||
| static void onVBlank0(void* unused) | ||||
| { | ||||
| 	if (!linkedTarget[0]) return; | ||||
| 
 | ||||
| 	if (gfxIs3D()) | ||||
| 	{ | ||||
| 		if (linkedTarget[1] && linkedTarget[1]->transferOk) | ||||
| 			transferTarget(linkedTarget[1]); | ||||
| 		else if (linkedTarget[0]->transferOk) | ||||
| 		{ | ||||
| 			// Use a temporary copy of the left framebuffer to fill in the missing right image.
 | ||||
| 			static C3D_RenderTarget temp; | ||||
| 			memcpy(&temp, linkedTarget[0], sizeof(temp)); | ||||
| 			temp.side = GFX_RIGHT; | ||||
| 			temp.clearBits = false; | ||||
| 			transferTarget(&temp); | ||||
| 		} | ||||
| 	} | ||||
| 	if (linkedTarget[0]->transferOk) | ||||
| 		transferTarget(linkedTarget[0]); | ||||
| } | ||||
| 
 | ||||
| static void onVBlank1(void* unused) | ||||
| { | ||||
| 	if (linkedTarget[2] && linkedTarget[2]->transferOk) | ||||
| 		transferTarget(linkedTarget[2]); | ||||
| } | ||||
| 
 | ||||
| void onRenderFinish(void* unused) | ||||
| { | ||||
| 	C3D_RenderTarget *a, *next; | ||||
| 
 | ||||
| 	// The following check should never trigger
 | ||||
| 	if (queuedState!=1) svcBreak(USERBREAK_PANIC); | ||||
| 
 | ||||
| 	for (a = queuedFrame[queueSwap].targetList; a; a = next) | ||||
| 	{ | ||||
| 		next = a->frame[queueSwap]; | ||||
| 		a->frame[queueSwap] = NULL; | ||||
| 		if (a->linked) | ||||
| 			a->transferOk = true; | ||||
| 		else if (a->clearBits) | ||||
| 			clearTarget(a); | ||||
| 		else | ||||
| 			a->drawOk = true; | ||||
| 	} | ||||
| 
 | ||||
| 	// Consume the frame that has been just rendered
 | ||||
| 	memset(&queuedFrame[queueSwap], 0, sizeof(queuedFrame[queueSwap])); | ||||
| 	queueSwap ^= 1; | ||||
| 	queuedCount--; | ||||
| 	queuedState = 0; | ||||
| 
 | ||||
| 	// Update the frame queue if there are still frames to render
 | ||||
| 	if (queuedCount>0) | ||||
| 		updateFrameQueue(); | ||||
| } | ||||
| 
 | ||||
| void onTransferFinish(void* unused) | ||||
| { | ||||
| 	C3D_RenderTarget* target = transferQueue; | ||||
| 	if (inSafeTransfer) | ||||
| 	{ | ||||
| 		inSafeTransfer = false; | ||||
| 		// Try again if there are queued transfers
 | ||||
| 		if (target) | ||||
| 			performTransfer(); | ||||
| 		return; | ||||
| 	} | ||||
| 	transferQueue = target->link; | ||||
| 	if (target->clearBits) | ||||
| 		clearTarget(target); | ||||
| 	else | ||||
| 		target->drawOk = true; | ||||
| 	if (transferQueue) | ||||
| 		performTransfer(); | ||||
| 	if (target->drawOk && queuedCount>0 && queuedState==0) | ||||
| 		updateFrameQueue(); | ||||
| } | ||||
| 
 | ||||
| void onClearDone(void* unused) | ||||
| { | ||||
| 	C3D_RenderTarget* target = clearQueue; | ||||
| 	if (inSafeClear) | ||||
| 	{ | ||||
| 		inSafeClear = false; | ||||
| 		// Try again if there are queued clears
 | ||||
| 		if (target) | ||||
| 			performClear(); | ||||
| 		return; | ||||
| 	} | ||||
| 	clearQueue = target->link; | ||||
| 	target->drawOk = true; | ||||
| 	if (clearQueue) | ||||
| 		performClear(); | ||||
| 	if (queuedCount>0 && queuedState==0) | ||||
| 		updateFrameQueue(); | ||||
| } | ||||
| 
 | ||||
| static void C3Di_RenderQueueInit(void) | ||||
| { | ||||
| 	gspSetEventCallback(GSPGPU_EVENT_VBlank0, onVBlank0, NULL, false); | ||||
| 	gspSetEventCallback(GSPGPU_EVENT_VBlank1, onVBlank1, NULL, false); | ||||
| } | ||||
| 
 | ||||
| static void C3Di_RenderQueueExit(void) | ||||
| { | ||||
| 	int i; | ||||
| 	C3D_RenderTarget *a, *next; | ||||
| 
 | ||||
| 	for (a = firstTarget; a; a = next) | ||||
| 	{ | ||||
| 		next = a->next; | ||||
| 		C3D_RenderTargetDelete(a); | ||||
| 	} | ||||
| 
 | ||||
| 	gspSetEventCallback(GSPGPU_EVENT_VBlank0, NULL, NULL, false); | ||||
| 	gspSetEventCallback(GSPGPU_EVENT_VBlank1, NULL, NULL, false); | ||||
| 
 | ||||
| 	for (i = 0; i < 3; i ++) | ||||
| 		linkedTarget[i] = NULL; | ||||
| 
 | ||||
| 	memset(queuedFrame, 0, sizeof(queuedFrame)); | ||||
| 	queueSwap = 0; | ||||
| 	queuedCount = 0; | ||||
| 	queuedState = 0; | ||||
| } | ||||
| 
 | ||||
| static void C3Di_RenderQueueWaitDone(void) | ||||
| { | ||||
| 	while (queuedCount || transferQueue || clearQueue) | ||||
| 		gspWaitForAnyEvent(); | ||||
| } | ||||
| 
 | ||||
| bool checkRenderQueueInit(void) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	if (!ctx->renderQueueExit) | ||||
| 	{ | ||||
| 		C3Di_RenderQueueInit(); | ||||
| 		ctx->renderQueueWaitDone = C3Di_RenderQueueWaitDone; | ||||
| 		ctx->renderQueueExit = C3Di_RenderQueueExit; | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool C3D_FrameBegin(u8 flags) | ||||
| { | ||||
| 	if (inFrame) return false; | ||||
| 	int maxCount = (flags & C3D_FRAME_SYNCDRAW) ? 1 : 2; | ||||
| 	while (queuedCount >= maxCount) | ||||
| 	{ | ||||
| 		if (flags & C3D_FRAME_NONBLOCK) | ||||
| 			return false; | ||||
| 		gspWaitForP3D(); | ||||
| 	} | ||||
| 	inFrame = true; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool C3D_FrameDrawOn(C3D_RenderTarget* target) | ||||
| { | ||||
| 	if (!inFrame) return false; | ||||
| 
 | ||||
| 	// Queue the target in the frame if it hasn't already been.
 | ||||
| 	int pos = queueSwap^queuedCount; | ||||
| 	if (!target->frame[pos]) | ||||
| 	{ | ||||
| 		if (!queuedFrame[pos].targetList) | ||||
| 			queuedFrame[pos].targetList = target; | ||||
| 		else | ||||
| 		{ | ||||
| 			C3D_RenderTarget* a; | ||||
| 			for (a = queuedFrame[pos].targetList; a->frame[pos]; a = a->frame[pos]); | ||||
| 			a->frame[pos] = target; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	C3D_RenderBufBind(&target->renderBuf); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void C3D_FrameEnd(u8 flags) | ||||
| { | ||||
| 	if (!inFrame) return; | ||||
| 	inFrame = false; | ||||
| 
 | ||||
| 	int pos = queueSwap^queuedCount; | ||||
| 	if (!queuedFrame[pos].targetList) return; | ||||
| 
 | ||||
| 	// Add the frame to the queue
 | ||||
| 	queuedCount++; | ||||
| 	C3Di_FinalizeFrame(&queuedFrame[pos].cmdBuf, &queuedFrame[pos].cmdBufSize); | ||||
| 	queuedFrame[pos].flags = flags; | ||||
| 
 | ||||
| 	// Flush the entire linear memory if the user did not explicitly mandate to flush the command list
 | ||||
| 	if (!(flags & GX_CMDLIST_FLUSH)) | ||||
| 	{ | ||||
| 		// Take advantage of GX_FlushCacheRegions to flush gsp heap
 | ||||
| 		extern u32 __ctru_linear_heap; | ||||
| 		extern u32 __ctru_linear_heap_size; | ||||
| 		GX_FlushCacheRegions(queuedFrame[queueSwap].cmdBuf, queuedFrame[queueSwap].cmdBufSize, (u32 *) __ctru_linear_heap, __ctru_linear_heap_size, NULL, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	// Update the frame queue
 | ||||
| 	updateFrameQueue(); | ||||
| } | ||||
| 
 | ||||
| C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, int colorFmt, int depthFmt) | ||||
| { | ||||
| 	if (!checkRenderQueueInit()) return NULL; | ||||
| 	C3D_RenderTarget* target = (C3D_RenderTarget*)malloc(sizeof(C3D_RenderTarget)); | ||||
| 	if (!target) return NULL; | ||||
| 	memset(target, 0, sizeof(C3D_RenderTarget)); | ||||
| 	if (!C3D_RenderBufInit(&target->renderBuf, width, height, colorFmt, depthFmt)) | ||||
| 	{ | ||||
| 		free(target); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	target->drawOk = true; | ||||
| 	target->prev = lastTarget; | ||||
| 	target->next = NULL; | ||||
| 	if (lastTarget) | ||||
| 		lastTarget->next = target; | ||||
| 	if (!firstTarget) | ||||
| 		firstTarget = target; | ||||
| 	lastTarget = target; | ||||
| 
 | ||||
| 	return target; | ||||
| } | ||||
| 
 | ||||
| void C3D_RenderTargetDelete(C3D_RenderTarget* target) | ||||
| { | ||||
| 	target->clearBits = 0; | ||||
| 	target->linked = false; | ||||
| 	while (!target->drawOk) | ||||
| 		gspWaitForAnyEvent(); | ||||
| 	C3D_RenderBufDelete(&target->renderBuf); | ||||
| 	C3D_RenderTarget** prevNext = target->prev ? &target->prev->next : &firstTarget; | ||||
| 	C3D_RenderTarget** nextPrev = target->next ? &target->next->prev : &lastTarget; | ||||
| 	*prevNext = target->next; | ||||
| 	*nextPrev = target->prev; | ||||
| 	free(target); | ||||
| } | ||||
| 
 | ||||
| void C3D_RenderTargetSetClear(C3D_RenderTarget* target, u32 clearBits, u32 clearColor, u32 clearDepth) | ||||
| { | ||||
| 	if (target->renderBuf.colorBuf.data==NULL) clearBits &= ~C3D_CLEAR_COLOR; | ||||
| 	if (target->renderBuf.depthBuf.data==NULL) clearBits &= ~C3D_CLEAR_DEPTH; | ||||
| 
 | ||||
| 	u32 oldClearBits = target->clearBits; | ||||
| 	target->clearBits = clearBits & 0xFF; | ||||
| 	target->renderBuf.clearColor = clearColor; | ||||
| 	target->renderBuf.clearDepth = clearDepth; | ||||
| 
 | ||||
| 	if (clearBits &~ oldClearBits && target->drawOk) | ||||
| 	{ | ||||
| 		target->drawOk = false; | ||||
| 		clearTarget(target); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags) | ||||
| { | ||||
| 	int id = 0; | ||||
| 	if (screen==GFX_BOTTOM) id = 2; | ||||
| 	else if (side==GFX_RIGHT) id = 1; | ||||
| 	if (linkedTarget[id]) | ||||
| 		linkedTarget[id]->linked = false; | ||||
| 	linkedTarget[id] = target; | ||||
| 	target->linked = true; | ||||
| 	target->transferFlags = transferFlags; | ||||
| 	target->screen = screen; | ||||
| 	target->side = side; | ||||
| } | ||||
| 
 | ||||
| void C3D_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags) | ||||
| { | ||||
| 	while (transferQueue || inSafeTransfer) | ||||
| 		gspWaitForPPF(); | ||||
| 	inSafeTransfer = true; | ||||
| 	gspSetEventCallback(GSPGPU_EVENT_PPF, onTransferFinish, NULL, true); | ||||
| 	GX_DisplayTransfer(inadr, indim, outadr, outdim, flags); | ||||
| } | ||||
| 
 | ||||
| void C3D_SafeTextureCopy(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 size, u32 flags) | ||||
| { | ||||
| 	while (transferQueue || inSafeTransfer) | ||||
| 		gspWaitForPPF(); | ||||
| 	inSafeTransfer = true; | ||||
| 	gspSetEventCallback(GSPGPU_EVENT_PPF, onTransferFinish, NULL, true); | ||||
| 	GX_TextureCopy(inadr, indim, outadr, outdim, size, flags); | ||||
| } | ||||
| 
 | ||||
| void C3D_SafeMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1) | ||||
| { | ||||
| 	while (clearQueue || inSafeClear) | ||||
| 		gspWaitForAnyEvent(); | ||||
| 	inSafeClear = true; | ||||
| 	gspSetEventCallback(buf0a ? GSPGPU_EVENT_PSC0 : GSPGPU_EVENT_PSC1, onClearDone, NULL, true); | ||||
| 	GX_MemoryFill(buf0a, buf0v, buf0e, control0, buf1a, buf1v, buf1e, control1); | ||||
| } | ||||
							
								
								
									
										81
									
								
								libs/citro3d/source/texenv.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								libs/citro3d/source/texenv.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | |||
| #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->scaleRgb = GPU_TEVSCALE_1; | ||||
| 	env->scaleAlpha = GPU_TEVSCALE_1; | ||||
| } | ||||
| 
 | ||||
| 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_AddIncrementalWrites(GPUREG_TEXENV0_SOURCE + id*8, (u32*)env, sizeof(C3D_TexEnv)/sizeof(u32)); | ||||
| } | ||||
| 
 | ||||
| void C3D_TexEnvBufUpdate(int mode, int mask) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return; | ||||
| 
 | ||||
| 	u32 val = ctx->texEnvBuf; | ||||
| 	mask &= 0xF; | ||||
| 
 | ||||
| 	if (mode & C3D_RGB) | ||||
| 	{ | ||||
| 		val &= ~(0xF << 8); | ||||
| 		val |= mask << 8; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mode & C3D_Alpha) | ||||
| 	{ | ||||
| 		val &= ~(0xF << 12); | ||||
| 		val |= mask << 12; | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->texEnvBuf = val; | ||||
| 	ctx->flags |= C3DiF_TexEnvBuf; | ||||
| } | ||||
| 
 | ||||
| void C3D_TexEnvBufColor(u32 color) | ||||
| { | ||||
| 	C3D_Context* ctx = C3Di_GetContext(); | ||||
| 
 | ||||
| 	if (!(ctx->flags & C3DiF_Active)) | ||||
| 		return; | ||||
| 
 | ||||
| 	ctx->texEnvBufClr = color; | ||||
| 	ctx->flags |= C3DiF_TexEnvBuf; | ||||
| } | ||||
							
								
								
									
										115
									
								
								libs/citro3d/source/texture.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								libs/citro3d/source/texture.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,115 @@ | |||
| #include "context.h" | ||||
| #include <string.h> | ||||
| 
 | ||||
| // Return bits per pixel
 | ||||
| static inline size_t fmtSize(GPU_TEXCOLOR fmt) | ||||
| { | ||||
| 	switch (fmt) | ||||
| 	{ | ||||
| 		case GPU_RGBA8: | ||||
| 			return 32; | ||||
| 		case GPU_RGB8: | ||||
| 			return 24; | ||||
| 		case GPU_RGBA5551: | ||||
| 		case GPU_RGB565: | ||||
| 		case GPU_RGBA4: | ||||
| 		case GPU_LA8: | ||||
| 		case GPU_HILO8: | ||||
| 			return 16; | ||||
| 		case GPU_L8: | ||||
| 		case GPU_A8: | ||||
| 		case GPU_LA4: | ||||
| 		case GPU_ETC1A4: | ||||
| 			return 8; | ||||
| 		case GPU_L4: | ||||
| 		case GPU_A4: | ||||
| 		case GPU_ETC1: | ||||
| 			return 4; | ||||
| 		default: | ||||
| 			return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static inline bool addrIsVRAM(const void* addr) | ||||
| { | ||||
| 	u32 vaddr = (u32)addr; | ||||
| 	return vaddr >= 0x1F000000 && vaddr < 0x1F600000; | ||||
| } | ||||
| 
 | ||||
| static bool C3Di_TexInitCommon(C3D_Tex* tex, int width, int height, GPU_TEXCOLOR format, void* (*texAlloc)(size_t)) | ||||
| { | ||||
| 	if (tex->data) return false; | ||||
| 
 | ||||
| 	u32 size = fmtSize(format); | ||||
| 	if (!size) return false; | ||||
| 	size *= width * height / 8; | ||||
| 
 | ||||
| 	tex->data = texAlloc(size); | ||||
| 	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); | ||||
| 	if (format == GPU_ETC1) | ||||
| 		tex->param |= GPU_TEXTURE_ETC1_PARAM; | ||||
| 	tex->fmt = format; | ||||
| 	tex->size = size; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool C3D_TexInit(C3D_Tex* tex, int width, int height, GPU_TEXCOLOR format) | ||||
| { | ||||
| 	return C3Di_TexInitCommon(tex, width, height, format, linearAlloc); | ||||
| } | ||||
| 
 | ||||
| bool C3D_TexInitVRAM(C3D_Tex* tex, int width, int height, GPU_TEXCOLOR format) | ||||
| { | ||||
| 	return C3Di_TexInitCommon(tex, width, height, format, vramAlloc); | ||||
| } | ||||
| 
 | ||||
| void C3D_TexUpload(C3D_Tex* tex, const void* data) | ||||
| { | ||||
| 	if (tex->data && !addrIsVRAM(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 && !addrIsVRAM(tex->data)) | ||||
| 		GSPGPU_FlushDataCache(tex->data, tex->size); | ||||
| } | ||||
| 
 | ||||
| void C3D_TexDelete(C3D_Tex* tex) | ||||
| { | ||||
| 	if (!tex->data) return; | ||||
| 
 | ||||
| 	if (addrIsVRAM(tex->data)) | ||||
| 		vramFree(tex->data); | ||||
| 	else | ||||
| 		linearFree(tex->data); | ||||
| 
 | ||||
| 	tex->data = NULL; | ||||
| } | ||||
							
								
								
									
										134
									
								
								libs/citro3d/source/uniforms.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								libs/citro3d/source/uniforms.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,134 @@ | |||
| #include <c3d/uniforms.h> | ||||
| //#include <stdio.h>
 | ||||
| 
 | ||||
| C3D_FVec C3D_FVUnif[2][C3D_FVUNIF_COUNT]; | ||||
| C3D_IVec C3D_IVUnif[2][C3D_IVUNIF_COUNT]; | ||||
| u16      C3D_BoolUnifs[2]; | ||||
| 
 | ||||
| bool C3D_FVUnifDirty[2][C3D_FVUNIF_COUNT]; | ||||
| bool C3D_IVUnifDirty[2][C3D_IVUNIF_COUNT]; | ||||
| bool C3D_BoolUnifsDirty[2]; | ||||
| 
 | ||||
| static struct | ||||
| { | ||||
| 	bool dirty; | ||||
| 	int count; | ||||
| 	float24Uniform_s* data; | ||||
| } C3Di_ShaderFVecData[2]; | ||||
| 
 | ||||
| static bool C3Di_FVUnifEverDirty[2][C3D_FVUNIF_COUNT]; | ||||
| static bool C3Di_IVUnifEverDirty[2][C3D_IVUNIF_COUNT]; | ||||
| 
 | ||||
| void C3D_UpdateUniforms(GPU_SHADER_TYPE type) | ||||
| { | ||||
| 	int offset = type == GPU_GEOMETRY_SHADER ? (GPUREG_GSH_BOOLUNIFORM-GPUREG_VSH_BOOLUNIFORM) : 0; | ||||
| 	int i = 0; | ||||
| 
 | ||||
| 	// Update FVec uniforms that come from shader constants
 | ||||
| 	if (C3Di_ShaderFVecData[type].dirty) | ||||
| 	{ | ||||
| 		while (i < C3Di_ShaderFVecData[type].count) | ||||
| 		{ | ||||
| 			float24Uniform_s* u = &C3Di_ShaderFVecData[type].data[i++]; | ||||
| 			GPUCMD_AddIncrementalWrites(GPUREG_VSH_FLOATUNIFORM_CONFIG+offset, (u32*)u, 4); | ||||
| 			C3D_FVUnifDirty[type][u->id] = false; | ||||
| 		} | ||||
| 		C3Di_ShaderFVecData[type].dirty = false; | ||||
| 		i = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	// Update FVec uniforms
 | ||||
| 	while (i < C3D_FVUNIF_COUNT) | ||||
| 	{ | ||||
| 		if (!C3D_FVUnifDirty[type][i]) | ||||
| 		{ | ||||
| 			i ++; | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		// Find the number of consecutive dirty uniforms
 | ||||
| 		int j; | ||||
| 		for (j = i; j < C3D_FVUNIF_COUNT && C3D_FVUnifDirty[type][j]; j ++); | ||||
| 
 | ||||
| 		// Upload the uniforms
 | ||||
| 		GPUCMD_AddWrite(GPUREG_VSH_FLOATUNIFORM_CONFIG+offset, 0x80000000|i); | ||||
| 		GPUCMD_AddWrites(GPUREG_VSH_FLOATUNIFORM_DATA+offset, (u32*)&C3D_FVUnif[type][i], (j-i)*4); | ||||
| 
 | ||||
| 		// Clear the dirty flag
 | ||||
| 		int k; | ||||
| 		for (k = i; k < j; k ++) | ||||
| 		{ | ||||
| 			C3D_FVUnifDirty[type][k] = false; | ||||
| 			C3Di_FVUnifEverDirty[type][k] = true; | ||||
| 		} | ||||
| 
 | ||||
| 		// Advance
 | ||||
| 		i += j; | ||||
| 	} | ||||
| 
 | ||||
| 	// Update IVec uniforms
 | ||||
| 	for (i = 0; i < C3D_IVUNIF_COUNT; i ++) | ||||
| 	{ | ||||
| 		if (!C3D_IVUnifDirty[type][i]) continue; | ||||
| 
 | ||||
| 		GPUCMD_AddWrite(GPUREG_VSH_INTUNIFORM_I0+offset+i, C3D_IVUnif[type][i]); | ||||
| 		C3D_IVUnifDirty[type][i] = false; | ||||
| 		C3Di_IVUnifEverDirty[type][i] = false; | ||||
| 	} | ||||
| 
 | ||||
| 	// Update bool uniforms
 | ||||
| 	if (C3D_BoolUnifsDirty[type]) | ||||
| 	{ | ||||
| 		GPUCMD_AddWrite(GPUREG_VSH_BOOLUNIFORM+offset, 0x7FFF0000 | C3D_BoolUnifs[type]); | ||||
| 		C3D_BoolUnifsDirty[type] = false; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void C3Di_DirtyUniforms(GPU_SHADER_TYPE type) | ||||
| { | ||||
| 	int i; | ||||
| 	C3D_BoolUnifsDirty[type] = true; | ||||
| 	if (C3Di_ShaderFVecData[type].count) | ||||
| 		C3Di_ShaderFVecData[type].dirty = true; | ||||
| 	for (i = 0; i < C3D_FVUNIF_COUNT; i ++) | ||||
| 		C3D_FVUnifDirty[type][i] = C3D_FVUnifDirty[type][i] || C3Di_FVUnifEverDirty[type][i]; | ||||
| 	for (i = 0; i < C3D_IVUNIF_COUNT; i ++) | ||||
| 		C3D_IVUnifDirty[type][i] = C3D_IVUnifDirty[type][i] || C3Di_IVUnifEverDirty[type][i]; | ||||
| } | ||||
| 
 | ||||
| void C3Di_LoadShaderUniforms(shaderInstance_s* si) | ||||
| { | ||||
| 	GPU_SHADER_TYPE type = si->dvle->type; | ||||
| 	if (si->boolUniformMask) | ||||
| 	{ | ||||
| 		C3D_BoolUnifs[type] &= ~si->boolUniformMask; | ||||
| 		C3D_BoolUnifs[type] |= si->boolUniforms; | ||||
| 	} | ||||
| 
 | ||||
| 	if (type == GPU_GEOMETRY_SHADER) | ||||
| 		C3D_BoolUnifs[type] &= ~BIT(15); | ||||
| 	C3D_BoolUnifsDirty[type] = true; | ||||
| 
 | ||||
| 	if (si->intUniformMask) | ||||
| 	{ | ||||
| 		int i; | ||||
| 		for (i = 0; i < 4; i ++) | ||||
| 		{ | ||||
| 			if (si->intUniformMask & BIT(i)) | ||||
| 			{ | ||||
| 				C3D_IVUnif[type][i] = si->intUniforms[i]; | ||||
| 				C3D_IVUnifDirty[type][i] = true; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	C3Di_ShaderFVecData[type].dirty = true; | ||||
| 	C3Di_ShaderFVecData[type].count = si->numFloat24Uniforms; | ||||
| 	C3Di_ShaderFVecData[type].data = si->float24Uniforms; | ||||
| } | ||||
| 
 | ||||
| void C3Di_ClearShaderUniforms(GPU_SHADER_TYPE type) | ||||
| { | ||||
| 	C3Di_ShaderFVecData[type].dirty = false; | ||||
| 	C3Di_ShaderFVecData[type].count = 0; | ||||
| 	C3Di_ShaderFVecData[type].data = NULL; | ||||
| } | ||||
							
								
								
									
										249
									
								
								libs/citro3d/test/3ds/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								libs/citro3d/test/3ds/Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,249 @@ | |||
| #---------------------------------------------------------------------------------
 | ||||
| .SUFFIXES: | ||||
| #---------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| ifeq ($(strip $(DEVKITARM)),) | ||||
| $(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM") | ||||
| endif | ||||
| 
 | ||||
| 3DSTEX := 3dstex | ||||
| TOPDIR ?= $(CURDIR) | ||||
| 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
 | ||||
| #
 | ||||
| # NO_SMDH: if set to anything, no SMDH file is generated.
 | ||||
| # ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional)
 | ||||
| # APP_TITLE is the name of the app stored in the SMDH file (Optional)
 | ||||
| # APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional)
 | ||||
| # APP_AUTHOR is the author of the app stored in the SMDH file (Optional)
 | ||||
| # ICON is the filename of the icon (.png), relative to the project folder.
 | ||||
| #   If not set, it attempts to use one of the following (in this order):
 | ||||
| #     - <Project name>.png
 | ||||
| #     - icon.png
 | ||||
| #     - <libctru folder>/default_icon.png
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| TARGET   := citro3d_test | ||||
| BUILD    := build | ||||
| SOURCES  := source | ||||
| GRAPHICS := gfx | ||||
| DATA     := data | ||||
| INCLUDES := include | ||||
| ROMFS    := romfs | ||||
| 
 | ||||
| APP_TITLE       := citro3d test | ||||
| APP_DESCRIPTION := v1.0 | ||||
| APP_AUTHOR      := mtheall | ||||
| ICON            := | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| # options for code generation
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| ARCH     := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft | ||||
| 
 | ||||
| CFLAGS   := -g -Wall -O3 -mword-relocations \
 | ||||
|             -fomit-frame-pointer -ffunction-sections \
 | ||||
|             $(ARCH) | ||||
| 
 | ||||
| CFLAGS   +=  $(INCLUDE) -DARM11 -D_3DS | ||||
| 
 | ||||
| CXXFLAGS := $(CFLAGS) -fno-rtti -std=gnu++11 | ||||
| 
 | ||||
| ASFLAGS  := -g $(ARCH) | ||||
| LDFLAGS   = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(TARGET).map | ||||
| 
 | ||||
| LIBS     := -lcitro3d -lctru | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| # list of directories containing libraries, this must be the top level containing
 | ||||
| # include and lib
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| LIBDIRS  := $(CTRULIB) #$(CURDIR)/../.. | ||||
| 
 | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| # 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)/$(TARGET) | ||||
| export TOPDIR  :=  $(CURDIR) | ||||
| 
 | ||||
| export VPATH   :=  $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
 | ||||
|                    $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
 | ||||
|                    $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) | ||||
| 
 | ||||
| export DEPSDIR :=  $(CURDIR)/$(BUILD) | ||||
| 
 | ||||
| CFILES    := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) | ||||
| CXXFILES  := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) | ||||
| SFILES    := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) | ||||
| PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica))) | ||||
| BINFILES  := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) | ||||
| PNGFILES  := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png))) | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| # use CXX for linking C++ projects, CC for standard C
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| ifeq ($(strip $(CXXFILES)),) | ||||
|   export LD := $(CC) | ||||
| else | ||||
|   export LD := $(CXX) | ||||
| endif | ||||
| #---------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| export OFILES   := $(addsuffix .o,$(BINFILES)) \
 | ||||
|                    $(PICAFILES:.v.pica=.shbin.o) \
 | ||||
|                    $(CXXFILES:.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) | ||||
| 
 | ||||
| export LIBPATHS :=  $(foreach dir,$(LIBDIRS),-L$(dir)/lib) | ||||
| 
 | ||||
| PNGROMFS := $(addprefix romfs/,$(PNGFILES:.png=.bin)) | ||||
| 
 | ||||
| ifeq ($(strip $(ICON)),) | ||||
| 	icons := $(wildcard *.png) | ||||
| 	ifneq (,$(findstring $(TARGET).png,$(icons))) | ||||
| 		export APP_ICON := $(TOPDIR)/$(TARGET).png | ||||
| 	else | ||||
| 		ifneq (,$(findstring icon.png,$(icons))) | ||||
| 			export APP_ICON := $(TOPDIR)/icon.png | ||||
| 		endif | ||||
| 	endif | ||||
| else | ||||
| 	export APP_ICON := $(TOPDIR)/$(ICON) | ||||
| endif | ||||
| 
 | ||||
| ifeq ($(strip $(NO_SMDH)),) | ||||
| 	export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh | ||||
| endif | ||||
| 
 | ||||
| ifneq ($(ROMFS),) | ||||
| 	export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS) | ||||
| endif | ||||
| 
 | ||||
| .PHONY: $(BUILD) clean all | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| all: $(BUILD) | ||||
| 
 | ||||
| $(BUILD): $(PNGROMFS) | ||||
| 	@[ -d $@ ] || mkdir -p $@ | ||||
| 	@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| clean: | ||||
| 	@echo clean ... | ||||
| 	@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf $(PNGROMFS) | ||||
| 
 | ||||
| $(ROMFS)/%.rgba.bin: %.rgba.png | ||||
| 	@$(3DSTEX) -o $@ --rgba $< | ||||
| 
 | ||||
| $(ROMFS)/%.rgb.bin: %.rgb.png | ||||
| 	@$(3DSTEX) -o $@ --rgb $< | ||||
| 
 | ||||
| $(ROMFS)/%.rgba5551.bin: %.rgba5551.png | ||||
| 	@$(3DSTEX) -o $@ --rgba5551 $< | ||||
| 
 | ||||
| $(ROMFS)/%.rgb565.bin: %.rgb565.png | ||||
| 	@$(3DSTEX) -o $@ --rgb565 $< | ||||
| 
 | ||||
| $(ROMFS)/%.rgba4.bin: %.rgba4.png | ||||
| 	@$(3DSTEX) -o $@ --rgba4 $< | ||||
| 
 | ||||
| $(ROMFS)/%.la.bin: %.la.png | ||||
| 	@$(3DSTEX) -o $@ --la $< | ||||
| 
 | ||||
| $(ROMFS)/%.hilo.bin: %.hilo.png | ||||
| 	@$(3DSTEX) -o $@ --hilo $< | ||||
| 
 | ||||
| $(ROMFS)/%.l.bin: %.l.png | ||||
| 	@$(3DSTEX) -o $@ --l $< | ||||
| 
 | ||||
| $(ROMFS)/%.a.bin: %.a.png | ||||
| 	@$(3DSTEX) -o $@ --a $< | ||||
| 
 | ||||
| $(ROMFS)/%.la4.bin: %.la4.png | ||||
| 	@$(3DSTEX) -o $@ --la4 $< | ||||
| 
 | ||||
| $(ROMFS)/%.l4.bin: %.l4.png | ||||
| 	@$(3DSTEX) -o $@ --l4 $< | ||||
| 
 | ||||
| $(ROMFS)/%.a4.bin: %.a4.png | ||||
| 	@$(3DSTEX) -o $@ --a4 $< | ||||
| 
 | ||||
| $(ROMFS)/%.etc1.bin: %.etc1.png | ||||
| 	@$(3DSTEX) -o $@ --etc1 $< | ||||
| 
 | ||||
| $(ROMFS)/%.etc1a4.bin: %.etc1a4.png | ||||
| 	@$(3DSTEX) -o $@ --etc1a4 $< | ||||
| 
 | ||||
| $(ROMFS)/%.bin: %.png | ||||
| 	@$(3DSTEX) -o $@ $< | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| else | ||||
| 
 | ||||
| DEPENDS := $(OFILES:.o=.d) | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| # main targets
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| ifeq ($(strip $(NO_SMDH)),) | ||||
| .PHONY: all | ||||
| all	:	$(OUTPUT).3dsx $(OUTPUT).smdh | ||||
| $(OUTPUT).smdh : $(TOPDIR)/Makefile | ||||
| $(OUTPUT).3dsx: $(OUTPUT).smdh | ||||
| endif | ||||
| $(OUTPUT).3dsx: $(OUTPUT).elf | ||||
| $(OUTPUT).elf:  $(OFILES) | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| # you need a rule like this for each extension you use as binary data
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| %.bin.o: %.bin | ||||
| #---------------------------------------------------------------------------------
 | ||||
| 	@echo $(notdir $<) | ||||
| 	@$(bin2o) | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| # rules for assembling GPU shaders
 | ||||
| #---------------------------------------------------------------------------------
 | ||||
| define shader-as | ||||
| 	$(eval CURBIN := $(patsubst %.shbin.o,%.shbin,$(notdir $@))) | ||||
| 	picasso -o $(CURBIN) $1 | ||||
| 	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 | ||||
| endef | ||||
| 
 | ||||
| %.shbin.o : %.v.pica %.g.pica | ||||
| 	@echo $(notdir $^) | ||||
| 	@$(call shader-as,$^) | ||||
| 
 | ||||
| %.shbin.o : %.v.pica | ||||
| 	@echo $(notdir $<) | ||||
| 	@$(call shader-as,$<) | ||||
| 
 | ||||
| %.shbin.o : %.shlist | ||||
| 	@echo $(notdir $<) | ||||
| 	@$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file))) | ||||
| 
 | ||||
| -include $(DEPENDS) | ||||
| 
 | ||||
| #---------------------------------------------------------------------------------------
 | ||||
| endif | ||||
| #---------------------------------------------------------------------------------------
 | ||||
							
								
								
									
										
											BIN
										
									
								
								libs/citro3d/test/3ds/logo48.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/citro3d/test/3ds/logo48.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 613 B | 
							
								
								
									
										
											BIN
										
									
								
								libs/citro3d/test/3ds/logo64.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/citro3d/test/3ds/logo64.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 725 B | 
							
								
								
									
										
											BIN
										
									
								
								libs/citro3d/test/3ds/romfs/logo.bin
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/citro3d/test/3ds/romfs/logo.bin
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										927
									
								
								libs/citro3d/test/3ds/source/main.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										927
									
								
								libs/citro3d/test/3ds/source/main.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,927 @@ | |||
| #include <algorithm> | ||||
| #include <cstdio> | ||||
| #include <cstdlib> | ||||
| #include <cstring> | ||||
| #include <fcntl.h> | ||||
| #include <sys/stat.h> | ||||
| #include <unistd.h> | ||||
| #include <3ds.h> | ||||
| #include <citro3d.h> | ||||
| 
 | ||||
| #include "vshader_shbin.h" | ||||
| 
 | ||||
| #define CLEAR_COLOR 0x777777FF | ||||
| 
 | ||||
| #define DISPLAY_TRANSFER_FLAGS \ | ||||
|   (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \ | ||||
|    GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \ | ||||
|    GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| 
 | ||||
| template<class T> | ||||
| inline T clamp(T val, T min, T max) | ||||
| { | ||||
|   return std::max(min, std::min(max, val)); | ||||
| } | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
|   float position[3]; | ||||
|   float texcoord[2]; | ||||
|   float normal[3]; | ||||
| } attribute_t; | ||||
| 
 | ||||
| const attribute_t attribute_list[] = | ||||
| { | ||||
|   { { -0.5f, -0.5f,  0.5f }, { 0.0f, 0.0f }, { 0.0f, 0.0f,  1.0f } }, | ||||
|   { {  0.5f, -0.5f,  0.5f }, { 1.0f, 0.0f }, { 0.0f, 0.0f,  1.0f } }, | ||||
|   { {  0.5f,  0.5f,  0.5f }, { 1.0f, 1.0f }, { 0.0f, 0.0f,  1.0f } }, | ||||
|   { {  0.5f,  0.5f,  0.5f }, { 1.0f, 1.0f }, { 0.0f, 0.0f,  1.0f } }, | ||||
|   { { -0.5f,  0.5f,  0.5f }, { 0.0f, 1.0f }, { 0.0f, 0.0f,  1.0f } }, | ||||
|   { { -0.5f, -0.5f,  0.5f }, { 0.0f, 0.0f }, { 0.0f, 0.0f,  1.0f } }, | ||||
| 
 | ||||
|   { { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f }, { 0.0f, 0.0f, -1.0f } }, | ||||
|   { { -0.5f,  0.5f, -0.5f }, { 1.0f, 0.0f }, { 0.0f, 0.0f, -1.0f } }, | ||||
|   { {  0.5f,  0.5f, -0.5f }, { 1.0f, 1.0f }, { 0.0f, 0.0f, -1.0f } }, | ||||
|   { {  0.5f,  0.5f, -0.5f }, { 1.0f, 1.0f }, { 0.0f, 0.0f, -1.0f } }, | ||||
|   { {  0.5f, -0.5f, -0.5f }, { 0.0f, 1.0f }, { 0.0f, 0.0f, -1.0f } }, | ||||
|   { { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f }, { 0.0f, 0.0f, -1.0f } }, | ||||
| 
 | ||||
|   { {  0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f }, {  1.0f, 0.0f, 0.0f } }, | ||||
|   { {  0.5f,  0.5f, -0.5f }, { 1.0f, 0.0f }, {  1.0f, 0.0f, 0.0f } }, | ||||
|   { {  0.5f,  0.5f,  0.5f }, { 1.0f, 1.0f }, {  1.0f, 0.0f, 0.0f } }, | ||||
|   { {  0.5f,  0.5f,  0.5f }, { 1.0f, 1.0f }, {  1.0f, 0.0f, 0.0f } }, | ||||
|   { {  0.5f, -0.5f,  0.5f }, { 0.0f, 1.0f }, {  1.0f, 0.0f, 0.0f } }, | ||||
|   { {  0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f }, {  1.0f, 0.0f, 0.0f } }, | ||||
| 
 | ||||
|   { { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f } }, | ||||
|   { { -0.5f, -0.5f,  0.5f }, { 1.0f, 0.0f }, { -1.0f, 0.0f, 0.0f } }, | ||||
|   { { -0.5f,  0.5f,  0.5f }, { 1.0f, 1.0f }, { -1.0f, 0.0f, 0.0f } }, | ||||
|   { { -0.5f,  0.5f,  0.5f }, { 1.0f, 1.0f }, { -1.0f, 0.0f, 0.0f } }, | ||||
|   { { -0.5f,  0.5f, -0.5f }, { 0.0f, 1.0f }, { -1.0f, 0.0f, 0.0f } }, | ||||
|   { { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f } }, | ||||
| 
 | ||||
|   { { -0.5f,  0.5f, -0.5f }, { 0.0f, 0.0f }, { 0.0f,  1.0f, 0.0f } }, | ||||
|   { { -0.5f,  0.5f,  0.5f }, { 1.0f, 0.0f }, { 0.0f,  1.0f, 0.0f } }, | ||||
|   { {  0.5f,  0.5f,  0.5f }, { 1.0f, 1.0f }, { 0.0f,  1.0f, 0.0f } }, | ||||
|   { {  0.5f,  0.5f,  0.5f }, { 1.0f, 1.0f }, { 0.0f,  1.0f, 0.0f } }, | ||||
|   { {  0.5f,  0.5f, -0.5f }, { 0.0f, 1.0f }, { 0.0f,  1.0f, 0.0f } }, | ||||
|   { { -0.5f,  0.5f, -0.5f }, { 0.0f, 0.0f }, { 0.0f,  1.0f, 0.0f } }, | ||||
| 
 | ||||
|   { { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f }, { 0.0f, -1.0f, 0.0f } }, | ||||
|   { {  0.5f, -0.5f, -0.5f }, { 1.0f, 0.0f }, { 0.0f, -1.0f, 0.0f } }, | ||||
|   { {  0.5f, -0.5f,  0.5f }, { 1.0f, 1.0f }, { 0.0f, -1.0f, 0.0f } }, | ||||
|   { {  0.5f, -0.5f,  0.5f }, { 1.0f, 1.0f }, { 0.0f, -1.0f, 0.0f } }, | ||||
|   { { -0.5f, -0.5f,  0.5f }, { 0.0f, 1.0f }, { 0.0f, -1.0f, 0.0f } }, | ||||
|   { { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f }, { 0.0f, -1.0f, 0.0f } }, | ||||
| }; | ||||
| 
 | ||||
| #define attribute_list_count (sizeof(attribute_list)/sizeof(attribute_list[0])) | ||||
| 
 | ||||
| int uLoc_projection, uLoc_modelView, uLoc_texView; | ||||
| int uLoc_lightVec, uLoc_lightHalfVec, uLoc_lightClr, uLoc_material; | ||||
| C3D_Mtx material = | ||||
| { | ||||
|   { | ||||
|     { { 0.0f, 0.2f, 0.2f, 0.2f } }, // Ambient
 | ||||
|     { { 0.0f, 0.4f, 0.4f, 0.4f } }, // Diffuse
 | ||||
|     { { 0.0f, 0.8f, 0.8f, 0.8f } }, // Specular
 | ||||
|     { { 1.0f, 0.0f, 0.0f, 0.0f } }, // Emission
 | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| struct | ||||
| { | ||||
|   C3D_Tex      tex; | ||||
|   const char   *path; | ||||
|   size_t       width, height; | ||||
|   GPU_TEXCOLOR format; | ||||
| } texture[] = | ||||
| { | ||||
|   { {}, "romfs:/logo.bin",  64, 64, GPU_RGBA8, }, | ||||
| }; | ||||
| 
 | ||||
| #define num_textures (sizeof(texture)/sizeof(texture[0])) | ||||
|    | ||||
| void *vbo_data; | ||||
| 
 | ||||
| void sceneInit(shaderProgram_s *program) | ||||
| { | ||||
|   uLoc_projection   = shaderInstanceGetUniformLocation(program->vertexShader, "projection"); | ||||
|   uLoc_modelView    = shaderInstanceGetUniformLocation(program->vertexShader, "modelView"); | ||||
|   uLoc_texView      = shaderInstanceGetUniformLocation(program->vertexShader, "texView"); | ||||
|   uLoc_lightVec     = shaderInstanceGetUniformLocation(program->vertexShader, "lightVec"); | ||||
|   uLoc_lightHalfVec = shaderInstanceGetUniformLocation(program->vertexShader, "lightHalfVec"); | ||||
|   uLoc_lightClr     = shaderInstanceGetUniformLocation(program->vertexShader, "lightClr"); | ||||
|   uLoc_material     = shaderInstanceGetUniformLocation(program->vertexShader, "material"); | ||||
| 
 | ||||
|   // Configure attributes for use with the vertex shader
 | ||||
|   C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); | ||||
|   AttrInfo_Init(attrInfo); | ||||
|   AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position
 | ||||
|   AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=texcoord
 | ||||
|   AttrInfo_AddLoader(attrInfo, 2, GPU_FLOAT, 3); // v2=normal
 | ||||
| 
 | ||||
|   // Create the VBO (vertex buffer object)
 | ||||
|   vbo_data = linearAlloc(sizeof(attribute_list)); | ||||
|   std::memcpy(vbo_data, attribute_list, sizeof(attribute_list)); | ||||
| 
 | ||||
|   // Configure buffers
 | ||||
|   C3D_BufInfo* bufInfo = C3D_GetBufInfo(); | ||||
|   BufInfo_Init(bufInfo); | ||||
|   BufInfo_Add(bufInfo, vbo_data, sizeof(attribute_t), 3, 0x210); | ||||
|    | ||||
|   // Load the texture and bind it to the first texture unit
 | ||||
|   for(size_t i = 0; i < num_textures; ++i) | ||||
|   { | ||||
|     struct stat st; | ||||
|     int         fd = ::open(texture[i].path, O_RDONLY); | ||||
|     ::fstat(fd, &st); | ||||
| 
 | ||||
|     size_t size = st.st_size; | ||||
| 
 | ||||
|     void *buffer = std::malloc(size); | ||||
|     void *p      = buffer; | ||||
|    | ||||
|     while(size > 0) | ||||
|     { | ||||
|       ssize_t rc = ::read(fd, p, size); | ||||
|       if(rc <= 0 || static_cast<size_t>(rc) > size) | ||||
|         break; | ||||
| 
 | ||||
|       size -= rc; | ||||
|       p    =  reinterpret_cast<char*>(p) + rc; | ||||
|     } | ||||
| 
 | ||||
|     ::close(fd); | ||||
| 
 | ||||
|     C3D_TexInit(&texture[i].tex, texture[i].width, texture[i].height, texture[i].format); | ||||
|     C3D_TexUpload(&texture[i].tex, buffer); | ||||
|     C3D_TexSetFilter(&texture[i].tex, GPU_LINEAR, GPU_NEAREST); | ||||
| 
 | ||||
|     ::free(buffer); | ||||
|   } | ||||
| 
 | ||||
|   C3D_TexBind(0, &texture[0].tex); | ||||
| 
 | ||||
|   // Configure the first fragment shading substage to blend the texture color with
 | ||||
|   // the vertex color (calculated by the vertex shader using a lighting algorithm)
 | ||||
|   // See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
 | ||||
|   C3D_TexEnv* env = C3D_GetTexEnv(0); | ||||
|   C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0); | ||||
|   C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); | ||||
|   C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); | ||||
| } | ||||
| 
 | ||||
| void sceneExit() | ||||
| { | ||||
|   for(size_t i = 0; i < num_textures; ++i) | ||||
|     C3D_TexDelete(&texture[i].tex); | ||||
| 
 | ||||
|   linearFree(vbo_data); | ||||
| } | ||||
| 
 | ||||
| void persp_tilt_test() | ||||
| { | ||||
|   C3D_RenderTarget *top; | ||||
|   C3D_Mtx          projection; | ||||
|   C3D_Mtx          modelView; | ||||
|   C3D_Mtx          texView; | ||||
|   float            x = 0.0f, y = 0.0f, z = -2.0f, | ||||
|                    old_x = x, old_y = y, old_z = z; | ||||
|   float            angle = 0.0f; | ||||
| 
 | ||||
|   top = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   C3D_RenderTargetSetClear(top, C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_RenderTargetSetOutput(top, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); | ||||
| 
 | ||||
|   Mtx_PerspTilt(&projection, 60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f, false); | ||||
| 
 | ||||
|   Mtx_Identity(&modelView); | ||||
|   Mtx_Translate(&modelView, x, y, z, true); | ||||
| 
 | ||||
|   Mtx_Identity(&texView); | ||||
| 
 | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection); | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView,  &modelView); | ||||
|   C3D_FVUnifMtx2x4(GPU_VERTEX_SHADER, uLoc_texView,    &texView); | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_material,   &material); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightVec,     0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightHalfVec, 0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr,     1.0f, 1.0f,  1.0f, 1.0f); | ||||
| 
 | ||||
|   C3D_TexBind(0, &texture[0].tex); | ||||
| 
 | ||||
|   std::printf("\x1b[2J"); | ||||
|   std::printf("(LEFT/RIGHT) x %.1f\n", x); | ||||
|   std::printf("(UP/DOWN)    y %.1f\n", y); | ||||
|   std::printf("(L/R)        z %.1f\n", z); | ||||
| 
 | ||||
|   while(aptMainLoop()) | ||||
|   { | ||||
|     gspWaitForVBlank(); | ||||
| 
 | ||||
|     hidScanInput(); | ||||
|     u32 down = hidKeysDown(); | ||||
|     u32 held = hidKeysHeld(); | ||||
|     if(down & (KEY_START|KEY_SELECT)) | ||||
|       break; | ||||
| 
 | ||||
|     old_x = x; | ||||
|     old_y = y; | ||||
|     old_z = z; | ||||
| 
 | ||||
|     if((down | held) & KEY_LEFT) | ||||
|       x = clamp(x - 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_RIGHT) | ||||
|       x = clamp(x + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_UP) | ||||
|       y = clamp(y + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_DOWN) | ||||
|       y = clamp(y - 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_L) | ||||
|       z = clamp(z + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_R) | ||||
|       z = clamp(z - 0.1f, -10.0f, 10.0f); | ||||
| 
 | ||||
|     if((x != old_x) || (y != old_y) || (z != old_z)) | ||||
|     { | ||||
|       std::printf("\x1b[0;0H"); | ||||
|       std::printf("(LEFT/RIGHT) x %.1f\n", x); | ||||
|       std::printf("(UP/DOWN)    y %.1f\n", y); | ||||
|       std::printf("(L/R)        z %.1f\n", z); | ||||
|     } | ||||
| 
 | ||||
|     Mtx_Identity(&modelView); | ||||
|     Mtx_Translate(&modelView, x, y, z, true); | ||||
|     Mtx_RotateY(&modelView, angle*M_TAU/360.0f, true); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); | ||||
| 
 | ||||
|     angle += 1.0f; | ||||
|     if(angle >= 360.0f) | ||||
|       angle = 0.0f; | ||||
| 
 | ||||
|     C3D_FrameBegin(C3D_FRAME_SYNCDRAW); | ||||
|     C3D_FrameDrawOn(top); | ||||
|     C3D_DrawArrays(GPU_TRIANGLES, 0, attribute_list_count); | ||||
|     C3D_FrameEnd(0); | ||||
|   } | ||||
| 
 | ||||
|   C3D_RenderTargetDelete(top); | ||||
| } | ||||
| 
 | ||||
| void ortho_tilt_test() | ||||
| { | ||||
|   C3D_RenderTarget *top; | ||||
|   C3D_Mtx          projection; | ||||
|   C3D_Mtx          modelView; | ||||
|   C3D_Mtx          texView; | ||||
|   float            x = 0.0f, y = 0.0f, z = 0.0f, | ||||
|                    old_x = x, old_y = y, old_z = z; | ||||
|   float            angle = 0.0f; | ||||
| 
 | ||||
|   top = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   C3D_RenderTargetSetClear(top, C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_RenderTargetSetOutput(top, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); | ||||
| 
 | ||||
|   Mtx_OrthoTilt(&projection, 0.0f, 400.0f, 0.0f, 240.0f, 100.0f, -100.0f, false); | ||||
| 
 | ||||
|   Mtx_Identity(&texView); | ||||
| 
 | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection); | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView,  &modelView); | ||||
|   C3D_FVUnifMtx2x4(GPU_VERTEX_SHADER, uLoc_texView,    &texView); | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_material,   &material); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightVec,     0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightHalfVec, 0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr,     1.0f, 1.0f,  1.0f, 1.0f); | ||||
| 
 | ||||
|   C3D_TexBind(0, &texture[0].tex); | ||||
| 
 | ||||
|   std::printf("\x1b[2J"); | ||||
|   std::printf("(LEFT/RIGHT) x %.1f\n", x); | ||||
|   std::printf("(UP/DOWN)    y %.1f\n", y); | ||||
|   std::printf("(L/R)        z %.1f\n", z); | ||||
| 
 | ||||
|   while(aptMainLoop()) | ||||
|   { | ||||
|     gspWaitForVBlank(); | ||||
| 
 | ||||
|     hidScanInput(); | ||||
|     u32 down = hidKeysDown(); | ||||
|     u32 held = hidKeysHeld(); | ||||
|     if(down & (KEY_START|KEY_SELECT)) | ||||
|       break; | ||||
| 
 | ||||
|     old_x = x; | ||||
|     old_y = y; | ||||
|     old_z = z; | ||||
| 
 | ||||
|     if((down | held) & KEY_LEFT) | ||||
|       x = clamp(x - 1.0f, 0.0f, 400.0f); | ||||
|     if((down | held) & KEY_RIGHT) | ||||
|       x = clamp(x + 1.0f, 0.0f, 400.0f); | ||||
|     if((down | held) & KEY_UP) | ||||
|       y = clamp(y + 1.0f, 0.0f, 240.0f); | ||||
|     if((down | held) & KEY_DOWN) | ||||
|       y = clamp(y - 1.0f, 0.0f, 240.0f); | ||||
|     if((down | held) & KEY_L) | ||||
|       z = clamp(z + 1.0f, -100.0f, 100.0f); | ||||
|     if((down | held) & KEY_R) | ||||
|       z = clamp(z - 1.0f, -100.0f, 100.0f); | ||||
| 
 | ||||
|     if((x != old_x) || (y != old_y) || (z != old_z)) | ||||
|     { | ||||
|       std::printf("\x1b[0;0H"); | ||||
|       std::printf("(LEFT/RIGHT) x %.1f\n", x); | ||||
|       std::printf("(UP/DOWN)    y %.1f\n", y); | ||||
|       std::printf("(L/R)        z %.1f\n", z); | ||||
|     } | ||||
| 
 | ||||
|     Mtx_Identity(&modelView); | ||||
|     Mtx_Translate(&modelView, x, y, z, true); | ||||
|     Mtx_Scale(&modelView, 64.0f, 64.0f, 64.0f); | ||||
|     Mtx_RotateY(&modelView, angle*M_TAU/360.0f, true); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); | ||||
| 
 | ||||
|     angle += 1.0f; | ||||
|     if(angle >= 360.0f) | ||||
|       angle = 0.0f; | ||||
| 
 | ||||
|     C3D_FrameBegin(C3D_FRAME_SYNCDRAW); | ||||
|     C3D_FrameDrawOn(top); | ||||
|     C3D_DrawArrays(GPU_TRIANGLES, 0, attribute_list_count); | ||||
|     C3D_FrameEnd(0); | ||||
|   } | ||||
| 
 | ||||
|   C3D_RenderTargetDelete(top); | ||||
| } | ||||
| 
 | ||||
| void stereo_tilt_test() | ||||
| { | ||||
|   C3D_RenderTarget *topLeft, *topRight; | ||||
|   C3D_Mtx          projLeft, projRight; | ||||
|   C3D_Mtx          modelView; | ||||
|   C3D_Mtx          texView; | ||||
|   float            x = 0.0f, y = 0.0f, z = -2.0f, | ||||
|                    old_x = x, old_y = y, old_z = z; | ||||
|   float            iod = osGet3DSliderState(), old_iod = iod; | ||||
|   float            focLen = 2.0f, old_focLen = focLen; | ||||
|   float            angle = 0.0f; | ||||
| 
 | ||||
|   gfxSet3D(true); | ||||
| 
 | ||||
|   topLeft  = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   topRight = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   C3D_RenderTargetSetClear(topLeft,  C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_RenderTargetSetClear(topRight, C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_RenderTargetSetOutput(topLeft,  GFX_TOP, GFX_LEFT,  DISPLAY_TRANSFER_FLAGS); | ||||
|   C3D_RenderTargetSetOutput(topRight, GFX_TOP, GFX_RIGHT, DISPLAY_TRANSFER_FLAGS); | ||||
| 
 | ||||
|   Mtx_PerspStereoTilt(&projLeft,  60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f, -iod, focLen, false); | ||||
|   Mtx_PerspStereoTilt(&projRight, 60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f,  iod, focLen, false); | ||||
| 
 | ||||
|   Mtx_Identity(&texView); | ||||
| 
 | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView,  &modelView); | ||||
|   C3D_FVUnifMtx2x4(GPU_VERTEX_SHADER, uLoc_texView,    &texView); | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_material,   &material); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightVec,     0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightHalfVec, 0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr,     1.0f, 1.0f,  1.0f, 1.0f); | ||||
| 
 | ||||
|   C3D_TexBind(0, &texture[0].tex); | ||||
| 
 | ||||
|   std::printf("\x1b[2J"); | ||||
|   std::printf("(LEFT/RIGHT) x      %.1f\n", x); | ||||
|   std::printf("(UP/DOWN)    y      %.1f\n", y); | ||||
|   std::printf("(L/R)        z      %.1f\n", z); | ||||
|   std::printf("(Y/A)        focLen %.1f\n", focLen); | ||||
|   std::printf("(3D Slider)  iod    %.1f\n", iod); | ||||
| 
 | ||||
|   while(aptMainLoop()) | ||||
|   { | ||||
|     gspWaitForVBlank(); | ||||
| 
 | ||||
|     hidScanInput(); | ||||
|     u32 down = hidKeysDown(); | ||||
|     u32 held = hidKeysHeld(); | ||||
|     if(down & (KEY_START|KEY_SELECT)) | ||||
|       break; | ||||
| 
 | ||||
|     old_x      = x; | ||||
|     old_y      = y; | ||||
|     old_z      = z; | ||||
|     old_focLen = focLen; | ||||
|     old_iod    = iod; | ||||
| 
 | ||||
|     if((down | held) & KEY_LEFT) | ||||
|       x = clamp(x - 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_RIGHT) | ||||
|       x = clamp(x + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_UP) | ||||
|       y = clamp(y + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_DOWN) | ||||
|       y = clamp(y - 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_L) | ||||
|       z = clamp(z + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_R) | ||||
|       z = clamp(z - 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_Y) | ||||
|       focLen = clamp(focLen - 0.1f, 0.1f, 10.0f); | ||||
|     if((down | held) & KEY_A) | ||||
|       focLen = clamp(focLen + 0.1f, 0.1f, 10.0f); | ||||
| 
 | ||||
|     iod = osGet3DSliderState(); | ||||
| 
 | ||||
|     if((x != old_x) || (y != old_y) || (z != old_z) | ||||
|     || (focLen != old_focLen) || (iod != old_iod)) | ||||
|     { | ||||
|       std::printf("\x1b[0;0H"); | ||||
|       std::printf("(LEFT/RIGHT) x      %.1f\n", x); | ||||
|       std::printf("(UP/DOWN)    y      %.1f\n", y); | ||||
|       std::printf("(L/R)        z      %.1f\n", z); | ||||
|       std::printf("(Y/A)        focLen %.1f\n", focLen); | ||||
|       std::printf("(3D Slider)  iod    %.1f\n", iod); | ||||
| 
 | ||||
|       Mtx_PerspStereoTilt(&projLeft,  60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f, -iod, focLen, false); | ||||
|       Mtx_PerspStereoTilt(&projRight, 60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f,  iod, focLen, false); | ||||
|     } | ||||
| 
 | ||||
|     Mtx_Identity(&modelView); | ||||
|     Mtx_Translate(&modelView, x, y, z, true); | ||||
|     Mtx_RotateY(&modelView, angle*M_TAU/360.0f, true); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); | ||||
| 
 | ||||
|     angle += 1.0f; | ||||
|     if(angle >= 360.0f) | ||||
|       angle = 0.0f; | ||||
| 
 | ||||
|     C3D_FrameBegin(C3D_FRAME_SYNCDRAW); | ||||
| 
 | ||||
|     C3D_FrameDrawOn(topLeft); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projLeft); | ||||
|     C3D_DrawArrays(GPU_TRIANGLES, 0, attribute_list_count); | ||||
| 
 | ||||
|     if(iod > 0.0f) | ||||
|     { | ||||
|       C3D_FrameDrawOn(topRight); | ||||
|       C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projRight); | ||||
|       C3D_DrawArrays(GPU_TRIANGLES, 0, attribute_list_count); | ||||
|     } | ||||
| 
 | ||||
|     C3D_FrameEnd(0); | ||||
|   } | ||||
| 
 | ||||
|   C3D_RenderTargetDelete(topLeft); | ||||
|   C3D_RenderTargetDelete(topRight); | ||||
| 
 | ||||
|   gfxSet3D(false); | ||||
| } | ||||
| 
 | ||||
| void persp_test() | ||||
| { | ||||
|   C3D_RenderTarget *top, *tex; | ||||
|   C3D_Mtx          projTop, projTex; | ||||
|   C3D_Mtx          modelView; | ||||
|   C3D_Mtx          texView; | ||||
|   float            x = 0.0f, y = 0.0f, z = -2.0f, | ||||
|                    old_x = x, old_y = y, old_z = z; | ||||
|   float            angle = 0.0f; | ||||
| 
 | ||||
|   top = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   C3D_RenderTargetSetClear(top, C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_RenderTargetSetOutput(top, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); | ||||
| 
 | ||||
|   tex = C3D_RenderTargetCreate(512, 256, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   C3D_RenderTargetSetClear(tex, C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_TexSetFilter(&tex->renderBuf.colorBuf, GPU_LINEAR, GPU_NEAREST); | ||||
| 
 | ||||
|   Mtx_Persp(&projTex, 60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f, false); | ||||
| 
 | ||||
|   Mtx_Identity(&modelView); | ||||
|   Mtx_Translate(&modelView, x, y, z, true); | ||||
| 
 | ||||
|   Mtx_OrthoTilt(&projTop, -0.5f, 0.5f, -0.5f, 0.5f, 100.0f, -100.0f, false); | ||||
|   Mtx_Identity(&texView); | ||||
| 
 | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView,  &modelView); | ||||
|   C3D_FVUnifMtx2x4(GPU_VERTEX_SHADER, uLoc_texView,    &texView); | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_material,   &material); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightVec,     0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightHalfVec, 0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr,     1.0f, 1.0f,  1.0f, 1.0f); | ||||
| 
 | ||||
|   std::printf("\x1b[2J"); | ||||
|   std::printf("(LEFT/RIGHT) x %.1f\n", x); | ||||
|   std::printf("(UP/DOWN)    y %.1f\n", y); | ||||
|   std::printf("(L/R)        z %.1f\n", z); | ||||
| 
 | ||||
|   while(aptMainLoop()) | ||||
|   { | ||||
|     gspWaitForVBlank(); | ||||
| 
 | ||||
|     hidScanInput(); | ||||
|     u32 down = hidKeysDown(); | ||||
|     u32 held = hidKeysHeld(); | ||||
|     if(down & (KEY_START|KEY_SELECT)) | ||||
|       break; | ||||
| 
 | ||||
|     old_x      = x; | ||||
|     old_y      = y; | ||||
|     old_z      = z; | ||||
| 
 | ||||
|     if((down | held) & KEY_LEFT) | ||||
|       x = clamp(x - 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_RIGHT) | ||||
|       x = clamp(x + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_UP) | ||||
|       y = clamp(y + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_DOWN) | ||||
|       y = clamp(y - 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_L) | ||||
|       z = clamp(z + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_R) | ||||
|       z = clamp(z - 0.1f, -10.0f, 10.0f); | ||||
| 
 | ||||
|     if((x != old_x) || (y != old_y) || (z != old_z)) | ||||
|     { | ||||
|       std::printf("\x1b[0;0H"); | ||||
|       std::printf("(LEFT/RIGHT) x %.1f\n", x); | ||||
|       std::printf("(UP/DOWN)    y %.1f\n", y); | ||||
|       std::printf("(L/R)        z %.1f\n", z); | ||||
| 
 | ||||
|       Mtx_Persp(&projTex,  60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f, false); | ||||
|     } | ||||
| 
 | ||||
|     Mtx_Identity(&modelView); | ||||
|     Mtx_Translate(&modelView, x, y, z, true); | ||||
|     Mtx_RotateY(&modelView, angle*M_TAU/360.0f, true); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); | ||||
| 
 | ||||
|     angle += 1.0f; | ||||
|     if(angle >= 360.0f) | ||||
|       angle = 0.0f; | ||||
| 
 | ||||
|     C3D_FrameBegin(C3D_FRAME_SYNCDRAW); | ||||
| 
 | ||||
|     C3D_TexBind(0, &texture[0].tex); | ||||
| 
 | ||||
|     C3D_FrameDrawOn(tex); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projTex); | ||||
|     C3D_DrawArrays(GPU_TRIANGLES, 0, attribute_list_count); | ||||
| 
 | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projTop); | ||||
|     Mtx_Identity(&modelView); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); | ||||
| 
 | ||||
|     C3D_FrameDrawOn(top); | ||||
|     C3D_TexBind(0, &tex->renderBuf.colorBuf); | ||||
|     C3D_DrawArrays(GPU_TRIANGLES, 0, 6); | ||||
|     C3D_FrameEnd(0); | ||||
|   } | ||||
| 
 | ||||
|   C3D_RenderTargetDelete(top); | ||||
|   C3D_RenderTargetDelete(tex); | ||||
| } | ||||
| 
 | ||||
| void stereo_test() | ||||
| { | ||||
|   C3D_RenderTarget     *topLeft, *topRight, *texLeft, *texRight; | ||||
|   C3D_Mtx              projLeft, projRight, proj; | ||||
|   C3D_Mtx              modelView; | ||||
|   C3D_Mtx              texView; | ||||
|   float                x = 0.0f, y = 0.0f, z = -2.0f, | ||||
|                        old_x = x, old_y = y, old_z = z; | ||||
|   float                iod = osGet3DSliderState(), old_iod = iod; | ||||
|   float                focLen = 2.0f, old_focLen = focLen; | ||||
|   float                angle = 0.0f; | ||||
| 
 | ||||
|   gfxSet3D(true); | ||||
| 
 | ||||
|   topLeft  = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   topRight = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   C3D_RenderTargetSetClear(topLeft,  C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_RenderTargetSetClear(topRight, C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_RenderTargetSetOutput(topLeft,  GFX_TOP, GFX_LEFT,  DISPLAY_TRANSFER_FLAGS); | ||||
|   C3D_RenderTargetSetOutput(topRight, GFX_TOP, GFX_RIGHT, DISPLAY_TRANSFER_FLAGS); | ||||
| 
 | ||||
|   texLeft  = C3D_RenderTargetCreate(512, 256, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   texRight = C3D_RenderTargetCreate(512, 256, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   C3D_RenderTargetSetClear(texLeft,  C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_RenderTargetSetClear(texRight, C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_TexSetFilter(&texLeft->renderBuf.colorBuf, GPU_LINEAR, GPU_NEAREST); | ||||
|   C3D_TexSetFilter(&texRight->renderBuf.colorBuf, GPU_LINEAR, GPU_NEAREST); | ||||
| 
 | ||||
|   Mtx_PerspStereo(&projLeft,  60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f, -iod, focLen, false); | ||||
|   Mtx_PerspStereo(&projRight, 60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f,  iod, focLen, false); | ||||
| 
 | ||||
|   Mtx_Identity(&modelView); | ||||
|   Mtx_Translate(&modelView, x, y, z, true); | ||||
| 
 | ||||
|   Mtx_OrthoTilt(&proj, -0.5f, 0.5f, -0.5f, 0.5f, 100.0f, -100.0f, false); | ||||
|   Mtx_Identity(&texView); | ||||
| 
 | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView,  &modelView); | ||||
|   C3D_FVUnifMtx2x4(GPU_VERTEX_SHADER, uLoc_texView,    &texView); | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_material,   &material); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightVec,     0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightHalfVec, 0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr,     1.0f, 1.0f,  1.0f, 1.0f); | ||||
| 
 | ||||
|   std::printf("\x1b[2J"); | ||||
|   std::printf("(LEFT/RIGHT) x      %.1f\n", x); | ||||
|   std::printf("(UP/DOWN)    y      %.1f\n", y); | ||||
|   std::printf("(L/R)        z      %.1f\n", z); | ||||
|   std::printf("(Y/A)        focLen %.1f\n", focLen); | ||||
|   std::printf("(3D Slider)  iod    %.1f\n", iod); | ||||
| 
 | ||||
|   while(aptMainLoop()) | ||||
|   { | ||||
|     gspWaitForVBlank(); | ||||
| 
 | ||||
|     hidScanInput(); | ||||
|     u32 down = hidKeysDown(); | ||||
|     u32 held = hidKeysHeld(); | ||||
|     if(down & (KEY_START|KEY_SELECT)) | ||||
|       break; | ||||
| 
 | ||||
|     old_x      = x; | ||||
|     old_y      = y; | ||||
|     old_z      = z; | ||||
|     old_focLen = focLen; | ||||
|     old_iod    = iod; | ||||
| 
 | ||||
|     if((down | held) & KEY_LEFT) | ||||
|       x = clamp(x - 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_RIGHT) | ||||
|       x = clamp(x + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_UP) | ||||
|       y = clamp(y + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_DOWN) | ||||
|       y = clamp(y - 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_L) | ||||
|       z = clamp(z + 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_R) | ||||
|       z = clamp(z - 0.1f, -10.0f, 10.0f); | ||||
|     if((down | held) & KEY_Y) | ||||
|       focLen = clamp(focLen - 0.1f, 0.1f, 10.0f); | ||||
|     if((down | held) & KEY_A) | ||||
|       focLen = clamp(focLen + 0.1f, 0.1f, 10.0f); | ||||
| 
 | ||||
|     iod = osGet3DSliderState(); | ||||
| 
 | ||||
|     if((x != old_x) || (y != old_y) || (z != old_z) | ||||
|     || (focLen != old_focLen) || (iod != old_iod)) | ||||
|     { | ||||
|       std::printf("\x1b[0;0H"); | ||||
|       std::printf("(LEFT/RIGHT) x      %.1f\n", x); | ||||
|       std::printf("(UP/DOWN)    y      %.1f\n", y); | ||||
|       std::printf("(L/R)        z      %.1f\n", z); | ||||
|       std::printf("(Y/A)        focLen %.1f\n", focLen); | ||||
|       std::printf("(3D Slider)  iod    %.1f\n", iod); | ||||
| 
 | ||||
|       Mtx_PerspStereo(&projLeft,  60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f, -iod, focLen, false); | ||||
|       Mtx_PerspStereo(&projRight, 60.0f*M_TAU/360.0f, 400.0f/240.0f, 1.0f, 10.0f,  iod, focLen, false); | ||||
|     } | ||||
| 
 | ||||
|     Mtx_Identity(&modelView); | ||||
|     Mtx_Translate(&modelView, x, y, z, true); | ||||
|     Mtx_RotateY(&modelView, angle*M_TAU/360.0f, true); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); | ||||
| 
 | ||||
|     angle += 1.0f; | ||||
|     if(angle >= 360.0f) | ||||
|       angle = 0.0f; | ||||
| 
 | ||||
|     C3D_FrameBegin(C3D_FRAME_SYNCDRAW); | ||||
| 
 | ||||
|     C3D_TexBind(0, &texture[0].tex); | ||||
| 
 | ||||
|     C3D_FrameDrawOn(texLeft); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projLeft); | ||||
|     C3D_DrawArrays(GPU_TRIANGLES, 0, attribute_list_count); | ||||
| 
 | ||||
|     if(iod > 0.0f) | ||||
|     { | ||||
|       C3D_FrameDrawOn(texRight); | ||||
|       C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projRight); | ||||
|       C3D_DrawArrays(GPU_TRIANGLES, 0, attribute_list_count); | ||||
|     } | ||||
| 
 | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &proj); | ||||
|     Mtx_Identity(&modelView); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); | ||||
| 
 | ||||
|     C3D_FrameDrawOn(topLeft); | ||||
|     C3D_TexBind(0, &texLeft->renderBuf.colorBuf); | ||||
|     C3D_DrawArrays(GPU_TRIANGLES, 0, attribute_list_count); | ||||
|     if(iod > 0.0f) | ||||
|     { | ||||
|       C3D_FrameDrawOn(topRight); | ||||
|       C3D_TexBind(0, &texRight->renderBuf.colorBuf); | ||||
|       C3D_DrawArrays(GPU_TRIANGLES, 0, attribute_list_count); | ||||
|     } | ||||
|     C3D_FrameEnd(0); | ||||
|   } | ||||
| 
 | ||||
|   C3D_RenderTargetDelete(topLeft); | ||||
|   C3D_RenderTargetDelete(topRight); | ||||
|   C3D_RenderTargetDelete(texLeft); | ||||
|   C3D_RenderTargetDelete(texRight); | ||||
| 
 | ||||
|   gfxSet3D(false); | ||||
| } | ||||
| 
 | ||||
| void ortho_test() | ||||
| { | ||||
|   C3D_RenderTarget *top, *tex; | ||||
|   C3D_Mtx          projTop, projTex; | ||||
|   C3D_Mtx          modelView; | ||||
|   C3D_Mtx          texView; | ||||
|   float            x = 0.0f, y = 0.0f, z = -2.0f, | ||||
|                    old_x = x, old_y = y, old_z = z; | ||||
|   float            angle = 0.0f; | ||||
| 
 | ||||
|   top = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   C3D_RenderTargetSetClear(top, C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_RenderTargetSetOutput(top, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); | ||||
| 
 | ||||
|   tex = C3D_RenderTargetCreate(512, 256, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | ||||
|   C3D_RenderTargetSetClear(tex, C3D_CLEAR_ALL, CLEAR_COLOR, 0); | ||||
|   C3D_TexSetFilter(&tex->renderBuf.colorBuf, GPU_LINEAR, GPU_NEAREST); | ||||
| 
 | ||||
|   Mtx_Ortho(&projTex, 0.0f, 400.0f, 0.0f, 240.0f, 100.0f, -100.0f, false); | ||||
| 
 | ||||
|   Mtx_Identity(&modelView); | ||||
|   Mtx_Translate(&modelView, x, y, z, true); | ||||
| 
 | ||||
|   Mtx_OrthoTilt(&projTop, -0.5f, 0.5f, -0.5f, 0.5f, 100.0f, -100.0f, false); | ||||
|   Mtx_Identity(&texView); | ||||
| 
 | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView,  &modelView); | ||||
|   C3D_FVUnifMtx2x4(GPU_VERTEX_SHADER, uLoc_texView,    &texView); | ||||
|   C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_material,   &material); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightVec,     0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightHalfVec, 0.0f, 0.0f, -1.0f, 0.0f); | ||||
|   C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr,     1.0f, 1.0f,  1.0f, 1.0f); | ||||
| 
 | ||||
|   std::printf("\x1b[2J"); | ||||
|   std::printf("(LEFT/RIGHT) x %.1f\n", x); | ||||
|   std::printf("(UP/DOWN)    y %.1f\n", y); | ||||
|   std::printf("(L/R)        z %.1f\n", z); | ||||
| 
 | ||||
|   while(aptMainLoop()) | ||||
|   { | ||||
|     gspWaitForVBlank(); | ||||
| 
 | ||||
|     hidScanInput(); | ||||
|     u32 down = hidKeysDown(); | ||||
|     u32 held = hidKeysHeld(); | ||||
|     if(down & (KEY_START|KEY_SELECT)) | ||||
|       break; | ||||
| 
 | ||||
|     old_x      = x; | ||||
|     old_y      = y; | ||||
|     old_z      = z; | ||||
| 
 | ||||
|     if((down | held) & KEY_LEFT) | ||||
|       x = clamp(x - 1.0f, 0.0f, 400.0f); | ||||
|     if((down | held) & KEY_RIGHT) | ||||
|       x = clamp(x + 1.0f, 0.0f, 400.0f); | ||||
|     if((down | held) & KEY_UP) | ||||
|       y = clamp(y + 1.0f, 0.0f, 240.0f); | ||||
|     if((down | held) & KEY_DOWN) | ||||
|       y = clamp(y - 1.0f, 0.0f, 240.0f); | ||||
|     if((down | held) & KEY_L) | ||||
|       z = clamp(z + 1.0f, -100.0f, 100.0f); | ||||
|     if((down | held) & KEY_R) | ||||
|       z = clamp(z - 1.0f, -100.0f, 100.0f); | ||||
| 
 | ||||
|     if((x != old_x) || (y != old_y) || (z != old_z)) | ||||
|     { | ||||
|       std::printf("\x1b[0;0H"); | ||||
|       std::printf("(LEFT/RIGHT) x %.1f\n", x); | ||||
|       std::printf("(UP/DOWN)    y %.1f\n", y); | ||||
|       std::printf("(L/R)        z %.1f\n", z); | ||||
|     } | ||||
| 
 | ||||
|     Mtx_Identity(&modelView); | ||||
|     Mtx_Translate(&modelView, x, y, z, true); | ||||
|     Mtx_Scale(&modelView, 64.0f, 64.0f, 64.0f); | ||||
|     Mtx_RotateY(&modelView, angle*M_TAU/360.0f, true); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); | ||||
| 
 | ||||
|     angle += 1.0f; | ||||
|     if(angle >= 360.0f) | ||||
|       angle = 0.0f; | ||||
| 
 | ||||
|     C3D_FrameBegin(C3D_FRAME_SYNCDRAW); | ||||
| 
 | ||||
|     C3D_TexBind(0, &texture[0].tex); | ||||
| 
 | ||||
|     C3D_FrameDrawOn(tex); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projTex); | ||||
|     C3D_DrawArrays(GPU_TRIANGLES, 0, attribute_list_count); | ||||
| 
 | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projTop); | ||||
|     Mtx_Identity(&modelView); | ||||
|     C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); | ||||
| 
 | ||||
|     C3D_FrameDrawOn(top); | ||||
|     C3D_TexBind(0, &tex->renderBuf.colorBuf); | ||||
|     C3D_DrawArrays(GPU_TRIANGLES, 0, 6); | ||||
|     C3D_FrameEnd(0); | ||||
|   } | ||||
| 
 | ||||
|   C3D_RenderTargetDelete(top); | ||||
|   C3D_RenderTargetDelete(tex); | ||||
| } | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
|   const char *name; | ||||
|   void (*test)(); | ||||
| } test_t; | ||||
| 
 | ||||
| test_t tests[] = | ||||
| { | ||||
|   { "Mtx_PerspTilt",       persp_tilt_test,  }, | ||||
|   { "Mtx_OrthoTilt",       ortho_tilt_test,  }, | ||||
|   { "Mtx_PerspStereoTilt", stereo_tilt_test, }, | ||||
|   { "Mtx_Persp",           persp_test,       }, | ||||
|   { "Mtx_PerspStereo",     stereo_test,      }, | ||||
|   { "Mtx_Ortho",           ortho_test,       }, | ||||
| }; | ||||
| 
 | ||||
| const size_t num_tests = sizeof(tests)/sizeof(tests[0]); | ||||
| 
 | ||||
| void print_choices(size_t choice) | ||||
| { | ||||
|   std::printf("\x1b[2J"); | ||||
|   for(size_t i = 0; i < num_tests; ++i) | ||||
|     std::printf("\x1b[%zu;0H%c%s", i, i == choice ? '*' : ' ', tests[i].name); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
|   size_t          choice = 0; | ||||
|   shaderProgram_s program; | ||||
|   DVLB_s          *vsh_dvlb; | ||||
| 
 | ||||
|   romfsInit(); | ||||
|   gfxInitDefault(); | ||||
|   gfxSet3D(false); | ||||
|   consoleInit(GFX_BOTTOM, nullptr); | ||||
|   C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); | ||||
| 
 | ||||
|   shaderProgramInit(&program); | ||||
|   vsh_dvlb = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_size); | ||||
|   shaderProgramSetVsh(&program, &vsh_dvlb->DVLE[0]); | ||||
|   C3D_BindProgram(&program); | ||||
| 
 | ||||
|   sceneInit(&program); | ||||
| 
 | ||||
|   print_choices(choice); | ||||
|   while(aptMainLoop()) | ||||
|   {  | ||||
|     gfxFlushBuffers(); | ||||
|     gspWaitForVBlank(); | ||||
|     gfxSwapBuffers(); | ||||
| 
 | ||||
|     hidScanInput(); | ||||
|     u32 down = hidKeysDown(); | ||||
| 
 | ||||
|     if(down & KEY_UP) | ||||
|     { | ||||
|       choice = (choice + num_tests - 1) % num_tests; | ||||
|       print_choices(choice); | ||||
|     } | ||||
|     else if(down & KEY_DOWN) | ||||
|     { | ||||
|       choice = (choice + 1) % num_tests; | ||||
|       print_choices(choice); | ||||
|     } | ||||
|     else if(down & KEY_A) | ||||
|     { | ||||
|       tests[choice].test(); | ||||
|       print_choices(choice); | ||||
|     } | ||||
|     else if(down & KEY_B) | ||||
|       break; | ||||
|   } | ||||
| 
 | ||||
|   sceneExit(); | ||||
| 
 | ||||
|   shaderProgramFree(&program); | ||||
|   DVLB_Free(vsh_dvlb); | ||||
|   C3D_Fini(); | ||||
|   gfxExit(); | ||||
|   romfsExit(); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										89
									
								
								libs/citro3d/test/3ds/source/vshader.v.pica
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								libs/citro3d/test/3ds/source/vshader.v.pica
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,89 @@ | |||
| ; Example PICA200 vertex shader | ||||
| 
 | ||||
| ; Uniforms | ||||
| .fvec projection[4], modelView[4], texView[2] | ||||
| .fvec lightVec, lightHalfVec, lightClr, material[4] | ||||
| .alias mat_amb material[0] | ||||
| .alias mat_dif material[1] | ||||
| .alias mat_spe material[2] | ||||
| .alias mat_emi material[3] | ||||
| 
 | ||||
| ; Constants | ||||
| .constf myconst(0.0, 1.0, -1.0, -0.5) | ||||
| .alias  zeros myconst.xxxx ; Vector full of zeros | ||||
| .alias  ones  myconst.yyyy ; Vector full of ones | ||||
| 
 | ||||
| ; Outputs | ||||
| .out outpos position | ||||
| .out outtc0 texcoord0 | ||||
| .out outclr color | ||||
| 
 | ||||
| ; Inputs (defined as aliases for convenience) | ||||
| .alias inpos v0 | ||||
| .alias intex v1 | ||||
| .alias innrm v2 | ||||
| 
 | ||||
| .proc main | ||||
| 	; Force the w component of inpos to be 1.0 | ||||
| 	mov r0.xyz, inpos | ||||
| 	mov r0.w,   ones | ||||
| 
 | ||||
| 	; r1 = modelView * inpos | ||||
| 	dp4 r1.x, modelView[0], r0 | ||||
| 	dp4 r1.y, modelView[1], r0 | ||||
| 	dp4 r1.z, modelView[2], r0 | ||||
| 	dp4 r1.w, modelView[3], r0 | ||||
| 
 | ||||
| 	; outpos = projection * r1 | ||||
| 	dp4 outpos.x, projection[0], r1 | ||||
| 	dp4 outpos.y, projection[1], r1 | ||||
| 	dp4 outpos.z, projection[2], r1 | ||||
| 	dp4 outpos.w, projection[3], r1 | ||||
| 
 | ||||
| 	; outtex = intex | ||||
| 	dp4 outtc0.x, texView[0], intex | ||||
| 	dp4 outtc0.y, texView[1], intex | ||||
| 	mov outtc0.zw, myconst.xy | ||||
| 
 | ||||
| 	; Transform the normal vector with the modelView matrix | ||||
| 	; r1 = normalize(modelView * innrm) | ||||
| 	mov r0.xyz, innrm | ||||
| 	mov r0.w,   zeros | ||||
| 	dp4 r1.x,   modelView[0], r0 | ||||
| 	dp4 r1.y,   modelView[1], r0 | ||||
| 	dp4 r1.z,   modelView[2], r0 | ||||
| 	mov r1.w,   zeros | ||||
| 	dp3 r2,     r1, r1 ; r2 = x^2+y^2+z^2 for each component | ||||
| 	rsq r2,     r2     ; r2 = 1/sqrt(r2)  '' | ||||
| 	mul r1,     r2, r1 ; r1 = r1*r2 | ||||
| 
 | ||||
| 	; Calculate the diffuse level (r0.x) and the shininess level (r0.y) | ||||
| 	; r0.x = max(0, -(lightVec * r1)) | ||||
| 	; r0.y = max(0, (-lightHalfVec[i]) * r1) ^ 2 | ||||
| 	dp3 r0.x, lightVec,      r1 | ||||
| 	add r0.x, zeros,         -r0 | ||||
| 	dp3 r0.y, -lightHalfVec, r1 | ||||
| 	max r0,   zeros,         r0 | ||||
| 	mul r0.y, r0,            r0 | ||||
| 
 | ||||
| 	; Accumulate the vertex color in r1, initializing it to the emission color | ||||
| 	mov r1, mat_emi | ||||
| 
 | ||||
| 	; r1 += specularColor * lightClr * shininessLevel | ||||
| 	mul r2, lightClr, r0.yyyy | ||||
| 	mad r1, r2, mat_spe, r1 | ||||
| 
 | ||||
| 	; r1 += diffuseColor * lightClr * diffuseLevel | ||||
| 	mul r2, lightClr, r0.xxxx | ||||
| 	mad r1, r2, mat_dif, r1 | ||||
| 
 | ||||
| 	; r1 += ambientColor * lightClr | ||||
| 	mov r2, lightClr | ||||
| 	mad r1, r2, mat_amb, r1 | ||||
| 
 | ||||
| 	; outclr = clamp r1 to [0,1] | ||||
| 	min outclr, ones, r1 | ||||
| 
 | ||||
| 	; We're finished | ||||
| 	end | ||||
| .end | ||||
							
								
								
									
										5
									
								
								libs/citro3d/test/pc/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								libs/citro3d/test/pc/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| *.d | ||||
| *.o | ||||
| test | ||||
| coverage.info | ||||
| lcov/ | ||||
							
								
								
									
										42
									
								
								libs/citro3d/test/pc/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								libs/citro3d/test/pc/Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| TARGET   := test | ||||
| 
 | ||||
| CFILES   := $(wildcard *.c) $(wildcard ../../source/maths/*.c) | ||||
| CXXFILES := $(wildcard *.cpp) | ||||
| OFILES   := $(addprefix build/,$(CXXFILES:.cpp=.o)) \
 | ||||
|             $(patsubst ../../source/maths/%,build/%,$(CFILES:.c=.o)) | ||||
| DFILES   := $(wildcard build/*.d) | ||||
| 
 | ||||
| CFLAGS   := -Wall -g -pipe -I../../include --coverage | ||||
| CXXFLAGS := $(CFLAGS) -std=gnu++11 -DGLM_FORCE_RADIANS | ||||
| LDFLAGS  := $(ARCH) -pipe -lm --coverage | ||||
| 
 | ||||
| .PHONY: all clean lcov | ||||
| 
 | ||||
| all: $(TARGET) | ||||
| 
 | ||||
| $(TARGET): $(OFILES) | ||||
| 	@echo "Linking $@" | ||||
| 	$(CXX) -o $@ $^ $(LDFLAGS) | ||||
| 
 | ||||
| lcov: all | ||||
| 	@./$(TARGET) | ||||
| 	@lcov --capture --no-external --directory ../../include --directory ../../source --directory ../../test/pc --output-file coverage.info | ||||
| 	@genhtml coverage.info --output-directory lcov | ||||
| 
 | ||||
| $(OFILES): | build | ||||
| 
 | ||||
| build: | ||||
| 	@[ -d build ] || mkdir build | ||||
| 
 | ||||
| build/%.o : %.cpp $(wildcard *.h) | ||||
| 	@echo "Compiling $@" | ||||
| 	@$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF build/$*.d | ||||
| 
 | ||||
| build/%.o : ../../source/maths/%.c $(wildcard *.h) | ||||
| 	@echo "Compiling $@" | ||||
| 	@$(CC) -o $@ -c $< $(CFLAGS) -MMD -MP -MF build/$*.d | ||||
| 
 | ||||
| clean: | ||||
| 	$(RM) -r $(TARGET) build/ coverage.info lcov/ | ||||
| 
 | ||||
| -include $(DFILES) | ||||
							
								
								
									
										939
									
								
								libs/citro3d/test/pc/main.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										939
									
								
								libs/citro3d/test/pc/main.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,939 @@ | |||
| #include <cassert> | ||||
| #include <cmath> | ||||
| #include <cstdio> | ||||
| #include <cstdlib> | ||||
| #include <random> | ||||
| 
 | ||||
| #include <glm/glm.hpp> | ||||
| #include <glm/gtc/matrix_transform.hpp> | ||||
| #include <glm/gtc/quaternion.hpp> | ||||
| #include <glm/gtx/quaternion.hpp> | ||||
| 
 | ||||
| extern "C" { | ||||
| #include <c3d/maths.h> | ||||
| } | ||||
| 
 | ||||
| typedef std::default_random_engine            generator_t; | ||||
| typedef std::uniform_real_distribution<float> distribution_t; | ||||
| 
 | ||||
| static inline void | ||||
| randomMatrix(C3D_Mtx &m, generator_t &g, distribution_t &d) | ||||
| { | ||||
|   for(size_t i = 0; i < 16; ++i) | ||||
|     m.m[i] = d(g); | ||||
| } | ||||
| 
 | ||||
| static inline glm::vec3 | ||||
| randomVector3(generator_t &g, distribution_t &d) | ||||
| { | ||||
|   return glm::vec3(d(g), d(g), d(g)); | ||||
| } | ||||
| 
 | ||||
| static inline glm::vec4 | ||||
| randomVector4(generator_t &g, distribution_t &d) | ||||
| { | ||||
|   return glm::vec4(d(g), d(g), d(g), d(g)); | ||||
| } | ||||
| 
 | ||||
| static inline float | ||||
| randomAngle(generator_t &g, distribution_t &d) | ||||
| { | ||||
|   return d(g); | ||||
| } | ||||
| 
 | ||||
| static inline C3D_FQuat | ||||
| randomQuat(generator_t &g, distribution_t &d) | ||||
| { | ||||
|   return Quat_New(d(g), d(g), d(g), d(g)); | ||||
| } | ||||
| 
 | ||||
| static inline glm::mat4 | ||||
| loadMatrix(const C3D_Mtx &m) | ||||
| { | ||||
|   return glm::mat4(m.m[ 3], m.m[ 7], m.m[11], m.m[15], | ||||
|                    m.m[ 2], m.m[ 6], m.m[10], m.m[14], | ||||
|                    m.m[ 1], m.m[ 5], m.m[ 9], m.m[13], | ||||
|                    m.m[ 0], m.m[ 4], m.m[ 8], m.m[12]); | ||||
| } | ||||
| 
 | ||||
| static inline glm::quat | ||||
| loadQuat(const C3D_FQuat &q) | ||||
| { | ||||
|   return glm::quat(q.r, q.i, q.j, q.k); | ||||
| } | ||||
| 
 | ||||
| static inline bool | ||||
| operator==(const glm::vec3 &lhs, const C3D_FVec &rhs) | ||||
| { | ||||
|   return std::abs(lhs.x - rhs.x) < 0.001f | ||||
|       && std::abs(lhs.y - rhs.y) < 0.001f | ||||
|       && std::abs(lhs.z - rhs.z) < 0.001f; | ||||
| } | ||||
| 
 | ||||
| static inline bool | ||||
| operator==(const C3D_FVec &lhs, const glm::vec3 &rhs) | ||||
| { | ||||
|   return rhs == lhs; | ||||
| } | ||||
| 
 | ||||
| static inline bool | ||||
| operator==(const glm::vec4 &lhs, const C3D_FVec &rhs) | ||||
| { | ||||
|   return std::abs(lhs.x - rhs.x) < 0.001f | ||||
|       && std::abs(lhs.y - rhs.y) < 0.001f | ||||
|       && std::abs(lhs.z - rhs.z) < 0.001f | ||||
|       && std::abs(lhs.w - rhs.w) < 0.001f; | ||||
| } | ||||
| 
 | ||||
| static inline bool | ||||
| operator==(const C3D_FVec &lhs, const glm::vec4 &rhs) | ||||
| { | ||||
|   return rhs == lhs; | ||||
| } | ||||
| 
 | ||||
| static inline bool | ||||
| operator==(const glm::mat4 &lhs, const C3D_Mtx &rhs) | ||||
| { | ||||
|   for(size_t i = 0; i < 4; ++i) | ||||
|   { | ||||
|     for(size_t j = 0; j < 4; ++j) | ||||
|     { | ||||
|       if(std::abs(lhs[i][j] - rhs.m[j*4+3-i]) > 0.001f) | ||||
|         return false; // LCOV_EXCL_LINE This would cause an assertion failure
 | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| static inline bool | ||||
| operator==(const C3D_Mtx &lhs, const glm::mat4 &rhs) | ||||
| { | ||||
|   return rhs == lhs; | ||||
| } | ||||
| 
 | ||||
| static inline bool | ||||
| operator==(const glm::quat &lhs, const C3D_FQuat &rhs) | ||||
| { | ||||
|   return std::abs(lhs.w - rhs.r) < 0.01f | ||||
|       && std::abs(lhs.x - rhs.i) < 0.01f | ||||
|       && std::abs(lhs.y - rhs.j) < 0.01f | ||||
|       && std::abs(lhs.z - rhs.k) < 0.01f; | ||||
| } | ||||
| 
 | ||||
| static inline bool | ||||
| operator==(const C3D_FQuat &lhs, const glm::quat &rhs) | ||||
| { | ||||
|   return rhs == lhs; | ||||
| } | ||||
| 
 | ||||
| static inline bool | ||||
| operator==(const C3D_FQuat &lhs, const C3D_FQuat &rhs) | ||||
| { | ||||
|   return std::abs(lhs.r - rhs.r) < 0.01f | ||||
|       && std::abs(lhs.i - rhs.i) < 0.01f | ||||
|       && std::abs(lhs.j - rhs.j) < 0.01f | ||||
|       && std::abs(lhs.k - rhs.k) < 0.01f; | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| print(const C3D_FVec &v) | ||||
| { | ||||
|   std::printf("%s:\n", __PRETTY_FUNCTION__); | ||||
|   std::printf("% 6.4f % 6.4f % 6.4f % 6.4f\n", v.w, v.x, v.y, v.z); | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| print(const glm::vec3 &v) | ||||
| { | ||||
|   std::printf("%s:\n", __PRETTY_FUNCTION__); | ||||
|   std::printf("% 6.4f % 6.4f % 6.4f\n", v.x, v.y, v.z); | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| print(const glm::vec4 &v) | ||||
| { | ||||
|   std::printf("%s:\n", __PRETTY_FUNCTION__); | ||||
|   std::printf("%6.4f % 6.4f % 6.4f % 6.4f\n", v.w, v.x, v.y, v.z); | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| print(const C3D_Mtx &m) | ||||
| { | ||||
|   std::printf("%s:\n", __PRETTY_FUNCTION__); | ||||
|   for(size_t j = 0; j < 4; ++j) | ||||
|   { | ||||
|     std::printf("% 6.4f % 6.4f % 6.4f % 6.4f\n", | ||||
|                 m.m[j*4+3], | ||||
|                 m.m[j*4+2], | ||||
|                 m.m[j*4+1], | ||||
|                 m.m[j*4+0]); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| print(const glm::mat4 &m) | ||||
| { | ||||
|   std::printf("%s:\n", __PRETTY_FUNCTION__); | ||||
|   for(size_t j = 0; j < 4; ++j) | ||||
|   { | ||||
|     std::printf("% 6.4f % 6.4f % 6.4f % 6.4f\n", | ||||
|                 m[0][j], | ||||
|                 m[1][j], | ||||
|                 m[2][j], | ||||
|                 m[3][j]); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| print(const glm::quat &q) | ||||
| { | ||||
|   std::printf("%s:\n", __PRETTY_FUNCTION__); | ||||
|   std::printf("% 6.4f % 6.4f % 6.4f % 6.4f\n", q.w, q.x, q.y, q.z); | ||||
| } | ||||
| 
 | ||||
| static const glm::vec3 x_axis(1.0f, 0.0f, 0.0f); | ||||
| static const glm::vec3 y_axis(0.0f, 1.0f, 0.0f); | ||||
| static const glm::vec3 z_axis(0.0f, 0.0f, 1.0f); | ||||
| static const glm::vec3 z_flip(1.0f, 1.0f, -1.0f); | ||||
| 
 | ||||
| static void | ||||
| check_matrix(generator_t &gen, distribution_t &dist) | ||||
| { | ||||
| 
 | ||||
|   glm::mat4 fix_depth(1.0f, 0.0f,  0.0f, 0.0f, | ||||
|                       0.0f, 1.0f,  0.0f, 0.0f, | ||||
|                       0.0f, 0.0f,  0.5f, 0.0f, | ||||
|                       0.0f, 0.0f, -0.5f, 1.0f); | ||||
|   glm::mat4 tilt = glm::rotate(glm::mat4(), -static_cast<float>(M_TAU)/4.0f, z_axis); | ||||
| 
 | ||||
|   // check identity
 | ||||
|   { | ||||
|     C3D_Mtx m; | ||||
|     Mtx_Identity(&m); | ||||
|     assert(m == glm::mat4()); | ||||
|   } | ||||
| 
 | ||||
|   // ortho nominal cases
 | ||||
|   { | ||||
|     C3D_Mtx  m; | ||||
|     C3D_FVec v; | ||||
|     float    l = 0.0f, | ||||
|              r = 400.0f, | ||||
|              b = 0.0f, | ||||
|              t = 320.0f, | ||||
|              n = 0.0f, | ||||
|              f = 100.0f; | ||||
| 
 | ||||
|     Mtx_Ortho(&m, l, r, b, t, n, f, false); | ||||
| 
 | ||||
|     // check near clip plane
 | ||||
|     v = Mtx_MultiplyFVecH(&m, FVec3_New((r-l)/2.0f, (t-b)/2.0f, -n)); | ||||
|     v = FVec4_PerspDivide(v); | ||||
|     assert(v == FVec4_New(0.0f, 0.0f, -1.0f, 1.0f)); | ||||
| 
 | ||||
|     // check far clip plane
 | ||||
|     v = Mtx_MultiplyFVecH(&m, FVec3_New((r-l)/2.0f, (t-b)/2.0f, -f)); | ||||
|     v = FVec4_PerspDivide(v); | ||||
|     assert(v == FVec4_New(0.0f, 0.0f, 0.0f, 1.0f)); | ||||
|   } | ||||
| 
 | ||||
|   // perspective nominal cases
 | ||||
|   { | ||||
|     C3D_Mtx  m; | ||||
|     C3D_FVec v; | ||||
|     float   fovy   = C3D_Angle(60.0f/360.0f), | ||||
|             aspect = C3D_AspectRatioTop, | ||||
|             near   = 0.1f, | ||||
|             far    = 10.0f; | ||||
| 
 | ||||
|     Mtx_Persp(&m, fovy, aspect, near, far, false); | ||||
| 
 | ||||
|     // check near clip plane
 | ||||
|     v = Mtx_MultiplyFVecH(&m, FVec3_New(0.0f, 0.0f, -near)); | ||||
|     v = FVec4_PerspDivide(v); | ||||
|     assert(v == FVec4_New(0.0f, 0.0f, -1.0f, 1.0f)); | ||||
| 
 | ||||
|     // check far clip plane
 | ||||
|     v = Mtx_MultiplyFVecH(&m, FVec3_New(0.0f, 0.0f, -far)); | ||||
|     v = FVec4_PerspDivide(v); | ||||
|     assert(v == FVec4_New(0.0f, 0.0f, 0.0f, 1.0f)); | ||||
|   } | ||||
| 
 | ||||
|   for(size_t x = 0; x < 10000; ++x) | ||||
|   { | ||||
|     // check inverse
 | ||||
|     { | ||||
|       C3D_Mtx m, inv, id; | ||||
| 
 | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       // cast to int to try to avoid assertion failure due to rounding error
 | ||||
|       for(size_t i = 0; i < 16; ++i) | ||||
|         m.m[i] = static_cast<int>(m.m[i]); | ||||
| 
 | ||||
|       Mtx_Copy(&inv, &m); | ||||
|       if(Mtx_Inverse(&inv)) | ||||
|       { | ||||
|         Mtx_Multiply(&id, &m, &inv); | ||||
|         assert(id == glm::mat4()); // could still fail due to rounding errors
 | ||||
|         Mtx_Multiply(&id, &inv, &m); | ||||
|         assert(id == glm::mat4()); // could still fail due to rounding errors
 | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // check perspective
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       float   fovy   = dist(gen), | ||||
|               aspect = dist(gen), | ||||
|               near   = dist(gen), | ||||
|               far    = dist(gen), | ||||
|               fovx; | ||||
| 
 | ||||
|       while(aspect < 0.25f || aspect > 4.0f) | ||||
|         aspect = dist(gen); | ||||
| 
 | ||||
|       while(fovy < M_TAU / 36.0f | ||||
|          || fovy >= M_TAU / 2.0f | ||||
|          || (fovx = 2.0f * atanf(tanf(fovy/2.0f) * aspect)) < M_TAU / 36.0f | ||||
|          || fovx >= M_TAU / 2.0f) | ||||
|       { | ||||
|         fovy = dist(gen); | ||||
|       } | ||||
| 
 | ||||
|       while(std::abs(far - near) < 0.1f) | ||||
|         far = dist(gen); | ||||
| 
 | ||||
|       // RH
 | ||||
|       Mtx_Persp(&m, fovy, aspect, near, far, false); | ||||
|       glm::mat4 g = glm::perspective(fovy, aspect, near, far); | ||||
|       assert(m == fix_depth*g); | ||||
| 
 | ||||
|       // LH
 | ||||
|       Mtx_Persp(&m, fovy, aspect, near, far, true); | ||||
|       g = glm::perspective(fovy, aspect, near, far); | ||||
|       assert(m == fix_depth*glm::scale(g, z_flip)); | ||||
|     } | ||||
| 
 | ||||
|     // check perspective tilt
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       float   fovy   = dist(gen), | ||||
|               aspect = dist(gen), | ||||
|               near   = dist(gen), | ||||
|               far    = dist(gen), | ||||
|               fovx; | ||||
| 
 | ||||
|       while(aspect < 0.25f || aspect > 4.0f) | ||||
|         aspect = dist(gen); | ||||
| 
 | ||||
|       while(fovy < M_TAU / 36.0f | ||||
|          || fovy >= M_TAU / 2.0f | ||||
|          || (fovx = 2.0f * atanf(tanf(fovy/2.0f) * aspect)) < M_TAU / 36.0f | ||||
|          || fovx >= M_TAU / 2.0f) | ||||
|       { | ||||
|         fovy = dist(gen); | ||||
|       } | ||||
| 
 | ||||
|       while(std::abs(far - near) < 0.1f) | ||||
|         far = dist(gen); | ||||
| 
 | ||||
|       // RH
 | ||||
|       Mtx_PerspTilt(&m, fovy, aspect, near, far, false); | ||||
|       glm::mat4 g = glm::perspective(fovx, 1.0f / aspect, near, far); | ||||
|       assert(m == fix_depth*g*tilt); | ||||
| 
 | ||||
|       // LH
 | ||||
|       Mtx_PerspTilt(&m, fovy, aspect, near, far, true); | ||||
|       g = glm::perspective(fovx, 1.0f / aspect, near, far); | ||||
|       assert(m == fix_depth*glm::scale(g, z_flip)*tilt); | ||||
|     } | ||||
| 
 | ||||
|     // check perspective stereo
 | ||||
|     { | ||||
|       C3D_Mtx left, right; | ||||
|       float   fovy   = dist(gen), | ||||
|               aspect = dist(gen), | ||||
|               near   = dist(gen), | ||||
|               far    = dist(gen), | ||||
|               iod    = dist(gen), | ||||
|               focLen = dist(gen), | ||||
|               fovy_tan, | ||||
|               fovx; | ||||
| 
 | ||||
|       while(aspect < 0.25f || aspect > 4.0f) | ||||
|         aspect = dist(gen); | ||||
| 
 | ||||
|       while(fovy < M_TAU / 36.0f | ||||
|          || fovy >= M_TAU / 2.0f | ||||
|          || (fovx = 2.0f * atanf(tanf(fovy/2.0f) * aspect)) < M_TAU / 36.0f | ||||
|          || fovx >= M_TAU / 2.0f) | ||||
|       { | ||||
|         fovy = dist(gen); | ||||
|       } | ||||
| 
 | ||||
|       while(std::abs(far - near) < 0.1f) | ||||
|         far = dist(gen); | ||||
| 
 | ||||
|       while(focLen < 0.25f) | ||||
|         focLen = dist(gen); | ||||
| 
 | ||||
|       glm::mat4 g = glm::perspective(fovy, aspect, near, far); | ||||
| 
 | ||||
|       fovy_tan = tanf(fovy/2.0f); | ||||
|       glm::mat4 left_eye (1.0f, 0.0f, 0.0f, 0.0f, | ||||
|                           0.0f, 1.0f, 0.0f, 0.0f, | ||||
|                           iod/(focLen*2.0f), 0.0f, 1.0f, 0.0f, | ||||
|                           iod*fovy_tan*aspect/2.0f, 0.0f, 0.0f, 1.0f); | ||||
|       glm::mat4 right_eye(1.0f, 0.0f, 0.0f, 0.0f, | ||||
|                           0.0f, 1.0f, 0.0f, 0.0f, | ||||
|                           -iod/(focLen*2.0f), 0.0f, 1.0f, 0.0f, | ||||
|                           -iod*fovy_tan*aspect/2.0f, 0.0f, 0.0f, 1.0f); | ||||
| 
 | ||||
|       // RH
 | ||||
|       Mtx_PerspStereo(&left, fovy, aspect, near, far, -iod, focLen, false); | ||||
|       Mtx_PerspStereo(&right, fovy, aspect, near, far, iod, focLen, false); | ||||
|       assert(left == fix_depth*g*left_eye); | ||||
|       assert(right == fix_depth*g*right_eye); | ||||
| 
 | ||||
|       // LH
 | ||||
|       Mtx_PerspStereo(&left, fovy, aspect, near, far, -iod, focLen, true); | ||||
|       Mtx_PerspStereo(&right, fovy, aspect, near, far, iod, focLen, true); | ||||
|       assert(left == fix_depth*glm::scale(g*left_eye, z_flip)); | ||||
|       assert(right == fix_depth*glm::scale(g*right_eye, z_flip)); | ||||
|     } | ||||
| 
 | ||||
|     // check perspective stereo tilt
 | ||||
|     { | ||||
|       C3D_Mtx left, right; | ||||
|       float   fovy   = dist(gen), | ||||
|               aspect = dist(gen), | ||||
|               near   = dist(gen), | ||||
|               far    = dist(gen), | ||||
|               iod    = dist(gen), | ||||
|               focLen = dist(gen), | ||||
|               fovx, | ||||
|               fovx_tan; | ||||
| 
 | ||||
|       while(aspect < 0.25f || aspect > 4.0f) | ||||
|         aspect = dist(gen); | ||||
| 
 | ||||
|       while(fovy < M_TAU / 36.0f | ||||
|          || fovy >= M_TAU / 2.0f | ||||
|          || (fovx = 2.0f * atanf(tanf(fovy/2.0f) * aspect)) < M_TAU / 36.0f | ||||
|          || fovx >= M_TAU / 2.0f) | ||||
|       { | ||||
|         fovy = dist(gen); | ||||
|       } | ||||
| 
 | ||||
|       while(std::abs(far - near) < 0.1f) | ||||
|         far = dist(gen); | ||||
| 
 | ||||
|       while(focLen < 0.25f) | ||||
|         focLen = dist(gen); | ||||
| 
 | ||||
|       glm::mat4 g = glm::perspective(fovx, 1.0f / aspect, near, far); | ||||
| 
 | ||||
|       fovx_tan = tanf(fovx/2.0f); | ||||
|       glm::mat4 left_eye (1.0f, 0.0f, 0.0f, 0.0f, | ||||
|                           0.0f, 1.0f, 0.0f, 0.0f, | ||||
|                           0.0f, -iod/(focLen*2.0f), 1.0f, 0.0f, | ||||
|                           0.0f, -iod*fovx_tan/2.0f, 0.0f, 1.0f); | ||||
|       glm::mat4 right_eye(1.0f, 0.0f, 0.0f, 0.0f, | ||||
|                           0.0f, 1.0f, 0.0f, 0.0f, | ||||
|                           0.0f, iod/(focLen*2.0f), 1.0f, 0.0f, | ||||
|                           0.0f, iod*fovx_tan/2.0f, 0.0f, 1.0f); | ||||
| 
 | ||||
|       // RH
 | ||||
|       Mtx_PerspStereoTilt(&left, fovy, aspect, near, far, -iod, focLen, false); | ||||
|       Mtx_PerspStereoTilt(&right, fovy, aspect, near, far, iod, focLen, false); | ||||
|       assert(left == fix_depth*g*left_eye*tilt); | ||||
|       assert(right == fix_depth*g*right_eye*tilt); | ||||
| 
 | ||||
|       // LH
 | ||||
|       Mtx_PerspStereoTilt(&left, fovy, aspect, near, far, -iod, focLen, true); | ||||
|       Mtx_PerspStereoTilt(&right, fovy, aspect, near, far, iod, focLen, true); | ||||
|       assert(left == fix_depth*glm::scale(g*left_eye, z_flip)*tilt); | ||||
|       assert(right == fix_depth*glm::scale(g*right_eye, z_flip)*tilt); | ||||
|     } | ||||
| 
 | ||||
|     // check ortho
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       float   l = dist(gen), | ||||
|               r = dist(gen), | ||||
|               b = dist(gen), | ||||
|               t = dist(gen), | ||||
|               n = dist(gen), | ||||
|               f = dist(gen); | ||||
| 
 | ||||
|       while(std::abs(r-l) < 0.1f) | ||||
|         r = dist(gen); | ||||
| 
 | ||||
|       while(std::abs(t-b) < 0.1f) | ||||
|         t = dist(gen); | ||||
| 
 | ||||
|       while(std::abs(f-n) < 0.1f) | ||||
|         f = dist(gen); | ||||
| 
 | ||||
|       // RH
 | ||||
|       Mtx_Ortho(&m, l, r, b, t, n, f, false); | ||||
|       glm::mat4 g = glm::ortho(l, r, b, t, n, f); | ||||
|       assert(m == fix_depth*g); | ||||
| 
 | ||||
|       // LH
 | ||||
|       Mtx_Ortho(&m, l, r, b, t, n, f, true); | ||||
|       g = glm::ortho(l, r, b, t, n, f); | ||||
|       assert(m == fix_depth*glm::scale(g, z_flip)); | ||||
|     } | ||||
| 
 | ||||
|     // check ortho tilt
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       float   l = dist(gen), | ||||
|               r = dist(gen), | ||||
|               b = dist(gen), | ||||
|               t = dist(gen), | ||||
|               n = dist(gen), | ||||
|               f = dist(gen); | ||||
| 
 | ||||
|       while(std::abs(r-l) < 0.1f) | ||||
|         r = dist(gen); | ||||
| 
 | ||||
|       while(std::abs(t-b) < 0.1f) | ||||
|         t = dist(gen); | ||||
| 
 | ||||
|       while(std::abs(f-n) < 0.1f) | ||||
|         f = dist(gen); | ||||
| 
 | ||||
|       // RH
 | ||||
|       Mtx_OrthoTilt(&m, l, r, b, t, n, f, false); | ||||
|       glm::mat4 g = glm::ortho(l, r, b, t, n, f); | ||||
|       assert(m == tilt*fix_depth*g); | ||||
| 
 | ||||
|       // LH
 | ||||
|       Mtx_OrthoTilt(&m, l, r, b, t, n, f, true); | ||||
|       g = glm::ortho(l, r, b, t, n, f); | ||||
|       assert(m == tilt*fix_depth*glm::scale(g, z_flip)); | ||||
|     } | ||||
| 
 | ||||
|     // check lookAt
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       C3D_FVec camera, target, diff, up; | ||||
| 
 | ||||
|       // avoid very small distances and 'up' pointing near the target
 | ||||
|       do | ||||
|       { | ||||
|         camera = FVec3_New(dist(gen), dist(gen), dist(gen)); | ||||
|         target = FVec3_New(dist(gen), dist(gen), dist(gen)); | ||||
|         up     = FVec3_New(dist(gen), dist(gen), dist(gen)); | ||||
|         diff   = FVec3_Subtract(target, camera); | ||||
|       } while(FVec3_Magnitude(diff) < 0.25f | ||||
|            || FVec3_Magnitude(up) < 0.25f | ||||
|            || FVec3_Dot(up, diff) / FVec3_Magnitude(up) / FVec3_Magnitude(diff) < cosf(30.0f*M_TAU/360.0f)); | ||||
| 
 | ||||
|       glm::mat4 g = glm::lookAt(glm::vec3(camera.x, camera.y, camera.z), | ||||
|                                 glm::vec3(target.x, target.y, target.z), | ||||
|                                 glm::vec3(up.x,     up.y,     up.z)); | ||||
| 
 | ||||
|       // RH
 | ||||
|       Mtx_LookAt(&m, camera, target, up, false); | ||||
|       assert(m == g); | ||||
| 
 | ||||
|       // LH
 | ||||
|       Mtx_LookAt(&m, camera, target, up, true); | ||||
|       // I can't say for certain that this is the correct test
 | ||||
|       assert(m == glm::scale(glm::mat4(), glm::vec3(-1.0f, 1.0f, -1.0f))*g); | ||||
|     } | ||||
| 
 | ||||
|     // check multiply
 | ||||
|     { | ||||
|       C3D_Mtx m1, m2; | ||||
|       randomMatrix(m1, gen, dist); | ||||
|       randomMatrix(m2, gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g1 = loadMatrix(m1); | ||||
|       glm::mat4 g2 = loadMatrix(m2); | ||||
| 
 | ||||
|       C3D_Mtx result; | ||||
|       Mtx_Multiply(&result, &m1, &m2); | ||||
|       assert(result == g1*g2); | ||||
|     } | ||||
| 
 | ||||
|     // check translate
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
|       glm::vec3 v = randomVector3(gen, dist); | ||||
| 
 | ||||
|       Mtx_Translate(&m, v.x, v.y, v.z, true); | ||||
|       assert(m == glm::translate(g, v)); | ||||
|     } | ||||
| 
 | ||||
|     // check translate (reversed)
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
|       glm::vec3 v = randomVector3(gen, dist); | ||||
| 
 | ||||
|       Mtx_Translate(&m, v.x, v.y, v.z, false); | ||||
|       assert(m == glm::translate(glm::mat4(), v)*g); | ||||
|     } | ||||
| 
 | ||||
|     // check scale
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
|       glm::vec3 v = randomVector3(gen, dist); | ||||
| 
 | ||||
|       Mtx_Scale(&m, v.x, v.y, v.z); | ||||
|       assert(m == glm::scale(g, v)); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       float r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
|       glm::vec3 v = randomVector3(gen, dist); | ||||
| 
 | ||||
|       Mtx_Rotate(&m, FVec3_New(v.x, v.y, v.z), r, true); | ||||
|       assert(m == glm::rotate(g, r, v)); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate (reversed)
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       float r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
|       glm::vec3 v = randomVector3(gen, dist); | ||||
| 
 | ||||
|       Mtx_Rotate(&m, FVec3_New(v.x, v.y, v.z), r, false); | ||||
|       assert(m == glm::rotate(glm::mat4(), r, v)*g); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate X
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       float r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
| 
 | ||||
|       Mtx_RotateX(&m, r, true); | ||||
|       assert(m == glm::rotate(g, r, x_axis)); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate X (reversed)
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       float r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
| 
 | ||||
|       Mtx_RotateX(&m, r, false); | ||||
|       assert(m == glm::rotate(glm::mat4(), r, x_axis)*g); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate Y
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       float r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
| 
 | ||||
|       Mtx_RotateY(&m, r, true); | ||||
|       assert(m == glm::rotate(g, r, y_axis)); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate Y (reversed)
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       float r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
| 
 | ||||
|       Mtx_RotateY(&m, r, false); | ||||
|       assert(m == glm::rotate(glm::mat4(), r, y_axis)*g); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate Z
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       float r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
| 
 | ||||
|       Mtx_RotateZ(&m, r, true); | ||||
|       assert(m == glm::rotate(g, r, z_axis)); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate Z (reversed)
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       float r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
| 
 | ||||
|       Mtx_RotateZ(&m, r, false); | ||||
|       assert(m == glm::rotate(glm::mat4(), r, z_axis)*g); | ||||
|     } | ||||
| 
 | ||||
|     // check vec3 multiply
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
|       glm::vec3 v = randomVector3(gen, dist); | ||||
| 
 | ||||
|       assert(Mtx_MultiplyFVec3(&m, FVec3_New(v.x, v.y, v.z)) == glm::mat3x3(g)*v); | ||||
|     } | ||||
| 
 | ||||
|     // check vec4 multiply
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
|       glm::vec4 v = randomVector4(gen, dist); | ||||
| 
 | ||||
|       assert(Mtx_MultiplyFVec4(&m, FVec4_New(v.x, v.y, v.z, v.w)) == g*v); | ||||
|     } | ||||
| 
 | ||||
|     // check vecH multiply
 | ||||
|     { | ||||
|       C3D_Mtx m; | ||||
|       randomMatrix(m, gen, dist); | ||||
| 
 | ||||
|       glm::mat4 g = loadMatrix(m); | ||||
|       glm::vec4 v = randomVector4(gen, dist); | ||||
|       v.w = 1.0f; | ||||
| 
 | ||||
|       assert(Mtx_MultiplyFVecH(&m, FVec3_New(v.x, v.y, v.z)) == glm::mat4x3(g)*v); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| check_quaternion(generator_t &gen, distribution_t &dist) | ||||
| { | ||||
|   // check identity
 | ||||
|   { | ||||
|     C3D_FQuat q = Quat_Identity(); | ||||
|     glm::quat g; | ||||
| 
 | ||||
|     assert(q == g); | ||||
|   } | ||||
| 
 | ||||
|   for(size_t x = 0; x < 10000; ++x) | ||||
|   { | ||||
|     // check negation
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       assert(Quat_Negate(q) == -g); | ||||
|     } | ||||
| 
 | ||||
|     // check addition
 | ||||
|     { | ||||
|       C3D_FQuat q1 = randomQuat(gen, dist); | ||||
|       C3D_FQuat q2 = randomQuat(gen, dist); | ||||
| 
 | ||||
|       glm::quat g1 = loadQuat(q1); | ||||
|       glm::quat g2 = loadQuat(q2); | ||||
| 
 | ||||
|       assert(Quat_Add(q1, q2) == g1+g2); | ||||
|     } | ||||
| 
 | ||||
|     // check subtraction
 | ||||
|     { | ||||
|       C3D_FQuat q1 = randomQuat(gen, dist); | ||||
|       C3D_FQuat q2 = randomQuat(gen, dist); | ||||
| 
 | ||||
|       glm::quat g1 = loadQuat(q1); | ||||
|       glm::quat g2 = loadQuat(q2); | ||||
| 
 | ||||
|       assert(Quat_Subtract(q1, q2) == g1 + (-g2)); | ||||
|     } | ||||
| 
 | ||||
|     // check scale
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       float f = dist(gen); | ||||
| 
 | ||||
|       assert(Quat_Scale(q, f) == g*f); | ||||
|     } | ||||
| 
 | ||||
|     // check normalize
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       assert(Quat_Normalize(q) == glm::normalize(g)); | ||||
|     } | ||||
| 
 | ||||
|     // check dot
 | ||||
|     { | ||||
|       C3D_FQuat q1 = randomQuat(gen, dist); | ||||
|       C3D_FQuat q2 = randomQuat(gen, dist); | ||||
|       glm::quat g1 = loadQuat(q1); | ||||
|       glm::quat g2 = loadQuat(q2); | ||||
| 
 | ||||
|       assert(std::abs(Quat_Dot(q1, q2) - glm::dot(g1, g2)) < 0.0001f); | ||||
|     } | ||||
| 
 | ||||
|     // check conjugate
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       assert(Quat_Conjugate(q) == glm::conjugate(g)); | ||||
|     } | ||||
| 
 | ||||
|     // check inverse
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       assert(Quat_Inverse(q) == glm::inverse(g)); | ||||
|     } | ||||
| 
 | ||||
|     // check quaternion multiplication
 | ||||
|     { | ||||
|       C3D_FQuat q1 = randomQuat(gen, dist); | ||||
|       C3D_FQuat q2 = randomQuat(gen, dist); | ||||
|       glm::quat g1 = loadQuat(q1); | ||||
|       glm::quat g2 = loadQuat(q2); | ||||
| 
 | ||||
|       assert(Quat_Multiply(q1, q2) == g1*g2); | ||||
|     } | ||||
| 
 | ||||
|     // check quat pow()
 | ||||
|     // Note: older versions of glm have broken pow() for quats
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       //glm::quat g = loadQuat(q);
 | ||||
|       float     r = dist(gen); | ||||
| 
 | ||||
|       //assert(Quat_Pow(q, r) == glm::pow(g, r));
 | ||||
| 
 | ||||
|       q = Quat_Normalize(q); | ||||
| 
 | ||||
|       // check trivial cases
 | ||||
|       assert(Quat_Pow(q, 1.0f) == q); | ||||
|       assert(Quat_Pow(q, 0.0f) == Quat_Identity()); | ||||
|       assert(Quat_Pow(Quat_Identity(), r) == Quat_Identity()); | ||||
| 
 | ||||
|       // validate semantics
 | ||||
|       assert(Quat_Pow(q, r) == Quat_Multiply(Quat_Pow(q, r/2), Quat_Pow(q, r/2))); | ||||
|     } | ||||
| 
 | ||||
|     // check vector multiplication (cross)
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       glm::vec3 v = randomVector3(gen, dist); | ||||
| 
 | ||||
|       assert(Quat_CrossFVec3(q, FVec3_New(v.x, v.y, v.z)) == glm::cross(g, v)); | ||||
|       assert(FVec3_CrossQuat(FVec3_New(v.x, v.y, v.z), q) == glm::cross(v, g)); | ||||
|     } | ||||
| 
 | ||||
|     // check rotation
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       glm::vec3 v = randomVector3(gen, dist); | ||||
|       float     r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       assert(Quat_Rotate(q, FVec3_New(v.x, v.y, v.z), r, false) == glm::rotate(g, r, v)); | ||||
|       assert(Quat_Rotate(q, FVec3_New(v.x, v.y, v.z), r, true) == glm::rotate(glm::quat(), r, v)*g); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate X
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       float     r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       assert(Quat_RotateX(q, r, false) == glm::rotate(g, r, x_axis)); | ||||
|       assert(Quat_RotateX(q, r, true) == glm::rotate(glm::quat(), r, x_axis)*g); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate Y
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       float     r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       assert(Quat_RotateY(q, r, false) == glm::rotate(g, r, y_axis)); | ||||
|       assert(Quat_RotateY(q, r, true) == glm::rotate(glm::quat(), r, y_axis)*g); | ||||
|     } | ||||
| 
 | ||||
|     // check rotate Z
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       float     r = randomAngle(gen, dist); | ||||
| 
 | ||||
|       assert(Quat_RotateZ(q, r, false) == glm::rotate(g, r, z_axis)); | ||||
|       assert(Quat_RotateZ(q, r, true) == glm::rotate(glm::quat(), r, z_axis)*g); | ||||
|     } | ||||
| 
 | ||||
|     // check conversion to matrix
 | ||||
|     { | ||||
|       C3D_FQuat q = randomQuat(gen, dist); | ||||
|       glm::quat g = loadQuat(q); | ||||
| 
 | ||||
|       C3D_Mtx m; | ||||
|       Mtx_FromQuat(&m, q); | ||||
| 
 | ||||
|       assert(m == glm::mat4_cast(g)); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
|   std::random_device rd; | ||||
|   generator_t        gen(rd()); | ||||
|   distribution_t     dist(-10.0f, 10.0f); | ||||
| 
 | ||||
|   check_matrix(gen, dist); | ||||
|   check_quaternion(gen, dist); | ||||
| 
 | ||||
|   return EXIT_SUCCESS; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Firew0lf
						Firew0lf