#include "MipMapGen.h" #include "MipMap.h" #include static StaticMutex LevelsMutex; static Vector Levels; static Vector ZoomLevels; bool CalcLevel(Image& img, int& step, int blocks, int zoomLevel, const String& dir, Progress& p, const Size& totalSize, int cx, int cy, double zx); void CalcCount(Image& img, int cx, int cy, int& step); int GetScalesTotal(Image& img, const Size& sz, double zoom); int GetBlocksTotal(Image& img, const Size& sz, const Size& cellSize, double zoom); Size GetScaledSize(Image& img, const Size& sz, double zoom, int level); Image GetScaledMap(Image& img, const Size& sz); Image GetScaledMap(Image& img, const Size& sz, double zoom, int level); bool Calculate(int cx, int cy, int px, int py, double zx, const String& name, Image& img) { Mutex::Lock __(LevelsMutex); Levels.Clear(); ZoomLevels.Clear(); // getting data Size sz = Size(cx, cy); Size ps = Size(px, py); // preparing directory String dir = AppendFileName( AppendFileName(GetFileDirectory(GetExeFilePath()), "Mipmaps"), name); RemoveDirectory(dir); RealizeDirectory(dir); String xmlFile = AppendFileName( AppendFileName(GetFileDirectory(GetExeFilePath()), "Mipmaps"), name + ".xml"); String zoomFile = AppendFileName( AppendFileName(GetFileDirectory(GetExeFilePath()), "Mipmaps"), name.ToString() + ".zoom"); FileDelete(xmlFile); FileDelete(zoomFile); // generating first level Levels.Clear(); int blocks = GetBlocksTotal(img, ps, sz, zx); int total = GetScalesTotal(img, ps, zx); int count = 0; Progress p; p.Create(); Size last = Null; for (int i = 0; i < total - 1; ++i) { Image scaledMap = GetScaledMap(img, ps, zx, i + 1); if (i == total - 2) last = scaledMap.GetSize(); if (!CalcLevel(scaledMap, count, blocks, i, dir, p, scaledMap.GetSize(), cx, cy, (i == total - 1) ? 1.0 : zx)) break; } if (!IsNull(last)) CalcLevel(img, count, blocks, total - 1, dir, p, img.GetSize(), cx, cy, (double)img.GetSize().cx / last.cx); p.Close(); if (!StoreAsXMLFile(Levels, "levels", xmlFile)) { Exclamation("Ошибка при сохранении XML-файла карты!"); return false; } if (!StoreAsXMLFile(ZoomLevels, "zoomLevels", zoomFile)) { Exclamation("Ошибка при сохранении XML-файла значений zoom!"); return false; } return true; } bool CalcLevel(Image& img, int& step, int blocks, int zoomLevel, const String& dir, Progress& p, const Size& totalSize, int cx, int cy, double zx) { Size sz = Size(cx, cy); double ratio = (double)img.GetSize().cx / img.GetSize().cy; int xt = img.GetSize().cx / cx + (img.GetSize().cx % cx ? 1 : 0); int yt = img.GetSize().cy / cy + (img.GetSize().cy % cy ? 1 : 0); MipMapLevel level; level .TotalCX(xt).TotalCY(yt).BlockCX(cx).BlockCY(cy).ZoomDX(zx) .TotalSizeCX(totalSize.cx) .TotalSizeCY(totalSize.cy); ZoomLevels.Add(MapZoomLevel(zx)); int count = 0; for (int i = 0; i < xt; ++i) for (int j = 0; j < yt; ++j) { p.Title(NFormat("Блок %d из %d [%d, %d]", step + 1, blocks, cx, cy)); ImageBuffer ib(cx, cy); BufferPainter sw(ib); sw.DrawRect(ib.GetSize(), White()); sw.DrawImage(ib.GetSize(), img, Rect(Point(i * cx, j * cy), ib.GetSize())); PNGEncoder en; if (!en.SaveFile(AppendFileName(dir, NFormat("%d-%d-%d.png", zoomLevel, i * cx, j * cy)), Rescale(ib, sz, ib.GetSize()))) { Exclamation("Ошибка при сохранении MipMap-изображения!"); return false; } level.AddMipMap( Point(i * cx, j * cy), new MipMapItem() ); p.Set(step++, blocks); } // xml part Levels.Add(level); return true; } void CalcCount(Image& img, int cx, int cy, int& step) { Size sz = img.GetSize(); int xt = sz.cx / cx + (sz.cx % cx ? 1 : 0); int yt = sz.cy / cy + (sz.cy % cy ? 1 : 0); for (int i = 0; i < xt; ++i) for (int j = 0; j < yt; ++j) { step++; } } Image GetScaledMap(Image& img, const Size& sz) { double scale = min((double)sz.cx / img.GetSize().cx, (double)sz.cy / img.GetSize().cy); return Rescale(img, img.GetSize() * scale, img.GetSize()); } Image GetScaledMap(Image& img, const Size& sz, double zoom, int level) { return Rescale(img, GetScaledSize(img, sz, zoom, level), img.GetSize()); } Size GetScaledSize(Image& img, const Size& sz, double zoom, int level) { if (!level) return sz; double scale = min((double)sz.cx / img.GetSize().cx, (double)sz.cy / img.GetSize().cy); Size mapSize = img.GetSize() * scale; double ratio = (double)img.GetSize().cx / img.GetSize().cy; double w = (double)mapSize.cx; for (int i = 1; i < level; ++i) w *= zoom; if (w > img.GetSize().cx || w / ratio > img.GetSize().cy) return img.GetSize(); return Size(fabs(w), fabs(w / ratio)); } int GetScalesTotal(Image& img, const Size& sz, double zoom) { int totalCount = 0; Size check(0, 0); for(;;) { Size scaledSize = GetScaledSize(img, sz, zoom, totalCount + 1); bool found = false; if (check == Size(0, 0)) check = scaledSize; else { if (check == scaledSize) found = true; else check = scaledSize; } if (found) break; totalCount++; } return totalCount; } int GetBlocksTotal(Image& img, const Size& sz, const Size& cellSize, double zoom) { int total = GetScalesTotal(img, sz, zoom); int count = 0; for (int i = 0; i < total - 1; ++i) { Image scaledMap = GetScaledMap(img, sz, zoom, i + 1); if (i < total - 1) CalcCount(scaledMap, cellSize.cx, cellSize.cy, count); if (i == total - 1) CalcCount(img, cellSize.cx, cellSize.cy, count); } return count; }