1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     graphics.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: 46365 $
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.h>
27 #include <nn/math.h>
28 #include <nn/fs.h>
29 #include <nn/ulcd.h>
30 #include "graphics.h"
31 #include "snd.h"
32 
33 #include "demo.h"
34 
35 /* program id */
36 GLuint s_PgID;
37 
38 /* shader id */
39 GLuint s_ShID;
40 
41 /* OpenGLES1.1 vertex lighting specular shininess */
42 #define SPEC_SHININESS  32.f
43 #define STEP 6.f
44 
45 /* object names */
46 enum {
47     OBJECT_SPHERE,  /* sphere */
48     OBJECT_PLANE,   /* plane */
49     OBJECT_COUNT    /* object count */
50 };
51 
52 /* buffer object ID */
53 static struct tagObject
54 {
55     GLuint id[OBJECT_COUNT];
56     GLuint idxId[OBJECT_COUNT];
57 } s_Object;
58 
59 /* buffer object information */
60 static struct tagObjectInfo
61 {
62     GLushort idxcnt[OBJECT_COUNT];
63     GLushort vtxcnt[OBJECT_COUNT];
64 } s_ObjectInfo;
65 
66 
67 #define ROW_NUM     (50)    /* NUM in ROW */
68 #define COL_NUM     (50)    /* NUM in COLUMN */
69 #define deltaROW    (DMP_PI / (ROW_NUM - 1))
70 #define deltaCOL    (2 * DMP_PI / (COL_NUM - 1))
71 
72 struct tagVertex{
73     GLfloat pos[ROW_NUM * COL_NUM][3];
74     GLfloat nor[ROW_NUM * COL_NUM][3];
75 } s_Vtx;
76 GLushort s_Idx[COL_NUM * (ROW_NUM - 1) * 2];
77 
78 /* ExpHeap for app. */
79 extern nn::fnd::ExpHeap s_AppHeap;
80 uptr s_HeapForGx;
81 const u32 s_GxHeapSize = 0x800000;
82 
83 /* Render system */
84 demo::RenderSystemExt       s_RenderSystem;
85 void* s_pShader;
86 
87 /* 3D view */
88 nn::ulcd::CTR::StereoCamera s_StereoCamera;
89 const f32 DEMO2_3D_DEPTH_LEVEL = 10.0f;
90 const f32 DEMO2_3D_FACTOR = 1.0f;
91 
92 
93 /* load sphere object */
LoadSphere(void)94 static void LoadSphere(void)
95 {
96     /* vertex array */
97     for(int row = 0; row < ROW_NUM; row++)
98     {
99         for(int col = 0; col < COL_NUM; col++)
100         {
101             /* position */
102             s_Vtx.pos[row * COL_NUM + col][0] =0.5f * (GLfloat)nn::math::SinRad(deltaROW * row) * nn::math::CosRad(deltaCOL * col);
103             s_Vtx.pos[row * COL_NUM + col][1] =0.5f * (GLfloat)nn::math::CosRad(deltaROW * row);
104             s_Vtx.pos[row * COL_NUM + col][2] =0.5f * (GLfloat)nn::math::SinRad(deltaROW * row) * nn::math::SinRad(deltaCOL * col);
105             /* normal */
106             s_Vtx.nor[row * COL_NUM + col][0] =0.5f * (GLfloat)nn::math::SinRad(deltaROW * row) * nn::math::CosRad(deltaCOL * col);
107             s_Vtx.nor[row * COL_NUM + col][1] =0.5f * (GLfloat)nn::math::CosRad(deltaROW * row);
108             s_Vtx.nor[row * COL_NUM + col][2] =0.5f * (GLfloat)nn::math::SinRad(deltaROW * row) * nn::math::SinRad(deltaCOL * col);
109         }
110     }
111 
112     /* index array */
113     for(int i = 0, row = 0; row < ROW_NUM - 1; row++)
114     {
115     #define __INDEX(ROW, COL)   ((ROW) * COL_NUM + (COL))
116         for(int col = 0; col < COL_NUM; col++)
117         {
118             s_Idx[i++] = __INDEX(row + 1, col);
119             s_Idx[i++] = __INDEX(row, col);
120         }
121     #undef __INDEX
122     }
123     /* count */
124     s_ObjectInfo.idxcnt[OBJECT_SPHERE] = COL_NUM * (ROW_NUM - 1) * 2;
125     s_ObjectInfo.vtxcnt[OBJECT_SPHERE] = ROW_NUM * COL_NUM;
126 
127     /* load vertex array and index array */
128     glBindBuffer(GL_ARRAY_BUFFER, s_Object.id[OBJECT_SPHERE]);
129     glBufferData(GL_ARRAY_BUFFER, sizeof(s_Vtx), &s_Vtx, GL_STATIC_DRAW);
130     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_Object.idxId[OBJECT_SPHERE]);
131     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(s_Idx), s_Idx, GL_STATIC_DRAW);
132 
133 
134 #undef LONG_NUM
135 #undef LATI_NUM
136 #undef deltaROW
137 #undef deltaCOL
138 }
139 
140 /* load plane object */
LoadPlane(void)141 static void LoadPlane(void)
142 {
143     struct tagVertex{
144         GLfloat pos[4][3];
145         GLfloat nor[4][3];
146     } vtx;
147     GLushort idx[4] ={0, 1, 2, 3};
148 
149     /* vertex array */
150     vtx.pos[0][0] = +4.0f;
151     vtx.pos[0][1] = 0.f;
152     vtx.pos[0][2] = +4.0f;
153 
154     vtx.pos[1][0] = +4.0f;
155     vtx.pos[1][1] = 0.f;
156     vtx.pos[1][2] = -4.0f;
157 
158     vtx.pos[2][0] = -4.0f;
159     vtx.pos[2][1] = 0.f;
160     vtx.pos[2][2] = +4.0f;
161 
162     vtx.pos[3][0] = -4.0f;
163     vtx.pos[3][1] = 0.f;
164     vtx.pos[3][2] = -4.0f;
165 
166     for(int i = 0; i < 4; i++)
167     {
168         vtx.nor[i][0] = 0.f;
169         vtx.nor[i][1] = 1.f;
170         vtx.nor[i][2] = 0.f;
171     }
172 
173     /* count */
174     s_ObjectInfo.idxcnt[OBJECT_PLANE] = 4;
175     s_ObjectInfo.vtxcnt[OBJECT_PLANE] = 4;
176 
177     /* load vertex array and index array */
178     glBindBuffer(GL_ARRAY_BUFFER, s_Object.id[OBJECT_PLANE]);
179     glBufferData(GL_ARRAY_BUFFER, sizeof(vtx), vtx.pos[0], GL_STATIC_DRAW);
180     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_Object.idxId[OBJECT_PLANE]);
181     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW);
182 }
183 
184 /* load objects */
LoadObjects(void)185 static void LoadObjects(void)
186 {
187     glGenBuffers(OBJECT_COUNT * 2, (GLuint*)&s_Object);
188 
189     LoadSphere();
190     LoadPlane();
191 }
192 
UpdateParams(nn::math::VEC3 * v_pos,nn::math::VEC2 * v_degSphere,nn::math::VEC2 * v_deg,const nn::math::VEC3 v_cam,const nn::math::VEC3 v_focus,const nn::math::VEC2 v_acc,const u8 loudness)193 static void UpdateParams(
194                  nn::math::VEC3* v_pos,         // Sphere position (output)
195                  nn::math::VEC2* v_degSphere,   // Slope of plane when sphere is on a plane (output)
196                  nn::math::VEC2* v_deg,         // Plane slope (output)
197                  const nn::math::VEC3 v_cam,    // Camera position
198                  const nn::math::VEC3 v_focus,  // Focus position
199                  const nn::math::VEC2 v_acc,    // Accelerometer
200                  const u8 loudness)             // Mic volume
201 {
202     /*
203      * About Coordinates (initial position)
204      * x: To the right direction on the horizontal plane
205      * y: Up in the vertical direction
206      * z: Down direction on the horizontal plane
207      */
208     const f32 SPEED = 0.05f;            // Parameters for moving speed of the sphere
209     static nn::math::VEC3 v_v(0, 0, 0);           // Sphere speed
210     nn::math::VEC3 v_g(v_acc.x, -1.f, v_acc.y);   // Gravitational acceleration
211 
212     // Calculate the plane's incline
213     if(v_g.x > 1.f)         v_g.x =  1.f;
214     else if(v_g.x < -1.f)   v_g.x = -1.f;
215     if(v_g.z > 1.f)         v_g.z =  1.f;
216     else if(v_g.z < -1.f)   v_g.z = -1.f;
217     v_deg->x = nn::math::AsinDeg(v_g.x);          // Incline of x-axis
218     v_deg->y = nn::math::AsinDeg(v_g.z);          // Incline of z-axis
219 
220     // Calculate acceleration with the microphone
221     const f32 MIC_STRENGTH = 0.25f;     // Parameter for the effect from the microphone volume
222     f32 micAcc = loudness * MIC_STRENGTH;
223     nn::math::VEC3 v_f(v_focus - v_cam);          // Focus vector from camera
224     nn::math::VEC3 v_s(*v_pos - v_cam);           // Vector from camera to sphere
225     if( nn::math::VEC3Dot(&v_f, &v_s) > 0 )
226     {
227         // When the direction from the camera to the focus and to the sphere are the same
228         // Vector normalization
229         nn::math::VEC3Normalize(&v_f, &v_f);
230         nn::math::VEC3Normalize(&v_s, &v_s);
231         // Calculate effect on sphere by microphone
232         micAcc *= nn::math::VEC3Dot(&v_f, &v_s) / nn::math::VEC3Len(*v_pos - v_cam);
233         nn::math::VEC3Scale(&v_s, &v_s, micAcc);
234     }
235     else
236     {
237         // When the direction from the camera to the focus and to the sphere are the opposite
238         nn::math::VEC3Scale(&v_s, &v_s, 0);
239     }
240 
241     if(v_pos->x > -4.f && v_pos->x < 4.f && v_pos->z > -4.f && v_pos->z < 4.f)
242     {
243         // When the sphere is on the plane, ignore speed in y-axis direction
244         //
245         v_g.y = 0;
246         v_s.y = 0;
247         v_v += (v_g + v_s) * SPEED;
248         *v_pos += v_v;
249         v_degSphere->x = v_deg->x;
250         v_degSphere->y = v_deg->y;
251     }
252     else if( v_pos->y > -50.f )
253     {
254         // When the sphere is falling
255         v_v.y += v_g.y * SPEED;
256         *v_pos += v_v;
257 
258         PlaySound();
259     }
260     else
261     {
262         // Reset sphere position
263         v_pos->x = 0.f;
264         v_pos->y = 0.f;
265         v_pos->z = 0.f;
266         v_v.x   = 0.f;
267         v_v.y   = 0.f;
268         v_v.z   = 0.f;
269 
270         StopSound();
271     }
272 }
273 
DrawObjects(const nn::math::Matrix44 & proj,const nn::math::Matrix34 & view,const nn::math::VEC3 v_pos,const nn::math::VEC2 v_degSphere,const nn::math::VEC2 v_deg,f32 posYforSphere)274 void DrawObjects(
275     const nn::math::Matrix44& proj,
276     const nn::math::Matrix34& view,
277     const nn::math::VEC3 v_pos,
278     const nn::math::VEC2 v_degSphere,
279     const nn::math::VEC2 v_deg,
280     f32   posYforSphere
281 )
282 {
283     glUseProgram(s_PgID);
284     glBindAttribLocation(s_PgID, 0, "aPosition");
285     glBindAttribLocation(s_PgID, 1, "aNormal");
286 
287     glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uProjection"), 1, GL_TRUE, static_cast<const f32*>(proj));
288 
289     /* set light position */
290     GLfloat lpos[] = {3.f, 3.f, 0.f, 1.f};      /* Light position */
291     /* constant light position is transformed from object-space to eye-space */
292     /* Lighting calculations in the vertex shader assume view coordinates system.
293      * For this reason, the light position is converted to view coordinates system. The shader does not perform conversion.
294      * This is because common values are used for lights in all vertex processing.
295      * mv is the view matrix, and multiplication by this matrix converts to view coordinates system.*/
296     nn::math::Vector4 p(lpos);
297     nn::math::Vector4 mvv0(view.m[0]);
298     nn::math::Vector4 mvv1(view.m[1]);
299     nn::math::Vector4 mvv2(view.m[2]);
300     nn::math::Vector4 lpos2( VEC4Dot(&mvv0, &p), VEC4Dot(&mvv1, &p), VEC4Dot(&mvv2, &p), 1.f);
301 
302     glUniform4fv(glGetUniformLocation(s_PgID, "uLightPos"), 1, static_cast<f32*>(lpos2));
303 
304     /* draw objects */
305     for (int i = 0; i < OBJECT_COUNT; i++)
306     {
307         glBindBuffer(GL_ARRAY_BUFFER, s_Object.id[i]);
308         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
309         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(GLfloat) * 3 * s_ObjectInfo.vtxcnt[i]));
310         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_Object.idxId[i]);
311 
312         if (i == OBJECT_SPHERE) /* for sphere */
313         {
314             nn::math::Matrix34 arr[3];
315             nn::math::Matrix34 mv2;
316             nn::math::Vector3 trans(v_pos.x, posYforSphere, v_pos.z);
317             nn::math::Vector3 fall(0.f, v_pos.y, 0.f);
318             nn::math::MTX34Translate(&arr[0], &trans);
319             nn::math::MTX34RotXYZDeg(&arr[1], v_degSphere.y, 0.f, -v_degSphere.x);
320             nn::math::MTX34Translate(&arr[2], &fall);
321             nn::math::MTX34Mult(&mv2, &view, &arr[2]);
322             nn::math::MTX34Mult(&mv2, &mv2, &arr[1]);
323             nn::math::MTX34Mult(&mv2, &mv2, &arr[0]);
324             nn::math::Matrix44 tmp2(mv2);
325             glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, static_cast<f32*>(tmp2));
326         }
327         else if(i == OBJECT_PLANE) /* for plane */
328         {
329             nn::math::Matrix34 arr;
330             nn::math::Matrix34 mv2;
331             nn::math::MTX34RotXYZDeg(&arr, v_deg.y, 0.f, -v_deg.x);
332             nn::math::MTX34Mult(&mv2, &view, &arr);
333             nn::math::Matrix44 tmp2(mv2);
334             glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, static_cast<f32*>(tmp2));
335         }
336 
337         glDrawElements(GL_TRIANGLE_STRIP, s_ObjectInfo.idxcnt[i], GL_UNSIGNED_SHORT,(GLvoid*)0);
338     }
339     glFinish();
340 }
341 
DrawFrame(nn::math::VEC3 v_cam,nn::math::VEC3 v_focus,nn::math::VEC2 v_acc,u8 loudness)342 int DrawFrame(nn::math::VEC3 v_cam, nn::math::VEC3 v_focus, nn::math::VEC2 v_acc, u8 loudness)
343 {
344     /*
345      * About Coordinates (initial position)
346      * x: To the right direction on the horizontal plane
347      * y: Up in the vertical direction
348      * z: Down direction on the horizontal plane
349      */
350     const f32 posYforSphere = 0.5f;               // Sphere y-axis position correction parameter
351     static nn::math::VEC3 v_pos(0, 0, 0);         // Sphere position
352     static nn::math::VEC2 v_degSphere(0, 0);      // Slope of plane when sphere is on a plane
353     nn::math::VEC2 v_deg(0, 0);                   // Plane slope
354 
355     // Update render parameters
356     UpdateParams(&v_pos, &v_degSphere, &v_deg, v_cam, v_focus, v_acc, loudness);
357 
358 
359     // Lower screen display
360     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
361     s_RenderSystem.Clear();
362 
363     // Display current time
364     nn::fnd::DateTime now = nn::fnd::DateTime::GetNow();
365     s_RenderSystem.SetColor(1.0f, 1.0f, 1.0f, 1.0f);
366     s_RenderSystem.DrawText(0, 0, "CTR demo2");
367     s_RenderSystem.DrawText(0, 16, "%04d/%02d/%02d %02d:%02d:%02d", now.GetYear(), now.GetMonth(), now.GetDay(), now.GetHour(), now.GetMinute(), now.GetSecond());
368 
369     s_RenderSystem.Transfer();
370     s_RenderSystem.SwapBuffers();
371 
372 
373     /* Projection settings */
374     s_StereoCamera.SetBaseFrustum(-0.07f * HEIGHT / WIDTH, 0.07f * HEIGHT / WIDTH, -0.07f, 0.07f, 0.2f, 200.f);
375 
376     /* modelview setting */
377     /* mv indicates the view matrix.*/
378     nn::math::Matrix34 cam;
379     nn::math::Vector3 camUp(0.f, 1.f, 0.f);
380     nn::math::MTX34LookAt(&cam, &v_cam, &camUp, &v_focus);
381 
382     // Calculate the view matrix and projection matrix for rendering the image that corresponds to the left and right parallax
383     nn::math::Matrix44 projL, projR;
384     nn::math::Matrix34 viewL, viewR;
385 
386     s_StereoCamera.SetBaseCamera(&cam);
387     s_StereoCamera.CalculateMatrices(
388         &projL, &viewL, &projR, &viewR,
389         DEMO2_3D_DEPTH_LEVEL,
390         DEMO2_3D_FACTOR,
391         nn::math::PIVOT_UPSIDE_TO_TOP
392     );
393 
394     // Display upper screen (left)
395     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
396     s_RenderSystem.Clear();
397 
398     DrawObjects(projL, viewL, v_pos, v_degSphere, v_deg, posYforSphere);
399     s_RenderSystem.Transfer();
400 
401     // Display upper screen (right)
402     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0_EXT);
403     s_RenderSystem.Clear();
404 
405     DrawObjects(projR, viewR, v_pos, v_degSphere, v_deg, posYforSphere);
406     s_RenderSystem.Transfer();
407 
408     s_RenderSystem.SwapBuffers();
409 
410     /* it is possible to save the content of the buffer */
411     /*
412     char fname[256];
413     sprintf(fname, "frame-%04d.tga", f);
414     outputImage(WIDTH, HEIGHT, fname);
415     */
416 
417     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
418 
419     return !glGetError();
420 }
421 
422 /* initialization */
InitializeGraphics(void)423 int InitializeGraphics(void)
424 {
425     s_HeapForGx = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
426 
427     /* Initialize display */
428     s_RenderSystem.Initialize(s_HeapForGx, s_GxHeapSize);
429 
430     s_StereoCamera.Initialize();
431 
432     /* setup vertex shader */
433     /* The shader setup process with DMPGL2.0 uses the same mechanism as OpenGLES2.0.
434      *
435      * Because only the vertex shader can be created as user-defined with DMPGL2.0, only one shader object is created.
436      * */
437     s_PgID = glCreateProgram();
438     s_ShID = glCreateShader(GL_VERTEX_SHADER);
439 
440     // Load shader binary with file system
441     nn::fs::FileReader shaderReader(L"rom:/shader.shbin");
442     size_t size = shaderReader.GetSize();
443     s_pShader = s_AppHeap.Allocate(size);
444     s32 read = shaderReader.Read(s_pShader, size);
445     NN_ASSERT(read == size);
446     glShaderBinary(1, &s_ShID, GL_PLATFORM_BINARY_DMP, s_pShader, read);
447 
448     glAttachShader(s_PgID, s_ShID);
449     /* The GL_DMP_FRAGMENT_SHADER_DMP shader object is the shader object of the fragment shader reserved with DMPGL2.0.
450      * */
451     glAttachShader(s_PgID, GL_DMP_FRAGMENT_SHADER_DMP);
452 
453     /* 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.
454      *
455      * */
456     glBindAttribLocation(s_PgID, 0, "aPosition");
457     glBindAttribLocation(s_PgID, 1, "aNormal");
458 
459     /* Links the vertex shader and fragment shader.*/
460     glLinkProgram(s_PgID);
461 
462     glValidateProgram(s_PgID);
463     glUseProgram(s_PgID);
464 
465     s_RenderSystem.SetClearColor(NN_GX_DISPLAY0, 0.36f, 0.42f, 0.5f, 1.0f);
466     s_RenderSystem.SetClearColor(NN_GX_DISPLAY1, 0.f, 0.f, 0.f, 1.0f);
467 
468     glClearDepthf(1.f);
469 
470     glEnableVertexAttribArray(0);
471     glEnableVertexAttribArray(1);
472 
473     glEnable(GL_DEPTH_TEST);
474     glDepthFunc(GL_LESS);
475 
476     glEnable(GL_CULL_FACE);
477     glFrontFace(GL_CCW);
478     glCullFace(GL_BACK);
479 
480     LoadObjects();
481 
482     /* The following parameters are the same as the OpenGLES1.1 vertex lighting parameters.
483      *
484      * Note that product of multiplying the same components of lights and materials is set in the shader Uniform.
485      * */
486     GLfloat ldif[] = {1.f, 1.f, 1.f, 1.f};      /* light diffuse */
487     GLfloat lspc[] = {1.f, 1.f, 1.f, 1.f};      /* light specular */
488     GLfloat lamb[] = {0.f, 0.f, 0.f, 1.f};      /* light ambient */
489     GLfloat lmamb[] = {0.2f, 0.2f, 0.f, 1.f};   /* light model ambient */
490 
491     GLfloat mspc[] = {1.f, 1.f, 1.f, 1.f};      /* material specular */
492     GLfloat mdif[] = {0.8f, 0.8f, 0.f, 1.f};    /* material diffuse */
493     GLfloat mamb[] = {0.8f, 0.f, 0.f, 1.f};     /* material ambient */
494 
495     /* Set the sum of the light ambient and global ambient as ambient.
496      * */
497     nn::math::Vector4 amb;
498     nn::math::Vector4 lamb_mamb  = nn::math::VEC4(lamb[0]*mamb[0], lamb[1]*mamb[1], lamb[2]*mamb[2], lamb[3]*mamb[3]);
499     nn::math::Vector4 lmamb_mamb = nn::math::VEC4(lmamb[0]*mamb[0], lmamb[1]*mamb[1], lmamb[2]*mamb[2], lmamb[3]*mamb[3]);
500     nn::math::VEC4Add(&amb, &lamb_mamb, &lmamb_mamb);
501 
502     nn::math::Vector4 dif = nn::math::VEC4(ldif[0]*mdif[0], ldif[1]*mdif[1], ldif[2]*mdif[2], ldif[3]*mdif[3]);
503     nn::math::Vector4 spc = nn::math::VEC4(lspc[0]*mspc[0], lspc[1]*mspc[1], lspc[2]*mspc[2], lspc[3]*mspc[3]);
504     GLfloat a[] = {amb.x, amb.y, amb.z, amb.w};
505     GLfloat d[] = {dif.x, dif.y, dif.z, dif.w};
506     GLfloat s[] = {spc.x, spc.y, spc.z, spc.w};
507 
508     glUniform4fv(glGetUniformLocation(s_PgID, "uDiff"), 1, d);
509     glUniform4fv(glGetUniformLocation(s_PgID, "uAmb"), 1, a);
510     glUniform4fv(glGetUniformLocation(s_PgID, "uSpec"), 1, s);
511     glUniform1f(glGetUniformLocation(s_PgID, "uMatShiniess"), SPEC_SHININESS);
512 
513     glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].srcRgb"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR);
514     glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].srcAlpha"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR);
515 
516     s_RenderSystem.SetLcdMode(NN_GX_DISPLAYMODE_STEREO);
517 
518     return 0;
519 }
520 
FinalizeGraphics(void)521 int FinalizeGraphics(void)
522 {
523     /* shutdown_display */
524     s_RenderSystem.Finalize();
525     s_AppHeap.Free(s_pShader);
526     s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForGx));
527 
528     return 0;
529 }
530 
531 /*---------------------------------------------------------------------------*
532   End of file
533  *---------------------------------------------------------------------------*/
534