#include "../sdlpp/sdlpp.hpp" #include "sprites.hpp" #ifdef _WIN32 #include "../sdlpp/SDL2/SDL2_framerate.h" #include #include #include #else #include #endif // UNIX #include #include #include #include "global_vars.hpp" #include "objectids.hpp" #include "blocks.hpp" #include "maploader.hpp" #include "../sdlpp/sdlpp_mouse.hpp" #include "edit_box.hpp" #include "editor_visitor.hpp" #include "tool_box.hpp" #include "blocks/coineditorblock.hpp" #define MAP_WIDTH 24 #define MAP_HEIGHT 16 #define QUIT_FLAG 0x00000001 #define UPDATE_FLAG 0x00000002 #define MAP_LEFT_ENABLED_FLAG 0x00000004 #define MAP_RIGHT_ENABLED_FLAG 0x00000008 #define TOOL_LEFT_ENABLED_FLAG 0x00000010 #define TOOL_RIGHT_ENABLED_FLAG 0x00000020 #define MOD_LEFT_ENABLED_FLAG 0x00000040 #define MOD_RIGHT_ENABLED_FLAG 0x00000080 #define CHARACTER_LEFT_ENABLED_FLAG 0x00000100 #define CHARACTER_RIGHT_ENABLED_FLAG 0x00000200 #define TOOLS_WIDTH 4 #define CHARACTER_WIDTH 3 #define MOD_WIDTH 2 #define OVERWORLD_WIDTH 2 struct ToolType { enum Value { BLOCK, MOD, CHARACTER, WORLD, }; }; struct MouseInfo { uint64_t cur_flags{}; uint64_t prev_flags{}; SDLPP::Vec2D edit_box; SDLPP::Vec2D tool_box; ToolType::Value tool_type{}; }; struct MapInfo { int cur_page; int max_page; }; struct ToolInfo { ToolType::Value type; uint64_t index; SDL_Rect texture_src; int cur_page_tools; int max_page_tools; int cur_page_mods; int max_page_mods; int cur_page_characters; int max_page_characters; }; struct GlobalVars { MouseInfo mouse{}; MapInfo map{}; ToolInfo tool{}; uint64_t flags{}; std::vector objects; std::vector> tools; std::vector> mods; std::vector> characters; std::vector> tool_boxes; std::vector> mod_boxes; std::vector> character_boxes; enum LandType::Value current_world_type{}; std::shared_ptr coin_tool; std::shared_ptr generic_tool; std::shared_ptr current_tool; std::shared_ptr translucent_terrain_texture; std::shared_ptr translucent_mario_texture; std::shared_ptr translucent_mod_texture; std::shared_ptr translucent_enemies_texture; std::shared_ptr mario; SDLPP::Vec2D mario_pos; }; GlobalVars global_vars; std::mutex destruction_mutex; void updateTool() { auto tool_index = global_vars.tool.index; uint64_t tool_id = 0; switch (global_vars.tool.type) { case ToolType::BLOCK: tool_id = possibleBlocks[tool_index]; break; case ToolType::MOD: tool_id = possibleMods[tool_index]; break; case ToolType::CHARACTER: tool_id = possibleCharacters[tool_index]; default: break; } auto tool_role = getBlockRole(tool_id); std::shared_ptr target_texture = nullptr; SDL_Rect target_src; switch (tool_role) { case BlockRole::TERRAIN: target_texture = global_vars.translucent_terrain_texture; target_src = global_vars.tools[global_vars.tool.index]->getTextureSourceRect(); break; case BlockRole::MARIO: target_texture = global_vars.translucent_mario_texture; target_src = global_vars.characters[global_vars.tool.index] ->getTextureSourceRect(); break; case BlockRole::MODIFIER: target_texture = global_vars.translucent_mod_texture; target_src = global_vars.mods[global_vars.tool.index]->getTextureSourceRect(); break; case BlockRole::CHARACTER: target_texture = global_vars.translucent_enemies_texture; target_src = global_vars.characters[global_vars.tool.index] ->getTextureSourceRect(); break; } global_vars.current_tool->setHidden(true); if (tool_id == COIN_MODIFIER_ID) { global_vars.coin_tool->setPos(global_vars.current_tool->getPos()); global_vars.current_tool = global_vars.coin_tool; } else { global_vars.generic_tool->setPos(global_vars.current_tool->getPos()); global_vars.current_tool = global_vars.generic_tool; global_vars.current_tool->setTexture(target_texture, target_src); global_vars.current_tool->setId(tool_id); global_vars.current_tool->getCollisions()[0]->setId(tool_id); } global_vars.current_tool->setHidden(false); } void removeMario() { if (!global_vars.mario) { return; } global_vars .objects[global_vars.mario_pos.getX()][global_vars.mario_pos.getY()] .unsetCharacter(); global_vars.mario->destroy(); } void setToolColor(const std::string &color) { std::vector> *store = nullptr; int multiplier = 0; switch (global_vars.tool.type) { case ToolType::BLOCK: multiplier = TOOLS_WIDTH; store = &global_vars.tool_boxes; break; case ToolType::MOD: multiplier = MOD_WIDTH; store = &global_vars.mod_boxes; break; case ToolType::CHARACTER: multiplier = CHARACTER_WIDTH; store = &global_vars.character_boxes; default: break; } if (store == nullptr) { return; } auto index = global_vars.tool.index % (2 * multiplier); store->at(index)->setColor(color); } void setToolColor() { setToolColor("#FFFF8888"); } void unsetToolColor() { setToolColor("#FFFFFF00"); } void updateToolSelection(int prev_index, ToolType::Value type) { unsetToolColor(); size_t cur_page = 0; size_t multiplier = 0; std::vector> *tool_vec = nullptr; switch (type) { case ToolType::BLOCK: cur_page = global_vars.tool.cur_page_tools; multiplier = 2 * TOOLS_WIDTH; tool_vec = &global_vars.tools; break; case ToolType::MOD: cur_page = global_vars.tool.cur_page_mods; multiplier = 2 * MOD_WIDTH; tool_vec = &global_vars.mods; break; case ToolType::CHARACTER: cur_page = global_vars.tool.cur_page_characters; multiplier = 2 * CHARACTER_WIDTH; tool_vec = &global_vars.characters; default: break; } if (tool_vec == nullptr) { return; } auto cur = cur_page * multiplier; size_t prev = prev_index * multiplier; for (size_t i = prev; i < (tool_vec->size() < prev + multiplier ? tool_vec->size() : prev + multiplier); i++) { tool_vec->at(i)->setHidden(true); } for (size_t i = cur; i < (tool_vec->size() < cur + multiplier ? tool_vec->size() : cur + multiplier); i++) { tool_vec->at(i)->setHidden(false); } if (global_vars.tool.index / multiplier == cur_page) { setToolColor(); } } void moveToolsLeft(ToolType::Value type) { switch (type) { case ToolType::BLOCK: global_vars.tool.cur_page_tools--; updateToolSelection(global_vars.tool.cur_page_tools + 1, type); break; case ToolType::MOD: global_vars.tool.cur_page_mods--; updateToolSelection(global_vars.tool.cur_page_mods + 1, type); break; case ToolType::CHARACTER: global_vars.tool.cur_page_characters--; updateToolSelection(global_vars.tool.cur_page_characters + 1, type); default: break; } } void moveToolsRight(ToolType::Value type) { switch (type) { case ToolType::BLOCK: global_vars.tool.cur_page_tools++; updateToolSelection(global_vars.tool.cur_page_tools - 1, type); break; case ToolType::MOD: global_vars.tool.cur_page_mods++; updateToolSelection(global_vars.tool.cur_page_mods - 1, type); break; case ToolType::CHARACTER: global_vars.tool.cur_page_characters++; updateToolSelection(global_vars.tool.cur_page_characters - 1, type); default: break; } } void updateToolIndex(uint64_t new_index, ToolType::Value new_type) { int multiplier = 0; int *page = nullptr; switch (new_type) { case ToolType::BLOCK: multiplier = 2 * TOOLS_WIDTH; page = &global_vars.tool.cur_page_tools; break; case ToolType::MOD: multiplier = 2 * MOD_WIDTH; page = &global_vars.tool.cur_page_mods; break; case ToolType::CHARACTER: multiplier = 2 * CHARACTER_WIDTH; page = &global_vars.tool.cur_page_characters; default: break; } unsetToolColor(); global_vars.tool.type = new_type; global_vars.tool.index = new_index; setToolColor(); updateTool(); if (new_index / multiplier != static_cast(*page)) { auto prev = *page; *page = new_index / multiplier; updateToolSelection(prev, global_vars.tool.type); } } void updateToolIndex(uint64_t new_index) { updateToolIndex(new_index, global_vars.tool.type); } void selectLowerTool() { int multiplier = 0; size_t max_index = 0; switch (global_vars.tool.type) { case ToolType::BLOCK: multiplier = 2 * TOOLS_WIDTH; max_index = global_vars.tools.size() - 1; break; case ToolType::MOD: multiplier = 2 * MOD_WIDTH; max_index = global_vars.mods.size() - 1; break; case ToolType::CHARACTER: multiplier = 2 * CHARACTER_WIDTH; max_index = global_vars.characters.size() - 1; default: break; } if (global_vars.tool.index % multiplier >= static_cast(multiplier / 2) || global_vars.tool.index + multiplier / 2 > max_index) { return; } updateToolIndex(global_vars.tool.index + multiplier / 2); } void selectUpperTool() { int multiplier = 0; switch (global_vars.tool.type) { case ToolType::BLOCK: multiplier = 2 * TOOLS_WIDTH; break; case ToolType::MOD: multiplier = 2 * MOD_WIDTH; break; case ToolType::CHARACTER: multiplier = 2 * CHARACTER_WIDTH; default: break; } if (global_vars.tool.index % multiplier < static_cast(multiplier / 2)) { return; } updateToolIndex(global_vars.tool.index - multiplier / 2); } void selectPrevTool() { int multiplier = 0; switch (global_vars.tool.type) { case ToolType::BLOCK: multiplier = TOOLS_WIDTH; break; case ToolType::MOD: multiplier = MOD_WIDTH; break; case ToolType::CHARACTER: multiplier = CHARACTER_WIDTH; default: break; } int subtraction = 1; if (global_vars.tool.index % multiplier == 0) { subtraction = multiplier + 1; } if (global_vars.tool.index == 0 || global_vars.tool.index - subtraction > static_cast(-multiplier)) { return; } updateToolIndex(global_vars.tool.index - subtraction); } void selectNextTool() { size_t max_index = 0; int multiplier = 0; switch (global_vars.tool.type) { case ToolType::BLOCK: max_index = global_vars.tools.size() - 1; multiplier = TOOLS_WIDTH; break; case ToolType::MOD: max_index = global_vars.mods.size() - 1; multiplier = MOD_WIDTH; break; case ToolType::CHARACTER: max_index = global_vars.characters.size() - 1; multiplier = CHARACTER_WIDTH; default: break; } int addition = 1; if (global_vars.tool.index % multiplier == static_cast(multiplier - 1)) { addition = multiplier + 1; } if (global_vars.tool.index == max_index) { return; } if (global_vars.tool.index + addition > max_index) { addition = 1; } updateToolIndex(global_vars.tool.index + addition); } void setFlag(uint64_t flag) { global_vars.flags |= flag; } void unsetFlag(uint64_t flag) { global_vars.flags &= ~flag; } bool getFlag(uint64_t flag) { return global_vars.flags & flag; } void updateWorld() { for (auto &block : global_vars.tools) { block->setType(global_vars.current_world_type); } for (auto &block : global_vars.characters) { block->setType(global_vars.current_world_type); } if (getBlockRole(global_vars.current_tool->getId()) != BlockRole::MODIFIER) { global_vars.current_tool->setType(global_vars.current_world_type); } } // TODO add mouse wheel control for modifiers void handleKeyUp(SDL_Keycode key, SDLPP::Scene &scene) { switch (key) { case SDLK_ESCAPE: setFlag(QUIT_FLAG); break; case SDLK_a: selectPrevTool(); break; case SDLK_d: selectNextTool(); break; case SDLK_w: selectUpperTool(); break; case SDLK_s: selectLowerTool(); break; case SDLK_1: global_vars.current_world_type = possibleLands[0]; updateWorld(); break; case SDLK_2: global_vars.current_world_type = possibleLands[1]; updateWorld(); break; case SDLK_3: global_vars.current_world_type = possibleLands[2]; updateWorld(); break; case SDLK_4: global_vars.current_world_type = possibleLands[3]; updateWorld(); break; case SDLK_r: scene.getRenderer().setRenderColiders( !scene.getRenderer().getRenderColiders()); default: break; } } void getMousePositionFlags(SDLPP::Scene &scene) { auto mouse = scene.getObjects({ EDITOR_MOUSE_ID })[0]; // move mouse colider to mouse position mouse->setPos(SDLPP::Mouse::getMousePositionDouble( scene.getRenderer(), SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER)); MouseVisitor visitor; scene.visitCollisions(*mouse, visitor); global_vars.mouse.cur_flags = visitor.getFlags(); // + 1 because the left map arrow is on position 0 global_vars.mouse.edit_box = visitor.getEditBoxIndexes() + SDLPP::Vec2D(1, 0); global_vars.mouse.tool_box = visitor.getToolBoxIndexes(); global_vars.mouse.tool_type = static_cast(visitor.getToolType()); // if we found an edit box, move tool icon to that box if (visitor.foundEditBox()) { const auto &box = global_vars.mouse.edit_box; global_vars.current_tool->setPos(box.getX() * BLOCK_SIZE, 1 - MAP_HEIGHT * BLOCK_SIZE + box.getY() * BLOCK_SIZE); } } void mouseUpAction(uint64_t flags, SDLPP::Scene &scene) { if (MouseVisitor::moveMapLeft(flags) && global_vars.map.cur_page != 0) { global_vars.map.cur_page--; scene.moveEverything(BLOCK_SIZE, 0); } if (MouseVisitor::moveMapRight(flags)) { if (global_vars.map.cur_page == global_vars.map.max_page) { // add column global_vars.objects.resize(global_vars.objects.size() + 1); global_vars.map.max_page++; } global_vars.map.cur_page += 1; scene.moveEverything(-BLOCK_SIZE, 0); } if (MouseVisitor::moveToolsLeft(flags) && global_vars.tool.cur_page_tools != 0) { global_vars.tool.cur_page_tools--; updateToolSelection(global_vars.tool.cur_page_tools + 1, ToolType::BLOCK); } if (MouseVisitor::moveToolsRight(flags) && global_vars.tool.cur_page_tools != global_vars.tool.max_page_tools) { global_vars.tool.cur_page_tools++; updateToolSelection(global_vars.tool.cur_page_tools - 1, ToolType::BLOCK); } if (MouseVisitor::moveModsLeft(flags) && global_vars.tool.cur_page_mods != 0) { global_vars.tool.cur_page_mods--; updateToolSelection(global_vars.tool.cur_page_mods + 1, ToolType::MOD); } if (MouseVisitor::moveModsRight(flags) && global_vars.tool.cur_page_mods != global_vars.tool.max_page_mods) { global_vars.tool.cur_page_mods++; updateToolSelection(global_vars.tool.cur_page_mods - 1, ToolType::MOD); } if (MouseVisitor::moveCharactersLeft(flags) && global_vars.tool.cur_page_characters != 0) { global_vars.tool.cur_page_characters--; updateToolSelection(global_vars.tool.cur_page_characters + 1, ToolType::CHARACTER); } if (MouseVisitor::moveCharactersRight(flags) && global_vars.tool.cur_page_characters != global_vars.tool.max_page_characters) { global_vars.tool.cur_page_characters++; updateToolSelection(global_vars.tool.cur_page_characters - 1, ToolType::CHARACTER); } } SDLPP::Vec2D getSelectedObjectIndexes() { // -1 because we're indexing edit boxes from 1 (due to left arrow on map) return global_vars.mouse.edit_box + SDLPP::Vec2D(global_vars.map.cur_page - 1, 0); } MapObject &getSelectedObject() { auto pos = getSelectedObjectIndexes(); return global_vars.objects[pos.getX()][pos.getY()]; } void placeTool(SDLPP::Scene &scene) { std::lock_guard lock(destruction_mutex); ToolVisitor visitor; visitor.setSourceType(global_vars.current_world_type); visitor.setSourceData(global_vars.current_tool->getData()); auto tool_type = getBlockRole(global_vars.current_tool->getId()); switch (tool_type) { case BlockRole::TERRAIN: visitor.setVisitorType(VisitorType::Terrain); break; case BlockRole::CHARACTER: case BlockRole::MARIO: visitor.setVisitorType(VisitorType::Character); break; default: visitor.setVisitorType(VisitorType::Modifier); break; } scene.visitCollisions(*global_vars.current_tool, visitor); auto &obj = getSelectedObject(); if (visitor.removeBlock() && !visitor.addBlock()) { switch (visitor.getVisitorType()) { case VisitorType::Terrain: obj.unsetTerrain(); break; case VisitorType::Character: obj.unsetCharacter(); break; case VisitorType::Modifier: obj.unsetModifier(); break; default: break; } } else if (visitor.addBlock()) { auto renderer = scene.getRendererShared(); uint64_t z_index = 1; std::shared_ptr new_obj = nullptr; switch (visitor.getVisitorType()) { case VisitorType::Terrain: obj.setTerrain(global_vars.current_tool->getId(), global_vars.current_world_type); new_obj = createTerrainBlock( obj.getTerrainId(), obj.getTerrainType(), renderer, global_vars.mouse.edit_box.getX(), global_vars.mouse.edit_box.getY(), false, true); new_obj->getCollisions()[0]->setId(EDITOR_TERRAIN_ID); break; case VisitorType::Character: if (tool_type == BlockRole::MARIO) { obj.setCharacter(MARIO_ID, global_vars.current_world_type); new_obj = createMario(global_vars.current_world_type, renderer, global_vars.mouse.edit_box.getX(), global_vars.mouse.edit_box.getY(), true); // remove mario if exists removeMario(); global_vars.mario = new_obj; global_vars.mario_pos = getSelectedObjectIndexes(); new_obj->getCollisions()[0]->setId(EDITOR_CHARACTER_ID); z_index = scene.getObjects().size() - 1; } else { obj.setCharacter(global_vars.current_tool->getId(), global_vars.current_world_type); new_obj = createTerrainBlock( obj.getCharacterId(), obj.getCharacterType(), renderer, global_vars.mouse.edit_box.getX(), global_vars.mouse.edit_box.getY(), false, true); new_obj->getCollisions()[0]->setId(EDITOR_CHARACTER_ID); dynamic_cast(new_obj.get())->setTerrain(false); z_index = scene.getObjects().size() - 1; } break; case VisitorType::Modifier: obj.setModifier(global_vars.current_tool->getId(), global_vars.current_tool->getData()); new_obj = createTerrainBlock( obj.getModifierId(), LandType::OVERWORLD, renderer, global_vars.mouse.edit_box.getX(), global_vars.mouse.edit_box.getY(), false, true); new_obj->setTextureKeepSRC(global_vars.translucent_mod_texture); new_obj->setData(global_vars.current_tool->getData()); new_obj->getCollisions()[0]->setId(EDITOR_TERRAIN_ID); // TODO createModifierBlock dynamic_cast(new_obj.get())->setTerrain(false); z_index = scene.getObjects().size() - 1; break; default: break; } scene.addObject(new_obj); scene.setZIndex(new_obj, z_index); } } void pollEvents(SDLPP::Scene &scene) { SDL_Event event; while (SDLPP::getSDLEvent(event)) { switch (event.type) { case SDL_QUIT: setFlag(QUIT_FLAG); break; case SDL_KEYUP: handleKeyUp(event.key.keysym.sym, scene); break; case SDL_WINDOWEVENT: if (event.window.event == SDL_WINDOWEVENT_RESIZED) { setFlag(UPDATE_FLAG); } break; case SDL_MOUSEMOTION: getMousePositionFlags(scene); break; case SDL_MOUSEBUTTONUP: if (global_vars.mouse.cur_flags == global_vars.mouse.prev_flags) { mouseUpAction(global_vars.mouse.cur_flags, scene); } if (global_vars.mouse.edit_box.getX() != 0) { placeTool(scene); } if (global_vars.mouse.tool_box.getX() != -1) { auto &tool_box = global_vars.mouse.tool_box; int multiplier = 0; size_t max_index = 0; size_t cur_page = 0; switch (global_vars.mouse.tool_type) { case ToolType::BLOCK: multiplier = 2 * TOOLS_WIDTH; max_index = global_vars.tools.size(); cur_page = global_vars.tool.cur_page_tools; break; case ToolType::MOD: multiplier = 2 * MOD_WIDTH; max_index = global_vars.mods.size(); cur_page = global_vars.tool.cur_page_mods; break; case ToolType::CHARACTER: multiplier = 2 * CHARACTER_WIDTH; max_index = global_vars.characters.size(); cur_page = global_vars.tool.cur_page_characters; break; case ToolType::WORLD: multiplier = 2 * OVERWORLD_WIDTH; default: break; } size_t index = tool_box.getY() * (multiplier / 2) + tool_box.getX(); if (global_vars.mouse.tool_type == ToolType::WORLD) { global_vars.current_world_type = possibleLands[index]; updateWorld(); } else if (index < max_index) { updateToolIndex(cur_page * multiplier + index, global_vars.mouse.tool_type); } } break; case SDL_MOUSEBUTTONDOWN: // store current mouse flags in previous mouse flags global_vars.mouse.prev_flags = global_vars.mouse.cur_flags; break; case SDL_MOUSEWHEEL: if (event.wheel.y > 0) { global_vars.current_tool->onScrollUp(); } else if (event.wheel.y < 0) { global_vars.current_tool->onScrollDown(); } break; default: break; } } } void doInput(std::shared_ptr scene) { FPSmanager gFPS; SDL_initFramerate(&gFPS); SDL_setFramerate(&gFPS, 200); while (true) { SDL_framerateDelay(&gFPS); pollEvents(*scene); scene->updateScene(); } } void createGrid(double start_x, double start_y, int count_x, int count_y, std::shared_ptr &scene) { auto renderer = scene->getRendererShared(); auto width = count_x * BLOCK_SIZE; auto height = count_y * BLOCK_SIZE; for (int i = 0; i < count_x + 1; i++) { auto line_vertical = std::make_shared( start_x + i * BLOCK_SIZE, start_y, start_x + i * BLOCK_SIZE, start_y + height, renderer, "#282828"); line_vertical->setPermanent(); line_vertical->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); scene->addObject(line_vertical); } for (int i = 0; i < count_y + 1; i++) { auto line_horizontal = std::make_shared( start_x, start_y + i * BLOCK_SIZE, start_x + width, start_y + i * BLOCK_SIZE, renderer, "#282828"); line_horizontal->setPermanent(); line_horizontal->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); scene->addObject(line_horizontal); } } std::pair, std::shared_ptr> createArrowControls(double left_x, double right_x, double start_y, double height, uint64_t left_id, uint64_t right_id, std::shared_ptr &scene, std::shared_ptr &font_config) { auto renderer = scene->getRendererShared(); // white rectangles auto rectangle1 = std::make_shared( left_x, start_y, BLOCK_SIZE, height, renderer, "#FFFFFF88", true); rectangle1->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); rectangle1->setId(left_id); rectangle1->setPermanent(); rectangle1->addCollision(SDLPP::RectColider(0, 0, 1, 1)); scene->addObject(rectangle1); // white rectangles auto rectangle2 = std::make_shared( right_x, start_y, BLOCK_SIZE, height, renderer, "#FFFFFF88", true); rectangle2->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); rectangle2->setId(right_id); rectangle2->setPermanent(); rectangle2->addCollision(SDLPP::RectColider(0, 0, 1, 1)); scene->addObject(rectangle2); auto left = std::make_shared( left_x, start_y + height / 2.0 - 0.5 * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, renderer, "<", font_config); left->setId(0); left->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); left->setPermanent(); scene->addObject(left); auto right = std::make_shared( right_x, start_y + height / 2.0 - 0.5 * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, renderer, ">", font_config); right->setId(0); right->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); right->setPermanent(); scene->addObject(right); return { left, right }; } void populateToolGrid( int count_x, int count_y, float start_x, float start_y, ToolType::Value type, const std::vector &blocks, std::vector> &tool_store, std::vector> &tool_box_store, std::shared_ptr &scene, const std::string &title, const std::shared_ptr &font_config) { auto renderer = scene->getRendererShared(); for (int j = 0; j < count_y; j++) { for (int i = 0; i < count_x; i++) { auto tool_box = std::make_shared(i, j, start_x, start_y, renderer, false); scene->addObject(tool_box); } } int tool_index = 0; for (auto &block : blocks) { switch (type) { case ToolType::CHARACTER: if (block == MARIO_ID) { tool_store.push_back(createMario(global_vars.current_world_type, renderer, 0, 0, true)); break; } // fall through case ToolType::MOD: tool_store.push_back(createTerrainBlock( block, global_vars.current_world_type, renderer, false, true)); break; case ToolType::BLOCK: tool_store.push_back(createTerrainBlock( block, global_vars.current_world_type, renderer, false, true)); break; default: break; } tool_store.back()->setHidden(true); tool_store.back()->setPermanent(); tool_store.back()->pauseAnimation(); auto x = tool_index % count_x; auto y = tool_index / count_x; tool_store.back()->setPos(start_x + x * BLOCK_SIZE, start_y + y * BLOCK_SIZE); scene->addObject(tool_store.back()); tool_index = (tool_index + 1) % (2 * count_x); } for (int j = 0; j < count_y; j++) { for (int i = 0; i < count_x; i++) { auto tool_box = std::make_shared(i, j, start_x, start_y, renderer); tool_box->setType(type); scene->addObject(tool_box); tool_box->setColor("#00000000"); tool_box_store.push_back(tool_box); } } auto tool_text = std::make_shared( start_x - BLOCK_SIZE, start_y - BLOCK_SIZE, (count_x + 2) * BLOCK_SIZE, BLOCK_SIZE, renderer, title, font_config, SDLPP_TEXT_CENTER); tool_text->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); tool_text->setPermanent(); scene->addObject(tool_text); } void populateWorldType( int count_x, int count_y, float start_x, float start_y, std::shared_ptr &scene, const std::string &title, const std::shared_ptr &font_config) { auto renderer = scene->getRendererShared(); for (int j = 0; j < count_y; j++) { for (int i = 0; i < count_x; i++) { auto tool_box = std::make_shared(i, j, start_x, start_y, renderer); tool_box->setType(ToolType::WORLD); scene->addObject(tool_box); } } int tool_index = 0; for (auto &type : possibleLands) { auto land = createTerrainBlock(BRICK_ID, type, renderer, false, true); auto x = tool_index % count_x; auto y = tool_index / count_x; land->setId(EDITOR_WORLD_CHANGE_ID); land->setPermanent(); land->setPos(start_x + x * BLOCK_SIZE, start_y + y * BLOCK_SIZE); scene->addObject(land); tool_index = (tool_index + 1) % (2 * count_x); } auto tool_text = std::make_shared( start_x, start_y - BLOCK_SIZE, count_x * BLOCK_SIZE, BLOCK_SIZE, renderer, title, font_config, SDLPP_TEXT_CENTER); tool_text->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); tool_text->setPermanent(); scene->addObject(tool_text); } void checkArrowsEnabled(uint64_t cur_page, uint64_t max_page, uint64_t left_flag, uint64_t right_flag, std::shared_ptr &left_arrow, std::shared_ptr &right_arrow, std::shared_ptr &font, bool map = false) { if (cur_page == 0 && getFlag(left_flag)) { setFlag(UPDATE_FLAG); unsetFlag(left_flag); left_arrow->setTextColor(font, "#CCCCCC", "#CCCCCC", 0.05); } else if (cur_page != 0 && !getFlag(left_flag)) { setFlag(UPDATE_FLAG); setFlag(left_flag); left_arrow->setTextColor(font, "#000000", "#282828", 0.05); } if (cur_page == max_page && getFlag(right_flag)) { setFlag(UPDATE_FLAG); unsetFlag(right_flag); if (map) { right_arrow->setTextColor(font, "#00FF00", "#000000", 0.1); right_arrow->changeText("+"); } else { right_arrow->setTextColor(font, "#CCCCCC", "#CCCCCC", 0.05); } } else if (cur_page != max_page && !getFlag(right_flag)) { setFlag(UPDATE_FLAG); setFlag(right_flag); right_arrow->setTextColor(font, "#000000", "#282828", 0.05); if (map) { right_arrow->changeText(">"); } } } #ifdef _WIN32 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR szCmdLine, int nCmdShow) { #else int main() { #endif SDLPP::init(); SDLPP::Window w("Mario editor!"); w.setResizable(true); BLOCK_SIZE = 1.0 / 26; auto font = std::make_shared("testfont.ttf", 36); auto font_config = std::make_shared( font, "#000000", "#282828", 0.05); g_text_config = std::make_shared(font, "#FFFFFF", "#000000", 0.15); auto renderer = std::make_shared(w); renderer->setBlendMode(SDL_BLENDMODE_BLEND); // prepare global vars g_terrain_texture = std::make_shared( renderer, "sprites/terrain.png", MARIO_OVERWORLD_COLORKEY); g_mario_texture = std::make_shared( renderer, "sprites/mario.png", MARIO_OVERWORLD_COLORKEY); g_mod_texture = std::make_shared(renderer, "sprites/mods.png"); g_enemies_texture = std::make_shared( renderer, "sprites/enemies.png", MARIO_OVERWORLD_COLORKEY); g_translucent_terrain_texture = std::make_shared( renderer, "sprites/terrain.png", MARIO_OVERWORLD_COLORKEY); g_translucent_terrain_texture->setAlpha(100); g_translucent_mod_texture = std::make_shared(renderer, "sprites/mods.png"); g_translucent_mod_texture->setAlpha(100); g_translucent_enemies_texture = std::make_shared( renderer, "sprites/enemies.png", MARIO_OVERWORLD_COLORKEY); g_translucent_enemies_texture->setAlpha(100); auto scene = std::make_shared(renderer); auto bg = std::make_shared( 0, 0, 10, 10, renderer, MARIO_OVERWORLD_COLORKEY, true); bg->setPermanent(); bg->setId(1); scene->addObject(bg); global_vars.current_world_type = LandType::OVERWORLD; // TODO file name loadMap(scene, global_vars.mario, "test_binary.bin", global_vars.objects, true, MAP_WIDTH); // create grids and arrow controls // map auto arrows = createArrowControls( 0, (MAP_WIDTH + 1) * BLOCK_SIZE, 1 - MAP_HEIGHT * BLOCK_SIZE, MAP_HEIGHT * BLOCK_SIZE, EDITOR_LEFT_MAP_ID, EDITOR_RIGHT_MAP_ID, scene, font_config); auto left_map_arrow = arrows.first; auto right_map_arrow = arrows.second; createGrid(BLOCK_SIZE, 1 - MAP_HEIGHT * BLOCK_SIZE, MAP_WIDTH, MAP_HEIGHT, scene); // edit blocks on map for (int i = 0; i < MAP_WIDTH; i++) { for (int j = 0; j < MAP_HEIGHT; j++) { scene->addObject(std::make_shared( i, j, BLOCK_SIZE, 1 - MAP_HEIGHT * BLOCK_SIZE, MAP_WIDTH, MAP_HEIGHT, renderer)); } } // tools populateToolGrid(TOOLS_WIDTH, 2, (MAP_WIDTH - TOOLS_WIDTH) * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, ToolType::BLOCK, possibleBlocks, global_vars.tools, global_vars.tool_boxes, scene, "TERRAIN", font_config); arrows = createArrowControls( (MAP_WIDTH - TOOLS_WIDTH - 1) * BLOCK_SIZE, MAP_WIDTH * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, 2 * BLOCK_SIZE, EDITOR_LEFT_TOOL_ID, EDITOR_RIGHT_TOOL_ID, scene, font_config); auto left_tool_arrow = arrows.first; auto right_tool_arrow = arrows.second; createGrid((MAP_WIDTH - TOOLS_WIDTH) * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, TOOLS_WIDTH, 2, scene); // mods populateToolGrid(MOD_WIDTH, 2, 5 * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, ToolType::MOD, possibleMods, global_vars.mods, global_vars.mod_boxes, scene, "MODS", font_config); arrows = createArrowControls(4 * BLOCK_SIZE, (MOD_WIDTH + 5) * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, 2 * BLOCK_SIZE, EDITOR_LEFT_MOD_ID, EDITOR_RIGHT_MOD_ID, scene, font_config); auto left_mod_arrow = arrows.first; auto right_mod_arrow = arrows.second; createGrid(5 * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, MOD_WIDTH, 2, scene); // characters populateToolGrid(CHARACTER_WIDTH, 2, (MOD_WIDTH + 8) * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, ToolType::CHARACTER, possibleCharacters, global_vars.characters, global_vars.character_boxes, scene, "CHARACTERS", font_config); arrows = createArrowControls((MOD_WIDTH + 7) * BLOCK_SIZE, (MOD_WIDTH + 8 + CHARACTER_WIDTH) * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, 2 * BLOCK_SIZE, EDITOR_LEFT_CHARACTER_ID, EDITOR_RIGHT_CHARACTER_ID, scene, font_config); auto left_char_arrow = arrows.first; auto right_char_arrow = arrows.second; createGrid((MOD_WIDTH + 8) * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, CHARACTER_WIDTH, 2, scene); // world type populateWorldType(OVERWORLD_WIDTH, 2, BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, scene, "WORLD", font_config); createGrid(BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, OVERWORLD_WIDTH, 2, scene); global_vars.map.max_page = global_vars.objects.size() - MAP_WIDTH; global_vars.tool.max_page_tools = (possibleBlocks.size() - 1) / (2 * TOOLS_WIDTH); global_vars.tool.max_page_mods = (possibleMods.size() - 1) / (2 * MOD_WIDTH); global_vars.tool.max_page_characters = (possibleCharacters.size() - 1) / (2 * CHARACTER_WIDTH); auto mouse = std::make_shared(0.01, 0.01, 0, 0, renderer); mouse->setMinWidth(1); mouse->setMinHeight(1); mouse->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); mouse->setId(EDITOR_MOUSE_ID); mouse->setColiderColor("#00FF00"); mouse->addCollision(SDLPP::RectColider({ 0, 0 }, { 1, 1 })); scene->addObject(mouse); global_vars.translucent_terrain_texture = g_translucent_terrain_texture; global_vars.translucent_mario_texture = std::make_shared( renderer, "sprites/mario.png", MARIO_OVERWORLD_COLORKEY); global_vars.translucent_mario_texture->setAlpha(100); global_vars.generic_tool = createTerrainBlock(possibleBlocks[global_vars.tool.index], global_vars.current_world_type, renderer, false); global_vars.generic_tool->setTextureKeepSRC( global_vars.translucent_terrain_texture); global_vars.generic_tool->removeCollisions(); global_vars.generic_tool->addCollision( SDLPP::RectColider(0.1, 0.1, 0.8, 0.8)); global_vars.current_tool = global_vars.generic_tool; global_vars.coin_tool = createTerrainBlock( COIN_MODIFIER_ID, LandType::OVERWORLD, renderer, 0, 0, false, true); global_vars.coin_tool->setData(1); global_vars.coin_tool->removeCollisions(); global_vars.coin_tool->addCollision(SDLPP::RectColider(0.1, 0.1, 0.8, 0.8)); global_vars.translucent_mod_texture = g_translucent_mod_texture; global_vars.translucent_enemies_texture = g_translucent_enemies_texture; dynamic_cast(*global_vars.current_tool).setTool(); scene->addObject(global_vars.current_tool); scene->addObject(global_vars.coin_tool); global_vars.coin_tool->setHidden(true); scene->moveZTop(global_vars.current_tool); scene->moveZTop(global_vars.coin_tool); scene->moveEverything(BLOCK_SIZE, 0); FPSmanager gFPS; SDL_initFramerate(&gFPS); SDL_setFramerate(&gFPS, 60); updateToolSelection(0, ToolType::BLOCK); updateToolSelection(0, ToolType::MOD); updateToolSelection(0, ToolType::CHARACTER); setToolColor(); auto base = SDL_GetTicks(); int frames = 0; std::thread inputThread(doInput, scene); inputThread.detach(); setFlag(UPDATE_FLAG); global_vars.tool.cur_page_tools = 0; global_vars.tool.cur_page_mods = 0; global_vars.tool.cur_page_characters = 0; // required for initial correct rendering setFlag(MAP_LEFT_ENABLED_FLAG | MAP_RIGHT_ENABLED_FLAG | TOOL_LEFT_ENABLED_FLAG | TOOL_RIGHT_ENABLED_FLAG | MOD_LEFT_ENABLED_FLAG | MOD_RIGHT_ENABLED_FLAG | CHARACTER_LEFT_ENABLED_FLAG | CHARACTER_RIGHT_ENABLED_FLAG); SDL_PumpEvents(); scene->updateSizeAndPosition(); scene->renderScene(); renderer->presentRenderer(); setFlag(UPDATE_FLAG); while (!getFlag(QUIT_FLAG)) { SDL_framerateDelay(&gFPS); SDL_PumpEvents(); std::lock_guard lock(destruction_mutex); scene->renderScene(); renderer->presentRenderer(); frames++; if (SDL_GetTicks() - base >= 1000) { std::cout << "FPS: " << frames << std::endl; frames = 0; base = SDL_GetTicks(); } checkArrowsEnabled(global_vars.map.cur_page, global_vars.map.max_page, MAP_LEFT_ENABLED_FLAG, MAP_RIGHT_ENABLED_FLAG, left_map_arrow, right_map_arrow, font, true); checkArrowsEnabled(global_vars.tool.cur_page_tools, global_vars.tool.max_page_tools, TOOL_LEFT_ENABLED_FLAG, TOOL_RIGHT_ENABLED_FLAG, left_tool_arrow, right_tool_arrow, font); checkArrowsEnabled(global_vars.tool.cur_page_mods, global_vars.tool.max_page_mods, MOD_LEFT_ENABLED_FLAG, MOD_RIGHT_ENABLED_FLAG, left_mod_arrow, right_mod_arrow, font); checkArrowsEnabled(global_vars.tool.cur_page_characters, global_vars.tool.max_page_characters, CHARACTER_LEFT_ENABLED_FLAG, CHARACTER_RIGHT_ENABLED_FLAG, left_char_arrow, right_char_arrow, font); if (getFlag(UPDATE_FLAG)) { scene->updateSizeAndPosition(); unsetFlag(UPDATE_FLAG); } } saveMap("test_binary2.bin", global_vars.objects); return 0; }