1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     gx_VertexBuffer.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 #include <nn/os.h>
17 #include <nn/fnd.h>
18 #include <nn/gx.h>
19 #include <nn/math.h>
20 #include <nn/fs.h>
21 #include <nn/init.h>
22 #include <nn/applet.h>
23 
24 #include "demo.h"
25 
26 namespace
27 {
28     // Specify whether the vertex buffer and the index buffer are copied into main memory as well as whether they are allocated in main memory, VRAMA, or VRAMB.
29     //
30     //
31     //
32     enum
33     {
34         // (a) When there is a copy to main memory and when PICA accesses the copy in main memory
35         USE_VBO_MEM_MAIN_COPY = 0,
36 
37         // (b) When there is no copy in main memory and PICA directly accesses main memory
38         USE_VBO_MEM_MAIN_NO_COPY,
39 
40         // (c) When there is a copy in main memory and PICA accesses VRAMA
41         //     Sends data from the copy in main memory to VRAMA using DMA transfer, and PICA accesses that VRAMA.
42         USE_VBO_VRAMA_COPY,
43 
44         // (d) When there is no copy in main memory and PICA accesses VRAMA
45         //     Sends data from main memory to VRAMA using DMA transfer, and PICA accesses that VRAMA.
46         USE_VBO_VRAMA_NO_COPY,
47 
48         // (e) When there is a copy in main memory and PICA accesses VRAMB
49         //     Sends data from the copy in main memory to VRAMB using DMA transfer, and PICA accesses that VRAMB.
50         USE_VBO_VRAMB_COPY,
51 
52         // (f) When there is no copy in main memory and PICA accesses VRAMB
53         //     Sends data from main memory to VRAMB using DMA transfer, and PICA accesses that VRAMB.
54         USE_VBO_VRAMB_NO_COPY
55     };
56 
57     u32 s_VertexBufferPattern = USE_VBO_MEM_MAIN_COPY;
58     // u32 s_VertexBufferPattern = USE_VBO_MEM_MAIN_NO_COPY;
59     // u32 s_VertexBufferPattern = USE_VBO_VRAMA_COPY;
60     // u32 s_VertexBufferPattern = USE_VBO_VRAMA_NO_COPY;
61     // u32 s_VertexBufferPattern = USE_VBO_VRAMB_COPY;
62     // u32 s_VertexBufferPattern = USE_VBO_VRAMB_NO_COPY;
63 
64     GLenum s_ArrayBufferDataType = GL_ARRAY_BUFFER;
65     GLenum s_ElementArrayBufferDataType = GL_ELEMENT_ARRAY_BUFFER;
66 
67     GLuint s_ProgramId = 0;
68     GLuint s_ShaderId = 0;
69 
70     nn::fnd::ExpHeap s_AppHeap;
71     uptr s_AddrForGxHeap;
72     const u32 s_GxHeapSize = 0x400000;
73 
74     demo::RenderSystem s_RenderSystem;
75 
76     nn::math::Vector3 s_CameraPosition(0.0f, 2.0f, 2.0f);
77     nn::math::Vector3 s_CameraUp(0.0f, 1.0f, 0.0f);
78     nn::math::Vector3 s_CameraTarget(0.0f, 0.0f, 0.0f);
79 
80     nn::math::Matrix34 s_ViewMatrix;
81     nn::math::Matrix44 s_Display0ProjectionMatrix;
82     nn::math::Matrix44 s_Display1ProjectionMatrix;
83 
84     f32 s_GlobalAmbientLight[] = { 0.3f,  0.3f,  0.3f, 1.0f};
85     f32 s_Light0Ambient[]      = { 0.3f,  0.3f,  0.3f, 1.0f};
86     f32 s_Light0Diffuse[]      = { 0.7f,  0.7f,  0.7f, 1.0f};
87     f32 s_Light0Position[]     = { 10.0f,  10.0f,  10.0f, 1.0f};
88 
89     f32 s_MaterialAmbient[] = {0.3f, 0.3f, 0.3f, 1.0f};
90     f32 s_MaterialDiffuse[] = {0.7f, 0.7f, 0.7f, 1.0f};
91 
92     const u32 VERTEX_POSITION_ATTRIBUTE_INDEX = 0;
93     const u32 VERTEX_COLOR_ATTRIBUTE_INDEX    = 1;
94     const u32 VERTEX_NORMAL_ATTRIBUTE_INDEX   = 2;
95     const u32 VERTEX_ATTRIBUTES_NUM           = 3;
96 
97     const u32 VERTEX_POSITION_ATTRIBUTE_SIZE = 4;
98     const u32 VERTEX_COLOR_ATTRIBUTE_SIZE    = 4;
99     const u32 VERTEX_NORMAL_ATTRIBUTE_SIZE   = 3;
100 
101     const u32 s_VerticesNum       = 24;
102     const u32 s_TrianglesNum      = 12;
103     const u32 s_PositionArraySize = s_VerticesNum * VERTEX_POSITION_ATTRIBUTE_SIZE * 4;
104     const u32 s_ColorArraySize    = s_VerticesNum * VERTEX_COLOR_ATTRIBUTE_SIZE * 4;
105     const u32 s_NormalArraySize   = s_VerticesNum * VERTEX_NORMAL_ATTRIBUTE_SIZE * 4;
106     const u32 s_IndexArraySize    = s_TrianglesNum * 3 * 2;
107 
108     GLfloat* s_PositionArray = NULL;
109     GLfloat* s_ColorArray    = NULL;
110     GLfloat* s_NormalArray   = NULL;
111     GLushort* s_IndexArray   = NULL;
112 
113     GLuint s_ArrayBufferIdArray[3];
114     GLuint s_ElementArrayBufferId = 0;
115 
116     f32 s_CubeHalfEdge[3];
117     nn::math::MTX44 s_WorldMatrix;
118     f32 s_Position[3];
119     f32 s_Angle[3];
120 }
121 
122 void InitializeGraphics(void);
123 void InitializeCube(void);
124 void InitializeShader(void);
125 
126 void AllocateCube(void);
127 void SetCube(void);
128 void UpdateCubeVBO(const bool& updatePosition=true, const bool& updateColor=true,
129                    const bool& updateNormal=true, const bool& updateIndex=true);
130 
131 void SetCubePosition(void);
132 void SetCubeColor(const f32& red, const f32& green, const f32& blue, const f32& alpha);
133 void SetCubeNormal(void);
134 void SetCubeIndex(void);
135 
136 void FinalizeCube(void);
137 void DeallocateCube(void);
138 
139 void UseShader(void);
140 void UpdateCamera(void);
141 void DrawDisplay0(void);
142 void DrawDisplay1(void);
143 
144 void UpdateCube(void);
145 void DrawCube(void);
146 
Initialize(void)147 void Initialize(void)
148 {
149     // fs initialization
150     nn::fs::Initialize();
151 
152     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
153     static char buffer[ROMFS_BUFFER_SIZE];
154     NN_UTIL_PANIC_IF_FAILED(
155         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
156 
157     InitializeGraphics();
158 }
159 
InitializeGraphics(void)160 void InitializeGraphics(void)
161 {
162     s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(),
163         nn::os::GetDeviceMemorySize() );
164     s_AddrForGxHeap = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
165 
166     s_RenderSystem.Initialize(s_AddrForGxHeap, s_GxHeapSize);
167 
168     // Stops executing the command list.
169     nngxStopCmdlist();
170 
171     glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
172     glClearDepthf(1.f);
173 
174     glEnable(GL_DEPTH_TEST);
175     glDepthFunc(GL_LESS);
176 
177     glEnable(GL_CULL_FACE);
178     glFrontFace(GL_CCW);
179     glCullFace(GL_BACK);
180 
181     InitializeShader();
182 
183     // Initialize projection matrix
184     nn::math::MTX44PerspectivePivotDeg(&s_Display0ProjectionMatrix, 45.0f,
185         demo::DISPLAY0_ASPECT, 0.2f, 100.0f,
186         nn::math::PIVOT_UPSIDE_TO_TOP);
187 
188     nn::math::MTX44PerspectivePivotDeg(&s_Display1ProjectionMatrix, 45.0f,
189         demo::DISPLAY1_ASPECT, 0.2f, 100.0f,
190         nn::math::PIVOT_UPSIDE_TO_TOP);
191 
192     InitializeCube();
193 
194     NN_LOG("Update vertex color to RED->GREEN->BLUE.\n");
195 }
196 
InitializeShader(void)197 void InitializeShader(void)
198 {
199     s_ProgramId = glCreateProgram();
200 
201     // Load vertex shader
202     s_ShaderId = glCreateShader(GL_VERTEX_SHADER);
203     nn::fs::FileReader file(L"rom:/shader.shbin");
204     size_t fileSize = file.GetSize();
205     void* buf = s_AppHeap.Allocate(fileSize);
206     s32 read = file.Read(buf, fileSize);
207     glShaderBinary(1, &s_ShaderId, GL_PLATFORM_BINARY_DMP, buf, read);
208     file.Finalize();
209     s_AppHeap.Free(buf);
210 
211     glAttachShader(s_ProgramId, s_ShaderId);
212     glAttachShader(s_ProgramId, GL_DMP_FRAGMENT_SHADER_DMP);
213 
214     glBindAttribLocation(s_ProgramId, VERTEX_POSITION_ATTRIBUTE_INDEX, "aPosition");
215     glBindAttribLocation(s_ProgramId, VERTEX_COLOR_ATTRIBUTE_INDEX, "aColor");
216     glBindAttribLocation(s_ProgramId, VERTEX_NORMAL_ATTRIBUTE_INDEX, "aNormal");
217 
218     glLinkProgram(s_ProgramId);
219     glValidateProgram(s_ProgramId);
220 
221     demo::InitializeUniforms(s_ProgramId);
222 }
223 
InitializeCube(void)224 void InitializeCube(void)
225 {
226     // (a) When there is a copy to main memory and when PICA accesses the copy in main memory
227     if ( s_VertexBufferPattern == USE_VBO_MEM_MAIN_COPY )
228     {
229         s_ArrayBufferDataType = GL_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_COPY_FCRAM_DMP;
230         s_ElementArrayBufferDataType = GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_COPY_FCRAM_DMP;
231         NN_LOG("Allocate the vertex buffer in main memory with COPY.\n");
232         NN_LOG("  GL_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_COPY_FCRAM_DMP\n");
233         NN_LOG("  GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_COPY_FCRAM_DMP\n");
234     }
235     // (b) When there is no copy in main memory and PICA directly accesses main memory
236     else if ( s_VertexBufferPattern == USE_VBO_MEM_MAIN_NO_COPY )
237     {
238         s_ArrayBufferDataType = GL_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP;
239         s_ElementArrayBufferDataType = GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP;
240         NN_LOG("Allocate the vertex buffer in main memory with NO_COPY.\n");
241         NN_LOG("  GL_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP\n");
242         NN_LOG("  GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP\n");
243     }
244     // (c) When there is a copy in main memory and PICA accesses VRAMA
245     else if ( s_VertexBufferPattern == USE_VBO_VRAMA_COPY )
246     {
247         s_ArrayBufferDataType = GL_ARRAY_BUFFER | NN_GX_MEM_VRAMA | GL_COPY_FCRAM_DMP;
248         s_ElementArrayBufferDataType = GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_VRAMA | GL_COPY_FCRAM_DMP;
249         NN_LOG("Allocate the vertex buffer in VRAMA with FCRAM COPY.\n");
250         NN_LOG("  GL_ARRAY_BUFFER | NN_GX_MEM_VRAMA | GL_COPY_FCRAM_DMP\n");
251         NN_LOG("  GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_VRAMA | GL_COPY_FCRAM_DMP\n");
252     }
253     // (d) When there is no copy in main memory and PICA accesses VRAMA
254     else if ( s_VertexBufferPattern == USE_VBO_VRAMA_NO_COPY )
255     {
256         s_ArrayBufferDataType = GL_ARRAY_BUFFER | NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP;
257         s_ElementArrayBufferDataType = GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP;
258         NN_LOG("Allocate the vertex buffer in VRAMA with FCRAM NO_COPY.\n");
259         NN_LOG("  GL_ARRAY_BUFFER | NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP\n");
260         NN_LOG("  GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP\n");
261     }
262     // (e) When there is a copy in main memory and PICA accesses VRAMB
263     else if ( s_VertexBufferPattern == USE_VBO_VRAMB_COPY )
264     {
265         s_ArrayBufferDataType = GL_ARRAY_BUFFER | NN_GX_MEM_VRAMB | GL_COPY_FCRAM_DMP;
266         s_ElementArrayBufferDataType = GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_VRAMB | GL_COPY_FCRAM_DMP;
267         NN_LOG("Allocate the vertex buffer in VRAMB with FCRAM COPY.\n");
268         NN_LOG("  GL_ARRAY_BUFFER | NN_GX_MEM_VRAMB | GL_COPY_FCRAM_DMP\n");
269         NN_LOG("  GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_VRAMB | GL_COPY_FCRAM_DMP\n");
270     }
271     // (f) When there is no copy in main memory and PICA accesses VRAMB
272     else if ( s_VertexBufferPattern == USE_VBO_VRAMB_NO_COPY )
273     {
274         s_ArrayBufferDataType = GL_ARRAY_BUFFER | NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP;
275         s_ElementArrayBufferDataType = GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP;
276         NN_LOG("Allocate the vertex buffer in VRAMB with FCRAM NO_COPY.\n");
277         NN_LOG("  GL_ARRAY_BUFFER | NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP\n");
278         NN_LOG("  GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP\n");
279     }
280 
281     // Allocates the arrays for vertex data and indices
282     AllocateCube();
283 
284     SetCube();
285 
286     // Generates the vertex buffer
287     for (u32 index = 0; index < 3; index++)
288     {
289         s_ArrayBufferIdArray[index] = 0;
290     }
291     glGenBuffers(3, s_ArrayBufferIdArray);
292     if ( s_ArrayBufferIdArray == NULL )
293     {
294         NN_PANIC("FILE(%s), LINE(%d) : s_ArrayBufferIdArray is 0.\n", __FILE__, __LINE__);
295     }
296 
297     // POSITION : Allocates the vertex buffer
298     glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferIdArray[VERTEX_POSITION_ATTRIBUTE_INDEX]);
299     glBufferData(s_ArrayBufferDataType, s_PositionArraySize, s_PositionArray, GL_STATIC_DRAW);
300 
301     // COLOR Allocates the vertex buffer
302     glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferIdArray[VERTEX_COLOR_ATTRIBUTE_INDEX]);
303     glBufferData(s_ArrayBufferDataType, s_ColorArraySize, s_ColorArray, GL_STATIC_DRAW);
304 
305     // NORMAL : Allocates the vertex buffer
306     glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferIdArray[VERTEX_NORMAL_ATTRIBUTE_INDEX]);
307     glBufferData(s_ArrayBufferDataType, s_NormalArraySize, s_NormalArray, GL_STATIC_DRAW);
308 
309     // Generates the index buffer
310     glGenBuffers(1, &s_ElementArrayBufferId);
311     if ( s_ElementArrayBufferId == 0 )
312     {
313         NN_PANIC("FILE(%s), LINE(%d) : s_ElementArrayBufferId is 0.\n", __FILE__, __LINE__);
314     }
315 
316     // INDEX
317     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_ElementArrayBufferId);
318     glBufferData(s_ElementArrayBufferDataType, s_IndexArraySize, s_IndexArray, GL_STATIC_DRAW);
319 
320     // Updates the vertex buffer and index buffer.
321     UpdateCubeVBO();
322 
323     DEMO_ASSERT_GL_ERROR();
324 }
325 
AllocateCube(void)326 void AllocateCube(void)
327 {
328     // If there is no copy in main memory (cases (b), (d) (f)), the vertex data must be allocated from device memory.
329     //
330     // In this demo, all vertex data is allocated from device memory.
331 
332     // Allocate vertex arrays from device memory
333     s_PositionArray = (f32*)demo::Alloc(s_PositionArraySize);
334     if ( s_PositionArray == NULL )
335     {
336         NN_PANIC("FILE(%s), LINE(%d) : s_PositionArray is NULL.\n", __FILE__, __LINE__);
337     }
338 
339     s_ColorArray = (f32*)demo::Alloc(s_ColorArraySize);
340     if ( s_ColorArray == NULL )
341     {
342         NN_PANIC("FILE(%s), LINE(%d) : s_ColorArray is NULL.\n", __FILE__, __LINE__);
343     }
344 
345     s_NormalArray = (f32*)demo::Alloc(s_NormalArraySize);
346     if ( s_NormalArray == NULL )
347     {
348         NN_PANIC("FILE(%s), LINE(%d) : s_NormalArray is NULL.\n", __FILE__, __LINE__);
349     }
350 
351     // Allocate index arrays from device memory
352     s_IndexArray = (GLushort*)demo::Alloc(s_IndexArraySize);
353     if ( s_IndexArray == NULL )
354     {
355         NN_PANIC("FILE(%s), LINE(%d) : s_IndexArray is NULL.\n", __FILE__, __LINE__);
356     }
357 }
358 
SetCube(void)359 void SetCube(void)
360 {
361     for (u32 index = 0; index < 3; index++)
362     {
363         s_CubeHalfEdge[index] = 0.5f;
364     }
365 
366     for (u32 index = 0; index < 3; index++)
367     {
368         s_Position[index] = 0.0f;
369         s_Angle[index] = 0.0f;
370     }
371 
372     SetCubePosition();
373     SetCubeColor(1.0f, 0.0f, 0.0f, 1.0f);
374     SetCubeNormal();
375     SetCubeIndex();
376 }
377 
SetCubePosition(void)378 void SetCubePosition(void)
379 {
380     // POSITION : -Y face
381     u32 vertexIndex = 0;
382     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
383     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
384     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
385     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
386     vertexIndex++;
387 
388     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
389     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
390     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
391     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
392     vertexIndex++;
393 
394     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
395     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
396     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
397     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
398     vertexIndex++;
399 
400     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
401     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
402     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
403     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
404     vertexIndex++;
405 
406     // POSITION : +Y face
407     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
408     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
409     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
410     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
411     vertexIndex++;
412 
413     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
414     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
415     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
416     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
417     vertexIndex++;
418 
419     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
420     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
421     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
422     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
423     vertexIndex++;
424 
425     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
426     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
427     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
428     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
429     vertexIndex++;
430 
431     // POSITION : -Z face
432     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
433     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
434     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
435     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
436     vertexIndex++;
437 
438     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
439     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
440     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
441     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
442     vertexIndex++;
443 
444     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
445     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
446     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
447     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
448     vertexIndex++;
449 
450     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
451     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
452     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
453     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
454     vertexIndex++;
455 
456     // POSITION : +Z face
457     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
458     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
459     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
460     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
461     vertexIndex++;
462 
463     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
464     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
465     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
466     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
467     vertexIndex++;
468 
469     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
470     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
471     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
472     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
473     vertexIndex++;
474 
475     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
476     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
477     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
478     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
479     vertexIndex++;
480 
481     // POSITION : -X face
482     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
483     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
484     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
485     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
486     vertexIndex++;
487 
488     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
489     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
490     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
491     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
492     vertexIndex++;
493 
494     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
495     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
496     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
497     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
498     vertexIndex++;
499 
500     s_PositionArray[4 * vertexIndex]     = (- s_CubeHalfEdge[0]);
501     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
502     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
503     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
504     vertexIndex++;
505 
506     // POSITION : +X face
507     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
508     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
509     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
510     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
511     vertexIndex++;
512 
513     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
514     s_PositionArray[4 * vertexIndex + 1] = (- s_CubeHalfEdge[1]);
515     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
516     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
517     vertexIndex++;
518 
519     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
520     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
521     s_PositionArray[4 * vertexIndex + 2] = (+ s_CubeHalfEdge[2]);
522     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
523     vertexIndex++;
524 
525     s_PositionArray[4 * vertexIndex]     = (+ s_CubeHalfEdge[0]);
526     s_PositionArray[4 * vertexIndex + 1] = (+ s_CubeHalfEdge[1]);
527     s_PositionArray[4 * vertexIndex + 2] = (- s_CubeHalfEdge[2]);
528     s_PositionArray[4 * vertexIndex + 3] = 1.0f;
529     vertexIndex++;
530 }
531 
SetCubeColor(const f32 & red,const f32 & green,const f32 & blue,const f32 & alpha)532 void SetCubeColor(const f32& red, const f32& green, const f32& blue, const f32& alpha)
533 {
534     for (u32 vertexIndex = 0; vertexIndex < s_VerticesNum; vertexIndex++)
535     {
536         s_ColorArray[4 * vertexIndex] = red;
537         s_ColorArray[4 * vertexIndex + 1] = green;
538         s_ColorArray[4 * vertexIndex + 2] = blue;
539         s_ColorArray[4 * vertexIndex + 3] = alpha;
540     }
541 }
542 
SetCubeNormal(void)543 void SetCubeNormal(void)
544 {
545     u32 vertexIndex = 0;
546 
547     // NORMAL : -Y face
548     for (u32 index = 0; index < 4; index++)
549     {
550         s_NormalArray[3 * vertexIndex]     =  0.0f;
551         s_NormalArray[3 * vertexIndex + 1] = -1.0f;
552         s_NormalArray[3 * vertexIndex + 2] =  0.0f;
553         vertexIndex++;
554     }
555 
556     // NORMAL : +Y face
557     for (u32 index = 0; index < 4; index++)
558     {
559         s_NormalArray[3 * vertexIndex]     =  0.0f;
560         s_NormalArray[3 * vertexIndex + 1] =  1.0f;
561         s_NormalArray[3 * vertexIndex + 2] =  0.0f;
562         vertexIndex++;
563     }
564 
565     // NORMAL : -Z face
566     for (u32 index = 0; index < 4; index++)
567     {
568         s_NormalArray[3 * vertexIndex]     =  0.0f;
569         s_NormalArray[3 * vertexIndex + 1] =  0.0f;
570         s_NormalArray[3 * vertexIndex + 2] = -1.0f;
571         vertexIndex++;
572     }
573 
574     // NORMAL : +Z face
575     for (u32 index = 0; index < 4; index++)
576     {
577         s_NormalArray[3 * vertexIndex]     =  0.0f;
578         s_NormalArray[3 * vertexIndex + 1] =  0.0f;
579         s_NormalArray[3 * vertexIndex + 2] =  1.0f;
580         vertexIndex++;
581     }
582 
583     // NORMAL : -X face
584     for (u32 index = 0; index < 4; index++)
585     {
586         s_NormalArray[3 * vertexIndex]     = -1.0f;
587         s_NormalArray[3 * vertexIndex + 1] =  0.0f;
588         s_NormalArray[3 * vertexIndex + 2] =  1.0f;
589         vertexIndex++;
590     }
591 
592     // NORMAL : +X face
593     for (u32 index = 0; index < 4; index++)
594     {
595         s_NormalArray[3 * vertexIndex]     =  1.0f;
596         s_NormalArray[3 * vertexIndex + 1] =  0.0f;
597         s_NormalArray[3 * vertexIndex + 2] =  0.0f;
598         vertexIndex++;
599     }
600 }
601 
SetCubeIndex(void)602 void SetCubeIndex(void)
603 {
604     u32 triangleIndex = 0;
605 
606     // INDEX : -Y face
607     s_IndexArray[3 * triangleIndex]     = 0;
608     s_IndexArray[3 * triangleIndex + 1] = 2;
609     s_IndexArray[3 * triangleIndex + 2] = 1;
610     triangleIndex++;
611     s_IndexArray[3 * triangleIndex]     = 0;
612     s_IndexArray[3 * triangleIndex + 1] = 3;
613     s_IndexArray[3 * triangleIndex + 2] = 2;
614     triangleIndex++;
615 
616     // INDEX : +Y face
617     s_IndexArray[3 * triangleIndex]     = 4;
618     s_IndexArray[3 * triangleIndex + 1] = 6;
619     s_IndexArray[3 * triangleIndex + 2] = 5;
620     triangleIndex++;
621     s_IndexArray[3 * triangleIndex]     = 4;
622     s_IndexArray[3 * triangleIndex + 1] = 7;
623     s_IndexArray[3 * triangleIndex + 2] = 6;
624     triangleIndex++;
625 
626     // INDEX : -Z face
627     s_IndexArray[3 * triangleIndex]     = 8;
628     s_IndexArray[3 * triangleIndex + 1] = 10;
629     s_IndexArray[3 * triangleIndex + 2] = 9;
630     triangleIndex++;
631     s_IndexArray[3 * triangleIndex]     = 8;
632     s_IndexArray[3 * triangleIndex + 1] = 11;
633     s_IndexArray[3 * triangleIndex + 2] = 10;
634     triangleIndex++;
635 
636     // INDEX : +Z face
637     s_IndexArray[3 * triangleIndex]     = 12;
638     s_IndexArray[3 * triangleIndex + 1] = 14;
639     s_IndexArray[3 * triangleIndex + 2] = 13;
640     triangleIndex++;
641     s_IndexArray[3 * triangleIndex]     = 12;
642     s_IndexArray[3 * triangleIndex + 1] = 15;
643     s_IndexArray[3 * triangleIndex + 2] = 14;
644     triangleIndex++;
645 
646     // INDEX : -X face
647     s_IndexArray[3 * triangleIndex]     = 16;
648     s_IndexArray[3 * triangleIndex + 1] = 18;
649     s_IndexArray[3 * triangleIndex + 2] = 17;
650     triangleIndex++;
651     s_IndexArray[3 * triangleIndex]     = 16;
652     s_IndexArray[3 * triangleIndex + 1] = 19;
653     s_IndexArray[3 * triangleIndex + 2] = 18;
654     triangleIndex++;
655 
656     // INDEX : +X face
657     s_IndexArray[3 * triangleIndex]     = 20;
658     s_IndexArray[3 * triangleIndex + 1] = 22;
659     s_IndexArray[3 * triangleIndex + 2] = 21;
660     triangleIndex++;
661     s_IndexArray[3 * triangleIndex]     = 20;
662     s_IndexArray[3 * triangleIndex + 1] = 23;
663     s_IndexArray[3 * triangleIndex + 2] = 22;
664     triangleIndex++;
665 }
666 
UpdateCubeVBO(const bool & updatePosition,const bool & updateColor,const bool & updateNormal,const bool & updateIndex)667 void UpdateCubeVBO(const bool& updatePosition, const bool& updateColor, const bool& updateNormal,
668                    const bool& updateIndex)
669 {
670     // POSITION : Update the vertex coordinates
671     if ( updatePosition )
672     {
673         glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferIdArray[VERTEX_POSITION_ATTRIBUTE_INDEX]);
674         glBufferSubData(GL_ARRAY_BUFFER, 0, s_PositionArraySize, s_PositionArray);
675     }
676 
677     // COLOR Update the vertex color
678     if ( updateColor )
679     {
680         glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferIdArray[VERTEX_COLOR_ATTRIBUTE_INDEX]);
681         glBufferSubData(GL_ARRAY_BUFFER, 0, s_ColorArraySize, s_ColorArray);
682     }
683 
684     // NORMAL : Update vertex normals
685     if ( updateNormal )
686     {
687         glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferIdArray[VERTEX_NORMAL_ATTRIBUTE_INDEX]);
688         glBufferSubData(GL_ARRAY_BUFFER, 0, s_NormalArraySize, s_NormalArray);
689     }
690 
691     // INDEX : Update vertex indices
692     if ( updateIndex )
693     {
694         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_ElementArrayBufferId);
695         glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, s_IndexArraySize, s_IndexArray);
696     }
697 
698     DEMO_ASSERT_GL_ERROR();
699 }
700 
Finalize(void)701 void Finalize(void)
702 {
703     FinalizeCube();
704 
705     s_RenderSystem.Finalize();
706 
707     s_AppHeap.Free(reinterpret_cast<void*>(s_AddrForGxHeap));
708     s_AppHeap.Finalize();
709 }
710 
FinalizeCube(void)711 void FinalizeCube(void)
712 {
713     DeallocateCube();
714 
715     if ( s_ArrayBufferIdArray[0] != 0 )
716     {
717         glDeleteBuffers(3, s_ArrayBufferIdArray);
718         for (u32 index = 0; index < 3; index++)
719         {
720             s_ArrayBufferIdArray[index] = 0;
721         }
722     }
723 
724     if ( s_ElementArrayBufferId != 0 )
725     {
726         glDeleteBuffers(1, &s_ElementArrayBufferId);
727         s_ElementArrayBufferId = 0;
728     }
729 }
730 
DeallocateCube(void)731 void DeallocateCube(void)
732 {
733     if ( s_PositionArray != NULL )
734     {
735         demo::Free((void*) s_PositionArray);
736         s_PositionArray = NULL;
737     }
738 
739     if ( s_ColorArray != NULL )
740     {
741         demo::Free((void*) s_ColorArray);
742         s_ColorArray = NULL;
743     }
744 
745     if ( s_NormalArray != NULL )
746     {
747         demo::Free((void*) s_NormalArray);
748         s_NormalArray = NULL;
749     }
750 
751     if ( s_IndexArray != NULL )
752     {
753         demo::Free((void*) s_IndexArray);
754         s_IndexArray = NULL;
755     }
756 }
757 
DrawFrame(void)758 bool DrawFrame(void)
759 {
760     UpdateCamera();
761 
762     DrawDisplay0();
763     DrawDisplay1();
764 
765     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
766 
767     // Stops executing the command list.
768     nngxStopCmdlist();
769 
770     return true;
771 }
772 
UpdateCamera(void)773 void UpdateCamera(void)
774 {
775     nn::math::MTX34LookAt(&s_ViewMatrix, &s_CameraPosition, &s_CameraUp, &s_CameraTarget);
776 }
777 
DrawDisplay0(void)778 void DrawDisplay0(void)
779 {
780     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
781     s_RenderSystem.Clear();
782     UseShader();
783     glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION],
784         1, GL_TRUE, static_cast<f32*>(s_Display0ProjectionMatrix));
785 
786     UpdateCube();
787     DrawCube();
788 
789     s_RenderSystem.SwapBuffers();
790 }
791 
UseShader(void)792 void UseShader(void)
793 {
794     glUseProgram(s_ProgramId);
795 
796     // Fragment uniform
797     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_ALPHA_TEST], GL_FALSE);
798 
799     // Fragment uniform : Texture samplerType
800     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE0_SAMPLER_TYPE], GL_FALSE);
801     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE1_SAMPLER_TYPE], GL_FALSE);
802     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE2_SAMPLER_TYPE], GL_FALSE);
803     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE3_SAMPLER_TYPE], GL_FALSE);
804 
805     // Fragment uniform : Fragment lighting
806     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_ENABLED], GL_TRUE);
807     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_AMBIENT], 1, s_GlobalAmbientLight);
808     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_ENABLED], GL_TRUE);
809     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_AMBIENT], 1, s_Light0Ambient);
810     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_DIFFUSE], 1, s_Light0Diffuse);
811     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_POSITION], 1, s_Light0Position);
812 
813     // Fragment uniform : Material
814     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_AMBIENT], 1, s_MaterialAmbient);
815     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_DIFFUSE], 1, s_MaterialDiffuse);
816 
817     // Fragment uniform : Texture combiner
818     //   Modulate fragment primary color and vertex color.
819     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_RGB],
820         GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_PRIMARY_COLOR, GL_PREVIOUS);
821     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_ALPHA],
822         GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PREVIOUS);
823     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_RGB],
824         GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
825     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_ALPHA],
826         GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
827     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_RGB],
828         GL_MODULATE);
829     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_ALPHA],
830         GL_MODULATE);
831 }
832 
DrawDisplay1(void)833 void DrawDisplay1(void)
834 {
835     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
836     s_RenderSystem.Clear();
837 
838     s_RenderSystem.SwapBuffers();
839 }
840 
UpdateCube(void)841 void UpdateCube(void)
842 {
843     static u32 mode = 1;
844     static u32 counter = 0;
845     static const u32 maxCounter = 120;
846 
847     s_Angle[1] += 1.0f;
848     if ( s_Angle[1] > 360.f )
849     {
850         s_Angle[1] -= 360.0f;
851     }
852 
853     nn::math::Vector3 positionVector(s_Position[0], s_Position[1], s_Position[2]);
854     nn::math::MTX34 positionMatrix;
855     nn::math::MTX34Identity(&positionMatrix);
856     nn::math::MTX34Translate(&positionMatrix, &positionVector);
857     nn::math::MTX44 worldMatrix(positionMatrix);
858 
859     nn::math::MTX44 worldRotMatrix;
860     nn::math::MTX44RotXYZDeg(&worldRotMatrix, s_Angle[0], s_Angle[1], s_Angle[2]);
861     nn::math::MTX44Mult(&s_WorldMatrix, &worldMatrix, &worldRotMatrix);
862 
863     // Updates the vertex color periodically.
864     if ( counter > maxCounter )
865     {
866         if ( mode == 0 )
867         {
868             SetCubeColor(1.0f, 0.0f, 0.0f, 1.0f);
869             mode = 1;
870         }
871         else if ( mode == 1 )
872         {
873             SetCubeColor(0.0f, 1.0f, 0.0f, 1.0f);
874             mode = 2;
875         }
876         else if ( mode == 2 )
877         {
878             SetCubeColor(0.0f, 0.0f, 1.0f, 1.0f);
879             mode = 0;
880         }
881 
882         // Updates the vertex buffer for vertex color
883         UpdateCubeVBO(false, true, false, false);
884         counter = 0;
885     }
886     else
887     {
888         counter++;
889     }
890 }
891 
DrawCube(void)892 void DrawCube(void)
893 {
894     nn::math::MTX44 modelViewMatrix(s_ViewMatrix);
895     nn::math::MTX44Mult(&modelViewMatrix, &modelViewMatrix, &s_WorldMatrix);
896     glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_MODELVIEW],
897         1, GL_TRUE, static_cast<f32*>(modelViewMatrix));
898 
899     // POSITION
900     glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferIdArray[VERTEX_POSITION_ATTRIBUTE_INDEX]);
901     glEnableVertexAttribArray(VERTEX_POSITION_ATTRIBUTE_INDEX);
902     glVertexAttribPointer(VERTEX_POSITION_ATTRIBUTE_INDEX,
903         VERTEX_POSITION_ATTRIBUTE_SIZE,
904         GL_FLOAT, GL_FALSE, 0, 0);
905 
906     // COLOR
907     glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferIdArray[VERTEX_COLOR_ATTRIBUTE_INDEX]);
908     glEnableVertexAttribArray(VERTEX_COLOR_ATTRIBUTE_INDEX);
909     glVertexAttribPointer(VERTEX_COLOR_ATTRIBUTE_INDEX,
910         VERTEX_COLOR_ATTRIBUTE_SIZE,
911         GL_FLOAT, GL_FALSE, 0, 0);
912 
913     // NORMAL
914     glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferIdArray[VERTEX_NORMAL_ATTRIBUTE_INDEX]);
915     glEnableVertexAttribArray(VERTEX_NORMAL_ATTRIBUTE_INDEX);
916     glVertexAttribPointer(VERTEX_NORMAL_ATTRIBUTE_INDEX,
917         VERTEX_NORMAL_ATTRIBUTE_SIZE,
918         GL_FLOAT, GL_FALSE, 0, 0);
919 
920     for (u32 index = VERTEX_ATTRIBUTES_NUM; index < 8; index++)
921     {
922         glDisableVertexAttribArray(index);
923     }
924 
925     glDrawElements(GL_TRIANGLES, s_TrianglesNum * 3, GL_UNSIGNED_SHORT, 0);
926 }
927 
nnMain(void)928 void nnMain(void)
929 {
930     // Call only nn::applet::Enable to also allow execution from the HOME Menu
931     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
932     nn::applet::Enable();
933 
934     Initialize();
935 
936     bool flag = true;
937     while ( flag )
938     {
939         flag = DrawFrame();
940     }
941 
942     Finalize();
943 }
944