1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     LightingAniso.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 /*
27  * Comments
28  * --------
29  *
30  * Light reflection in this sample consists of two parts - diffuse one
31  * (simulating reflection from inside of cloth) modulated by texture and
32  * anisotropic one (simulating reflection of the air-fiber interface).
33  *
34  * To render anisotropic appearance, we use Schlick's model described in
35  * the following paper
36  *
37  * Christophe Schlick, An Inexpensive BRDF Model for Physically-Based
38  * Rendering, Comput. Graph. Forum 13(3), 233-246 (1994).
39  *
40  * (c) DMP, Inc.
41  * konstantin.kolchin@dmprof.com
42  */
43 
44 #include <nn/os.h>
45 #include <nn/gx.h>
46 #include <nn/fs.h>
47 #include <nn/math.h>
48 #include <nn/init.h>
49 #include <nn/os.h>
50 #include <nn/applet.h>
51 
52 #include "demo.h"
53 
54 #include "Util.h"
55 #include "Loader.h"
56 
57 #include <string.h>
58 
59 #include "Memory.h"
60 
61 /* program id */
62 GLuint s_ProgramID;
63 
64 /* shader id */
65 GLuint s_ShaderID;
66 
67 /* diffuse texture ID */
68 GLuint s_DiffTexName;
69 
70 /* bump texture ID */
71 GLuint s_BumpTexName;
72 
73 /* obj file loader class object */
74 dat_t kimono;
75 
76 /* texture collection name */
77 GLuint s_TexColl ;
78 
79 /* ExpHeap for app. */
80 nn::fnd::ExpHeap s_AppHeap;
81 uptr s_HeapForGx;
82 uptr s_HeapForMalloc;
83 const u32 s_GxHeapSize = 0x400000;
84 const u32 s_HeapSize = 0x200000;
85 
86 demo::RenderSystem s_RenderSystem;
87 
SetLutTable()88 static void SetLutTable()
89 {
90     /* Schlick suggested that distribution function of anisotropic reflection
91     is composed of two functions, one dependent on dot product NH, and other dependent on
92     dot product of the angle between the projection of H on the tangent plane and the
93     tangent vector. in microfacets theory, distribution function is not
94     depended on wave length(R,G,B) essentially. but, this sample distribution term
95     looked up by NH is depended on wave length. therefore, specular has a little blue. */
96 
97     GLuint lutids[5] ;
98 
99     glGenTextures(5, lutids);
100 
101     GLfloat lut[512];
102     int j;
103     memset(lut, 0, sizeof(lut));
104 
105     /* to ignore 1st specular term, set 0. */
106     glBindTexture(GL_LUT_TEXTURE0_DMP, lutids[0]);
107     glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
108 
109     /* set term depended on NH */
110     for (j = 0; j < 256; j++)
111         lut[j] = 0.7f * z_schlick(0.7f, (float)j/256.f, true);
112 
113     for (j = 0; j < 255; j++)
114         lut[j + 256] = lut[j+1] - lut[j];
115 
116     lut[255 + 256] = 0.7f * z_schlick(0.7f, 1.f, true) - lut[255];
117     glBindTexture(GL_LUT_TEXTURE1_DMP, lutids[1]);
118     glTexImage1D(GL_LUT_TEXTURE1_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
119 
120     for (j = 0; j < 256; j++)
121         lut[j] = 0.7f * z_schlick(0.7f, (float)j/256.f, true);
122 
123     for (j = 0; j < 255; j++)
124         lut[j + 256] = lut[j+1] - lut[j];
125 
126     lut[255 + 256] = 0.7f * z_schlick(0.7f, 1.f, true) - lut[255];
127     glBindTexture(GL_LUT_TEXTURE2_DMP, lutids[2]);
128     glTexImage1D(GL_LUT_TEXTURE2_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
129 
130     for (j = 0; j < 256; j++)
131         lut[j] = z_schlick(0.5f, (float)j/256.f, true);
132 
133     for (j = 0; j < 255; j++)
134         lut[j + 256] = lut[j+1] - lut[j];
135 
136     lut[255 + 256] = z_schlick(0.5f, 1.f, true) - lut[255];
137     glBindTexture(GL_LUT_TEXTURE3_DMP, lutids[3]);
138     glTexImage1D(GL_LUT_TEXTURE3_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
139 
140     /* set term dependent on dot product between the projection of H on the tangent plane
141     and the tangent vector */
142     for (j = 0; j < 256; j++)
143         lut[j] = a_schlick(0.015f, (float)j/256.f, true);
144 
145     for (j = 0; j < 255; j++)
146         lut[j + 256] = lut[j + 1] - lut[j];
147 
148     lut[255 + 256] = a_schlick(0.015f, 1.f, true) - lut[255];
149     glBindTexture(GL_LUT_TEXTURE4_DMP, lutids[4]);
150     glTexImage1D(GL_LUT_TEXTURE4_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
151 }
152 
153 /* set lighting render state */
SetRenderState(void)154 static void SetRenderState(void)
155 {
156     GLfloat ld0[] = {0.5f,0.5f,0.5f,1.f} ;
157     GLfloat ls0[] = {0.7f,0.7f,0.7f,1.f} ;
158     GLfloat ld1[] = {0.5f,0.5f,0.5f,1.f} ;
159     GLfloat ls1[] = {0.7f,0.7f,0.7f,1.f} ;
160 
161     /* all light setting */
162     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLighting.enabled"), GL_TRUE);
163     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].enabled"), GL_TRUE);
164     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].enabled"), GL_TRUE);
165     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputD0"), GL_TRUE);
166     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputD1"), GL_TRUE);
167     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputSP"), GL_TRUE);
168     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputFR"), GL_TRUE);
169     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputRB"), GL_TRUE);
170     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputRG"), GL_TRUE);
171     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputRR"), GL_TRUE);
172 
173     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputD1"), GL_LIGHT_ENV_CP_DMP);
174     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRB"), GL_LIGHT_ENV_NH_DMP);
175     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRG"), GL_LIGHT_ENV_NH_DMP);
176     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRR"), GL_LIGHT_ENV_NH_DMP);
177 
178     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleD0"), 1.f);
179     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleD1"), 1.f);
180     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleSP"), 1.f);
181     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleFR"), 1.f);
182     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRB"), 1.f);
183     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRG"), 1.f);
184     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRR"), 1.f);
185 
186     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledRefl"), GL_TRUE);
187 
188     /* when anisotropic lighting, distribution function is looked up by
189     dot product between projection of half-vector onto tangent plane and
190     tangent vector. HW specification require layer configuration setting7
191     in this case. another layer configuration setting can not be used. */
192     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.config"), GL_LIGHT_ENV_LAYER_CONFIG7_DMP);
193 
194     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.bumpMode"), GL_LIGHT_ENV_BUMP_AS_BUMP_DMP);
195     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.bumpSelector"), GL_TEXTURE1);
196 
197     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledD0"), GL_TRUE);
198     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledD1"), GL_TRUE);
199 
200     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.clampHighlights"), GL_FALSE);
201 
202     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].geomFactor0"), GL_FALSE);
203     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].geomFactor1"), GL_FALSE);
204 
205     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].twoSideDiffuse"), GL_TRUE);
206 
207     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].geomFactor0"), GL_FALSE);
208     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].geomFactor1"), GL_FALSE);
209 
210     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].twoSideDiffuse"), GL_TRUE);
211 
212     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerD0"), 0);
213     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerRR"), 1);
214     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerRG"), 2);
215     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerRB"), 3);
216     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerD1"), 4);
217 
218     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].diffuse"), 1, ld0);
219     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].specular0"), 1, ls0);
220     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].specular1"), 1, ls0);
221 
222     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].diffuse"), 1, ld1);
223     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].specular0"), 1, ls1);
224     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].specular1"), 1, ls1);
225 
226     /* light position settings */
227 
228     nn::math::Matrix34 mv;
229     nn::math::Vector3 camPos(0.f, 0.f, 1.5f);
230     nn::math::Vector3 camUp(0.f, 1.f, 0.f);
231     nn::math::Vector3 target(0.f, 0.f, 0.f);
232 
233     nn::math::MTX34LookAt(&mv, &camPos, &camUp, &target);
234 
235     nn::math::Vector4 lpos0(-1.f, 0.5f, 1.f, 1.f);
236     nn::math::Vector4 lpos1(1.f, 0.5f,1.f,1.f);
237 
238     nn::math::Vector4 mv0(mv.m[0][0], mv.m[0][1], mv.m[0][2], mv.m[0][3]);
239     nn::math::Vector4 mv1(mv.m[1][0], mv.m[1][1], mv.m[1][2], mv.m[1][3]);
240     nn::math::Vector4 mv2(mv.m[2][0], mv.m[2][1], mv.m[2][2], mv.m[2][3]);
241     nn::math::Vector4 lpos(nn::math::VEC4Dot(&mv0, &lpos0), nn::math::VEC4Dot(&mv1, &lpos0), nn::math::VEC4Dot(&mv2, &lpos0), lpos0.w);
242 
243     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].position"), 1, static_cast<f32*>(lpos));
244 
245     lpos = nn::math::Vector4(nn::math::VEC4Dot(&mv0, &lpos1), nn::math::VEC4Dot(&mv1, &lpos1), nn::math::VEC4Dot(&mv2, &lpos1), lpos1.w);
246     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].position"), 1, static_cast<f32*>(lpos));
247 
248     /* set projection matrix */
249     nn::math::Matrix44 proj;
250     nn::math::MTX44Frustum(&proj, -0.01f, 0.01f, -0.01f * nn::gx::DISPLAY0_HEIGHT / nn::gx::DISPLAY0_WIDTH,
251                  0.01f * nn::gx::DISPLAY0_HEIGHT / nn::gx::DISPLAY0_WIDTH, 0.2f, 10.f);
252     glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uProjection"), 1, GL_TRUE, static_cast<f32*>(proj));
253 
254     /* texture and texture environment settings */
255     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_Texture[0].samplerType"), GL_TEXTURE_2D);
256     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_Texture[1].samplerType"), GL_TEXTURE_2D);
257 
258     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineRgb"), GL_MULT_ADD_DMP);
259     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineAlpha"), GL_REPLACE);
260     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
261     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
262     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcRgb"), GL_TEXTURE0, GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_FRAGMENT_SECONDARY_COLOR_DMP);
263     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcAlpha"), GL_CONSTANT, GL_CONSTANT, GL_CONSTANT);
264 
265     /* lookup table settings */
266     SetLutTable();
267 }
268 
269 /* load objects */
LoadObjects(void)270 static void LoadObjects(void)
271 {
272     bool use_alpha;
273 
274     /* load obj file geometry and diffuse texture */
275     loadDAT( "rom:/resources/kimono.dat", &kimono);
276 
277     /* load texture */
278     glGenTextures(1, &s_DiffTexName);
279     glActiveTexture(GL_TEXTURE0);
280     /* stored in the texture collection */
281     glBindTexture(GL_TEXTURE_2D, s_DiffTexName);
282     /* limit texture sampling to the top level only */
283     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
284     loadTexture( "rom:/resources/KIMONO01.tga", GL_TEXTURE_2D, 0, use_alpha, true);
285 
286     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
287     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
288 
289     /* load bump texture */
290     glGenTextures(1, &s_BumpTexName);
291     glActiveTexture(GL_TEXTURE1) ;
292     /* stored in the texture collection */
293     glBindTexture(GL_TEXTURE_2D, s_BumpTexName);
294     /* limit texture sampling to the top level only */
295     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
296     loadTexture( "rom:/resources/KIMONOB0.tga", GL_TEXTURE_2D, 0, use_alpha, true);
297 
298     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
299     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
300 
301     /* restore active texture to unit 0 to enable loading of object's diffuse texture */
302     glActiveTexture(GL_TEXTURE0);
303 }
304 
UnloadObjects(void)305 static void UnloadObjects(void)
306 {
307     unloadDAT(&kimono);
308 
309     return;
310 }
311 
DrawFrame(void)312 int DrawFrame(void)
313 {
314     static int f = 0;
315 
316     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
317     s_RenderSystem.Clear();
318 
319     nn::math::Matrix34 mv, rot;
320     nn::math::Vector3 camPos(0.f, 0.f, 1.5f);
321     nn::math::Vector3 camUp(0.f, 1.f, 0.f);
322     nn::math::Vector3 target(0.f, 0.f, 0.f);
323 
324     nn::math::MTX34LookAt(&mv, &camPos, &camUp, &target);
325 
326     nn::math::MTX34RotXYZDeg(&rot, 0.f, static_cast<f32>(-f), 0.f);
327     nn::math::MTX34Mult(&mv, &mv, &rot);
328 
329     nn::math::Matrix44 tmp(mv);
330     glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uModelView"), 1, GL_TRUE, static_cast<f32*>(tmp));
331 
332     for (int i = 0; i < kimono.obj_num; i++)
333     {
334         glBindBuffer(GL_ARRAY_BUFFER, kimono.posVB);
335         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)kimono.obj[i].vtx_offset);
336         glBindBuffer(GL_ARRAY_BUFFER, kimono.normVB);
337         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)kimono.obj[i].nrm_offset);
338         if (kimono.obj[i].tex_size)
339         {
340             glBindBuffer(GL_ARRAY_BUFFER, kimono.tangVB);
341             glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)kimono.obj[i].tgt_offset);
342             glBindBuffer(GL_ARRAY_BUFFER, kimono.texVB);
343             glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (void*)kimono.obj[i].tex_offset);
344             glEnableVertexAttribArray(2);
345             glEnableVertexAttribArray(3) ;
346             glUniform1i(glGetUniformLocation(s_ProgramID, "uTangentEnabled"), GL_TRUE);
347         }
348         else
349         {
350             glDisableVertexAttribArray(2);
351             glDisableVertexAttribArray(3);
352             glUniform1i(glGetUniformLocation(s_ProgramID, "uTangentEnabled"), GL_FALSE);
353         }
354 
355         for (unsigned j = kimono.obj[i].patch_offset; j < kimono.obj[i].patch_size + kimono.obj[i].patch_offset; j++)
356         {
357             GLfloat ma[4] = {0.f, 0.f, 0.f, 1.f};
358             GLfloat md[4] = {0.f, 0.f, 0.f, 1.f};
359             GLfloat ms[4] = {0.f, 0.f, 0.f, 1.f};
360             for (int col = 0; col < 3; col++)
361             {
362                 ma[col] = kimono.patch[j].ambient[col];
363                 md[col] = kimono.patch[j].diffuse[col];
364                 ms[col] = kimono.patch[j].specular[col];
365             }
366             glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.diffuse"), 1, md);
367             glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.specular0"), 1, ms);
368             glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.ambient"), 1, ma);
369 
370             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, kimono.idxVB);
371             glDrawElements(GL_TRIANGLES, kimono.patch[j].elm_size,
372                 GL_UNSIGNED_SHORT, (GLvoid*)(kimono.patch[j].elm_offset + kimono.obj[i].elm_offset));
373         }
374     }
375 
376     glFinish();
377 
378     s_RenderSystem.SwapBuffers();
379 
380     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
381     s_RenderSystem.Clear();
382     s_RenderSystem.SwapBuffers();
383 
384     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
385 
386     f++;
387 
388     return !glGetError();
389 }
390 
391 /* initialization */
Initialize(void)392 static int Initialize(void)
393 {
394     // fs initialization
395     nn::fs::Initialize();
396 
397     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
398     static char buffer[ROMFS_BUFFER_SIZE];
399     NN_UTIL_PANIC_IF_FAILED(
400         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
401 
402     s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() );
403     s_HeapForGx = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
404     /* Initialize display */
405     s_RenderSystem.Initialize(s_HeapForGx, s_GxHeapSize);
406 
407     /* Create heap for malloc*/
408     s_HeapForMalloc = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_HeapSize));
409     setMemoryHeap(s_HeapForMalloc, s_HeapSize);
410 
411     glClearColor(0.36f, 0.42f, 0.5f, 1.0f);
412     glClearDepthf(1.f);
413 
414     glEnable(GL_DEPTH_TEST);
415     glDepthFunc(GL_LESS);
416 
417     glEnable(GL_CULL_FACE);
418     glFrontFace(GL_CCW);
419     glCullFace(GL_BACK);
420 
421     /* create program and load & attach vertex shader */
422     s_ProgramID = glCreateProgram();
423     s_ShaderID = glCreateShader(GL_VERTEX_SHADER);
424 
425     nn::fs::FileReader file(L"rom:/shader.shbin");
426     size_t fileSize = file.GetSize();
427     void* buf = s_AppHeap.Allocate(fileSize);
428 
429     s32 read = file.Read(buf, fileSize);
430     glShaderBinary(1, &s_ShaderID, GL_PLATFORM_BINARY_DMP, buf, read);
431     file.Finalize();
432     s_AppHeap.Free(buf);
433 
434     glAttachShader(s_ProgramID, s_ShaderID);
435 
436     /* attach fixed-function fragment shader */
437     glAttachShader(s_ProgramID, GL_DMP_FRAGMENT_SHADER_DMP);
438 
439     glBindAttribLocation(s_ProgramID, 0, "aPosition");
440     glBindAttribLocation(s_ProgramID, 1, "aNormal");
441     glBindAttribLocation(s_ProgramID, 2, "aTang");
442     glBindAttribLocation(s_ProgramID, 3, "aTexCoord");
443 
444     glLinkProgram(s_ProgramID);
445     glValidateProgram(s_ProgramID);
446     /* set program as current one to enable setting its uniforms */
447     glUseProgram(s_ProgramID);
448 
449     /* create and bind texture collection object to capture subsequent modifications in the texture state
450      both lookup table-related one and ordinary (2D, cube) textures */
451     glGenTextures(1, &s_TexColl);
452     glBindTexture(GL_TEXTURE_COLLECTION_DMP, s_TexColl);
453 
454     LoadObjects();
455 
456     /* enable arrays that will be mapped to position and normal */
457     glEnableVertexAttribArray(0);
458     glEnableVertexAttribArray(1);
459 
460     return 0;
461 }
462 
nnMain(void)463 void nnMain(void)
464 {
465     // Call only nn::applet::Enable to also allow execution from the HOME Menu
466     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
467     nn::applet::Enable();
468 
469     /* initialization */
470     if (Initialize() >= 0)
471     {
472         /* set another render state */
473         SetRenderState();
474 
475         /* Enter loop */
476         while (1)
477         {
478             (void)DrawFrame();
479         }
480     }
481 
482     UnloadObjects();
483     /* shutdown_display */
484     s_RenderSystem.Finalize();
485     s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForMalloc));
486     s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForGx));
487     s_AppHeap.Finalize();
488 }
489 
490