/*---------------------------------------------------------------------------* Project: NintendoWare File: lyt_GraphicsResource.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 25594 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #if defined(NW_PLATFORM_CTRWIN) #include #endif #define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) namespace nw { namespace lyt { namespace { enum ResouceFileID { RESOURCEFILEID_RECTDRAWERSHADER, #ifdef NW_LYT_DMPGL_ENABLED RESOURCEFILEID_FONTSHADER, RESOURCEFILEID_PANESHADER, RESOURCEFILEID_CONSTCOLORSHADER, #endif RESOURCEFILEID_MAX }; const wchar_t* sResourceFiles[] = { L"/shaders/nwfont_RectDrawerShader.shbin", #ifdef NW_LYT_DMPGL_ENABLED L"/shaders/nwfont_TextWriterShader.shbin", L"/shaders/nwlyt_PaneShader.shbin", L"/shaders/nwlyt_ConstColorShader.shbin", #endif }; NW_COMPILER_ASSERT(ARRAY_LENGTH(sResourceFiles) == RESOURCEFILEID_MAX); wchar_t sResourcePaths[RESOURCEFILEID_MAX][FILENAME_MAX]; bool sResourcePathsInitialized = false; #ifdef NW_TARGET_CTR_GL_FINAL #define FEATURE_FINAL(x) x #else #define FEATURE_FINAL(x) NULL #endif #ifdef NW_LYT_DMPGL_ENABLED const char* s_UniformNames[] = { "uProjection", "uModelView", "uTexMtx0", "uTexMtx1", "uTexMtx2", "uColor", "uTransform", "uFrameSpec", "uVertexColor", "uVertexTexCoord0", "uVertexTexCoord1", "uVertexTexCoord2", "uRcpTexSize0", "dmp_Texture[0].samplerType", "dmp_Texture[1].samplerType", "dmp_Texture[2].samplerType", "dmp_Texture[3].samplerType", "dmp_TexEnv[0].combineRgb", "dmp_TexEnv[1].combineRgb", "dmp_TexEnv[2].combineRgb", FEATURE_FINAL("dmp_TexEnv[3].combineRgb"), FEATURE_FINAL("dmp_TexEnv[4].combineRgb"), FEATURE_FINAL("dmp_TexEnv[5].combineRgb"), "dmp_TexEnv[0].combineAlpha", "dmp_TexEnv[1].combineAlpha", "dmp_TexEnv[2].combineAlpha", FEATURE_FINAL("dmp_TexEnv[3].combineAlpha"), FEATURE_FINAL("dmp_TexEnv[4].combineAlpha"), FEATURE_FINAL("dmp_TexEnv[5].combineAlpha"), "dmp_TexEnv[0].srcRgb", "dmp_TexEnv[1].srcRgb", "dmp_TexEnv[2].srcRgb", FEATURE_FINAL("dmp_TexEnv[3].srcRgb"), FEATURE_FINAL("dmp_TexEnv[4].srcRgb"), FEATURE_FINAL("dmp_TexEnv[5].srcRgb"), "dmp_TexEnv[0].srcAlpha", "dmp_TexEnv[1].srcAlpha", "dmp_TexEnv[2].srcAlpha", FEATURE_FINAL("dmp_TexEnv[3].srcAlpha"), FEATURE_FINAL("dmp_TexEnv[4].srcAlpha"), FEATURE_FINAL("dmp_TexEnv[5].srcAlpha"), "dmp_TexEnv[0].operandRgb", "dmp_TexEnv[1].operandRgb", "dmp_TexEnv[2].operandRgb", FEATURE_FINAL("dmp_TexEnv[3].operandRgb"), FEATURE_FINAL("dmp_TexEnv[4].operandRgb"), FEATURE_FINAL("dmp_TexEnv[5].operandRgb"), "dmp_TexEnv[0].operandAlpha", "dmp_TexEnv[1].operandAlpha", "dmp_TexEnv[2].operandAlpha", FEATURE_FINAL("dmp_TexEnv[3].operandAlpha"), FEATURE_FINAL("dmp_TexEnv[4].operandAlpha"), FEATURE_FINAL("dmp_TexEnv[5].operandAlpha"), "dmp_TexEnv[0].scaleRgb", "dmp_TexEnv[1].scaleRgb", "dmp_TexEnv[2].scaleRgb", FEATURE_FINAL("dmp_TexEnv[3].scaleRgb"), FEATURE_FINAL("dmp_TexEnv[4].scaleRgb"), FEATURE_FINAL("dmp_TexEnv[5].scaleRgb"), "dmp_TexEnv[0].scaleAlpha", "dmp_TexEnv[1].scaleAlpha", "dmp_TexEnv[2].scaleAlpha", FEATURE_FINAL("dmp_TexEnv[3].scaleAlpha"), FEATURE_FINAL("dmp_TexEnv[4].scaleAlpha"), FEATURE_FINAL("dmp_TexEnv[5].scaleAlpha"), "dmp_TexEnv[0].constRgba", "dmp_TexEnv[1].constRgba", "dmp_TexEnv[2].constRgba", FEATURE_FINAL("dmp_TexEnv[3].constRgba"), FEATURE_FINAL("dmp_TexEnv[4].constRgba"), FEATURE_FINAL("dmp_TexEnv[5].constRgba"), FEATURE_FINAL("dmp_TexEnv[0].bufferColor"), FEATURE_FINAL("dmp_TexEnv[1].bufferInput"), FEATURE_FINAL("dmp_TexEnv[2].bufferInput"), FEATURE_FINAL("dmp_TexEnv[3].bufferInput"), FEATURE_FINAL("dmp_TexEnv[4].bufferInput"), "dmp_FragOperation.enableAlphaTest", "dmp_FragOperation.alphaRefValue", "dmp_FragOperation.alphaTestFunc", }; NW_COMPILER_ASSERT(ARRAY_LENGTH(s_UniformNames) == GraphicsResource::UNIFORM_MAX); #endif // NW_LYT_DMPGL_ENABLED wchar_t* StrCopy(wchar_t* dst, const wchar_t* src) { NW_NULL_ASSERT(dst); NW_NULL_ASSERT(src); size_t i = 0; for (; src[i] != L'\0'; ++i) { dst[i] = src[i]; } dst[i] = src[i]; return dst + i; } } // namespace GraphicsResource::GraphicsResource() : m_pRectShaderBinary(NULL) , m_RectShaderBinarySize(0) #ifdef NW_LYT_DMPGL_ENABLED , m_GlProgram(0) , m_GlProgramDebug(0) #endif , m_Initialized(false) { } GraphicsResource::~GraphicsResource() { this->Finalize(); } void GraphicsResource::Finalize() { if (!m_Initialized) { return; } m_Initialized = false; #ifdef NW_LYT_DMPGL_ENABLED glUseProgram(0); glDeleteProgram(m_GlProgram); m_GlProgram = 0; glDeleteProgram(m_GlProgramDebug); m_GlProgramDebug = 0; glDeleteBuffers(this->VBO_MAX, m_GlVertexBufferObject); #endif if (NULL != m_pRectShaderBinary) { Layout::FreeMemory(m_pRectShaderBinary); } m_pRectShaderBinary = NULL; m_RectShaderBinarySize = 0; m_TextWriter.SetTextWriterResource(0); m_TextWriterResource.DeleteResource(); } const wchar_t* GraphicsResource::GetResourcePath(int index) { if (!sResourcePathsInitialized) { #if defined(NW_PLATFORM_CTR) static const wchar_t* pResourceRoot = L"rom:"; for (int i = 0; i < RESOURCEFILEID_MAX; ++i) { wchar_t* buff = sResourcePaths[i]; buff = StrCopy(buff, pResourceRoot); buff = StrCopy(buff, sResourceFiles[i]); } #endif #if defined(NW_PLATFORM_CTRWIN) for (int i = 0; i < RESOURCEFILEID_MAX; ++i) { wchar_t* buff = sResourcePaths[i]; size_t bufferSize = 0; _wgetenv_s(&bufferSize, buff, FILENAME_MAX, L"NW4C_ROOT"); NW_ASSERT(bufferSize > 0); buff = StrCopy(buff + bufferSize - 1, sResourceFiles[i]); } #endif sResourcePathsInitialized = true; } if (0 <= index && index < RESOURCEFILEID_MAX) { return sResourcePaths[index]; } else { return NULL; } } void GraphicsResource::SetResource(int index, void* content, u32 fileSize, bool bFree) { NW_MINMAX_ASSERT(index, 0, RESOURCEFILEID_MAX - 1); NW_NULL_ASSERT(content); NW_ASSERT(fileSize > 0); switch (index) { case RESOURCEFILEID_RECTDRAWERSHADER: { m_pRectShaderBinary = Layout::AllocMemory(fileSize); NW_NULL_ASSERT(m_pRectShaderBinary); m_RectShaderBinarySize = fileSize; std::memcpy(m_pRectShaderBinary, content, fileSize); if (bFree) { Layout::FreeMemory(content); } return; } #ifdef NW_LYT_DMPGL_ENABLED case RESOURCEFILEID_FONTSHADER: { m_TextWriterResource.InitResource(static_cast(content), fileSize); m_TextWriter.SetTextWriterResource(&m_TextWriterResource); NW_GL_ASSERT(); if (bFree) { Layout::FreeMemory(content); } return; } case RESOURCEFILEID_PANESHADER: { m_GlProgram = glCreateProgram(); NW_ASSERT(m_GlProgram != 0); NW_GL_ASSERT(); GLuint shader = glCreateShader(GL_VERTEX_SHADER); NW_ASSERT(shader != 0); NW_GL_ASSERT(); glShaderBinary(1, &shader, GL_PLATFORM_BINARY_DMP, content, fileSize); NW_GL_ASSERT(); glAttachShader(m_GlProgram, shader); glAttachShader(m_GlProgram, GL_DMP_FRAGMENT_SHADER_DMP); NW_GL_ASSERT(); // プログラムが削除されたらシェーダも削除されるように。 glDeleteShader(shader); NW_GL_ASSERT(); glBindAttribLocation(m_GlProgram, VERTEXATTR_VERTEX_INDEX, "aVertexIndex"); NW_GL_ASSERT(); glLinkProgram(m_GlProgram); NW_GL_ASSERT(); glUseProgram(m_GlProgram); // フラグメントシェーダを標準モードに設定。 glUniform1i(glGetUniformLocation(m_GlProgram, "dmp_FragOperation.mode"), GL_FRAGOP_MODE_GL_DMP); // ライティングを無効化。 glUniform1i(glGetUniformLocation(m_GlProgram, "dmp_FragmentLighting.enabled"), GL_FALSE); NW_GL_ASSERT(); if (bFree) { Layout::FreeMemory(content); } return; } case RESOURCEFILEID_CONSTCOLORSHADER: { m_GlProgramDebug = glCreateProgram(); NW_ASSERT(m_GlProgramDebug != 0); NW_GL_ASSERT(); GLuint shader = glCreateShader(GL_VERTEX_SHADER); NW_ASSERT(shader != 0); NW_GL_ASSERT(); glShaderBinary(1, &shader, GL_PLATFORM_BINARY_DMP, content, fileSize); NW_GL_ASSERT(); glAttachShader(m_GlProgramDebug, shader); glAttachShader(m_GlProgramDebug, GL_DMP_FRAGMENT_SHADER_DMP); NW_GL_ASSERT(); // プログラムが削除されたらシェーダも削除されるように。 glDeleteShader(shader); NW_GL_ASSERT(); glBindAttribLocation(m_GlProgramDebug, VERTEXATTR_POS, "aPosition"); NW_GL_ASSERT(); glLinkProgram(m_GlProgramDebug); NW_GL_ASSERT(); if (bFree) { Layout::FreeMemory(content); } return; } #endif // NW_LYT_DMPGL_ENABLED default: NW_FATAL_ERROR("not implemented (%d).", index); } } void GraphicsResource::StartSetup() { NW_ASSERT(!m_Initialized); } bool GraphicsResource::FinishSetup() { NW_NULL_ASSERT(m_pRectShaderBinary); #ifdef NW_LYT_DMPGL_ENABLED NW_ASSERT(m_GlProgram != 0); NW_ASSERT(m_GlProgramDebug != 0); math::MTX34Identity(&m_MtxModelView); this->InitVBO(); for (int i = 0; i < this->UNIFORM_MAX; ++i) { if (s_UniformNames[i] == NULL) { m_UniformLocation[i] = 0; } else { m_UniformLocation[i] = glGetUniformLocation(m_GlProgram, s_UniformNames[i]); } } NW_GL_ASSERT(); #endif // NW_LYT_DMPGL_ENABLED m_Initialized = true; return true; } #ifdef NW_LYT_DMPGL_ENABLED void GraphicsResource::SetProjectionMtx(const nw::math::MTX44& mtx) { NW_ASSERT(this->Initialized()); GLuint program = 0; program = this->GetGlProgram(); glUseProgram(program); glUniformMatrix4fv(this->GetUniformLocation(this->UNIFORM_uProjection), 1, GL_TRUE, mtx.a); NW_GL_ASSERT(); program = this->GetGlProgramDebug(); glUseProgram(program); glUniformMatrix4fv(glGetUniformLocation(program, "uProjection"), 1, GL_TRUE, mtx.a); NW_GL_ASSERT(); m_TextWriterResource.ActiveGlProgram(); m_TextWriterResource.SetProjectionMtx(mtx.a); NW_GL_ASSERT(); } void GraphicsResource::ResetGlProgramState() { this->SetNumTexEnv(internal::TexEnvUnitMax); this->SetTexEnvAuto(false); } void GraphicsResource::ResetGlState() { m_FirstDraw = true; } void GraphicsResource::ActiveVBO() { // 頂点インデックス glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->GetVBO(this->VBO_ELEMENT)); // 頂点座標 glBindBuffer(GL_ARRAY_BUFFER, this->GetVBO(this->VBO_VERTEX_INDEX)); glEnableVertexAttribArray(VERTEXATTR_VERTEX_INDEX); glVertexAttribPointer(VERTEXATTR_VERTEX_INDEX, VERTEXATTRSIZE_INDEX, GL_SHORT, GL_FALSE, 0, NULL); } #endif // NW_LYT_DMPGL_ENABLED } // namespace nw::lyt } // namespace nw