#include "editor.h" #include "consts.h" void Editor::tick( double dt, const Uint8* keystate) { if (keystate[SDL_SCANCODE_LEFT] || keystate[SDL_SCANCODE_UP] || keystate[SDL_SCANCODE_RIGHT] || keystate[SDL_SCANCODE_DOWN]) { // If the player is holding down a directional key, accumulate the time // since the last tick, and then apply the directional key as many times as // needed. The input lag class automatically handles the delays necessary // for key repeat. inputLag_.accumulate(dt); while (inputLag_.step()) { if (mapFocus_) { // If we are focused on the map, move the map cursor. if (keystate[SDL_SCANCODE_LEFT] && cursor_.x() > 0) { cursor_.x()--; } if (keystate[SDL_SCANCODE_UP] && cursor_.y() > 0) { cursor_.y()--; } if (keystate[SDL_SCANCODE_RIGHT] && cursor_.x() < level_.getSize().w() - 1) { cursor_.x()++; } if (keystate[SDL_SCANCODE_DOWN] && cursor_.y() < level_.getSize().h() - 1) { cursor_.y()++; } } else { // If we are focused on the tileset, rotate through the selection of // tiles. if (keystate[SDL_SCANCODE_UP]) { selectedTile_--; } else if (keystate[SDL_SCANCODE_DOWN]) { selectedTile_++; } selectedTile_ %= level_.getTileset(layer_).getNumTiles(); } } } else if (inputLag_.isActive()) { // If the player is not holding down a directional key, reset the input lag. inputLag_.reset(); } // Check for keypress changes since the last tick. input_.tick(); if (input_.wasPressed(SDL_SCANCODE_Z)) { switch (layer_) { case Layer::map: { layer_ = Layer::object; break; } case Layer::track: { layer_ = Layer::map; break; } case Layer::object: { layer_ = Layer::track; break; } } selectedTile_ = 0; // Reset the cached map so that it gets redrawn with the focused layer. renderedMap_.reset(); } else if (input_.wasPressed(SDL_SCANCODE_X)) { switch (layer_) { case Layer::map: { layer_ = Layer::track; break; } case Layer::track: { layer_ = Layer::object; break; } case Layer::object: { layer_ = Layer::map; break; } } selectedTile_ = 0; // Reset the cached map so that it gets redrawn with the focused layer. renderedMap_.reset(); } else if (input_.wasPressed(SDL_SCANCODE_TAB)) { mapFocus_ = !mapFocus_; } bool newlyTabbed = false; if (input_.wasClicked(SDL_BUTTON_LEFT)) { if (EDITOR_MAP_AREA.contains(input_.getMousePos())) { if (!mapFocus_) { newlyTabbed = true; } mapFocus_ = true; } else if (EDITOR_TILESET_AREA.contains(input_.getMousePos())) { if (mapFocus_) { newlyTabbed = true; } mapFocus_ = false; selectedTile_ = (input_.getMousePos() - EDITOR_TILESET_AREA.pos).y() / TILE_SIZE.h(); } } if (mapFocus_) { if (EDITOR_MAP_AREA.contains(input_.getMousePos()) && ( input_.hasMouseMoved() || newlyTabbed )) { cursor_ = (input_.getMousePos() - EDITOR_MAP_AREA.pos) / TILE_SIZE; } if (keystate[SDL_SCANCODE_RETURN] || keystate[SDL_SCANCODE_SPACE] || ( input_.isClicked(SDL_BUTTON_LEFT) && EDITOR_MAP_AREA.contains(input_.getMousePos()) && !newlyTabbed )) { level_.at(cursor_.x(), cursor_.y(), layer_) = selectedTile_; // Reset the cached map so that it gets redrawn with the new tile. renderedMap_.reset(); } } } void Editor::render(SDL_Renderer* ren) { // Tile the background art. for (int y = 0; y <= WINDOW_SIZE.h() / bgSize_.h(); y++) { for (int x = 0; x <= WINDOW_SIZE.w() / bgSize_.w(); x++) { SDL_Rect rect { x * bgSize_.w(), y * bgSize_.h(), bgSize_.w(), bgSize_.h() }; SDL_RenderCopy(ren, background_.get(), nullptr, &rect); } } // Render and cache the map if the cache is currently empty. if (!renderedMap_) { renderedMap_.reset( SDL_CreateTexture( ren, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, LEVEL_SIZE.w(), LEVEL_SIZE.h())); // Render each layer separately, then compose them atop each other. Layers // above the currently selected one are drawn semi-transparently. texture_ptr mapRender = level_.render(ren, Layer::map); texture_ptr trackRender = level_.render(ren, Layer::track); texture_ptr objectRender = level_.render(ren, Layer::object); if (layer_ < Layer::track) { SDL_SetTextureBlendMode(trackRender.get(), SDL_BLENDMODE_BLEND); SDL_SetTextureAlphaMod(trackRender.get(), 127); } if (layer_ < Layer::object) { SDL_SetTextureBlendMode(objectRender.get(), SDL_BLENDMODE_BLEND); SDL_SetTextureAlphaMod(objectRender.get(), 127); } SDL_SetRenderTarget(ren, renderedMap_.get()); SDL_RenderCopy(ren, mapRender.get(), nullptr, nullptr); SDL_RenderCopy(ren, trackRender.get(), nullptr, nullptr); SDL_RenderCopy(ren, objectRender.get(), nullptr, nullptr); SDL_SetRenderTarget(ren, nullptr); } // Copy the rendered map onto the editor. SDL_Rect mapLoc { static_cast(BORDER_SIZE.w()), static_cast(BORDER_SIZE.h()), static_cast(LEVEL_SIZE.w()), static_cast(LEVEL_SIZE.h()) }; SDL_RenderCopy(ren, renderedMap_.get(), nullptr, &mapLoc); // If the map is focused, draw an outline around it. if (mapFocus_) { SDL_SetRenderDrawColor(ren, 255, 0, 0, 255); SDL_RenderDrawRect(ren, &mapLoc); } // Draw a box indicating the position of the map cursor. vec2s cursorLoc = BORDER_SIZE + TILE_SIZE * cursor_; SDL_Rect cursorRect { static_cast(cursorLoc.x()), static_cast(cursorLoc.y()), static_cast(TILE_SIZE.w()), static_cast(TILE_SIZE.h()) }; SDL_SetRenderDrawColor(ren, 255, 0, 0, 255); SDL_RenderDrawRect(ren, &cursorRect); // Draw the tileset for the currently selected layer. SDL_Rect tilesetLoc { static_cast(BORDER_SIZE.w() * 2 + LEVEL_SIZE.w()), static_cast(BORDER_SIZE.h()), static_cast(TILE_SIZE.w()), level_.getTileset(layer_).getSize().h() }; SDL_SetRenderDrawColor(ren, 255, 255, 255, 255); SDL_RenderFillRect(ren, &tilesetLoc); SDL_RenderCopy( ren, level_.getTileset(layer_).getImage().get(), nullptr, &tilesetLoc); // If the tileset is focused, draw an outline around it. if (!mapFocus_) { SDL_SetRenderDrawColor(ren, 255, 0, 0, 255); SDL_RenderDrawRect(ren, &tilesetLoc); } // Draw a box indicating which tile is currently selected. SDL_Rect tileCursorRect { tilesetLoc.x, static_cast((1 + selectedTile_) * TILE_SIZE.h()), static_cast(TILE_SIZE.w()), static_cast(TILE_SIZE.h()) }; SDL_SetRenderDrawColor(ren, 255, 255, 0, 255); SDL_RenderDrawRect(ren, &tileCursorRect); }