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