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