// Working thread for the pool ThreadResult * ThreadPoolWork(ThreadOrder * order) { ThreadString * next = (ThreadString *)order; ChunkPrefs prefs = next->prefs; Chunk * chunk = next->chunk; chunk->pref = prefs; // Alpha if (prefs.version == ALPHA) { chunk->Load(next->file); } // Beta else if (prefs.version == BETA) { chunk->Load((BYTE *)next->file.c_str(), next->file.size()); } if (chunk->isValid()) { chunk->CreateImage(); return (ThreadResult *)1; } return (ThreadResult *)0; }
// Create image saved in file int Level::CreateImage(const STRING & file) { if (cancel) return LVL_ERR_CANCEL; state = CREATEIMAGE; if (chunks.empty()) return LVL_ERR_NOCHUNKS; INT64 minX = MAPCOORD; INT64 minY = MAPCOORD; INT64 maxX = -MAPCOORD; INT64 maxY = -MAPCOORD; blocks = chunks.size() << 8; bool doRender = !(prefs.flags & CHUNKP_NORENDER); // Calculate size for (list<Chunk *>::iterator i = chunks.begin(); i != chunks.end(); ++i) { Chunk * chunk = (*i); if (!chunk->isValid()) continue; if (doRender) { COORDS x = chunk->GetX(); COORDS y = chunk->GetY(); if (x < minX) minX = x; if (y < minY) minY = y; if (x > maxX) maxX = x; if (y > maxY) maxY = y; } // And add to amount while we are processing amount += chunk->amount; } if (cancel) return LVL_ERR_CANCEL; if (doRender) { // No valid chunks? if (minX == MAPCOORD && minY == MAPCOORD && maxX == -MAPCOORD && maxY == -MAPCOORD) return LVL_ERR_INVALIDCHUNKS; prefs.rotation = abs((prefs.rotation / 90) * 90) % 360; float rad = (2 * 3.14159265f * prefs.rotation) / 360; UINT maxWidth = (UINT)(maxX - minX), maxHeight = (UINT)(maxY - minY); UINT width = (maxWidth + 1) * MAPX, height = (maxHeight + 1) * MAPY; // Foolproof if (width == 0 || height == 0) return LVL_ERR_INVALIDSIZE; // Rotate { float rCos = cos(rad); float rSin = sin(rad); rCos = (rCos < 0) ? -rCos : rCos; rSin = (rSin < 0) ? -rSin : rSin; UINT newWidth = UINT(width * rCos + height * rSin); UINT newHeight = UINT(height * rCos + width * rSin); width = newWidth; height = newHeight; } // Foolproof if (width == 0 || height == 0) return LVL_ERR_INVALIDSIZE; bool useCache = !prefs.cache.empty(); ImageCache cache(height, width); Image * image = 0; if (!useCache) { #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif // No more than 1 GiB if (width * height * sizeof(Color) > min(1073741824, Computer::GetAvailableMemory())) return LVL_ERR_TOOLARGE; try { image = new Image(height, width); if (image == 0) throw LVL_ERR_TOOLARGE; } catch (Level_Error error) { return error; } } else { STRING cacheFile = prefs.cache; cacheFile.append(STR("\\cache.bin")); cacheFile = Port::ReplacePath(cacheFile); if (!cache.Open(cacheFile)) return LVL_ERR_CACHE; } // Sort list //chunks.sort(compare_chunks); // Found duplicates //if (amountDuplicates > 0) // return LVL_ERR_DUPLICATES; // Create image int n = 0; for (list<Chunk *>::iterator i = chunks.begin(); i != chunks.end(); ++i, ++n) { Chunk * chunk = (*i); if (!chunk->isValid()) continue; Image * img = chunk->GetImage(); // One more try if (!img) { chunk->pref = prefs; chunk->CreateImage(); img = chunk->GetImage(); if (!img) continue; } UINT x = 0; UINT y = 0; switch (prefs.rotation) { case 90: x = (width - (UINT(chunk->GetY() - minY) * (MAPY))) - MAPY; y = UINT(chunk->GetX() - minX) * MAPX; break; case 180: x = (width - (UINT(chunk->GetX() - minX) * (MAPX))) - MAPX; y = (height - (UINT(chunk->GetY() - minY) * (MAPY))) - MAPY; break; case 270: x = UINT(chunk->GetY() - minY) * MAPY; y = (height - (UINT(chunk->GetX() - minX) * (MAPX))) - MAPX; break; case 0: default: x = UINT(chunk->GetX() - minX) * MAPX; y = UINT(chunk->GetY() - minY) * MAPY; } Color chnk[MAPX][MAPY] = {0}; // Write pixel for pixel for (UINT X = 0; X < MAPX; ++X) { for (UINT Y = 0; Y < MAPY; ++Y) { UINT XX = 0; UINT YY = 0; switch (prefs.rotation) { case 90: XX = Y; YY = (MAPX - 1) - X; break; case 180: XX = (MAPX - 1) - X; YY = (MAPY - 1) - Y; break; case 270: XX = (MAPY - 1) - Y; YY = X; break; case 0: default: XX = X; YY = Y; } if (!useCache) { image->SetPixel((height - (y + Y)) - 1, (x + X), img->GetPixel(YY, XX)); } else { Color * current = (*chnk) + ((MAPY - (Y+1)) + (MAPY * X)); Color c = img->GetPixel(YY, XX); memcpy(current, &c, sizeof(Color)); } } } if (useCache) { for (UINT X = 0; X < MAPX; ++X) { cache.Write(chnk[X], (height - y) - MAPY, (x + X), MAPY); } } done = ((float)n/(float)total); } done = 1; // No render mode if (prefs.flags & CHUNKP_NORENDER) { saved = true; if (!useCache) { delete image; } else { cache.Close(); } state = FINALIZING; return LVL_OK; } // Save image state = SAVING; // Normal save of image if (!useCache) { if (image->PrepareSave(file)) { for (UINT i = 0; i < width; ++i) { if (!image->SaveRow(i)) break; done = (float)i/(float)width; } saved = image->CloseSave(); } done = 1; delete image; } // Save from cache else { ImageSave sav; if (sav.Prepare(file, height, width)) { Color * line = new Color[height]; for (UINT i = 0; i < width; ++i) { cache.Read(&line, 0, i, height); if (!sav.Row(line)) break; done = (float)i/(float)width; } delete[] line; saved = sav.Close(); } cache.Close(); done = 1; } } else { saved = true; } state = FINALIZING; return saved ? LVL_OK : LVL_ERR_SAVE; }
// Load singlethreaded void Level::LoadSingle() { // Go through all files Chunk * temp = 0; while (files.empty() == false && cancel == false) { if (prefs.version == ALPHA) { temp = new Chunk(); // Load chunk temp->pref = prefs; temp->Load(files.top()); files.pop(); // Everything is fine if (temp->isValid()) { temp->CreateImage(); chunks.push_back(temp); } else { // Display correct total chunks --total; // Evade memory leak delete temp; } // Do some aftermath result = chunks.size(); work = total - result; done = ((float)result/(float)total); } else if (prefs.version == BETA) { RegionReader region = RegionReader(); region.Load(files.top()); files.pop(); // Reduce amount total -= 1024 - region.GetAmountChunks(); // Go through region for (int i = 0; i < region.GetAmountChunks() && cancel == false; ++i) { temp = new Chunk(); // Load chunk temp->pref = prefs; UINT size = 0; BYTE * data = region.GetChunk(i, size); temp->Load(data, size); // Everything is fine if (temp->isValid()) { temp->CreateImage(); chunks.push_back(temp); } else { // Display correct total chunks --total; // Evade memory leak delete temp; } // Do some aftermath result = chunks.size(); work = total - result; done = ((float)result/(float)total); } } } }