citro3d/test/3ds/source/main.cpp
2017-02-09 19:45:33 +01:00

1028 lines
32 KiB
C++

#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 <float.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);
}
void transpose_test()
{
consoleClear();
C3D_Mtx modelView, check;
Mtx_Identity(&modelView);
Mtx_Translate(&modelView, ((float)(rand() % 100)) + 5.0f, ((float)(rand() % 100)) + 5.0f, ((float)(rand() % 100)) + 5.0f, true);
Mtx_RotateX(&modelView, (float)(rand() % 180) * (acos(-1)/180.0f), true);
Mtx_RotateY(&modelView, (float)(rand() % 180) * (acos(-1)/180.0f), true);
Mtx_RotateZ(&modelView, (float)(rand() % 180) * (acos(-1)/180.0f), true);
Mtx_Copy(&check, &modelView);
std::printf("Random Translation:\n");
for (int i = 0; i < 16; i++)
{
std::printf("%2.2f ", modelView.m[i]);
if (i % 4 == 3)
std::printf("\n");
}
Mtx_Transpose(&modelView);
std::printf("Random Translation Transposed:\n");
for (int i = 0; i < 16; i++)
{
std::printf("%2.2f ", modelView.m[i]);
if (i % 4 == 3)
std::printf("\n");
}
Mtx_Transpose(&modelView);
std::printf("Rand-Trans Transposed Transposed:\n");
for (int i = 0; i < 16; i++)
{
std::printf("%2.2f ", modelView.m[i]);
if (i % 4 == 3)
std::printf("\n");
}
bool transposeFailCheck = false;
for (int i = 0; i < 16; i++)
{
if (modelView.m[i] != check.m[i])
{
transposeFailCheck = true;
break;
}
}
bool transInvFailCheck = false;
Mtx_Inverse(&modelView);
Mtx_Transpose(&modelView);
Mtx_Transpose(&check);
Mtx_Inverse(&check);
for (int i = 0; i < 16; i++)
{
if (fabsf(modelView.m[i] - check.m[i]) > 0.001f)
{
std::printf("%f != %f\n", modelView.m[i], check.m[i]);
transInvFailCheck = true;
break;
}
}
std::printf("Transposed Inverse of RandMatrix:\n");
for (int i = 0; i < 16; i++)
{
std::printf("%2.2f ", modelView.m[i]);
if (i % 4 == 3)
std::printf("\n");
}
std::printf("Inverse Transposed of RandMatrix:\n");
for (int i = 0; i < 16; i++)
{
std::printf("%2.2f ", check.m[i]);
if (i % 4 == 3)
std::printf("\n");
}
std::printf("\n");
std::printf("Transpose(Transpose(A)) = A? %s\n", (transposeFailCheck ? "False" : "True"));
std::printf("Inv(Trans(A))=Trans(Inv(A))? %s\n", (transInvFailCheck ? "False" : "True"));
while(aptMainLoop())
{
gspWaitForVBlank();
hidScanInput();
u32 down = hidKeysDown();
if(down & (KEY_START|KEY_SELECT))
break;
}
}
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, },
{ "Mtx_Transpose", transpose_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;
}