1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: LightingSpotAtte.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 #include <nn/gx.h>
27 #include <nn/fs.h>
28 #include <nn/math.h>
29 #include <nn/init.h>
30 #include <nn/os.h>
31 #include <nn/applet.h>
32 #include "Util.h"
33 #include "Loader.h"
34
35 #include "demo.h"
36
37 #include <string.h>
38 #include <math.h>
39
40 #include "Memory.h"
41
42 #define APP_NAME "LightingSpotAtte"
43
44 #define DMP_PI (3.1415926f)
45 #define REV_PI (1.0f/DMP_PI)
46
47 /* program id */
48 GLuint s_ProgramID;
49
50 /* shader id */
51 GLuint s_ShaderID;
52
53 /* ExpHeap for app. */
54 nn::fnd::ExpHeap s_AppHeap;
55 uptr s_HeapForGx;
56 uptr s_HeapForMalloc;
57 const u32 s_GxHeapSize = 0x400000;
58 const u32 s_HeapSize = 0x200000;
59
60 demo::RenderSystem s_RenderSystem;
61
SetRenderState(void)62 static void SetRenderState(void)
63 {
64 GLfloat ld_0[] = {1.f, 0.f, 0.f, 1.f};
65 GLfloat ld_1[] = {0.f, 1.f, 0.f, 1.f};
66 GLfloat ld_2[] = {0.f, 0.f, 1.f, 1.f};
67 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].diffuse"), 1, ld_0);
68 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].diffuse"), 1, ld_1);
69 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].diffuse"), 1, ld_2);
70
71 /* setup spot lighting configuration */
72 /* Individual lookup tables are allocated for individual lights, but note that common settings for lookup table input and sampling methods are applied to all lights.
73 */
74 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.lutInputSP"), GL_LIGHT_ENV_SP_DMP);
75 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_LightEnv.absLutInputSP"), GL_TRUE);
76
77 GLuint lutids[3];
78 float lut[512];
79 unsigned int j;
80 glGenTextures(3, lutids);
81
82 #define COS_45 0.71f
83 #define COS_40 0.77f
84 #define COS_35 0.82f
85 #define COS_30 0.87f
86 #define COS_25 0.91f
87 #define COS_20 0.94f
88 #define COS_15 0.97f
89 #define COS_10 0.98f
90
91 memset( lut, 0, sizeof( lut ) );
92 for (j = 0; j < 256; j++)
93 {
94 float x = ( float )j / ( float )256;
95 if ( x > COS_30 )
96 lut[j] = 1.f;
97 }
98
99 glBindTexture(GL_LUT_TEXTURE0_DMP, lutids[0]);
100 glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
101 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].samplerSP"), 0);
102 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].spotEnabled"), GL_TRUE);
103
104 memset( lut, 0, sizeof( lut ) );
105 for (j = 0; j < 256; j++)
106 {
107 float x = ( float )j / ( float )256;
108 if ( x > COS_20 )
109 lut[j] = 1.f;
110 }
111
112 glBindTexture(GL_LUT_TEXTURE1_DMP, lutids[1]);
113 glTexImage1D(GL_LUT_TEXTURE1_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
114 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].samplerSP"), 1);
115 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].spotEnabled"), GL_TRUE);
116
117 memset( lut, 0, sizeof( lut ) );
118 for (j = 0; j < 256; j++)
119 {
120 float x = ( float )j / ( float )256;
121 if ( x > COS_10 )
122 lut[j] = 1.f;
123 }
124
125 glBindTexture(GL_LUT_TEXTURE2_DMP, lutids[2]);
126 glTexImage1D(GL_LUT_TEXTURE2_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, GL_LUMINANCEF_DMP, GL_FLOAT, lut);
127 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].samplerSP"), 2);
128 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].spotEnabled"), GL_TRUE);
129 }
130
DrawPlane()131 void DrawPlane()
132 {
133 /* Using fragment lighting, you can create beautiful spotlights even on polygon models that are not finely divided. This differs from vertex lighting.
134 In this sample, the spotlight is applied to a model composed of only 2 polygons. If vertex lighting were used to achieve the same effect, a finely divided model would have to be used.
135 */
136 GLfloat coords[] =
137 {
138 -3.f, 0.f, 3.f,
139 3.f, 0.f, 3.f,
140 3.f, 0.f, -3.f,
141 -3.f, 0.f, -3.f,
142 };
143
144 GLfloat norm[] =
145 {
146 0.f, 1.f, 0.f,
147 0.f, 1.f, 0.f,
148 0.f, 1.f, 0.f,
149 0.f, 1.f, 0.f,
150 };
151
152 unsigned short index[] =
153 {
154 0, 1, 2, 0, 2, 3
155 };
156
157 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, coords);
158 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, norm);
159 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, index);
160 }
161
DrawFrame(void)162 int DrawFrame(void)
163 {
164 static int f = 0;
165
166 nn::math::Matrix34 mv, rot;
167
168 s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
169 s_RenderSystem.Clear();
170
171 /* setup projection matrix */
172 nn::math::Matrix44 proj;
173 nn::math::MTX44Frustum(&proj, -0.06f, 0.06f, -0.06f*nn::gx::DISPLAY0_HEIGHT/nn::gx::DISPLAY0_WIDTH,
174 0.06f*nn::gx::DISPLAY0_HEIGHT/nn::gx::DISPLAY0_WIDTH, 0.2f, 200.f);
175 glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uProjection"), 1, GL_TRUE, static_cast<f32*>(proj));
176
177 nn::math::Vector3 camPos(0.f, 7.f, 7.f);
178 nn::math::Vector3 camUp(0.f, 1.f, 0.f);
179 nn::math::Vector3 target(0.f, 0.f, 0.f);
180 nn::math::MTX34RotXYZDeg(&rot, 0.f, 0.f, -90.0f);
181 nn::math::MTX34LookAt(&mv, &camPos, &camUp, &target);
182 nn::math::MTX34Mult(&mv, &rot, &mv);
183
184 /* Light position and spotlight direction are converted to view coordinate values and then passed to the reserve fragment shader uniform.
185
186 The conversion to view coordinates is not absolute
187 In this sample, the normals and view vectors needed for fragment lighting calculations are converted to view coordinates in the vertex shader
188
189 For this reason, light position and spotlight direction must be in view coordinates
190 Also note that the spot direction vector must be normalized before being passed */
191 /* setup light direction and spot direction (light0) */
192 nn::math::Vector4 lpos0(0.f, 1.f, 0.f, 1.f);
193 lpos0.y = 3.f * cosf(2.f * f / 60.f) + 5.f;
194 nn::math::Vector4 mv0(mv.m[0][0], mv.m[0][1], mv.m[0][2], mv.m[0][3]);
195 nn::math::Vector4 mv1(mv.m[1][0], mv.m[1][1], mv.m[1][2], mv.m[1][3]);
196 nn::math::Vector4 mv2(mv.m[2][0], mv.m[2][1], mv.m[2][2], mv.m[2][3]);
197 nn::math::Vector4 lpos(VEC4Dot(&mv0, &lpos0), VEC4Dot(&mv1, &lpos0), VEC4Dot(&mv2, &lpos0), lpos0.w);
198 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].position"), 1, static_cast<f32*>(lpos));
199
200 nn::math::Vector4 lpos0_dir(0.f, -1.f, 0.f, 0.f);
201 lpos0_dir.x = 0.5f * cosf(2.f * f / 60.f);
202 lpos0_dir.z = 0.5f * sinf(2.f * f / 60.f);
203 nn::math::Vector4 lpos_dir(nn::math::VEC4Dot(&mv0, &lpos0_dir), nn::math::VEC4Dot(&mv1, &lpos0_dir),
204 nn::math::VEC4Dot(&mv2, &lpos0_dir), lpos0_dir.w);
205 lpos_dir.Normalize();
206 glUniform3fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].spotDirection"), 1, static_cast<f32*>(lpos_dir));
207
208 /* setup light direction and spot direction (light1) */
209 nn::math::Vector4 lpos1(0.f, 1.f, 0.f, 1.f);
210 lpos1.y = 3.f * cosf(2.5f * f / 60.f) + 4.f;
211 lpos = nn::math::Vector4(nn::math::VEC4Dot(&mv0, &lpos1), nn::math::VEC4Dot(&mv1, &lpos1),
212 nn::math::VEC4Dot(&mv2, &lpos1), lpos1.w);
213 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].position"), 1, static_cast<f32*>(lpos));
214
215 nn::math::Vector4 lpos1_dir(0.f, -1.f, 0.f, 0.f);
216 lpos1_dir.x = 0.5f * cosf(2.5f * f / 60.f);
217 lpos1_dir.z = 0.5f * sinf(2.5f * f / 60.f);
218 lpos_dir = nn::math::Vector4(nn::math::VEC4Dot(&mv0, &lpos1_dir), nn::math::VEC4Dot(&mv1, &lpos1_dir),
219 nn::math::VEC4Dot(&mv2, &lpos1_dir), lpos1_dir.w);
220 lpos_dir.Normalize();
221 glUniform3fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].spotDirection"), 1, static_cast<f32*>(lpos_dir));
222
223 /* setup light direction and spot direction (light2) */
224 nn::math::Vector4 lpos2(0.f, 1.f, 0.f, 1.f);
225 lpos2.y = 3.f * cosf(3.f * f / 60.f) + 4.f;
226 lpos = nn::math::Vector4(nn::math::VEC4Dot(&mv0, &lpos2), nn::math::VEC4Dot(&mv1, &lpos2),
227 nn::math::VEC4Dot(&mv2, &lpos2), lpos2.w);
228 glUniform4fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].position"), 1, static_cast<f32*>(lpos));
229
230 nn::math::Vector4 lpos2_dir(0.f, -1.f, 0.f, 0.f);
231 lpos2_dir.x = 0.5f * cosf(3.f * f / 60.f);
232 lpos2_dir.z = 0.5f * sinf(3.f * f / 60.f);
233 lpos_dir = nn::math::Vector4(nn::math::VEC4Dot(&mv0, &lpos2_dir), nn::math::VEC4Dot(&mv1, &lpos2_dir),
234 nn::math::VEC4Dot(&mv2, &lpos2_dir), lpos2_dir.w);
235 lpos_dir.Normalize();
236 glUniform3fv(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].spotDirection"), 1, static_cast<f32*>(lpos_dir));
237
238 nn::math::Matrix44 m(mv);
239 glUniformMatrix4fv(glGetUniformLocation(s_ProgramID, "uModelView"), 1, GL_TRUE, static_cast<f32*>(m));
240
241 glEnableVertexAttribArray(0);
242 glEnableVertexAttribArray(1);
243
244 /* draw objects */
245 DrawPlane();
246
247 glFinish();
248
249 s_RenderSystem.SwapBuffers();
250
251 s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
252 s_RenderSystem.Clear();
253 s_RenderSystem.SwapBuffers();
254
255 s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
256
257 f++;
258
259 return !glGetError();
260 }
261
262 /* initialization */
Initialize(void)263 static int Initialize(void)
264 {
265 s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() );
266 s_HeapForGx = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
267 /* Initialize display */
268 s_RenderSystem.Initialize(s_HeapForGx, s_GxHeapSize);
269
270 /* Create heap for malloc*/
271 s_HeapForMalloc = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_HeapSize));
272 setMemoryHeap(s_HeapForMalloc, s_HeapSize);
273
274 s_ProgramID = glCreateProgram();
275 s_ShaderID = glCreateShader(GL_VERTEX_SHADER);
276
277 nn::fs::FileReader file(L"rom:/shader.shbin");
278 size_t fileSize = file.GetSize();
279 void* buf = s_AppHeap.Allocate(fileSize);
280
281 s32 read = file.Read(buf, fileSize);
282 glShaderBinary(1, &s_ShaderID, GL_PLATFORM_BINARY_DMP, buf, read);
283 file.Finalize();
284 s_AppHeap.Free(buf);
285
286 glAttachShader(s_ProgramID, s_ShaderID);
287 glAttachShader(s_ProgramID, GL_DMP_FRAGMENT_SHADER_DMP);
288
289 glBindAttribLocation(s_ProgramID, 0, "aPosition");
290 glBindAttribLocation(s_ProgramID, 1, "aNormal");
291
292 glLinkProgram(s_ProgramID);
293 glValidateProgram(s_ProgramID);
294 glUseProgram(s_ProgramID);
295
296 glClearColor(0.36f, 0.42f, 0.5f, 1.0f);
297 glClearDepthf(1.f);
298
299 glEnable(GL_DEPTH_TEST);
300 glDepthFunc(GL_LESS);
301 glEnable(GL_CULL_FACE);
302 glFrontFace(GL_CCW);
303 glCullFace(GL_BACK);
304
305 /* set another render state */
306 SetRenderState();
307
308 /* enable DMP fragment lighting */
309 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLighting.enabled"), GL_TRUE);
310 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[0].enabled"), GL_TRUE);
311 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[1].enabled"), GL_TRUE);
312 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_FragmentLightSource[2].enabled"), GL_TRUE);
313
314 /* this sample use only fragment primary color */
315 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineRgb"), GL_REPLACE);
316 glUniform1i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].combineAlpha"), GL_REPLACE);
317 glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
318 glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
319 glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcRgb"), GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_CONSTANT, GL_CONSTANT);
320 glUniform3i(glGetUniformLocation(s_ProgramID, "dmp_TexEnv[0].srcAlpha"), GL_CONSTANT, GL_CONSTANT, GL_CONSTANT);
321
322 return 0;
323 }
324
nnMain(void)325 void nnMain(void)
326 {
327 // Call only nn::applet::Enable to also allow execution from the HOME Menu
328 // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
329 nn::applet::Enable();
330
331 // fs initialization
332 nn::fs::Initialize();
333
334 const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
335 static char buffer[ROMFS_BUFFER_SIZE];
336 NN_UTIL_PANIC_IF_FAILED(
337 nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
338
339 /* initialization */
340 if (Initialize() >= 0)
341 {
342 /* Enter loop */
343 while (1)
344 {
345 (void)DrawFrame();
346 }
347 }
348
349 /* shutdown_display */
350 s_RenderSystem.Finalize();
351 s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForMalloc));
352 s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForGx));
353 s_AppHeap.Finalize();
354 }
355