1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     lyt_GraphicsResource.cpp
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  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   $Revision: 25594 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/lyt/lyt_GraphicsResource.h>
19 #include <nw/lyt/lyt_Common.h>
20 #include <nw/lyt/lyt_Layout.h>
21 #include <nw/lyt/lyt_Stopwatch.h>
22 
23 #if defined(NW_PLATFORM_CTRWIN)
24 #include    <cstdlib>
25 #endif
26 
27 #define ARRAY_LENGTH(a)   (sizeof(a) / sizeof((a)[0]))
28 
29 namespace nw
30 {
31 namespace lyt
32 {
33 
34 namespace
35 {
36 
37 enum ResouceFileID
38 {
39     RESOURCEFILEID_RECTDRAWERSHADER,
40 #ifdef NW_LYT_DMPGL_ENABLED
41     RESOURCEFILEID_FONTSHADER,
42     RESOURCEFILEID_PANESHADER,
43     RESOURCEFILEID_CONSTCOLORSHADER,
44 #endif
45 
46     RESOURCEFILEID_MAX
47 };
48 
49 const wchar_t* sResourceFiles[] =
50 {
51     L"/shaders/nwfont_RectDrawerShader.shbin",
52 #ifdef NW_LYT_DMPGL_ENABLED
53     L"/shaders/nwfont_TextWriterShader.shbin",
54     L"/shaders/nwlyt_PaneShader.shbin",
55     L"/shaders/nwlyt_ConstColorShader.shbin",
56 #endif
57 };
58 
59 NW_COMPILER_ASSERT(ARRAY_LENGTH(sResourceFiles) == RESOURCEFILEID_MAX);
60 
61 wchar_t sResourcePaths[RESOURCEFILEID_MAX][FILENAME_MAX];
62 bool sResourcePathsInitialized = false;
63 
64 #ifdef NW_TARGET_CTR_GL_FINAL
65   #define FEATURE_FINAL(x) x
66 #else
67   #define FEATURE_FINAL(x) NULL
68 #endif
69 
70 #ifdef NW_LYT_DMPGL_ENABLED
71 const char* s_UniformNames[] =
72 {
73     "uProjection",
74     "uModelView",
75     "uTexMtx0",
76     "uTexMtx1",
77     "uTexMtx2",
78     "uColor",
79     "uTransform",
80     "uFrameSpec",
81     "uVertexColor",
82     "uVertexTexCoord0",
83     "uVertexTexCoord1",
84     "uVertexTexCoord2",
85     "uRcpTexSize0",
86     "dmp_Texture[0].samplerType",
87     "dmp_Texture[1].samplerType",
88     "dmp_Texture[2].samplerType",
89     "dmp_Texture[3].samplerType",
90     "dmp_TexEnv[0].combineRgb",
91     "dmp_TexEnv[1].combineRgb",
92     "dmp_TexEnv[2].combineRgb",
93     FEATURE_FINAL("dmp_TexEnv[3].combineRgb"),
94     FEATURE_FINAL("dmp_TexEnv[4].combineRgb"),
95     FEATURE_FINAL("dmp_TexEnv[5].combineRgb"),
96     "dmp_TexEnv[0].combineAlpha",
97     "dmp_TexEnv[1].combineAlpha",
98     "dmp_TexEnv[2].combineAlpha",
99     FEATURE_FINAL("dmp_TexEnv[3].combineAlpha"),
100     FEATURE_FINAL("dmp_TexEnv[4].combineAlpha"),
101     FEATURE_FINAL("dmp_TexEnv[5].combineAlpha"),
102     "dmp_TexEnv[0].srcRgb",
103     "dmp_TexEnv[1].srcRgb",
104     "dmp_TexEnv[2].srcRgb",
105     FEATURE_FINAL("dmp_TexEnv[3].srcRgb"),
106     FEATURE_FINAL("dmp_TexEnv[4].srcRgb"),
107     FEATURE_FINAL("dmp_TexEnv[5].srcRgb"),
108     "dmp_TexEnv[0].srcAlpha",
109     "dmp_TexEnv[1].srcAlpha",
110     "dmp_TexEnv[2].srcAlpha",
111     FEATURE_FINAL("dmp_TexEnv[3].srcAlpha"),
112     FEATURE_FINAL("dmp_TexEnv[4].srcAlpha"),
113     FEATURE_FINAL("dmp_TexEnv[5].srcAlpha"),
114     "dmp_TexEnv[0].operandRgb",
115     "dmp_TexEnv[1].operandRgb",
116     "dmp_TexEnv[2].operandRgb",
117     FEATURE_FINAL("dmp_TexEnv[3].operandRgb"),
118     FEATURE_FINAL("dmp_TexEnv[4].operandRgb"),
119     FEATURE_FINAL("dmp_TexEnv[5].operandRgb"),
120     "dmp_TexEnv[0].operandAlpha",
121     "dmp_TexEnv[1].operandAlpha",
122     "dmp_TexEnv[2].operandAlpha",
123     FEATURE_FINAL("dmp_TexEnv[3].operandAlpha"),
124     FEATURE_FINAL("dmp_TexEnv[4].operandAlpha"),
125     FEATURE_FINAL("dmp_TexEnv[5].operandAlpha"),
126     "dmp_TexEnv[0].scaleRgb",
127     "dmp_TexEnv[1].scaleRgb",
128     "dmp_TexEnv[2].scaleRgb",
129     FEATURE_FINAL("dmp_TexEnv[3].scaleRgb"),
130     FEATURE_FINAL("dmp_TexEnv[4].scaleRgb"),
131     FEATURE_FINAL("dmp_TexEnv[5].scaleRgb"),
132     "dmp_TexEnv[0].scaleAlpha",
133     "dmp_TexEnv[1].scaleAlpha",
134     "dmp_TexEnv[2].scaleAlpha",
135     FEATURE_FINAL("dmp_TexEnv[3].scaleAlpha"),
136     FEATURE_FINAL("dmp_TexEnv[4].scaleAlpha"),
137     FEATURE_FINAL("dmp_TexEnv[5].scaleAlpha"),
138     "dmp_TexEnv[0].constRgba",
139     "dmp_TexEnv[1].constRgba",
140     "dmp_TexEnv[2].constRgba",
141     FEATURE_FINAL("dmp_TexEnv[3].constRgba"),
142     FEATURE_FINAL("dmp_TexEnv[4].constRgba"),
143     FEATURE_FINAL("dmp_TexEnv[5].constRgba"),
144     FEATURE_FINAL("dmp_TexEnv[0].bufferColor"),
145     FEATURE_FINAL("dmp_TexEnv[1].bufferInput"),
146     FEATURE_FINAL("dmp_TexEnv[2].bufferInput"),
147     FEATURE_FINAL("dmp_TexEnv[3].bufferInput"),
148     FEATURE_FINAL("dmp_TexEnv[4].bufferInput"),
149     "dmp_FragOperation.enableAlphaTest",
150     "dmp_FragOperation.alphaRefValue",
151     "dmp_FragOperation.alphaTestFunc",
152 };
153 NW_COMPILER_ASSERT(ARRAY_LENGTH(s_UniformNames) == GraphicsResource::UNIFORM_MAX);
154 #endif // NW_LYT_DMPGL_ENABLED
155 
StrCopy(wchar_t * dst,const wchar_t * src)156 wchar_t* StrCopy(wchar_t* dst, const wchar_t* src)
157 {
158     NW_NULL_ASSERT(dst);
159     NW_NULL_ASSERT(src);
160 
161     size_t i = 0;
162     for (; src[i] != L'\0'; ++i)
163     {
164         dst[i] = src[i];
165     }
166 
167     dst[i] = src[i];
168 
169     return dst + i;
170 }
171 
172 } // namespace
173 
GraphicsResource()174 GraphicsResource::GraphicsResource()
175 : m_pRectShaderBinary(NULL)
176 , m_RectShaderBinarySize(0)
177 #ifdef NW_LYT_DMPGL_ENABLED
178 , m_GlProgram(0)
179 , m_GlProgramDebug(0)
180 #endif
181 , m_Initialized(false)
182 {
183 }
184 
~GraphicsResource()185 GraphicsResource::~GraphicsResource()
186 {
187     this->Finalize();
188 }
189 
190 void
Finalize()191 GraphicsResource::Finalize()
192 {
193     if (!m_Initialized)
194     {
195         return;
196     }
197 
198     m_Initialized = false;
199 
200 #ifdef NW_LYT_DMPGL_ENABLED
201     glUseProgram(0);
202 
203     glDeleteProgram(m_GlProgram);
204     m_GlProgram = 0;
205 
206     glDeleteProgram(m_GlProgramDebug);
207     m_GlProgramDebug = 0;
208 
209     glDeleteBuffers(this->VBO_MAX, m_GlVertexBufferObject);
210 #endif
211 
212     if (NULL != m_pRectShaderBinary)
213     {
214         Layout::FreeMemory(m_pRectShaderBinary);
215     }
216     m_pRectShaderBinary = NULL;
217     m_RectShaderBinarySize = 0;
218 
219     m_TextWriter.SetTextWriterResource(0);
220     m_TextWriterResource.DeleteResource();
221 }
222 
223 const wchar_t*
GetResourcePath(int index)224 GraphicsResource::GetResourcePath(int index)
225 {
226     if (!sResourcePathsInitialized)
227     {
228 #if defined(NW_PLATFORM_CTR)
229         static const wchar_t* pResourceRoot = L"rom:";
230         for (int i = 0; i < RESOURCEFILEID_MAX; ++i)
231         {
232             wchar_t* buff = sResourcePaths[i];
233             buff = StrCopy(buff, pResourceRoot);
234             buff = StrCopy(buff, sResourceFiles[i]);
235         }
236 #endif
237 
238 #if defined(NW_PLATFORM_CTRWIN)
239         for (int i = 0; i < RESOURCEFILEID_MAX; ++i)
240         {
241             wchar_t* buff = sResourcePaths[i];
242             size_t bufferSize = 0;
243             _wgetenv_s(&bufferSize, buff, FILENAME_MAX, L"NW4C_ROOT");
244             NW_ASSERT(bufferSize > 0);
245             buff = StrCopy(buff + bufferSize - 1, sResourceFiles[i]);
246         }
247 #endif
248 
249         sResourcePathsInitialized = true;
250     }
251 
252     if (0 <= index && index < RESOURCEFILEID_MAX)
253     {
254         return sResourcePaths[index];
255     }
256     else
257     {
258         return NULL;
259     }
260 }
261 
262 void
SetResource(int index,void * content,u32 fileSize,bool bFree)263 GraphicsResource::SetResource(int index, void* content, u32 fileSize, bool bFree)
264 {
265     NW_MINMAX_ASSERT(index, 0, RESOURCEFILEID_MAX - 1);
266     NW_NULL_ASSERT(content);
267     NW_ASSERT(fileSize > 0);
268 
269     switch (index)
270     {
271     case RESOURCEFILEID_RECTDRAWERSHADER:
272         {
273             m_pRectShaderBinary = Layout::AllocMemory(fileSize);
274             NW_NULL_ASSERT(m_pRectShaderBinary);
275             m_RectShaderBinarySize = fileSize;
276             std::memcpy(m_pRectShaderBinary, content, fileSize);
277             if (bFree)
278             {
279                 Layout::FreeMemory(content);
280             }
281             return;
282         }
283 
284 #ifdef NW_LYT_DMPGL_ENABLED
285 
286     case RESOURCEFILEID_FONTSHADER:
287         {
288             m_TextWriterResource.InitResource(static_cast<u8*>(content), fileSize);
289             m_TextWriter.SetTextWriterResource(&m_TextWriterResource);
290             NW_GL_ASSERT();
291 
292             if (bFree)
293             {
294                 Layout::FreeMemory(content);
295             }
296             return;
297         }
298 
299     case RESOURCEFILEID_PANESHADER:
300         {
301             m_GlProgram = glCreateProgram();
302             NW_ASSERT(m_GlProgram != 0);
303             NW_GL_ASSERT();
304 
305             GLuint shader = glCreateShader(GL_VERTEX_SHADER);
306             NW_ASSERT(shader != 0);
307             NW_GL_ASSERT();
308 
309             glShaderBinary(1, &shader, GL_PLATFORM_BINARY_DMP, content, fileSize);
310             NW_GL_ASSERT();
311 
312             glAttachShader(m_GlProgram, shader);
313             glAttachShader(m_GlProgram, GL_DMP_FRAGMENT_SHADER_DMP);
314             NW_GL_ASSERT();
315 
316             // プログラムが削除されたらシェーダも削除されるように。
317             glDeleteShader(shader);
318             NW_GL_ASSERT();
319 
320             glBindAttribLocation(m_GlProgram, VERTEXATTR_VERTEX_INDEX, "aVertexIndex");
321             NW_GL_ASSERT();
322 
323             glLinkProgram(m_GlProgram);
324             NW_GL_ASSERT();
325 
326             glUseProgram(m_GlProgram);
327             // フラグメントシェーダを標準モードに設定。
328             glUniform1i(glGetUniformLocation(m_GlProgram, "dmp_FragOperation.mode"), GL_FRAGOP_MODE_GL_DMP);
329             // ライティングを無効化。
330             glUniform1i(glGetUniformLocation(m_GlProgram, "dmp_FragmentLighting.enabled"), GL_FALSE);
331             NW_GL_ASSERT();
332 
333             if (bFree)
334             {
335                 Layout::FreeMemory(content);
336             }
337             return;
338         }
339 
340     case RESOURCEFILEID_CONSTCOLORSHADER:
341         {
342             m_GlProgramDebug = glCreateProgram();
343             NW_ASSERT(m_GlProgramDebug != 0);
344             NW_GL_ASSERT();
345 
346             GLuint shader = glCreateShader(GL_VERTEX_SHADER);
347             NW_ASSERT(shader != 0);
348             NW_GL_ASSERT();
349 
350             glShaderBinary(1, &shader, GL_PLATFORM_BINARY_DMP, content, fileSize);
351             NW_GL_ASSERT();
352 
353             glAttachShader(m_GlProgramDebug, shader);
354             glAttachShader(m_GlProgramDebug, GL_DMP_FRAGMENT_SHADER_DMP);
355             NW_GL_ASSERT();
356 
357             // プログラムが削除されたらシェーダも削除されるように。
358             glDeleteShader(shader);
359             NW_GL_ASSERT();
360 
361             glBindAttribLocation(m_GlProgramDebug, VERTEXATTR_POS, "aPosition");
362             NW_GL_ASSERT();
363 
364             glLinkProgram(m_GlProgramDebug);
365             NW_GL_ASSERT();
366 
367             if (bFree)
368             {
369                 Layout::FreeMemory(content);
370             }
371             return;
372         }
373 
374 #endif // NW_LYT_DMPGL_ENABLED
375 
376     default:
377         NW_FATAL_ERROR("not implemented (%d).", index);
378     }
379 }
380 
381 void
StartSetup()382 GraphicsResource::StartSetup()
383 {
384     NW_ASSERT(!m_Initialized);
385 }
386 
387 bool
FinishSetup()388 GraphicsResource::FinishSetup()
389 {
390     NW_NULL_ASSERT(m_pRectShaderBinary);
391 
392 #ifdef NW_LYT_DMPGL_ENABLED
393 
394     NW_ASSERT(m_GlProgram != 0);
395     NW_ASSERT(m_GlProgramDebug != 0);
396 
397     math::MTX34Identity(&m_MtxModelView);
398 
399     this->InitVBO();
400 
401     for (int i = 0; i < this->UNIFORM_MAX; ++i)
402     {
403         if (s_UniformNames[i] == NULL)
404         {
405             m_UniformLocation[i] = 0;
406         }
407         else
408         {
409             m_UniformLocation[i] = glGetUniformLocation(m_GlProgram, s_UniformNames[i]);
410         }
411     }
412     NW_GL_ASSERT();
413 
414 #endif // NW_LYT_DMPGL_ENABLED
415 
416     m_Initialized = true;
417 
418     return true;
419 }
420 
421 #ifdef NW_LYT_DMPGL_ENABLED
422 
423 void
SetProjectionMtx(const nw::math::MTX44 & mtx)424 GraphicsResource::SetProjectionMtx(const nw::math::MTX44& mtx)
425 {
426     NW_ASSERT(this->Initialized());
427 
428     GLuint program = 0;
429 
430     program = this->GetGlProgram();
431     glUseProgram(program);
432     glUniformMatrix4fv(this->GetUniformLocation(this->UNIFORM_uProjection), 1, GL_TRUE, mtx.a);
433     NW_GL_ASSERT();
434 
435     program = this->GetGlProgramDebug();
436     glUseProgram(program);
437     glUniformMatrix4fv(glGetUniformLocation(program, "uProjection"), 1, GL_TRUE, mtx.a);
438     NW_GL_ASSERT();
439 
440     m_TextWriterResource.ActiveGlProgram();
441     m_TextWriterResource.SetProjectionMtx(mtx.a);
442     NW_GL_ASSERT();
443 }
444 
ResetGlProgramState()445 void GraphicsResource::ResetGlProgramState()
446 {
447     this->SetNumTexEnv(internal::TexEnvUnitMax);
448     this->SetTexEnvAuto(false);
449 }
450 
ResetGlState()451 void GraphicsResource::ResetGlState()
452 {
453     m_FirstDraw = true;
454 }
455 
456 void
ActiveVBO()457 GraphicsResource::ActiveVBO()
458 {
459     // 頂点インデックス
460     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->GetVBO(this->VBO_ELEMENT));
461 
462     // 頂点座標
463     glBindBuffer(GL_ARRAY_BUFFER, this->GetVBO(this->VBO_VERTEX_INDEX));
464     glEnableVertexAttribArray(VERTEXATTR_VERTEX_INDEX);
465     glVertexAttribPointer(VERTEXATTR_VERTEX_INDEX, VERTEXATTRSIZE_INDEX, GL_SHORT, GL_FALSE, 0, NULL);
466 }
467 
468 #endif // NW_LYT_DMPGL_ENABLED
469 
470 } // namespace nw::lyt
471 } // namespace nw
472