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