1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: LightingToonApple.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 * VN masking means that light reflection is set to zero when VN is smaller
31 * than some threshold value 'outline.' This method works poorly when an
32 * object has concave places (such as a center part of the inside of a palm).
33 */
34
35 #include <nn/gx.h>
36 #include <nn/fs.h>
37 #include <nn/math.h>
38 #include <nn/init.h>
39 #include <nn/os.h>
40 #include <nn/applet.h>
41
42 #include "demo.h"
43
44 #include "Util.h"
45 #include "Loader.h"
46
47 #include <string.h>
48
49 #include "Memory.h"
50
51 #define APP_NAME "LightingToonApple"
52
53 /* program id */
54 GLuint s_ProgramID;
55
56 /* shader id */
57 GLuint s_ShaderID;
58
59 /* env texture id */
60 GLuint s_EnvTexName;
61 /* obj file loader class object */
62 dat_t sphere;
63
64 /* texture collection id */
65 GLuint s_TexColl;
66
67 /* ExpHeap for app. */
68 nn::fnd::ExpHeap s_AppHeap;
69 uptr s_HeapForGx;
70 uptr s_HeapForMalloc;
71 const u32 s_GxHeapSize = 0x400000;
72 const u32 s_HeapSize = 0x200000;
73
74 demo::RenderSystem s_RenderSystem;
75
76 /* if USE_LN is not defined, half-vector is used as the vector controlling both diffuse illumination and highlight position */
77 #define USE_LN
78 /* if WINDOW is defined, a window highlight is used */
79 #define WINDOW
80
SetLutTable(void)81 static void SetLutTable(void)
82 {
83 GLuint luts[4];
84 glGenTextures(4, luts);
85
86 const float outline = 0.15f;
87 const float highlight_eps = 0.01f;
88 float delta[] = {1.f, 0.7f, 0.5f, -1.f};
89
90 GLfloat lut[512];
91 int j;
92 memset(lut, 0, sizeof(lut));
93 float previous = 0, LN;
94 int i = 0;
95
96 /* f(D) = D is used as the initial shading function - see "Illumination Models in Maestro" for details
97 first specify the steps in the [0, 1) interval */
98 for (j = 127; j >= 0; j--)
99 {
100 LN = (float)j/127.9375f;
101 if (LN > delta[i])
102 lut[j] = previous;
103 else
104 {
105 lut[j] = LN;
106 previous = lut[j];
107 i++;
108 }
109 }
110 for (j = 0; j < 127; j++)
111 lut[j + 256] = lut[j+1] - lut[j];
112 lut[127 + 256] = 0.f;
113
114 /* now specify the steps in the [-1, 0) interval */
115 for (j = 255; j >= 128; j--)
116 {
117 LN = (float)(j - 256) /128.f;
118 if (LN > delta[i])
119 lut[j] = previous;
120 else
121 {
122 lut[j] = LN;
123 previous = lut[j];
124 i++;
125 }
126 }
127
128 /* now calculate differences (some are 0, some are not) */
129 for (j = 128; j < 255; j++)
130 lut[j + 256] = lut[j+1] - lut[j];
131 lut[255 + 256] = lut[0] - lut[255];
132
133 glBindTexture(GL_LUT_TEXTURE0_DMP, luts[0]);
134 glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
135
136 for (j = 0; j < 256; j++)
137 if ((float)j/255.9375f <= 1.f - highlight_eps)
138 lut[j] = 0.f;
139 else
140 lut[j] = 1.f;
141 for (j = 0; j < 255; j++)
142 lut[j + 256] = lut[j+1] - lut[j];
143 lut[255 + 256] = 0.f;
144
145 glBindTexture(GL_LUT_TEXTURE1_DMP, luts[1]);
146 glTexImage1D(GL_LUT_TEXTURE1_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
147
148 for (j = 0; j < 256; j++)
149 if ((float)j/255.9375f < outline)
150 lut[j] = 0.f;
151 else
152 lut[j] = 1.f;
153
154 for (j = 0; j < 255; j++)
155 lut[j + 256] = lut[j+1] - lut[j];
156 lut[255 + 256] = 1.f - lut[255];
157
158 glBindTexture(GL_LUT_TEXTURE2_DMP, luts[2]);
159 glTexImage1D(GL_LUT_TEXTURE2_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
160
161 for (j = 0; j < 256; j++)
162 lut[j] = 1.f;
163
164 for (j = 0; j < 256; j++)
165 lut[j + 256] = 0.f;
166
167 glBindTexture(GL_LUT_TEXTURE3_DMP, luts[3]);
168 glTexImage1D(GL_LUT_TEXTURE3_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
169 }
170
171 /* set lighting render state */
SetRenderState(void)172 static void SetRenderState(void)
173 {
174 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLighting.enabled"), GL_TRUE);
175 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].enabled"), GL_TRUE);
176
177 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputD0"), GL_TRUE);
178 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputD1"), GL_TRUE);
179 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputFR"), GL_TRUE);
180 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputRR"), GL_FALSE);
181
182 #ifdef USE_LN
183 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRR"), GL_LIGHT_ENV_LN_DMP);
184 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputD0"), GL_LIGHT_ENV_LN_DMP);
185 #else
186 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputRR"), GL_LIGHT_ENV_NH_DMP);
187 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputD0"), GL_LIGHT_ENV_NH_DMP);
188 #endif
189 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputD1"), GL_LIGHT_ENV_NV_DMP);
190 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputFR"), GL_LIGHT_ENV_NV_DMP);
191
192 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].shadowed"), GL_FALSE);
193 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].twoSideDiffuse"), GL_FALSE);
194 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].geomFactor0"), GL_FALSE);
195 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].geomFactor1"), GL_FALSE);
196
197 glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleD0"), 1.f);
198 glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleD1"), 1.f);
199 glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleSP"), 1.f);
200 glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleFR"), 1.f);
201 glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRB"), 1.f);
202 glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRG"), 1.f);
203 glUniform1f(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutScaleRR"), 1.f);
204
205 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledRefl"), GL_TRUE);
206 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledSP"), GL_FALSE);
207 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.config"), GL_LIGHT_ENV_LAYER_CONFIG6_DMP);
208 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.bumpMode"), GL_LIGHT_ENV_BUMP_NOT_USED_DMP);
209
210 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledD0"), GL_TRUE);
211 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutEnabledD1"), GL_TRUE);
212 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.clampHighlights"), GL_FALSE);
213 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.fresnelSelector"), GL_LIGHT_ENV_PRI_SEC_ALPHA_FRESNEL_DMP);
214
215 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerRR"), 0);
216 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerD0"), 1);
217 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerD1"), 2);
218 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.samplerFR"), 3);
219
220 SetLutTable();
221
222 GLfloat ma[] = {0.f, 0.f, 0.f, 1.f}; /* material ambient */
223 GLfloat md[] = {0.f, 0.f, 0.f, 1.f}; /* material diffuse */
224 GLfloat ms[] = {1.f, 1.f, 1.f, 1.f}; /* material specular */
225 #ifdef WINDOW
226 ms[0] = 0.f;
227 ms[1] = 0.f;
228 ms[2] = 0.f;
229 #endif
230 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.diffuse"), 1, md);
231 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.specular0"), 1, ms);
232 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentMaterial.ambient"), 1, ma);
233
234 GLfloat ld[] = {1.f, 1.f, 1.f, 1.f}; /* light diffuse */
235 GLfloat ls[] = {1.f, 1.f, 1.f, 1.f}; /* light specular */
236 GLfloat ls2[] = {1.f, 0.2f, 0.f, 1.f}; /* light specular2 */
237 GLfloat la[] = {1.f, 1.f, 1.f, 1.f}; /* light ambient */
238
239 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].diffuse"), 1, ld);
240 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].specular0"), 1, ls);
241 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].specular1"), 1, ls2);
242 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].ambient"), 1, la);
243
244 nn::math::Matrix44 proj;
245 /* set projection matrix */
246 nn::math::MTX44Frustum(&proj, -0.015f, 0.015f, -0.015f * nn::gx::DISPLAY0_HEIGHT / nn::gx::DISPLAY0_WIDTH,
247 0.015f * nn::gx::DISPLAY0_HEIGHT / nn::gx::DISPLAY0_WIDTH, 0.2f, 200.f);
248 glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uProjection"), 1, GL_TRUE, static_cast<f32*>(proj));
249
250 /* set texture setting */
251 #ifdef WINDOW
252 /* output color is EnvTexture_rgb * PriColor_alpha + SecColor_rgb
253 EnvTexture_rgb is environment highlight specular, PriColor_alpha is frensel reflection,
254 and SecColor_rgb is toon shading diffuse color. */
255 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_Texture[0].samplerType"), GL_TEXTURE_CUBE_MAP);
256 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineRgb"), GL_MULT_ADD_DMP);
257 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineAlpha"), GL_REPLACE);
258 glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_COLOR);
259 glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcRgb"), GL_TEXTURE0, GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_FRAGMENT_SECONDARY_COLOR_DMP);
260 #else
261 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_Texture[0].samplerType"), GL_FALSE);
262 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineRgb"), GL_REPLACE);
263 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineAlpha"), GL_REPLACE);
264 glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
265 glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcRgb"), GL_FRAGMENT_SECONDARY_COLOR_DMP, GL_CONSTANT, GL_CONSTANT);
266 #endif
267 }
268
269 /* load objects */
LoadObjects(void)270 static void LoadObjects(void)
271 {
272 /* load obj file geometry and diffuse texture */
273 loadDAT( "rom:/resources/sphere.dat", &sphere);
274
275 /* if you environment highlight specular, load environment cube texture */
276 #ifdef WINDOW
277 char *env_tex[] =
278 {
279 "rom:/resources/wright.tga",
280 "rom:/resources/wleft.tga",
281 "rom:/resources/wtop.tga",
282 "rom:/resources/wbottom.tga",
283 "rom:/resources/wback.tga",
284 "rom:/resources/wfront.tga",
285 };
286 glGenTextures(1, &s_EnvTexName);
287 glBindTexture(GL_TEXTURE_CUBE_MAP, s_EnvTexName);
288 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_LOD, 0);
289
290 for (int face = 0; face < 6; face++)
291 {
292 bool use_alpha;
293 loadTexture(env_tex[face], GL_TEXTURE_CUBE_MAP_POSITIVE_X+face, 0, use_alpha, true, 0, GL_RGBA);
294 }
295 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
296 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
297 #endif
298 }
299
UnloadObjects(void)300 static void UnloadObjects(void)
301 {
302 unloadDAT(&sphere);
303
304 return;
305 }
306
DrawFrame(void)307 int DrawFrame(void)
308 {
309 static int f = 0;
310
311 s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
312 s_RenderSystem.Clear();
313
314 nn::math::Matrix44 id;
315
316 nn::math::MTX44Identity(&id);
317 glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uWorld"), 1, GL_FALSE, static_cast<f32*>(id));
318
319 /* modelview setting */
320 nn::math::Matrix34 mv;
321 nn::math::Vector3 camPos(0.f, 5.75f, 22.5f);
322 nn::math::Vector3 camUp(0.f, 1.f, 0.f);
323 nn::math::Vector3 target(0.f, 0.f, 0.f);
324 nn::math::MTX34LookAt(&mv, &camPos, &camUp, &target);
325
326 /* light direction setting */
327 nn::math::Vector4 lpos0(28.5f, 9.5f, 14.f, 1.f);
328 nn::math::Vector4 mv0(mv.m[0][0], mv.m[0][1], mv.m[0][2], mv.m[0][3]);
329 nn::math::Vector4 mv1(mv.m[1][0], mv.m[1][1], mv.m[1][2], mv.m[1][3]);
330 nn::math::Vector4 mv2(mv.m[2][0], mv.m[2][1], mv.m[2][2], mv.m[2][3]);
331 nn::math::Vector4 lpos(nn::math::VEC4Dot(&mv0, &lpos0), nn::math::VEC4Dot(&mv1, &lpos0), nn::math::VEC4Dot(&mv2, &lpos0), lpos0.w);
332 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].position"), 1, static_cast<f32*>(lpos));
333
334 nn::math::Matrix34 rot;
335 nn::math::MTX34RotXYZDeg(&rot, 0.f, static_cast<f32>(-f), 0.f);
336 nn::math::MTX34Mult(&mv, &mv, &rot);
337 nn::math::Matrix44 m(mv);
338 glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uModelView"), 1, GL_TRUE, static_cast<f32*>(m));
339
340 /* draw objects */
341 for (int i = 0; i < sphere.obj_num; i++)
342 {
343 glBindBuffer(GL_ARRAY_BUFFER, sphere.posVB);
344 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)sphere.obj[i].vtx_offset);
345 glBindBuffer(GL_ARRAY_BUFFER, sphere.normVB);
346 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)sphere.obj[i].nrm_offset);
347
348 for (unsigned j = sphere.obj[i].patch_offset; j < sphere.obj[i].patch_size + sphere.obj[i].patch_offset; j++)
349 {
350 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sphere.idxVB);
351 glDrawElements(GL_TRIANGLES, sphere.patch[j].elm_size,
352 GL_UNSIGNED_SHORT, (GLvoid*)(sphere.patch[j].elm_offset + sphere.obj[i].elm_offset));
353 }
354 }
355
356 glFinish();
357
358 s_RenderSystem.SwapBuffers();
359
360 s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
361 s_RenderSystem.Clear();
362 s_RenderSystem.SwapBuffers();
363
364 s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
365
366 f++;
367
368 return !glGetError();
369 }
370
371 /* initialization */
Initialize(void)372 static int Initialize(void)
373 {
374 s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() );
375 s_HeapForGx = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
376 /* Initialize display */
377 s_RenderSystem.Initialize(s_HeapForGx, s_GxHeapSize);
378
379 /* Create heap for malloc*/
380 s_HeapForMalloc = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_HeapSize));
381 setMemoryHeap(s_HeapForMalloc, s_HeapSize);
382
383 glClearColor(0.36f, 0.42f, 0.5f, 1.0f);
384 glClearDepthf(1.f);
385
386 glEnable(GL_DEPTH_TEST);
387 glDepthFunc(GL_LESS);
388
389 glEnable(GL_CULL_FACE);
390 glFrontFace(GL_CCW);
391 glCullFace(GL_BACK);
392
393 s_ProgramID = glCreateProgram();
394 s_ShaderID = glCreateShader(GL_VERTEX_SHADER);
395
396 nn::fs::FileReader file(L"rom:/shader.shbin");
397 size_t fileSize = file.GetSize();
398 void* buf = s_AppHeap.Allocate(fileSize);
399
400 s32 read = file.Read(buf, fileSize);
401 glShaderBinary(1, &s_ShaderID, GL_PLATFORM_BINARY_DMP, buf, read);
402 file.Finalize();
403 s_AppHeap.Free(buf);
404
405 glAttachShader(s_ProgramID, s_ShaderID);
406
407 /* attach fixed-function fragment shader */
408 glAttachShader(s_ProgramID, GL_DMP_FRAGMENT_SHADER_DMP);
409
410 glBindAttribLocation(s_ProgramID, 0, "aPosition");
411 glBindAttribLocation(s_ProgramID, 1, "aNormal");
412
413 glLinkProgram(s_ProgramID);
414 glValidateProgram(s_ProgramID);
415 /* set program as current one to enable setting its uniforms */
416 glUseProgram(s_ProgramID);
417
418 /* enable arrays that will be mapped to position and normal */
419 glEnableVertexAttribArray(0);
420 glEnableVertexAttribArray(1);
421
422 /* create and bind texture collection object to capture subsequent modifications in the texture state
423 both lookup table-related one and ordinary (2D, cube) textures */
424 glGenTextures(1, &s_TexColl) ;
425 glBindTexture(GL_TEXTURE_COLLECTION_DMP, s_TexColl);
426
427 LoadObjects();
428
429 return 0;
430 }
431
nnMain(void)432 void nnMain(void)
433 {
434 // Call only nn::applet::Enable to also allow execution from the HOME Menu
435 // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
436 nn::applet::Enable();
437
438 // fs initialization
439 nn::fs::Initialize();
440
441 const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
442 static char buffer[ROMFS_BUFFER_SIZE];
443 NN_UTIL_PANIC_IF_FAILED(
444 nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
445
446 /* initialization */
447 if (Initialize() >= 0)
448 {
449 /* set another render state */
450 SetRenderState();
451
452 /* Enter loop */
453 while (1)
454 {
455 (void)DrawFrame();
456 }
457 }
458
459 UnloadObjects();
460 /* shutdown_display */
461 s_RenderSystem.Finalize();
462 s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForMalloc));
463 s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForGx));
464 s_AppHeap.Finalize();
465 }
466