Skip to content

Commit e8b27b0

Browse files
committed
Add GPU example (procedural texture)
1 parent 5e7a447 commit e8b27b0

File tree

3 files changed

+395
-0
lines changed

3 files changed

+395
-0
lines changed

graphics/gpu/proctex/Makefile

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
#---------------------------------------------------------------------------------
2+
.SUFFIXES:
3+
#---------------------------------------------------------------------------------
4+
5+
ifeq ($(strip $(DEVKITARM)),)
6+
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
7+
endif
8+
9+
TOPDIR ?= $(CURDIR)
10+
include $(DEVKITARM)/3ds_rules
11+
12+
#---------------------------------------------------------------------------------
13+
# TARGET is the name of the output
14+
# BUILD is the directory where object files & intermediate files will be placed
15+
# SOURCES is a list of directories containing source code
16+
# DATA is a list of directories containing data files
17+
# INCLUDES is a list of directories containing header files
18+
#
19+
# NO_SMDH: if set to anything, no SMDH file is generated.
20+
# ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional)
21+
# APP_TITLE is the name of the app stored in the SMDH file (Optional)
22+
# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional)
23+
# APP_AUTHOR is the author of the app stored in the SMDH file (Optional)
24+
# ICON is the filename of the icon (.png), relative to the project folder.
25+
# If not set, it attempts to use one of the following (in this order):
26+
# - <Project name>.png
27+
# - icon.png
28+
# - <libctru folder>/default_icon.png
29+
#---------------------------------------------------------------------------------
30+
TARGET := $(notdir $(CURDIR))
31+
BUILD := build
32+
SOURCES := source
33+
DATA := data
34+
INCLUDES := include
35+
#ROMFS := romfs
36+
37+
#---------------------------------------------------------------------------------
38+
# options for code generation
39+
#---------------------------------------------------------------------------------
40+
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
41+
42+
CFLAGS := -g -Wall -O2 -mword-relocations \
43+
-fomit-frame-pointer -ffunction-sections \
44+
$(ARCH)
45+
46+
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
47+
48+
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
49+
50+
ASFLAGS := -g $(ARCH)
51+
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
52+
53+
LIBS := -lcitro3d -lctru -lm
54+
55+
#---------------------------------------------------------------------------------
56+
# list of directories containing libraries, this must be the top level containing
57+
# include and lib
58+
#---------------------------------------------------------------------------------
59+
LIBDIRS := $(CTRULIB)
60+
61+
62+
#---------------------------------------------------------------------------------
63+
# no real need to edit anything past this point unless you need to add additional
64+
# rules for different file extensions
65+
#---------------------------------------------------------------------------------
66+
ifneq ($(BUILD),$(notdir $(CURDIR)))
67+
#---------------------------------------------------------------------------------
68+
69+
export OUTPUT := $(CURDIR)/$(TARGET)
70+
export TOPDIR := $(CURDIR)
71+
72+
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
73+
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
74+
75+
export DEPSDIR := $(CURDIR)/$(BUILD)
76+
77+
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
78+
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
79+
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
80+
PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica)))
81+
SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist)))
82+
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
83+
84+
#---------------------------------------------------------------------------------
85+
# use CXX for linking C++ projects, CC for standard C
86+
#---------------------------------------------------------------------------------
87+
ifeq ($(strip $(CPPFILES)),)
88+
#---------------------------------------------------------------------------------
89+
export LD := $(CC)
90+
#---------------------------------------------------------------------------------
91+
else
92+
#---------------------------------------------------------------------------------
93+
export LD := $(CXX)
94+
#---------------------------------------------------------------------------------
95+
endif
96+
#---------------------------------------------------------------------------------
97+
98+
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
99+
100+
export OFILES_BIN := $(addsuffix .o,$(BINFILES)) \
101+
$(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o)
102+
103+
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES)
104+
105+
export HFILES := $(PICAFILES:.v.pica=_shbin.h) $(addsuffix .h,$(subst .,_,$(BINFILES)))
106+
107+
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
108+
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
109+
-I$(CURDIR)/$(BUILD)
110+
111+
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
112+
113+
ifeq ($(strip $(ICON)),)
114+
icons := $(wildcard *.png)
115+
ifneq (,$(findstring $(TARGET).png,$(icons)))
116+
export APP_ICON := $(TOPDIR)/$(TARGET).png
117+
else
118+
ifneq (,$(findstring icon.png,$(icons)))
119+
export APP_ICON := $(TOPDIR)/icon.png
120+
endif
121+
endif
122+
else
123+
export APP_ICON := $(TOPDIR)/$(ICON)
124+
endif
125+
126+
ifeq ($(strip $(NO_SMDH)),)
127+
export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh
128+
endif
129+
130+
ifneq ($(ROMFS),)
131+
export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS)
132+
endif
133+
134+
.PHONY: $(BUILD) clean all
135+
136+
#---------------------------------------------------------------------------------
137+
all: $(BUILD)
138+
139+
$(BUILD):
140+
@[ -d $@ ] || mkdir -p $@
141+
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
142+
143+
#---------------------------------------------------------------------------------
144+
clean:
145+
@echo clean ...
146+
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf
147+
148+
149+
#---------------------------------------------------------------------------------
150+
else
151+
152+
DEPENDS := $(OFILES:.o=.d)
153+
154+
#---------------------------------------------------------------------------------
155+
# main targets
156+
#---------------------------------------------------------------------------------
157+
ifeq ($(strip $(NO_SMDH)),)
158+
$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh
159+
else
160+
$(OUTPUT).3dsx : $(OUTPUT).elf
161+
endif
162+
163+
$(OFILES_SOURCES) : $(HFILES)
164+
165+
$(OUTPUT).elf : $(OFILES)
166+
167+
#---------------------------------------------------------------------------------
168+
# you need a rule like this for each extension you use as binary data
169+
#---------------------------------------------------------------------------------
170+
%.bin.o %_bin.h : %.bin
171+
#---------------------------------------------------------------------------------
172+
@echo $(notdir $<)
173+
@$(bin2o)
174+
175+
#---------------------------------------------------------------------------------
176+
# rules for assembling GPU shaders
177+
#---------------------------------------------------------------------------------
178+
define shader-as
179+
$(eval CURBIN := $*.shbin)
180+
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h
181+
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h
182+
echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h
183+
picasso -o $(CURBIN) $1
184+
bin2s $(CURBIN) | $(AS) -o $*.shbin.o
185+
endef
186+
187+
%.shbin.o %_shbin.h : %.v.pica
188+
@echo $(notdir $<)
189+
@$(call shader-as,$<)
190+
191+
-include $(DEPENDS)
192+
193+
#---------------------------------------------------------------------------------------
194+
endif
195+
#---------------------------------------------------------------------------------------

