1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     LightingVertex.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  * This sample emulates the fixed vertex pipeline of OpenGL ES 1.1.
31  * It is implemented using the vertex shader to convert vertex coordinates to clip space and calculate vertex colors from one light and point light source.
32  *
33  */
34 
35 #include <string.h>
36 #include <math.h>
37 
38 #include <nn/gx.h>
39 #include <nn/math.h>
40 #include <nn/fs.h>
41 #include <nn/os.h>
42 #include <nn/init.h>
43 #include <nn/applet.h>
44 #include <nn/fnd/fnd_ExpHeap.h>
45 
46 #include "demo.h"
47 
48 #define DMP_PI  (3.1415926f)
49 
50 /* program id */
51 GLuint s_PgID;
52 
53 /* shader id */
54 GLuint s_ShID;
55 
56 /* OpenGLES1.1 vertex lighting specular shininess */
57 #define SPEC_SHININESS  32.f
58 #define STEP 6.f
59 
60 /* object names */
61 enum {
62     OBJECT_SPHERE,  /* sphere */
63     OBJECT_PLANE,   /* plane */
64     OBJECT_COUNT    /* object count */
65 };
66 
67 /* buffer object ID */
68 static struct tagObject
69 {
70     GLuint id[OBJECT_COUNT];
71     GLuint idxId[OBJECT_COUNT];
72 } s_Object;
73 
74 /* buffer object information */
75 static struct tagObjectInfo
76 {
77     GLushort idxcnt[OBJECT_COUNT];
78     GLushort vtxcnt[OBJECT_COUNT];
79 } s_ObjectInfo;
80 
81 
82 #define ROW_NUM     (50)    /* NUM in ROW */
83 #define COL_NUM     (50)    /* NUM in COLUMN */
84 #define deltaROW    (DMP_PI / (ROW_NUM - 1))
85 #define deltaCOL    (2 * DMP_PI / (COL_NUM - 1))
86 
87 struct tagVertex{
88     GLfloat pos[ROW_NUM * COL_NUM][3];
89     GLfloat nor[ROW_NUM * COL_NUM][3];
90 } s_Vtx;
91 GLushort s_Idx[COL_NUM * (ROW_NUM - 1) * 2];
92 
93 /* ExpHeap for app. */
94 nn::fnd::ExpHeap s_AppHeap;
95 uptr s_HeapForGx;
96 const u32 s_GxHeapSize = 0x400000;
97 
98 demo::RenderSystem s_RenderSystem;
99 
100 /* load sphere object */
LoadSphere(void)101 static void LoadSphere(void)
102 {
103     /* vertex array */
104     for(int row = 0; row < ROW_NUM; row++)
105     {
106         for(int col = 0; col < COL_NUM; col++)
107         {
108             /* position */
109             s_Vtx.pos[row * COL_NUM + col][0] =(GLfloat)sin(deltaROW * row) * cos(deltaCOL * col);
110             s_Vtx.pos[row * COL_NUM + col][1] =(GLfloat)cos(deltaROW * row);
111             s_Vtx.pos[row * COL_NUM + col][2] =(GLfloat)sin(deltaROW * row) * sin(deltaCOL * col);
112             /* normal */
113             s_Vtx.nor[row * COL_NUM + col][0] =(GLfloat)sin(deltaROW * row) * cos(deltaCOL * col);
114             s_Vtx.nor[row * COL_NUM + col][1] =(GLfloat)cos(deltaROW * row);
115             s_Vtx.nor[row * COL_NUM + col][2] =(GLfloat)sin(deltaROW * row) * sin(deltaCOL * col);
116         }
117     }
118 
119     /* index array */
120     for(int i = 0, row = 0; row < ROW_NUM - 1; row++)
121     {
122     #define __INDEX(ROW, COL)   ((ROW) * COL_NUM + (COL))
123         for(int col = 0; col < COL_NUM; col++)
124         {
125             s_Idx[i++] = __INDEX(row + 1, col);
126             s_Idx[i++] = __INDEX(row, col);
127         }
128     #undef __INDEX
129     }
130     /* count */
131     s_ObjectInfo.idxcnt[OBJECT_SPHERE] = COL_NUM * (ROW_NUM - 1) * 2;
132     s_ObjectInfo.vtxcnt[OBJECT_SPHERE] = ROW_NUM * COL_NUM;
133 
134     /* load vertex array and index array */
135     glBindBuffer(GL_ARRAY_BUFFER, s_Object.id[OBJECT_SPHERE]);
136     glBufferData(GL_ARRAY_BUFFER, sizeof(s_Vtx), &s_Vtx, GL_STATIC_DRAW);
137     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_Object.idxId[OBJECT_SPHERE]);
138     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(s_Idx), s_Idx, GL_STATIC_DRAW);
139 
140 
141 #undef LONG_NUM
142 #undef LATI_NUM
143 #undef deltaROW
144 #undef deltaCOL
145 }
146 
147 /* load plane object */
LoadPlane(void)148 static void LoadPlane(void)
149 {
150     struct tagVertex{
151         GLfloat pos[4][3];
152         GLfloat nor[4][3];
153     } vtx;
154     GLushort idx[4] ={0, 1, 2, 3};
155 
156     /* vertex array */
157     vtx.pos[0][0] = +3.0f;
158     vtx.pos[0][1] = -1.0f;
159     vtx.pos[0][2] = +3.0f;
160 
161     vtx.pos[1][0] = +3.0f;
162     vtx.pos[1][1] = -1.0f;
163     vtx.pos[1][2] = -3.0f;
164 
165     vtx.pos[2][0] = -3.0f;
166     vtx.pos[2][1] = -1.0f;
167     vtx.pos[2][2] = +3.0f;
168 
169     vtx.pos[3][0] = -3.0f;
170     vtx.pos[3][1] = -1.0f;
171     vtx.pos[3][2] = -3.0f;
172 
173     for(int i = 0; i < 4; i++)
174     {
175         vtx.nor[i][0] = 0.f;
176         vtx.nor[i][1] = 1.f;
177         vtx.nor[i][2] = 0.f;
178     }
179 
180     /* count */
181     s_ObjectInfo.idxcnt[OBJECT_PLANE] = 4;
182     s_ObjectInfo.vtxcnt[OBJECT_PLANE] = 4;
183 
184     /* load vertex array and index array */
185     glBindBuffer(GL_ARRAY_BUFFER, s_Object.id[OBJECT_PLANE]);
186     glBufferData(GL_ARRAY_BUFFER, sizeof(vtx), vtx.pos[0], GL_STATIC_DRAW);
187     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_Object.idxId[OBJECT_PLANE]);
188     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW);
189 }
190 
191 /* load objects */
LoadObjects(void)192 static void LoadObjects(void)
193 {
194     glGenBuffers(OBJECT_COUNT * 2, (GLuint*)&s_Object);
195 
196     LoadSphere();
197     LoadPlane();
198 }
199 
DrawFrame(void)200 int DrawFrame(void)
201 {
202     static int f = 0;
203     nn::math::Matrix44 proj;
204     nn::math::Matrix34 mv;
205 
206     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
207     s_RenderSystem.Clear();
208 
209     /* In this application light positions are specified in object coordinates.
210      * */
211     GLfloat lpos[] = {3.f, 3.f, 0.f, 1.f};      /* light position */
212 
213     /* Projection settings */
214     nn::math::MTX44Frustum(&proj, -0.07f, 0.07f, -0.07f * nn::gx::DISPLAY0_HEIGHT / nn::gx::DISPLAY0_WIDTH,
215                  0.07f * nn::gx::DISPLAY0_HEIGHT / nn::gx::DISPLAY0_WIDTH, 0.2f, 200.f);
216     glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uProjection"), 1, GL_TRUE, static_cast<f32*>(proj));
217 
218     /* modelview setting */
219     /* mv indicates the view matrix.*/
220     nn::math::MTX34RotXYZDeg(&mv, 0.0f, 0.0f, -90.0f);
221     nn::math::Matrix34 cam;
222     nn::math::Vector3 camPos(0.f, 5.f, 10.f);
223     nn::math::Vector3 camUp(0.f, 1.f, 0.f);
224     nn::math::Vector3 target(0.f, 0.f, 0.f);
225     nn::math::MTX34LookAt(&cam, &camPos, &camUp, &target);
226     nn::math::MTX34Mult(&mv, &mv, &cam);
227     nn::math::Matrix44 tmp(mv);
228     glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, static_cast<f32*>(tmp));
229 
230     /* set light position */
231     /* constant light position is transformed from object-space to eye-space */
232     /* The vertex shader assumes that the eye coordinate system is used for lighting calculations.
233      * The light's position is therefore converted to the eye coordinate system. The shader does not perform conversion.
234      * This is because lights use common values in all vertex processing.
235      * mv is the view matrix. Multiplication by this matrix converts coordinates to the eye coordinate system.*/
236     nn::math::Vector4 p(lpos);
237     nn::math::Vector4 mvv0(mv.m[0]);
238     nn::math::Vector4 mvv1(mv.m[1]);
239     nn::math::Vector4 mvv2(mv.m[2]);
240     nn::math::Vector4 lpos2( nn::math::VEC4Dot(&mvv0, &p), nn::math::VEC4Dot(&mvv1, &p), nn::math::VEC4Dot(&mvv2, &p), 1.f);
241 
242     glUniform4fv(glGetUniformLocation(s_PgID, "uLightPos"), 1, static_cast<f32*>(lpos2));
243 
244     /* draw objects */
245     for (int i = 0; i < OBJECT_COUNT; i++)
246     {
247         glBindBuffer(GL_ARRAY_BUFFER, s_Object.id[i]);
248         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
249         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(GLfloat) * 3 * s_ObjectInfo.vtxcnt[i]));
250         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_Object.idxId[i]);
251 
252         if (i == OBJECT_SPHERE) /* for sphere */
253         {
254             /* Rotation and translation are contributed to the current model view matrix (mv) only when a sphere model is used, resulting in mv2. The model view matrix returns to its original state (mv1) when rendering is complete.
255              *
256              * This is equivalent to the glPushMatrix and glPopMatrix operations in OpenGL ES 1.1.*/
257             nn::math::Matrix34 arr[2];
258             nn::math::Matrix34 mv2;
259             nn::math::Vector3 trans(2.0f, 0.f, 0.f);
260             nn::math::MTX34RotXYZDeg(&arr[0], 0.f, STEP * f / 2, 0.f);
261             nn::math::MTX34Translate(&arr[1], &trans);
262             nn::math::MTX34Mult(&mv2, &mv, &arr[0]);
263             nn::math::MTX34Mult(&mv2, &mv2, &arr[1]);
264             nn::math::Matrix44 tmp2(mv2);
265             glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, static_cast<f32*>(tmp2));
266         }
267 
268         glDrawElements(GL_TRIANGLE_STRIP, s_ObjectInfo.idxcnt[i], GL_UNSIGNED_SHORT,(GLvoid*)0);
269 
270         if (i == OBJECT_SPHERE) /* for sphere */
271         {
272             /* Returns the model view matrix to its original state. (mv) */
273             glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, static_cast<f32*>(tmp));
274         }
275     }
276     glFinish();
277 
278     s_RenderSystem.SwapBuffers();
279 
280     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
281     s_RenderSystem.Clear();
282     s_RenderSystem.SwapBuffers();
283 
284     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
285 
286     f++;
287 
288     return !glGetError();
289 }
290 
291 /* initialization */
Initialize(void)292 static int Initialize(void)
293 {
294     // fs initialization
295     nn::fs::Initialize();
296 
297     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
298     static char buffer[ROMFS_BUFFER_SIZE];
299     NN_UTIL_PANIC_IF_FAILED(
300         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
301 
302     s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() );
303     s_HeapForGx = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
304     /* Initialize display */
305     s_RenderSystem.Initialize(s_HeapForGx, s_GxHeapSize);
306 
307     /* setup vertex shader */
308     /* The shader setup process with DMPGL2.0 uses the same mechanism as OpenGLES2.0.
309      * Because in DMPGL 2.0 only the vertex shader can be user-defined, only one shader object is created.
310      *
311      * */
312     s_PgID = glCreateProgram();
313     s_ShID = glCreateShader(GL_VERTEX_SHADER);
314 
315     nn::fs::FileReader file(L"rom:/shader.shbin");
316     size_t fileSize = file.GetSize();
317     void* buf = s_AppHeap.Allocate(fileSize);
318 
319     s32 read = file.Read(buf, fileSize);
320     glShaderBinary(1, &s_ShID, GL_PLATFORM_BINARY_DMP, buf, read);
321     file.Finalize();
322     s_AppHeap.Free(buf);
323 
324     glAttachShader(s_PgID, s_ShID);
325     /* The GL_DMP_FRAGMENT_SHADER_DMP shader object is the shader object of the fragment shader reserved with DMPGL2.0.
326      * */
327     glAttachShader(s_PgID, GL_DMP_FRAGMENT_SHADER_DMP);
328 
329     /* Because the shader program performs coordinate conversions and lighting calculations, vertex coordinates and normals are required as vertex attributes, and the vertex coordinates are allocated to attribute0 and the normals are allocated to attribute1.
330      *
331      * */
332     glBindAttribLocation(s_PgID, 0, "aPosition");
333     glBindAttribLocation(s_PgID, 1, "aNormal");
334 
335     /* Links the vertex shader and fragment shader.*/
336     glLinkProgram(s_PgID);
337 
338     glValidateProgram(s_PgID);
339     glUseProgram(s_PgID);
340 
341     glClearColor(0.36f, 0.42f, 0.5f, 1.0f);
342     glClearDepthf(1.f);
343 
344     glEnableVertexAttribArray(0);
345     glEnableVertexAttribArray(1);
346 
347     glEnable(GL_DEPTH_TEST);
348     glDepthFunc(GL_LESS);
349 
350     glEnable(GL_CULL_FACE);
351     glFrontFace(GL_CCW);
352     glCullFace(GL_BACK);
353 
354     LoadObjects();
355 
356     /* The following parameters are the same as the OpenGLES1.1 vertex lighting parameters.
357      *
358      * Note that the result of multiplying the same light and material components together is set in the shader Uniform.
359      * */
360     GLfloat ldif[] = {1.f, 1.f, 1.f, 1.f};      /* light diffuse */
361     GLfloat lspc[] = {1.f, 1.f, 1.f, 1.f};      /* light specular */
362     GLfloat lamb[] = {0.f, 0.f, 0.f, 1.f};      /* light ambient */
363     GLfloat lmamb[] = {0.2f, 0.2f, 0.f, 1.f};   /* light model ambient */
364 
365     GLfloat mspc[] = {1.f, 1.f, 1.f, 1.f};      /* material specular */
366     GLfloat mdif[] = {0.8f, 0.8f, 0.f, 1.f};    /* material diffuse */
367     GLfloat mamb[] = {0.8f, 0.f, 0.f, 1.f};     /* material ambient */
368 
369     /* Set the sum of the light ambient and global ambient as ambient.
370      * */
371     nn::math::Vector4 amb;
372     nn::math::Vector4 lamb_mamb  = nn::math::Vector4(lamb[0]*mamb[0], lamb[1]*mamb[1], lamb[2]*mamb[2], lamb[3]*mamb[3]);
373     nn::math::Vector4 lmamb_mamb = nn::math::Vector4(lmamb[0]*mamb[0], lmamb[1]*mamb[1], lmamb[2]*mamb[2], lmamb[3]*mamb[3]);
374     nn::math::VEC4Add(&amb, &lamb_mamb, &lmamb_mamb);
375 
376     nn::math::Vector4 dif = nn::math::Vector4(ldif[0]*mdif[0], ldif[1]*mdif[1], ldif[2]*mdif[2], ldif[3]*mdif[3]);
377     nn::math::Vector4 spc = nn::math::Vector4(lspc[0]*mspc[0], lspc[1]*mspc[1], lspc[2]*mspc[2], lspc[3]*mspc[3]);
378     GLfloat a[] = {amb.x, amb.y, amb.z, amb.w};
379     GLfloat d[] = {dif.x, dif.y, dif.z, dif.w};
380     GLfloat s[] = {spc.x, spc.y, spc.z, spc.w};
381 
382     glUniform4fv(glGetUniformLocation(s_PgID, "uDiff"), 1, d);
383     glUniform4fv(glGetUniformLocation(s_PgID, "uAmb"), 1, a);
384     glUniform4fv(glGetUniformLocation(s_PgID, "uSpec"), 1, s);
385     glUniform1f(glGetUniformLocation(s_PgID, "uMatShiniess"), SPEC_SHININESS);
386 
387     glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].srcRgb"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR);
388     glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].srcAlpha"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR);
389 
390     return 0;
391 }
392 
nnMain(void)393 void nnMain(void)
394 {
395     // Call only nn::applet::Enable to also allow execution from the HOME Menu
396     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
397     nn::applet::Enable();
398 
399     /* initialization */
400     if (Initialize() >= 0)
401     {
402         while (1)
403         {
404             (void)DrawFrame();
405         }
406     }
407 
408     /* shutdown_display */
409     s_RenderSystem.Finalize();
410     s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForGx));
411     s_AppHeap.Finalize();
412 }
413