initial commit

This commit is contained in:
Shylie 2023-04-08 12:51:11 -04:00
commit 85641231c2
4 changed files with 688 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
rt.*
build/
.vs/

255
Makefile Normal file
View File

@ -0,0 +1,255 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>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
# GRAPHICS is a list of directories containing graphics files
# GFXBUILD is the directory where converted graphics files will be placed
# If set to $(BUILD), it will statically link in the converted
# files as if they were data 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 := $(notdir $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
GRAPHICS := gfx
GFXBUILD := $(BUILD)
#ROMFS := romfs
#GFXBUILD := $(ROMFS)/gfx
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
CFLAGS := -g -Wall -O2 -mword-relocations \
-ffunction-sections \
$(ARCH)
CFLAGS += $(INCLUDE) -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 := -lcitro3d -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,$(GRAPHICS),$(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)))
PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica)))
SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist)))
GFXFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.t3s)))
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
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------
ifeq ($(GFXBUILD),$(BUILD))
#---------------------------------------------------------------------------------
export T3XFILES := $(GFXFILES:.t3s=.t3x)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export ROMFS_T3XFILES := $(patsubst %.t3s, $(GFXBUILD)/%.t3x, $(GFXFILES))
export T3XHFILES := $(patsubst %.t3s, $(BUILD)/%.h, $(GFXFILES))
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES_BIN := $(addsuffix .o,$(BINFILES)) \
$(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o) \
$(addsuffix .o,$(T3XFILES))
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES)
export HFILES := $(PICAFILES:.v.pica=_shbin.h) $(SHLISTFILES:.shlist=_shbin.h) \
$(addsuffix .h,$(subst .,_,$(BINFILES))) \
$(GFXFILES:.t3s=.h)
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)
export _3DSXDEPS := $(if $(NO_SMDH),,$(OUTPUT).smdh)
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: all clean
#---------------------------------------------------------------------------------
all: $(BUILD) $(GFXBUILD) $(DEPSDIR) $(ROMFS_T3XFILES) $(T3XHFILES)
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
$(BUILD):
@mkdir -p $@
ifneq ($(GFXBUILD),$(BUILD))
$(GFXBUILD):
@mkdir -p $@
endif
ifneq ($(DEPSDIR),$(BUILD))
$(DEPSDIR):
@mkdir -p $@
endif
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf $(GFXBUILD)
#---------------------------------------------------------------------------------
$(GFXBUILD)/%.t3x $(BUILD)/%.h : %.t3s
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@tex3ds -i $< -H $(BUILD)/$*.h -d $(DEPSDIR)/$*.d -o $(GFXBUILD)/$*.t3x
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).3dsx : $(OUTPUT).elf $(_3DSXDEPS)
$(OFILES_SOURCES) : $(HFILES)
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
.PRECIOUS : %.t3x
#---------------------------------------------------------------------------------
%.t3x.o %_t3x.h : %.t3x
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
# rules for assembling GPU shaders
#---------------------------------------------------------------------------------
define shader-as
$(eval CURBIN := $*.shbin)
$(eval DEPSFILE := $(DEPSDIR)/$*.shbin.d)
echo "$(CURBIN).o: $< $1" > $(DEPSFILE)
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
picasso -o $(CURBIN) $1
bin2s $(CURBIN) | $(AS) -o $*.shbin.o
endef
%.shbin.o %_shbin.h : %.v.pica %.g.pica
@echo $(notdir $^)
@$(call shader-as,$^)
%.shbin.o %_shbin.h : %.v.pica
@echo $(notdir $<)
@$(call shader-as,$<)
%.shbin.o %_shbin.h : %.shlist
@echo $(notdir $<)
@$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)$(file)))
#---------------------------------------------------------------------------------
%.t3x %.h : %.t3s
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@tex3ds -i $< -H $*.h -d $*.d -o $*.t3x
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

259
source/main.cpp Normal file
View File

