1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     gx_CommandListDouble.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 #define USE_COMMAND_LIST_DOUBLE
27 
28 namespace
29 {
30     GLuint s_ProgramId = 0;
31     GLuint s_ShaderId = 0;
32 
33     nn::fnd::ExpHeap s_AppHeap;
34     uptr s_AddrForGxHeap;
35     const u32 s_GxHeapSize = 0x400000;
36 
37     nn::os::Tick s_FrameStartTick;
38     nn::os::Tick s_FrameEndTick;
39     nn::os::Tick s_StoreTick;
40     nn::os::Tick s_RenderTick;
41 
42     nn::math::Vector3 s_CameraPosition(0.0f, 1.0f, 5.0f);
43     nn::math::Vector3 s_CameraUp(0.0f, 1.0f, 0.0f);
44     nn::math::Vector3 s_CameraTarget(0.0f, 0.0f, 0.0f);
45 
46     nn::math::Matrix34 s_ViewMatrix;
47     nn::math::Matrix44 s_Display0ProjectionMatrix;
48     nn::math::Matrix44 s_Display1ProjectionMatrix;
49 
50     f32 s_GlobalAmbientLight[] = { 0.2f,  0.2f,  0.2f, 1.0f};
51     f32 s_Light0Ambient[]      = { 0.2f,  0.2f,  0.2f, 1.0f};
52     f32 s_Light0Diffuse[]      = { 0.7f,  0.7f,  0.7f, 1.0f};
53     f32 s_Light0Position[]     = {10.0f, 10.0f, 10.0f, 0.0f};
54 
55     f32 s_MaterialAmbient[] = {0.3f, 0.3f, 0.3f, 1.0f};
56     f32 s_MaterialDiffuse[] = {0.7f, 0.7f, 0.7f, 1.0f};
57 
58     const u32 s_RowCubeNum = 20;
59     const u32 s_ColumnCubeNum = 10;
60     demo::Cube s_Cube[s_RowCubeNum][s_ColumnCubeNum];
61 
62     const u32 s_MaxCount = 120;
63 }
64 
65 namespace demo
66 {
67     //
68     // Class that double buffers the render command list
69     //
70     class RenderSystemDouble : public demo::RenderSystem
71     {
72     public:
73         RenderSystemDouble(void);
74         virtual ~RenderSystemDouble();
75 
76     public:
77         virtual void Initialize(const uptr fcramAddress, const size_t memorySize,
78                 const u32 commandBufferSize = 0x40000, const u32 requestNum = 128,
79                 const bool serialRunMode = true,
80                 const demo::DisplayBuffersDescription& displayBuffers0Desc = DisplayBuffersDescription::GetDefaultDisplay0Description(),
81                 const demo::DisplayBuffersDescription& displayBuffers1Desc = DisplayBuffersDescription::GetDefaultDisplay1Description(),
82                 const demo::FrameBufferDescription& frameBuffer0Desc = FrameBufferDescription::GetDefaultDisplay0FrameBufferDescription(),
83                 const demo::DisplayBuffersDescription& displayBuffers0ExtDesc = DisplayBuffersDescription::GetDefaultDisplay0ExtDescription() );
84         virtual void Finalize(void);
85 
86     protected:
87         void CreateCommandListDouble(GLsizei bufSize, GLsizei reqCountNum);
88         void RunCommandListDouble(void);
89 
90     public:
91         virtual void SwapBuffers(void);
92     protected:
93         virtual void SwapBuffers0(void);
94         virtual void SwapBuffers1(void);
95 
96     protected:
97         GLuint m_CurrentDisplay0BufferIndex;
98         GLuint m_CurrentDisplay1BufferIndex;
99 
100         GLuint m_Display0BufferIdArray[2];
101         GLuint m_Display1BufferIdArray[2];
102 
103         GLuint m_CurrentCommandListIndex;
104         GLuint m_CommandListIdArray[2];
105     };
106 
RenderSystemDouble()107     RenderSystemDouble::RenderSystemDouble() :
108     demo::RenderSystem(),
109     m_CurrentDisplay0BufferIndex(0), m_CurrentDisplay1BufferIndex(0),
110     m_CurrentCommandListIndex(0)
111     {
112         for (u32 index = 0; index < 2; index++)
113         {
114             m_Display0BufferIdArray[index] = 0;
115             m_Display1BufferIdArray[index] = 0;
116 
117             m_CommandListIdArray[index] = 0;
118         }
119     }
120 
~RenderSystemDouble()121     RenderSystemDouble::~RenderSystemDouble()
122     {
123     }
124 
Initialize(const uptr fcramAddress,const size_t memorySize,const u32 commandBufferSize,const u32 requestNum,const bool serialRunMode,const demo::DisplayBuffersDescription & displayBuffers0Desc,const demo::DisplayBuffersDescription & displayBuffers1Desc,const demo::FrameBufferDescription & frameBuffer0Desc,const demo::DisplayBuffersDescription & displayBuffers0ExtDesc)125     void RenderSystemDouble::Initialize(const uptr fcramAddress, const size_t memorySize,
126         const u32 commandBufferSize, const u32 requestNum,
127         const bool serialRunMode,
128         const demo::DisplayBuffersDescription& displayBuffers0Desc,
129         const demo::DisplayBuffersDescription& displayBuffers1Desc,
130         const demo::FrameBufferDescription& frameBuffer0Desc,
131         const demo::DisplayBuffersDescription& displayBuffers0ExtDesc)
132     {
133         NN_UNUSED_VAR(serialRunMode);
134         NN_UNUSED_VAR(displayBuffers0ExtDesc);
135 
136 #ifdef USE_COMMAND_LIST_DOUBLE
137         demo::InitializeMemoryManager(fcramAddress, memorySize);
138         if ( nngxInitialize(demo::GetAllocator, demo::GetDeallocator) == GL_FALSE )
139         {
140             NN_TPANIC_("nngxInitialize() failed.\n");
141         }
142 
143         // Double buffer the command list
144         CreateCommandListDouble(commandBufferSize, requestNum);
145 
146         DisplayBuffers::Create(displayBuffers0Desc, m_DisplayBuffers0);
147         DEMO_ASSERT_GL_ERROR();
148 
149         DisplayBuffers::Create(displayBuffers1Desc, m_DisplayBuffers1);
150         DEMO_ASSERT_GL_ERROR();
151 
152         m_CurrentDisplay0BufferIndex = 0;
153         m_CurrentDisplay1BufferIndex = 0;
154 
155         for (u32 index = 0; index < 2; index++)
156         {
157             m_Display0BufferIdArray[index] = m_DisplayBuffers0.GetDisplayBufferId(index);
158             m_Display1BufferIdArray[index] = m_DisplayBuffers1.GetDisplayBufferId(index);
159         }
160 
161         FrameBuffer::Create(frameBuffer0Desc, m_FrameBuffer0);
162         DEMO_ASSERT_GL_ERROR();
163 
164         m_InitializeFlag = true;
165 
166         InitializeLcdDisplay();
167 
168         DEMO_ASSERT_GL_ERROR();
169 #else
170 
171         RenderSystem::Initialize(fcramAddress, memorySize,
172             commandBufferSize, requestNum, serialRunMode,
173             displayBuffers0Desc, displayBuffers1Desc, frameBuffer0Desc);
174 #endif
175     }
176 
CreateCommandListDouble(GLsizei bufSize,GLsizei reqCountNum)177     void RenderSystemDouble::CreateCommandListDouble(GLsizei bufSize, GLsizei reqCountNum)
178     {
179         nngxGenCmdlists(2, &m_CommandListIdArray[0]);
180         for (u32 index = 0; index < 2; index++)
181         {
182             nngxBindCmdlist(m_CommandListIdArray[index]);
183             nngxCmdlistStorage(bufSize, reqCountNum);
184             nngxSetCmdlistParameteri(NN_GX_CMDLIST_RUN_MODE, NN_GX_CMDLIST_SERIAL_RUN);
185             nngxClearCmdlist();
186         }
187 
188         m_CurrentCommandListIndex = 0;
189         nngxBindCmdlist( m_CommandListIdArray[m_CurrentCommandListIndex] );
190     }
191 
Finalize(void)192     void RenderSystemDouble::Finalize(void)
193     {
194 #ifdef USE_COMMAND_LIST_DOUBLE
195         nngxDeleteCmdlists(2, &m_CommandListIdArray[0]);
196 #endif
197 
198         RenderSystem::Finalize();
199     }
200 
SwapBuffers(void)201     void RenderSystemDouble::SwapBuffers(void)
202     {
203 #ifdef USE_COMMAND_LIST_DOUBLE
204         if ( m_TargetDisplay == NN_GX_DISPLAY0 )
205         {
206             SwapBuffers0();
207         }
208         else if ( m_TargetDisplay == NN_GX_DISPLAY1 )
209         {
210             SwapBuffers1();
211         }
212         else
213         {
214             NN_TPANIC_("Invalid display.\n");
215         }
216 #else
217         RenderSystem::SwapBuffers();
218         s_RenderTick = nn::os::Tick::GetSystemCurrent();
219 #endif
220 
221     }
222 
SwapBuffers0(void)223     void RenderSystemDouble::SwapBuffers0(void)
224     {
225         if (! m_InitializeFlag )
226         {
227             return;
228         }
229 
230         // Sends the color buffer contents for each screen to display buffers.
231         nngxTransferRenderImage(m_Display0BufferIdArray[m_CurrentDisplay0BufferIndex],
232             NN_GX_ANTIALIASE_NOT_USED, GL_FALSE, 0, 0);
233 
234         // Binds the display buffers to each display
235         // However, the buffers for the previous screens are bound
236         nngxActiveDisplay(NN_GX_DISPLAY0);
237         m_CurrentDisplay0BufferIndex = 1 - m_CurrentDisplay0BufferIndex;
238         nngxBindDisplaybuffer(m_Display0BufferIdArray[m_CurrentDisplay0BufferIndex]);
239 
240         // Waits for the color buffer to finish sending.
241         RunCommandListDouble();
242 
243         // Measures the time it takes to finish rendering to the upper screen
244         s_RenderTick = nn::os::Tick::GetSystemCurrent();
245 
246         nngxSwapBuffers(m_TargetDisplay);
247 
248         // Binds the accumulated command list and executes it
249         nngxBindCmdlist( m_CommandListIdArray[m_CurrentCommandListIndex] );
250         nngxRunCmdlist();
251 
252         // Switches the command list to start accumulating
253         m_CurrentCommandListIndex = 1 - m_CurrentCommandListIndex;
254 
255         // Binds the command list to start accumulating
256         nngxBindCmdlist( m_CommandListIdArray[m_CurrentCommandListIndex] );
257     }
258 
SwapBuffers1(void)259     void RenderSystemDouble::SwapBuffers1(void)
260     {
261         if (! m_InitializeFlag )
262         {
263             return;
264         }
265 
266         // Sends the color buffer contents for each screen to display buffers.
267         nngxTransferRenderImage(m_Display1BufferIdArray[m_CurrentDisplay1BufferIndex],
268             NN_GX_ANTIALIASE_NOT_USED, GL_FALSE, 0, 0);
269 
270         // Binds the display buffers to each display
271         // However, the buffers for the previous screens are bound
272         nngxActiveDisplay(NN_GX_DISPLAY1);
273         m_CurrentDisplay0BufferIndex = 1 - m_CurrentDisplay1BufferIndex;
274         nngxBindDisplaybuffer(m_Display1BufferIdArray[m_CurrentDisplay1BufferIndex]);
275 
276         // Waits for the color buffer to finish sending.
277         RunCommandListDouble();
278 
279         s_RenderTick = nn::os::Tick::GetSystemCurrent();
280 
281         nngxSwapBuffers(m_TargetDisplay);
282 
283         // Binds the accumulated command list and executes it
284         nngxBindCmdlist( m_CommandListIdArray[m_CurrentCommandListIndex] );
285         nngxRunCmdlist();
286 
287         // Switches the command list to start accumulating
288         m_CurrentCommandListIndex = 1 - m_CurrentCommandListIndex;
289 
290         // Binds the command list to start accumulating
291         nngxBindCmdlist( m_CommandListIdArray[m_CurrentCommandListIndex] );
292     }
293 
RunCommandListDouble(void)294     void RenderSystemDouble::RunCommandListDouble(void)
295     {
296         // Splits the 3D command buffer of the accumulating command list
297         nngxSplitDrawCmdlist();
298 
299         // Waits for the executing command list to finish
300         nngxBindCmdlist( m_CommandListIdArray[1 - m_CurrentCommandListIndex] );
301         nngxWaitCmdlistDone();
302 
303         // Clears the command list that has finished execution
304         nngxClearCmdlist();
305 
306         // Binds the accumulating command list
307         nngxBindCmdlist( m_CommandListIdArray[m_CurrentCommandListIndex] );
308     }
309 }
310 
311 namespace
312 {
313     demo::RenderSystemDouble s_RenderSystem;
314 }
315 
316 void InitializeGraphics(void);
317 void InitializeShader(void);
318 
319 void UseShader(void);
320 void UpdateCamera(void);
321 void DrawDisplay0(void);
322 void DrawDisplay1(void);
323 void DrawBody(demo::Body& body);
324 
Initialize(void)325 void Initialize(void)
326 {
327     // fs initialization
328     nn::fs::Initialize();
329 
330     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
331     static char buffer[ROMFS_BUFFER_SIZE];
332     NN_UTIL_PANIC_IF_FAILED(
333         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
334 
335     InitializeGraphics();
336 }
337 
InitializeGraphics(void)338 void InitializeGraphics(void)
339 {
340     s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() );
341     s_AddrForGxHeap = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
342     s_RenderSystem.Initialize(s_AddrForGxHeap, s_GxHeapSize);
343 
344     glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
345     glClearDepthf(1.0f);
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     InitializeShader();
355 
356     // Initialize projection matrix
357     nn::math::MTX44PerspectivePivotDeg(&s_Display0ProjectionMatrix, 45.0f,
358         demo::DISPLAY0_ASPECT, 0.2f, 100.0f,
359         nn::math::PIVOT_UPSIDE_TO_TOP);
360 
361     nn::math::MTX44PerspectivePivotDeg(&s_Display1ProjectionMatrix, 45.0f,
362         demo::DISPLAY1_ASPECT, 0.2f, 100.0f,
363         nn::math::PIVOT_UPSIDE_TO_TOP);
364 
365     // Initialize cubes
366     u32 vertexAttributes = demo::VERTEX_POSITION_ATTRIBUTE |
367         demo::VERTEX_COLOR_ATTRIBUTE |
368         demo::VERTEX_NORMAL_ATTRIBUTE;
369 
370     f32 s_CubeHalfEdges[3];
371     s_CubeHalfEdges[0] = 0.1f;
372     s_CubeHalfEdges[1] = 0.1f;
373     s_CubeHalfEdges[2] = 0.1f;
374 
375     f32 s_CubeOffsetSpace = 0.025f;
376     f32 s_CubeOffsetX = - (s_CubeHalfEdges[0] + s_CubeOffsetSpace) * s_RowCubeNum;
377     f32 s_CubeOffsetY = - (s_CubeHalfEdges[1] + s_CubeOffsetSpace) * s_ColumnCubeNum;
378 
379     f32 z = 0.0f;
380     for (u32 j = 0; j < s_ColumnCubeNum; j++)
381     {
382         f32 y = s_CubeOffsetY + 2.0f * (s_CubeHalfEdges[1] + s_CubeOffsetSpace) * j;
383         for (u32 i = 0; i < s_RowCubeNum; i++)
384         {
385             f32 x = s_CubeOffsetX + 2.0f * (s_CubeHalfEdges[0] + s_CubeOffsetSpace) * i;
386             s_Cube[i][j].InitializeCube(vertexAttributes, s_CubeHalfEdges[0], s_CubeHalfEdges[1], s_CubeHalfEdges[2]);
387             s_Cube[i][j].SetWorldPosition(x, y, z);
388 
389             f32 color[3];
390             demo::GetRandomColor(color[0], color[1], color[2]);
391             s_Cube[i][j].SetColor(color[0], color[1], color[2]);
392         }
393     }
394 
395 #ifdef USE_COMMAND_LIST_DOUBLE
396     NN_LOG("Use double-buffered command list\n");
397 #else
398     NN_LOG("Use single command list\n");
399 #endif
400     NN_LOG("  Total number of cubes = %d\n", s_ColumnCubeNum * s_RowCubeNum);
401     NN_LOG("  Total number of vertices to draw = %d\n", s_ColumnCubeNum * s_RowCubeNum * 24);
402     NN_LOG("  Total number of triangles to draw = %d\n", s_ColumnCubeNum * s_RowCubeNum * 12);
403 }
404 
InitializeShader(void)405 void InitializeShader(void)
406 {
407     s_ProgramId = glCreateProgram();
408 
409     s_ShaderId = glCreateShader(GL_VERTEX_SHADER);
410     nn::fs::FileReader file(L"rom:/shader.shbin");
411     size_t fileSize = file.GetSize();
412     void* buf = s_AppHeap.Allocate(fileSize);
413     s32 read = file.Read(buf, fileSize);
414     glShaderBinary(1, &s_ShaderId, GL_PLATFORM_BINARY_DMP, buf, read);
415     file.Finalize();
416     s_AppHeap.Free(buf);
417 
418     glAttachShader(s_ProgramId, s_ShaderId);
419 
420     glAttachShader(s_ProgramId, GL_DMP_FRAGMENT_SHADER_DMP);
421     glBindAttribLocation(s_ProgramId, 0, "aPosition");
422     glBindAttribLocation(s_ProgramId, 1, "aColor");
423     glBindAttribLocation(s_ProgramId, 2, "aNormal");
424 
425     glLinkProgram(s_ProgramId);
426     glValidateProgram(s_ProgramId);
427 
428     demo::InitializeUniforms(s_ProgramId);
429 }
430 
Finalize(void)431 void Finalize(void)
432 {
433     for (u32 j = 0; j < s_ColumnCubeNum; j++)
434     {
435         for (u32 i = 0; i < s_RowCubeNum; i++)
436         {
437             s_Cube[i][j].Finalize();
438         }
439     }
440 
441     s_RenderSystem.Finalize();
442 
443     s_AppHeap.Free(reinterpret_cast<void*>(s_AddrForGxHeap));
444     s_AppHeap.Finalize();
445 }
446 
DrawFrame(void)447 bool DrawFrame(void)
448 {
449     static f32 totalStoreTime = 0.0f;
450     static f32 totalRenderTime = 0.0f;
451     static f32 totalFrameTime = 0.0f;
452     static u32 count = 0;
453 
454     s_FrameStartTick = nn::os::Tick::GetSystemCurrent();
455 
456     UpdateCamera();
457     DrawDisplay0();
458     DrawDisplay1();
459 
460     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
461 
462     s_FrameEndTick = nn::os::Tick::GetSystemCurrent();
463 
464     nn::fnd::TimeSpan storeTimeSpan = s_StoreTick - s_FrameStartTick;
465     totalStoreTime += storeTimeSpan.GetMicroSeconds();
466 
467     nn::fnd::TimeSpan renderTimeSpan = s_RenderTick - s_StoreTick;
468     totalRenderTime += renderTimeSpan.GetMicroSeconds();
469 
470     nn::fnd::TimeSpan frameTimeSpan = s_FrameEndTick - s_FrameStartTick;
471     totalFrameTime += frameTimeSpan.GetMicroSeconds();
472 
473     if ( count >= s_MaxCount )
474     {
475         NN_UNUSED_VAR(totalStoreTime);
476         NN_UNUSED_VAR(totalRenderTime);
477         NN_UNUSED_VAR(totalFrameTime);
478 
479         f32 storeTime = totalStoreTime / static_cast<f32>( s_MaxCount );
480         f32 renderTime = totalRenderTime / static_cast<f32>( s_MaxCount );
481         f32 frameTime = totalFrameTime / static_cast<f32>( s_MaxCount );
482 
483         NN_UNUSED_VAR(storeTime);
484         NN_UNUSED_VAR(renderTime);
485         NN_UNUSED_VAR(frameTime);
486 
487         NN_LOG("\n");
488         NN_LOG("Average storeTime  = %f (usec)\n", storeTime);
489         NN_LOG("Average renderTime = %f (usec)\n", renderTime);
490         NN_LOG("Average frameTime  = %f (usec)\n", frameTime);
491 
492         count = 0;
493 
494         totalStoreTime = 0.0f;
495         totalRenderTime = 0.0f;
496         totalFrameTime = 0.0f;
497     }
498     else
499     {
500         count += 1;
501     }
502 
503     return true;
504 }
505 
UseShader(void)506 void UseShader(void)
507 {
508     glUseProgram(s_ProgramId);
509 
510     // Fragment uniform
511     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_ALPHA_TEST], GL_FALSE);
512 
513     // Fragment uniform : Texture samplerType
514     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE0_SAMPLER_TYPE], GL_FALSE);
515     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE1_SAMPLER_TYPE], GL_FALSE);
516     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE2_SAMPLER_TYPE], GL_FALSE);
517     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXTURE3_SAMPLER_TYPE], GL_FALSE);
518 
519     // Fragment uniform : Fragment lighting
520     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_ENABLED], GL_TRUE);
521     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHTING_AMBIENT], 1, s_GlobalAmbientLight);
522     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_ENABLED], GL_TRUE);
523     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_AMBIENT], 1, s_Light0Ambient);
524     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_DIFFUSE], 1, s_Light0Diffuse);
525     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_LIGHT_SOURCE0_POSITION], 1, s_Light0Position);
526 
527     // Fragment uniform : Material
528     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_AMBIENT], 1, s_MaterialAmbient);
529     glUniform4fv(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_FRAGMENT_MATERIAL_DIFFUSE], 1, s_MaterialDiffuse);
530 
531     // Fragment uniform : Texture combiner
532     //   Modulate fragment primary color and vertex color.
533     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_RGB],
534         GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_PRIMARY_COLOR, GL_PREVIOUS);
535     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_SRC_ALPHA],
536         GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PREVIOUS);
537     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_RGB],
538         GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
539     glUniform3i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_OPERAND_ALPHA],
540         GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
541     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_RGB],
542         GL_MODULATE);
543     glUniform1i(demo::s_UniformLocations[demo::FRAGMENT_UNIFORM_TEXENV2_COMBINE_ALPHA],
544         GL_MODULATE);
545 }
546 
UpdateCamera(void)547 void UpdateCamera(void)
548 {
549     nn::math::MTX34LookAt(&s_ViewMatrix, &s_CameraPosition, &s_CameraUp, &s_CameraTarget);
550 }
551 
DrawDisplay0(void)552 void DrawDisplay0(void)
553 {
554     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
555     s_RenderSystem.Clear();
556 
557     UseShader();
558 
559     glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_PROJECTION],
560         1, GL_TRUE, static_cast<f32*>(s_Display0ProjectionMatrix));
561 
562     for (u32 i = 0; i < s_RowCubeNum; i++)
563     {
564         for (u32 j = 0; j < s_ColumnCubeNum; j++)
565         {
566             DrawBody(s_Cube[i][j]);
567         }
568     }
569 
570     s_StoreTick = nn::os::Tick::GetSystemCurrent();
571 
572     s_RenderSystem.SwapBuffers();
573 }
574 
DrawDisplay1(void)575 void DrawDisplay1(void)
576 {
577     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
578     s_RenderSystem.Clear();
579 
580     s_RenderSystem.SwapBuffers();
581 }
582 
DrawBody(demo::Body & body)583 void DrawBody(demo::Body& body)
584 {
585     nn::math::MTX44 modelViewMatrix(s_ViewMatrix);
586     nn::math::Matrix44 worldMatrix = body.GetWorldMatrix();
587     nn::math::MTX44Mult(&modelViewMatrix, &modelViewMatrix, &worldMatrix);
588     glUniformMatrix4fv(demo::s_UniformLocations[demo::VERTEX_UNIFORM_MODELVIEW],
589         1, GL_TRUE, static_cast<f32*>(modelViewMatrix));
590 
591     body.Draw();
592 }
593 
nnMain(void)594 void nnMain(void)
595 {
596     // Call only nn::applet::Enable to also allow execution from the HOME Menu
597     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
598     nn::applet::Enable();
599 
600     Initialize();
601 
602     bool flag = true;
603     while ( flag )
604     {
605         flag = DrawFrame();
606     }
607 
608     Finalize();
609 }
610