/*---------------------------------------------------------------------------* Project: Horizon File: gx_RenderToTexture.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 "demo.h" namespace { GLuint s_ProgramId = 0; GLuint s_ShaderId = 0; nn::fnd::ExpHeap s_AppHeap; uptr s_AddrForGxHeap; const u32 s_GxHeapSize = 0x400000; demo::RenderSystem s_RenderSystem; nn::math::Vector3 s_CameraPosition(0.0f, 4.0f, 6.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; nn::math::Matrix44 s_Display0ProjectionMatrix; nn::math::Matrix44 s_Display1ProjectionMatrix; nn::math::Matrix44 s_RenderTextureProjectionMatrix; const u32 MAX_LIGHT_NUM = 1; f32 s_GlobalAmbientLight[] = { 0.4f, 0.4f, 0.4f, 1.0f}; demo::Light s_LightArray[MAX_LIGHT_NUM]; f32 s_MaterialAmbient[] = {0.2f, 0.2f, 0.2f, 1.0f}; f32 s_MaterialDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f}; f32 s_MaterialSpecular0[] = {1.0f, 1.0f, 1.0f, 1.0f}; f32 s_MaterialSpecular1[] = {0.0f, 0.0f, 0.0f, 1.0f}; demo::Cube s_Cube; GLuint s_FrameBufferId = 0; GLuint s_RenderColorTextureId = 0; GLsizei s_RenderTextureWidth = 256; GLsizei s_RenderTextureHeight = 256; GLuint s_DepthBufferId = 0; const nn::math::Vector3 s_InitialPosition(0.0f, -3.0f, 0.0f); const nn::math::Vector3 s_InitialVelocity(0.0f, 1.0f, 0.0f); const nn::math::Vector3 s_Gravity(0.0f, -0.1f, 0.0f); const f32 s_DeltaTime = 0.1f; const u32 MAX_PARTICLE_NUM = 64; demo::Particle s_ParticleArray[MAX_PARTICLE_NUM]; } void InitializeGraphics(void); void InitializeParticles(void); void InitializeLights(void); void InitializeShader(void); void InitializeRenderTexture(void); void Finalize(void); void UseShader(void); void UpdateCamera(void); void UpdateLights(void); void UpdateParticles(void); void RenderTexture(void); void DrawDisplay0(void); void DrawDisplay1(void); void UseShaderParticle(void); void DrawParticles(void); void UseShaderTexture(void); void UpdateBody(demo::Body& body); void DrawBody(demo::Body& body); 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(); InitializeParticles(); } void InitializeGraphics(void) { s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() ); s_AddrForGxHeap = reinterpret_cast(s_AppHeap.Allocate(s_GxHeapSize)); s_RenderSystem.Initialize(s_AddrForGxHeap, s_GxHeapSize); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClearDepthf(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glCullFace(GL_BACK); InitializeLights(); InitializeShader(); InitializeRenderTexture(); // Initialize projection matrix nn::math::MTX44PerspectivePivotDeg(&s_Display0ProjectionMatrix, 45.0f, demo::DISPLAY0_ASPECT, 0.1f, 20.0f, nn::math::PIVOT_UPSIDE_TO_TOP); nn::math::MTX44PerspectivePivotDeg(&s_Display1ProjectionMatrix, 45.0f, demo::DISPLAY1_ASPECT, 0.1f, 20.0f, nn::math::PIVOT_UPSIDE_TO_TOP); nn::math::MTX44PerspectivePivotDeg(&s_RenderTextureProjectionMatrix, 45.0f, 1.0f, 0.1f, 20.0f, nn::math::PIVOT_NONE); // Initialize cube u32 vertexAttributes = demo::VERTEX_POSITION_ATTRIBUTE | demo::VERTEX_COLOR_ATTRIBUTE | demo::VERTEX_NORMAL_ATTRIBUTE | demo::VERTEX_TEXCOORD_ATTRIBUTE; s_Cube.InitializeCube(vertexAttributes, 1.6f, 1.6f, 1.6f); s_Cube.SetColor(1.0f, 0.0f, 0.0f); s_Cube.SetWorldPosition(0.0f, 0.0f, 0.0f); s_Cube.SetWorldAngle(0.0f, 0.0f, 0.0f); } void InitializeLights(void) { for (u32 lightIndex = 0; lightIndex < MAX_LIGHT_NUM; lightIndex++) { s_LightArray[lightIndex].Initialize(); } // Light0 u32 lightIndex = 0; s_LightArray[lightIndex].m_Ambient[0] = 0.0f; s_LightArray[lightIndex].m_Ambient[1] = 0.0f; s_LightArray[lightIndex].m_Ambient[2] = 0.0f; s_LightArray[lightIndex].m_Ambient[3] = 1.0f; s_LightArray[lightIndex].m_Diffuse[0] = 0.9f; s_LightArray[lightIndex].m_Diffuse[1] = 0.9f; s_LightArray[lightIndex].m_Diffuse[2] = 0.9f; s_LightArray[lightIndex].m_Diffuse[3] = 1.0f; s_LightArray[lightIndex].m_Specular0[0] = 0.0f; s_LightArray[lightIndex].m_Specular0[1] = 0.0f; s_LightArray[lightIndex].m_Specular0[2] = 0.0f; s_LightArray[lightIndex].m_Specular0[3] = 0.0f; } void InitializeRenderTexture(void) { glGenFramebuffers(1, &s_FrameBufferId); glGenTextures(1, &s_RenderColorTextureId); glBindTexture(GL_TEXTURE_2D, s_RenderColorTextureId); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, s_RenderTextureWidth, s_RenderTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); GLfloat bcolor[] = {0.0f, 1.0f, 0.0f, 1.0f}; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bcolor); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glGenRenderbuffers(1, &s_DepthBufferId); glBindRenderbuffer(GL_RENDERBUFFER, s_DepthBufferId); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_EXT, s_RenderTextureWidth, s_RenderTextureHeight); glBindFramebuffer(GL_FRAMEBUFFER, s_FrameBufferId); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s_RenderColorTextureId, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, s_DepthBufferId); } void InitializeShader(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, "aTexcoord"); glBindAttribLocation(s_ProgramId, 3, "aNormal"); glLinkProgram(s_ProgramId); glValidateProgram(s_ProgramId); demo::InitializeUniforms(s_ProgramId); } void InitializeParticles(void) { demo::Particle::s_InitialPosition = ::s_InitialPosition; demo::Particle::s_InitialVelocity = ::s_InitialVelocity; demo::Particle::s_Gravity = ::s_Gravity; for (u32 particleIndex = 0; particleIndex < MAX_PARTICLE_NUM; particleIndex++) { s_ParticleArray[particleIndex].Initialize(); } } void Finalize(void) { s_Cube.Finalize(); for (u32 particleIndex = 0; particleIndex < MAX_PARTICLE_NUM; particleIndex++) { s_ParticleArray[particleIndex].Finalize(); } glDeleteTextures(1, &s_RenderColorTextureId); glDeleteRenderbuffers(1, &s_DepthBufferId); s_RenderSystem.Finalize(); s_AppHeap.Free(reinterpret_cast(s_AddrForGxHeap)); s_AppHeap.Finalize(); } bool DrawFrame(void) { UpdateCamera(); UpdateParticles(); RenderTexture(); DrawDisplay0(); DrawDisplay1(); s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH); return true; } void UpdateCamera(void) { nn::math::MTX34LookAt(&s_ViewMatrix, s_CameraPosition, s_CameraUp, s_CameraTarget); } void UpdateParticles(void) { for (u32 particleIndex = 0; particleIndex < MAX_PARTICLE_NUM; particleIndex++) { s_ParticleArray[particleIndex].Update(s_DeltaTime); } } void RenderTexture(void) { glBindFramebuffer(GL_FRAMEBUFFER, s_FrameBufferId); glViewport(0, 0, s_RenderTextureWidth, s_RenderTextureHeight); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); UseShaderParticle(); glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION], 1, GL_TRUE, static_cast(s_RenderTextureProjectionMatrix)); DrawParticles(); } void UseShaderParticle(void) { glUseProgram(s_ProgramId); // Fragment uniform glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_ALPHA_TEST], GL_FALSE); // Fragment uniform : Texture samplerType glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE0_SAMPLER_TYPE], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE1_SAMPLER_TYPE], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE2_SAMPLER_TYPE], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE3_SAMPLER_TYPE], GL_FALSE); // Fragment uniform : Fragment lighting glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_ENABLED], GL_FALSE); // Fragment uniform : Texture combiner glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_RGB], GL_PRIMARY_COLOR, GL_PREVIOUS, GL_PREVIOUS); glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_ALPHA], GL_PRIMARY_COLOR, GL_PREVIOUS, GL_PREVIOUS); glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_RGB], GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR); glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_ALPHA], GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_RGB], GL_REPLACE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_ALPHA], GL_REPLACE); } void DrawDisplay0(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); s_RenderSystem.Clear(); UseShaderTexture(); glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION], 1, GL_TRUE, static_cast(s_Display0ProjectionMatrix)); UpdateBody(s_Cube); DrawBody(s_Cube); s_RenderSystem.SwapBuffers(); } void UseShaderTexture(void) { glUseProgram(s_ProgramId); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, s_RenderColorTextureId); // Fragment uniform glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_ALPHA_TEST], GL_FALSE); // Fragment uniform : Texture samplerType glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE0_SAMPLER_TYPE], GL_TEXTURE_2D); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE1_SAMPLER_TYPE], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE2_SAMPLER_TYPE], GL_FALSE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE3_SAMPLER_TYPE], GL_FALSE); // Fragment uniform : Fragment lighting glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_ENABLED], GL_TRUE); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_AMBIENT], 1, s_GlobalAmbientLight); // Light0 u32 lightIndex = 0; glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_ENABLED], GL_TRUE); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_AMBIENT], 1, s_LightArray[lightIndex].m_Ambient); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_DIFFUSE], 1, s_LightArray[lightIndex].m_Diffuse); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_SPECULAR0], 1, s_LightArray[lightIndex].m_Specular0); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_SPECULAR1], 1, s_LightArray[lightIndex].m_Specular1); // Compute Light0 view matrix nn::math::MTX34 s_LightWorldMatrix; nn::math::MTX34Identity(&s_LightWorldMatrix); nn::math::VEC3 position(0.0f, 10.0f, 10.0f); 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); 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); // Fragment uniform : Material glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_AMBIENT], 1, s_MaterialAmbient); glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_DIFFUSE], 1, s_MaterialDiffuse); 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); // Fragment uniform : Texture combiner glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_RGB], GL_TEXTURE0, GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_PREVIOUS); glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_ALPHA], GL_TEXTURE0, GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_PREVIOUS); glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_RGB], GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR); glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_ALPHA], GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_RGB], GL_MODULATE); glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_ALPHA], GL_MODULATE); } void DrawParticles(void) { for (u32 particleIndex = 0; particleIndex < MAX_PARTICLE_NUM; particleIndex++) { DrawBody(s_ParticleArray[particleIndex]); } } void DrawDisplay1(void) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); s_RenderSystem.Clear(); glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION], 1, GL_TRUE, static_cast(s_Display1ProjectionMatrix)); UseShaderParticle(); DrawParticles(); s_RenderSystem.SwapBuffers(); } void UpdateBody(demo::Body& body) { f32 worldAngle[3]; body.GetWorldAngle(worldAngle[0], worldAngle[1], worldAngle[2]); worldAngle[1] += 1.0f; if ( worldAngle[1] > 360.0f ) { worldAngle[1] = 0.0f; } body.SetWorldAngle(worldAngle[0], worldAngle[1], worldAngle[2]); } void DrawBody(demo::Body& body) { nn::math::MTX44 modelViewMatrix(s_ViewMatrix); nn::math::Matrix44 worldMatrix = body.GetWorldMatrix(); nn::math::MTX44Mult(&modelViewMatrix, &modelViewMatrix, &worldMatrix); glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_MODELVIEW], 1, GL_TRUE, static_cast(modelViewMatrix)); body.Draw(); } 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(); }