/*---------------------------------------------------------------------------* Project: Horizon File: LightingSpotAtte.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 $ *---------------------------------------------------------------------------*/ /* *------------------------------------------------------------ * Copyright(c) 2009-2010 by Digital Media Professionals Inc. * All rights reserved. *------------------------------------------------------------ * This source code is the confidential and proprietary * of Digital Media Professionals Inc. *------------------------------------------------------------ */ #include #include #include #include #include #include #include "Util.h" #include "Loader.h" #include "demo.h" #include #include #include "Memory.h" #define APP_NAME "LightingSpotAtte" #define DMP_PI (3.1415926f) #define REV_PI (1.0f/DMP_PI) /* program id */ GLuint s_ProgramID; /* shader id */ GLuint s_ShaderID; /* ExpHeap for app. */ nn::fnd::ExpHeap s_AppHeap; uptr s_HeapForGx; uptr s_HeapForMalloc; const u32 s_GxHeapSize = 0x400000; const u32 s_HeapSize = 0x200000; demo::RenderSystem s_RenderSystem; static void SetRenderState(void) { GLfloat ld_0[] = {1.f, 0.f, 0.f, 1.f}; GLfloat ld_1[] = {0.f, 1.f, 0.f, 1.f}; GLfloat ld_2[] = {0.f, 0.f, 1.f, 1.f}; glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].diffuse"), 1, ld_0); glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].diffuse"), 1, ld_1); glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].diffuse"), 1, ld_2); /* setup spot lighting configuration */ /* Individual lookup tables are allocated for individual lights, but note that common settings for lookup table input and sampling methods are applied to all lights. */ glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputSP"), GL_LIGHT_ENV_SP_DMP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputSP"), GL_TRUE); GLuint lutids[3]; float lut[512]; unsigned int j; glGenTextures(3, lutids); #define COS_45 0.71f #define COS_40 0.77f #define COS_35 0.82f #define COS_30 0.87f #define COS_25 0.91f #define COS_20 0.94f #define COS_15 0.97f #define COS_10 0.98f memset( lut, 0, sizeof( lut ) ); for (j = 0; j < 256; j++) { float x = ( float )j / ( float )256; if ( x > COS_30 ) lut[j] = 1.f; } glBindTexture(GL_LUT_TEXTURE0_DMP, lutids[0]); glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].samplerSP"), 0); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].spotEnabled"), GL_TRUE); memset( lut, 0, sizeof( lut ) ); for (j = 0; j < 256; j++) { float x = ( float )j / ( float )256; if ( x > COS_20 ) lut[j] = 1.f; } glBindTexture(GL_LUT_TEXTURE1_DMP, lutids[1]); glTexImage1D(GL_LUT_TEXTURE1_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].samplerSP"), 1); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].spotEnabled"), GL_TRUE); memset( lut, 0, sizeof( lut ) ); for (j = 0; j < 256; j++) { float x = ( float )j / ( float )256; if ( x > COS_10 ) lut[j] = 1.f; } glBindTexture(GL_LUT_TEXTURE2_DMP, lutids[2]); glTexImage1D(GL_LUT_TEXTURE2_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].samplerSP"), 2); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].spotEnabled"), GL_TRUE); } void DrawPlane() { /* Using fragment lighting, you can create beautiful spotlights even on polygon models that are not finely divided. This differs from vertex lighting. In this sample, the spotlight is applied to a model composed of only 2 polygons. If vertex lighting were used to achieve the same effect, a finely divided model would have to be used. */ GLfloat coords[] = { -3.f, 0.f, 3.f, 3.f, 0.f, 3.f, 3.f, 0.f, -3.f, -3.f, 0.f, -3.f, }; GLfloat norm[] = { 0.f, 1.f, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 0.f, }; unsigned short index[] = { 0, 1, 2, 0, 2, 3 }; glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, coords); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, norm); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, index); } int DrawFrame(void) { static int f = 0; nn::math::Matrix34 mv, rot; s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); /* setup projection matrix */ nn::math::Matrix44 proj; nn::math::MTX44Frustum(&proj, -0.06f, 0.06f, -0.06f*nn::gx::DISPLAY0_HEIGHT/nn::gx::DISPLAY0_WIDTH, 0.06f*nn::gx::DISPLAY0_HEIGHT/nn::gx::DISPLAY0_WIDTH, 0.2f, 200.f); glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uProjection"), 1, GL_TRUE, static_cast(proj)); nn::math::Vector3 camPos(0.f, 7.f, 7.f); nn::math::Vector3 camUp(0.f, 1.f, 0.f); nn::math::Vector3 target(0.f, 0.f, 0.f); nn::math::MTX34RotXYZDeg(&rot, 0.f, 0.f, -90.0f); nn::math::MTX34LookAt(&mv, &camPos, &camUp, &target); nn::math::MTX34Mult(&mv, &rot, &mv); /* Light position and spotlight direction are converted to view coordinate values and then passed to the reserve fragment shader uniform.   The conversion to view coordinates is not absolute In this sample, the normals and view vectors needed for fragment lighting calculations are converted to view coordinates in the vertex shader      For this reason, light position and spotlight direction must be in view coordinates   Also note that the spot direction vector must be normalized before being passed */ /* setup light direction and spot direction (light0) */ nn::math::Vector4 lpos0(0.f, 1.f, 0.f, 1.f); lpos0.y = 3.f * cosf(2.f * f / 60.f) + 5.f; nn::math::Vector4 mv0(mv.m[0][0], mv.m[0][1], mv.m[0][2], mv.m[0][3]); nn::math::Vector4 mv1(mv.m[1][0], mv.m[1][1], mv.m[1][2], mv.m[1][3]); nn::math::Vector4 mv2(mv.m[2][0], mv.m[2][1], mv.m[2][2], mv.m[2][3]); nn::math::Vector4 lpos(VEC4Dot(&mv0, &lpos0), VEC4Dot(&mv1, &lpos0), VEC4Dot(&mv2, &lpos0), lpos0.w); glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].position"), 1, static_cast(lpos)); nn::math::Vector4 lpos0_dir(0.f, -1.f, 0.f, 0.f); lpos0_dir.x = 0.5f * cosf(2.f * f / 60.f); lpos0_dir.z = 0.5f * sinf(2.f * f / 60.f); nn::math::Vector4 lpos_dir(nn::math::VEC4Dot(&mv0, &lpos0_dir), nn::math::VEC4Dot(&mv1, &lpos0_dir), nn::math::VEC4Dot(&mv2, &lpos0_dir), lpos0_dir.w); lpos_dir.Normalize(); glUniform3fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].spotDirection"), 1, static_cast(lpos_dir)); /* setup light direction and spot direction (light1) */ nn::math::Vector4 lpos1(0.f, 1.f, 0.f, 1.f); lpos1.y = 3.f * cosf(2.5f * f / 60.f) + 4.f; lpos = nn::math::Vector4(nn::math::VEC4Dot(&mv0, &lpos1), nn::math::VEC4Dot(&mv1, &lpos1), nn::math::VEC4Dot(&mv2, &lpos1), lpos1.w); glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].position"), 1, static_cast(lpos)); nn::math::Vector4 lpos1_dir(0.f, -1.f, 0.f, 0.f); lpos1_dir.x = 0.5f * cosf(2.5f * f / 60.f); lpos1_dir.z = 0.5f * sinf(2.5f * f / 60.f); lpos_dir = nn::math::Vector4(nn::math::VEC4Dot(&mv0, &lpos1_dir), nn::math::VEC4Dot(&mv1, &lpos1_dir), nn::math::VEC4Dot(&mv2, &lpos1_dir), lpos1_dir.w); lpos_dir.Normalize(); glUniform3fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].spotDirection"), 1, static_cast(lpos_dir)); /* setup light direction and spot direction (light2) */ nn::math::Vector4 lpos2(0.f, 1.f, 0.f, 1.f); lpos2.y = 3.f * cosf(3.f * f / 60.f) + 4.f; lpos = nn::math::Vector4(nn::math::VEC4Dot(&mv0, &lpos2), nn::math::VEC4Dot(&mv1, &lpos2), nn::math::VEC4Dot(&mv2, &lpos2), lpos2.w); glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].position"), 1, static_cast(lpos)); nn::math::Vector4 lpos2_dir(0.f, -1.f, 0.f, 0.f); lpos2_dir.x = 0.5f * cosf(3.f * f / 60.f); lpos2_dir.z = 0.5f * sinf(3.f * f / 60.f); lpos_dir = nn::math::Vector4(nn::math::VEC4Dot(&mv0, &lpos2_dir), nn::math::VEC4Dot(&mv1, &lpos2_dir), nn::math::VEC4Dot(&mv2, &lpos2_dir), lpos2_dir.w); lpos_dir.Normalize(); glUniform3fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].spotDirection"), 1, static_cast(lpos_dir)); nn::math::Matrix44 m(mv); glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uModelView"), 1, GL_TRUE, static_cast(m)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); /* draw objects */ DrawPlane(); glFinish(); s_RenderSystem.SwapBuffers(); s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); s_RenderSystem.Clear(); s_RenderSystem.SwapBuffers(); s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH); f++; return !glGetError(); } /* initialization */ static int Initialize(void) { 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); /* Create heap for malloc*/ s_HeapForMalloc = reinterpret_cast(s_AppHeap.Allocate(s_HeapSize)); setMemoryHeap(s_HeapForMalloc, s_HeapSize); s_ProgramID = glCreateProgram(); 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, "aNormal"); glLinkProgram(s_ProgramID); glValidateProgram(s_ProgramID); glUseProgram(s_ProgramID); glClearColor(0.36f, 0.42f, 0.5f, 1.0f); glClearDepthf(1.f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glCullFace(GL_BACK); /* set another render state */ SetRenderState(); /* enable DMP fragment lighting */ glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLighting.enabled"), GL_TRUE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].enabled"), GL_TRUE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].enabled"), GL_TRUE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].enabled"), GL_TRUE); /* this sample use only fragment primary color */ glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineRgb"), GL_REPLACE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineAlpha"), GL_REPLACE); glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR); glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA); glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcRgb"), GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_CONSTANT, GL_CONSTANT); glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcAlpha"), GL_CONSTANT, GL_CONSTANT, GL_CONSTANT); return 0; } 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(); // 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)); /* initialization */ if (Initialize() >= 0) { /* Enter loop */ while (1) { (void)DrawFrame(); } } /* shutdown_display */ s_RenderSystem.Finalize(); s_AppHeap.Free(reinterpret_cast(s_HeapForMalloc)); s_AppHeap.Free(reinterpret_cast(s_HeapForGx)); s_AppHeap.Finalize(); }