virtual C4Surface* LoadTexture(const char* filename) { if (!Group.AccessEntry(filename)) return NULL; C4Surface* surface = new C4Surface; // Suppress error message here, StdMeshMaterial loader // will show one. if (!surface->Read(Group, GetExtension(filename), C4SF_MipMap)) { delete surface; surface = NULL; } return surface; }
bool C4FacetExSurface::CopyFromSfcMaxSize(C4Surface &srcSfc, int32_t iMaxSize, uint32_t dwColor) { // safety if (!srcSfc.Wdt || !srcSfc.Hgt) return false; Clear(); // no scale? bool fNeedsScale = !(srcSfc.Wdt <= iMaxSize && srcSfc.Hgt <= iMaxSize); if (!fNeedsScale && !dwColor) { // no change necessary; just copy then Face.Copy(srcSfc); } else { // must scale down or colorize. Just blit. C4Facet fctSource; fctSource.Set(&srcSfc, 0, 0, srcSfc.Wdt, srcSfc.Hgt); int32_t iTargetWdt, iTargetHgt; if (fNeedsScale) { if (fctSource.Wdt > fctSource.Hgt) { iTargetWdt = iMaxSize; iTargetHgt = fctSource.Hgt * iTargetWdt / fctSource.Wdt; } else { iTargetHgt = iMaxSize; iTargetWdt = fctSource.Wdt * iTargetHgt / fctSource.Hgt; } } else { iTargetWdt = fctSource.Wdt; iTargetHgt = fctSource.Hgt; } if (dwColor) srcSfc.SetClr(dwColor); Create(iTargetWdt, iTargetHgt); lpDDraw->Blit(&srcSfc, 0.0f, 0.0f, float(fctSource.Wdt), float(fctSource.Hgt), &Face, 0, 0, iTargetWdt, iTargetHgt); } Set(&Face, 0, 0, Face.Wdt, Face.Hgt); return true; }
bool C4GraphicsResource::LoadFile(C4Surface& sfc, const char *szName, C4GroupSet &rGfxSet, int32_t &ridCurrSfc, int iFlags) { // find char FileName[_MAX_FNAME]; int32_t ID = 0; C4Group *pGrp = FindSuitableFile(szName, rGfxSet, FileName, &ID); if (!pGrp) { LogF(LoadResStr("IDS_PRC_NOGFXFILE"), szName, LoadResStr("IDS_PRC_FILENOTFOUND")); return false; } // check group if (ID == ridCurrSfc) // already up-to-date return true; // load if (!sfc.Load(*pGrp, FileName, false, false, iFlags)) { LogF(LoadResStr("IDS_PRC_NOGFXFILE"), FileName, LoadResStr("IDS_ERR_NOFILE")); return false; } ridCurrSfc = ID; Game.SetInitProgress(ProgressStart); ProgressStart += ProgressIncrement; return true; }
bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs) { // Populate our map with all needed textures MaterialTextureMap.push_back(StdCopyStrBuf("")); AddTexturesFromMap(pTexs); // Determine depth to use iMaterialTextureDepth = 2*MaterialTextureMap.size(); int32_t iNormalDepth = iMaterialTextureDepth / 2; // Find the largest texture C4Texture *pTex; C4Surface *pRefSfc = NULL; for(int iTexIx = 0; (pTex = pTexs->GetTexture(pTexs->GetTexture(iTexIx))); iTexIx++) if(C4Surface *pSfc = pTex->Surface32) if (!pRefSfc || pRefSfc->Wdt < pSfc->Wdt || pRefSfc->Hgt < pSfc->Hgt) pRefSfc = pSfc; if(!pRefSfc) return false; // Get size for our textures. We might be limited by hardware int iTexWdt = pRefSfc->Wdt, iTexHgt = pRefSfc->Hgt; GLint iMaxTexSize, iMaxTexLayers; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &iMaxTexSize); glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &iMaxTexLayers); if (iTexWdt > iMaxTexSize || iTexHgt > iMaxTexSize) { iTexWdt = std::min(iTexWdt, iMaxTexSize); iTexHgt = std::min(iTexHgt, iMaxTexSize); LogF(" gl: Material textures too large, GPU only supports %dx%d! Cropping might occur!", iMaxTexSize, iMaxTexSize); } if(iMaterialTextureDepth >= iMaxTexLayers) { LogF(" gl: Too many material textures! GPU only supports 3D texture depth of %d!", iMaxTexSize); return false; } iMaterialWidth = iTexWdt; iMaterialHeight = iTexHgt; // Compose together data of all textures const int iTexSize = iTexWdt * iTexHgt * C4Draw::COLOR_DEPTH_BYTES; const int iSize = iTexSize * iMaterialTextureDepth; BYTE *pData = new BYTE [iSize]; for(int i = 0; i < iMaterialTextureDepth; i++) { BYTE *p = pData + i * iTexSize; // Get texture at position StdStrBuf Texture; bool fNormal = i >= iNormalDepth; if(i < int32_t(MaterialTextureMap.size())) Texture.Ref(MaterialTextureMap[i]); else if(fNormal && i < iNormalDepth + int32_t(MaterialTextureMap.size())) Texture.Format("%s_NRM", MaterialTextureMap[i-iNormalDepth].getData()); // Try to find the texture C4Texture *pTex; C4Surface *pSurface; if((pTex = pTexs->GetTexture(Texture.getData())) && (pSurface = pTex->Surface32)) { #ifdef DEBUG_SOLID_COLOR_TEXTURES // Just write a solid color that depends on the texture index DWORD *texdata = reinterpret_cast<DWORD *>(p); for (int y = 0; y < iTexHgt; ++y) for (int x = 0; x < iTexWdt; ++x) *texdata++ = RGBA((iTex & 48), (iTex & 3) * 16, (i & 12) * 4, 255); continue; #else // Size recheck. It's fine if this texture's size is a divisor // of the maximum texture size, because then we can just tile // the smaller texture. if(pSurface->Wdt != iTexWdt || pSurface->Hgt != iTexHgt) if (iTexWdt % pSurface->Wdt != 0 || iTexHgt % pSurface->Hgt != 0) LogF(" gl: texture %s size mismatch (%dx%d vs %dx%d)!", Texture.getData(), pSurface->Wdt, pSurface->Hgt, iTexWdt, iTexHgt); // Copy bytes DWORD *texdata = reinterpret_cast<DWORD *>(p); pSurface->Lock(); for (int y = 0; y < iTexHgt; ++y) for (int x = 0; x < iTexWdt; ++x) *texdata++ = pSurface->GetPixDw(x % pSurface->Wdt, y % pSurface->Hgt, false); pSurface->Unlock(); continue; #endif } // Seperator texture? if(SEqual(Texture.getData(), SEPERATOR_TEXTURE)) { // Make some ugly stripes DWORD *texdata = reinterpret_cast<DWORD *>(p); for (int y = 0; y < iTexHgt; ++y) for (int x = 0; x < iTexWdt; ++x) *texdata++ = ((x + y) % 32 < 16 ? RGBA(255, 0, 0, 255) : RGBA(0, 255, 255, 255)); continue; } // If we didn't "continue" yet, we haven't written the texture yet. // Make color texture transparent, and normal texture flat. if (fNormal) { DWORD *texdata = reinterpret_cast<DWORD *>(p); for (int y = 0; y < iTexHgt; ++y) for (int x = 0; x < iTexWdt; ++x) *texdata++ = RGBA(127, 127, 255, 255); } else memset(p, 0, iTexSize); } // Clear error error(s?) while(glGetError()) {} // Alloc 1D matmap texture glGenTextures(1, &matMapTexture); // Alloc 2D texture array glGenTextures(1, &hMaterialTexture); // Generate textures int iSizeSum = 0; // Select texture glBindTexture(GL_TEXTURE_2D_ARRAY, hMaterialTexture); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // We fully expect to tile these glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); // Make it happen! glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, iTexWdt, iTexHgt, iMaterialTextureDepth, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pData); glGenerateMipmap(GL_TEXTURE_2D_ARRAY); // Statistics iSizeSum += iTexWdt * iTexHgt * iMaterialTextureDepth * C4Draw::COLOR_DEPTH_BYTES; // Dispose of data delete [] pData; // Check whether we were successful if(int err = glGetError()) { LogF(" gl: Could not load textures (error %d)", err); return false; } // Announce the good news LogF(" gl: Texturing uses %d slots at %dx%d (%d MB total)", static_cast<int>(MaterialTextureMap.size()), iMaterialWidth, iMaterialHeight, iSizeSum / 1000000); return true; }
bool C4FontLoader::InitFont(CStdFont &rFont, const char *szFontName, FontType eType, int32_t iSize, C4GroupSet *pGfxGroups, bool fDoShadow) { // safety if (!szFontName || !*szFontName) { LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } // get font to load // pFontDefs may be NULL if no fonts are loaded; but then iFontDefCount is zero as well // the function must not be aborted, because a standard windows font may be loaded std::vector<C4FontDef>::iterator pFontDefC = FontDefs.begin(), pFontDef = FontDefs.end(); while (pFontDefC != FontDefs.end()) { // check font if (pFontDefC->Name == szFontName) { int32_t iSizeDiff = Abs(pFontDefC->iSize - iSize); // better match than last font? if (pFontDef == FontDefs.end() || Abs(pFontDef->iSize - iSize) >= iSizeDiff) pFontDef = pFontDefC; } // check next one ++pFontDefC; } // if def has not been found, use the def as font name // determine font def string const char *szFontString = szFontName; // special: Fonts without shadow are always newly rendered if (!fDoShadow) { pFontDef=FontDefs.end(); } if (pFontDef!=FontDefs.end()) switch (eType) { case C4FT_Log: szFontString = pFontDef->LogFont.getData(); break; case C4FT_MainSmall:szFontString = pFontDef->SmallFont.getData(); break; case C4FT_Main: szFontString = pFontDef->Font.getData(); break; case C4FT_Caption: szFontString = pFontDef->CaptionFont.getData(); break; case C4FT_Title: szFontString = pFontDef->TitleFont.getData(); break; default: LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; // invalid call } // font not assigned? if (!*szFontString) { // invalid call or spec LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } // get font name char FontFaceName[C4MaxName+1], FontParam[C4MaxName+1]; SCopyUntil(szFontString, FontFaceName, ',', C4MaxName); // is it an image file? const char *szExt = GetExtension(FontFaceName); if (SEqualNoCase(szExt, "png") || SEqualNoCase(szExt, "bmp")) { // image file name: load bitmap font from image file // if no graphics group is given, do not load yet if (!pGfxGroups) { LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } // indent given? int32_t iIndent = 0; if (SCopySegment(szFontString, 1, FontParam, ',', C4MaxName)) sscanf(FontParam, "%i", &iIndent); // load font face from gfx group int32_t iGrpId; C4Group *pGrp = pGfxGroups->FindEntry(FontFaceName, NULL, &iGrpId); if (!pGrp) { LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } // check if it's already loaded from that group with that parameters if (!rFont.IsSameAsID(FontFaceName, iGrpId, iIndent)) { // it's not; so (re-)load it now! if (rFont.IsInitialized()) { // reloading rFont.Clear(); LogF(LoadResStr("IDS_PRC_UPDATEFONT"), FontFaceName, iIndent, 0); } C4Surface sfc; if (!sfc.Load(*pGrp, FontFaceName)) { LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } // init font from face try { rFont.Init(GetFilenameOnly(FontFaceName), &sfc, iIndent); } catch (std::runtime_error & e) { LogFatal(e.what()); LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } rFont.id = iGrpId; } } else { int32_t iDefFontSize; DWORD dwDefWeight=FW_NORMAL; #if defined(_WIN32) && !defined(HAVE_FREETYPE) switch (eType) { case C4FT_Log: iDefFontSize = 8; break; case C4FT_MainSmall:iDefFontSize = iSize+1; break; case C4FT_Main: iDefFontSize = iSize+4; break; case C4FT_Caption: iDefFontSize = iSize+6; dwDefWeight = FW_BOLD; break; case C4FT_Title: iDefFontSize = iSize*3; break; default: LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; // invalid call } #else switch (eType) { case C4FT_Log: iDefFontSize = iSize*12/14; break; case C4FT_MainSmall:iDefFontSize = iSize*13/14; break; case C4FT_Main: iDefFontSize = iSize; break; case C4FT_Caption: iDefFontSize = iSize*16/14; /*dwDefWeight = FW_MEDIUM;*/ break; case C4FT_Title: iDefFontSize = iSize*22/14; /*dwDefWeight = FW_MEDIUM;*/ break; default: LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; // invalid call } #endif // regular font name: let WinGDI or Freetype draw a font with the given parameters // font size given? if (SCopySegment(szFontString, 1, FontParam, ',', C4MaxName)) sscanf(FontParam, "%i", &iDefFontSize); // font weight given? if (SCopySegment(szFontString, 2, FontParam, ',', C4MaxName)) sscanf(FontParam, "%i", &dwDefWeight); // check if it's already loaded from that group with that parameters if (!rFont.IsSameAs(FontFaceName, iDefFontSize, dwDefWeight)) { // it's not; so (re-)load it now! if (rFont.IsInitialized()) { // reloading rFont.Clear(); LogF(LoadResStr("IDS_PRC_UPDATEFONT"), FontFaceName, iDefFontSize, dwDefWeight); } // init with given font name try { // check if one of the internally listed fonts should be used C4VectorFont * pFont = pVectorFonts; while (pFont) { if (SEqual(pFont->Name.getData(), FontFaceName)) { if (InitFont(rFont, pFont, iDefFontSize, dwDefWeight, fDoShadow)) break; } pFont = pFont->pNext; } // no internal font matching? Then create one using the given face/filename (using a system font) if (!pFont) { pFont = new C4VectorFont(); if (pFont->Init(FontFaceName, iDefFontSize, dwDefWeight, Config.General.LanguageCharset)) { AddVectorFont(pFont); if (!InitFont(rFont, pFont, iDefFontSize, dwDefWeight, fDoShadow)) throw std::runtime_error(FormatString("Error initializing font %s", FontFaceName).getData()); } else { delete pFont; // no match for font face found throw std::runtime_error(FormatString("Font face %s undefined", FontFaceName).getData()); } } } catch (std::runtime_error & e) { LogFatal(e.what()); LogFatal(LoadResStr("IDS_ERR_INITFONTS")); return false; } rFont.id = 0; } } // done, success return true; }