1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     LightingSss.cpp
4 
5   Copyright (C)2009-2012 Nintendo Co., Ltd.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Rev: 47228 $
14  *---------------------------------------------------------------------------*/
15 
16 /*
17  *------------------------------------------------------------
18  * Copyright(c) 2009-2010 by Digital Media Professionals Inc.
19  * All rights reserved.
20  *------------------------------------------------------------
21  * This source code is the confidential and proprietary
22  * of Digital Media Professionals Inc.
23  *------------------------------------------------------------
24  */
25 /*
26  * Comments
27  * --------
28  *
29  * This example is the rendering translucent materials in Maestro. See Subsurface-Scattering Model
30  * section of "ILLUMINATION MODELS IN MAESTRO" for details.
31  * The following papers can help you understand the LUT settings.
32  *  Jensen,H., Marschner,S., Levoy,H., and Hanrahan,P., A Practical Model for Subsurface Light Transport
33  *  Jensen,H. and Buhler,J., A Rapid Hierarchical Rendering Technique for Translucent Materials
34  *  Kolchin,K., Curvature-Based Shading of Translucent Materials ,such as Human Skin
35  */
36 
37 #include <nn/gx.h>
38 #include <nn/fs.h>
39 #include <nn/math.h>
40 #include <nn/init.h>
41 #include <nn/os.h>
42 #include <nn/applet.h>
43 
44 #include "demo.h"
45 
46 #include "Util.h"
47 #include "Loader.h"
48 
49 #include <string.h>
50 #include <math.h>
51 
52 #include "Memory.h"
53 
54 #define APP_NAME "LightingSSS"
55 
56 #define DMP_PI  (3.1415926f)
57 #define REV_PI  (1.0f/DMP_PI)
58 
59 /* env texture name */
60 GLuint s_EnvTexName;
61 
62 /* obj file loader class object */
63 dat_t hand;
64 
65 /* program name */
66 GLuint s_ProgramID;
67 
68 /* shader name */
69 GLuint s_ShaderID;
70 
71 /* texture collection name */
72 GLuint s_TexColl;
73 
74 /* ExpHeap for app. */
75 nn::fnd::ExpHeap s_AppHeap;
76 uptr s_HeapForGx;
77 uptr s_HeapForMalloc;
78 const u32 s_GxHeapSize = 0x400000;
79 const u32 s_HeapSize = 0x200000;
80 
81 demo::RenderSystem s_RenderSystem;
82 
SetLutTable(void)83 static void SetLutTable(void)
84 {
85     struct
86     {
87         float albedo[3];
88         float dif_refl[4];
89         float beta[3];
90         float beta_prime[3];
91         float zr[3];
92         float Bi;
93         float F_dr;
94         float refi;
95         float m;
96         float i0[3];
97         float i1[3];
98     } mat;
99 
100     GLfloat qlut[3][512], lut[512];
101     int j, co;
102 
103     GLuint lutids[6];
104     glGenTextures(6, lutids);
105 
106     for (co = 0; co < 3; co++)
107         memset(qlut[co], 0, sizeof(qlut[0]));
108     memset(lut, 0, sizeof(lut));
109 
110     GLfloat A, refi, sigma_s_prim[3], sigma_a[3], sigma_t_prim[3], geom_scale = 0.24f;
111     refi = 1.4f;
112     #if 0  /* face */
113     sigma_s_prim[0] = 1.09f;
114     sigma_s_prim[1] = 1.59f;
115     sigma_s_prim[2] = 1.79f;
116     sigma_a[0] = 0.013f;
117     sigma_a[1] = 0.070f; /* 0.085; */   /* <-- use these values for more sun-tanned skin */
118     sigma_a[2] = 0.145f; /* 0.180; */
119     #else   /* hand */
120     sigma_s_prim[0] = 1.09f;
121     sigma_s_prim[1] = 1.39f;
122     sigma_s_prim[2] = 1.3f;
123     sigma_a[0] = 0.013f;
124     sigma_a[1] = 0.120f;
125     sigma_a[2] = 0.295f;
126     #endif
127 
128     mat.F_dr = - 1.440f / (refi * refi) + 0.71f / refi + 0.668f + 0.0636f * refi;
129     A = (1.0f + mat.F_dr) / (1.0f - mat.F_dr);
130     mat.Bi = 1.0f + (4.0f / 3.0f) * A;
131     mat.refi = refi;
132     for (co = 0; co < 3; co++)
133     {
134         sigma_t_prim[co] = sigma_s_prim[co] + sigma_a[co];
135         mat.zr[co] = geom_scale / sigma_t_prim[co];
136         mat.albedo[co] = sigma_s_prim[co] / sigma_t_prim[co];
137         mat.beta[co] = sqrt(3.0f * (1.0f - mat.albedo[co]));
138         mat.beta_prime[co] = mat.beta[co] * mat.Bi;
139         mat.dif_refl[co] = 0.5f * mat.albedo[co] * (exp(-mat.beta[co]) + exp(-mat.beta_prime[co]));
140         mat.i0[co] = exp(-mat.beta[co]) * sqrt(2.0f * DMP_PI / mat.beta[co]) +
141           mat.Bi * exp(-mat.beta_prime[co]) * sqrt(2.0f * DMP_PI / mat.beta_prime[co]);
142         mat.i1[co] = DMP_PI * (exp(-mat.beta[co]) + exp(-mat.beta_prime[co])) / mat.i0[co];
143     }
144 
145     float gamma, LN, h, kappa, display_gamma = 0.47f;
146     for (j = 0; j < 128; j++)
147     {
148         LN = (float)j/128.f;
149         kappa = 1.0f - LN * LN;
150         for (co = 0; co < 3; co++)
151         {
152             /* R(LN) is sum of lambertian term(linear term)and wrapping term(non-linear term). */
153             if (LN > 0.f)
154                 qlut[co][j] = mat.dif_refl[co] * LN;
155             gamma = mat.zr[co] * sqrt(kappa);
156             h = fabsf(LN) / gamma;
157             qlut[co][j] += mat.i0[co] * (1.0f / (1.0f + mat.i1[co] * h)) * gamma * mat.albedo[co] * 0.25f * REV_PI;
158             qlut[co][j] = pow(qlut[co][j], display_gamma);
159         }
160     }
161 
162     for (j = 128; j < 256; j++)
163     {
164         LN = (float)(j - 256) /128.f;
165         kappa = 1.0f - LN * LN;
166         for (co = 0; co < 3; co++)
167         {
168             if (LN > 0.f)
169                 qlut[co][j] = mat.dif_refl[co] * LN;
170             gamma = mat.zr[co] * sqrt(kappa);
171             h = fabsf(LN) / gamma;
172             qlut[co][j] += mat.i0[co] * (1.0f / (1.0f + mat.i1[co] * h)) *
173                 gamma * mat.albedo[co] * 0.25f * REV_PI;
174             qlut[co][j] = pow(qlut[co][j], display_gamma);
175         }
176     }
177 
178     for (j = 0; j < 127; j++)
179         for (co = 0; co < 3; co++)
180             qlut[co][j + 256] = qlut[co][j + 1] - qlut[co][j];
181 
182     for (co = 0; co < 3; co++)
183         qlut[co][127 + 256] = pow(mat.dif_refl[co], display_gamma) - qlut[co][127];
184 
185     for (j = 128; j < 255; j++)
186         for (co = 0; co < 3; co++)
187             qlut[co][j + 256] = qlut[co][j + 1] - qlut[co][j];
188 
189     for (co = 0; co < 3; co++)
190         qlut[co][255 + 256] = qlut[co][0] - qlut[co][255];
191 
192     glBindTexture(GL_LUT_TEXTURE0_DMP, lutids[0]);
193     glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, qlut[0]);
194     glBindTexture(GL_LUT_TEXTURE1_DMP, lutids[1]);
195     glTexImage1D(GL_LUT_TEXTURE1_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, qlut[1]);
196     glBindTexture(GL_LUT_TEXTURE2_DMP, lutids[2]);
197     glTexImage1D(GL_LUT_TEXTURE2_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, qlut[2]);
198 
199     /* T(NV) term setting */
200     for (j = 0; j < 256; j++)
201     {
202         lut[j] = 1.f - r_fresnel((float)j / 255.9375f, 1.7f, 0.36f, 0.f);
203         lut[j] = pow(lut[j], display_gamma);
204     }
205     for (j = 0; j < 255; j++)
206         lut[j + 256] = lut[j + 1] - lut[j];
207     lut[255 + 256] = pow((1.f - r_fresnel(1.f, 1.7f, 0.36f, 0.f)), display_gamma) - lut[255];
208 
209     glBindTexture(GL_LUT_TEXTURE3_DMP, lutids[3]);
210     glTexImage1D(GL_LUT_TEXTURE3_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
211 
212     /* distribution function of specular setting */
213     /* beckmann function is used. */
214     memset(lut, 0, sizeof(lut));
215     for (j = 0; j < 128; j++)
216         lut[j] = beckmann((float)j / 128.f, 0.5f);
217     for (j = 128; j < 256; j++)
218         lut[j] = 0.f;
219 
220     for (j = 0; j < 127; j++)
221         lut[j + 256] = lut[j + 1] - lut[j];
222     lut[127 + 256] = 1.f - lut[127];
223     for (j = 128; j < 256; j++)
224         lut[j + 256] = 0;
225 
226     glBindTexture(GL_LUT_TEXTURE4_DMP, lutids[4]);
227     glTexImage1D(GL_LUT_TEXTURE4_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
228 
229     /* fresnel function is used for environment illumination. is is looked up by
230     dot product NV. */
231     memset(lut, 0, sizeof(lut));
232     for (j = 0; j < 256; j++)
233         /*lut[j] = 0.6f * r_fresnel((float)j / 255.9375f, 2.f, 0.35f, 0.f);*/
234         lut[j] = r_fresnel((float)j / 255.9375f, 2.f, 0.35f, 0.f);
235 
236     for (j = 0; j < 255; j++)
237         lut[j + 256] = lut[j + 1] - lut[j];
238 
239     /*lut[255 + 256] = 0.6f * r_fresnel(1.f, 2.f, 0.35f, 0.f) - lut[255];*/
240     lut[255 + 256] = r_fresnel(1.f, 2.f, 0.35f, 0.f) - lut[255];
241 
242     glBindTexture(GL_LUT_TEXTURE5_DMP, lutids[5]);
243     glTexImage1D(GL_LUT_TEXTURE5_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
244 }
245 
246 /* load objects */
LoadObjects(void)247 static void LoadObjects(void)
248 {
249     /* load obj file geometory and diffuse texture */
250     loadDAT( "rom:/resources/hand.dat", &hand);
251 
252     /* load env texture */
253     char *env_tex[] =
254     {
255          "rom:/resources/bright1.tga",
256          "rom:/resources/bright1.tga",
257          "rom:/resources/bright1.tga",
258          "rom:/resources/bright1.tga",
259          "rom:/resources/bright1.tga",
260          "rom:/resources/bright1.tga",
261     };
262     glGenTextures(1, &s_EnvTexName);
263     glActiveTexture(GL_TEXTURE0);
264     glBindTexture(GL_TEXTURE_CUBE_MAP, s_EnvTexName);
265     for (int face = 0; face < 6; face++)
266     {
267         bool use_alpha;
268         loadTexture(env_tex[face], GL_TEXTURE_CUBE_MAP_POSITIVE_X+face, 0, use_alpha, true, 0, GL_RGBA);
269     }
270     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
271     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
272     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
273     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
274     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_LOD, 0);
275 }
276 
UnloadObjects(void)277 static void UnloadObjects(void)
278 {
279     unloadDAT(&hand);
280 
281     return;
282 }
283 
284 /* set lighting render state */
SetRenderState(void)285 static void SetRenderState(void)
286 {
287     GLfloat ld0[] = {1.f, 1.f, 1.f, 1.f};           /* light0 diffuse */
288     GLfloat ls0[] = {0.35f, 0.35f, 0.35f, 1.f};     /* light0 specular */
289     GLfloat ls1[] = {0.28f, 0.28f, 0.28f, 1.f};     /* light0 specular2 */
290 
291     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].diffuse"), 1, ld0);
292     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].specular0"), 1, ls0);
293     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].specular1"), 1, ls1);
294 
295     GLfloat ms2[] = {0.28f, 0.28f, 0.28f, 1.f};
296     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.specular1"), 1, ms2);
297 
298     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputD0" ), GL_FALSE);
299     /* We use GL_TRUE below to make negative NV non-zero because negative NV values happen on silhouettes */
300     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputD1" ), GL_TRUE);
301     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputSP" ), GL_FALSE);
302     /* We use GL_TRUE below to make negative NV non-zero because negative NV values happen on silhouettes */
303     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputFR" ), GL_TRUE);
304     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputRB" ), GL_FALSE);
305     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputRG" ), GL_FALSE);
306     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputRR" ), GL_FALSE);
307 
308     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRB" ), GL_LIGHT_ENV_LN_DMP);
309     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRG" ), GL_LIGHT_ENV_LN_DMP);
310     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRR" ), GL_LIGHT_ENV_LN_DMP);
311     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputD1" ), GL_LIGHT_ENV_NV_DMP);
312     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputD0" ), GL_LIGHT_ENV_NH_DMP);
313     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputFR" ), GL_LIGHT_ENV_NV_DMP);
314 
315     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].geomFactor0" ), GL_FALSE);
316     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].geomFactor1" ), GL_FALSE);
317 
318     /* all light setting */
319     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRR" ), 2.f);
320     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRG" ), 2.f);
321     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRB" ), 2.f);
322     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleD0" ), 2.f);
323     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleD1" ), 2.f);
324     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleSP" ), 2.f);
325     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleFR" ), 2.f);
326 
327     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledRefl" ), GL_TRUE);
328 
329     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.config" ), GL_LIGHT_ENV_LAYER_CONFIG7_DMP);
330     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.fresnelSelector" ), GL_LIGHT_ENV_PRI_SEC_ALPHA_FRESNEL_DMP);
331     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.clampHighlights" ), GL_FALSE);
332 
333     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledD0" ), GL_TRUE);
334     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledD1" ), GL_TRUE);
335 
336     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerRR"), 0);
337     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerRG"), 1);
338     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerRB"), 2);
339     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerD1"), 3);
340     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerD0"), 4);
341     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerFR"), 5);
342 
343     SetLutTable();
344 
345     /* setup texture combine */
346     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_Texture[0].samplerType" ), GL_TEXTURE_CUBE_MAP);
347     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineRgb"), GL_ADD);
348     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineAlpha"), GL_REPLACE);
349     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
350     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
351     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcRgb"), GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_FRAGMENT_SECONDARY_COLOR_DMP, GL_CONSTANT);
352     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcAlpha"), GL_CONSTANT, GL_CONSTANT, GL_CONSTANT);
353 
354     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].combineRgb"), GL_MULT_ADD_DMP);
355     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].combineAlpha"), GL_REPLACE);
356     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].operandRgb"), GL_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_COLOR);
357     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
358     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].srcRgb"), GL_TEXTURE0, GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_PREVIOUS);
359     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].srcAlpha"), GL_PREVIOUS, GL_PREVIOUS, GL_PREVIOUS);
360 }
361 
DrawFrame(void)362 int DrawFrame(void)
363 {
364     static int f = 0;
365     nn::math::Matrix44 proj, world;
366     nn::math::Matrix34 mv, rot;
367 
368     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
369     s_RenderSystem.Clear();
370 
371     /* setup projection matrix */
372     nn::math::MTX44Frustum(&proj, -0.06f, 0.06f, -0.06f * nn::gx::DISPLAY0_HEIGHT / nn::gx::DISPLAY0_WIDTH,
373                  0.06f * nn::gx::DISPLAY0_HEIGHT / nn::gx::DISPLAY0_WIDTH, 0.2f, 200.f);
374     glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uProjection"), 1, GL_TRUE, static_cast<f32*>(proj));
375 
376     nn::math::Vector3 camPos(0.f, 0.f, 2.f);
377     nn::math::Vector3 camUp(0.f, 1.f, 0.f);
378     nn::math::Vector3 target(0.f, 0.f, 0.f);
379     nn::math::MTX34RotXYZDeg(&rot, 0.f, 0.f, -90.0f);
380     nn::math::MTX34LookAt(&mv, &camPos, &camUp, &target);
381     nn::math::MTX34Mult(&mv, &rot, &mv);
382 
383     /* setup light direction */
384     nn::math::Vector4 lpos0(-30.f, 0.4f, 18.5f, 1.f);
385     nn::math::Vector4 mv0(mv.m[0][0], mv.m[0][1], mv.m[0][2], mv.m[0][3]);
386     nn::math::Vector4 mv1(mv.m[1][0], mv.m[1][1], mv.m[1][2], mv.m[1][3]);
387     nn::math::Vector4 mv2(mv.m[2][0], mv.m[2][1], mv.m[2][2], mv.m[2][3]);
388     nn::math::Vector4 lpos(nn::math::VEC4Dot(&mv0, &lpos0), nn::math::VEC4Dot(&mv1, &lpos0), nn::math::VEC4Dot(&mv2, &lpos0), lpos0.w);
389 
390     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].position"), 1, static_cast<f32*>(lpos));
391 
392     /* setup modelview matrix */
393     nn::math::MTX34RotXYZDeg(&rot, 0.f, static_cast<f32>(-f), 0.f);
394     nn::math::MTX34Mult(&mv, &mv, &rot);
395     nn::math::Matrix44 m(mv);
396     glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uModelView"), 1, GL_TRUE, static_cast<f32*>(m));
397 
398     /* for calculation of reflection vector */
399     nn::math::MTX44Identity(&world);
400     glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uWorld"), 1, GL_FALSE, static_cast<f32*>(world));
401 
402     glEnableVertexAttribArray(0);
403     glEnableVertexAttribArray(1);
404 
405     /* draw objects */
406     for (int i = 0; i < hand.obj_num; i++)
407     {
408         glBindBuffer(GL_ARRAY_BUFFER, hand.posVB);
409         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)hand.obj[i].vtx_offset);
410         glBindBuffer(GL_ARRAY_BUFFER, hand.normVB);
411         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)hand.obj[i].nrm_offset);
412 
413         for (unsigned j = hand.obj[i].patch_offset; j < hand.obj[i].patch_size + hand.obj[i].patch_offset; j++)
414         {
415             GLfloat ma[4] = {0.f, 0.f, 0.f, 1.f};
416             GLfloat md[4] = {0.f, 0.f, 0.f, 1.f};
417             GLfloat ms[4] = {0.f, 0.f, 0.f, 1.f};
418             for (int col = 0; col < 3; col++)
419             {
420                 ma[col] = hand.patch[j].ambient[col];
421                 md[col] = hand.patch[j].diffuse[col];
422                 ms[col] = hand.patch[j].specular[col];
423             }
424             glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.diffuse"), 1, md);
425             glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.specular0"), 1, ms);
426             glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.ambient"), 1, ma);
427 
428             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, hand.idxVB);
429             glDrawElements(GL_TRIANGLES, hand.patch[j].elm_size,
430                 GL_UNSIGNED_SHORT, (GLvoid*)(hand.patch[j].elm_offset + hand.obj[i].elm_offset));
431         }
432     }
433 
434     glFinish();
435 
436     s_RenderSystem.SwapBuffers();
437 
438     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
439     s_RenderSystem.Clear();
440     s_RenderSystem.SwapBuffers();
441 
442     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
443 
444     f++;
445 
446     return !glGetError();
447 }
448 
449 /* initialization */
Initialize(void)450 static int Initialize(void)
451 {
452     s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() );
453     s_HeapForGx = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
454 
455     /* Initialize display */
456     s_RenderSystem.Initialize(s_HeapForGx, s_GxHeapSize);
457 
458     /* Create heap for malloc*/
459     s_HeapForMalloc = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_HeapSize));
460     setMemoryHeap(s_HeapForMalloc, s_HeapSize);
461 
462     s_ProgramID = glCreateProgram();
463     s_ShaderID = glCreateShader(GL_VERTEX_SHADER);
464 
465     nn::fs::FileReader file(L"rom:/shader.shbin");
466     size_t fileSize = file.GetSize();
467     void* buf = s_AppHeap.Allocate(fileSize);
468 
469     s32 read = file.Read(buf, fileSize);
470     glShaderBinary(1, &s_ShaderID, GL_PLATFORM_BINARY_DMP, buf, read);
471     file.Finalize();
472     s_AppHeap.Free(buf);
473 
474     glAttachShader(s_ProgramID, s_ShaderID);
475     glAttachShader(s_ProgramID, GL_DMP_FRAGMENT_SHADER_DMP);
476 
477     glBindAttribLocation(s_ProgramID, 0, "aPosition");
478     glBindAttribLocation(s_ProgramID, 1, "aNormal");
479 
480     glLinkProgram(s_ProgramID);
481     glValidateProgram(s_ProgramID);
482     glUseProgram(s_ProgramID);
483 
484     glClearColor(0.36f, 0.42f, 0.5f, 1.0f);
485     glClearDepthf(1.f);
486 
487     glEnable(GL_DEPTH_TEST);
488     glDepthFunc(GL_LESS);
489 
490     glEnable(GL_CULL_FACE);
491     glFrontFace(GL_CCW);
492     glCullFace(GL_BACK);
493 
494     /* create and bind texture collection object to capture subsequent modifications in the texture state
495     both lookup table-related one and ordinary (2d, cube) textures */
496     glGenTextures(1, &s_TexColl);
497     glBindTexture(GL_TEXTURE_COLLECTION_DMP, s_TexColl);
498 
499     LoadObjects();
500 
501     /* set another render state */
502     SetRenderState();
503 
504     /* enable DMP fragment lighting */
505     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLighting.enabled"), GL_TRUE);
506     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].enabled"), GL_TRUE);
507 
508     return 0;
509 }
510 
nnMain(void)511 void nnMain(void)
512 {
513     // Call only nn::applet::Enable to also allow execution from the HOME Menu
514     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
515     nn::applet::Enable();
516 
517     // fs initialization
518     nn::fs::Initialize();
519 
520     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
521     static char buffer[ROMFS_BUFFER_SIZE];
522     NN_UTIL_PANIC_IF_FAILED(
523         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
524 
525     /* initialization */
526     if (Initialize() >= 0)
527     {
528         /* Enter loop */
529         while (1)
530         {
531             (void)DrawFrame();
532         }
533     }
534 
535     UnloadObjects();
536     /* shutdown_display */
537     s_RenderSystem.Finalize();
538     s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForMalloc));
539     s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForGx));
540     s_AppHeap.Finalize();
541 }
542