void ItemEntity::DoCollision(World* world, double deltaTime) { m_pos.x += m_motion.x; m_pos.y += m_motion.y; int toprightX = (int)(m_pos.x - m_size.x / 2.0); int toprightY = (int)(m_pos.y - m_size.y / 2.0); Chunk* chunkPtr = world->GetChunkAt(toprightX / (Chunk::TILESIZE*Chunk::SIZE), toprightY / (Chunk::TILESIZE*Chunk::SIZE)); if (chunkPtr == nullptr) { m_motion.y += 1 * deltaTime; return; } int blockposX = toprightX / (Chunk::TILESIZE) - chunkPtr->GetX()*Chunk::SIZE; int blockposY = (toprightY + m_size.y/2.0) / (Chunk::TILESIZE) - chunkPtr->GetY()*Chunk::SIZE; Tile* tilePtr = chunkPtr->GetTileAt(blockposX, blockposY); double topRightLocX = toprightX - chunkPtr->GetX()* Chunk::TILESIZE* Chunk::SIZE; double topRightLocY = toprightY - chunkPtr->GetY()* Chunk::TILESIZE* Chunk::SIZE; if (tilePtr != nullptr) { if (tilePtr->type != Chunk::Type::AIR) { m_pos.y = blockposY * Chunk::TILESIZE + chunkPtr->GetY()* Chunk::TILESIZE* Chunk::SIZE - m_size.y / 2; m_motion.y = 0; } else { m_motion.y += 1 * deltaTime; } } }
// 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; }