Last active
December 4, 2022 19:47
-
-
Save misterhat/5045d79731c7229ca94da919bd12ed1e to your computer and use it in GitHub Desktop.
/devkitpro/examples/3ds/graphics/gpu/textured_cube/ modified to dump framebuffer to ppm file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const drawIndex = 0; | |
const yOffsets = [1, 4, 5, 16, 17, 20, 21, 64]; | |
const xOffsets = [2, 8, 10, 32, 34, 40, 42, 1920]; | |
const expandedYOffsets = [0]; | |
let test = 0; | |
for (let i = 0; i < 30; i++) { | |
let last = 0; | |
for (let j = 0; j < 8; j++) { | |
last = test + yOffsets[j]; | |
expandedYOffsets.unshift(last); | |
} | |
test = last; | |
} | |
const expandedXOffsets = [0]; | |
test = 0; | |
for (let i = 0; i < 40; i++) { | |
let last = 0; | |
for (let j = 0; j < 8; j++) { | |
last = test + xOffsets[j]; | |
expandedXOffsets.push(last); | |
} | |
test = last; | |
} | |
expandedYOffsets.shift(); | |
expandedXOffsets.pop(); | |
const yOffset = Math.floor(drawIndex / 320); | |
const xOffset = drawIndex - (yOffset * 320); | |
const framebufferIndex = expandedYOffsets[yOffset] + expandedXOffsets[xOffset]; | |
console.log(framebufferIndex); | |
console.log(JSON.stringify(expandedXOffsets), | |
JSON.stringify(expandedYOffsets)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <3ds.h> | |
#include <citro3d.h> | |
#include <math.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <tex3ds.h> | |
#include "vshader_shbin.h" | |
#include "kitten_t3x.h" | |
#define CLEAR_COLOR 0x68B0D8FF | |
#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)) | |
int framebufferOffsetsX[] = { | |
0, 2, 8, 10, 32, 34, 40, 42, 1920, 1922, 1928, | |
1930, 1952, 1954, 1960, 1962, 3840, 3842, 3848, 3850, 3872, 3874, | |
3880, 3882, 5760, 5762, 5768, 5770, 5792, 5794, 5800, 5802, 7680, | |
7682, 7688, 7690, 7712, 7714, 7720, 7722, 9600, 9602, 9608, 9610, | |
9632, 9634, 9640, 9642, 11520, 11522, 11528, 11530, 11552, 11554, 11560, | |
11562, 13440, 13442, 13448, 13450, 13472, 13474, 13480, 13482, 15360, 15362, | |
15368, 15370, 15392, 15394, 15400, 15402, 17280, 17282, 17288, 17290, 17312, | |
17314, 17320, 17322, 19200, 19202, 19208, 19210, 19232, 19234, 19240, 19242, | |
21120, 21122, 21128, 21130, 21152, 21154, 21160, 21162, 23040, 23042, 23048, | |
23050, 23072, 23074, 23080, 23082, 24960, 24962, 24968, 24970, 24992, 24994, | |
25000, 25002, 26880, 26882, 26888, 26890, 26912, 26914, 26920, 26922, 28800, | |
28802, 28808, 28810, 28832, 28834, 28840, 28842, 30720, 30722, 30728, 30730, | |
30752, 30754, 30760, 30762, 32640, 32642, 32648, 32650, 32672, 32674, 32680, | |
32682, 34560, 34562, 34568, 34570, 34592, 34594, 34600, 34602, 36480, 36482, | |
36488, 36490, 36512, 36514, 36520, 36522, 38400, 38402, 38408, 38410, 38432, | |
38434, 38440, 38442, 40320, 40322, 40328, 40330, 40352, 40354, 40360, 40362, | |
42240, 42242, 42248, 42250, 42272, 42274, 42280, 42282, 44160, 44162, 44168, | |
44170, 44192, 44194, 44200, 44202, 46080, 46082, 46088, 46090, 46112, 46114, | |
46120, 46122, 48000, 48002, 48008, 48010, 48032, 48034, 48040, 48042, 49920, | |
49922, 49928, 49930, 49952, 49954, 49960, 49962, 51840, 51842, 51848, 51850, | |
51872, 51874, 51880, 51882, 53760, 53762, 53768, 53770, 53792, 53794, 53800, | |
53802, 55680, 55682, 55688, 55690, 55712, 55714, 55720, 55722, 57600, 57602, | |
57608, 57610, 57632, 57634, 57640, 57642, 59520, 59522, 59528, 59530, 59552, | |
59554, 59560, 59562, 61440, 61442, 61448, 61450, 61472, 61474, 61480, 61482, | |
63360, 63362, 63368, 63370, 63392, 63394, 63400, 63402, 65280, 65282, 65288, | |
65290, 65312, 65314, 65320, 65322, 67200, 67202, 67208, 67210, 67232, 67234, | |
67240, 67242, 69120, 69122, 69128, 69130, 69152, 69154, 69160, 69162, 71040, | |
71042, 71048, 71050, 71072, 71074, 71080, 71082, 72960, 72962, 72968, 72970, | |
72992, 72994, 73000, 73002, 74880, 74882, 74888, 74890, 74912, 74914, 74920, | |
74922}; | |
int framebufferOffsetsY[] = { | |
1877, 1876, 1873, 1872, 1861, 1860, 1857, 1856, 1813, 1812, 1809, 1808, | |
1797, 1796, 1793, 1792, 1749, 1748, 1745, 1744, 1733, 1732, 1729, 1728, | |
1685, 1684, 1681, 1680, 1669, 1668, 1665, 1664, 1621, 1620, 1617, 1616, | |
1605, 1604, 1601, 1600, 1557, 1556, 1553, 1552, 1541, 1540, 1537, 1536, | |
1493, 1492, 1489, 1488, 1477, 1476, 1473, 1472, 1429, 1428, 1425, 1424, | |
1413, 1412, 1409, 1408, 1365, 1364, 1361, 1360, 1349, 1348, 1345, 1344, | |
1301, 1300, 1297, 1296, 1285, 1284, 1281, 1280, 1237, 1236, 1233, 1232, | |
1221, 1220, 1217, 1216, 1173, 1172, 1169, 1168, 1157, 1156, 1153, 1152, | |
1109, 1108, 1105, 1104, 1093, 1092, 1089, 1088, 1045, 1044, 1041, 1040, | |
1029, 1028, 1025, 1024, 981, 980, 977, 976, 965, 964, 961, 960, | |
917, 916, 913, 912, 901, 900, 897, 896, 853, 852, 849, 848, | |
837, 836, 833, 832, 789, 788, 785, 784, 773, 772, 769, 768, | |
725, 724, 721, 720, 709, 708, 705, 704, 661, 660, 657, 656, | |
645, 644, 641, 640, 597, 596, 593, 592, 581, 580, 577, 576, | |
533, 532, 529, 528, 517, 516, 513, 512, 469, 468, 465, 464, | |
453, 452, 449, 448, 405, 404, 401, 400, 389, 388, 385, 384, | |
341, 340, 337, 336, 325, 324, 321, 320, 277, 276, 273, 272, | |
261, 260, 257, 256, 213, 212, 209, 208, 197, 196, 193, 192, | |
149, 148, 145, 144, 133, 132, 129, 128, 85, 84, 81, 80, | |
69, 68, 65, 64, 21, 20, 17, 16, 5, 4, 1, 0}; | |
typedef struct { float position[3]; float texcoord[2]; float normal[3]; } vertex; | |
static const vertex vertex_list[] = | |
{ | |
// First face (PZ) | |
// First triangle | |
{ {-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} }, | |
// Second triangle | |
{ {+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} }, | |
// Second face (MZ) | |
// First triangle | |
{ {-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} }, | |
// Second triangle | |
{ {+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} }, | |
// Third face (PX) | |
// First triangle | |
{ {+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} }, | |
// Second triangle | |
{ {+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} }, | |
// Fourth face (MX) | |
// First triangle | |
{ {-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} }, | |
// Second triangle | |
{ {-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} }, | |
// Fifth face (PY) | |
// First triangle | |
{ {-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} }, | |
// Second triangle | |
{ {+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} }, | |
// Sixth face (MY) | |
// First triangle | |
{ {-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} }, | |
// Second triangle | |
{ {+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 vertex_list_count (sizeof(vertex_list)/sizeof(vertex_list[0])) | |
static DVLB_s* vshader_dvlb; | |
static shaderProgram_s program; | |
static int uLoc_projection, uLoc_modelView; | |
static int uLoc_lightVec, uLoc_lightHalfVec, uLoc_lightClr, uLoc_material; | |
static C3D_Mtx projection; | |
static 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 | |
} | |
}; | |
static void* vbo_data; | |
static C3D_Tex kitten_tex; | |
static float angleX = 0.0, angleY = 0.0; | |
// Helper function for loading a texture from memory | |
static bool loadTextureFromMem(C3D_Tex* tex, C3D_TexCube* cube, const void* data, size_t size) | |
{ | |
Tex3DS_Texture t3x = Tex3DS_TextureImport(data, size, tex, cube, false); | |
if (!t3x) | |
return false; | |
// Delete the t3x object since we don't need it | |
Tex3DS_TextureFree(t3x); | |
return true; | |
} | |
static void sceneInit(void) | |
{ | |
// Load the vertex shader, create a shader program and bind it | |
vshader_dvlb = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_size); | |
shaderProgramInit(&program); | |
shaderProgramSetVsh(&program, &vshader_dvlb->DVLE[0]); | |
C3D_BindProgram(&program); | |
// Get the location of the uniforms | |
uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection"); | |
uLoc_modelView = shaderInstanceGetUniformLocation(program.vertexShader, "modelView"); | |
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 | |
// Compute the projection matrix | |
Mtx_PerspTilt(&projection, C3D_AngleFromDegrees(80.0f), C3D_AspectRatioBot, 0.01f, 1000.0f, false); | |
// Create the VBO (vertex buffer object) | |
vbo_data = linearAlloc(sizeof(vertex_list)); | |
memcpy(vbo_data, vertex_list, sizeof(vertex_list)); | |
// Configure buffers | |
C3D_BufInfo* bufInfo = C3D_GetBufInfo(); | |
BufInfo_Init(bufInfo); | |
BufInfo_Add(bufInfo, vbo_data, sizeof(vertex), 3, 0x210); | |
// Load the texture and bind it to the first texture unit | |
if (!loadTextureFromMem(&kitten_tex, NULL, kitten_t3x, kitten_t3x_size)) | |
svcBreak(USERBREAK_PANIC); | |
C3D_TexSetFilter(&kitten_tex, GPU_LINEAR, GPU_NEAREST); | |
C3D_TexBind(0, &kitten_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_TexEnvInit(env); | |
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0); | |
C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); | |
} | |
static void sceneRender(void) | |
{ | |
// Calculate the modelView matrix | |
C3D_Mtx modelView; | |
Mtx_Identity(&modelView); | |
Mtx_Translate(&modelView, 0.0, 0.0, -2.0 + 0.5*sinf(angleX), true); | |
Mtx_RotateX(&modelView, angleX, true); | |
Mtx_RotateY(&modelView, angleY, true); | |
// Rotate the cube each frame | |
angleX += M_PI / 180; | |
angleY += M_PI / 360; | |
// Update the uniforms | |
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection); | |
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); | |
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); | |
// Draw the VBO | |
C3D_DrawArrays(GPU_TRIANGLES, 0, vertex_list_count); | |
} | |
static void sceneExit(void) | |
{ | |
// Free the texture | |
C3D_TexDelete(&kitten_tex); | |
// Free the VBO | |
linearFree(vbo_data); | |
// Free the shader program | |
shaderProgramFree(&program); | |
DVLB_Free(vshader_dvlb); | |
} | |
/* translate (y * width) + index into internal framebuffer index */ | |
int translateFramebufferIndex(int index) { | |
int y_offset = floor(index / 320); | |
int x_offset = index - (y_offset * 320); | |
return framebufferOffsetsX[x_offset] + framebufferOffsetsY[y_offset]; | |
} | |
void dumpFramebuffer(C3D_RenderTarget *target) { | |
uint8_t *colourBuf = (uint8_t*)(target->frameBuf.colorBuf); | |
FILE *ppm = fopen("./framebuffer.ppm", "w"); | |
fprintf(ppm, "P3\n320 240\n255\n"); | |
int index = 0; | |
for (int x = 0; x < 320; x++) { | |
for (int y = 0; y < 240; y++) { | |
int fb_index = translateFramebufferIndex(index) * 4; | |
int a = colourBuf[fb_index++]; | |
int b = colourBuf[fb_index++]; | |
int g = colourBuf[fb_index++]; | |
int r = colourBuf[fb_index++]; | |
fprintf(ppm, "%d %d %d\n", r, g, b); | |
index++; | |
} | |
} | |
fclose(ppm); | |
} | |
int main() | |
{ | |
// Initialize graphics | |
gfxInitDefault(); | |
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); | |
// Initialize the render target | |
C3D_RenderTarget* target = C3D_RenderTargetCreate(240, 320, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); | |
C3D_RenderTargetSetOutput(target, GFX_BOTTOM, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); | |
// Initialize the scene | |
sceneInit(); | |
// Main loop | |
while (aptMainLoop()) | |
{ | |
hidScanInput(); | |
// Respond to user input | |
u32 kDown = hidKeysDown(); | |
if (kDown & KEY_SELECT) { | |
dumpFramebuffer(target); | |
} | |
if (kDown & KEY_START) | |
break; // break in order to return to hbmenu | |
// Render the scene | |
C3D_FrameBegin(C3D_FRAME_SYNCDRAW); | |
C3D_RenderTargetClear(target, C3D_CLEAR_ALL, CLEAR_COLOR, 0); | |
C3D_FrameDrawOn(target); | |
sceneRender(); | |
C3D_FrameEnd(0); | |
} | |
// Deinitialize the scene | |
sceneExit(); | |
// Deinitialize graphics | |
C3D_Fini(); | |
gfxExit(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment