CRenderingContext::CRenderingContext(CRenderer* pRenderer, bool bInherit) { m_pRenderer = pRenderer; m_clrRender = ::Color(255, 255, 255, 255); s_aContexts.push_back(); if (bInherit && s_aContexts.size() > 1) { CRenderContext& oLastContext = s_aContexts[s_aContexts.size()-2]; CRenderContext& oThisContext = GetContext(); oThisContext.m_mProjection = oLastContext.m_mProjection; oThisContext.m_mView = oLastContext.m_mView; oThisContext.m_mTransformations = oLastContext.m_mTransformations; oThisContext.m_hMaterial = oLastContext.m_hMaterial; oThisContext.m_pFrameBuffer = oLastContext.m_pFrameBuffer; tstrncpy(oThisContext.m_szProgram, PROGRAM_LEN, oLastContext.m_szProgram, PROGRAM_LEN); oThisContext.m_pShader = oLastContext.m_pShader; oThisContext.m_rViewport = oLastContext.m_rViewport; oThisContext.m_eBlend = oLastContext.m_eBlend; oThisContext.m_flAlpha = oLastContext.m_flAlpha; oThisContext.m_bDepthMask = oLastContext.m_bDepthMask; oThisContext.m_bDepthTest = oLastContext.m_bDepthTest; oThisContext.m_eDepthFunction = oLastContext.m_eDepthFunction; oThisContext.m_bCull = oLastContext.m_bCull; oThisContext.m_bWinding = oLastContext.m_bWinding; m_pShader = oThisContext.m_pShader; if (m_pShader) m_iProgram = m_pShader->m_iProgram; else m_iProgram = 0; } else { m_pShader = NULL; BindTexture(0); UseMaterial(CMaterialHandle()); UseFrameBuffer(NULL); UseProgram(""); SetViewport(Rect(0, 0, Application()->GetWindowWidth(), Application()->GetWindowHeight())); SetBlend(BLEND_NONE); SetAlpha(1); SetDepthMask(true); SetDepthTest(true); SetDepthFunction(DF_LESS); SetBackCulling(true); SetWinding(true); } }
void CRenderingContext::UseProgram(const tchar* pszProgram) { tstrncpy(GetContext().m_szProgram, PROGRAM_LEN, pszProgram, PROGRAM_LEN); GetContext().m_pShader = m_pShader = CShaderLibrary::GetShader(pszProgram); if (*pszProgram) TAssert(m_pShader); UseProgram(m_pShader); }
void CTrayIcon::Add(const CWnd& oWnd, uint nTrayID, uint nMsgID, uint nRscID, const tchar* pszToolTip) { ASSERT(m_hWnd == NULL); ASSERT(m_nTrayID == 0); ASSERT(m_nMsgID == 0); ASSERT(oWnd.Handle() != NULL); ASSERT(nTrayID != 0); ASSERT((pszToolTip == nullptr) || (tstrlen(pszToolTip) < MAX_TIP_LEN)); // Save parameters. m_hWnd = oWnd.Handle(); m_nTrayID = nTrayID; m_nMsgID = nMsgID; // Load the icon resource. CIcon oIcon(nRscID, ICON_WIDTH, ICON_HEIGHT); uint nFlags = NIF_ICON; // Work out which other fields to set. if (m_nMsgID != 0) nFlags |= NIF_MESSAGE; if (pszToolTip != nullptr) nFlags |= NIF_TIP; NOTIFYICONDATA oData = { 0 }; // Fill in the message structure. oData.cbSize = sizeof(oData); oData.hWnd = m_hWnd; oData.uID = m_nTrayID; oData.uFlags = nFlags; oData.uCallbackMessage = m_nMsgID; oData.hIcon = oIcon.Handle(); if (pszToolTip != nullptr) tstrncpy(oData.szTip, pszToolTip, MAX_TIP_LEN-1); // Send message. ::Shell_NotifyIcon(NIM_ADD, &oData); }
void CRenderingContext::UseProgram(class CShader* pShader) { GetContext().m_pShader = m_pShader = pShader; if (!m_pShader) { GetContext().m_szProgram[0] = '\0'; m_iProgram = 0; glUseProgram(0); return; } tstrncpy(GetContext().m_szProgram, PROGRAM_LEN, pShader->m_sName.c_str(), PROGRAM_LEN); m_iProgram = m_pShader->m_iProgram; glUseProgram((GLuint)m_pShader->m_iProgram); SetUniform("mProjection", GetContext().m_mProjection); SetUniform("mView", GetContext().m_mView); }
void CRenderingContext::UseProgram(class CShader* pShader) { CRenderContext& oContext = GetContext(); oContext.m_pShader = m_pShader = pShader; if (!m_pShader) { oContext.m_szProgram[0] = '\0'; m_iProgram = 0; glUseProgram(0); return; } tstrncpy(oContext.m_szProgram, PROGRAM_LEN, pShader->m_sName.c_str(), PROGRAM_LEN); m_iProgram = m_pShader->m_iProgram; glUseProgram((GLuint)m_pShader->m_iProgram); oContext.m_bProjectionUpdated = false; oContext.m_bViewUpdated = false; }
void CTrayIcon::Modify(uint nRscID, const tchar* pszToolTip) { ASSERT(m_hWnd != NULL); ASSERT(m_nTrayID != 0); ASSERT(nRscID != 0 || pszToolTip != nullptr); ASSERT((pszToolTip == nullptr) || (tstrlen(pszToolTip) < MAX_TIP_LEN)); uint nFlags = 0; // Work out which fields we're setting. if (nRscID != 0) nFlags |= NIF_ICON; if (pszToolTip != nullptr) nFlags |= NIF_TIP; NOTIFYICONDATA oData = { 0 }; // Fill in the message structure. oData.cbSize = sizeof(oData); oData.hWnd = m_hWnd; oData.uID = m_nTrayID; oData.uFlags = nFlags; oData.uCallbackMessage = m_nMsgID; if (nRscID != 0) { CIcon oIcon(nRscID, ICON_WIDTH, ICON_HEIGHT); oData.hIcon = oIcon.Handle(); } if (pszToolTip != nullptr) tstrncpy(oData.szTip, pszToolTip, MAX_TIP_LEN-1); // Send message. ::Shell_NotifyIcon(NIM_MODIFY, &oData); }
// Silo ascii void CModelConverter::ReadSIA(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); CConversionSceneNode* pScene = m_pScene->GetScene(m_pScene->AddScene(GetFilename(sFilename).append(_T(".sia")))); if (m_pWorkListener) m_pWorkListener->SetAction(_T("Reading file into memory..."), 0); FILE* fp = tfopen(sFilename, _T("r")); if (!fp) { printf("No input file. Sorry!\n"); return; } fseek(fp, 0L, SEEK_END); long iOBJSize = ftell(fp); fseek(fp, 0L, SEEK_SET); // Make sure we allocate more than we need just in case. size_t iFileSize = (iOBJSize+1) * (sizeof(tchar)+1); tchar* pszEntireFile = (tchar*)malloc(iFileSize); tchar* pszCurrent = pszEntireFile; // Read the entire file into an array first for faster processing. tstring sLine; while (fgetts(sLine, fp)) { tstrncpy(pszCurrent, iFileSize-(pszCurrent-pszEntireFile), sLine.c_str(), sLine.length()); size_t iLength = sLine.length(); if (pszCurrent[iLength-1] == _T('\n')) { pszCurrent[iLength-1] = _T('\0'); iLength--; } pszCurrent += iLength; pszCurrent++; if (m_pWorkListener) m_pWorkListener->WorkProgress(0); } pszCurrent[0] = _T('\0'); fclose(fp); const tchar* pszLine = pszEntireFile; const tchar* pszNextLine = NULL; while (pszLine < pszCurrent) { if (pszNextLine) pszLine = pszNextLine; pszNextLine = pszLine + tstrlen(pszLine) + 1; // This code used to call StripWhitespace() but that's too slow for very large files w/ millions of lines. // Instead we'll just cut the whitespace off the front and deal with whitespace on the end when we come to it. while (*pszLine && IsWhitespace(*pszLine)) pszLine++; if (tstrlen(pszLine) == 0) continue; eastl::vector<tstring> aTokens; tstrtok(pszLine, aTokens, _T(" ")); const tchar* pszToken = aTokens[0].c_str(); if (tstrncmp(pszToken, _T("-Version"), 8) == 0) { // Warning if version is later than 1.0, we may not support it int iMajor, iMinor; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" .")); if (asTokens.size() >= 3) { iMajor = stoi(asTokens[1]); iMinor = stoi(asTokens[2]); if (iMajor != 1 && iMinor != 0) printf("WARNING: I was programmed for version 1.0, this file is version %d.%d, so this might not work exactly right!\n", iMajor, iMinor); } } else if (tstrncmp(pszToken, _T("-Mat"), 4) == 0) { pszNextLine = ReadSIAMat(pszNextLine, pszCurrent, pScene, sFilename); } else if (tstrncmp(pszToken, _T("-Shape"), 6) == 0) { pszNextLine = ReadSIAShape(pszNextLine, pszCurrent, pScene); } else if (tstrncmp(pszToken, _T("-Texshape"), 9) == 0) { // This is the 3d UV space of the object, but we only care about its 2d UV space which is contained in rhw -Shape section, so meh. pszNextLine = ReadSIAShape(pszNextLine, pszCurrent, pScene, false); } } free(pszEntireFile); m_pScene->SetWorkListener(m_pWorkListener); for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { m_pScene->GetMesh(i)->CalculateEdgeData(); m_pScene->GetMesh(i)->CalculateVertexNormals(); m_pScene->GetMesh(i)->CalculateVertexTangents(); } m_pScene->CalculateExtends(); if (m_pWorkListener) m_pWorkListener->EndProgress(); }
void CModelConverter::ReadOBJ(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); FILE* fp = tfopen(sFilename, _T("r")); if (!fp) { printf("No input file. Sorry!\n"); return; } CConversionSceneNode* pScene = m_pScene->GetScene(m_pScene->AddScene(GetFilename(sFilename).append(_T(".obj")))); CConversionMesh* pMesh = m_pScene->GetMesh(m_pScene->AddMesh(GetFilename(sFilename))); // Make sure it exists. CConversionSceneNode* pMeshNode = m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh); size_t iCurrentMaterial = ~0; size_t iSmoothingGroup = ~0; bool bSmoothingGroups = false; tstring sLastTask; int iTotalVertices = 0; int iTotalFaces = 0; int iVerticesComplete = 0; int iFacesComplete = 0; if (m_pWorkListener) m_pWorkListener->SetAction(_T("Reading file into memory..."), 0); fseek(fp, 0L, SEEK_END); long iOBJSize = ftell(fp); fseek(fp, 0L, SEEK_SET); // Make sure we allocate more than we need just in case. size_t iFileSize = (iOBJSize+1) * (sizeof(tchar)+1); tchar* pszEntireFile = (tchar*)malloc(iFileSize); tchar* pszCurrent = pszEntireFile; pszCurrent[0] = _T('\0'); // Read the entire file into an array first for faster processing. tstring sLine; while (fgetts(sLine, fp)) { tstrncpy(pszCurrent, iFileSize-(pszCurrent-pszEntireFile), sLine.c_str(), sLine.length()); size_t iLength = sLine.length(); tchar cLastChar = pszCurrent[iLength-1]; while (cLastChar == _T('\n') || cLastChar == _T('\r')) { pszCurrent[iLength-1] = _T('\0'); iLength--; cLastChar = pszCurrent[iLength-1]; } pszCurrent += iLength; pszCurrent++; if (m_pWorkListener) m_pWorkListener->WorkProgress(0); } pszCurrent[0] = _T('\0'); fclose(fp); const tchar* pszLine = pszEntireFile; const tchar* pszNextLine = NULL; while (pszLine < pszCurrent) { if (pszNextLine) pszLine = pszNextLine; pszNextLine = pszLine + tstrlen(pszLine) + 1; // This code used to call StripWhitespace() but that's too slow for very large files w/ millions of lines. // Instead we'll just cut the whitespace off the front and deal with whitespace on the end when we come to it. while (*pszLine && IsWhitespace(*pszLine)) pszLine++; if (tstrlen(pszLine) == 0) continue; if (pszLine[0] == '#') { // ZBrush is kind enough to notate exactly how many vertices and faces we have in the comments at the top of the file. if (tstrncmp(pszLine, _T("#Vertex Count"), 13) == 0) { iTotalVertices = stoi(pszLine+13); pMesh->SetTotalVertices(iTotalVertices); } if (tstrncmp(pszLine, _T("#Face Count"), 11) == 0) { iTotalFaces = stoi(pszLine+11); pMesh->SetTotalFaces(iTotalFaces); // Don't kill the video card while we're loading the faces. if (iTotalFaces > 10000) pMeshNode->GetMeshInstance(0)->SetVisible(false); } continue; } tchar szToken[1024]; tstrncpy(szToken, 1024, pszLine, 1024); tchar* pszState = NULL; tchar* pszToken = strtok<tchar>(szToken, " ", &pszState); if (tstrncmp(pszToken, _T("mtllib"), 6) == 0) { tstring sDirectory = GetDirectory(sFilename); tstring sMaterial = sprintf(tstring("%s/%s"), sDirectory.c_str(), pszLine + 7); ReadMTL(sMaterial); } else if (tstrncmp(pszToken, _T("o"), 1) == 0) { // Dunno what this does. } else if (tstrncmp(pszToken, _T("v"), 2) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(iVerticesComplete++); else { m_pWorkListener->SetAction(_T("Reading vertex data"), iTotalVertices); sLastTask = tstring(pszToken); } } // A vertex. float v[3]; // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszToken = pszLine+1; int iDimension = 0; while (*pszToken) { while (pszToken[0] == _T(' ')) pszToken++; v[iDimension++] = (float)stof(pszToken); if (iDimension >= 3) break; while (pszToken[0] != _T(' ')) pszToken++; } pMesh->AddVertex(v[0], v[1], v[2]); } else if (tstrncmp(pszToken, _T("vn"), 3) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(0); else m_pWorkListener->SetAction(_T("Reading vertex normal data"), 0); } sLastTask = tstring(pszToken); // A vertex normal. float x, y, z; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 4) { x = stof(asTokens[1]); y = stof(asTokens[2]); z = stof(asTokens[3]); pMesh->AddNormal(x, y, z); } } else if (tstrncmp(pszToken, _T("vt"), 3) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(0); else m_pWorkListener->SetAction(_T("Reading texture coordinate data"), 0); } sLastTask = tstring(pszToken); // A UV coordinate for a vertex. float u, v; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 3) { u = stof(asTokens[1]); v = stof(asTokens[2]); pMesh->AddUV(u, v); } } else if (tstrncmp(pszToken, _T("g"), 1) == 0) { // A group of faces. pMesh->AddBone(pszLine+2); } else if (tstrncmp(pszToken, _T("usemtl"), 6) == 0) { // All following faces should use this material. tstring sMaterial = tstring(pszLine+7); size_t iMaterial = pMesh->FindMaterialStub(sMaterial); if (iMaterial == ((size_t)~0)) { size_t iSceneMaterial = m_pScene->FindMaterial(sMaterial); if (iSceneMaterial == ((size_t)~0)) iCurrentMaterial = m_pScene->AddDefaultSceneMaterial(pScene, pMesh, sMaterial); else { size_t iMaterialStub = pMesh->AddMaterialStub(sMaterial); m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh)->GetMeshInstance(0)->AddMappedMaterial(iMaterialStub, iSceneMaterial); iCurrentMaterial = iMaterialStub; } } else iCurrentMaterial = iMaterial; } else if (tstrncmp(pszToken, _T("s"), 1) == 0) { if (tstrncmp(pszLine, _T("s off"), 5) == 0) { iSmoothingGroup = ~0; } else { bSmoothingGroups = true; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 2) iSmoothingGroup = stoi(asTokens[1]); } } else if (tstrncmp(pszToken, _T("f"), 1) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(iFacesComplete++); else { m_pWorkListener->SetAction(_T("Reading polygon data"), iTotalFaces); sLastTask = tstring(pszToken); } } if (iCurrentMaterial == ~0) iCurrentMaterial = m_pScene->AddDefaultSceneMaterial(pScene, pMesh, pMesh->GetName()); // A face. size_t iFace = pMesh->AddFace(iCurrentMaterial); // If we get to 10k faces force the mesh off so it doesn't kill the video card. if (iFace == 10000) pMeshNode->GetMeshInstance(0)->SetVisible(false); pMesh->GetFace(iFace)->m_iSmoothingGroup = iSmoothingGroup; while (pszToken = strtok<tchar>(NULL, _T(" "), &pszState)) { if (tstrlen(pszToken) == 0) continue; // We don't use size_t because SOME EXPORTS put out negative numbers. long f[3]; bool bValues[3]; bValues[0] = false; bValues[1] = false; bValues[2] = false; // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszValues = pszToken; int iValue = 0; do { if (!pszValues) break; if (!bValues[0] || pszValues[0] == _T('/')) { if (pszValues[0] == _T('/')) pszValues++; bValues[iValue] = true; f[iValue++] = (long)stoi(pszValues); if (iValue >= 3) break; } // Don't advance if we're on a slash, because that means empty slashes. ie, 11//12 <-- the 12 would get skipped. if (pszValues[0] != _T('/')) pszValues++; } while (*pszValues); if (bValues[0]) { if (f[0] < 0) f[0] = (long)pMesh->GetNumVertices()+f[0]+1; TAssert ( f[0] >= 1 && f[0] < (long)pMesh->GetNumVertices()+1 ); } if (bValues[1] && pMesh->GetNumUVs()) { if (f[1] < 0) f[1] = (long)pMesh->GetNumUVs()+f[1]+1; TAssert ( f[1] >= 1 && f[1] < (long)pMesh->GetNumUVs()+1 ); } if (bValues[2] && pMesh->GetNumNormals()) { if (f[2] < 0) f[2] = (long)pMesh->GetNumNormals()+f[2]+1; TAssert ( f[2] >= 1 && f[2] < (long)pMesh->GetNumNormals()+1 ); } // OBJ uses 1-based indexing. // Convert to 0-based indexing. f[0]--; f[1]--; f[2]--; if (!pMesh->GetNumUVs()) f[1] = ~0; if (bValues[2] == false || !pMesh->GetNumNormals()) f[2] = ~0; pMesh->AddVertexToFace(iFace, f[0], f[1], f[2]); } } } free(pszEntireFile); m_pScene->SetWorkListener(m_pWorkListener); m_pScene->CalculateExtends(); for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { m_pScene->GetMesh(i)->CalculateEdgeData(); if (bSmoothingGroups || m_pScene->GetMesh(i)->GetNumNormals() == 0) m_pScene->GetMesh(i)->CalculateVertexNormals(); m_pScene->GetMesh(i)->CalculateVertexTangents(); } if (m_pWorkListener) m_pWorkListener->EndProgress(); }