@ -0,0 +1,259 @@
#include <3ds.h>
#include <citro3d.h>
#include "vshader_shbin.h"
constexpr u32 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);
constexpr u32 CLEAR_COLOR = 0;
struct vertex
{
float direction[3];
float coords[3];
};
class camera
{
public:
camera(const C3D_FVec lookfrom, const C3D_FVec lookat, const C3D_FVec vup, const float vfov, const float aspectRatio)
{
const float theta = C3D_AngleFromDegrees(vfov);
const float h = tanf(theta / 2.0f);
const float viewportHeight = 2.0f * h;
const float viewportWidth = aspectRatio * viewportHeight;
const C3D_FVec w = FVec3_Normalize(FVec3_Subtract(lookfrom, lookat));
const C3D_FVec u = FVec3_Normalize(FVec3_Cross(vup, w));
const C3D_FVec v = FVec3_Cross(w, u);
origin = lookfrom;
horizontal = FVec3_Scale(u, viewportWidth);
vertical = FVec3_Scale(v, viewportHeight);
lowerLeftCorner = FVec3_Subtract(FVec3_Add(FVec3_Scale(horizontal, -0.5f), FVec3_Scale(vertical, -0.5f)), w);
}
C3D_FVec getOrigin() const
{
return origin;
}
void setupVertices(vertex* vs, const unsigned int w, const unsigned int h) const
{
for (unsigned int x = 0; x < w; x++)
{
for (unsigned int y = 0; y < h; y++)
{
getRay(vs[x + y * w], static_cast<float>(x) / (w - 1), static_cast<float>(y) / (h - 1));
}
}
}
private:
C3D_FVec origin;
C3D_FVec lowerLeftCorner;
C3D_FVec horizontal;
C3D_FVec vertical;
void getRay(vertex& v, const float s, const float t) const
{
const C3D_FVec dir = FVec3_Add(lowerLeftCorner, FVec3_Add(FVec3_Scale(horizontal, t), FVec3_Scale(vertical, s)));
v.direction[0] = dir.x;
v.direction[1] = dir.y;
v.direction[2] = dir.z;
v.coords[0] = 2.0f * s - 1.0f;
v.coords[1] = 2.0f * t - 1.0f;
v.coords[2] = -0.5f;
}
};
static DVLB_s* vshaderDVLB;
static shaderProgram_s program;
static s8 spheresUniformLocation;
static constexpr unsigned int VERTEX_COUNT_W = 150;
static constexpr unsigned int VERTEX_COUNT_H = 250;
static constexpr unsigned int VERTEX_COUNT = VERTEX_COUNT_W * VERTEX_COUNT_H;
static vertex vertexList[VERTEX_COUNT];
static u16 vertexIndices[VERTEX_COUNT * 2 + VERTEX_COUNT_H * 2];
static void* vboData;
static void* iboData;
static void setupVertices(C3D_FVec lookFrom, C3D_FVec lookAt, C3D_FVec up)
{
constexpr float VFOV = 90;
constexpr float ASPECT_RATIO = 400.0f / 240.0f;
camera cam(lookFrom, lookAt, up, VFOV, ASPECT_RATIO);
cam.setupVertices(vertexList, VERTEX_COUNT_W, VERTEX_COUNT_H);
*C3D_FixedAttribGetWritePtr(0) = cam.getOrigin();
memcpy(vboData, vertexList, sizeof(vertexList));
}
static void sceneInit()
{
vboData = linearAlloc(sizeof(vertexList));
camera cam(FVec3_New(0, 0.25f, 0), FVec3_New(0, 0, -1), FVec3_New(0, 1, 0), 90, 400.0f / 240.0f);
cam.setupVertices(vertexList, VERTEX_COUNT_W, VERTEX_COUNT_H);
unsigned int v = 0;
for (unsigned int y = 0; y < VERTEX_COUNT_H; y++)
{
vertexIndices[v++] = y * VERTEX_COUNT_W;
for (unsigned int x = 0; x < VERTEX_COUNT_W; x++)
{
vertexIndices[v++] = y * VERTEX_COUNT_W + x;
vertexIndices[v++] = (y + 1) * VERTEX_COUNT_W + x;
}
vertexIndices[v++] = (y + 2) * VERTEX_COUNT_W - 1;
}
vshaderDVLB = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_size);
shaderProgramInit(&program);
shaderProgramSetVsh(&program, &vshaderDVLB->DVLE[0]);
C3D_BindProgram(&program);
spheresUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "spheres");
C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
AttrInfo_Init(attrInfo);
AttrInfo_AddFixed(attrInfo, 0);
AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 3);
AttrInfo_AddLoader(attrInfo, 2, GPU_FLOAT, 3);
iboData = linearAlloc(sizeof(vertexIndices));
memcpy(iboData, vertexIndices, sizeof(vertexIndices));
C3D_BufInfo* bufInfo = C3D_GetBufInfo();
BufInfo_Init(bufInfo);
BufInfo_Add(bufInfo, vboData, sizeof(vertex), 2, 0x21);
C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvInit(env);
C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR);
C3D_TexEnvFunc(env, C3D_Both, GPU_ADD);
C3D_FVec* spheres = C3D_FVUnifWritePtr(GPU_VERTEX_SHADER, spheresUniformLocation, 3);
spheres[0] = FVec4_New(0.0f, -100.5f, -1.0f, 100.0f);
spheres[1] = FVec4_New(0.5f, 0.0f, -1.0f, 0.5f);
spheres[2] = FVec4_New(-0.5f, 0.0f, -1.0f, 0.5f);
}
static void sceneRender()
{
C3D_DrawElements(GPU_TRIANGLE_STRIP, VERTEX_COUNT * 2 + VERTEX_COUNT_H * 2, C3D_UNSIGNED_SHORT, iboData);
}
static void sceneExit()
{
linearFree(vboData);
linearFree(iboData);
shaderProgramFree(&program);
DVLB_Free(vshaderDVLB);
}
int main(int argc, char* argv[])
{
gfxInitDefault();
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
C3D_RenderTarget* target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
sceneInit();
C3D_FVec lookFrom = FVec3_New(0, 1.25f, 0);
C3D_FVec lookAt = FVec3_New(0, 0, -1.0f);
C3D_FVec vup = FVec3_New(0, 1.0f, 0);
bool dirty = false;
setupVertices(lookFrom, lookAt, vup);
// Main loop
while (aptMainLoop())
{
hidScanInput();
const u32 kDown = hidKeysHeld();
if (kDown & KEY_START)
{
break; // break in order to return to hbmenu
}
constexpr float MOVE_RATE = 1.0f / 60.0f;
C3D_FVec diff = FVec3_New(0, 0, 0);
if (kDown & KEY_DLEFT)
{
diff.x -= MOVE_RATE;
dirty = true;
}
if (kDown & KEY_DRIGHT)
{
diff.x += MOVE_RATE;
dirty = true;
}
if (kDown & KEY_DUP)
{
diff.z += MOVE_RATE;
dirty = true;
}
if (kDown & KEY_DDOWN)
{
diff.z -= MOVE_RATE;
dirty = true;
}
if (kDown & KEY_L)
{
diff.y -= MOVE_RATE;
dirty = true;
}
if (kDown & KEY_R)
{
diff.y += MOVE_RATE;
dirty = true;
}
lookFrom = FVec3_Add(lookFrom, diff);
if (dirty)
{
setupVertices(lookFrom, lookAt, vup);
dirty = false;
}
if (C3D_FrameBegin(C3D_FRAME_SYNCDRAW))
{
C3D_RenderTargetClear(target, C3D_CLEAR_ALL, CLEAR_COLOR, 0);
C3D_FrameDrawOn(target);
sceneRender();
C3D_FrameEnd(0);
}
}
sceneExit();
C3D_Fini();
gfxExit();
return 0;
}

