1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     gx_TriangleSimpleCmd.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.h>
17 #include <nn/gx.h>
18 #include <nn/math.h>
19 #include <nn/fs.h>
20 #include <nn/os.h>
21 #include <nn/init.h>
22 #include <nn/applet.h>
23 #include <nn/fnd/fnd_ExpHeap.h>
24 
25 #include "nn/gx/CTR/gx_CommandAccess.h"
26 
27 #include "MemoryManager.h"
28 
29 /* Objects for system API */
30 GLuint s_CmdlistID;
31 GLuint s_FramebufferID;
32 GLuint s_RenderbufferID[2];
33 GLuint s_Displaybuffer0ID[2];
34 GLuint s_Displaybuffer1ID[2];
35 GLint s_CurrentDisplaybuffer0 = 0;
36 GLint s_CurrentDisplaybuffer1 = 0;
37 
38 /* buffer id */
39 GLuint s_ArrayBufferID;
40 GLuint s_ElementArrayBufferID;
41 
42 /* ExpHeap for app. */
43 nn::fnd::ExpHeap s_AppHeap;
44 uptr s_HeapForGx;
45 const u32 s_GxHeapSize = 0x400000;
46 
47 GLfloat* s_VertexArray = NULL;
48 GLushort* s_IndexArray = NULL;
49 
50 u32 s_VertexAttributeBaseAddress = 0x0;
51 u32 s_VertexAttribute0AddressOffset = 0x0;
52 u32 s_VertexAttribute1AddressOffset = 0x0;
53 u32 s_VertexIndexAddressOffset = 0x0;
54 u32 s_VertexNum = 3;
55 u32 s_IndexNum = 3;
56 
57 const u32 FRAME_COUNTER_THRE = 60;
58 u32 s_FrameCount = 0;
59 
60 
61 
62 int Initialize(void);
63 void InitializeGraphics(void);
64 void AddDepthBufferCommand(void);
65 void InitializeVBO(void);
66 
67 int DrawFrame(void);
68 void DrawFrameUpper(void);
69 void DrawFrameLower(void);
70 
71 void AddViewportCommand(const s32 display);
72 
73 void AddFirstDrawCommand(void);
74 void AddVertexShaderCommand(void);
75 void AddVertexAttributeCommand(void);
76 void AddVertexShaderUniformCommand(void);
77 void AddTextureCombinerCommand(void);
78 
79 void AddDrawTriangleCommand(void);
80 
81 void AddFrameBufferControlCommand(void);
82 
Initialize(void)83 int Initialize(void)
84 {
85 
86     // fs initialization
87     nn::fs::Initialize();
88 
89     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
90     static char buffer[ROMFS_BUFFER_SIZE];
91     NN_UTIL_PANIC_IF_FAILED(
92         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
93 
94     s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() );
95     s_HeapForGx = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
96 
97     InitializeGraphics();
98 
99     return 0;
100 }
101 
InitializeGraphics(void)102 void InitializeGraphics(void)
103 {
104     demo::InitializeMemoryManager(s_HeapForGx, s_GxHeapSize);
105     nngxInitialize(demo::GetAllocator, demo::GetDeallocator);
106 
107     /* Generate and allocate command list object */
108     nngxGenCmdlists(1, &s_CmdlistID);
109     nngxBindCmdlist(s_CmdlistID);
110     nngxCmdlistStorage(0x40000, 128);
111 
112     /* Generate, allocate and attach framebuffer object and render buffer */
113     glGenFramebuffers(1, &s_FramebufferID);
114     glBindFramebuffer(GL_FRAMEBUFFER, s_FramebufferID);
115 
116     glGenRenderbuffers(2, s_RenderbufferID);
117     glBindRenderbuffer(GL_RENDERBUFFER, s_RenderbufferID[0]);
118     glRenderbufferStorage(GL_RENDERBUFFER | NN_GX_MEM_VRAMA, GL_RGBA8_OES,
119                           nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT);
120     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, s_RenderbufferID[0]);
121 
122     glBindRenderbuffer(GL_RENDERBUFFER, s_RenderbufferID[1]);
123     glRenderbufferStorage(GL_RENDERBUFFER | NN_GX_MEM_VRAMB, GL_DEPTH24_STENCIL8_EXT,
124                           nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT);
125     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, s_RenderbufferID[1]);
126 
127     /* Generate and allocate display buffer; set display region */
128     nngxGenDisplaybuffers(2, s_Displaybuffer0ID);
129     nngxActiveDisplay(NN_GX_DISPLAY0);
130     nngxDisplayEnv(0, 0);
131     nngxBindDisplaybuffer(s_Displaybuffer0ID[0]);
132     nngxDisplaybufferStorage(GL_RGB8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, NN_GX_MEM_FCRAM);
133 
134     nngxBindDisplaybuffer(s_Displaybuffer0ID[1]);
135     nngxDisplaybufferStorage(GL_RGB8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, NN_GX_MEM_FCRAM);
136 
137     nngxGenDisplaybuffers(2, s_Displaybuffer1ID);
138     nngxActiveDisplay(NN_GX_DISPLAY1);
139     nngxDisplayEnv(0, 0);
140     nngxBindDisplaybuffer(s_Displaybuffer1ID[0]);
141     nngxDisplaybufferStorage(GL_RGB8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, NN_GX_MEM_FCRAM);
142 
143     nngxBindDisplaybuffer(s_Displaybuffer1ID[1]);
144     nngxDisplaybufferStorage(GL_RGB8_OES, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, NN_GX_MEM_FCRAM);
145 
146     nngxRunCmdlist();
147 
148     glClearColor(0.36f, 0.42f, 0.5f, 1.0f);
149     glClearDepthf(1.f);
150 
151     AddDepthBufferCommand();
152 
153     glFrontFace(GL_CCW);
154 
155     InitializeVBO();
156 }
157 
AddDepthBufferCommand(void)158 void AddDepthBufferCommand(void)
159 {
160     /*
161     glEnable(GL_DEPTH_TEST);
162     glDepthFunc(GL_LESS);
163     */
164 
165     u32 commandBuffer[] =
166     {
167         // Depth test
168         // 0x107
169         PICA_CMD_DATA_DEPTH_COLOR_MASK(
170             // enableDepthTest
171             1,
172             // depthFunc
173             PICA_DATA_DEPTH_TEST_LESS,
174             // red, green, blue, alpha
175             0, 0, 0, 0,
176             // depthMask
177             0),
178         PICA_CMD_HEADER_SINGLE_BE(PICA_REG_DEPTH_COLOR_MASK, 0x1),
179 
180         // dmp_Gas.deltaZ
181         // 0x126 [25:24]
182         PICA_CMD_DATA_GAS_DELTAZ_DEPTH(0, PICA_DATA_DEPTH_TEST2_OTHER),
183         PICA_CMD_HEADER_SINGLE_BE(PICA_REG_GAS_DELTAZ_DEPTH, 0x8),
184     };
185 
186     nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
187 }
188 
InitializeVBO(void)189 void InitializeVBO(void)
190 {
191     GLenum arrayFlag        = GL_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP;
192     GLenum elementArrayFlag = GL_ELEMENT_ARRAY_BUFFER | NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP;
193 
194     u32 positionSize = sizeof(GLfloat) * s_VertexNum * 4;
195     u32 colorSize = sizeof(GLfloat) * s_VertexNum * 3;
196     u32 indexSize = sizeof(GLushort) * s_IndexNum;
197 
198     s_VertexArray = (GLfloat*) demo::Alloc(NN_GX_MEM_VERTEXBUFFER, positionSize + colorSize);
199     u32 vertexArrayPhysicalAddress = nngxGetPhysicalAddr( (uptr) s_VertexArray );
200     // NN_LOG("s_VertexArray = 0x%x, Physical address = 0x%p\n", s_VertexArray, vertexArrayPhysicalAddress);
201 
202     /*
203     GLfloat coords[] =
204     {
205          0.5f, 0.0f, 0.f, 1.f,
206         -0.5f, 0.5f, 0.f, 1.f,
207         -0.5f,-0.5f, 0.f, 1.f
208     };
209     */
210 
211     s_VertexArray[ 0 ]  = 0.5f;
212     s_VertexArray[ 1 ]  = 0.0f;
213     s_VertexArray[ 2 ]  = 0.0f;
214     s_VertexArray[ 3 ]  = 1.0f;
215 
216     s_VertexArray[ 4 ]  = -0.5f;
217     s_VertexArray[ 5 ]  =  0.5f;
218     s_VertexArray[ 6 ]  =  0.0f;
219     s_VertexArray[ 7 ]  =  1.0f;
220 
221     s_VertexArray[ 8 ]  = -0.5f;
222     s_VertexArray[ 9 ]  = -0.5f;
223     s_VertexArray[ 10 ] =  0.0f;
224     s_VertexArray[ 11 ] =  1.0f;
225 
226     /*
227     GLfloat color[] =
228     {
229         1.f, 1.0f, 0.0f,
230         0.f, 1.0f, 0.0f,
231         0.f, 0.0f, 1.0f
232     };
233     */
234 
235     const u32 offset = 12;
236     s_VertexArray[ offset + 0 ] = 1.0f;
237     s_VertexArray[ offset + 1 ] = 0.0f;
238     s_VertexArray[ offset + 2 ] = 0.0f;
239 
240     s_VertexArray[ offset + 3 ] = 0.0f;
241     s_VertexArray[ offset + 4 ] = 1.0f;
242     s_VertexArray[ offset + 5 ] = 0.0f;
243 
244     s_VertexArray[ offset + 6 ] = 0.0f;
245     s_VertexArray[ offset + 7 ] = 0.0f;
246     s_VertexArray[ offset + 8 ] = 1.0f;
247 
248     s_IndexArray = (GLushort*) demo::Alloc(NN_GX_MEM_VERTEXBUFFER, indexSize);
249     u32 indexArrayPhysicalAddress = nngxGetPhysicalAddr( (uptr) s_IndexArray);
250 
251     // NN_LOG("s_IndexArray = 0x%x, physical address = 0x%p\n", s_IndexArray, indexArrayPhysicalAddress);
252 
253     /*
254     GLushort idxs[] = {0, 1, 2};
255     */
256     s_IndexArray[ 0 ] = 0;
257     s_IndexArray[ 1 ] = 1;
258     s_IndexArray[ 2 ] = 2;
259 
260     glGenBuffers(1, &s_ArrayBufferID);
261     glBindBuffer(GL_ARRAY_BUFFER, s_ArrayBufferID);
262     glBufferData(arrayFlag, positionSize + colorSize, s_VertexArray, GL_STATIC_DRAW);
263 
264     glGenBuffers(1, &s_ElementArrayBufferID);
265     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_ElementArrayBufferID);
266     glBufferData(elementArrayFlag, indexSize, s_IndexArray, GL_STATIC_DRAW);
267 
268     // Base address is aligned to 16 bytes
269     u32 alignOffset = (uptr)vertexArrayPhysicalAddress % 16;
270     u32 baseAddress = vertexArrayPhysicalAddress - alignOffset;
271 
272     s_VertexAttributeBaseAddress = PICA_CMD_DATA_VERTEX_ATTR_ARRAYS_BASE_ADDR(baseAddress);
273     s_VertexAttribute0AddressOffset = vertexArrayPhysicalAddress - baseAddress;
274     s_VertexAttribute1AddressOffset = alignOffset + positionSize;
275     s_VertexIndexAddressOffset = indexArrayPhysicalAddress - baseAddress;
276 }
277 
278 
279 
DrawFrame(void)280 int DrawFrame(void)
281 {
282     DrawFrameUpper();
283     DrawFrameLower();
284 
285     nngxActiveDisplay(NN_GX_DISPLAY0);
286     nngxBindDisplaybuffer(s_Displaybuffer0ID[s_CurrentDisplaybuffer0]);
287 
288     nngxActiveDisplay(NN_GX_DISPLAY1);
289     nngxBindDisplaybuffer(s_Displaybuffer1ID[s_CurrentDisplaybuffer1]);
290 
291     nngxSwapBuffers(NN_GX_DISPLAY_BOTH);
292 
293     s_CurrentDisplaybuffer0 = (s_CurrentDisplaybuffer0 == 0 ? 1 : 0);
294     s_CurrentDisplaybuffer1 = (s_CurrentDisplaybuffer1 == 0 ? 1 : 0);
295 
296     nngxClearCmdlist();
297     nngxRunCmdlist();
298 
299     nngxWaitVSync(NN_GX_DISPLAY_BOTH);
300 
301     if ( s_FrameCount == 0 )
302     {
303         nngxStartLcdDisplay();
304     }
305 
306     if ( ( s_FrameCount % FRAME_COUNTER_THRE) == 0 )
307     {
308         NN_LOG("Total frame count = %d\n", s_FrameCount);
309     }
310 
311     s_FrameCount += 1;
312 
313     return 1;
314 }
315 
DrawFrameUpper(void)316 void DrawFrameUpper(void)
317 {
318     static bool firstFlag = true;
319 
320     AddViewportCommand(NN_GX_DISPLAY0);
321     glBindFramebuffer(GL_FRAMEBUFFER, s_FramebufferID);
322     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
323 
324     if ( firstFlag )
325     {
326         AddFirstDrawCommand();
327         firstFlag = false;
328     }
329 
330     AddDrawTriangleCommand();
331 
332     nngxSplitDrawCmdlist();
333     nngxRunCmdlist();
334     nngxWaitCmdlistDone();
335 
336     nngxTransferRenderImage(s_Displaybuffer0ID[s_CurrentDisplaybuffer0], NN_GX_ANTIALIASE_NOT_USED, GL_FALSE, 0, 0);
337 }
338 
DrawFrameLower(void)339 void DrawFrameLower(void)
340 {
341     // Just clear the lower screen; do not render anything
342     AddViewportCommand(NN_GX_DISPLAY1);
343     glBindFramebuffer(GL_FRAMEBUFFER, s_FramebufferID);
344     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
345     nngxTransferRenderImage(s_Displaybuffer1ID[s_CurrentDisplaybuffer1], NN_GX_ANTIALIASE_NOT_USED, GL_FALSE, 0, 0);
346 
347     nngxRunCmdlist();
348     nngxWaitCmdlistDone();
349 }
350 
AddViewportCommand(s32 display)351 void AddViewportCommand(s32 display)
352 {
353     if ( display == NN_GX_DISPLAY0 )
354     {
355         // glViewport(0, 0, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT);
356         u32 commandBuffer[] =
357         {
358             // Set the Viewport width (set width to f32, divide by two, and convert to f24)
359             // 0x41
360             0x45E000, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_WIDTH1),
361 
362             // Set the Viewport height (set height to f32, divide by two, and convert to f24)
363             // 0x43
364             0x469000, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_HEIGHT1),
365 
366             // Set Viewport width (Divide 2 by width, convert to f31, and shift 1 bit left)
367             // 0x42
368             0x38111111, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_WIDTH2),
369 
370             // Set Viewport height (Divide 2 by height, convert to f31, and shift 1 bit left)
371             // 0x44
372             0x3747AE14, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_HEIGHT2),
373 
374             // x = 0, y = 0
375             // 0x68
376             PICA_CMD_DATA_VIEWPORT_XY(0, 0),  PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_XY)
377         };
378 
379         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
380     }
381     else if ( display == NN_GX_DISPLAY1 )
382     {
383         // glViewport(0, 0, nn::gx::DISPLAY1_WIDTH, nn::gx::DISPLAY1_HEIGHT);
384         u32 commandBuffer[] =
385         {
386             // Set the Viewport width (set width to f32, divide by two, and convert to f24)
387             // 0x41
388             0x45E000, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_WIDTH1),
389 
390             // Set the Viewport height (set height to f32, divide by two, and convert to f24)
391             // 0x43
392             0x464000, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_HEIGHT1),
393 
394             // Set Viewport width (Divide 2 by width, convert to f31, and shift 1 bit left)
395             // 0x42
396             0x38111111, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_WIDTH2),
397 
398             // Set Viewport height (Divide 2 by height, convert to f31, and shift 1 bit left)
399             // 0x44
400             0x37999999, PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_HEIGHT2),
401 
402             // x = 0, y = 0
403             // 0x68
404             PICA_CMD_DATA_VIEWPORT_XY(0, 0),  PICA_CMD_HEADER_SINGLE(PICA_REG_VIEWPORT_XY)
405         };
406 
407         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
408     }
409 }
410 
AddFirstDrawCommand(void)411 void AddFirstDrawCommand(void)
412 {
413     AddVertexShaderCommand();
414     AddVertexAttributeCommand();
415 
416     AddVertexShaderUniformCommand();
417 
418     AddTextureCombinerCommand();
419 }
420 
AddVertexShaderCommand(void)421 void AddVertexShaderCommand(void)
422 {
423     /*
424     s_PgID = glCreateProgram();
425     s_ShID = glCreateShader(GL_VERTEX_SHADER);
426 
427     nn::fs::FileReader file(L"rom:/shader.shbin");
428     size_t fileSize = file.GetSize();
429     void* buf = s_AppHeap.Allocate(fileSize);
430 
431     s32 read = file.Read(buf, fileSize);
432     glShaderBinary(1, &s_ShID, GL_PLATFORM_BINARY_DMP, buf, read);
433     file.Finalize();
434     s_AppHeap.Free(buf);
435 
436     glAttachShader(s_PgID, s_ShID);
437     glAttachShader(s_PgID, GL_DMP_FRAGMENT_SHADER_DMP);
438 
439     glBindAttribLocation(s_PgID, 0, "aPosition");
440     glBindAttribLocation(s_PgID, 1, "aColor");
441 
442     glLinkProgram(s_PgID);
443     glValidateProgram(s_PgID);
444     glUseProgram(s_PgID);
445     */
446 
447     {
448         u32 commandBuffer[] =
449         {
450             // Do not use geometry shader
451             // 0x229
452             PICA_CMD_SET_VS_GS_MODE(0x0, 0x0),
453             // Do not use geometry shader
454             // 0x244 : 0x0 (BE 0x1)
455             PICA_CMD_SET_VS_COM_MODE(0x0),
456             // Set the load address for the vertex shader program code to 0
457             // 0x2CB : 0x0 (BE 0xF)
458             PICA_CMD_DATA_VS_PROG_ADDR(0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_PROG_ADDR)
459         };
460 
461         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
462     }
463 
464     {
465         // Vertex shader program data
466         u32 commandBuffer[] =
467         {
468             // BurstSingle (13 times, BE 0xF)
469             // 0x2CC : 0xBE24000
470             0xBE24000, PICA_CMD_HEADER_BURST(PICA_REG_VS_PROG_DATA0, 13),
471             // 0x2CC : 0xBE25001
472             // 0x2CC : 0xBE26002
473             0xBE25001, 0xBE26002,
474             // 0x2CC : 0xBE27003
475             // 0x2CC : 0x8020F80
476             0xBE27003, 0x8020F80,
477             // 0x2CC : 0x8021F81
478             // 0x2CC : 0x8022F82
479             0x8021F81, 0x8022F82,
480             // 0x2CC : 0x8023F83
481             // 0x2CC : 0x84000000
482             0x8023F83, 0x84000000,
483             // 0x2CC : 0x90000008
484             // 0x2CC :0x4C201004
485             0x90000008, 0x4C201004,
486             // 0x2CC : 0x88000000
487             // 0x2CC : 0x84000000
488             0x88000000, 0x84000000
489         };
490 
491         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
492     }
493 
494     {
495         // Notification that update of vertex shader program is complete
496         u32 commandBuffer[] =
497         {
498             // 0x2BF : 0x1 (BE 0xF)
499             PICA_CMD_DATA_VS_PROG_END(0x1), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_PROG_UPDATE_END)
500         };
501 
502         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
503     }
504 
505     {
506         // Swizzle
507         u32 commandBuffer[] =
508         {
509             // Set the Swizzle pattern's load address to 0
510             // 0x2D5 : 0x0 (BE 0xF)
511             PICA_CMD_DATA_VS_PROG_SWIZZLE_ADDR(0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_PROG_SWIZZLE_ADDR),
512 
513             // Set the Swizzle pattern's data
514             // BurstSingle (5 times, BE 0xF)
515             // 0x2D6 : 0x8006C368
516             PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C368), PICA_CMD_HEADER_BURST(PICA_REG_VS_PROG_SWIZZLE_DATA0, 5),
517             // 0x2D6 : 0x8006C364
518             // 0x2D6 : 0x8006C362
519             PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C364), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C362),
520             // 0x2D6 : 0x8006C361
521             // 0x2D6 : 0x8000036F
522             PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8006C361), PICA_CMD_DATA_VS_PROG_SWIZZLE_DATA(0x8000036F)
523         };
524 
525         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
526     }
527 }
528 
AddVertexAttributeCommand(void)529 void AddVertexAttributeCommand(void)
530 {
531     {
532         u32 commandBuffer[] =
533         {
534             // BurstSequence (39 times, BE 0xF)
535 
536             // Common base address for all vertex arrays
537             // 0x200 : BaseAddress
538             s_VertexAttributeBaseAddress, PICA_CMD_HEADER_BURSTSEQ(PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, 39),
539 
540             // 0x201 : 0xBFF
541             //   Attribute0  [3:0] 0xF : size=4, GL_FLOAT
542             //   Attribute1 [7:4] 0xB : size=3, GL_FLOAT
543             //
544             // 0x202 : 0x10000000
545             //   [31:28] TotalVertexAttributeNum - 1
546             0xBF, 0x10000000,
547 
548             // 0x203 : 0x0
549             //   Byte offset from the the base address of load array 0
550             //
551             // 0x204 : 0x0
552             //   [3:0] The 1st element of load array 0 is internal vertex attribute 0
553             s_VertexAttribute0AddressOffset, 0x0,
554 
555             // 0x205 : 0x10100000
556             //   [23:16] : Number of bytes per vertex in load array 0: 16 (Bytes)
557             //   [31:28] : Number of elements in load array 0: 1
558             //
559             // 0x206 : 0x30
560             //   Byte offset from the the base address of load array 1
561             0x10100000, s_VertexAttribute1AddressOffset,
562 
563             // 0x207 : 0x1
564             //   [3:0] The 1st element of load array 1 is internal vertex attribute 1
565             //
566             // 0x208 : 0x100C0000
567             //   [23:16] : Number of bytes per vertex in load array 1: 12 (Bytes)
568             //   [31:28] : Number of elements in load array 1: 1
569             0x1, 0x100C0000,
570 
571             // 0x209 : 0x0
572             // 0x20A : 0x0
573             0x0, 0x0,
574 
575             // 0x20B : 0x0
576             // 0x20C : 0x0
577             0x0, 0x0,
578 
579             // 0x20D : 0x0
580             // 0x20E : 0x0
581             0x0, 0x0,
582 
583             // 0x20F : 0x0
584             // 0x210 : 0x0
585             0x0, 0x0,
586 
587             // 0x211 : 0x0
588             // 0x212 : 0x0
589             0x0, 0x0,
590 
591             // 0x213 : 0x0
592             // 0x214 : 0x0
593             0x0, 0x0,
594 
595             // 0x215 : 0x0
596             // 0x216 : 0x0
597             0x0, 0x0,
598 
599             // 0x217 : 0x0
600             // 0x218 : 0x0
601             0x0, 0x0,
602 
603             // 0x219 : 0x0
604             // 0x21A : 0x0
605             0x0, 0x0,
606 
607             // 0x21B : 0x0
608             // 0x21C : 0x0
609             0x0, 0x0,
610 
611             // 0x21D : 0x0
612             // 0x21E : 0x0
613             0x0, 0x0,
614 
615             // 0x21F : 0x0
616             // 0x220 : 0x0
617             0x0, 0x0,
618 
619             // 0x221 : 0x0
620             // 0x222 : 0x0
621             0x0, 0x0,
622 
623             // 0x223 : 0x0
624             // 0x224 : 0x0
625             0x0, 0x0,
626 
627             // 0x225 : 0x0
628             // 0x226 : 0x0
629             0x0, 0x0
630         };
631 
632         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
633     }
634 
635     {
636         u32 commandBuffer[] =
637         {
638             // 0x2BB : 0x10 (BE 0xF)
639             // Register that sets the input register map for vertex attributes 0-8
640             //   [3:0] = 0 (The index of the input register for the storage location of the first vertex attribute that was input)
641             //   [7:4] = 1 (The index of the input register for the storage location of the second vertex attribute that was input)
642             PICA_CMD_DATA_VS_ATTR_IN_REG_MAP0(0, 1, 0, 0, 0, 0, 0, 0),
643             PICA_CMD_HEADER_SINGLE(PICA_REG_VS_ATTR_IN_REG_MAP0),
644 
645             // 0x2BC : 0x0 (BE 0xF)
646             // Register that sets the input register map for vertex attributes 9-12
647             PICA_CMD_DATA_VS_ATTR_IN_REG_MAP1(0, 0, 0, 0),
648             PICA_CMD_HEADER_SINGLE(PICA_REG_VS_ATTR_IN_REG_MAP1)
649         };
650 
651         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
652     }
653 
654     {
655         u32 commandBuffer[] =
656         {
657             // Register that sets the number of vertex attribute inputs.
658             //
659             // 0x2B9 : 0xA0000000 | 0x1, (BE 0xB = 1011(2) )
660             // PICA_CMD_DATA_VS_ATTR_NUM0(0x2), PICA_CMD_HEADER_SINGLE_BE(PICA_REG_VS_ATTR_NUM0, 0xB),
661             //
662             // 0x242 : 0x1 (BE 0xF)
663             // PICA_CMD_DATA_VS_ATTR_NUM1(0x2), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_ATTR_NUM1)
664             PICA_CMD_SET_VS_ATTR_NUM( 0x2 ),
665 
666             // Register that sets the number of vertex attributes to input to the vertex shader
667             //
668             // 0x4F : 0x2
669             // 0x2, PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_NUM0)
670             //
671             // 0x24A : 0x1 (BE 0xF)
672             // 0x1, PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_NUM1),
673             //
674             // 0x251 [3:0] : 0x2 (BE 0xF)
675             // 0x1, PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_NUM2),
676             PICA_CMD_SET_VS_GS_OUT_REG_NUM( 0x2 ),
677 
678             // 0x2BA [15:0]  : Sets the data address of the vertex shader
679             //       [31:16] : Sets 0x7FFF
680             // 0x7FFF0009 (BE 0xF)
681             PICA_CMD_DATA_VS_START_ADDR(0x9), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_START_ADDR),
682 
683             // 0x2BD : 0x3 (BE 0xF)
684             // Set the mask for the vertex shader output register (o0 = [0:0], o1 = [1;1])
685             PICA_CMD_DATA_VS_OUT_MASK(0x3), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_REG_MASK),
686 
687             // Register that sets the vertex shader output attribute
688             // 0x50 : 0x3020100 (BE 0xF)
689             // #pragma output_map ( position, o0 )
690             //   [ 4: 0] : Vertex coordinate x, 0x00
691             //   [12: 8] : Vertex coordinate y, 0x01
692             //   [20:16] : Vertex coordinate z, 0x02
693             //   [28:24] : Vertex coordinate w, 0x03
694             PICA_CMD_DATA_VS_GS_OUT_ATTR(PICA_DATA_VS_OUT_ATTR_X,
695                 PICA_DATA_VS_OUT_ATTR_Y, PICA_DATA_VS_OUT_ATTR_Z,
696                 PICA_DATA_VS_OUT_ATTR_W),
697             PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_ATTR0),
698 
699             // Register that sets the vertex shader output attribute
700             // 0x51 : 0xB0A0908 (BE 0xF)
701             // #pragma output_map (color, o1)
702             //   [ 4: 0] : Vertex color R, 0x08
703             //   [12: 8] : Vertex color G, 0x09
704             //   [20:16] : Vertex color B, 0x0a
705             //   [28:24] : Vertex color A, 0x0b
706             PICA_CMD_DATA_VS_GS_OUT_ATTR(PICA_DATA_VS_OUT_ATTR_R,
707                 PICA_DATA_VS_OUT_ATTR_G, PICA_DATA_VS_OUT_ATTR_B,
708                 PICA_DATA_VS_OUT_ATTR_A),
709             PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_ATTR1),
710 
711             // Clock control setting register for output attributes from the vertex shader
712             // 0x6F : 0x3 (BE 0xF)
713             // Output the vertex's z coordinate; output the vertex color
714             PICA_CMD_DATA_VS_GS_OUT_ATTR_CLK(1, 1, 0, 0, 0, 0, 0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_OUT_ATTR_CLK)
715         };
716 
717         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
718     }
719 }
720 
AddVertexShaderUniformCommand(void)721 void AddVertexShaderUniformCommand(void)
722 {
723     /*
724     // Upper screen vertex uniform settings
725     nn::math::Matrix44 proj;
726     nn::math::MTX44Frustum(&proj, -0.02f, 0.02f, -0.02f*nn::gx::DISPLAY0_HEIGHT/nn::gx::DISPLAY0_WIDTH,
727                  0.02f*nn::gx::DISPLAY0_HEIGHT/nn::gx::DISPLAY0_WIDTH, 0.2f, 10.f);
728     glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uProjection"), 1, GL_TRUE, static_cast<f32*>(proj));
729 
730     nn::math::Matrix34 eye, rot;
731     nn::math::Vector3 camPos(0.f, 0.4f, 9.5f);
732     nn::math::Vector3 camUp(0.f, 1.f, 0.f);
733     nn::math::Vector3 target(0.f, 0.f, 0.f);
734     nn::math::Vector3 rotAxis(0.f, 1.f, 0.f);
735 
736     nn::math::MTX34Identity(&eye);
737     nn::math::MTX34LookAt(&eye, &camPos, &camUp, &target);
738     nn::math::MTX34RotAxisDeg(&rot, &rotAxis, -6.f * 0.0f);
739 
740     nn::math::MTX34Mult(&eye, &eye, &rot);
741     nn::math::Matrix44 mv(eye);
742     glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, (f32*)(mv));
743     */
744 
745     {
746         // Index of floating-point registers for vertex shader
747         u32 commandBuffer[] =
748         {
749             // 0x2C0 : 0x80000000 (BE 0xF)
750             PICA_CMD_DATA_VS_FLOAT_ADDR(PICA_DATA_VS_F32, 0x0),
751             PICA_CMD_HEADER_SINGLE(PICA_REG_VS_FLOAT_ADDR)
752         };
753 
754         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
755     }
756 
757     {
758         // Settings for floating-point registers of the vertex shader
759         u32 commandBuffer[] =
760         {
761             // BurstSingle (32 times, BE 0xF)
762             // 0x2C1 : 0x0
763             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_HEADER_BURST(PICA_REG_VS_FLOAT1, 32),
764 
765             // 0x2C1 : 0x0
766             // 0x2C1 : 0x0
767             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0),
768 
769             // 0x2C1 : 0x41200000
770             // 0x2C1 : 0x0
771             PICA_CMD_DATA_VS_FLOAT(0x41200000), PICA_CMD_DATA_VS_FLOAT(0x0),
772 
773             // 0x2C1 : 0x0
774             // 0x2C1 : 0x40BFFFFF
775             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x40BFFFFF),
776 
777             // 0x2C1 : 0x0
778             // 0x2C1 : 0x3E50FAC6
779             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x3E50FAC6),
780 
781             // 0x2C1 : 0x3F829CBC
782             // 0x2C1 : 0x0
783             PICA_CMD_DATA_VS_FLOAT(0x3F829CBC), PICA_CMD_DATA_VS_FLOAT(0x0),
784 
785             // 0x2C1 : 0x0
786             // 0x2C1 : 0x0
787             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0),
788 
789             // 0x2C1 : 0xBF800000
790             // 0x2C1 : 0x0
791             PICA_CMD_DATA_VS_FLOAT(0xBF800000), PICA_CMD_DATA_VS_FLOAT(0x0),
792 
793             // 0x2C1 : 0x0
794             // 0x2C1 : 0x0
795             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0),
796 
797             // 0x2C1 : 0x0
798             // 0x2C1 : 0x0
799             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0),
800 
801             // 0x2C1 : 0x3F800000
802             // 0x2C1 : 0x0
803             PICA_CMD_DATA_VS_FLOAT(0x3F800000), PICA_CMD_DATA_VS_FLOAT(0x0),
804 
805             // 0x2C1 : 0xBD2C4F7C
806             // 0x2C1 : 0x3F7FC5FC
807             PICA_CMD_DATA_VS_FLOAT(0xBD2C4F7C), PICA_CMD_DATA_VS_FLOAT(0x3F7FC5FC),
808 
809             // 0x2C1 : 0x0
810             // 0x2C1 : 0xC118227B
811             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0xC118227B),
812 
813             // 0x2C1 : 0x3F7FC5FC
814             // 0x2C1 : 0x3D2C4F7C
815             PICA_CMD_DATA_VS_FLOAT(0x3F7FC5FC), PICA_CMD_DATA_VS_FLOAT(0x3D2C4F7C),
816 
817             // 0x2C1 : 0x0
818             // 0x2C1 : 0x3F800000
819             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x3F800000),
820 
821             // 0x2C1 : 0x0
822             // 0x2C1 : 0x0
823             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x0),
824 
825             // 0x2C1 : 0x0, 0x5544
826             PICA_CMD_DATA_VS_FLOAT(0x0), PICA_CMD_DATA_VS_FLOAT(0x5544)
827         };
828 
829         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
830     }
831 
832     {
833         u32 commandBuffer[] =
834         {
835             // Vertex shader Boolean register
836             // 0x2B0 : 0x7FFF0000 (BE 0xF)
837             PICA_CMD_DATA_VS_BOOL(0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_BOOL),
838 
839             // Vertex shader integer register i0
840             // 0x2B1 : 0x0 (BE 0xF)
841             PICA_CMD_DATA_VS_INT(0x0, 0x0, 0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_INT0),
842 
843             // Vertex shader integer register i1
844             // 0x2B2 : 0x0 (BE 0xF)
845             PICA_CMD_DATA_VS_INT(0x0, 0x0, 0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_INT1),
846 
847             // Vertex shader integer register i2
848             // 0x2B3 : 0x0 (BE 0xF)
849             PICA_CMD_DATA_VS_INT(0x0, 0x0, 0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_INT2),
850 
851             // Vertex shader integer register i3
852             // 0x2B4 : 0x0 (BE 0xF)
853             PICA_CMD_DATA_VS_INT(0x0, 0x0, 0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_VS_INT3)
854         };
855 
856         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
857     }
858 }
859 
AddTextureCombinerCommand(void)860 void AddTextureCombinerCommand(void)
861 {
862     {
863         u32 commandBuffer[] =
864         {
865             // 0xc0 + 0
866             // srcRgb, srcAlpha
867             // glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].srcRgb"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR);
868             // glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].srcAlpha"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR);
869             PICA_CMD_DATA_TEX_ENV_SRC(PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR, PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR,
870                                       PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR, PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR,
871                                       PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR, PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR),
872 
873             // 0xc0
874             // Start register of texture combiner 0
875             PICA_CMD_HEADER_BURSTSEQ(PICA_REG_TEX_ENV0, 0x5),
876 
877             // operandRgb, operandAlpha
878             // 0xc0 + 1
879             // glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
880             // glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
881             PICA_CMD_DATA_TEX_ENV_OPERAND(PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR,
882                                           PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA),
883 
884             // combineRgb, combineAlpha
885             // 0xc0 + 2
886             // glUniform1i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].combineRgb"), GL_REPLACE);
887             // glUniform1i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].combineAlpha"), GL_REPLACE);
888             PICA_CMD_DATA_TEX_ENV_COMBINE(PICA_DATA_TEX_ENV_COMBINE_REPLACE, PICA_DATA_TEX_ENV_COMBINE_REPLACE),
889 
890             // constRgba
891             // 0xc0 + 3
892             // glUniform4f(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].constRgba"), 0.0f, 0.0f, 0.0f, 0.0f);
893             PICA_CMD_DATA_TEX_ENV_CONST(0x0, 0x0, 0x0, 0x0),
894 
895             // scaleRgb, scaleAlpha
896             // 0xc0 + 4
897             // glUniform1f(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].scaleRgb"), 1.0f);
898             // glUniform1f(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].scaleAlpha"), 1.0f);
899             PICA_CMD_DATA_TEX_ENV_SCALE(PICA_DATA_TEX_ENV_SCALE_1, PICA_DATA_TEX_ENV_SCALE_1)
900          };
901 
902         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
903     }
904 }
905 
906 
AddDrawTriangleCommand(void)907 void AddDrawTriangleCommand(void)
908 {
909     AddFrameBufferControlCommand();
910 
911     {
912         u32 commandBuffer[] =
913         {
914             // 0x229
915             // Using glDrawElements function and GL_TRIANGLES, so drawMode = 1
916             PICA_CMD_SET_DRAW_MODE0( 1 )
917         };
918 
919         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
920     }
921 
922     {
923         u32 commandBuffer[] =
924         {
925             // 0x253 [0:8]
926             // Using glDrawElements function and GL_TRIANGLES, so [8:8] = 1
927             0x100,
928             PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE1, 0x2 ),
929 
930             // 0x25e [9:8]
931             // Using glDrawElements function and mode = GL_TRIANGLES, so [9:8] = PICA_DATA_DRAW_TRIANGLES = 3
932             PICA_CMD_SET_DRAW_MODE2( PICA_DATA_DRAW_TRIANGLES ),
933 
934             // Clear the internal states of vertex indices when drawing triangles
935             // 0x25f
936             PICA_CMD_DATA_START_DRAW_FUNC1(0x1),
937             PICA_CMD_HEADER_SINGLE(PICA_REG_START_DRAW_FUNC1),
938 
939             // 0x253[0:0] is set equal to 0 when nngxInitialize() is run, so this is unnecessary.
940             // 0x253 [0:0]
941             // Using vertex buffer and glDrawElements function, so [0:0] = 0
942             // PICA_CMD_DATA_DRAW_MODE1(0x0, 0x0),
943             // PICA_CMD_HEADER_SINGLE_BE(PICA_REG_DRAW_MODE1, 0x1),
944 
945             // 0x227 [27:0]
946             // Vertex index address offset
947             // Vertex index type is GL_UNSIGNED_SHORT, so [31:31] = 1
948             PICA_CMD_DATA_INDEX_ARRAY_ADDR_OFFSET(s_VertexIndexAddressOffset, PICA_DATA_INDEX_ARRAY_UNSIGNED_SHORT),
949             PICA_CMD_HEADER_SINGLE(PICA_REG_INDEX_ARRAY_ADDR_OFFSET),
950 
951             // 0x228 [31:0]
952             // Set the number of vertices to render: 3
953             s_IndexNum, PICA_CMD_HEADER_SINGLE(PICA_REG_DRAW_VERTEX_NUM),
954 
955             // Render kick command macro
956             // 1. Set to 0 immediately before Draw
957             //    0x245 = 0x0
958             // 2. Render kick command
959             //    0x22f = Write 1 to any bit
960             // 3. Set to 1 immediately after Draw
961             //    0x245 = 0x1
962             // 4. Immediately after the render kick command, clear the vertex cache.
963             //    0x231 = 0x1
964             PICA_CMD_SET_START_DRAW_ELEMENT(1),
965 
966             // Immediately after the render kick command, clear both color buffer and depth buffer caches.
967             PICA_CMD_SET_COLOR_DEPTH_BUFFER_CLEAR(0x1, 0x1),
968         };
969 
970         nngxAdd3DCommand(commandBuffer, sizeof(commandBuffer), GL_TRUE);
971     }
972 }
973 
AddFrameBufferControlCommand(void)974 void AddFrameBufferControlCommand(void)
975 {
976     {
977         u32 cmdbuf[] =
978         {
979             // Clear the color buffer and depth buffer caches.
980             PICA_CMD_SET_COLOR_DEPTH_BUFFER_CLEAR(0x1, 0x1),
981 
982             // To disable color buffer read, set to 0
983             // 0x112 [3:0]
984             PICA_CMD_DATA_FRAME_BUFFER_MODE(0x0), PICA_CMD_HEADER_SINGLE(PICA_REG_COLOR_BUFFER_READ),
985 
986             // To enable color buffer write, set to 0xF.
987             // 0x113 [3:0]
988             PICA_CMD_DATA_FRAME_BUFFER_MODE(0xF), PICA_CMD_HEADER_SINGLE(PICA_REG_COLOR_BUFFER_WRITE),
989 
990             // To enable depth buffer read, set [1:1] to 1.
991             // To disable stencil buffer read, set to [0:0] to 1.
992             // 0x114 [1:0]
993             PICA_CMD_DATA_FRAME_BUFFER_MODE(0x2), PICA_CMD_HEADER_SINGLE(PICA_REG_DEPTH_STENCIL_BUFFER_READ),
994 
995             // To enable depth buffer write, set to [1:1] to 1.
996             // To enable stencil buffer write, set [0:0] to 1.
997             // 0x115 [1:0]
998             PICA_CMD_DATA_FRAME_BUFFER_MODE(0x2), PICA_CMD_HEADER_SINGLE(PICA_REG_DEPTH_STENCIL_BUFFER_WRITE),
999 
1000             // Clear the color buffer and depth buffer caches.
1001             PICA_CMD_SET_COLOR_DEPTH_BUFFER_CLEAR(0x1, 0x1)
1002         };
1003 
1004         nngxAdd3DCommand(cmdbuf, sizeof(cmdbuf), GL_TRUE);
1005     }
1006 }
1007 
nnMain(void)1008 void nnMain(void)
1009 {
1010     // Call only nn::applet::Enable to also allow execution from the HOME Menu
1011     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
1012     nn::applet::Enable();
1013 
1014     /* initialization */
1015     if (Initialize() >= 0)
1016     {
1017         while (1)
1018         {
1019             (void)DrawFrame();
1020         }
1021     }
1022 
1023     if ( s_VertexArray != NULL )
1024     {
1025         demo::Free(s_VertexArray);
1026         s_VertexArray = NULL;
1027     }
1028 
1029     if ( s_IndexArray != NULL )
1030     {
1031         demo::Free(s_IndexArray);
1032         s_IndexArray = NULL;
1033     }
1034 
1035     nngxFinalize();
1036 
1037     /* shutdown_display */
1038     s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForGx));
1039     s_AppHeap.Finalize();
1040 }
1041