void TileView::Render() { int dpyWidth = fw.Display_GetWidth(); int dpyHeight = fw.Display_GetHeight(); al_clear_to_color( al_map_rgb( 0, 0, 0 ) ); for (int y = 0; y < map.size.y; y++) { for (int z = 0; z < maxZDraw; z++) { for (int x = 0; x < map.size.x; x++) { bool showSelected = (fw.gamecore->DebugModeEnabled && z == selectedTilePosition.z && y == selectedTilePosition.y && x == selectedTilePosition.x); auto &tile = map.tiles[z][y][x]; // Skip over transparent (missing) tiles auto screenPos = tileToScreenCoords(Vec3<float>{(float)x,(float)y,(float)z}); screenPos.x += offsetX; screenPos.y += offsetY; //Skip over tiles that would be outside the window if (screenPos.x + tileSize.x < 0 || screenPos.y + tileSize.y < 0 || screenPos.x - tileSize.x > dpyWidth || screenPos.y - tileSize.y > dpyHeight) continue; if (showSelected) selectedTileImageBack->draw(screenPos.x, screenPos.y); for (auto obj : tile.objects) { if (obj->visible) { auto objScreenPos = tileToScreenCoords(obj->getPosition()); objScreenPos.x += offsetX; objScreenPos.y += offsetY; auto &img = obj->getSprite(); img.draw(objScreenPos.x, objScreenPos.y); } } if (showSelected) selectedTileImageFront->draw(screenPos.x, screenPos.y); } } } fw.gamecore->MouseCursor->Render(); }
void TileView::EventOccurred(Event *e) { bool selectionChanged = false; if (e->Type == EVENT_KEY_DOWN) { switch (e->Data.Keyboard.KeyCode) { case ALLEGRO_KEY_UP: // offsetY += tileSize.y; cameraScrollY = isoTileSize.y / 8; break; case ALLEGRO_KEY_DOWN: // offsetY -= tileSize.y; cameraScrollY = -isoTileSize.y / 8; break; case ALLEGRO_KEY_LEFT: // offsetX += tileSize.x; cameraScrollX = isoTileSize.x / 8; break; case ALLEGRO_KEY_RIGHT: // offsetX -= tileSize.x; cameraScrollX = -isoTileSize.x / 8; break; case ALLEGRO_KEY_PGDN: if (fw.gamecore->DebugModeEnabled && maxZDraw > 1) { maxZDraw--; } break; case ALLEGRO_KEY_PGUP: if (fw.gamecore->DebugModeEnabled && maxZDraw < map.size.z) { maxZDraw++; } break; case ALLEGRO_KEY_S: selectionChanged = true; if (selectedTilePosition.y < (map.size.y - 1)) selectedTilePosition.y++; break; case ALLEGRO_KEY_W: selectionChanged = true; if (selectedTilePosition.y > 0) selectedTilePosition.y--; break; case ALLEGRO_KEY_A: selectionChanged = true; if (selectedTilePosition.x > 0) selectedTilePosition.x--; break; case ALLEGRO_KEY_D: selectionChanged = true; if (selectedTilePosition.x < (map.size.x - 1)) selectedTilePosition.x++; break; case ALLEGRO_KEY_R: selectionChanged = true; if (selectedTilePosition.z < (map.size.z - 1)) selectedTilePosition.z++; break; case ALLEGRO_KEY_F: selectionChanged = true; if (selectedTilePosition.z > 0) selectedTilePosition.z--; break; case ALLEGRO_KEY_1: pal = fw.data->load_palette("xcom3/ufodata/PAL_01.DAT"); break; case ALLEGRO_KEY_2: pal = fw.data->load_palette("xcom3/ufodata/PAL_02.DAT"); break; case ALLEGRO_KEY_3: pal = fw.data->load_palette("xcom3/ufodata/PAL_03.DAT"); break; } } else if (e->Type == EVENT_MOUSE_DOWN) { auto &ev = e->Data.Mouse; auto selectedPos = Vec2<float>{static_cast<float>(ev.X) - offsetX, static_cast<float>(ev.Y) - offsetY}; std::shared_ptr<TileObject> newSelectedTileObject; for (auto &obj : this->map.selectableObjects) { Rect<float> bounds; if (this->viewMode == TileViewMode::Strategy) { bounds = {0, 0, 8, 8}; } else { bounds = obj->getSelectableBounds(); } auto tileOffset = tileToScreenCoords(obj->getDrawPosition()); bounds.p0 += tileOffset; bounds.p1 += tileOffset; if (bounds.within(selectedPos)) { if (newSelectedTileObject) { if (newSelectedTileObject->getDrawPosition().z < obj->getDrawPosition().z) newSelectedTileObject = obj; } else newSelectedTileObject = obj; } if (newSelectedTileObject != this->selectedTileObject) { /* Either could be nullptr if there's nothing currently selected * or if you've clicked somewhere with no selectable objects * (IE deselected) */ if (this->selectedTileObject) this->selectedTileObject->setSelected(false); if (newSelectedTileObject) newSelectedTileObject->setSelected(true); this->selectedTileObject = newSelectedTileObject; } } } else if (e->Type == EVENT_KEY_UP) { switch (e->Data.Keyboard.KeyCode) { case ALLEGRO_KEY_UP: case ALLEGRO_KEY_DOWN: cameraScrollY = 0; break; case ALLEGRO_KEY_LEFT: case ALLEGRO_KEY_RIGHT: cameraScrollX = 0; break; } } if (fw.gamecore->DebugModeEnabled && selectionChanged) { LogInfo("Selected tile {%d,%d,%d}", selectedTilePosition.x, selectedTilePosition.y, selectedTilePosition.z); } }
void TileView::Render() { int dpyWidth = fw.Display_GetWidth(); int dpyHeight = fw.Display_GetHeight(); Renderer &r = *fw.renderer; r.clear(); r.setPalette(this->pal); // offsetX/offsetY is the 'amount added to the tile coords' - so we want // the inverse to tell which tiles are at the screen bounds auto topLeft = screenToTileCoords(Vec2<int>{-offsetX - isoTileSize.x, -offsetY - isoTileSize.y}, 0); auto topRight = screenToTileCoords(Vec2<int>{-offsetX + dpyWidth, -offsetY - isoTileSize.y}, 0); auto bottomLeft = screenToTileCoords(Vec2<int>{-offsetX - isoTileSize.x, -offsetY + dpyHeight}, map.size.z); auto bottomRight = screenToTileCoords(Vec2<int>{-offsetX + dpyWidth, -offsetY + dpyHeight}, map.size.z); int minX = std::max(0, topLeft.x); int maxX = std::min(map.size.x, bottomRight.x); int minY = std::max(0, topRight.y); int maxY = std::min(map.size.y, bottomLeft.y); for (int z = 0; z < maxZDraw; z++) { for (int y = minY; y < maxY; y++) { for (int x = minX; x < maxX; x++) { bool showOrigin = fw.state->showTileOrigin; bool showSelected = (fw.gamecore->DebugModeEnabled && z == selectedTilePosition.z && y == selectedTilePosition.y && x == selectedTilePosition.x); auto tile = map.getTile(x, y, z); auto screenPos = tileToScreenCoords(Vec3<float>{ static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)}); screenPos.x += offsetX; screenPos.y += offsetY; if (showSelected) r.draw(selectedTileImageBack, screenPos); for (auto obj : tile->visibleObjects) { assert(obj->isVisible()); bool showBounds = obj == this->selectedTileObject || (fw.state->showSelectableBounds && obj->isSelectable()); std::shared_ptr<Image> img; switch (this->viewMode) { case TileViewMode::Strategy: img = obj->getStrategySprite(); break; case TileViewMode::Isometric: img = obj->getSprite(); break; default: LogError("Invalid view mode"); } if (!img) { continue; } auto pos = obj->getDrawPosition(); auto objScreenPos = tileToScreenCoords(pos); objScreenPos.x += offsetX; objScreenPos.y += offsetY; r.draw(img, objScreenPos); if (x != obj->getOwningTile()->position.x || y != obj->getOwningTile()->position.y || z != obj->getOwningTile()->position.z) { LogError("Object has mismatches owning tile / visible object link" " visible in {%d,%d,%d} owned by {%d,%d,%d}", x, y, z, obj->getOwningTile()->position.x, obj->getOwningTile()->position.y, obj->getOwningTile()->position.z); } if (showOrigin) { Vec2<float> offset{offsetX, offsetY}; auto linePos0 = tileToScreenCoords(obj->getPosition() + Vec3<float>{0, 0, 0.5}); auto linePos1 = tileToScreenCoords(obj->getPosition() + Vec3<float>{0, 0, -0.5}); linePos1 += offset; linePos0 += offset; r.drawLine(linePos0, linePos1, Colour{255, 0, 0, 255}); linePos0 = tileToScreenCoords(obj->getPosition() + Vec3<float>{0, 0.5, 0}); linePos1 = tileToScreenCoords(obj->getPosition() + Vec3<float>{0, -0.5, 0}); linePos1 += offset; linePos0 += offset; r.drawLine(linePos0, linePos1, Colour{255, 0, 0, 255}); linePos0 = tileToScreenCoords(obj->getPosition() + Vec3<float>{0.5, 0, 0}); linePos1 = tileToScreenCoords(obj->getPosition() + Vec3<float>{-0.5, 0, 0}); linePos1 += offset; linePos0 += offset; r.drawLine(linePos0, linePos1, Colour{255, 0, 0, 255}); linePos0 = tileToScreenCoords(Vec3<float>{obj->getOwningTile()->position} + Vec3<float>{0, 0, 0.5}); linePos1 = tileToScreenCoords(Vec3<float>{obj->getOwningTile()->position} + Vec3<float>{0, 0, -0.5}); linePos1 += offset; linePos0 += offset; r.drawLine(linePos0, linePos1, Colour{255, 255, 0, 255}); linePos0 = tileToScreenCoords(Vec3<float>{obj->getOwningTile()->position} + Vec3<float>{0, 0.5, 0}); linePos1 = tileToScreenCoords(Vec3<float>{obj->getOwningTile()->position} + Vec3<float>{0, -0.5, 0}); linePos1 += offset; linePos0 += offset; r.drawLine(linePos0, linePos1, Colour{255, 255, 0, 255}); linePos0 = tileToScreenCoords(Vec3<float>{obj->getOwningTile()->position} + Vec3<float>{0.5, 0, 0}); linePos1 = tileToScreenCoords(Vec3<float>{obj->getOwningTile()->position} + Vec3<float>{-0.5, 0, 0}); linePos1 += offset; linePos0 += offset; r.drawLine(linePos0, linePos1, Colour{255, 255, 0, 255}); } if (showBounds) { Vec2<float> offset{offsetX, offsetY}; Rect<float> bounds; if (this->viewMode == TileViewMode::Strategy) { bounds = {0, 0, 8, 8}; } else { bounds = obj->getSelectableBounds(); } auto p00 = tileToScreenCoords(obj->getDrawPosition()); p00 += offset; p00 += bounds.p0; auto p11 = tileToScreenCoords(obj->getDrawPosition()); p11 += offset; p11 += bounds.p1; auto p10 = Vec2<float>{p11.x, p00.y}; auto p01 = Vec2<float>{p00.x, p11.y}; r.drawLine(p00, p00 + Vec2<float>{0, 5}, Colour{255, 0, 0, 255}); r.drawLine(p00, p00 + Vec2<float>{5, 0}, Colour{255, 0, 0, 255}); r.drawLine(p01, p01 + Vec2<float>{0, -5}, Colour{255, 0, 0, 255}); r.drawLine(p01, p01 + Vec2<float>{5, 0}, Colour{255, 0, 0, 255}); r.drawLine(p10, p10 + Vec2<float>{0, 5}, Colour{255, 0, 0, 255}); r.drawLine(p10, p10 + Vec2<float>{-5, 0}, Colour{255, 0, 0, 255}); r.drawLine(p11, p11 + Vec2<float>{0, -5}, Colour{255, 0, 0, 255}); r.drawLine(p11, p11 + Vec2<float>{-5, 0}, Colour{255, 0, 0, 255}); } } for (auto &p : tile->ownedProjectiles) p->drawProjectile(*this, r, Vec2<int>{offsetX, offsetY}); if (showSelected) r.draw(selectedTileImageFront, screenPos); } } } }