171
source/vshader.v.pica Normal file
View File

@ -0,0 +1,171 @@
.constf myconst(0.0, 1.0, 0.01, 1000.0)
.constf myconst2(0.25, 0.0, 0.0, 0.0)
.alias zeros myconst.xxxx
.alias ones myconst.yyyy
.alias near myconst.zzzz
.alias far myconst.wwww
.alias defaultMissColor myconst.xxxy
.alias defaultHitColor myconst.yxxy
.alias halfs myconst2.xxxx
.consti bounceLoopParams(0, 0, 1, 0)
.consti calcSphereLoopParams(2, 0, 1, 0)
.setb b0 true
.alias true b0
; xyz center (in world space)
; w radius (in world space)
.fvec spheres[3]
.in inOrigin v0
.in inDirection v1
.in inPos v2
.out outPos position
.out outColor color
.proc main
; outPos = inPos
mov outPos, inPos
; r1 = inOrigin
mov r1, inOrigin
; r2 = inDirection
mov r2, inDirection
; calculate light bounces
for bounceLoopParams
; r4 = (0, 0, 0, far)
mov r4, myconst.xxxw
; for each sphere
for calcSphereLoopParams
; r3 = spheres[i]
mov r3, spheres[aL]
; do calculation
; call calcSphere
; vec3 oc = origin - center
add r8.xyz, r1.xyz, -r3.xyz
; float a = dot(direction, direction)
dp3 r9.x, r2.xyz, r2.xyz
; float halfB = dot(oc, direction)
dp3 r9.y, r8.xyz, r2.xyz
; float radiusSquared = radius * radius
mul r8.w, r3.w, r3.w
; float c = dot(oc, oc) - radius * radius
dp3 r9.z, r8.xyz, r8.xyz
add r9.z, r9.z, -r8.w
; float halfBSquared = halfB * halfB;
mul r8.w, r9.y, r9.y
; float ac = a * c;
mul r9.w, r9.x, r9.z
; float discriminant = bSquared - ac
add r8.w, r8.w, -r9.w
; if discriminant < 0, exit procedure early
cmp zeros, gt, gt, r8.w
jmpc cmp.x, calcSphereExit
; calculate t
; float sqrtDiscriminant = sqrt(discriminant)
rsq r8.w, r8.w
rcp r8.w, r8.w
; a = 1 / a
rcp r9.x, r9.x
; float root = (-halfB - sqrtDiscriminant) / a
add r9.z, -r9.y, -r8.w
mul r9.z, r9.z, r9.x
; if root < min distance, check other root
cmp near, gt, gt, r9.z
jmpc cmp.x, calcSphereCheckOtherRoot
; if root > max distance, check other root
cmp r9.z, gt, gt, r4.w
jmpc cmp.x, calcSphereCheckOtherRoot
; if root is in range, finalize calculations
jmpu true, calcSphereFin
calcSphereCheckOtherRoot:
; float root = (-halfB + sqrtDiscriminant) / a
add r9.z, -r9.y, r8.w
mul r9.z, r9.z, r9.x
; if root < min distance, check other root
cmp near, gt, gt, r9.z
jmpc cmp.x, calcSphereExit
; if root > max distance, check other root
cmp r9.z, gt, gt, r4.w
jmpc cmp.x, calcSphereExit
calcSphereFin:
; change max distance to closest hit
mov r4.w, r9.z
; calculate new origin
mul r5.xyz, r2.xyz, r9.zzz
add r5.xyz, r5.xyz, r1.xyz
; calculate normal
add r7.xyz, r5.xyz, -r3.xyz
rcp r3.w, r3.w
mul r7.xyz, r7.xyz, r3.w
; assign color
mov r4.xyz, r7.xyz
add r4.xyz, ones, r4.xyz
mul r4.xyz, halfs, r4.xyz
; early exit label
calcSphereExit:
nop
; done with calculation
.end
.end
; copy final color to output
mov outColor.xyz, r4.xyz
; set alpha to 1
mov outColor.w, ones
end
.end
; Inputs
; ------
; r1.xyz: ray origin
; r2.xyz: ray direction
; r3.xyzw: sphere info
; r4.w: min distance
;
; Outputs
; -------
; r4.w: new min distance
; r4.xyz: new color
;
; Temporaries
; -----------
; r5.xyz: new origin
; r6.xyz: new direction
; r7.xyz: hit normal
; r8
; r9
;
;.proc calcSphere
;.end