/*---------------------------------------------------------------------------* Project: Horizon File: gx_TriangleSimpleCmd.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 #include #include "nn/gx/CTR/gx_CommandAccess.h" #include "MemoryManager.h" /* Objects for system API */ GLuint s_CmdlistID; GLuint s_FramebufferID; GLuint s_RenderbufferID[2]; GLuint s_Displaybuffer0ID[2]; GLuint s_Displaybuffer1ID[2]; GLint s_CurrentDisplaybuffer0 = 0; GLint s_CurrentDisplaybuffer1 = 0; /* buffer id */ GLuint s_ArrayBufferID; GLuint s_ElementArrayBufferID; /* ExpHeap for app. */ nn::fnd::ExpHeap s_AppHeap; uptr s_HeapForGx; const u32 s_GxHeapSize = 0x400000; GLfloat* s_VertexArray = NULL; GLushort* s_IndexArray = NULL; u32 s_VertexAttributeBaseAddress = 0x0; u32 s_VertexAttribute0AddressOffset = 0x0; u32 s_VertexAttribute1AddressOffset = 0x0; u32 s_VertexIndexAddressOffset = 0x0; u32 s_VertexNum = 3; u32 s_IndexNum = 3; const u32 FRAME_COUNTER_THRE = 60; u32 s_FrameCount = 0; int Initialize(void); void InitializeGraphics(void); void AddDepthBufferCommand(void); void InitializeVBO(void); int DrawFrame(void); void DrawFrameUpper(void); void DrawFrameLower(void); void AddViewportCommand(const s32 display); void AddFirstDrawCommand(void); void AddVertexShaderCommand(void); void AddVertexAttributeCommand(void); void AddVertexShaderUniformCommand(void); void AddTextureCombinerCommand(void); void AddDrawTriangleCommand(void); void AddFrameBufferControlCommand(void); int Initialize(void) { // fs initialization nn::fs::Initialize(); 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)); s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() ); s_HeapForGx = reinterpret_cast(s_AppHeap.Allocate(s_GxHeapSize)); InitializeGraphics(); return 0; } void InitializeGraphics(void) { demo::InitializeMemoryManager(s_HeapForGx, s_GxHeapSize); nngxInitialize(demo::GetAllocator, demo::GetDeallocator); /* Generate and allocate command list object */ nngxGenCmdlists(1, &s_CmdlistID); nngxBindCmdlist(s_CmdlistID); nngxCmdlistStorage(0x40000, 128); /* Generate, allocate and attach framebuffer object and render buffer */ glGenFramebuffers(1, &s_FramebufferID); glBindFramebuffer(GL_FRAMEBUFFER, s_FramebufferID); glGenRenderbuffers(2, s_RenderbufferID); glBindRenderbuffer(GL_RENDERBUFFER, s_RenderbufferID[0]); glRenderbufferStorage(GL_RENDERBUFFER | NN_GX_MEM_VRAMA, GL_RGBA8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, s_RenderbufferID[0]); glBindRenderbuffer(GL_RENDERBUFFER, s_RenderbufferID[1]); glRenderbufferStorage(GL_RENDERBUFFER | NN_GX_MEM_VRAMB, GL_DEPTH24_STENCIL8_EXT, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, s_RenderbufferID[1]); /* Generate and allocate display buffer; set display region */ nngxGenDisplaybuffers(2, s_Displaybuffer0ID); nngxActiveDisplay(NN_GX_DISPLAY0); nngxDisplayEnv(0, 0); nngxBindDisplaybuffer(s_Displaybuffer0ID[0]); nngxDisplaybufferStorage(GL_RGB8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, NN_GX_MEM_FCRAM); nngxBindDisplaybuffer(s_Displaybuffer0ID[1]); nngxDisplaybufferStorage(GL_RGB8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, NN_GX_MEM_FCRAM); nngxGenDisplaybuffers(2, s_Displaybuffer1ID); nngxActiveDisplay(NN_GX_DISPLAY1); nngxDisplayEnv(0, 0); nngxBindDisplaybuffer(s_Displaybuffer1ID[0]); nngxDisplaybufferStorage(GL_RGB8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, NN_GX_MEM_FCRAM); nngxBindDisplaybuffer(s_Displaybuffer1ID[1]); nngxDisplaybufferStorage(GL_RGB8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, NN_GX_MEM_FCRAM); nngxRunCmdlist(); glClearColor(0.36f, 0.42f, 0.5f, 1.0f); glClearDepthf(1.f); AddDepthBufferCommand(); glFrontFace(GL_CCW); InitializeVBO(); } void AddDepthBufferCommand(void) { /* glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); */ u32 commandBuffer[] = { // Depth test // 0x107 PICA_CMD_DATA_DEPTH_COLOR_MASK( // enableDepthTest 1, // depthFunc PICA_DATA_DEPTH_TEST_LESS, // red, green, blue, alpha 0, 0, 0, 0, // depthMask 0), PICA_CMD_HEADER_SINGLE_BE(PICA_REG_DEPTH_COLOR_MASK, 0x1), // dmp_Gas.deltaZ // 0x126 [25:24] PICA_CMD_DATA_GAS_DELTAZ_DEPTH(0, PICA_DATA_DEPTH_TEST2_OTHER), PICA_CMD_HEADER_SINGLE_BE(PICA_REG_GAS_DELTAZ_DEPTH, 0x8), }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } void InitializeVBO(void) { GLenum arrayFlag = GL_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP; GLenum elementArrayFlag = GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP; u32 positionSize = sizeof(GLfloat) * s_VertexNum * 4; u32 colorSize = sizeof(GLfloat) * s_VertexNum * 3; u32 indexSize = sizeof(GLushort) * s_IndexNum; s_VertexArray = (GLfloat*) demo::Alloc(NN_GX_MEM_VERTEXBUFFER, positionSize + colorSize); u32 vertexArrayPhysicalAddress = nngxGetPhysicalAddr( (uptr) s_VertexArray ); // NN_LOG("s_VertexArray = 0x%x, Physical address = 0x%p\n", s_VertexArray, vertexArrayPhysicalAddress); /* 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 }; */ s_VertexArray[ 0 ] = 0.5f; s_VertexArray[ 1 ] = 0.0f; s_VertexArray[ 2 ] = 0.0f; s_VertexArray[ 3 ] = 1.0f; s_VertexArray[ 4 ] = -0.5f; s_VertexArray[ 5 ] = 0.5f; s_VertexArray[ 6 ] = 0.0f; s_VertexArray[ 7 ] = 1.0f; s_VertexArray[ 8 ] = -0.5f; s_VertexArray[ 9 ] = -0.5f; s_VertexArray[ 10 ] = 0.0f; s_VertexArray[ 11 ] = 1.0f; /* GLfloat color[] = { 1.f, 1.0f, 0.0f, 0.f, 1.0f, 0.0f, 0.f, 0.0f, 1.0f }; */ const u32 offset = 12; s_VertexArray[ offset + 0 ] = 1.0f; s_VertexArray[ offset + 1 ] = 0.0f; s_VertexArray[ offset + 2 ] = 0.0f; s_VertexArray[ offset + 3 ] = 0.0f; s_VertexArray[ offset + 4 ] = 1.0f; s_VertexArray[ offset + 5 ] = 0.0f; s_VertexArray[ offset + 6 ] = 0.0f; s_VertexArray[ offset + 7 ] = 0.0f; s_VertexArray[ offset + 8 ] = 1.0f; s_IndexArray = (GLushort*) demo::Alloc(NN_GX_MEM_VERTEXBUFFER, indexSize); u32 indexArrayPhysicalAddress = nngxGetPhysicalAddr( (uptr) s_IndexArray); // NN_LOG("s_IndexArray = 0x%x, physical address = 0x%p\n", s_IndexArray, indexArrayPhysicalAddress); /* GLushort idxs[] = {0, 1, 2}; */ s_IndexArray[ 0 ] = 0; s_IndexArray[ 1 ] = 1; s_IndexArray[ 2 ] = 2; glGenBuffers(1, &s_ArrayBufferID); glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferID); glBufferData(arrayFlag, positionSize + colorSize, s_VertexArray, GL_STATIC_DRAW); glGenBuffers(1, &s_ElementArrayBufferID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_ElementArrayBufferID); glBufferData(elementArrayFlag, indexSize, s_IndexArray, GL_STATIC_DRAW); // Base address is aligned to 16 bytes u32 alignOffset = (uptr)vertexArrayPhysicalAddress % 16; u32 baseAddress = vertexArrayPhysicalAddress - alignOffset; s_VertexAttributeBaseAddress = PICA_CMD_DATA_VERTEX_ATTR_ARRAYS_BASE_ADDR(baseAddress); s_VertexAttribute0AddressOffset = vertexArrayPhysicalAddress - baseAddress; s_VertexAttribute1AddressOffset = alignOffset + positionSize; s_VertexIndexAddressOffset = indexArrayPhysicalAddress - baseAddress; } int DrawFrame(void) { DrawFrameUpper(); DrawFrameLower(); nngxActiveDisplay(NN_GX_DISPLAY0); nngxBindDisplaybuffer(s_Displaybuffer0ID[s_CurrentDisplaybuffer0]); nngxActiveDisplay(NN_GX_DISPLAY1); nngxBindDisplaybuffer(s_Displaybuffer1ID[s_CurrentDisplaybuffer1]); nngxSwapBuffers(NN_GX_DISPLAY_BOTH); s_CurrentDisplaybuffer0 = (s_CurrentDisplaybuffer0 == 0 ? 1 : 0); s_CurrentDisplaybuffer1 = (s_CurrentDisplaybuffer1 == 0 ? 1 : 0); nngxClearCmdlist(); nngxRunCmdlist(); nngxWaitVSync(NN_GX_DISPLAY_BOTH); if ( s_FrameCount == 0 ) { nngxStartLcdDisplay(); } if ( ( s_FrameCount % FRAME_COUNTER_THRE) == 0 ) { NN_LOG("Total frame count = %d\n", s_FrameCount); } s_FrameCount += 1; return 1; } void DrawFrameUpper(void) { static bool firstFlag = true; AddViewportCommand(NN_GX_DISPLAY0); glBindFramebuffer(GL_FRAMEBUFFER, s_FramebufferID); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); if ( firstFlag ) { AddFirstDrawCommand(); firstFlag = false; } AddDrawTriangleCommand(); nngxSplitDrawCmdlist(); nngxRunCmdlist(); nngxWaitCmdlistDone(); nngxTransferRenderImage(s_Displaybuffer0ID[s_CurrentDisplaybuffer0], NN_GX_ANTIALIASE_NOT_USED, GL_FALSE, 0, 0); } void DrawFrameLower(void) { // Just clear the lower screen; do not render anything AddViewportCommand(NN_GX_DISPLAY1); glBindFramebuffer(GL_FRAMEBUFFER, s_FramebufferID); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); nngxTransferRenderImage(s_Displaybuffer1ID[s_CurrentDisplaybuffer1], NN_GX_ANTIALIASE_NOT_USED, GL_FALSE, 0, 0); nngxRunCmdlist(); nngxWaitCmdlistDone(); } void AddViewportCommand(s32 display) { if ( display == NN_GX_DISPLAY0 ) { // glViewport(0, 0, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT); u32 commandBuffer[] = { // Set the Viewport width (set width to f32, divide by two, and convert to f24) // 0x41 0x45E000, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_WIDTH1), // Set the Viewport height (set height to f32, divide by two, and convert to f24) // 0x43 0x469000, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_HEIGHT1), // Set Viewport width (Divide 2 by width, convert to f31, and shift 1 bit left) // 0x42 0x38111111, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_WIDTH2), // Set Viewport height (Divide 2 by height, convert to f31, and shift 1 bit left) // 0x44 0x3747AE14, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_HEIGHT2), // x = 0, y = 0 // 0x68 PICA_CMD_DATA_VIEWPORT_XY(0, 0), PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_XY) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } else if ( display == NN_GX_DISPLAY1 ) { // glViewport(0, 0, nn::gx::DISPLAY1_WIDTH, nn::gx::DISPLAY1_HEIGHT); u32 commandBuffer[] = { // Set the Viewport width (set width to f32, divide by two, and convert to f24) // 0x41 0x45E000, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_WIDTH1), // Set the Viewport height (set height to f32, divide by two, and convert to f24) // 0x43 0x464000, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_HEIGHT1), // Set Viewport width (Divide 2 by width, convert to f31, and shift 1 bit left) // 0x42 0x38111111, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_WIDTH2), // Set Viewport height (Divide 2 by height, convert to f31, and shift 1 bit left) // 0x44 0x37999999, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_HEIGHT2), // x = 0, y = 0 // 0x68 PICA_CMD_DATA_VIEWPORT_XY(0, 0), PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_XY) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } } void AddFirstDrawCommand(void) { AddVertexShaderCommand(); AddVertexAttributeCommand(); AddVertexShaderUniformCommand(); AddTextureCombinerCommand(); } void AddVertexShaderCommand(void) { /* 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); */ { u32 commandBuffer[] = { // Do not use geometry shader // 0x229 PICA_CMD_SET_VS_GS_MODE(0x0, 0x0), // Do not use geometry shader // 0x244 : 0x0 (BE 0x1) PICA_CMD_SET_VS_COM_MODE(0x0), // Set the load address for the vertex shader program code to 0 // 0x2CB : 0x0 (BE 0xF) PICA_CMD_DATA_VS_PROG_ADDR(0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_PROG_ADDR) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { // Vertex shader program data u32 commandBuffer[] = { // BurstSingle (13 times, BE 0xF) // 0x2CC : 0xBE24000 0xBE24000, PICA_CMD_HEADER_BURST(PICA_REG_VS_PROG_DATA0, 13), // 0x2CC : 0xBE25001 // 0x2CC : 0xBE26002 0xBE25001, 0xBE26002, // 0x2CC : 0xBE27003 // 0x2CC : 0x8020F80 0xBE27003, 0x8020F80, // 0x2CC : 0x8021F81 // 0x2CC : 0x8022F82 0x8021F81, 0x8022F82, // 0x2CC : 0x8023F83 // 0x2CC : 0x84000000 0x8023F83, 0x84000000, // 0x2CC : 0x90000008 // 0x2CC :0x4C201004 0x90000008, 0x4C201004, // 0x2CC : 0x88000000 // 0x2CC : 0x84000000 0x88000000, 0x84000000 }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { // Notification that update of vertex shader program is complete u32 commandBuffer[] = { // 0x2BF : 0x1 (BE 0xF) PICA_CMD_DATA_VS_PROG_END(0x1), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_PROG_UPDATE_END) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { // Swizzle u32 commandBuffer[] = { // Set the Swizzle pattern's load address to 0 // 0x2D5 : 0x0 (BE 0xF) PICA_CMD_DATA_VS_PROG_SWIZZLE_ADDR(0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_PROG_SWIZZLE_ADDR), // Set the Swizzle pattern's data // BurstSingle (5 times, BE 0xF) // 0x2D6 : 0x8006C368 PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C368), PICA_CMD_HEADER_BURST(PICA_REG_VS_PROG_SWIZZLE_DATA0, 5), // 0x2D6 : 0x8006C364 // 0x2D6 : 0x8006C362 PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C364), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C362), // 0x2D6 : 0x8006C361 // 0x2D6 : 0x8000036F PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C361), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8000036F) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } } void AddVertexAttributeCommand(void) { { u32 commandBuffer[] = { // BurstSequence (39 times, BE 0xF) // Common base address for all vertex arrays // 0x200 : BaseAddress s_VertexAttributeBaseAddress, PICA_CMD_HEADER_BURSTSEQ(PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 39), // 0x201 : 0xBFF // Attribute0 [3:0] 0xF : size=4, GL_FLOAT // Attribute1 [7:4] 0xB : size=3, GL_FLOAT // // 0x202 : 0x10000000 // [31:28] TotalVertexAttributeNum - 1 0xBF, 0x10000000, // 0x203 : 0x0 // Byte offset from the the base address of load array 0 // // 0x204 : 0x0 // [3:0] The 1st element of load array 0 is internal vertex attribute 0 s_VertexAttribute0AddressOffset, 0x0, // 0x205 : 0x10100000 // [23:16] : Number of bytes per vertex in load array 0: 16 (Bytes) // [31:28] : Number of elements in load array 0: 1 // // 0x206 : 0x30 // Byte offset from the the base address of load array 1 0x10100000, s_VertexAttribute1AddressOffset, // 0x207 : 0x1 // [3:0] The 1st element of load array 1 is internal vertex attribute 1 // // 0x208 : 0x100C0000 // [23:16] : Number of bytes per vertex in load array 1: 12 (Bytes) // [31:28] : Number of elements in load array 1: 1 0x1, 0x100C0000, // 0x209 : 0x0 // 0x20A : 0x0 0x0, 0x0, // 0x20B : 0x0 // 0x20C : 0x0 0x0, 0x0, // 0x20D : 0x0 // 0x20E : 0x0 0x0, 0x0, // 0x20F : 0x0 // 0x210 : 0x0 0x0, 0x0, // 0x211 : 0x0 // 0x212 : 0x0 0x0, 0x0, // 0x213 : 0x0 // 0x214 : 0x0 0x0, 0x0, // 0x215 : 0x0 // 0x216 : 0x0 0x0, 0x0, // 0x217 : 0x0 // 0x218 : 0x0 0x0, 0x0, // 0x219 : 0x0 // 0x21A : 0x0 0x0, 0x0, // 0x21B : 0x0 // 0x21C : 0x0 0x0, 0x0, // 0x21D : 0x0 // 0x21E : 0x0 0x0, 0x0, // 0x21F : 0x0 // 0x220 : 0x0 0x0, 0x0, // 0x221 : 0x0 // 0x222 : 0x0 0x0, 0x0, // 0x223 : 0x0 // 0x224 : 0x0 0x0, 0x0, // 0x225 : 0x0 // 0x226 : 0x0 0x0, 0x0 }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { u32 commandBuffer[] = { // 0x2BB : 0x10 (BE 0xF) // Register that sets the input register map for vertex attributes 0-8 // [3:0] = 0 (The index of the input register for the storage location of the first vertex attribute that was input) // [7:4] = 1 (The index of the input register for the storage location of the second vertex attribute that was input) PICA_CMD_DATA_VS_ATTR_IN_REG_MAP0(0, 1, 0, 0, 0, 0, 0, 0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_ATTR_IN_REG_MAP0), // 0x2BC : 0x0 (BE 0xF) // Register that sets the input register map for vertex attributes 9-12 PICA_CMD_DATA_VS_ATTR_IN_REG_MAP1(0, 0, 0, 0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_ATTR_IN_REG_MAP1) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { u32 commandBuffer[] = { // Register that sets the number of vertex attribute inputs. // // 0x2B9 : 0xA0000000 | 0x1, (BE 0xB = 1011(2) ) // PICA_CMD_DATA_VS_ATTR_NUM0(0x2), PICA_CMD_HEADER_SINGLE_BE(PICA_REG_VS_ATTR_NUM0, 0xB), // // 0x242 : 0x1 (BE 0xF) // PICA_CMD_DATA_VS_ATTR_NUM1(0x2), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_ATTR_NUM1) PICA_CMD_SET_VS_ATTR_NUM( 0x2 ), // Register that sets the number of vertex attributes to input to the vertex shader // // 0x4F : 0x2 // 0x2, PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_NUM0) // // 0x24A : 0x1 (BE 0xF) // 0x1, PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_NUM1), // // 0x251 [3:0] : 0x2 (BE 0xF) // 0x1, PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_NUM2), PICA_CMD_SET_VS_GS_OUT_REG_NUM( 0x2 ), // 0x2BA [15:0] : Sets the data address of the vertex shader // [31:16] : Sets 0x7FFF // 0x7FFF0009 (BE 0xF) PICA_CMD_DATA_VS_START_ADDR(0x9), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_START_ADDR), // 0x2BD : 0x3 (BE 0xF) // Set the mask for the vertex shader output register (o0 = [0:0], o1 = [1;1]) PICA_CMD_DATA_VS_OUT_MASK(0x3), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_MASK), // Register that sets the vertex shader output attribute // 0x50 : 0x3020100 (BE 0xF) // #pragma output_map ( position, o0 ) // [ 4: 0] : Vertex coordinate x, 0x00 // [12: 8] : Vertex coordinate y, 0x01 // [20:16] : Vertex coordinate z, 0x02 // [28:24] : Vertex coordinate w, 0x03 PICA_CMD_DATA_VS_GS_OUT_ATTR(PICA_DATA_VS_OUT_ATTR_X, PICA_DATA_VS_OUT_ATTR_Y, PICA_DATA_VS_OUT_ATTR_Z, PICA_DATA_VS_OUT_ATTR_W), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_ATTR0), // Register that sets the vertex shader output attribute // 0x51 : 0xB0A0908 (BE 0xF) // #pragma output_map (color, o1) // [ 4: 0] : Vertex color R, 0x08 // [12: 8] : Vertex color G, 0x09 // [20:16] : Vertex color B, 0x0a // [28:24] : Vertex color A, 0x0b PICA_CMD_DATA_VS_GS_OUT_ATTR(PICA_DATA_VS_OUT_ATTR_R, PICA_DATA_VS_OUT_ATTR_G, PICA_DATA_VS_OUT_ATTR_B, PICA_DATA_VS_OUT_ATTR_A), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_ATTR1), // Clock control setting register for output attributes from the vertex shader // 0x6F : 0x3 (BE 0xF) // Output the vertex's z coordinate; output the vertex color PICA_CMD_DATA_VS_GS_OUT_ATTR_CLK(1, 1, 0, 0, 0, 0, 0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_ATTR_CLK) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } } void AddVertexShaderUniformCommand(void) { /* // Upper screen vertex uniform settings 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 * 0.0f); nn::math::MTX34Mult(&eye, &eye, &rot); nn::math::Matrix44 mv(eye); glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, (f32*)(mv)); */ { // Index of floating-point registers for vertex shader u32 commandBuffer[] = { // 0x2C0 : 0x80000000 (BE 0xF) PICA_CMD_DATA_VS_FLOAT_ADDR(PICA_DATA_VS_F32, 0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_FLOAT_ADDR) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { // Settings for floating-point registers of the vertex shader u32 commandBuffer[] = { // BurstSingle (32 times, BE 0xF) // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_HEADER_BURST(PICA_REG_VS_FLOAT1, 32), // 0x2C1 : 0x0 // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0), // 0x2C1 : 0x41200000 // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0x41200000), PICA_CMD_DATA_VS_FLOAT(0x0), // 0x2C1 : 0x0 // 0x2C1 : 0x40BFFFFF PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x40BFFFFF), // 0x2C1 : 0x0 // 0x2C1 : 0x3E50FAC6 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x3E50FAC6), // 0x2C1 : 0x3F829CBC // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0x3F829CBC), PICA_CMD_DATA_VS_FLOAT(0x0), // 0x2C1 : 0x0 // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0), // 0x2C1 : 0xBF800000 // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0xBF800000), PICA_CMD_DATA_VS_FLOAT(0x0), // 0x2C1 : 0x0 // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0), // 0x2C1 : 0x0 // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0), // 0x2C1 : 0x3F800000 // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0x3F800000), PICA_CMD_DATA_VS_FLOAT(0x0), // 0x2C1 : 0xBD2C4F7C // 0x2C1 : 0x3F7FC5FC PICA_CMD_DATA_VS_FLOAT(0xBD2C4F7C), PICA_CMD_DATA_VS_FLOAT(0x3F7FC5FC), // 0x2C1 : 0x0 // 0x2C1 : 0xC118227B PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0xC118227B), // 0x2C1 : 0x3F7FC5FC // 0x2C1 : 0x3D2C4F7C PICA_CMD_DATA_VS_FLOAT(0x3F7FC5FC), PICA_CMD_DATA_VS_FLOAT(0x3D2C4F7C), // 0x2C1 : 0x0 // 0x2C1 : 0x3F800000 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x3F800000), // 0x2C1 : 0x0 // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0), // 0x2C1 : 0x0, 0x5544 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x5544) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { u32 commandBuffer[] = { // Vertex shader Boolean register // 0x2B0 : 0x7FFF0000 (BE 0xF) PICA_CMD_DATA_VS_BOOL(0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_BOOL), // Vertex shader integer register i0 // 0x2B1 : 0x0 (BE 0xF) PICA_CMD_DATA_VS_INT(0x0, 0x0, 0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_INT0), // Vertex shader integer register i1 // 0x2B2 : 0x0 (BE 0xF) PICA_CMD_DATA_VS_INT(0x0, 0x0, 0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_INT1), // Vertex shader integer register i2 // 0x2B3 : 0x0 (BE 0xF) PICA_CMD_DATA_VS_INT(0x0, 0x0, 0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_INT2), // Vertex shader integer register i3 // 0x2B4 : 0x0 (BE 0xF) PICA_CMD_DATA_VS_INT(0x0, 0x0, 0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_INT3) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } } void AddTextureCombinerCommand(void) { { u32 commandBuffer[] = { // 0xc0 + 0 // srcRgb, srcAlpha // 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); PICA_CMD_DATA_TEX_ENV_SRC(PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR, PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR, PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR, PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR, PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR, PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR), // 0xc0 // Start register of texture combiner 0 PICA_CMD_HEADER_BURSTSEQ(PICA_REG_TEX_ENV0, 0x5), // operandRgb, operandAlpha // 0xc0 + 1 // glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR); // glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA); PICA_CMD_DATA_TEX_ENV_OPERAND(PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA), // combineRgb, combineAlpha // 0xc0 + 2 // glUniform1i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].combineRgb"), GL_REPLACE); // glUniform1i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].combineAlpha"), GL_REPLACE); PICA_CMD_DATA_TEX_ENV_COMBINE(PICA_DATA_TEX_ENV_COMBINE_REPLACE, PICA_DATA_TEX_ENV_COMBINE_REPLACE), // constRgba // 0xc0 + 3 // glUniform4f(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].constRgba"), 0.0f, 0.0f, 0.0f, 0.0f); PICA_CMD_DATA_TEX_ENV_CONST(0x0, 0x0, 0x0, 0x0), // scaleRgb, scaleAlpha // 0xc0 + 4 // glUniform1f(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].scaleRgb"), 1.0f); // glUniform1f(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].scaleAlpha"), 1.0f); PICA_CMD_DATA_TEX_ENV_SCALE(PICA_DATA_TEX_ENV_SCALE_1, PICA_DATA_TEX_ENV_SCALE_1) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } } void AddDrawTriangleCommand(void) { AddFrameBufferControlCommand(); { u32 commandBuffer[] = { // 0x229 // Using glDrawElements function and GL_TRIANGLES, so drawMode = 1 PICA_CMD_SET_DRAW_MODE0( 1 ) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { u32 commandBuffer[] = { // 0x253 [0:8] // Using glDrawElements function and GL_TRIANGLES, so [8:8] = 1 0x100, PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE1, 0x2 ), // 0x25e [9:8] // Using glDrawElements function and mode = GL_TRIANGLES, so [9:8] = PICA_DATA_DRAW_TRIANGLES = 3 PICA_CMD_SET_DRAW_MODE2( PICA_DATA_DRAW_TRIANGLES ), // Clear the internal states of vertex indices when drawing triangles // 0x25f PICA_CMD_DATA_START_DRAW_FUNC1(0x1), PICA_CMD_HEADER_SINGLE(PICA_REG_START_DRAW_FUNC1), // 0x253[0:0] is set equal to 0 when nngxInitialize() is run, so this is unnecessary. // 0x253 [0:0] // Using vertex buffer and glDrawElements function, so [0:0] = 0 // PICA_CMD_DATA_DRAW_MODE1(0x0, 0x0), // PICA_CMD_HEADER_SINGLE_BE(PICA_REG_DRAW_MODE1, 0x1), // 0x227 [27:0] // Vertex index address offset // Vertex index type is GL_UNSIGNED_SHORT, so [31:31] = 1 PICA_CMD_DATA_INDEX_ARRAY_ADDR_OFFSET(s_VertexIndexAddressOffset, PICA_DATA_INDEX_ARRAY_UNSIGNED_SHORT), PICA_CMD_HEADER_SINGLE(PICA_REG_INDEX_ARRAY_ADDR_OFFSET), // 0x228 [31:0] // Set the number of vertices to render: 3 s_IndexNum, PICA_CMD_HEADER_SINGLE(PICA_REG_DRAW_VERTEX_NUM), // Render kick command macro // 1. Set to 0 immediately before Draw // 0x245 = 0x0 // 2. Render kick command // 0x22f = Write 1 to any bit // 3. Set to 1 immediately after Draw // 0x245 = 0x1 // 4. Immediately after the render kick command, clear the vertex cache. // 0x231 = 0x1 PICA_CMD_SET_START_DRAW_ELEMENT(1), // Immediately after the render kick command, clear both color buffer and depth buffer caches. PICA_CMD_SET_COLOR_DEPTH_BUFFER_CLEAR(0x1, 0x1), }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } } void AddFrameBufferControlCommand(void) { { u32 cmdbuf[] = { // Clear the color buffer and depth buffer caches. PICA_CMD_SET_COLOR_DEPTH_BUFFER_CLEAR(0x1, 0x1), // To disable color buffer read, set to 0 // 0x112 [3:0] PICA_CMD_DATA_FRAME_BUFFER_MODE(0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_COLOR_BUFFER_READ), // To enable color buffer write, set to 0xF. // 0x113 [3:0] PICA_CMD_DATA_FRAME_BUFFER_MODE(0xF), PICA_CMD_HEADER_SINGLE(PICA_REG_COLOR_BUFFER_WRITE), // To enable depth buffer read, set [1:1] to 1. // To disable stencil buffer read, set to [0:0] to 1. // 0x114 [1:0] PICA_CMD_DATA_FRAME_BUFFER_MODE(0x2), PICA_CMD_HEADER_SINGLE(PICA_REG_DEPTH_STENCIL_BUFFER_READ), // To enable depth buffer write, set to [1:1] to 1. // To enable stencil buffer write, set [0:0] to 1. // 0x115 [1:0] PICA_CMD_DATA_FRAME_BUFFER_MODE(0x2), PICA_CMD_HEADER_SINGLE(PICA_REG_DEPTH_STENCIL_BUFFER_WRITE), // Clear the color buffer and depth buffer caches. PICA_CMD_SET_COLOR_DEPTH_BUFFER_CLEAR(0x1, 0x1) }; nngxAdd3DCommand(cmdbuf, sizeof(cmdbuf), GL_TRUE); } } void nnMain(void) { // Call only nn::applet::Enable to also allow execution from the HOME Menu // HOME Menu transitions, POWER Button presses, and sleep are all unsupported nn::applet::Enable(); /* initialization */ if (Initialize() >= 0) { while (1) { (void)DrawFrame(); } } if ( s_VertexArray != NULL ) { demo::Free(s_VertexArray); s_VertexArray = NULL; } if ( s_IndexArray != NULL ) { demo::Free(s_IndexArray); s_IndexArray = NULL; } nngxFinalize(); /* shutdown_display */ s_AppHeap.Free(reinterpret_cast(s_HeapForGx)); s_AppHeap.Finalize(); }