/*---------------------------------------------------------------------------* Project: Horizon File: TriangleSimple.cpp Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 47228 $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include "demo.h" /* buffer id */ GLuint s_ArrayBufferID; GLuint s_ElementArrayBufferID; /* program id */ GLuint s_PgID; /* shader id */ GLuint s_ShID; s32 s_Count = 0; /* ExpHeap for app. */ nn::fnd::ExpHeap s_AppHeap; uptr s_HeapForGx; const u32 s_GxHeapSize = 0x400000; demo::RenderSystem s_RenderSystem; /* Define in gx_CaptureUtil.cpp */ extern int SaveDisplayBufferSD(const wchar_t *dirname, const wchar_t *filename, u32 index, GLuint addr, const u32 width, const u32 height, u8 *work = NULL); extern void GetProjectionForPartialCapture(nn::math::Matrix44* pOut, nn::math::Matrix44* proj, s32 div, s32 indexH, s32 indexV, const f32 dist, nn::math::PivotDirection pivot); /* generate simple object */ static void LoadObjects(void) { GLfloat coords[] = { 0.5f, 0.0f, 0.f, 1.f, -0.5f, 0.5f, 0.f, 1.f, -0.5f,-0.5f, 0.f, 1.f }; GLfloat color[] = { 1.f, 0.0f, 0.0f, 0.f, 1.0f, 0.0f, 0.f, 0.0f, 1.0f }; GLushort idxs[] = {0, 1, 2}; glGenBuffers(1, &s_ArrayBufferID); glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferID); glBufferData(GL_ARRAY_BUFFER, sizeof(coords) + sizeof(color), 0, GL_STATIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(coords), coords); glBufferSubData(GL_ARRAY_BUFFER, sizeof(coords), sizeof(color), color); glGenBuffers(1, &s_ElementArrayBufferID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_ElementArrayBufferID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idxs), idxs, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0) ; glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)sizeof(coords)); } void DrawDisplay0(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); nn::math::Matrix44 proj; nn::math::MTX44Frustum(&proj, -0.02f, 0.02f, -0.02f*nn::gx::DISPLAY0_HEIGHT/nn::gx::DISPLAY0_WIDTH, 0.02f*nn::gx::DISPLAY0_HEIGHT/nn::gx::DISPLAY0_WIDTH, 0.2f, 10.f); glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uProjection"), 1, GL_TRUE, static_cast(proj)); nn::math::Matrix34 eye, rot; nn::math::Vector3 camPos(0.f, 0.4f, 9.5f); nn::math::Vector3 camUp(0.f, 1.f, 0.f); nn::math::Vector3 target(0.f, 0.f, 0.f); nn::math::Vector3 rotAxis(0.f, 1.f, 0.f); nn::math::MTX34Identity(&eye); nn::math::MTX34LookAt(&eye, &camPos, &camUp, &target); nn::math::MTX34RotAxisDeg(&rot, &rotAxis, -6.f * s_Count); nn::math::MTX34Mult(&eye, &eye, &rot); nn::math::Matrix44 mv(eye); glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, (f32*)(mv)); glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0); s_RenderSystem.SwapBuffers(); } void DrawDisplay0AndSave(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); nn::math::Matrix44 proj, tmp; s32 i, j; s32 div = 2; int currDispBuf = 0; // Allocate the display buffer for SD saving and then obtain the address. GLuint disp[2]; GLint addr[2]; nngxGenDisplaybuffers(2, disp); nngxBindDisplaybuffer(disp[0]); nngxDisplaybufferStorage(GL_RGB8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, NN_GX_MEM_FCRAM); nngxGetDisplaybufferParameteri(NN_GX_DISPLAYBUFFER_ADDRESS, &addr[0]); nngxBindDisplaybuffer(disp[1]); nngxDisplaybufferStorage(GL_RGB8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, NN_GX_MEM_FCRAM); nngxGetDisplaybufferParameteri(NN_GX_DISPLAYBUFFER_ADDRESS, &addr[1]); NN_TLOG_("Start saving...\n"); DEMO_ASSERT_GL_ERROR(); nn::math::Matrix34 eye, rot; nn::math::Vector3 camPos(0.f, 0.4f, 9.5f); nn::math::Vector3 camUp(0.f, 1.f, 0.f); nn::math::Vector3 target(0.f, 0.f, 0.f); nn::math::Vector3 rotAxis(0.f, 1.f, 0.f); nn::math::MTX34Identity(&eye); nn::math::MTX34LookAt(&eye, &camPos, &camUp, &target); nn::math::MTX34RotAxisDeg(&rot, &rotAxis, -6.f * s_Count); nn::math::MTX34Mult(&eye, &eye, &rot); nn::math::Matrix44 mv(eye); glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, (f32*)(mv)); void* buf = s_AppHeap.Allocate(nn::gx::DISPLAY0_HEIGHT * nn::gx::DISPLAY0_WIDTH *3 + 54); // Divide into div x div and render. Transfer the color buffer to the display buffer for SD writing. for (i = 0; i < div; ++i) { for (j = 0; j < div; ++j) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); // Clear the color buffer held by the RenderSystem. // If the buffer is not cleared, the previous render results are sent to the display buffer each time. s_RenderSystem.Clear(); // Create the perspective projection matrix. // Disable rotation using pivot since the matrix can be decomposed using the GetProjectionForPartialCapture function. nn::math::MTX44Frustum(&tmp, -0.02f, 0.02f, -0.02f*nn::gx::DISPLAY0_HEIGHT/nn::gx::DISPLAY0_WIDTH, 0.02f*nn::gx::DISPLAY0_HEIGHT/nn::gx::DISPLAY0_WIDTH, 0.2f, 10.f); GetProjectionForPartialCapture(&proj, &tmp, 2, i, j, 0.0f, nn::math::PIVOT_NONE); glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uProjection"), 1, GL_TRUE, static_cast(proj)); glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, (f32*)(mv)); glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0); // Render to the color buffer held by RenderSystem. // Waits for rendering to finish in this function. s_RenderSystem.SwapBuffers(); // Transfers the rendering results remaining in the RenderSystem color buffer to the display buffer for SD Card writes. // // Immediately after RenderSystem.SwapBuffers is called, the command list is stopped (by default), so call Run. // To match the state after RenderSystem.SwapBuffers is called, clear the command list and stop. nngxTransferRenderImage(disp[currDispBuf], NN_GX_ANTIALIASE_NOT_USED, GL_FALSE, 0, 0); nngxRunCmdlist(); nngxWaitCmdlistDone(); nngxClearCmdlist(); nngxStopCmdlist(); int err; err = SaveDisplayBufferSD(L"sdmc:/test", L"test", i * div + j, addr[currDispBuf], nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, (u8 *)buf); if (err != 0) { NN_TLOG_("SaveDisplayBufferSD failed. (err: %d)\n", err); nngxDeleteDisplaybuffers(2, disp); return; } // If the same display buffer is used repeatedly, the previously written image will be corrupted because of cache issues. Use double buffering. // currDispBuf = (currDispBuf == 1 ? 0 : 1); NN_TLOG_("save. section (%d, %d)\n", i, j); } } s_AppHeap.Free(buf); NN_TLOG_("done.\n"); nngxDeleteDisplaybuffers(2, disp); } int DrawFrame(bool isCapture) { if (isCapture) { DrawDisplay0AndSave(); } else { DrawDisplay0(); } s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); s_RenderSystem.Clear(); s_RenderSystem.SwapBuffers(); s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH); s_Count++; return !glGetError(); } /* initialization */ int Initialize(void) { // fs initialization nn::fs::Initialize(); // Will not work without SD Card nn::Result result = nn::fs::MountSdmc(); if (result.IsFailure()) { NN_PANIC("SD memory card is unavailable."); } const size_t ROMFS_BUFFER_SIZE = 1024 * 64; static char buffer[ROMFS_BUFFER_SIZE]; NN_UTIL_PANIC_IF_FAILED( nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE)); nn::hid::Initialize(); s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() ); s_HeapForGx = reinterpret_cast(s_AppHeap.Allocate(s_GxHeapSize)); /* Initialize display */ s_RenderSystem.Initialize(s_HeapForGx, s_GxHeapSize); s_PgID = glCreateProgram(); s_ShID = glCreateShader(GL_VERTEX_SHADER); nn::fs::FileReader file(L"rom:/shader.shbin"); size_t fileSize = file.GetSize(); void* buf = s_AppHeap.Allocate(fileSize); s32 read = file.Read(buf, fileSize); glShaderBinary(1, &s_ShID, GL_PLATFORM_BINARY_DMP, buf, read); file.Finalize(); s_AppHeap.Free(buf); glAttachShader(s_PgID, s_ShID); glAttachShader(s_PgID, GL_DMP_FRAGMENT_SHADER_DMP); glBindAttribLocation(s_PgID, 0, "aPosition"); glBindAttribLocation(s_PgID, 1, "aColor"); glLinkProgram(s_PgID); glValidateProgram(s_PgID); glUseProgram(s_PgID); glClearColor(0.36f, 0.42f, 0.5f, 1.0f); glClearDepthf(1.f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glFrontFace(GL_CCW); LoadObjects(); glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].srcRgb"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR); glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].srcAlpha"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR); return 0; } void Finalize(void) { /* shutdown_display */ s_RenderSystem.Finalize(); s_AppHeap.Free(reinterpret_cast(s_HeapForGx)); s_AppHeap.Finalize(); }