graphics/gpu/proctex/source/main.c

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#include <3ds.h>
2+
#include <citro3d.h>
3+
#include <string.h>
4+
#include <stdio.h>
5+
#include "vshader_shbin.h"
6+
7+
#define CLEAR_COLOR 0x68B0D8FF
8+
9+
#define DISPLAY_TRANSFER_FLAGS \
10+
(GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \
11+
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \
12+
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
13+
14+
static DVLB_s* vshader_dvlb;
15+
static shaderProgram_s program;
16+
static int uLoc_projection;
17+
static C3D_Mtx projection;
18+
19+
static C3D_ProcTex pt;
20+
static C3D_ProcTexLut pt_map;
21+
static C3D_ProcTexLut pt_noise;
22+
static C3D_ProcTexColorLut pt_clr;
23+
24+
static void sceneInit(void)
25+
{
26+
// Load the vertex shader, create a shader program and bind it
27+
vshader_dvlb = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_size);
28+
shaderProgramInit(&program);
29+
shaderProgramSetVsh(&program, &vshader_dvlb->DVLE[0]);
30+
C3D_BindProgram(&program);
31+
32+
// Get the location of the uniforms
33+
uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection");
34+
35+
// Configure attributes for use with the vertex shader
36+
// Attribute format and element count are ignored in immediate mode
37+
C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
38+
AttrInfo_Init(attrInfo);
39+
AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position
40+
AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 3); // v1=texcoord0
41+
42+
// Compute the projection matrix
43+
Mtx_OrthoTilt(&projection, 0.0, 400.0, 240.0, 0.0, 0.0, 1.0, true);
44+
45+
#define NUMCOLORS 2
46+
C3D_ProcTexInit(&pt, 0, NUMCOLORS);
47+
C3D_ProcTexClamp(&pt, GPU_PT_MIRRORED_REPEAT, GPU_PT_MIRRORED_REPEAT);
48+
C3D_ProcTexNoiseCoefs(&pt, C3D_ProcTex_UV, 0.1f, 0.3f, 0.1f);
49+
C3D_ProcTexCombiner(&pt, false, GPU_PT_SQRT2, GPU_PT_SQRT2); // <- for wood rings
50+
//C3D_ProcTexCombiner(&pt, false, GPU_PT_V, GPU_PT_V); // <- for wood stripes (or also _U)
51+
C3D_ProcTexFilter(&pt, GPU_PT_LINEAR);
52+
C3D_ProcTexBind(0, &pt);
53+
54+
float data[129];
55+
int i;
56+
for (i = 0; i <= 128; i ++)
57+
{
58+
float x = i/128.0f;
59+
data[i] = fabsf(sinf(C3D_Angle(6*(x+0.125f)))); // 6*2 = 12 stripes
60+
}
61+
ProcTexLut_FromArray(&pt_map, data);
62+
C3D_ProcTexLutBind(GPU_LUT_RGBMAP, &pt_map);
63+
64+
// Noise smooth step equation
65+
for (i = 0; i <= 128; i ++)
66+
{
67+
float x = i/128.0f;
68+
data[i] = x*x*(3-2*x);
69+
}
70+
ProcTexLut_FromArray(&pt_noise, data);
71+
C3D_ProcTexLutBind(GPU_LUT_NOISE, &pt_noise);
72+
73+
u32 colors[NUMCOLORS];
74+
colors[0] = 0xFF1F1F4F; // dark brown
75+
colors[1] = 0xFF1F9ED1; // light brown
76+
77+
ProcTexColorLut_Write(&pt_clr, colors, 0, NUMCOLORS);
78+
C3D_ProcTexColorLutBind(&pt_clr);
79+
80+
// Configure the first fragment shading substage to just pass through the procedural texture color
81+
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
82+
C3D_TexEnv* env = C3D_GetTexEnv(0);
83+
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE3, 0, 0);
84+
C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
85+
C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
86+
}
87+
88+
static void sceneRender(void)
89+
{
90+
// Update the uniforms
91+
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection);
92+
93+
// Draw the triangle directly
94+
//float min = -1.0f; //<-- for (symmetrical) wood rings
95+
//float max = +1.0f;
96+
float min = 1.0f; //<-- for asymmetrical wood rings
97+
float max = 3.0f;
98+
//float min = 0.0f; //<-- for wood stripes
99+
//float max = +3.0f; // triplicate stripes
100+
float size = 200.0f/2;
101+
C3D_ImmDrawBegin(GPU_TRIANGLE_STRIP);
102+
C3D_ImmSendAttrib(200.0f-size, 120.0f+size, 0.5f, 0.0f); // v0=position
103+
C3D_ImmSendAttrib(min, min, 0.0f, 0.0f); // v1=texcoord0
104+
105+
C3D_ImmSendAttrib(200.0f+size, 120.0f+size, 0.5f, 0.0f);
106+
C3D_ImmSendAttrib(max, min, 0.0f, 0.0f);
107+
108+
C3D_ImmSendAttrib(200.0f-size, 120.0f-size, 0.5f, 0.0f);
109+
C3D_ImmSendAttrib(min, max, 0.0f, 0.0f);
110+
111+
C3D_ImmSendAttrib(200.0f+size, 120.0f-size, 0.5f, 0.0f);
112+
C3D_ImmSendAttrib(max, max, 0.0f, 0.0f);
113+
C3D_ImmDrawEnd();
114+
}
115+
116+
static void sceneExit(void)
117+
{
118+
// Free the shader program
119+
shaderProgramFree(&program);
120+
DVLB_Free(vshader_dvlb);
121+
}
122+
123+
int main()
124+
{
125+
// Initialize graphics
126+
gfxInitDefault();
127+
consoleInit(GFX_BOTTOM, NULL);
128+
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
129+
130+
// Initialize the render target
131+
C3D_RenderTarget* target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
132+
C3D_RenderTargetSetClear(target, C3D_CLEAR_ALL, CLEAR_COLOR, 0);
133+
C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
134+
135+
// Initialize the scene
136+
sceneInit();
137+
138+
// Main loop
139+
while (aptMainLoop())
140+
{
141+
hidScanInput();
142+
143+
// Respond to user input
144+
u32 kDown = hidKeysDown();
145+
if (kDown & KEY_START)
146+
break; // break in order to return to hbmenu
147+
148+
printf("\x1b[29;1Hgpu: %5.2f%% cpu: %5.2f%% buf:%5.2f%%\n", C3D_GetDrawingTime()*3, C3D_GetProcessingTime()*3, C3D_GetCmdBufUsage()*100);
149+
150+
// Render the scene
151+
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
152+
C3D_FrameDrawOn(target);
153+
sceneRender();
154+
C3D_FrameEnd(0);
155+
}
156+
157+
// Deinitialize the scene
158+
sceneExit();
159+
160+
// Deinitialize graphics
161+
C3D_Fini();
162+
gfxExit();
163+
return 0;
164+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
; Example PICA200 vertex shader
2+
3+
; Uniforms
4+
.fvec projection[4]
5+
6+
; Constants
7+
.constf myconst(0.0, 1.0, -1.0, 0.1)
8+
.constf myconst2(0.3, 0.0, 0.0, 0.0)
9+
.alias zeros myconst.xxxx ; Vector full of zeros
10+
.alias ones myconst.yyyy ; Vector full of ones
11+
12+
; Outputs
13+
.out outpos position
14+
.out outtc0 texcoord0
15+
16+
; Inputs (defined as aliases for convenience)
17+
.alias inpos v0
18+
.alias intc0 v1
19+
20+
.proc main
21+
; Force the w component of inpos to be 1.0
22+
mov r0.xyz, inpos
23+
mov r0.w, ones
24+
25+
; outpos = projectionMatrix * inpos
26+
dp4 outpos.x, projection[0], r0
27+
dp4 outpos.y, projection[1], r0
28+
dp4 outpos.z, projection[2], r0
29+
dp4 outpos.w, projection[3], r0
30+
31+
; outtc0 = intc0
32+
mov outtc0, intc0
33+
34+
; We're finished
35+
end
36+
.end

0 commit comments

Comments
 (0)