diff --git a/rts/Map/SMF/SMFReadMap.cpp b/rts/Map/SMF/SMFReadMap.cpp index 23976425ace..438ee393f76 100644 --- a/rts/Map/SMF/SMFReadMap.cpp +++ b/rts/Map/SMF/SMFReadMap.cpp @@ -302,10 +302,12 @@ void CSMFReadMap::CreateGrassTex() grassShadingTex.SetRawSize(int2(1024, 1024)); CBitmap grassShadingTexBM; - if (grassShadingTexBM.Load(mapInfo->smf.grassShadingTexName)) { - grassShadingTex.SetRawTexID(grassShadingTexBM.CreateMipMapTexture()); - grassShadingTex.SetRawSize(int2(grassShadingTexBM.xsize, grassShadingTexBM.ysize)); - } + + if (!grassShadingTexBM.Load(mapInfo->smf.grassShadingTexName)) + grassShadingTexBM.AllocDummy(); + + grassShadingTex.SetRawTexID(grassShadingTexBM.CreateMipMapTexture()); + grassShadingTex.SetRawSize(int2(grassShadingTexBM.xsize, grassShadingTexBM.ysize)); } @@ -314,7 +316,7 @@ void CSMFReadMap::CreateDetailTex() CBitmap detailTexBM; if (!detailTexBM.Load(mapInfo->smf.detailTexName)) - throw content_error("Could not load detail texture from file " + mapInfo->smf.detailTexName); + detailTexBM.AllocDummy(); detailTex.SetRawTexID(detailTexBM.CreateTexture(texAnisotropyLevels[false], 0.0f, true)); detailTex.SetRawSize(int2(detailTexBM.xsize, detailTexBM.ysize)); @@ -849,51 +851,56 @@ const char* CSMFReadMap::GetFeatureTypeName(int typeID) { return mapFile.GetFeat unsigned char* CSMFReadMap::GetInfoMap(const std::string& name, MapBitmapInfo* bmInfo) { - char failMsg[512]; - // get size mapFile.GetInfoMapSize(name, bmInfo); if (bmInfo->width <= 0) return nullptr; + char errMsg[512]; unsigned char* data = new unsigned char[bmInfo->width * bmInfo->height]; CBitmap infomapBM; std::string texName; - if (name == "metal" && !mapInfo->smf.metalmapTexName.empty()) { - texName = mapInfo->smf.metalmapTexName; - } else if (name == "type" && !mapInfo->smf.typemapTexName.empty()) { - texName = mapInfo->smf.typemapTexName; - } else if (name == "grass" && !mapInfo->smf.grassmapTexName.empty()) { - texName = mapInfo->smf.grassmapTexName; + + switch (hashString(name.c_str())) { + case hashString("metal"): { texName = mapInfo->smf.metalmapTexName; } break; + case hashString("type" ): { texName = mapInfo->smf.typemapTexName ; } break; + case hashString("grass"): { texName = mapInfo->smf.grassmapTexName; } break; + default: { + LOG_L(L_WARNING, "[SMFReadMap::%s] unknown texture-name \"%s\"", __func__, name.c_str()); + } break; } + // get data from mapinfo-override texture if (!texName.empty() && !infomapBM.LoadGrayscale(texName)) - throw content_error("[CSMFReadMap::GetInfoMap] cannot load: " + texName); + LOG_L(L_WARNING, "[SMFReadMap::%s] cannot load override-texture \"%s\"", __func__, texName.c_str()); if (!infomapBM.Empty()) { if (infomapBM.xsize == bmInfo->width && infomapBM.ysize == bmInfo->height) { memcpy(data, infomapBM.GetRawMem(), bmInfo->width * bmInfo->height); return data; } - sprintf(failMsg, "[CSMFReadMap::GetInfoMap] Invalid image dimensions: %s %ix%i != %ix%i", - texName.c_str(), infomapBM.xsize, infomapBM.ysize, - bmInfo->width, bmInfo->height); - throw content_error(failMsg); - } - // get data - if (!mapFile.ReadInfoMap(name, data)) { - delete[] data; - data = nullptr; + snprintf(errMsg, sizeof(errMsg), "[SMFReadMap::%s] invalid dimensions for override-texture \"%s\": %ix%i != %ix%i", + __func__, texName.c_str(), + infomapBM.xsize, infomapBM.ysize, + bmInfo->width, bmInfo->height + ); + + throw content_error(errMsg); } - return data; + // get data from map itself + if (mapFile.ReadInfoMap(name, data)) + return data; + + delete[] data; + return nullptr; } -void CSMFReadMap::FreeInfoMap(const std::string& name, unsigned char *data) +void CSMFReadMap::FreeInfoMap(const std::string& name, unsigned char* data) { delete[] data; } diff --git a/rts/Rendering/Textures/Bitmap.cpp b/rts/Rendering/Textures/Bitmap.cpp index 2a003312746..ca9dd985269 100644 --- a/rts/Rendering/Textures/Bitmap.cpp +++ b/rts/Rendering/Textures/Bitmap.cpp @@ -385,6 +385,9 @@ const uint8_t* CBitmap::GetRawMem() const { return ((memIdx == size_t(-1))? null void CBitmap::Alloc(int w, int h, int c) { + if (!Empty()) + texMemPool.Free(GetRawMem(), GetMemSize()); + memIdx = texMemPool.AllocIdx((xsize = w) * (ysize = h) * (channels = c)); memset(GetRawMem(), 0, GetMemSize()); } @@ -392,6 +395,7 @@ void CBitmap::Alloc(int w, int h, int c) void CBitmap::AllocDummy(const SColor fill) { compressed = false; + Alloc(1, 1, sizeof(SColor)); memcpy(GetRawMem(), &fill.r, sizeof(SColor)); } @@ -402,7 +406,9 @@ bool CBitmap::Load(std::string const& filename, uint8_t defaultAlpha) SCOPED_TIMER("Misc::Bitmap::Load"); #endif - bool noAlpha = true; + bool isLoaded = false; + bool isValid = false; + bool noAlpha = true; const bool loadDDS = (FileSystem::GetExtension(filename) == "dds"); // always lower-case const bool flipDDS = true; // default, also assumed by gl.TexRect @@ -410,6 +416,7 @@ bool CBitmap::Load(std::string const& filename, uint8_t defaultAlpha) const size_t curMemSize = GetMemSize(); + channels = 4; #ifndef BITMAP_NO_OPENGL textype = GL_TEXTURE_2D; #endif @@ -458,21 +465,18 @@ bool CBitmap::Load(std::string const& filename, uint8_t defaultAlpha) compressed = loadDDS; #endif - channels = 4; - CFileHandler file(filename); + std::vector buffer; if (!file.FileExists()) { AllocDummy(); return false; } - std::vector buffer; - if (!file.IsBuffered()) { - buffer.resize(file.FileSize() + 2, 0); - file.Read(buffer.data(), file.FileSize()); + buffer.resize(file.FileSize(), 0); + file.Read(buffer.data(), buffer.size()); } else { // steal if file was loaded from VFS buffer = std::move(file.GetBuffer()); @@ -482,7 +486,8 @@ bool CBitmap::Load(std::string const& filename, uint8_t defaultAlpha) { std::lock_guard lck(texMemPool.GetMutex()); - // IL does not vertically flip DDS images by default, unlike nv_dds + // do not preserve the image origin since IL does not + // vertically flip DDS images by default, unlike nv_dds ilOriginFunc((loadDDS && flipDDS)? IL_ORIGIN_LOWER_LEFT: IL_ORIGIN_UPPER_LEFT); ilEnable(IL_ORIGIN_SET); @@ -494,43 +499,39 @@ bool CBitmap::Load(std::string const& filename, uint8_t defaultAlpha) // do not signal floating point exceptions in devil library ScopedDisableFpuExceptions fe; - const bool success = !!ilLoadL(IL_TYPE_UNKNOWN, buffer.data(), buffer.size()); + isLoaded = !!ilLoadL(IL_TYPE_UNKNOWN, buffer.data(), buffer.size()); + isValid = (isLoaded && IsValidImageFormat(ilGetInteger(IL_IMAGE_FORMAT))); + noAlpha = (isValid && (ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL) != 4)); // FPU control word has to be restored as well streflop::streflop_init(); - - ilDisable(IL_ORIGIN_SET); - - if (!success) { - AllocDummy(); - return false; - } } - { - if (!IsValidImageFormat(ilGetInteger(IL_IMAGE_FORMAT))) { - LOG_L(L_ERROR, "Invalid image format for %s: %d", filename.c_str(), ilGetInteger(IL_IMAGE_FORMAT)); - return false; - } - } + if (isValid) { + ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE); - noAlpha = (ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL) != 4); - ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE); + xsize = ilGetInteger(IL_IMAGE_WIDTH); + ysize = ilGetInteger(IL_IMAGE_HEIGHT); - xsize = ilGetInteger(IL_IMAGE_WIDTH); - ysize = ilGetInteger(IL_IMAGE_HEIGHT); - - { texMemPool.FreeRaw(GetRawMem(), curMemSize); memIdx = texMemPool.AllocIdxRaw(GetMemSize()); // ilCopyPixels(0, 0, 0, xsize, ysize, 0, IL_RGBA, IL_UNSIGNED_BYTE, GetRawMem()); std::memcpy(GetRawMem(), ilGetData(), GetMemSize()); + } else { + LOG_L(L_ERROR, "[BMP::%s] failed to load \"%s\" or invalid format %d", __func__, filename.c_str(), ilGetInteger(IL_IMAGE_FORMAT)); } + ilDisable(IL_ORIGIN_SET); ilDeleteImages(1, &imageID); } + // has to be outside the mutex scope + if (!isValid) { + AllocDummy(); + return false; + } + if (noAlpha) { uint8_t* mem = GetRawMem();