1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     LightingFresnel.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 
41 
42 #include <nn/os.h>
43 #include <nn/gx.h>
44 #include <nn/fs.h>
45 #include <nn/math.h>
46 #include <nn/init.h>
47 #include <nn/os.h>
48 #include <nn/applet.h>
49 
50 #include "demo.h"
51 
52 #include "Util.h"
53 #include "Loader.h"
54 
55 #include <string.h>
56 
57 #include "Memory.h"
58 
59 /* program id */
60 GLuint s_ProgramID;
61 
62 /* shader id */
63 GLuint s_ShaderID;
64 
65 /* lut texture ID */
66 GLuint s_LutIDs[4];
67 
68 /* env texture ID */
69 GLuint s_EnvTexName;
70 
71 /* bump texture ID */
72 GLuint s_BumpTexName;
73 
74 /* obj file loader class object */
75 dat_t car;
76 
77 /* ExpHeap for app. */
78 nn::fnd::ExpHeap s_AppHeap;
79 uptr s_HeapForGx;
80 uptr s_HeapForMalloc;
81 const u32 s_GxHeapSize = 0x800000;
82 const u32 s_HeapSize = 0x400000;
83 
84 demo::RenderSystem s_RenderSystem;
85 
SetLutTable()86 static void SetLutTable()
87 {
88     /* Beckmann function is used as distribution function. see Microfacet Reflection
89     section in "ILLUMINATION MODELS IN MAESTRO LIGHTING" for details.
90     distribution function means distribution ratio of microfacet normal(local normal)
91     against surface normal(macroscopic normal). */
92     GLfloat lut[512];
93     int j;
94 
95     glGenTextures ( 4, s_LutIDs ) ;
96     glBindTexture ( GL_TEXTURE_COLLECTION_DMP, s_LutIDs[0] ) ;
97 
98     memset(lut, 0, sizeof(lut));
99     for (j = 1; j < 128; j++)
100         lut[j] = 0.85f * beckmann((float)j/128.f, 0.3f);
101 
102     for (j = 0; j < 127; j++)
103         lut[j + 256] = lut[j+1] - lut[j];
104     lut[127 + 256] = 1.f - lut[127];
105 
106     glBindTexture(GL_LUT_TEXTURE0_DMP, s_LutIDs[1]);
107     glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
108 
109     for (j = 1; j < 128; j++)
110         lut[j] = beckmann((float)j/128.f, 1.4f);
111 
112     for (j = 0; j < 127; j++)
113         lut[j + 256] = lut[j+1] - lut[j];
114     lut[127 + 256] = 1.f - lut[127];
115     glBindTexture(GL_LUT_TEXTURE1_DMP, s_LutIDs[2]);
116     glTexImage1D(GL_LUT_TEXTURE1_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
117 
118     for (j = 0; j < 256; j++)
119         lut[j] = r_fresnel((float)j/256.f);
120 
121     for (j = 0; j < 255; j++)
122         lut[j + 256] = lut[j+1] - lut[j];
123 
124     lut[255 + 256] = r_fresnel(1.f) - lut[255];
125     glBindTexture(GL_LUT_TEXTURE2_DMP, s_LutIDs[3]);
126     glTexImage1D(GL_LUT_TEXTURE2_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
127 
128     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerD0"), 0);
129     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerD1"), 1);
130     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerFR"), 2);
131 }
132 
133 /* set lighting render state */
SetRenderState(void)134 static void SetRenderState(void)
135 {
136     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLighting.enabled"), GL_TRUE);
137     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].enabled"), GL_TRUE);
138 
139     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputD0"),   GL_FALSE);
140     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputD1"),   GL_FALSE);
141     /* We use GL_TRUE below to make negative NV non-zero because negative NV values happen on silhouettes
142     we need to do this trick because we use normal map(Change to GL_FALSE if normal map is not used) */
143     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputFR"), GL_TRUE);
144 
145     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputD0"), GL_LIGHT_ENV_NH_DMP);
146     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputD1"), GL_LIGHT_ENV_NH_DMP);
147     /* fresnel function is looked up by light incidence. an angle of incidence is
148     be equivalent to angle of reflectance. so fresnel looked up by
149     dot product of light vector and view vector. */
150     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputFR"), GL_LIGHT_ENV_NV_DMP);
151 
152     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].geomFactor0"), GL_FALSE);
153     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].geomFactor1"), GL_FALSE);
154     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].twoSideDiffuse"), GL_FALSE);
155     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledRefl"), GL_FALSE);
156     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.clampHighlights"), GL_FALSE);
157 
158     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleD0"), 1.f);
159     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleD1"), 1.f);
160     /* below we make bit shift after sampling table of Fresnel reflection
161     we have to do this because we do not have HDR(and sky has high intensity) */
162     glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleFR"), 2.f);
163     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.fresnelSelector"), GL_LIGHT_ENV_PRI_SEC_ALPHA_FRESNEL_DMP);
164 
165     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.config"), GL_LIGHT_ENV_LAYER_CONFIG3_DMP);
166 
167     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledD0"), GL_TRUE);
168     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledD1"), GL_TRUE);
169 
170     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.bumpMode"), GL_LIGHT_ENV_BUMP_AS_BUMP_DMP);
171     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.bumpSelector"), GL_TEXTURE1);
172     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.bumpRenorm"), GL_TRUE);
173 
174     SetLutTable();
175 
176     GLfloat ms2[] = {0.7f, 0.01f, 0.25f, 1.f};
177     GLfloat ld0[] = {1.f, 1.f, 1.f, 1.f};
178     GLfloat ls0[] = {1.f, 1.f, 1.f, 1.f};
179 
180     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.specular1"), 1, ms2);
181     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].diffuse"), 1, ld0);
182     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].specular0"), 1, ls0);
183     glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].specular1"), 1, ls0);
184 
185     {
186         /* Loading bump texture */
187         char filename[]=  "rom:/resources/car_tsp0.tga";
188         int _lev = 0;
189         glGenTextures(1, &s_BumpTexName);
190         glActiveTexture(GL_TEXTURE1);
191         glBindTexture(GL_TEXTURE_2D, s_BumpTexName);
192         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
193         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
194         bool bUseAlpha;
195         loadTexture(filename, GL_TEXTURE_2D, _lev, bUseAlpha);
196     }
197 
198     {
199         /* loading environment */
200         char *env_tex[] =
201         {
202              "rom:/resources/tpx0002.tga",
203              "rom:/resources/tnx0002.tga",
204              "rom:/resources/tpy0002.tga",
205              "rom:/resources/tny0002.tga",
206              "rom:/resources/tpz0002.tga",
207              "rom:/resources/tnz0002.tga"
208         };
209 
210         glGenTextures(1, &s_EnvTexName);
211         glActiveTexture(GL_TEXTURE0);
212         glBindTexture(GL_TEXTURE_CUBE_MAP, s_EnvTexName);
213         for (int face = 0; face < 6; face++)
214         {
215             bool use_alpha;
216             loadTexture(env_tex[face], GL_TEXTURE_CUBE_MAP_POSITIVE_X+face,0, use_alpha, true, 0, GL_RGBA);
217         }
218         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
219         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
220         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
221         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_LOD, 0);
222     }
223 
224     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_Texture[0].samplerType"), GL_TEXTURE_CUBE_MAP);
225     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineRgb"), GL_ADD);
226     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineAlpha"), GL_REPLACE);
227     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
228     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
229     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcRgb"), GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_FRAGMENT_SECONDARY_COLOR_DMP, GL_CONSTANT);
230 
231     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_Texture[1].samplerType"), GL_TEXTURE_2D);
232     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].combineRgb"), GL_INTERPOLATE);
233     glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].combineAlpha"), GL_REPLACE);
234     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_ALPHA);
235     glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[1].srcRgb"), GL_TEXTURE0, GL_PREVIOUS, GL_FRAGMENT_SECONDARY_COLOR_DMP);
236 }
237 
238 /* load objects */
LoadObjects(void)239 static void LoadObjects(void)
240 {
241     loadDAT( "rom:/resources/supercar.dat", &car);
242 
243     return;
244 }
245 
UnloadObjects(void)246 static void UnloadObjects(void)
247 {
248     unloadDAT(&car);
249 
250     return;
251 }
252 
DrawFrame(void)253 int DrawFrame(void)
254 {
255     static int f = 0;
256 
257     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
258     s_RenderSystem.Clear();
259 
260     nn::math::Matrix44 proj;
261     nn::math::MTX44Frustum(&proj, -0.025f, 0.025f, -0.025f * nn::gx::DISPLAY0_HEIGHT / nn::gx::DISPLAY0_WIDTH,
262                  0.025f * nn::gx::DISPLAY0_HEIGHT / nn::gx::DISPLAY0_WIDTH, 0.2f, 200.f);
263     glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uProjection"), 1, GL_TRUE, static_cast<f32*>(proj));
264 
265     float step = 0.5f;
266 
267     nn::math::Matrix44 id;
268     nn::math::MTX44Identity(&id);
269     glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uWorld"), 1, GL_TRUE, static_cast<f32*>(id));
270 
271     nn::math::Matrix34 mv;
272     nn::math::Vector3 camPos(0.f, 5.75f, 22.5f);
273     nn::math::Vector3 camUp(-1.f, 0.f, 0.f);
274     nn::math::Vector3 target(0.f, 0.f, 0.f);
275     nn::math::MTX34LookAt(&mv, &camPos, &camUp, &target);
276 
277     nn::math::Vector4 lpos0(8.f, 8.5f, 1.f, 1.f);
278     nn::math::Vector4 mv0(mv.m[0][0], mv.m[0][1], mv.m[0][2], mv.m[0][3]);
279     nn::math::Vector4 mv1(mv.m[1][0], mv.m[1][1], mv.m[1][2], mv.m[1][3]);
280     nn::math::Vector4 mv2(mv.m[2][0], mv.m[2][1], mv.m[2][2], mv.m[2][3]);
281 
282     nn::math::Vector4 lpos(nn::math::VEC4Dot(&mv0, &lpos0), nn::math::VEC4Dot(&mv1, &lpos0), nn::math::VEC4Dot(&mv2, &lpos0), lpos0.w);
283     glUniform4fv ( glGetUniformLocation ( s_ProgramID, "dmp_FragmentLightSource[0].position" ), 1, static_cast<f32*>(lpos)) ;
284 
285     nn::math::Matrix34 rot;
286     nn::math::MTX34RotXYZDeg(&rot, 0.f, -step*f, 0.f);
287     nn::math::MTX34Mult(&mv, &mv, &rot);
288 
289     nn::math::Matrix44 tmp(mv);
290     glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uModelView"), 1, GL_TRUE, static_cast<f32*>(tmp));
291 
292     for (int i = 0; i < car.obj_num; i++)
293     {
294         glBindBuffer(GL_ARRAY_BUFFER, car.posVB);
295         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)car.obj[i].vtx_offset);
296         glBindBuffer(GL_ARRAY_BUFFER, car.normVB);
297         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)car.obj[i].nrm_offset);
298         glBindBuffer(GL_ARRAY_BUFFER, car.tangVB);
299         glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)car.obj[i].tgt_offset);
300         glBindBuffer(GL_ARRAY_BUFFER, car.texVB);
301         glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (void*)car.obj[i].tex_offset);
302 
303         for (unsigned j = car.obj[i].patch_offset; j < car.obj[i].patch_size + car.obj[i].patch_offset; j++)
304         {
305             GLfloat ma[4] = {0.f, 0.f, 0.f, 1.f};
306             GLfloat md[4] = {0.f, 0.f, 0.f, 1.f};
307             GLfloat ms[4] = {0.f, 0.f, 0.f, 1.f};
308             for (int col = 0; col < 3; col++)
309             {
310                 ma[col] = car.patch[j].ambient[col];
311                 md[col] = car.patch[j].diffuse[col];
312                 ms[col] = car.patch[j].specular[col];
313             }
314             glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.diffuse"), 1, md);
315             glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.specular0"), 1, ms);
316             glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.ambient"), 1, ma);
317 
318             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, car.idxVB);
319             glDrawElements(GL_TRIANGLES, car.patch[j].elm_size,
320                 GL_UNSIGNED_SHORT, (GLvoid*)(car.patch[j].elm_offset + car.obj[i].elm_offset));
321         }
322     }
323 
324     glFinish();
325 
326     s_RenderSystem.SwapBuffers();
327 
328     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
329     s_RenderSystem.Clear();
330     s_RenderSystem.SwapBuffers();
331 
332     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
333 
334     f++;
335 
336     return !glGetError();
337 }
338 
339 /* initialization */
Initialize(void)340 static int Initialize(void)
341 {
342     // fs initialization
343     nn::fs::Initialize();
344 
345     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
346     static char buffer[ROMFS_BUFFER_SIZE];
347     NN_UTIL_PANIC_IF_FAILED(
348         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
349 
350     s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() );
351     s_HeapForGx = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
352     /* Initialize display */
353     s_RenderSystem.Initialize(s_HeapForGx, s_GxHeapSize);
354 
355     /* Create heap for malloc*/
356     s_HeapForMalloc = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_HeapSize));
357     setMemoryHeap(s_HeapForMalloc, s_HeapSize);
358 
359     glClearColor(0.36f, 0.42f, 0.5f, 1.0f);
360     glClearDepthf(1.f);
361 
362     glEnable(GL_DEPTH_TEST);
363     glDepthFunc(GL_LESS);
364 
365     glEnable(GL_CULL_FACE);
366     glFrontFace(GL_CCW);
367     glCullFace(GL_BACK);
368 
369     /* create program and load & attach vertex shader */
370     s_ProgramID = glCreateProgram();
371     s_ShaderID = glCreateShader(GL_VERTEX_SHADER);
372 
373     nn::fs::FileReader file(L"rom:/shader.shbin");
374     size_t fileSize = file.GetSize();
375     void* buf = s_AppHeap.Allocate(fileSize);
376 
377     s32 read = file.Read(buf, fileSize);
378     glShaderBinary(1, &s_ShaderID, GL_PLATFORM_BINARY_DMP, buf, read);
379     file.Finalize();
380     s_AppHeap.Free(buf);
381 
382     glAttachShader(s_ProgramID, s_ShaderID);
383 
384     /* attach fixed-function fragment shader */
385     glAttachShader(s_ProgramID, GL_DMP_FRAGMENT_SHADER_DMP);
386 
387     glBindAttribLocation(s_ProgramID, 0, "aPosition");
388     glBindAttribLocation(s_ProgramID, 1, "aNormal");
389     glBindAttribLocation(s_ProgramID, 2, "aTang");
390     glBindAttribLocation(s_ProgramID, 3, "aTexCoord");
391 
392     glLinkProgram(s_ProgramID);
393     glValidateProgram(s_ProgramID);
394     /* set program as current one to enable setting its uniforms */
395     glUseProgram(s_ProgramID);
396 
397     LoadObjects();
398 
399     glEnableVertexAttribArray(0);
400     glEnableVertexAttribArray(1);
401     glEnableVertexAttribArray(2);
402     glEnableVertexAttribArray(3);
403 
404     return 0;
405 }
406 
nnMain(void)407 void nnMain(void)
408 {
409     // Call only nn::applet::Enable to also allow execution from the HOME Menu
410     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
411     nn::applet::Enable();
412 
413     /* initialization */
414     if (Initialize() >= 0)
415     {
416         /* set another render state */
417         SetRenderState();
418 
419         /* Enter loop */
420         while (1)
421         {
422             (void)DrawFrame();
423         }
424     }
425     UnloadObjects();
426     /* shutdown_display */
427     s_RenderSystem.Finalize();
428     s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForMalloc));
429     s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForGx));
430     s_AppHeap.Finalize();
431 }
432 
433