1
0
Fork 0
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:
Firew0lf 2016-08-05 17:30:24 +02:00
parent 68a44645f7
commit 49c87e5526
97 changed files with 7341 additions and 944 deletions

View 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
#---------------------------------------------------------------------------------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

View 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;
}

View 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
View file

@ -0,0 +1,5 @@
*.d
*.o
test
coverage.info
lcov/

View 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)

View 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;
}