/*---------------------------------------------------------------------------* Project: Horizon File: gx_FragmentLightingSimpleCmd.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 "MemoryManager.h" #include "nn/gx/CTR/gx_CommandAccess.h" namespace { GLuint s_CmdlistID = 0; GLuint s_FramebufferID = 0; GLuint s_RenderbufferID[2]; GLuint s_Displaybuffer0ID[2]; GLuint s_Displaybuffer1ID[2]; GLint s_CurrentDisplaybuffer0 = 0; GLint s_CurrentDisplaybuffer1 = 0; nn::fnd::ExpHeap s_AppHeap; uptr s_HeapForGx; const u32 s_GxHeapSize = 0x800000; nn::math::Vector3 s_CameraPosition(0.0f, 1.0f, 4.0f); nn::math::Vector3 s_CameraUp(0.0f, 1.0f, 0.0f); nn::math::Vector3 s_CameraTarget(0.0f, 0.0f, 0.0f); nn::math::Matrix34 s_ViewMatrix; u32 s_MaterialShininess = 8; GLuint s_ArrayBufferID = 0; GLuint s_ElementArrayBufferID = 0; GLfloat* s_VertexArray = NULL; GLushort* s_IndexArray = NULL; const u32 LUT_TABLE_SIZE = 512; const u32 LUT_TABLE_HALF_SIZE = LUT_TABLE_SIZE / 2; GLfloat s_LutArray[LUT_TABLE_SIZE]; u32 s_VertexAttributeBaseAddress = 0x0; u32 s_VertexAttribute0AddressOffset = 0x0; u32 s_VertexAttribute1AddressOffset = 0x0; u32 s_VertexAttribute2AddressOffset = 0x0; u32 s_VertexIndexAddressOffset = 0x0; u32 s_VertexNum = 4; u32 s_IndexNum = 6; const u32 FRAME_COUNTER_THRE = 60; u32 s_FrameCount = 0; } void InitializeGraphics(void); void InitializeVBO(void); void InitializeD0Lut(const u32 materialShininess); void AddDepthBufferCommand(void); void UpdateCamera(void); void DrawDisplay0(void); void DrawDisplay1(void); void AddViewportCommand(const s32 display); void AddFirstDrawCommand(void); void AddVertexShaderCommand(void); void AddVertexAttributeCommand(void); void AddVertexShaderUniformCommand(void); void AddTextureCombinerCommand(void); void AddFragmentLightCommand(void); void AddLUTCommand(void); void AddDrawPlaneCommand(void); void AddFrameBufferControlCommand(void); void 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)); InitializeGraphics(); } void InitializeVBO(void) { u32 positionSize = sizeof(GLfloat) * 4 * s_VertexNum; u32 colorSize = sizeof(GLfloat) * 4 * s_VertexNum; u32 normalSize = sizeof(GLfloat) * 3 * s_VertexNum; u32 vertexSize = positionSize + colorSize + normalSize; u32 indexSize = sizeof(GLushort) * s_IndexNum; 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; s_VertexArray = (GLfloat*) demo::memory_manager::Alloc(NN_GX_MEM_VERTEXBUFFER, vertexSize); u32 vertexArrayPhysicalAddress = nngxGetPhysicalAddr( (uptr) s_VertexArray ); // NN_LOG("s_VertexArray = 0x%x, Physical address = 0x%p\n", s_VertexArray, vertexArrayPhysicalAddress); f32 s_HalfEdge = 2.0f; // Position s_VertexArray[0] = s_HalfEdge; s_VertexArray[1] = 0.0f; s_VertexArray[2] = s_HalfEdge; s_VertexArray[3] = 1.0f; s_VertexArray[4] = (- s_HalfEdge); s_VertexArray[5] = 0.0f; s_VertexArray[6] = s_HalfEdge; s_VertexArray[7] = 1.0f; s_VertexArray[8] = (- s_HalfEdge); s_VertexArray[9] = 0.0f; s_VertexArray[10] = (- s_HalfEdge); s_VertexArray[11] = 1.0f; s_VertexArray[12] = s_HalfEdge; s_VertexArray[13] = 0.0f; s_VertexArray[14] = (- s_HalfEdge); s_VertexArray[15] = 1.0f; // Color u32 offset = 4 * s_VertexNum; 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] = 0.0f; s_VertexArray[offset + 5] = 1.0f; s_VertexArray[offset + 6] = 0.0f; s_VertexArray[offset + 7] = 0.0f; s_VertexArray[offset + 8] = 0.0f; s_VertexArray[offset + 9] = 0.0f; s_VertexArray[offset + 10] = 1.0f; s_VertexArray[offset + 11] = 1.0f; s_VertexArray[offset + 12] = 1.0f; s_VertexArray[offset + 13] = 1.0f; s_VertexArray[offset + 14] = 0.0f; s_VertexArray[offset + 15] = 1.0f; // Normal offset += 16; s_VertexArray[offset + 0] = 0.0f; s_VertexArray[offset + 1] = 1.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] = 1.0f; s_VertexArray[offset + 8] = 0.0f; s_VertexArray[offset + 9] = 0.0f; s_VertexArray[offset + 10] = 1.0f; s_VertexArray[offset + 11] = 0.0f; s_IndexArray = (GLushort*) demo::memory_manager::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); // Index s_IndexArray[0] = 0; s_IndexArray[1] = 2; s_IndexArray[2] = 1; s_IndexArray[3] = 0; s_IndexArray[4] = 3; s_IndexArray[5] = 2; glGenBuffers(1, &s_ArrayBufferID); glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferID); glBufferData(arrayFlag, vertexSize, 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_VertexAttribute2AddressOffset = alignOffset + positionSize + colorSize; s_VertexIndexAddressOffset = indexArrayPhysicalAddress - baseAddress; } void InitializeGraphics(void) { s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() ); s_HeapForGx = reinterpret_cast(s_AppHeap.Allocate(s_GxHeapSize)); demo::memory_manager::InitializeMemoryManager(s_HeapForGx, s_GxHeapSize); nngxInitialize(demo::memory_manager::GetAllocator, demo::memory_manager::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.3f, 0.3f, 0.3f, 1.0f); glClearDepthf(1.0f); AddDepthBufferCommand(); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glCullFace(GL_BACK); InitializeD0Lut(s_MaterialShininess); 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 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 InitializeD0Lut(const u32 materialShininess) { for (u32 index = 0; index < LUT_TABLE_SIZE; index++) { s_LutArray[index] = 0.0f; } for (u32 j = 0; j < LUT_TABLE_HALF_SIZE; j++) { f32 value = 1.0f; for (u32 count = 0; count < materialShininess; count++) { value *= (j / 255.0f); } s_LutArray[j] = value; } for (u32 j = 0; j < (LUT_TABLE_HALF_SIZE - 1); j++) { s_LutArray[j + LUT_TABLE_HALF_SIZE] = s_LutArray[j + 1] - s_LutArray[j]; } s_LutArray[(LUT_TABLE_HALF_SIZE - 1) + LUT_TABLE_HALF_SIZE] = 1.0f - s_LutArray[LUT_TABLE_HALF_SIZE - 1]; } void Finalize(void) { if ( s_VertexArray != NULL ) { demo::memory_manager::Free(s_VertexArray); s_VertexArray = NULL; } if ( s_IndexArray != NULL ) { demo::memory_manager::Free(s_IndexArray); s_IndexArray = NULL; } nngxFinalize(); s_AppHeap.Free(reinterpret_cast( s_HeapForGx) ); s_AppHeap.Finalize(); } bool DrawFrame(void) { UpdateCamera(); DrawDisplay0(); DrawDisplay1(); 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 true; } void UpdateCamera(void) { nn::math::MTX34LookAt(&s_ViewMatrix, s_CameraPosition, s_CameraUp, s_CameraTarget); } void DrawDisplay0(void) { static bool firstFlag = true; glBindFramebuffer(GL_FRAMEBUFFER, s_FramebufferID); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); AddViewportCommand(NN_GX_DISPLAY0); if ( firstFlag ) { AddFirstDrawCommand(); firstFlag = false; } AddDrawPlaneCommand(); nngxSplitDrawCmdlist(); nngxRunCmdlist(); nngxWaitCmdlistDone(); nngxTransferRenderImage(s_Displaybuffer0ID[s_CurrentDisplaybuffer0], NN_GX_ANTIALIASE_NOT_USED, GL_FALSE, 0, 0); } void AddFirstDrawCommand(void) { AddVertexShaderCommand(); AddVertexAttributeCommand(); AddVertexShaderUniformCommand(); AddFragmentLightCommand(); AddLUTCommand(); } void AddVertexShaderCommand(void) { /* s_ProgramId = glCreateProgram(); // Load vertex shader s_ShaderId = 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_ShaderId, GL_PLATFORM_BINARY_DMP, buf, read); file.Finalize(); s_AppHeap.Free(buf); glAttachShader(s_ProgramId, s_ShaderId); glAttachShader(s_ProgramId, GL_DMP_FRAGMENT_SHADER_DMP); glBindAttribLocation(s_ProgramId, 0, "aPosition"); glBindAttribLocation(s_ProgramId, 1, "aColor"); glBindAttribLocation(s_ProgramId, 2, "aNormal"); glLinkProgram(s_ProgramId); glValidateProgram(s_ProgramId); */ { u32 commandBuffer[] = { // 0x229 // Do not use geometry shader PICA_CMD_SET_VS_GS_MODE(0, 0), // 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); } { u32 commandBuffer[] = { // Vertex shader program data // BurstSingle (28 times, BE 0xF) // 0x2CC : 0xBE24000 0xBE24000, PICA_CMD_HEADER_BURST(PICA_REG_VS_PROG_DATA0, 28), // 0x2CC : 0xBE25001 // 0x2CC : 0xBE26002 0xBE25001, 0xBE26002, // 0x2CC : 0xBE27003 // 0x2CC : 0x7C26102 0xBE27003, 0x7C26102, // 0x2CC : 0x7C24100 // 0x2CC : 0x7C25101 0x7C24100, 0x7C25101, // 0x2CC : 0x4C41F004 // 0x2CC : 0x8020F80 0x4C41F004, 0x8020F80, // 0x2CC : 0x8021F81 // 0x2CC : 0xB807DF05 0x8021F81, 0xB807DF05, // 0x2CC : 0x287DF06 // 0x2CC : 0x8022F82 0x287DF06, 0x8022F82, // 0x2CC : 0x8023F83 // 0x2CC : 0x2287EA07 0x8023F83, 0x2287EA07, // 0x2CC : 0x4C27D008 // 0x2CC : 0x3E814009 0x4C27D008, 0x3E814009, // 0x2CC : 0x22A7EF07 // 0x2CC : 0xA1805401 0x22A7EF07, 0xA1805401, // 0x2CC : 0x3821400A // 0x2CC : 0x20215A0B 0x3821400A, 0x20215A0B, // 0x2CC : 0x4C27D00C // 0x2CC : 0x84000000 0x4C27D00C, 0x84000000, // 0x2CC : 0x84000000 // 0x2CC : 0x90000017 0x84000000, 0x90000017, // 0x2CC : 0x4C60100D // 0x2CC : 0x88000000 0x4C60100D, 0x88000000, // 0x2CC : 0x84000000 0x84000000, 0x0 }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { u32 commandBuffer[] = { // Notification that update of vertex shader program is complete // 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); } { 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 (14 times, BE 0xF) // 0x2D6 : 0x8006C368 PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C368), PICA_CMD_HEADER_BURST(PICA_REG_VS_PROG_SWIZZLE_DATA0, 14), // 0x2D6 : 0x8006C364 // 0x2D6 : 0x8006C362 PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C364), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C362), // 0x2D6 : 0x8006C361 // 0x2D6 : 0x8000037F PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C361), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8000037F), // 0x2D6 : 0x802A8AB0 // 0x2D6 : 0x802A8AAF PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x802A8AB0), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x802A8AAF), // 0x2D6 : 0x8006D54F // 0x2D6 : 0x80000001 PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006D54F), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x80000001), // 0x2D6 : 0x8000000F // 0x2D6 : 0x80000002 PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8000000F), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x80000002), // 0x2D6 : 0x8006C36C // 0x2D6 : 0x8000080E PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C36C), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8000080E), // 0x2D6 : 0x8000036F PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8000036F), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x0), }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { u32 commandBuffer[] = { // BurstSequence (4 times, BE 0xF) // 0x2C0 : 0x5D PICA_CMD_DATA_VS_FLOAT_ADDR(PICA_DATA_VS_F24, 0x5D), PICA_CMD_HEADER_BURSTSEQ(PICA_REG_VS_FLOAT_ADDR, 0x4), // 0x2C1 : 0x40800040 // 0x2C2 : 0x3F00 PICA_CMD_DATA_VS_FLOAT_DATA(0x40800040), PICA_CMD_DATA_VS_FLOAT_DATA(0x3F00), // 0x2C3 : 0x0 PICA_CMD_DATA_VS_FLOAT_DATA(0x0), PICA_CMD_DATA_VS_FLOAT_DATA(0x0) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { u32 commandBuffer[] = { // BurstSequence (4 times, BE 0xF) // 0x2C0 : 0x5E PICA_CMD_DATA_VS_FLOAT_ADDR(PICA_DATA_VS_F24, 0x5E), PICA_CMD_HEADER_BURSTSEQ(PICA_REG_VS_FLOAT_ADDR, 0x4), // 0x2C1 : 0x3D00003E // 0x2C2 : 0x3700 PICA_CMD_DATA_VS_FLOAT_DATA(0x3D00003E), PICA_CMD_DATA_VS_FLOAT_DATA(0x3700), // 0x2C3 : 0x3C0000 PICA_CMD_DATA_VS_FLOAT_DATA(0x3C0000), PICA_CMD_DATA_VS_FLOAT_DATA(0x0) }; 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] 0xF : size=4, GL_FLOAT // Attribute1 [11:8] 0xB : size=3, GL_FLOAT // // 0x202 : 0x20000000 // [31:28] TotalVertexAttributeNum - 1 0xBFF, 0x20000000, // 0x203 : 0x8 // 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 : 0x10100000 // [23:16] : Number of bytes per vertex in load array 1: 16 (Bytes) // [31:28] : Number of elements in load array 1: 1 0x1, 0x10100000, // 0x209 : 0x88 // 0x20A : 0x2 internal vertex attribute 2 s_VertexAttribute2AddressOffset, 0x2, // 0x20B : 0x100C0000 // [23:16] : Number of bytes per vertex in load array 1: 12 (Bytes) // [31:28] : Number of elements in load array 1: 1 // 0x20C : 0x0 0x100C0000, 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 : 0x210 (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) // [11:8] = 2 (The index of the input register for the storage location of the third vertex attribute that was input) PICA_CMD_DATA_VS_ATTR_IN_REG_MAP0(0, 1, 2, 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); } /* glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0) ; glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*) positionSize); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*) (positionSize + colorSize) ); */ { u32 commandBuffer[] = { // Register that sets the number of vertex attribute inputs. // // 0x2B9 : 0xA0000000 | 0x2 (BE 0xB = 1011(2) ) // PICA_CMD_DATA_VS_ATTR_NUM0(0x3), PICA_CMD_HEADER_SINGLE_BE(PICA_REG_VS_ATTR_NUM0, 0xB), // // 0x242 : 0x2 (BE 0xF) // PICA_CMD_DATA_VS_ATTR_NUM1(0x3), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_ATTR_NUM1) PICA_CMD_SET_VS_ATTR_NUM(0x3), // Register that sets the number of vertex attributes to input to the vertex shader // // 0x4F : 0x4 // 0x4, PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_NUM0) // // 0x24A : 0x3 (BE 0xF) // 0x4 - 0x1, PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_NUM1), // // 0x251 [3:0] : 0x3 (BE 0xF) // 0x4 - 0x1, PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_NUM2), PICA_CMD_SET_VS_GS_OUT_REG_NUM(0x4), // 0x2BA [15:0] : Sets the data address of the vertex shader // [31:16] : Sets 0x7FFF // 0x7FFF0018 (BE 0xF) PICA_CMD_DATA_VS_START_ADDR(0x18), 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(0xF), 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 : 0x7060504 (BE 0xF) // #pragma output_map ( quaternion, o1 ) // [ 4: 0] : Quaternion x, 0x04 // [12: 8] : Quaternion y, 0x05 // [20:16] : Quaternion z, 0x06 // [28:24] : Quaternion w, 0x07 PICA_CMD_DATA_VS_GS_OUT_ATTR(PICA_DATA_VS_OUT_ATTR_QUART_X, PICA_DATA_VS_OUT_ATTR_QUART_Y, PICA_DATA_VS_OUT_ATTR_QUART_Z, PICA_DATA_VS_OUT_ATTR_QUART_W), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_ATTR1), // Register that sets the vertex shader output attribute // 0x52 : 0x1F141312 // #pragma output_map ( view, o2 ) // [ 4: 0] : View vector x, 0x12 // [12: 8] : View vector y, 0x13 // [20:16] : View vector z, 0x14 // [28:24] : Invalid, 0x1f PICA_CMD_DATA_VS_GS_OUT_ATTR(PICA_DATA_VS_OUT_ATTR_VIEW_X, PICA_DATA_VS_OUT_ATTR_VIEW_Y, PICA_DATA_VS_OUT_ATTR_VIEW_Z, PICA_DATA_VS_OUT_ATTR_INVALID), PICA_CMD_HEADER_SINGLE(0x52), // 0x53 : 0xB0A0908 // #pragma output_map ( color, o3 ) // [ 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(0x53), // Clock control setting register for output attributes from the vertex shader // 0x6F : 0x1000003 (BE 0xF) // Output vertex coordinates z, output vertex colors, output view vectors, and quaternions // PICA_CMD_DATA_VS_GS_OUT_ATTR_CLK(1, 1, 0, 0, 0, 0, 1), 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 s_Display0ProjectionMatrix; nn::math::Matrix44 s_Display1ProjectionMatrix; nn::math::MTX34LookAt(&s_ViewMatrix, s_CameraPosition, s_CameraUp, s_CameraTarget); nn::math::MTX44 modelViewMatrix(s_ViewMatrix); nn::math::Matrix44 worldMatrix; MTX44Identity(&worldMatrix); nn::math::MTX44Mult(&modelViewMatrix, &modelViewMatrix, &worldMatrix); glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_MODELVIEW], 1, GL_TRUE, static_cast(modelViewMatrix)); glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION], 1, GL_TRUE, static_cast(s_Display0ProjectionMatrix)); */ { u32 commandBuffer[] = { // Index of floating-point registers for vertex shader // 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); } { u32 commandBuffer[] = { // Settings for floating-point registers of the vertex shader // 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 : 0x401A8279 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x401A8279), // 0x2C1 : 0x0 // 0x2C1 : 0x80000000 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x80000000), // 0x2C1 : 0x80000000 // 0x2C1 : 0x80000000 PICA_CMD_DATA_VS_FLOAT(0x80000000), PICA_CMD_DATA_VS_FLOAT(0x80000000), // 0x2C1 : 0xBFB9695E // 0x2C1 : 0x3DCDD443 PICA_CMD_DATA_VS_FLOAT(0xBFB9695E), PICA_CMD_DATA_VS_FLOAT(0x3DCDD443), // 0x2C1 : 0x3F80A4AA // 0x2C1 : 0x0 PICA_CMD_DATA_VS_FLOAT(0x3F80A4AA), 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 : 0xBE785B43 // 0x2C1 : 0x3F785B43 PICA_CMD_DATA_VS_FLOAT(0xBE785B43), PICA_CMD_DATA_VS_FLOAT(0x3F785B43), // 0x2C1 : 0x0 // 0x2C1 : 0xC083F07C PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0xC083F07C), // 0x2C1 : 0x3F785B43 // 0x2C1 : 0x3E785B43 PICA_CMD_DATA_VS_FLOAT(0x3F785B43), PICA_CMD_DATA_VS_FLOAT(0x3E785B43), // 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 PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0) }; 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[] = { // 0xd0 : 0xF210F21 (BE 0xF) // srcRgb, srcAlpha // glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_RGB], // GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_FRAGMENT_SECONDARY_COLOR_DMP, GL_PREVIOUS); // glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_ALPHA], // GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_FRAGMENT_SECONDARY_COLOR_DMP, GL_PREVIOUS); PICA_CMD_DATA_TEX_ENV_SRC(PICA_DATA_TEX_ENV_SRC_RGBA_FRAGMENT_PRIMARY_COLOR_DMP, PICA_DATA_TEX_ENV_SRC_RGBA_FRAGMENT_SECONDARY_COLOR_DMP, PICA_DATA_TEX_ENV_SRC_RGBA_PREVIOUS, PICA_DATA_TEX_ENV_SRC_RGBA_FRAGMENT_PRIMARY_COLOR_DMP, PICA_DATA_TEX_ENV_SRC_RGBA_FRAGMENT_SECONDARY_COLOR_DMP, PICA_DATA_TEX_ENV_SRC_RGBA_PREVIOUS), PICA_CMD_HEADER_SINGLE(PICA_REG_TEX_ENV2), // combineRgb, combineAlpha // 0xd2 : 0x20002 (BE 0xF) // glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_RGB], GL_ADD); // glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_ALPHA], GL_ADD); PICA_CMD_DATA_TEX_ENV_COMBINE(PICA_DATA_TEX_ENV_COMBINE_ADD, PICA_DATA_TEX_ENV_COMBINE_ADD), PICA_CMD_HEADER_SINGLE(PICA_REG_TEX_ENV2_COMBINE) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } } void AddFragmentLightCommand(void) { /* // LightEnv glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_LIGHT_ENV_CONFIG], GL_LIGHT_ENV_LAYER_CONFIG0_DMP); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_LIGHT_ENV_LUT_ENABLED_REFL], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_LIGHT_ENV_CLAMP_HIGHLIGHTS], GL_TRUE); // D0 glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_LIGHT_ENV_ABS_LUT_INPUT_D0], GL_TRUE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_LIGHT_ENV_LUT_INPUT_D0], GL_LIGHT_ENV_NH_DMP); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_SAMPLER_D0], 0); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_GEOM_FACTOR1], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_GEOM_FACTOR0], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_TWO_SIDE_DIFFUSE], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE1_ENABLED], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE2_ENABLED], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE3_ENABLED], GL_FALSE); */ // Enable FragmentLight // glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_ENABLED], GL_TRUE); // 0x8F : 0x1 (BE 0xF) // 0x1C6 : 0x0 (BE 0xF) { u32 commandBuffer[] = { PICA_CMD_SET_FRAG_LIGHT_ENABLE(0x1) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } AddTextureCombinerCommand(); // 0x1c2 // glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_ENABLED], GL_TRUE); { // Light0 specular0, 0x140 : 0xFF3FCFF (BE 0xF) // glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_SPECULAR0], 1, s_MaterialSpecular0); // glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_SPECULAR1], 1, s_MaterialSpecular1); // glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_SPECULAR0], 1, s_Light0.m_Specular0); // glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_SPECULAR1], 1, s_Light0.m_Specular1); // dmp_FragmentMaterial.specular0 * dmp_FragmentLightSource[0].specular0 // dmp_FragmentMaterial.specular1 * dmp_FragmentLightSource[0].specular1 // Fragment uniform : Material // f32 s_MaterialSpecular0[] = {1.0f, 1.0f, 1.0f, 1.0f}; // f32 s_MaterialSpecular1[] = {0.0f, 0.0f, 0.0f, 1.0f}; // s_Light0.m_Specular0[0] = 1.0f; // s_Light0.m_Specular0[1] = 1.0f; // s_Light0.m_Specular0[2] = 1.0f; // s_Light0.m_Specular0[3] = 1.0f; // s_Light0.m_Specular1[0] = 0.0.0f; // s_Light0.m_Specular1[1] = 0.0.0f; // s_Light0.m_Specular1[2] = 0.0.0f; // s_Light0.m_Specular1[3] = 1.0f; u32 commandBuffer[] = { 0xff3fcff, PICA_CMD_HEADER_SINGLE(PICA_REG_FRAG_LIGHT_START) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } { u32 commandBuffer[] = { // Light0 diffuse, 0x142 h: 0x9900000 // f32 s_MaterialDiffuse[] = {0.6f, 0.6f, 0.6f, 1.0f}; // s_Light0.m_Diffuse[0] = 1.0f; // s_Light0.m_Diffuse[1] = 0.0.0f; // s_Light0.m_Diffuse[2] = 0.0.0f; // s_Light0.m_Diffuse[3] = 1.0f; // glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_DIFFUSE], 1, s_MaterialDiffuse); // glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_DIFFUSE], 1, s_Light0.m_Diffuse); // dmp_FragmentMaterial.diffuse * dmp_FragmentLightSource[0].diffuse 0x9900000, // BurstSequence (4 times, BE 0xF) PICA_CMD_HEADER_BURSTSEQ(PICA_REG_FRAG_LIGHT0_DIFFUSE, 0x4), // Light0 ambient, 0x143 : 0xA0280A // f32 s_MaterialAmbient[] = {0.2f, 0.2f, 0.2f, 1.0f}; // s_Light0.m_Ambient[0] = 0.2f; // s_Light0.m_Ambient[1] = 0.2f; // s_Light0.m_Ambient[2] = 0.2f; // s_Light0.m_Ambient[3] = 1.0f; // glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_AMBIENT], 1, s_Light0.m_Ambient); // glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_AMBIENT], 1, s_MaterialAmbient); // dmp_FragmentMaterial.ambient * dmp_FragmentLightSource[0].ambient 0xA0280A, // Light0 position_xy, 0x144 : 0x3BC20000 // s_Light0.m_Position[0] = 0.0f; // s_Light0.m_Position[1] = 1.0.0f; // s_Light0.m_Position[2] = 0.0f; // nn::math::MTX34 s_LightWorldMatrix; // nn::math::MTX34Identity(&s_LightWorldMatrix); // nn::math::VEC3 position(s_Light0.m_Position[0], s_Light0.m_Position[1], s_Light0.m_Position[2]); // nn::math::MTX34Translate(&s_LightWorldMatrix, &position); // nn::math::Matrix34 lightViewMatrix; // nn::math::MTX34Mult(&lightViewMatrix, s_ViewMatrix, s_LightWorldMatrix); // glUniform4f(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_POSITION], // lightViewMatrix.m[0][3], lightViewMatrix.m[1][3], lightViewMatrix.m[2][3], // 1.0f); // dmp_FragmentLightSource[i].position xy 0x3BC20000, // Light0 position_z, 0x145 : 0xC3C2 // dmp_FragmentLightSource[i].position z 0xC3C2, 0x0, // Light0 position.w 0x149 : 0x0 // dmp_FragmentLightSource[i].position w 0x0, PICA_CMD_HEADER_SINGLE(PICA_REG_FRAG_LIGHT0_TYPE) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } u32 fragLightFuncMode = 0; u32 shadowed = 0; u32 spotEnabled = 0; u32 distanceAttenuationEnabled = 0; for (u32 lightIndex = 0; lightIndex < 8; lightIndex++) { fragLightFuncMode |= PICA_CMD_DATA_FRAG_LIGHT_FUNC_MODE1_LIGHT_SOURCE(lightIndex, shadowed, spotEnabled, distanceAttenuationEnabled); } u32 lutEnabledD0 = 1; u32 lutEnabledD1 = 0; u32 fresnelSelector = 0; u32 lutEnabledRef1 = 0; fragLightFuncMode |= PICA_CMD_DATA_FRAG_LIGHT_FUNC_MODE1_LUT(lutEnabledD0, lutEnabledD1, fresnelSelector, lutEnabledRef1); { u32 commandBuffer[] = { // 0x1C0 : 0x1405014 (BE 0xF) // f32 s_GlobalAmbientLight[] = { 0.4f, 0.4f, 0.4f, 1.0f}; // glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_AMBIENT], 1, s_GlobalAmbientLight); 0x1405014, PICA_CMD_HEADER_SINGLE(PICA_REG_FRAG_LIGHT_AMBIENT), // 0x1C4 : 0xFFFEFFFF (BE 0xF) // glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_LIGHT_ENV_LUT_ENABLED_D0], GL_TRUE); fragLightFuncMode, PICA_CMD_HEADER_SINGLE(PICA_REG_FRAG_LIGHT_FUNC_MODE1), // 0x1D0 : 0x2222220 (BE 0xF) PICA_CMD_DATA_FRAG_LIGHT_ABSLUTINPUT(1, 0, 0, 0, 0, 0, 0), PICA_CMD_HEADER_SINGLE(PICA_REG_FRAG_LIGHT_ABSLUTINPUT) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } } // Convert from float32 to unsigned fixed12 (12-bit fraction) #define UTL_F2UFX_12W_0I(_inarg, _outarg) \ { \ float f_ = (_inarg); \ unsigned val_; \ unsigned v_ = *(unsigned*)&f_; \ if (f_ <= 0 || (v_ & 0x7f800000) == 0x7f800000) \ val_ = 0; \ else \ { \ f_ *= 1 << (12 - 0); \ if (f_ >= (1 << 12)) \ val_ = (1 << 12) - 1; \ else \ val_ = (unsigned)(f_); \ } \ (_outarg) = val_; \ } // Convert from float32 to signed fixed12 (11-bit fraction) #define UTL_F2FX_12W_1I_F(_inarg, _outarg) \ { \ float f_; \ unsigned v_; \ f_ = (_inarg); \ v_ = *(unsigned*)&f_; \ if (f_ == 0.f || (v_ & 0x7f800000) == 0x7f800000) \ _outarg = 0; \ else \ { \ f_ *= (1 << (12 - 1)); \ if (f_ < 0) \ { \ _outarg = 1 << (12 - 1); \ f_ = -f_; \ } \ else \ _outarg = 0; \ if (f_ >= (1 << (12 - 1))) f_ = (1 << (12 - 1)) - 1; \ _outarg |= (unsigned)(f_); \ } \ } void AddLUTCommand(void) { /* GLenum target = GL_LUT_TEXTURE0_DMP; glGenTextures(1, &s_D0LutTextureId); glBindTexture(GL_LUT_TEXTURE0_DMP, s_D0LutTextureId); glTexImage1D(target, 0, GL_LUMINANCEF_DMP, LUT_TABLE_SIZE, 0, GL_LUMINANCEF_DMP, GL_FLOAT, s_LutArray); */ { u32 commandBuffer[] = { // 0x1C5 : 0x0 (BE 0xF) PICA_CMD_DATA_FRAG_LIGHT_LUT(0x0, PICA_DATA_SAMPLER_D0), PICA_CMD_HEADER_SINGLE(PICA_REG_FRAG_LIGHT_LUT) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } // 0x1C8 u32 old_data = 0; for (u32 i = 0; i < LUT_TABLE_HALF_SIZE; i++) { u32 index0 = i; u32 index1 = i + 256; // Convert from float32 to unsigned fixed12 (12-bit fraction) u32 data0 = 0; UTL_F2UFX_12W_0I(s_LutArray[index0], data0); data0 &= 0xfff; // Convert from float32 to signed fixed12 (11-bit fraction) u32 data1 = 0; UTL_F2FX_12W_1I_F(s_LutArray[index1], data1); data1 &= 0xfff; u32 data = PICA_CMD_DATA_FRAG_LIGHT_LUT_DATA(data0, data1); if ( i == 0 ) { u32 commandBuffer[] = { data, PICA_CMD_HEADER_BURST(PICA_REG_FRAG_LIGHT_LUT_DATA0, LUT_TABLE_HALF_SIZE) }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } else if ( i == (LUT_TABLE_HALF_SIZE - 1) ) { u32 commandBuffer[] = { data, 0x0 }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } else if ( (i % 2) == 1 ) { old_data = data; } else if ( (i % 2) == 0 ) { u32 commandBuffer[] = { old_data, data }; nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE); } } } void AddDrawPlaneCommand(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); } // glDrawElements(GL_TRIANGLES, indexNum, GL_UNSIGNED_SHORT, 0); { 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: 6 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 0. // 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 disable stencil buffer write, set to [0:0] to 0. // 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 DrawDisplay1(void) { 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 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(); Initialize(); bool flag = true; while ( flag ) { flag = DrawFrame(); } Finalize(); }