1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     gx_DrawTexture2d.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/types.h>
18 #include <nn/dbg.h>
19 
20 #include <nn/os/os_Memory.h>
21 #include <nn/os/os_MemoryTypes.h>
22 #include <nn/fnd/fnd_ExpHeap.h>
23 
24 #include <nn/gx.h>
25 #include <nn/fs.h>
26 #include <nn/applet.h>
27 
28 #include "demo.h"
29 
30 namespace
31 {
32     demo::RenderSystemDrawing s_RenderSystem;
33 
34     nn::fnd::ExpHeap s_AppHeap;
35     uptr s_HeapForGx;
36     const u32 s_GxHeapSize = 0x400000;
37 }
38 
39 typedef __packed struct BitmapFileHeader
40 {
41     u8 bfType[2];
42     u16 bfSize[2];
43     u16 bfReserved1;
44     u16 bfReserved2;
45     u16 bfOffBits[2];
46 } BitmapFileHeader;
47 
48 typedef __packed struct BitmapInfoHeader
49 {
50     u32 biSize;
51     s32 biWidth;
52     s32 biHeight;
53     u16 biPlanes;
54     u16 biBitCount;
55     u32 biCompression;
56     u32 biSizeImage;
57     s32 biXPixPerMeter;
58     s32 biYPixPerMeter;
59     u32 biClrUsed;
60     u32 biClrImportant;
61 } BitmapInfoHeader;
62 
63 // Texture0
64 GLuint s_BmpTexture0Id = 0;
65 u32 s_Bmp0Width = 0;
66 u32 s_Bmp0Height = 0;
67 u32 s_Texture0Width = 0;
68 u32 s_Texture0Height = 0;
69 
70 // Texture1
71 GLuint s_BmpTexture1Id = 0;
72 u32 s_Bmp1Width = 0;
73 u32 s_Bmp1Height = 0;
74 u32 s_Texture1Width = 0;
75 u32 s_Texture1Height = 0;
76 
77 void Initialize(void);
78 void Finalize(void);
79 
80 void LoadTexture0(void);
81 void DeleteTexture0(void);
82 void LoadTexture1(void);
83 void DeleteTexture1(void);
84 u8* GetTextureData(const wchar_t* bmpRomFilename,
85                    u32& bmpWidth, u32& bmpHeight, u32& textureWidth, u32& textureHeight);
86 u8* GetBmpFileData(u8* rawDataBuffer, u32& bmpWidth, u32& bmpHeight);
87 u8* GetTextureDataFromBmpFileData(const u32& bmpWidth, const u32& bmpHeight, u8* bmpDataBuffer,
88                                   u32& textureWidth, u32& textureHeight);
89 u32 GetTextureLength(const u32& imageLength);
90 
91 bool DrawFrame(void);
92 void DrawDisplay0(void);
93 void DrawDisplay1(void);
94 
95 
Initialize(void)96 void Initialize(void)
97 {
98     // fs initialization
99     nn::fs::Initialize();
100 
101     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
102     static char buffer[ROMFS_BUFFER_SIZE];
103     NN_UTIL_PANIC_IF_FAILED(
104         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
105 
106     s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(),
107         nn::os::GetDeviceMemorySize() );
108     s_HeapForGx = reinterpret_cast<uptr>(s_AppHeap.Allocate(s_GxHeapSize));
109 
110     s_RenderSystem.Initialize(s_HeapForGx, s_GxHeapSize);
111 
112     LoadTexture0();
113     LoadTexture1();
114 }
115 
Finalize(void)116 void Finalize(void)
117 {
118     DeleteTexture0();
119     DeleteTexture1();
120 
121     s_RenderSystem.Finalize();
122 
123     s_AppHeap.Free(reinterpret_cast<void*>(s_HeapForGx));
124 
125     s_AppHeap.Finalize();
126 }
127 
LoadTexture0(void)128 void LoadTexture0(void)
129 {
130     if ( s_BmpTexture0Id != 0 )
131     {
132         DeleteTexture0();
133     }
134 
135     wchar_t* bmpRomFilename = L"rom:/tulip.bmp";
136     u8* textureDataPtr = GetTextureData(bmpRomFilename,
137         s_Bmp0Width, s_Bmp0Height, s_Texture0Width, s_Texture0Height);
138 
139     GLenum target = GL_TEXTURE_2D;
140     GLenum internalFormat = GL_RGB_NATIVE_DMP;
141     GLenum format = GL_RGB_NATIVE_DMP;
142     GLenum type = GL_UNSIGNED_BYTE;
143     GLuint textureId = 0;
144 
145     s_RenderSystem.GenerateTexture(target,
146         internalFormat, s_Texture0Width, s_Texture0Height,
147         format, type, textureDataPtr, textureId);
148 
149     if ( textureId != 0 )
150     {
151         s_BmpTexture0Id = textureId;
152         NN_LOG("  Create texture (id = %d)\n", textureId);
153     }
154 
155     s_AppHeap.Free(textureDataPtr);
156 }
157 
DeleteTexture0(void)158 void DeleteTexture0(void)
159 {
160     if ( s_BmpTexture0Id != 0 )
161     {
162         bool flag = s_RenderSystem.DeleteTexture(s_BmpTexture0Id);
163         if ( flag )
164         {
165             NN_LOG("  Delete texture. (id = %d)\n", s_BmpTexture0Id);
166             s_BmpTexture0Id = 0;
167         }
168         else
169         {
170             NN_TPANIC_("  Failed to delete texture. (id = %d)\n", s_BmpTexture0Id);
171         }
172     }
173 }
174 
LoadTexture1(void)175 void LoadTexture1(void)
176 {
177     if ( s_BmpTexture1Id != 0 )
178     {
179         DeleteTexture1();
180     }
181 
182     wchar_t* bmpRomFilename = L"rom:/dandelion.bmp";
183     u8* textureDataPtr = GetTextureData(bmpRomFilename,
184         s_Bmp1Width, s_Bmp1Height, s_Texture1Width, s_Texture1Height);
185 
186     GLenum target = GL_TEXTURE_2D;
187     GLenum internalFormat = GL_RGB_NATIVE_DMP;
188     GLenum format = GL_RGB_NATIVE_DMP;
189     GLenum type = GL_UNSIGNED_BYTE;
190     GLuint textureId = 0;
191 
192     s_RenderSystem.GenerateTexture(target,
193         internalFormat, s_Texture1Width, s_Texture1Height,
194         format, type, textureDataPtr, textureId);
195 
196     if ( textureId != 0 )
197     {
198         s_BmpTexture1Id = textureId;
199         NN_LOG("  Create texture. (id = %d)\n", textureId);
200     }
201 
202     s_AppHeap.Free(textureDataPtr);
203 }
204 
DeleteTexture1(void)205 void DeleteTexture1(void)
206 {
207     if ( s_BmpTexture1Id != 0 )
208     {
209         bool flag = s_RenderSystem.DeleteTexture(s_BmpTexture1Id);
210         if ( flag )
211         {
212             NN_LOG("  Delete texture. (id = %d)\n", s_BmpTexture1Id);
213             s_BmpTexture1Id = 0;
214         }
215         else
216         {
217             NN_TPANIC_("Failed to delete texture. (id = %d)\n", s_BmpTexture1Id);
218         }
219     }
220 }
221 
GetTextureData(const wchar_t * bmpRomFilename,u32 & bmpWidth,u32 & bmpHeight,u32 & textureWidth,u32 & textureHeight)222 u8* GetTextureData(const wchar_t* bmpRomFilename,
223                    u32& bmpWidth, u32& bmpHeight,
224                    u32& textureWidth, u32& textureHeight)
225 {
226     NN_LOG("\nReading data from ROMFS...\n");
227 
228     nn::fs::FileReader file(bmpRomFilename);
229 
230     size_t fileSize = file.GetSize();
231     NN_LOG("  fileSize = %d (Byte)\n", fileSize);
232     if ( fileSize == 0 )
233     {
234         NN_TPANIC_("Failed to open BMP file.\n");
235         return NULL;
236     }
237 
238     void* buf = s_AppHeap.Allocate( fileSize, 4 );
239 
240     s32 readSize = file.Read(buf, fileSize);
241     NN_LOG("  file readSize = %d (Byte)\n", readSize);
242     if ( readSize == 0 )
243     {
244         NN_TPANIC_("Failed to open BMP file.\n");
245         return NULL;
246     }
247 
248     u8* bmpDataBuffer = NULL;
249     bmpDataBuffer = GetBmpFileData((u8*)buf, bmpWidth, bmpHeight);
250     NN_LOG("  bmpWidth = %d, bmpHeight = %d\n", bmpWidth, bmpHeight);
251 
252     u8* textureDataBuffer = NULL;
253     textureDataBuffer = GetTextureDataFromBmpFileData(bmpWidth, bmpHeight, bmpDataBuffer,
254         textureWidth, textureHeight);
255     NN_LOG("  textureWidth = %d, textureHeight = %d\n", textureWidth, textureHeight);
256 
257     file.Finalize();
258     s_AppHeap.Free(buf);
259 
260     return textureDataBuffer;
261 }
262 
GetBmpFileData(u8 * rawDataBuffer,u32 & bmpWidth,u32 & bmpHeight)263 u8* GetBmpFileData(u8* rawDataBuffer,
264                     u32& bmpWidth, u32& bmpHeight)
265 {
266     BitmapInfoHeader* bmp_info_header_ptr = (BitmapInfoHeader*)(rawDataBuffer + sizeof(BitmapFileHeader));
267     bmpWidth = bmp_info_header_ptr->biWidth;
268     bmpHeight = bmp_info_header_ptr->biHeight;
269     u8* bmpDataBuffer = rawDataBuffer + sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader);
270 
271     return bmpDataBuffer;
272 }
273 
GetTextureDataFromBmpFileData(const u32 & bmpWidth,const u32 & bmpHeight,u8 * bmpDataBuffer,u32 & textureWidth,u32 & textureHeight)274 u8* GetTextureDataFromBmpFileData(const u32& bmpWidth, const u32& bmpHeight, u8* bmpDataBuffer,
275                                     u32& textureWidth, u32& textureHeight)
276 {
277     // Convert BMP to OpenGL RGB format
278     textureWidth = GetTextureLength(bmpWidth);
279     textureHeight = GetTextureLength(bmpHeight);
280     u8* textureGLDataBuffer = reinterpret_cast<u8*>( s_AppHeap.Allocate(3 * textureWidth * textureHeight) );
281 
282     for (u32 y = 0; y < textureHeight; y++)
283     {
284         for (u32 x = 0; x < textureWidth; x++)
285         {
286             u8* textureDataPtr = textureGLDataBuffer;
287             textureDataPtr += 3 * ((static_cast<u32>(textureWidth) * y) + x);
288             if ( ( x >= bmpWidth ) || ( y >= bmpHeight ) )
289             {
290                 (*textureDataPtr) = 0x00;
291                 textureDataPtr += 1;
292 
293                 (*textureDataPtr) = 0x00;
294                 textureDataPtr += 1;
295 
296                 (*textureDataPtr) = 0x00;
297             }
298             else
299             {
300                 u8* bmpDataPtr = bmpDataBuffer;
301                 bmpDataPtr += 3 * (bmpWidth * y + x);
302 
303                 (*textureDataPtr) = (*(bmpDataPtr + 2));
304                 textureDataPtr += 1;
305                 (*textureDataPtr) = (*(bmpDataPtr + 1));
306                 textureDataPtr += 1;
307 
308                 (*textureDataPtr) = (*(bmpDataPtr + 0));
309             }
310         }
311     }
312 
313     u8* textureDataBuffer = reinterpret_cast<u8*>( s_AppHeap.Allocate(3 * textureWidth * textureHeight) );
314 
315     // Convert OpenGL RGB format to PICA Native RGB format
316     GLenum format = GL_RGB_NATIVE_DMP;
317     bool result = demo::ConvertGLTextureToNative(
318         format, textureWidth, textureHeight,
319         textureGLDataBuffer, textureDataBuffer);
320     if ( result )
321     {
322         NN_LOG("  Conversion to GL_RGB_NATIVE_DMP succeeded.\n");
323     }
324     else
325     {
326         NN_TPANIC_("  Conversion to GL_RGB_NATIVE_DMP failed.\n");
327     }
328 
329     s_AppHeap.Free(textureGLDataBuffer);
330 
331     return textureDataBuffer;
332 }
333 
GetTextureLength(const u32 & imageLength)334 u32 GetTextureLength(const u32& imageLength)
335 {
336     u32 textureLength = 8;
337 
338     // 8, 16, 32, 64, 128, 256, 512, 1024
339     for (u32 i = 0; i < 7; i++)
340     {
341         if ( imageLength > textureLength )
342         {
343             textureLength *= 2;
344         }
345         else
346         {
347             return textureLength;
348         }
349     }
350 
351     return 1024;
352 }
353 
DrawFrame(void)354 bool DrawFrame(void)
355 {
356     DrawDisplay0();
357     DrawDisplay1();
358 
359     s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
360 
361     return true;
362 }
363 
DrawDisplay0(void)364 void DrawDisplay0(void)
365 {
366     s_RenderSystem.SetClearColor(NN_GX_DISPLAY0, 0.0f, 1.0f, 0.0f, 1.0f);
367     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
368     s_RenderSystem.Clear();
369 
370     s_RenderSystem.SetColor(0.0f, 1.0f, 0.0f, 0.0f);
371 
372     f32 windowCoordinateX = 0.0f;
373     f32 windowCoordinateY = 0.0f;
374     f32 rectangleWidth = 400.0f;
375     f32 rectangleHeight = 240.0f;
376     s_RenderSystem.FillTexturedRectangle(s_BmpTexture0Id,
377         windowCoordinateX, windowCoordinateY,
378         rectangleWidth, rectangleHeight,
379         s_Bmp0Width, s_Bmp0Height,
380         s_Texture0Width, s_Texture0Height);
381 
382     s_RenderSystem.SwapBuffers();
383 }
384 
DrawDisplay1(void)385 void DrawDisplay1(void)
386 {
387     s_RenderSystem.SetClearColor(NN_GX_DISPLAY1, 0.0f, 0.0f, 1.0f, 0.0f);
388     s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
389     s_RenderSystem.Clear();
390 
391     f32 windowCoordinateX = 0.0f;
392     f32 windowCoordinateY = 0.0f;
393     f32 rectangleWidth = 320.0f;
394     f32 rectangleHeight = 240.0f;
395     s_RenderSystem.FillTexturedRectangle(s_BmpTexture1Id,
396         windowCoordinateX, windowCoordinateY,
397         rectangleWidth, rectangleHeight,
398         s_Bmp1Width, s_Bmp1Height,
399         s_Texture1Width, s_Texture1Height);
400 
401     s_RenderSystem.SwapBuffers();
402 }
403 
nnMain(void)404 void nnMain( void )
405 {
406     // Call only nn::applet::Enable to also allow execution from the HOME Menu
407     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
408     nn::applet::Enable();
409 
410     Initialize();
411 
412     bool flag = true;
413     while ( flag )
414     {
415         flag = DrawFrame();
416     }
417 
418     Finalize();
419 }
420