/*---------------------------------------------------------------------------* Project: Horizon File: LightingSss.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. *------------------------------------------------------------ */ /* * Comments * -------- * * This example is the rendering translucent materials in Maestro. See Subsurface-Scattering Model * section of "ILLUMINATION MODELS IN MAESTRO" for details. * The following papers can help you understand the LUT settings. * Jensen,H., Marschner,S., Levoy,H., and Hanrahan,P., A Practical Model for Subsurface Light Transport * Jensen,H. and Buhler,J., A Rapid Hierarchical Rendering Technique for Translucent Materials * Kolchin,K., Curvature-Based Shading of Translucent Materials ,such as Human Skin */ #include #include #include #include #include #include #include "demo.h" #include "Util.h" #include "Loader.h" #include #include #include "Memory.h" #define APP_NAME "LightingSSS" #define DMP_PI (3.1415926f) #define REV_PI (1.0f/DMP_PI) /* env texture name */ GLuint s_EnvTexName; /* obj file loader class object */ dat_t hand; /* program name */ GLuint s_ProgramID; /* shader name */ GLuint s_ShaderID; /* texture collection name */ GLuint s_TexColl; /* 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 SetLutTable(void) { struct { float albedo[3]; float dif_refl[4]; float beta[3]; float beta_prime[3]; float zr[3]; float Bi; float F_dr; float refi; float m; float i0[3]; float i1[3]; } mat; GLfloat qlut[3][512], lut[512]; int j, co; GLuint lutids[6]; glGenTextures(6, lutids); for (co = 0; co < 3; co++) memset(qlut[co], 0, sizeof(qlut[0])); memset(lut, 0, sizeof(lut)); GLfloat A, refi, sigma_s_prim[3], sigma_a[3], sigma_t_prim[3], geom_scale = 0.24f; refi = 1.4f; #if 0 /* face */ sigma_s_prim[0] = 1.09f; sigma_s_prim[1] = 1.59f; sigma_s_prim[2] = 1.79f; sigma_a[0] = 0.013f; sigma_a[1] = 0.070f; /* 0.085; */ /* <-- use these values for more sun-tanned skin */ sigma_a[2] = 0.145f; /* 0.180; */ #else /* hand */ sigma_s_prim[0] = 1.09f; sigma_s_prim[1] = 1.39f; sigma_s_prim[2] = 1.3f; sigma_a[0] = 0.013f; sigma_a[1] = 0.120f; sigma_a[2] = 0.295f; #endif mat.F_dr = - 1.440f / (refi * refi) + 0.71f / refi + 0.668f + 0.0636f * refi; A = (1.0f + mat.F_dr) / (1.0f - mat.F_dr); mat.Bi = 1.0f + (4.0f / 3.0f) * A; mat.refi = refi; for (co = 0; co < 3; co++) { sigma_t_prim[co] = sigma_s_prim[co] + sigma_a[co]; mat.zr[co] = geom_scale / sigma_t_prim[co]; mat.albedo[co] = sigma_s_prim[co] / sigma_t_prim[co]; mat.beta[co] = sqrt(3.0f * (1.0f - mat.albedo[co])); mat.beta_prime[co] = mat.beta[co] * mat.Bi; mat.dif_refl[co] = 0.5f * mat.albedo[co] * (exp(-mat.beta[co]) + exp(-mat.beta_prime[co])); mat.i0[co] = exp(-mat.beta[co]) * sqrt(2.0f * DMP_PI / mat.beta[co]) + mat.Bi * exp(-mat.beta_prime[co]) * sqrt(2.0f * DMP_PI / mat.beta_prime[co]); mat.i1[co] = DMP_PI * (exp(-mat.beta[co]) + exp(-mat.beta_prime[co])) / mat.i0[co]; } float gamma, LN, h, kappa, display_gamma = 0.47f; for (j = 0; j < 128; j++) { LN = (float)j/128.f; kappa = 1.0f - LN * LN; for (co = 0; co < 3; co++) { /* R(LN) is sum of lambertian term(linear term)and wrapping term(non-linear term). */ if (LN > 0.f) qlut[co][j] = mat.dif_refl[co] * LN; gamma = mat.zr[co] * sqrt(kappa); h = fabsf(LN) / gamma; qlut[co][j] += mat.i0[co] * (1.0f / (1.0f + mat.i1[co] * h)) * gamma * mat.albedo[co] * 0.25f * REV_PI; qlut[co][j] = pow(qlut[co][j], display_gamma); } } for (j = 128; j < 256; j++) { LN = (float)(j - 256) /128.f; kappa = 1.0f - LN * LN; for (co = 0; co < 3; co++) { if (LN > 0.f) qlut[co][j] = mat.dif_refl[co] * LN; gamma = mat.zr[co] * sqrt(kappa); h = fabsf(LN) / gamma; qlut[co][j] += mat.i0[co] * (1.0f / (1.0f + mat.i1[co] * h)) * gamma * mat.albedo[co] * 0.25f * REV_PI; qlut[co][j] = pow(qlut[co][j], display_gamma); } } for (j = 0; j < 127; j++) for (co = 0; co < 3; co++) qlut[co][j + 256] = qlut[co][j + 1] - qlut[co][j]; for (co = 0; co < 3; co++) qlut[co][127 + 256] = pow(mat.dif_refl[co], display_gamma) - qlut[co][127]; for (j = 128; j < 255; j++) for (co = 0; co < 3; co++) qlut[co][j + 256] = qlut[co][j + 1] - qlut[co][j]; for (co = 0; co < 3; co++) qlut[co][255 + 256] = qlut[co][0] - qlut[co][255]; glBindTexture(GL_LUT_TEXTURE0_DMP, lutids[0]); glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, qlut[0]); glBindTexture(GL_LUT_TEXTURE1_DMP, lutids[1]); glTexImage1D(GL_LUT_TEXTURE1_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, qlut[1]); glBindTexture(GL_LUT_TEXTURE2_DMP, lutids[2]); glTexImage1D(GL_LUT_TEXTURE2_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, qlut[2]); /* T(NV) term setting */ for (j = 0; j < 256; j++) { lut[j] = 1.f - r_fresnel((float)j / 255.9375f, 1.7f, 0.36f, 0.f); lut[j] = pow(lut[j], display_gamma); } for (j = 0; j < 255; j++) lut[j + 256] = lut[j + 1] - lut[j]; lut[255 + 256] = pow((1.f - r_fresnel(1.f, 1.7f, 0.36f, 0.f)), display_gamma) - lut[255]; glBindTexture(GL_LUT_TEXTURE3_DMP, lutids[3]); glTexImage1D(GL_LUT_TEXTURE3_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut); /* distribution function of specular setting */ /* beckmann function is used. */ memset(lut, 0, sizeof(lut)); for (j = 0; j < 128; j++) lut[j] = beckmann((float)j / 128.f, 0.5f); for (j = 128; j < 256; j++) lut[j] = 0.f; for (j = 0; j < 127; j++) lut[j + 256] = lut[j + 1] - lut[j]; lut[127 + 256] = 1.f - lut[127]; for (j = 128; j < 256; j++) lut[j + 256] = 0; glBindTexture(GL_LUT_TEXTURE4_DMP, lutids[4]); glTexImage1D(GL_LUT_TEXTURE4_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut); /* fresnel function is used for environment illumination. is is looked up by dot product NV. */ memset(lut, 0, sizeof(lut)); for (j = 0; j < 256; j++) /*lut[j] = 0.6f * r_fresnel((float)j / 255.9375f, 2.f, 0.35f, 0.f);*/ lut[j] = r_fresnel((float)j / 255.9375f, 2.f, 0.35f, 0.f); for (j = 0; j < 255; j++) lut[j + 256] = lut[j + 1] - lut[j]; /*lut[255 + 256] = 0.6f * r_fresnel(1.f, 2.f, 0.35f, 0.f) - lut[255];*/ lut[255 + 256] = r_fresnel(1.f, 2.f, 0.35f, 0.f) - lut[255]; glBindTexture(GL_LUT_TEXTURE5_DMP, lutids[5]); glTexImage1D(GL_LUT_TEXTURE5_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut); } /* load objects */ static void LoadObjects(void) { /* load obj file geometory and diffuse texture */ loadDAT( "rom:/resources/hand.dat", &hand); /* load env texture */ char *env_tex[] = { "rom:/resources/bright1.tga", "rom:/resources/bright1.tga", "rom:/resources/bright1.tga", "rom:/resources/bright1.tga", "rom:/resources/bright1.tga", "rom:/resources/bright1.tga", }; glGenTextures(1, &s_EnvTexName); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, s_EnvTexName); for (int face = 0; face < 6; face++) { bool use_alpha; loadTexture(env_tex[face], GL_TEXTURE_CUBE_MAP_POSITIVE_X+face, 0, use_alpha, true, 0, GL_RGBA); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_LOD, 0); } static void UnloadObjects(void) { unloadDAT(&hand); return; } /* set lighting render state */ static void SetRenderState(void) { GLfloat ld0[] = {1.f, 1.f, 1.f, 1.f}; /* light0 diffuse */ GLfloat ls0[] = {0.35f, 0.35f, 0.35f, 1.f}; /* light0 specular */ GLfloat ls1[] = {0.28f, 0.28f, 0.28f, 1.f}; /* light0 specular2 */ glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].diffuse"), 1, ld0); glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].specular0"), 1, ls0); glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].specular1"), 1, ls1); GLfloat ms2[] = {0.28f, 0.28f, 0.28f, 1.f}; glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.specular1"), 1, ms2); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputD0" ), GL_FALSE); /* We use GL_TRUE below to make negative NV non-zero because negative NV values happen on silhouettes */ glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputD1" ), GL_TRUE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputSP" ), GL_FALSE); /* We use GL_TRUE below to make negative NV non-zero because negative NV values happen on silhouettes */ glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputFR" ), GL_TRUE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputRB" ), GL_FALSE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputRG" ), GL_FALSE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputRR" ), GL_FALSE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRB" ), GL_LIGHT_ENV_LN_DMP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRG" ), GL_LIGHT_ENV_LN_DMP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRR" ), GL_LIGHT_ENV_LN_DMP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputD1" ), GL_LIGHT_ENV_NV_DMP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputD0" ), GL_LIGHT_ENV_NH_DMP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputFR" ), GL_LIGHT_ENV_NV_DMP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].geomFactor0" ), GL_FALSE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].geomFactor1" ), GL_FALSE); /* all light setting */ glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRR" ), 2.f); glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRG" ), 2.f); glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRB" ), 2.f); glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleD0" ), 2.f); glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleD1" ), 2.f); glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleSP" ), 2.f); glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleFR" ), 2.f); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledRefl" ), GL_TRUE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.config" ), GL_LIGHT_ENV_LAYER_CONFIG7_DMP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.fresnelSelector" ), GL_LIGHT_ENV_PRI_SEC_ALPHA_FRESNEL_DMP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.clampHighlights" ), GL_FALSE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledD0" ), GL_TRUE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledD1" ), GL_TRUE); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerRR"), 0); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerRG"), 1); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerRB"), 2); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerD1"), 3); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerD0"), 4); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerFR"), 5); SetLutTable(); /* setup texture combine */ glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_Texture[0].samplerType" ), GL_TEXTURE_CUBE_MAP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineRgb"), GL_ADD); 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_FRAGMENT_SECONDARY_COLOR_DMP, GL_CONSTANT); glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcAlpha"), GL_CONSTANT, GL_CONSTANT, GL_CONSTANT); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].combineRgb"), GL_MULT_ADD_DMP); glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].combineAlpha"), GL_REPLACE); glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].operandRgb"), GL_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_COLOR); glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA); glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].srcRgb"), GL_TEXTURE0, GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_PREVIOUS); glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].srcAlpha"), GL_PREVIOUS, GL_PREVIOUS, GL_PREVIOUS); } int DrawFrame(void) { static int f = 0; nn::math::Matrix44 proj, world; nn::math::Matrix34 mv, rot; s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); /* setup projection matrix */ 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, 0.f, 2.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); /* setup light direction */ nn::math::Vector4 lpos0(-30.f, 0.4f, 18.5f, 1.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(nn::math::VEC4Dot(&mv0, &lpos0), nn::math::VEC4Dot(&mv1, &lpos0), nn::math::VEC4Dot(&mv2, &lpos0), lpos0.w); glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].position"), 1, static_cast(lpos)); /* setup modelview matrix */ nn::math::MTX34RotXYZDeg(&rot, 0.f, static_cast(-f), 0.f); nn::math::MTX34Mult(&mv, &mv, &rot); nn::math::Matrix44 m(mv); glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uModelView"), 1, GL_TRUE, static_cast(m)); /* for calculation of reflection vector */ nn::math::MTX44Identity(&world); glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uWorld"), 1, GL_FALSE, static_cast(world)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); /* draw objects */ for (int i = 0; i < hand.obj_num; i++) { glBindBuffer(GL_ARRAY_BUFFER, hand.posVB); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)hand.obj[i].vtx_offset); glBindBuffer(GL_ARRAY_BUFFER, hand.normVB); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)hand.obj[i].nrm_offset); for (unsigned j = hand.obj[i].patch_offset; j < hand.obj[i].patch_size + hand.obj[i].patch_offset; j++) { GLfloat ma[4] = {0.f, 0.f, 0.f, 1.f}; GLfloat md[4] = {0.f, 0.f, 0.f, 1.f}; GLfloat ms[4] = {0.f, 0.f, 0.f, 1.f}; for (int col = 0; col < 3; col++) { ma[col] = hand.patch[j].ambient[col]; md[col] = hand.patch[j].diffuse[col]; ms[col] = hand.patch[j].specular[col]; } glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.diffuse"), 1, md); glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.specular0"), 1, ms); glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.ambient"), 1, ma); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, hand.idxVB); glDrawElements(GL_TRIANGLES, hand.patch[j].elm_size, GL_UNSIGNED_SHORT, (GLvoid*)(hand.patch[j].elm_offset + hand.obj[i].elm_offset)); } } 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); /* create and bind texture collection object to capture subsequent modifications in the texture state both lookup table-related one and ordinary (2d, cube) textures */ glGenTextures(1, &s_TexColl); glBindTexture(GL_TEXTURE_COLLECTION_DMP, s_TexColl); LoadObjects(); /* 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); 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(); } } UnloadObjects(); /* shutdown_display */ s_RenderSystem.Finalize(); s_AppHeap.Free(reinterpret_cast(s_HeapForMalloc)); s_AppHeap.Free(reinterpret_cast(s_HeapForGx)); s_AppHeap.Finalize(); }