diff --git a/examples/graphics/hello_triangle/Makefile b/examples/graphics/hello_triangle/Makefile new file mode 100644 index 0000000..150cce9 --- /dev/null +++ b/examples/graphics/hello_triangle/Makefile @@ -0,0 +1,170 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +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. +# 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): +# - .png +# - icon.png +# - /default_icon.png +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard + +CFLAGS := -g -Wall -Wfatal-errors -O2 -mword-relocations \ + -fomit-frame-pointer -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM11 -D_3DS + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lctru -lm + +#--------------------------------------------------------------------------------- +# 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)/$(TARGET) +export TOPDIR := $(CURDIR) + +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) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +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 + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +ifeq ($(strip $(NO_SMDH)),) +.PHONY: all +all : $(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) + +# WARNING: This is not the right way to do this! TODO: Do it right! +#--------------------------------------------------------------------------------- +%.vsh.o : %.vsh +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + picasso ../$(notdir $<).shbin $< + @bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@ + @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h + @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h + @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h + @rm ../$(notdir $<).shbin + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/examples/graphics/hello_triangle/README.md b/examples/graphics/hello_triangle/README.md new file mode 100644 index 0000000..00535b6 --- /dev/null +++ b/examples/graphics/hello_triangle/README.md @@ -0,0 +1,4 @@ +Hello Triangle + +A simple GPU demo to display a white triangle. +Requires the [picasso](https://github.com/fincs/picasso) shader assembler. \ No newline at end of file diff --git a/examples/graphics/hello_triangle/data/shader.vsh b/examples/graphics/hello_triangle/data/shader.vsh new file mode 100644 index 0000000..d86c35a --- /dev/null +++ b/examples/graphics/hello_triangle/data/shader.vsh @@ -0,0 +1,32 @@ +; Really simple & stupid PICA200 shader +; Taken from picasso example + +; Uniforms +.fvec projection[4] + +; Constants +.constf myconst(0.0, 1.0, -1.0, 0.0) +.alias ones myconst.yyyy ; (1.0,1.0,1.0,1.0) + +; Outputs : here only position and color +.out outpos position +.out outclr color + +; Inputs : here we have only vertices +.alias inpos v0 + +.proc main + ; r0 = (inpos.x, inpos.y, inpos.z, 1.0) + mov r0.xyz, inpos + mov r0.w, ones + + ; outpos = projection * r1 + dp4 outpos.x, projection[0], r0 + dp4 outpos.y, projection[1], r0 + dp4 outpos.z, projection[2], r0 + dp4 outpos.w, projection[3], r0 + + ; Set vertex color to white + mov outclr, ones + end +.end \ No newline at end of file diff --git a/examples/graphics/hello_triangle/source/3dutils.c b/examples/graphics/hello_triangle/source/3dutils.c new file mode 100644 index 0000000..45215b8 --- /dev/null +++ b/examples/graphics/hello_triangle/source/3dutils.c @@ -0,0 +1,31 @@ +// +// Created by Lectem on 22/03/2015. +// + +#include "3dutils.h" + +void SetUniformMatrix(u32 startreg, float* m) { + float param[16]; + + param[0x0]=m[3]; //w + param[0x1]=m[2]; //z + param[0x2]=m[1]; //y + param[0x3]=m[0]; //x + + param[0x4]=m[7]; + param[0x5]=m[6]; + param[0x6]=m[5]; + param[0x7]=m[4]; + + param[0x8]=m[11]; + param[0x9]=m[10]; + param[0xa]=m[9]; + param[0xb]=m[8]; + + param[0xc]=m[15]; + param[0xd]=m[14]; + param[0xe]=m[13]; + param[0xf]=m[12]; + + GPU_SetFloatUniform(GPU_VERTEX_SHADER, startreg, (u32*)param, 4); +} diff --git a/examples/graphics/hello_triangle/source/3dutils.h b/examples/graphics/hello_triangle/source/3dutils.h new file mode 100644 index 0000000..9e3f859 --- /dev/null +++ b/examples/graphics/hello_triangle/source/3dutils.h @@ -0,0 +1,10 @@ +// +// Created by Lectem on 22/03/2015. +// + +#ifndef _2DGPU_3DUTILS_H_ +#define _2DGPU_3DUTILS_H_ +#include <3ds.h> +void SetUniformMatrix(u32 startreg, float* m); + +#endif //_2DGPU_3DUTILS_H_ diff --git a/examples/graphics/hello_triangle/source/main.c b/examples/graphics/hello_triangle/source/main.c new file mode 100644 index 0000000..fe6f25a --- /dev/null +++ b/examples/graphics/hello_triangle/source/main.c @@ -0,0 +1,246 @@ +#include <3ds.h> +#include +#include +#include +#include "shader_vsh_shbin.h" +#include "3dutils.h" +#include "mmath.h" + + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define LINE_STRING STRINGIZE(__LINE__) +#define my_assert(e) ((e) ? (void)0 : _my_assert("assert failed at " __FILE__ ":" LINE_STRING " (" #e ")\n")) +void _my_assert(char * text) +{ + printf("%s\n",text); + do{ + hidScanInput(); + if(keysDown()&KEY_START)break; + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank(); + }while(aptMainLoop()); + exit(0); +} + + + + +typedef struct { + float x, y, z; +} vector_3f; + + +typedef struct { + float r, g, b, a; +} vector_4f; + +typedef struct { + vector_3f position; + vector_4f color; +} vertex_pos_col; + +#define GPU_CMD_SIZE 0x40000 + +//GPU framebuffer address +u32* gpuFBuffer =(u32*)0x1F119400; +//GPU depth buffer address +u32* gpuDBuffer =(u32*)0x1F370800; + +//GPU command buffers +u32* gpuCmd = NULL; + +//shader structure +DVLB_s* shader_dvlb; //the header +shaderProgram_s shader; //the program + + +Result projUniformRegister =-1; +Result modelviewUniformRegister =-1; + +#define RGBA8(r,g,b,a) ((((r)&0xFF)<<24) | (((g)&0xFF)<<16) | (((b)&0xFF)<<8) | (((a)&0xFF)<<0)) + +//The color used to clear the screen +u32 clearColor=RGBA8(0x68, 0xB0, 0xD8, 0xFF); + +//The projection matrix +static float ortho_matrix[4*4]; + +void GPU_SetDummyTexEnv(u8 num); +void gpuUIEndFrame(); + +void gpuUIInit() +{ + + GPU_Init(NULL);//initialize GPU + + gfxSet3D(false);//We will not be using the 3D mode in this example + Result res=0; + + /** + * Load our vertex shader and its uniforms + * Check http://3dbrew.org/wiki/SHBIN for more informations about the shader binaries + */ + shader_dvlb = DVLB_ParseFile((u32 *)shader_vsh_shbin, shader_vsh_shbin_size);//load our vertex shader binary + my_assert(shader_dvlb != NULL); + shaderProgramInit(&shader); + res = shaderProgramSetVsh(&shader, &shader_dvlb->DVLE[0]); + my_assert(res >=0); // check for errors + + //In this example we are only rendering in "2D mode", so we don't need one command buffer per eye + gpuCmd=(u32*)linearAlloc(GPU_CMD_SIZE * (sizeof *gpuCmd) ); //Don't forget that commands size is 4 (hence the sizeof) + my_assert(gpuCmd != NULL); + + //Reset the gpu + //This actually needs a command buffer to work, and will then use it as default + GPU_Reset(NULL, gpuCmd, GPU_CMD_SIZE); + + projUniformRegister = shaderInstanceGetUniformLocation(shader.vertexShader, "projection"); + my_assert(projUniformRegister != -1); // make sure we did get the uniform + + + shaderProgramUse(&shader); // Select the shader to use + + + + initOrthographicMatrix(ortho_matrix, 0.0f, 400.0f, 0.0f, 240.0f, 0.0f, 1.0f); // A basic projection for 2D drawings + SetUniformMatrix(projUniformRegister, ortho_matrix); // Upload the matrix to the GPU + + //Flush buffers and setup the environment for the next frame + gpuUIEndFrame(); + +} + +void gpuUIExit() +{ + //do things properly + linearFree(gpuCmd); + shaderProgramFree(&shader); + DVLB_Free(shader_dvlb); + GPU_Reset(NULL, gpuCmd, GPU_CMD_SIZE); // Not really needed, but safer for the next applications ? +} + +void gpuUIEndFrame() +{ + //Ask the GPU to draw everything (execute the commands) + GPU_FinishDrawing(); + GPUCMD_Finalize(); + GPUCMD_FlushAndRun(NULL); + gspWaitForP3D(); + //Draw the screen + GX_SetDisplayTransfer(NULL, gpuFBuffer, 0x019001E0, (u32*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 0x019001E0, 0x01001000); + gspWaitForPPF(); + //Clear the screen + GX_SetMemoryFill(NULL, gpuFBuffer, clearColor, &gpuFBuffer[0x2EE00], + 0x201, gpuDBuffer, 0x00000000, &gpuDBuffer[0x2EE00], 0x201); + gspWaitForPSC0(); + gfxSwapBuffersGpu(); + + //Wait for the screen to be updated + gspWaitForVBlank(); + + //Get ready to start a new frame + GPUCMD_SetBufferOffset(0); + + //Viewport (http://3dbrew.org/wiki/GPU_Commands#Command_0x0041) + GPU_SetViewport((u32 *)osConvertVirtToPhys((u32)gpuDBuffer), + (u32 *)osConvertVirtToPhys((u32)gpuFBuffer), + 0, 0, 240*2, 400); //Our screen is 400*240, and we actually have 2 framebuffers, even without 3D mode activated + + + GPU_DepthMap(-1.0f, 0.0f); //Be careful, standard OpenGL clipping is [-1;1], but it is [-1;0] on the pica200 + // Note : this is corrected by our projection matrix ! + + //Sets the texture environment parameters not to modify our pixels at fragment stage + //See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight + GPU_SetTexEnv( + 0, + GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR), + GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR), + GPU_TEVOPERANDS(0,0,0), + GPU_TEVOPERANDS(0,0,0), + GPU_REPLACE, GPU_REPLACE, + 0xFFFFFFFF + ); + GPU_SetDummyTexEnv(1); + GPU_SetDummyTexEnv(2); + GPU_SetDummyTexEnv(3); + GPU_SetDummyTexEnv(4); + GPU_SetDummyTexEnv(5); +} + + + +//Our data +static const vector_3f triangle_mesh[] = + { + {240.0f+60.0f, 120.0f, 0.5f}, + {240.0f-60.0f, 120.0f+60.0f, 0.5f}, + {240.0f-60.0f, 120.0f-60.0f, 0.5f} + }; + +static void* triangle_data = NULL; + +int main(int argc, char** argv) +{ + + srvInit(); + aptInit(); + hidInit(NULL); + + gfxInitDefault(); + consoleInit(GFX_BOTTOM, NULL); + + + gpuUIInit(); + printf("hello triangle !\n"); + triangle_data = linearAlloc(sizeof(triangle_mesh)); //allocate our vbo on the linear heap + memcpy(triangle_data, triangle_mesh, sizeof(triangle_mesh)); //Copy our data + + do{ + hidScanInput(); + if(keysDown()&KEY_START)break; //Stop the program when Start is pressed + + //Setup the buffers data + GPU_SetAttributeBuffers( + 1, // number of attributes + (u32 *) osConvertVirtToPhys((u32) triangle_data), + GPU_ATTRIBFMT(0, 3, GPU_FLOAT),//We only have vertices + 0xFFFE,//Attribute mask, in our case 0b1110 + 0x0,//Attribute permutations (here it is the identity) + 1, //number of buffers + (u32[]) {0x0}, // buffer offsets (placeholders) + (u64[]) {0x0}, // attribute permutations for each buffer (identity again) + (u8[]) {1} // number of attributes for each buffer + ); + //Display the buffers data + GPU_DrawArray(GPU_TRIANGLES, sizeof(triangle_mesh) / sizeof(triangle_mesh[0])); + + gpuUIEndFrame(); + + }while(aptMainLoop()); + gpuUIExit(); + + + gfxExit(); + hidExit(); + aptExit(); + srvExit(); + + return 0; +} + + +void GPU_SetDummyTexEnv(u8 num) +{ + //Don't touch the colors of the previous stages + GPU_SetTexEnv(num, + GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0), + GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0), + GPU_TEVOPERANDS(0,0,0), + GPU_TEVOPERANDS(0,0,0), + GPU_REPLACE, + GPU_REPLACE, + 0xFFFFFFFF); +} \ No newline at end of file diff --git a/examples/graphics/hello_triangle/source/mmath.c b/examples/graphics/hello_triangle/source/mmath.c new file mode 100644 index 0000000..e7715d1 --- /dev/null +++ b/examples/graphics/hello_triangle/source/mmath.c @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include <3ds.h> +#include "mmath.h" + +void loadIdentity44(float* m) +{ + if(!m)return; + + memset(m, 0x00, 16*4); + m[0]=m[5]=m[10]=m[15]=1.0f; +} + +void multMatrix44(float* m1, float* m2, float* m) //4x4 +{ + int i, j; + for(i=0;i<4;i++)for(j=0;j<4;j++)m[i+j*4]=(m1[0+j*4]*m2[i+0*4])+(m1[1+j*4]*m2[i+1*4])+(m1[2+j*4]*m2[i+2*4])+(m1[3+j*4]*m2[i+3*4]); + +} + +void translateMatrix(float* tm, float x, float y, float z) +{ + float rm[16], m[16]; + + loadIdentity44(rm); + rm[3]=x; + rm[7]=y; + rm[11]=z; + + multMatrix44(tm,rm,m); + memcpy(tm,m,16*sizeof(float)); +} + +// 00 01 02 03 +// 04 05 06 07 +// 08 09 10 11 +// 12 13 14 15 + +void rotateMatrixX(float* tm, float x, bool r) +{ + float rm[16], m[16]; + memset(rm, 0x00, 16*4); + rm[0]=1.0f; + rm[5]=cos(x); + rm[6]=sin(x); + rm[9]=-sin(x); + rm[10]=cos(x); + rm[15]=1.0f; + if(!r)multMatrix44(tm,rm,m); + else multMatrix44(rm,tm,m); + memcpy(tm,m,16*sizeof(float)); +} + +void rotateMatrixY(float* tm, float x, bool r) +{ + float rm[16], m[16]; + memset(rm, 0x00, 16*4); + rm[0]=cos(x); + rm[2]=sin(x); + rm[5]=1.0f; + rm[8]=-sin(x); + rm[10]=cos(x); + rm[15]=1.0f; + if(!r)multMatrix44(tm,rm,m); + else multMatrix44(rm,tm,m); + memcpy(tm,m,16*sizeof(float)); +} + +void rotateMatrixZ(float* tm, float x, bool r) +{ + float rm[16], m[16]; + memset(rm, 0x00, 16*4); + rm[0]=cos(x); + rm[1]=sin(x); + rm[4]=-sin(x); + rm[5]=cos(x); + rm[10]=1.0f; + rm[15]=1.0f; + if(!r)multMatrix44(tm,rm,m); + else multMatrix44(rm,tm,m); + memcpy(tm,m,16*sizeof(float)); +} + +void scaleMatrix(float* tm, float x, float y, float z) +{ + tm[0]*=x; tm[4]*=x; tm[8]*=x; tm[12]*=x; + tm[1]*=y; tm[5]*=y; tm[9]*=y; tm[13]*=y; + tm[2]*=z; tm[6]*=z; tm[10]*=z; tm[14]*=z; +} + +void initProjectionMatrix(float* m, float fovy, float aspect, float near, float far) +{ + float top = near*tan(fovy/2); + float right = (top*aspect); + + float mp[4*4]; + + mp[0x0] = near/right; + mp[0x1] = 0.0f; + mp[0x2] = 0.0f; + mp[0x3] = 0.0f; + + mp[0x4] = 0.0f; + mp[0x5] = near/top; + mp[0x6] = 0.0f; + mp[0x7] = 0.0f; + + mp[0x8] = 0.0f; + mp[0x9] = 0.0f; + mp[0xA] = -(far+near)/(far-near); + mp[0xB] = -2.0f*(far*near)/(far-near); + + mp[0xC] = 0.0f; + mp[0xD] = 0.0f; + mp[0xE] = -1.0f; + mp[0xF] = 0.0f; + + float mp2[4*4]; + loadIdentity44(mp2); + mp2[0xA]=0.5; + mp2[0xB]=-0.5; + + multMatrix44(mp2, mp, m); +} + +void initOrthographicMatrix(float *m, float left, float right, float bottom, float top, float near, float far) +{ + /* ______________________ + | | + | | + | | + | | + | | + |______________________| ^ + | x + <----- + y + */ + + //Mirror + //right = 400-right; + //left = 400-left; + //top = 240-top; + //bottom = 240-bottom; + + float mp[4*4]; + + mp[0x0] = 2.0f/(right-left); + mp[0x1] = 0.0f; + mp[0x2] = 0.0f; + mp[0x3] = -(right+left)/(right-left); + + mp[0x4] = 0.0f; + mp[0x5] = 2.0f/(top-bottom); + mp[0x6] = 0.0f; + mp[0x7] = -(top+bottom)/(top-bottom); + + mp[0x8] = 0.0f; + mp[0x9] = 0.0f; + mp[0xA] = -2.0f/(far-near); + mp[0xB] = (far+near)/(far-near); + + mp[0xC] = 0.0f; + mp[0xD] = 0.0f; + mp[0xE] = 0.0f; + mp[0xF] = 1.0f; + + float mp2[4*4]; + loadIdentity44(mp2); + mp2[0xA] = 0.5; + mp2[0xB] = -0.5; + + //Convert Z [-1, 1] to [-1, 0] (PICA shiz) + multMatrix44(mp2, mp, m); + + //rotateMatrixZ(m, M_PI/2, false); +} + +vect3Df_s getMatrixColumn(float* m, u8 i) +{ + if(!m || i>=4)return vect3Df(0,0,0); + return vect3Df(m[0+i*4],m[1+i*4],m[2+i*4]); +} + +vect3Df_s getMatrixRow(float* m, u8 i) +{ + if(!m || i>=4)return vect3Df(0,0,0); + return vect3Df(m[i+0*4],m[i+1*4],m[i+2*4]); +} + +vect4Df_s getMatrixColumn4(float* m, u8 i) +{ + if(!m || i>=4)return vect4Df(0,0,0,0); + return vect4Df(m[0+i*4],m[1+i*4],m[2+i*4],m[3+i*4]); +} + +vect4Df_s getMatrixRow4(float* m, u8 i) +{ + if(!m || i>=4)return vect4Df(0,0,0,0); + return vect4Df(m[i+0*4],m[i+1*4],m[i+2*4],m[i+3*4]); +} diff --git a/examples/graphics/hello_triangle/source/mmath.h b/examples/graphics/hello_triangle/source/mmath.h new file mode 100644 index 0000000..370b3c2 --- /dev/null +++ b/examples/graphics/hello_triangle/source/mmath.h @@ -0,0 +1,152 @@ +#ifndef MATH_H +#define MATH_H +#ifdef __cplusplus +extern "C" { +#endif +#include <3ds/types.h> +#include +#pragma GCC diagnostic ignored "-Wnarrowing" + + +typedef float mtx44[4][4]; +typedef float mtx33[3][3]; + +typedef struct +{ + s32 x, y, z; +}vect3Di_s; + +static inline vect3Di_s vect3Di(s32 x, s32 y, s32 z) +{ + return (vect3Di_s){x,y,z}; +} + +static inline vect3Di_s vaddi(vect3Di_s u, vect3Di_s v) +{ + return (vect3Di_s){u.x+v.x,u.y+v.y,u.z+v.z}; +} + +static inline vect3Di_s vsubi(vect3Di_s u, vect3Di_s v) +{ + return (vect3Di_s){u.x-v.x,u.y-v.y,u.z-v.z}; +} + +static inline vect3Di_s vmuli(vect3Di_s v, s32 f) +{ + return (vect3Di_s){v.x*f,v.y*f,v.z*f}; +} + +typedef struct +{ + float x, y, z; +}vect3Df_s; + +static inline vect3Df_s vect3Df(float x, float y, float z) +{ + return (vect3Df_s){x,y,z}; +} + +static inline vect3Df_s vaddf(vect3Df_s u, vect3Df_s v) +{ + return (vect3Df_s){u.x+v.x,u.y+v.y,u.z+v.z}; +} + +static inline vect3Df_s vsubf(vect3Df_s u, vect3Df_s v) +{ + return (vect3Df_s){u.x-v.x,u.y-v.y,u.z-v.z}; +} + +static inline vect3Df_s vmulf(vect3Df_s v, float f) +{ + return (vect3Df_s){v.x*f,v.y*f,v.z*f}; +} + +static inline vect3Df_s vscalef(vect3Df_s v1, vect3Df_s v2) +{ + return (vect3Df_s){v1.x*v2.x,v1.y*v2.y,v1.z*v2.z}; +} + +static inline float vmagf(vect3Df_s v) +{ + return sqrtf(v.x*v.x+v.y*v.y+v.z*v.z); +} + +static inline float vdistf(vect3Df_s v1, vect3Df_s v2) +{ + return sqrtf((v1.x-v2.x)*(v1.x-v2.x)+(v1.y-v2.y)*(v1.y-v2.y)+(v1.z-v2.z)*(v1.z-v2.z)); +} + +static inline vect3Df_s vnormf(vect3Df_s v) +{ + const float l=sqrtf(v.x*v.x+v.y*v.y+v.z*v.z); + return (vect3Df_s){v.x/l,v.y/l,v.z/l}; +} + +typedef struct +{ + float x, y, z, w; +}vect4Df_s; + +static inline vect4Df_s vect4Df(float x, float y, float z, float w) +{ + return (vect4Df_s){x,y,z,w}; +} + +static inline vect4Df_s vaddf4(vect4Df_s u, vect4Df_s v) +{ + return (vect4Df_s){u.x+v.x,u.y+v.y,u.z+v.z,u.w+v.w}; +} + +static inline vect4Df_s vsubf4(vect4Df_s u, vect4Df_s v) +{ + return (vect4Df_s){u.x-v.x,u.y-v.y,u.z-v.z,u.w-v.w}; +} + +static inline vect4Df_s vmulf4(vect4Df_s v, float f) +{ + return (vect4Df_s){v.x*f,v.y*f,v.z*f,v.w*f}; +} + +static inline float vdotf4(vect4Df_s v1, vect4Df_s v2) +{ + return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z+v1.w*v2.w; +} + +static inline vect4Df_s vnormf4(vect4Df_s v) +{ + const float l=sqrtf(v.x*v.x+v.y*v.y+v.z*v.z+v.w*v.w); + return (vect4Df_s){v.x/l,v.y/l,v.z/l,v.w/l}; +} + +//interstuff +static inline vect3Di_s vf2i(vect3Df_s v) +{ + return (vect3Di_s){floorf(v.x),floorf(v.y),floorf(v.z)}; +} + +static inline vect3Df_s vi2f(vect3Di_s v) +{ + return (vect3Df_s){(float)v.x,(float)v.y,(float)v.z}; +} + +void loadIdentity44(float* m); +void multMatrix44(float* m1, float* m2, float* m); + +void translateMatrix(float* tm, float x, float y, float z); +void rotateMatrixX(float* tm, float x, bool r); +void rotateMatrixY(float* tm, float x, bool r); +void rotateMatrixZ(float* tm, float x, bool r); +void scaleMatrix(float* tm, float x, float y, float z); + +void initProjectionMatrix(float* m, float fovy, float aspect, float near, float far); +void initOrthographicMatrix(float *m, float left, float right, float bottom, float top, float near, float far); + + +vect3Df_s getMatrixColumn(float* m, u8 i); +vect3Df_s getMatrixRow(float* m, u8 i); +vect4Df_s getMatrixColumn4(float* m, u8 i); +vect4Df_s getMatrixRow4(float* m, u8 i); +#ifdef __cplusplus +} +#endif +#endif