From eeda003c1f47acfd32f415fa16bb409f9ee11703 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Wed, 8 Jul 2026 20:14:09 +0200 Subject: [PATCH 01/16] Draw terrain using OpenGL --- CGame.h | 1 - CGame_Render.cpp | 60 +- CIO/CFile.cpp | 18 +- CIO/CFont.cpp | 12 +- CIO/CFont.h | 2 +- CMakeLists.txt | 5 +- CMap.cpp | 310 ++-- CMap.h | 19 +- CSurface.cpp | 450 ++---- CSurface.h | 18 +- LICENSES/LGPL-2.1-or-later.txt | 175 --- SGE/CMakeLists.txt | 20 - SGE/LICENSE | 504 ------ SGE/README.md | 227 --- SGE/include/SGE/FixedPoint.h | 54 - SGE/include/SGE/sge.h | 21 - SGE/include/SGE/sge_blib.h | 105 -- SGE/include/SGE/sge_collision.h | 46 - SGE/include/SGE/sge_config.h | 12 - SGE/include/SGE/sge_internal.h | 97 -- SGE/include/SGE/sge_misc.cpp | 82 - SGE/include/SGE/sge_misc.h | 30 - SGE/include/SGE/sge_primitives.h | 133 -- SGE/include/SGE/sge_rotation.h | 34 - SGE/include/SGE/sge_shape.h | 372 ----- SGE/include/SGE/sge_surface.h | 85 -- SGE/sge_blib.cpp | 2437 ------------------------------ SGE/sge_collision.cpp | 438 ------ SGE/sge_primitives.cpp | 2265 --------------------------- SGE/sge_primitives_int.h | 26 - SGE/sge_rotation.cpp | 669 -------- SGE/sge_shape.cpp | 573 ------- SGE/sge_surface.cpp | 723 --------- Texture.cpp | 171 ++- Texture.h | 31 +- include/defines.h | 9 +- 36 files changed, 554 insertions(+), 9680 deletions(-) delete mode 100644 LICENSES/LGPL-2.1-or-later.txt delete mode 100644 SGE/CMakeLists.txt delete mode 100644 SGE/LICENSE delete mode 100644 SGE/README.md delete mode 100644 SGE/include/SGE/FixedPoint.h delete mode 100644 SGE/include/SGE/sge.h delete mode 100644 SGE/include/SGE/sge_blib.h delete mode 100644 SGE/include/SGE/sge_collision.h delete mode 100644 SGE/include/SGE/sge_config.h delete mode 100644 SGE/include/SGE/sge_internal.h delete mode 100644 SGE/include/SGE/sge_misc.cpp delete mode 100644 SGE/include/SGE/sge_misc.h delete mode 100644 SGE/include/SGE/sge_primitives.h delete mode 100644 SGE/include/SGE/sge_rotation.h delete mode 100644 SGE/include/SGE/sge_shape.h delete mode 100644 SGE/include/SGE/sge_surface.h delete mode 100644 SGE/sge_blib.cpp delete mode 100644 SGE/sge_collision.cpp delete mode 100644 SGE/sge_primitives.cpp delete mode 100644 SGE/sge_primitives_int.h delete mode 100644 SGE/sge_rotation.cpp delete mode 100644 SGE/sge_shape.cpp delete mode 100644 SGE/sge_surface.cpp diff --git a/CGame.h b/CGame.h index d62ea65..be79019 100644 --- a/CGame.h +++ b/CGame.h @@ -49,7 +49,6 @@ class CGame Texture cursor_; Texture cursorClicked_; Texture cross_; - Texture mapTex_; ///< Texture for the map/terrain (Surf_Map may be 8-bit) // structure for mouse cursor struct diff --git a/CGame_Render.cpp b/CGame_Render.cpp index 3fb5b4b..9071ae9 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -55,28 +55,44 @@ void CGame::Render() // render the map if active if(MapObj && MapObj->isActive()) { - if(auto* mapSurf = MapObj->getSurface()) - { - std::array textBuffer; - std::snprintf(textBuffer.data(), textBuffer.size(), "%d %d", MapObj->getVertexX(), MapObj->getVertexY()); - CFont::writeText(mapSurf, textBuffer.data(), 20, 20); - std::snprintf(textBuffer.data(), textBuffer.size(), - "min. height: %#04x/0x3C max. height: %#04x/0x3C NormalNull: 0x0A", - MapObj->getMinReduceHeight(), MapObj->getMaxRaiseHeight()); - CFont::writeText(mapSurf, textBuffer.data(), 100, 20); - if(MapObj->isHorizontalMovementLocked() && MapObj->isVerticalMovementLocked()) - CFont::writeText(mapSurf, "Movement locked (F9 or F10 to unlock)", 20, 40, FontSize::Large, - FontColor::Orange); - else if(MapObj->isHorizontalMovementLocked()) - CFont::writeText(mapSurf, "Horizontal movement locked (F9 to unlock)", 20, 40, FontSize::Large, - FontColor::Orange); - else if(MapObj->isVerticalMovementLocked()) - CFont::writeText(mapSurf, "Vertical movement locked (F10 to unlock)", 20, 40, FontSize::Large, - FontColor::Orange); - - mapTex_.load(mapSurf); - mapTex_.draw(Rect(0, 0, GameResolution.x, GameResolution.y)); - } + // Set up map-space projection: (displayRect.left, top) maps to (0,0) screen + auto viewRect = MapObj->getDisplayRect(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(static_cast(viewRect.left), static_cast(viewRect.left + GameResolution.x), + static_cast(viewRect.top + GameResolution.y), static_cast(viewRect.top), -1, 1); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + MapObj->render(); + + // Restore screen-space projection + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + // HUD text overlays drawn directly via OpenGL + std::array textBuffer; + // text for x and y of vertex (shown in upper left corner) + std::snprintf(textBuffer.data(), textBuffer.size(), "%d %d", MapObj->getVertexX(), MapObj->getVertexY()); + CFont::draw(textBuffer.data(), Position(20, 20), FontSize::Medium); + // text for MinReduceHeight and MaxRaiseHeight + std::snprintf(textBuffer.data(), textBuffer.size(), + "min. height: %#04x/0x3C max. height: %#04x/0x3C NormalNull: 0x0A", + MapObj->getMinReduceHeight(), MapObj->getMaxRaiseHeight()); + CFont::draw(textBuffer.data(), Position(100, 20), FontSize::Medium); + // text for MovementLocked + if(MapObj->isHorizontalMovementLocked() && MapObj->isVerticalMovementLocked()) + CFont::draw("Movement locked (F9 or F10 to unlock)", Position(20, 40), FontSize::Large, FontColor::Orange); + else if(MapObj->isHorizontalMovementLocked()) + CFont::draw("Horizontal movement locked (F9 to unlock)", Position(20, 40), FontSize::Large, + FontColor::Orange); + else if(MapObj->isVerticalMovementLocked()) + CFont::draw("Vertical movement locked (F10 to unlock)", Position(20, 40), FontSize::Large, + FontColor::Orange); } // render active menus diff --git a/CIO/CFile.cpp b/CIO/CFile.cpp index 078d1d0..20af7bf 100644 --- a/CIO/CFile.cpp +++ b/CIO/CFile.cpp @@ -470,20 +470,10 @@ bool CFile::read_lbm(FILE* fp, const boost::filesystem::path& filepath) } else return false; - // if this is a texture file, we need a secondary 32-bit surface for SGE and we set a color key at both surfaces + // if this is a texture file, set a color key for transparency if(filepath.filename() == "TEX5.LBM" || filepath.filename() == "TEX6.LBM" || filepath.filename() == "TEX7.LBM" || filepath.filename() == "TEXTUR_0.LBM" || filepath.filename() == "TEXTUR_3.LBM") - { - SDL_SetColorKey(bmpArray->surface.get(), SDL_TRUE, SDL_MapRGB(bmpArray->surface->format, 0, 0, 0)); - - bmpArray++; - if((bmpArray->surface = makeRGBSurface((bmpArray - 1)->w, (bmpArray - 1)->h))) - { - SDL_SetColorKey(bmpArray->surface.get(), SDL_TRUE, SDL_MapRGB(bmpArray->surface->format, 0, 0, 0)); - CSurface::Draw(bmpArray->surface, (bmpArray - 1)->surface); - } else - bmpArray--; - } + SDL_SetColorKey(bmpArray->surface.get(), SDL_TRUE, 0); // we are finished, the surface is filled // increment bmpArray for the next picture @@ -1013,7 +1003,7 @@ bool CFile::read_bob02(FILE* fp) // now we are ready to read the picture lines and fill the surface, so lets create one if((bmpArray->surface = makePalSurface(bmpArray->w, bmpArray->h, palActual->colors)) == nullptr) return false; - SDL_SetColorKey(bmpArray->surface.get(), SDL_TRUE, SDL_MapRGB(bmpArray->surface->format, 0, 0, 0)); + SDL_SetColorKey(bmpArray->surface.get(), SDL_TRUE, 0); // SDL_SetAlpha(bmpArray->surface, SDL_SRCALPHA, 128); // main loop for reading picture lines @@ -1174,7 +1164,7 @@ bool CFile::read_bob04(FILE* fp, int player_color) if((bmpArray->surface = makePalSurface(bmpArray->w, bmpArray->h, palActual->colors)) == nullptr) return false; - SDL_SetColorKey(bmpArray->surface.get(), SDL_TRUE, SDL_MapRGB(bmpArray->surface->format, 0, 0, 0)); + SDL_SetColorKey(bmpArray->surface.get(), SDL_TRUE, 0); // main loop for reading picture lines for(Position pos{0, 0}; pos.y < bmpArray->h; pos.y++) diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp index 3fac602..77b12be 100644 --- a/CIO/CFont.cpp +++ b/CIO/CFont.cpp @@ -190,13 +190,6 @@ unsigned getCharWidth(uint8_t c, FontSize fontsize, FontColor color) } } // namespace -void CFont::draw(Position parentOrigin) const -{ - if(string_.empty()) - return; - draw(string_, parentOrigin + pos_, fontsize_, color_, FontAlign::Left); -} - void CFont::draw(const std::string& string, Position pos, FontSize fontsize, FontColor color, FontAlign align) { if(string.empty()) @@ -301,7 +294,10 @@ unsigned CFont::getTextWidth(const std::string& string, FontSize fontsize) { unsigned w = 0; for(unsigned char c : string) + { + if(c == '\n') + break; w += getCharWidth(c, fontsize, FontColor::Yellow); // width is same for all colors - + } return w; } diff --git a/CIO/CFont.h b/CIO/CFont.h index 2448235..698eb5b 100644 --- a/CIO/CFont.h +++ b/CIO/CFont.h @@ -48,7 +48,7 @@ class CFont void setMouseData(SDL_MouseButtonEvent button); /// Draw this font's text at the given absolute position - void draw(Position parentOrigin) const; + void draw(Position parentOrigin) const { draw(string_, parentOrigin + pos_, fontsize_, color_, FontAlign::Left); } /// Draw text directly /// @param pos Absolute position (top-left of the text, adjusted for alignment). diff --git a/CMakeLists.txt b/CMakeLists.txt index 524f7d4..5c62a5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,9 @@ cmake_minimum_required(VERSION 3.16..3.20) project(s25edit) find_package(Boost 1.64 REQUIRED) +find_package(SDL2 REQUIRED) + -add_subdirectory(SGE) option(RTTR_EDITOR_ADMINMODE "In admin mode there are some key combos to open debugger, resource viewer and so on" OFF) if(RTTR_EDITOR_ADMINMODE) @@ -38,7 +39,7 @@ ELSE() ENDIF() add_executable(s25edit ${MAIN_SOURCES} ${CIO_SOURCES} ${icon_RC}) -target_link_libraries(s25edit PRIVATE SGE rttrConfig s25Common gamedata siedler2 endian::static glad Boost::nowide PUBLIC Boost::disable_autolinking Boost::program_options) +target_link_libraries(s25edit PRIVATE rttrConfig s25Common gamedata siedler2 endian::static glad Boost::nowide SDL2::SDL2 PUBLIC Boost::disable_autolinking Boost::program_options) target_include_directories(s25edit PRIVATE include) target_compile_features(s25edit PRIVATE cxx_std_17) diff --git a/CMap.cpp b/CMap.cpp index 5588322..5139377 100644 --- a/CMap.cpp +++ b/CMap.cpp @@ -8,10 +8,12 @@ #include "CIO/CFile.h" #include "CIO/CFont.h" #include "CSurface.h" +#include "Texture.h" #include "callbacks.h" #include "globals.h" #include "gameData/LandscapeDesc.h" #include "gameData/TerrainDesc.h" +#include #include #include #include @@ -83,8 +85,6 @@ void CMap::constructMap(const boost::filesystem::path& filepath, int width, int TriangleTerrainType texture, int border, int border_texture) { map = nullptr; - Surf_Map.reset(); - Surf_RightMenubar.reset(); displayRect.left = 0; displayRect.top = 0; displayRect.setSize(global::s2->GameResolution); @@ -141,12 +141,10 @@ void CMap::constructMap(const boost::filesystem::path& filepath, int width, int } } - Surf_Map.reset(); active = true; Vertex_ = {10, 10}; RenderBuildHelp = false; RenderBorders = true; - BitsPerPixel = 32; MouseBlit = correctMouseBlit(Vertex_); ChangeSection_ = 1; lastChangeSection = ChangeSection_; @@ -223,12 +221,8 @@ void CMap::constructMap(const boost::filesystem::path& filepath, int width, int } void CMap::destructMap() { - // free all surfaces that MAP0x.LST needed - unloadMapPics(); undoBuffer.clear(); redoBuffer.clear(); - Surf_Map.reset(); - Surf_RightMenubar.reset(); // free vertex array Vertices.clear(); // free map structure memory @@ -445,13 +439,6 @@ void CMap::loadMapPics() std::cout << "failure"; } // set back palette - // CFile::set_palActual(CFile::get_palArray()); - // std::cout << "\nLoading file: DATA/MBOB/ROM_BOBS.LST..."; - // if ( !CFile::open_file(global::gameDataFilePath + "DATA/MBOB/ROM_BOBS.LST", LST) ) - //{ - // std::cout << "failure"; - //} - // set back palette CFile::set_palActual(CFile::get_palArray()); CFile::set_palArray(&global::palArray[PAL_xBBM]); // load palette file for the map (for precalculated shading) @@ -464,10 +451,8 @@ void CMap::loadMapPics() void CMap::unloadMapPics() { - for(int i = MAPPIC_ARROWCROSS_YELLOW; i <= MAPPIC_LAST_ENTRY; i++) - { - global::bmpArray[i].surface.reset(); - } + // Invalidate GL textures so next getBmpTexture() re-uploads from the new surfaces + Texture::invalidateBmpCache(MAPPIC_ARROWCROSS_YELLOW, MAPPIC_LAST_ENTRY); // set back bmpArray-pointer, cause MAP0x.LST is no longer needed CFile::set_bmpArray(&global::bmpArray[MAPPIC_ARROWCROSS_YELLOW]); // set back palArray-pointer, cause PALx.BBM is no longer needed @@ -920,6 +905,7 @@ void CMap::setKeyboardData(const SDL_KeyboardEvent& key) unloadMapPics(); loadMapPics(); + callback::PleaseWait(WINDOW_QUIT_MESSAGE); break; case SDLK_w: // convert map to winterland callback::PleaseWait(INITIALIZING_CALL); @@ -940,12 +926,7 @@ void CMap::setKeyboardData(const SDL_KeyboardEvent& key) callback::PleaseWait(WINDOW_QUIT_MESSAGE); break; - case SDLK_p: - if(BitsPerPixel == 8) - setBitsPerPixel(32); - else - setBitsPerPixel(8); - break; + case SDLK_F9: // lock horizontal movement HorizontalMovementLocked = !HorizontalMovementLocked; @@ -1076,28 +1057,32 @@ void CMap::render() if(displayRect.getSize() != global::s2->GameResolution) { displayRect.setSize(global::s2->GameResolution); - Surf_Map.reset(); } - // if we need a new surface - if(!Surf_Map) - { - if(BitsPerPixel == 8) - Surf_Map = - makePalSurface(displayRect.getSize().x, displayRect.getSize().y, global::palArray[PAL_xBBM].colors); - else - Surf_Map = makeRGBSurface(displayRect.getSize().x, displayRect.getSize().y); - } - // else - // clear the surface before drawing new (in normal case not needed) - // SDL_FillRect( Surf_Map, nullptr, SDL_MapRGB(Surf_Map->format,0,0,0) ); - // touch vertex data if user modifies it if(modify) + { modifyVertex(); + } + // ---- 1. Draw terrain with OpenGL ---- if(!map->vertex.empty()) - CSurface::DrawTriangleField(Surf_Map.get(), displayRect, *map); + CSurface::DrawTriangleField(displayRect, *map); + + // ---- 2. Draw editor UI chrome on top (screen-space) ---- + // Switch to screen-space projection for UI chrome + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, static_cast(displayRect.getSize().x), static_cast(displayRect.getSize().y), 0, -1, + 1); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // draw pictures to cursor position int symbol_index, symbol_index2 = -1; @@ -1126,160 +1111,177 @@ void CMap::render() { if(Vertices[i].active) { - CSurface::Draw(Surf_Map, global::bmpArray[symbol_index].surface, Vertices[i].blit - Position::all(10)); + Texture::getBmpTexture(symbol_index).draw(Position(Vertices[i].blit.x - 10, Vertices[i].blit.y - 10)); if(symbol_index2 >= 0) - CSurface::Draw(Surf_Map, global::bmpArray[symbol_index2].surface, Vertices[i].blit - Position(0, 7)); + Texture::getBmpTexture(symbol_index2).draw(Position(Vertices[i].blit.x, Vertices[i].blit.y - 7)); } } // draw the frame if(displayRect.getSize() == Extent(640, 480)) - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_640_480].surface); + Texture::getBmpTexture(MAINFRAME_640_480).draw(Position(0, 0)); else if(displayRect.getSize() == Extent(800, 600)) - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_800_600].surface); + Texture::getBmpTexture(MAINFRAME_800_600).draw(Position(0, 0)); else if(displayRect.getSize() == Extent(1024, 768)) - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_1024_768].surface); + Texture::getBmpTexture(MAINFRAME_1024_768).draw(Position(0, 0)); else if(displayRect.getSize() == Extent(1280, 1024)) { - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_LEFT_1280_1024].surface); - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_RIGHT_1280_1024].surface, Position(640, 0)); + Texture::getBmpTexture(MAINFRAME_LEFT_1280_1024).draw(Position(0, 0)); + Texture::getBmpTexture(MAINFRAME_RIGHT_1280_1024).draw(Position(640, 0)); } else { // draw the corners - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_640_480].surface, 0, 0, 0, 0, 150, 150); - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_640_480].surface, 0, displayRect.getSize().y - 150, 0, - 480 - 150, 150, 150); - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_640_480].surface, displayRect.getSize().x - 150, 0, - 640 - 150, 0, 150, 150); - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_640_480].surface, displayRect.getSize().x - 150, - displayRect.getSize().y - 150, 640 - 150, 480 - 150, 150, 150); + Texture::getBmpTexture(MAINFRAME_640_480).draw(Rect(0, 0, 150, 150), Rect(0, 0, 150, 150)); + Texture::getBmpTexture(MAINFRAME_640_480) + .draw(Rect(0, static_cast(displayRect.getSize().y) - 150, 150, 150), Rect(0, 480 - 150, 150, 150)); + Texture::getBmpTexture(MAINFRAME_640_480) + .draw(Rect(static_cast(displayRect.getSize().x) - 150, 0, 150, 150), Rect(640 - 150, 0, 150, 150)); + Texture::getBmpTexture(MAINFRAME_640_480) + .draw(Rect(static_cast(displayRect.getSize().x) - 150, static_cast(displayRect.getSize().y) - 150, + 150, 150), + Rect(640 - 150, 480 - 150, 150, 150)); // draw the edges unsigned x = 150, y = 150; while(x + 150 < displayRect.getSize().x) { - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_640_480].surface, x, 0, 150, 0, 150, 12); - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_640_480].surface, x, displayRect.getSize().y - 12, 150, - 0, 150, 12); + Texture::getBmpTexture(MAINFRAME_640_480) + .draw(Rect(static_cast(x), 0, 150, 12), Rect(150, 0, 150, 12)); + Texture::getBmpTexture(MAINFRAME_640_480) + .draw(Rect(static_cast(x), static_cast(displayRect.getSize().y) - 12, 150, 12), + Rect(150, 0, 150, 12)); x += 150; } while(y + 150 < displayRect.getSize().y) { - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_640_480].surface, 0, y, 0, 150, 12, 150); - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_640_480].surface, displayRect.getSize().x - 12, y, 0, - 150, 12, 150); + Texture::getBmpTexture(MAINFRAME_640_480) + .draw(Rect(0, static_cast(y), 12, 150), Rect(0, 150, 12, 150)); + Texture::getBmpTexture(MAINFRAME_640_480) + .draw(Rect(static_cast(displayRect.getSize().x) - 12, static_cast(y), 12, 150), + Rect(0, 150, 12, 150)); y += 150; } } // draw the statues at the frame - CSurface::Draw(Surf_Map, global::bmpArray[STATUE_UP_LEFT].surface, Position(12, 12)); - CSurface::Draw(Surf_Map, global::bmpArray[STATUE_UP_RIGHT].surface, - Position(displayRect.getSize().x - global::bmpArray[STATUE_UP_RIGHT].w - 12, 12)); - CSurface::Draw(Surf_Map, global::bmpArray[STATUE_DOWN_LEFT].surface, - Position(12, displayRect.getSize().y - global::bmpArray[STATUE_DOWN_LEFT].h - 12)); - CSurface::Draw(Surf_Map, global::bmpArray[STATUE_DOWN_RIGHT].surface, - displayRect.getSize() - - Position(global::bmpArray[STATUE_DOWN_RIGHT].w, global::bmpArray[STATUE_DOWN_RIGHT].h) - - Position::all(12)); + Texture::getBmpTexture(STATUE_UP_LEFT).draw(Position(12, 12)); + Texture::getBmpTexture(STATUE_UP_RIGHT) + .draw(Position(static_cast(displayRect.getSize().x) - global::bmpArray[STATUE_UP_RIGHT].w - 12, 12)); + Texture::getBmpTexture(STATUE_DOWN_LEFT) + .draw(Position(12, static_cast(displayRect.getSize().y) - global::bmpArray[STATUE_DOWN_LEFT].h - 12)); + Texture::getBmpTexture(STATUE_DOWN_RIGHT) + .draw(Position(static_cast(displayRect.getSize().x) - global::bmpArray[STATUE_DOWN_RIGHT].w - 12, + static_cast(displayRect.getSize().y) - global::bmpArray[STATUE_DOWN_RIGHT].h - 12)); // lower menubar - const Position menubarPos = Position(displayRect.getSize().x / 2, displayRect.getSize().y); + const Position menubarPos = + Position(static_cast(displayRect.getSize().x) / 2, static_cast(displayRect.getSize().y)); // draw lower menubar - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR].surface, - menubarPos - Extent(global::bmpArray[MENUBAR].w / 2, global::bmpArray[MENUBAR].h)); + Texture::getBmpTexture(MENUBAR).draw(Position(menubarPos.x - static_cast(global::bmpArray[MENUBAR].w / 2), + menubarPos.y - global::bmpArray[MENUBAR].h)); // draw pictures to lower menubar - // backgrounds - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x - 236, menubarPos.y - 36, 0, 0, - 37, 32); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x - 199, menubarPos.y - 36, 0, 0, - 37, 32); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x - 162, menubarPos.y - 36, 0, 0, - 37, 32); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x - 125, menubarPos.y - 36, 0, 0, - 37, 32); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x - 88, menubarPos.y - 36, 0, 0, - 37, 32); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x - 51, menubarPos.y - 36, 0, 0, - 37, 32); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x - 14, menubarPos.y - 36, 0, 0, - 37, 32); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x + 92, menubarPos.y - 36, 0, 0, - 37, 32); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x + 129, menubarPos.y - 36, 0, 0, - 37, 32); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x + 166, menubarPos.y - 36, 0, 0, - 37, 32); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, menubarPos.x + 203, menubarPos.y - 36, 0, 0, - 37, 32); + // backgrounds (use button background texture for each slot) + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x - 236, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x - 199, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x - 162, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x - 125, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x - 88, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x - 51, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x - 14, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x + 92, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x + 129, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x + 166, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(menubarPos.x + 203, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); + // pictures - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_HEIGHT].surface, menubarPos - Extent(232, 35)); - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_TEXTURE].surface, menubarPos - Extent(195, 35)); - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_TREE].surface, menubarPos - Extent(158, 37)); - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_RESOURCE].surface, menubarPos - Extent(121, 32)); - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_LANDSCAPE].surface, menubarPos - Extent(84, 37)); - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_ANIMAL].surface, menubarPos - Extent(48, 36)); - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_PLAYER].surface, menubarPos - Extent(10, 34)); - - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_BUILDHELP].surface, menubarPos + Position(96, -35)); - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_MINIMAP].surface, menubarPos + Position(131, -37)); - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_NEWWORLD].surface, menubarPos + Position(166, -37)); - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_COMPUTER].surface, menubarPos + Position(207, -35)); - - // right menubar - // do we need a surface? - if(!Surf_RightMenubar) - { - // we permute width and height, cause we want to rotate the menubar 90 degrees - if((Surf_RightMenubar = makePalSurface(global::bmpArray[MENUBAR].h, global::bmpArray[MENUBAR].w, - global::palArray[PAL_RESOURCE].colors)) - != nullptr) + Texture::getBmpTexture(MENUBAR_HEIGHT).draw(Position(menubarPos.x - 232, menubarPos.y - 35)); + Texture::getBmpTexture(MENUBAR_TEXTURE).draw(Position(menubarPos.x - 195, menubarPos.y - 35)); + Texture::getBmpTexture(MENUBAR_TREE).draw(Position(menubarPos.x - 158, menubarPos.y - 37)); + Texture::getBmpTexture(MENUBAR_RESOURCE).draw(Position(menubarPos.x - 121, menubarPos.y - 32)); + Texture::getBmpTexture(MENUBAR_LANDSCAPE).draw(Position(menubarPos.x - 84, menubarPos.y - 37)); + Texture::getBmpTexture(MENUBAR_ANIMAL).draw(Position(menubarPos.x - 48, menubarPos.y - 36)); + Texture::getBmpTexture(MENUBAR_PLAYER).draw(Position(menubarPos.x - 10, menubarPos.y - 34)); + + Texture::getBmpTexture(MENUBAR_BUILDHELP).draw(Position(menubarPos.x + 96, menubarPos.y - 35)); + Texture::getBmpTexture(MENUBAR_MINIMAP).draw(Position(menubarPos.x + 131, menubarPos.y - 37)); + Texture::getBmpTexture(MENUBAR_NEWWORLD).draw(Position(menubarPos.x + 166, menubarPos.y - 37)); + Texture::getBmpTexture(MENUBAR_COMPUTER).draw(Position(menubarPos.x + 207, menubarPos.y - 35)); + + // right menubar: draw the MENUBAR sprite rotated 270 degrees via OpenGL + { + const auto& bmp = global::bmpArray[MENUBAR]; + const int mw = bmp.w; + const int mh = bmp.h; + const Position rmPos = + Position(static_cast(displayRect.getSize().x), static_cast(displayRect.getSize().y) / 2); + + auto& tex = Texture::getBmpTexture(MENUBAR); + if(tex.isValid()) { - SDL_SetColorKey(Surf_RightMenubar.get(), SDL_TRUE, SDL_MapRGB(Surf_RightMenubar->format, 0, 0, 0)); - CSurface::Draw(Surf_RightMenubar, global::bmpArray[MENUBAR].surface, 0, 0, 270); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + // Shift right menubar 1px right, 2px down to align button backgrounds + glTranslatef(static_cast(rmPos.x - mh / 2 + 1), static_cast(rmPos.y + 2), 0.f); + glRotatef(270.f, 0.f, 0.f, 1.f); + tex.draw(Rect(-mw / 2, -mh / 2, mw, mh)); + glPopMatrix(); } } - // draw right menubar (remember permutation of width and height) - const Position rightMenubarPos = Position(displayRect.getSize().x, displayRect.getSize().y / 2); - CSurface::Draw(Surf_Map, Surf_RightMenubar, - rightMenubarPos - Extent(global::bmpArray[MENUBAR].h, global::bmpArray[MENUBAR].w / 2)); // draw pictures to right menubar - // backgrounds - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y - 239, 0, 0, 32, 37); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y - 202, 0, 0, 32, 37); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y - 165, 0, 0, 32, 37); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y - 128, 0, 0, 32, 37); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y - 22, 0, 0, 32, 37); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y + 15, 0, 0, 32, 37); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y + 52, 0, 0, 32, 37); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y + 89, 0, 0, 32, 37); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y + 126, 0, 0, 32, 37); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y + 163, 0, 0, 32, 37); - CSurface::Draw(Surf_Map, global::bmpArray[BUTTON_GREEN1_DARK].surface, rightMenubarPos.x - 36, - rightMenubarPos.y + 200, 0, 0, 32, 37); + const Position rightMenubarPos = + Position(static_cast(displayRect.getSize().x), static_cast(displayRect.getSize().y) / 2); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 239, 32, 37), Rect(0, 0, 32, 37)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 202, 32, 37), Rect(0, 0, 32, 37)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 165, 32, 37), Rect(0, 0, 32, 37)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 128, 32, 37), Rect(0, 0, 32, 37)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 22, 32, 37), Rect(0, 0, 32, 37)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 15, 32, 37), Rect(0, 0, 32, 37)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 52, 32, 37), Rect(0, 0, 32, 37)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 89, 32, 37), Rect(0, 0, 32, 37)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 126, 32, 37), Rect(0, 0, 32, 37)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 163, 32, 37), Rect(0, 0, 32, 37)); + Texture::getBmpTexture(BUTTON_GREEN1_DARK) + .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 200, 32, 37), Rect(0, 0, 32, 37)); + // pictures - // four cursor menu pictures - CSurface::Draw(Surf_Map, global::bmpArray[CURSOR_SYMBOL_ARROW_UP].surface, rightMenubarPos - Extent(33, 237)); - CSurface::Draw(Surf_Map, global::bmpArray[CURSOR_SYMBOL_ARROW_DOWN].surface, rightMenubarPos - Extent(20, 235)); - CSurface::Draw(Surf_Map, global::bmpArray[CURSOR_SYMBOL_ARROW_DOWN].surface, rightMenubarPos - Extent(33, 220)); - CSurface::Draw(Surf_Map, global::bmpArray[CURSOR_SYMBOL_ARROW_UP].surface, rightMenubarPos - Extent(20, 220)); + Texture::getBmpTexture(CURSOR_SYMBOL_ARROW_UP).draw(Position(rightMenubarPos.x - 33, rightMenubarPos.y - 237)); + Texture::getBmpTexture(CURSOR_SYMBOL_ARROW_DOWN).draw(Position(rightMenubarPos.x - 20, rightMenubarPos.y - 235)); + Texture::getBmpTexture(CURSOR_SYMBOL_ARROW_DOWN).draw(Position(rightMenubarPos.x - 33, rightMenubarPos.y - 220)); + Texture::getBmpTexture(CURSOR_SYMBOL_ARROW_UP).draw(Position(rightMenubarPos.x - 20, rightMenubarPos.y - 220)); // bugkill picture for quickload with text - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_BUGKILL].surface, rightMenubarPos + Position(-37, 162)); - CFont::writeText(Surf_Map, "Load", Position(rightMenubarPos.x - 35, rightMenubarPos.y + 193)); + Texture::getBmpTexture(MENUBAR_BUGKILL).draw(Position(rightMenubarPos.x - 37, rightMenubarPos.y + 162)); + CFont::draw("Load", Position(rightMenubarPos.x - 35, rightMenubarPos.y + 193), FontSize::Medium); // bugkill picture for quicksave with text - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_BUGKILL].surface, rightMenubarPos + Position(-37, 200)); - CFont::writeText(Surf_Map, "Save", Position(rightMenubarPos.x - 35, rightMenubarPos.y + 231)); + Texture::getBmpTexture(MENUBAR_BUGKILL).draw(Position(rightMenubarPos.x - 37, rightMenubarPos.y + 200)); + CFont::draw("Save", Position(rightMenubarPos.x - 35, rightMenubarPos.y + 231), FontSize::Medium); + + // Restore matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); } static const TerrainDesc* getTerrainDesc(const bobMAP& map, Uint8 rawTextureId) diff --git a/CMap.h b/CMap.h index fbb3352..b0d6b62 100644 --- a/CMap.h +++ b/CMap.h @@ -5,6 +5,7 @@ #pragma once +#include "CSurface.h" #include "defines.h" #include #include @@ -45,15 +46,12 @@ class CMap private: boost::filesystem::path filepath_; - SdlSurface Surf_Map; - SdlSurface Surf_RightMenubar; std::unique_ptr map; DisplayRectangle displayRect; bool active; Position Vertex_; bool RenderBuildHelp; bool RenderBorders; - int BitsPerPixel; // editor mode variables int mode; // necessary for release the EDITOR_MODE_CUT (set back to last used mode) @@ -132,12 +130,6 @@ class CMap bool isVerticalMovementLocked() const { return VerticalMovementLocked; } bool getRenderBuildHelp() const { return RenderBuildHelp; } bool getRenderBorders() const { return RenderBorders; } - int getBitsPerPixel() const { return BitsPerPixel; } - void setBitsPerPixel(int bbp) - { - BitsPerPixel = bbp; - Surf_Map.reset(); - } void setMode(int mode) { this->mode = mode; } int getMode() const { return mode; } void setModeContent(int modeContent) { this->modeContent = modeContent; } @@ -145,11 +137,9 @@ class CMap int getModeContent() const { return modeContent; } int getModeContent2() const { return modeContent2; } bobMAP* getMap() { return map.get(); } - SDL_Surface* getSurface() - { - render(); - return Surf_Map.get(); - } + /// Render terrain directly with OpenGL, then draw editor UI chrome. + /// Should be called from the main render loop with the correct GL projection set. + void render(); DisplayRectangle getDisplayRect() { return displayRect; } void setDisplayRect(const DisplayRectangle& displayRect) { this->displayRect = displayRect; } auto& getPlayerHQx() { return PlayerHQx; } @@ -162,7 +152,6 @@ class CMap void setAuthor(const std::string& author) { map->setAuthor(author); } void drawMinimap(std::vector& pixels, int w, int h, int& scale); - void render(); // get and set some variables necessary for cursor behavior void setHexagonMode(bool HexagonMode) { diff --git a/CSurface.cpp b/CSurface.cpp index 730f3f4..e60cdad 100644 --- a/CSurface.cpp +++ b/CSurface.cpp @@ -7,19 +7,37 @@ #include "CGame.h" #include "CMap.h" #include "Rect.h" -#include "SGE/sge_blib.h" -#include "SGE/sge_surface.h" +#include "Texture.h" #include "globals.h" #include "gameData/EdgeDesc.h" #include "gameData/TerrainDesc.h" +#include + #include #include #include -// Disable SGE's internal surface locking once at startup; terrain drawing is -// the only remaining consumer of SGE functions and the caller already handles -// locking. Was originally called in CGame::Init(). -static bool sgeLockOff = (sge_Lock_OFF(), true); +static uint8_t intensityToColor(Sint32 val) +{ + if(val <= 0) + return 0; + constexpr Sint32 maxVal = 2 * 65536; + if(val >= maxVal) + return 255; + return static_cast((val * 255 + maxVal / 2) / maxVal); +} + +// For border rendering we use GL_MODULATE (no RGB_SCALE), so +// [0, 65536] maps linearly to [0, 255]. +static uint8_t intensityToModulate(Sint32 val) +{ + if(val <= 0) + return 0; + constexpr Sint32 maxVal = 65536; + if(val >= maxVal) + return 255; + return static_cast((val * 255 + maxVal / 2) / maxVal); +} namespace { const TerrainDesc* getTerrainDesc(const bobMAP& map, Uint8 rawTextureId) @@ -33,45 +51,27 @@ const TerrainDesc* getTerrainDesc(const bobMAP& map, Uint8 rawTextureId) } return nullptr; } -} // namespace - -namespace { -SDL_Rect rect2SDL_Rect(const Rect& rect) -{ - Point origin(rect.getOrigin()); - Point size(rect.getSize()); - SDL_Rect result; - result.x = origin.x; - result.y = origin.y; - result.w = size.x; - result.h = size.y; - return result; -} -void DrawPreCalcFadedTexturedTrigon(SDL_Surface* dest, const Point16& p1, const Point16& p2, const Point16& p3, - SDL_Surface* source, const SDL_Rect& rect, Uint16 I1, Uint16 I2, - Uint8 PreCalcPalettes[][256]) +static void DrawFadedTexturedTrigon(const Point16& p1, const Point16& p2, const Point16& p3, const Rect& rect, + Sint32 I1, Sint32 I2, float texW, float texH) { - Sint16 right = rect.x + rect.w - 1; - Sint16 middle = rect.x + rect.w / Sint16(2); - Sint16 bottom = rect.y + rect.h - 1; - Uint32 colorKey; - const int keycount = (SDL_GetColorKey(source, &colorKey) < 0) ? 0 : 1; - sge_PreCalcFadedTexturedTrigonColorKeys(dest, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, source, rect.x, rect.y, right, - rect.y, middle, bottom, I1, I2, I2, PreCalcPalettes, &colorKey, keycount); + uint8_t c1 = intensityToModulate(I1); + uint8_t c2 = intensityToModulate(I2); + uint8_t ct = c2; + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBegin(GL_TRIANGLES); + glTexCoord2f(float(rect.left) / texW, float(rect.top) / texH); + glColor4ub(c1, c1, c1, 255); + glVertex2f(float(p1.x), float(p1.y)); + glTexCoord2f(float(rect.right) / texW, float(rect.top) / texH); + glColor4ub(c2, c2, c2, 255); + glVertex2f(float(p2.x), float(p2.y)); + glTexCoord2f(float((rect.left + rect.right) / 2) / texW, float(rect.bottom) / texH); + glColor4ub(ct, ct, ct, 255); + glVertex2f(float(p3.x), float(p3.y)); + glEnd(); } -void DrawFadedTexturedTrigon(SDL_Surface* dest, const Point16& p1, const Point16& p2, const Point16& p3, - SDL_Surface* source, const SDL_Rect& rect, Sint32 I1, Sint32 I2) -{ - Sint16 right = rect.x + rect.w - 1; - Sint16 middle = rect.x + rect.w / Sint16(2); - Sint16 bottom = rect.y + rect.h - 1; - Uint32 colorKey; - const int keycount = (SDL_GetColorKey(source, &colorKey) < 0) ? 0 : 1; - sge_FadedTexturedTrigonColorKeys(dest, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, source, rect.x, rect.y, right, rect.y, - middle, bottom, I1, I2, I2, &colorKey, keycount); -} } // namespace bool CSurface::drawTextures = false; @@ -106,71 +106,6 @@ bool CSurface::Draw(SdlSurface& Surf_Dest, SDL_Surface* Surf_Src, int X, int Y) return Draw(Surf_Dest.get(), Surf_Src, X, Y); } -bool CSurface::Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y, int angle) -{ - if(!Surf_Dest || !Surf_Src) - return false; - - if(angle != 90 && angle != 180 && angle != 270) - return false; - - // Simple software rotation for 90/180/270 degrees - // 90/270 swap width and height; 180 keeps original dimensions - int rotW = (angle == 180) ? Surf_Src->w : Surf_Src->h; - int rotH = (angle == 180) ? Surf_Src->h : Surf_Src->w; - SDL_Surface* rotated = - SDL_CreateRGBSurface(0, rotW, rotH, Surf_Src->format->BitsPerPixel, Surf_Src->format->Rmask, - Surf_Src->format->Gmask, Surf_Src->format->Bmask, Surf_Src->format->Amask); - if(!rotated) - return false; - // Copy palette for 8-bit surfaces - if(Surf_Src->format->palette && rotated->format->palette) - SDL_SetPaletteColors(rotated->format->palette, Surf_Src->format->palette->colors, 0, 256); - SDL_LockSurface(Surf_Src); - SDL_LockSurface(rotated); - int srcW = Surf_Src->w, srcH = Surf_Src->h, bpp = Surf_Src->format->BytesPerPixel; - for(int sy = 0; sy < srcH; sy++) - { - for(int sx = 0; sx < srcW; sx++) - { - int dx, dy; - switch(angle) - { - case 90: - dx = srcH - 1 - sy; - dy = sx; - break; - case 180: - dx = srcW - 1 - sx; - dy = srcH - 1 - sy; - break; - case 270: - dx = sy; - dy = srcW - 1 - sx; - break; - default: - dx = sx; - dy = sy; - break; - } - memcpy((Uint8*)rotated->pixels + dy * rotated->pitch + dx * bpp, - (Uint8*)Surf_Src->pixels + sy * Surf_Src->pitch + sx * bpp, bpp); - } - } - SDL_UnlockSurface(rotated); - SDL_UnlockSurface(Surf_Src); - SDL_Rect dst = {(Sint16)X, (Sint16)Y, 0, 0}; - SDL_BlitSurface(rotated, nullptr, Surf_Dest, &dst); - SDL_FreeSurface(rotated); - - return true; -} - -bool CSurface::Draw(SdlSurface& Surf_Dest, SdlSurface& Surf_Src, int X, int Y, int angle) -{ - return Draw(Surf_Dest.get(), Surf_Src.get(), X, Y, angle); -} - bool CSurface::Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, Position dest, Position srcOffset, Extent srcSize) { if(!Surf_Dest || !Surf_Src) @@ -246,30 +181,7 @@ void CSurface::DrawPixel_RGBA(SDL_Surface* screen, Position pos, Uint8 R, Uint8 DrawPixel_Color(screen, pos, SDL_MapRGBA(screen->format, R, G, B, A)); } -Uint32 CSurface::GetPixel(SDL_Surface* surface, Position pos) -{ - int bpp = surface->format->BytesPerPixel; - /* Here p is the address to the pixel we want to retrieve */ - Uint8* p = (Uint8*)surface->pixels + static_cast(pos.y) * surface->pitch + static_cast(pos.x) * bpp; - switch(bpp) - { - case 1: return *p; - - case 2: return *(Uint16*)p; - - case 3: - if((SDL_BYTEORDER) == SDL_BIG_ENDIAN) - return p[0] << 16 | p[1] << 8 | p[2]; - else - return p[0] | p[1] << 8 | p[2] << 16; - - case 4: return *(Uint32*)p; //-V206 - - default: return 0; /* shouldn't happen, but avoids warnings */ - } -} - -void CSurface::DrawTriangleField(SDL_Surface* display, const DisplayRectangle& displayRect, const bobMAP& myMap) +void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobMAP& myMap) { Uint16 width = myMap.width; Uint16 height = myMap.height; @@ -280,20 +192,8 @@ void CSurface::DrawTriangleField(SDL_Surface* display, const DisplayRectangle& d if(width < 8 || height < 8) return; - assert(displayRect.left < myMap.width_pixel); - assert(displayRect.right > 0); - assert(displayRect.top < myMap.height_pixel); - assert(displayRect.bottom > 0); - - Uint8 maxH = 0; - for(int y = 0; y < height; ++y) - { - for(int x = 0; x < width; ++x) - { - maxH = std::max(myMap.getVertex(x, y).h, maxH); - } - } - const int additionalRows = triangleIncrease * std::max(0, maxH - 0x0A) / triangleHeight; + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); // draw triangle field // NOTE: WE DO THIS TWICE, AT FIRST ONLY TRIANGLE-TEXTURES, AT SECOND THE TEXTURE-BORDERS AND OBJECTS @@ -303,15 +203,12 @@ void CSurface::DrawTriangleField(SDL_Surface* display, const DisplayRectangle& d for(int k = 0; k < 4; k++) { - // beware calling DrawTriangle for each triangle - // IMPORTANT: integer values like +8 or -1 are for tolerance to beware of high triangles are not shown - // at first call DrawTriangle for all triangles inside the map edges - int row_start = std::max(displayRect.top, 2 * triangleHeight) / triangleHeight - 2; - int row_end = (displayRect.bottom) / triangleHeight + additionalRows; - int col_start = std::max(displayRect.left, triangleWidth) / triangleWidth - 1; - int col_end = (displayRect.right) / triangleWidth + 1; + int row_start = std::max(0, displayRect.top / triangleHeight - 1); + int row_end = std::min(height, displayRect.bottom / triangleHeight + 2); + int col_start = std::max(0, displayRect.left / triangleWidth - 1); + int col_end = std::min(width, displayRect.right / triangleWidth + 2); bool view_outside_edges; if(k > 0) @@ -386,44 +283,43 @@ void CSurface::DrawTriangleField(SDL_Surface* display, const DisplayRectangle& d // first RightSideUp tempP2 = myMap.getVertex(width - 1, y + 1); tempP2.x = 0; - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(0, y), tempP2, - myMap.getVertex(0, y + 1)); + DrawTriangle(displayRect, myMap, type, myMap.getVertex(0, y), tempP2, myMap.getVertex(0, y + 1)); for(unsigned x = std::max(col_start, 1); x < width && x <= static_cast(col_end); x++) { // RightSideUp - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x, y), - myMap.getVertex(x - 1, y + 1), myMap.getVertex(x, y + 1)); + DrawTriangle(displayRect, myMap, type, myMap.getVertex(x, y), myMap.getVertex(x - 1, y + 1), + myMap.getVertex(x, y + 1)); // UpSideDown - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x - 1, y + 1), - myMap.getVertex(x - 1, y), myMap.getVertex(x, y)); + DrawTriangle(displayRect, myMap, type, myMap.getVertex(x - 1, y + 1), myMap.getVertex(x - 1, y), + myMap.getVertex(x, y)); } // last UpSideDown tempP3 = myMap.getVertex(0, y); tempP3.x = myMap.getVertex(width - 1, y).x + triangleWidth; - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(width - 1, y + 1), + DrawTriangle(displayRect, myMap, type, myMap.getVertex(width - 1, y + 1), myMap.getVertex(width - 1, y), tempP3); } else { for(unsigned x = col_start; x < width - 1u && x <= static_cast(col_end); x++) { // RightSideUp - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x, y), - myMap.getVertex(x, y + 1), myMap.getVertex(x + 1, y + 1)); + DrawTriangle(displayRect, myMap, type, myMap.getVertex(x, y), myMap.getVertex(x, y + 1), + myMap.getVertex(x + 1, y + 1)); // UpSideDown - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x + 1, y + 1), - myMap.getVertex(x, y), myMap.getVertex(x + 1, y)); + DrawTriangle(displayRect, myMap, type, myMap.getVertex(x + 1, y + 1), myMap.getVertex(x, y), + myMap.getVertex(x + 1, y)); } // last RightSideUp tempP3 = myMap.getVertex(0, y + 1); tempP3.x = myMap.getVertex(width - 1, y + 1).x + triangleWidth; - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(width - 1, y), + DrawTriangle(displayRect, myMap, type, myMap.getVertex(width - 1, y), myMap.getVertex(width - 1, y + 1), tempP3); // last UpSideDown tempP1 = myMap.getVertex(0, y + 1); tempP1.x = myMap.getVertex(width - 1, y + 1).x + triangleWidth; tempP3 = myMap.getVertex(0, y); tempP3.x = myMap.getVertex(width - 1, y).x + triangleWidth; - DrawTriangle(display, displayRect, myMap, type, tempP1, myMap.getVertex(width - 1, y), tempP3); + DrawTriangle(displayRect, myMap, type, tempP1, myMap.getVertex(width - 1, y), tempP3); } } @@ -435,11 +331,11 @@ void CSurface::DrawTriangleField(SDL_Surface* display, const DisplayRectangle& d tempP2.y = height * triangleHeight + myMap.getVertex(x, 0).y; tempP3 = myMap.getVertex(x + 1, 0); tempP3.y = height * triangleHeight + myMap.getVertex(x + 1, 0).y; - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x, height - 1), tempP2, tempP3); + DrawTriangle(displayRect, myMap, type, myMap.getVertex(x, height - 1), tempP2, tempP3); // UpSideDown tempP1 = myMap.getVertex(x + 1, 0); tempP1.y = height * triangleHeight + myMap.getVertex(x + 1, 0).y; - DrawTriangle(display, displayRect, myMap, type, tempP1, myMap.getVertex(x, height - 1), + DrawTriangle(displayRect, myMap, type, tempP1, myMap.getVertex(x, height - 1), myMap.getVertex(x + 1, height - 1)); } } @@ -450,14 +346,14 @@ void CSurface::DrawTriangleField(SDL_Surface* display, const DisplayRectangle& d tempP3 = myMap.getVertex(0, 0); tempP3.x = myMap.getVertex(width - 1, 0).x + triangleWidth; tempP3.y += height * triangleHeight; - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(width - 1, height - 1), tempP2, tempP3); + DrawTriangle(displayRect, myMap, type, myMap.getVertex(width - 1, height - 1), tempP2, tempP3); // last UpSideDown tempP1 = myMap.getVertex(0, 0); tempP1.x = myMap.getVertex(width - 1, 0).x + triangleWidth; tempP1.y += height * triangleHeight; tempP3 = myMap.getVertex(0, height - 1); tempP3.x = myMap.getVertex(width - 1, height - 1).x + triangleWidth; - DrawTriangle(display, displayRect, myMap, type, tempP1, myMap.getVertex(width - 1, height - 1), tempP3); + DrawTriangle(displayRect, myMap, type, tempP1, myMap.getVertex(width - 1, height - 1), tempP3); } } @@ -468,7 +364,7 @@ enum class BorderPreference LeftTop, RightBottom }; -BorderPreference CalcBorders(const bobMAP& map, Uint8 s2Id1, Uint8 s2Id2, SDL_Rect& borderRect) +BorderPreference CalcBorders(const bobMAP& map, Uint8 s2Id1, Uint8 s2Id2, Rect& borderRect) { // we have to decide which border to blit, "left or right" or "top or bottom" s2Id1 &= ~(0x40 | 0x80); @@ -487,13 +383,13 @@ BorderPreference CalcBorders(const bobMAP& map, Uint8 s2Id1, Uint8 s2Id2, SDL_Re { if(!t1.edgeType) return BorderPreference::None; - borderRect = rect2SDL_Rect(global::worldDesc.get(t1.edgeType).posInTexture); + borderRect = global::worldDesc.get(t1.edgeType).posInTexture; return BorderPreference::LeftTop; } else if(t1.edgePriority < t2.edgePriority) { if(!t2.edgeType) return BorderPreference::None; - borderRect = rect2SDL_Rect(global::worldDesc.get(t2.edgeType).posInTexture); + borderRect = global::worldDesc.get(t2.edgeType).posInTexture; return BorderPreference::RightBottom; } return BorderPreference::None; @@ -616,9 +512,6 @@ bool GetAdjustedPoints(const DisplayRectangle& displayRect, const bobMAP& myMap, if(!triangle_shown) return false; } - p1 -= displayRect.getOrigin(); - p2 -= displayRect.getOrigin(); - p3 -= displayRect.getOrigin(); return true; } } // namespace @@ -776,12 +669,13 @@ void CSurface::GetTerrainTextureCoords(MapType mapType, TriangleTerrainType text } } -void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displayRect, const bobMAP& myMap, - MapType type, const MapNode& P1, const MapNode& P2, const MapNode& P3) +void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& myMap, MapType type, const MapNode& P1, + const MapNode& P2, const MapNode& P3) { Point32 p1(P1.x, P1.y); Point32 p2(P2.x, P2.y); Point32 p3(P3.x, P3.y); + // prevent drawing triangles that are not shown if(!GetAdjustedPoints(displayRect, myMap, p1, p2, p3)) return; @@ -790,9 +684,12 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa // This is very tricky: there are ice floes in the winterland and the water under this floes is moving. // I don't know how this works in original settlers 2 but i solved it this way: // i texture the triangle with normal water and then draw the floe over it. To Extract the floe - // from it's surrounded water, i use this color keys below. These are the color values for the water texture. - // I wrote a special SGE-Function that uses these color keys and ignores them in the Surf_Tileset. - static std::array colorkeys = {14191, 14195, 13167, 13159, 11119}; + // from it's surrounded water, i use color keys. These are the color values for the water texture. + // The OpenGL renderer approximates this via a two-pass draw with GL_ALPHA_TEST. + // The water color keys are handled in Texture::load() when converting the 8-bit paletted + // tileset surface to RGBA — matching palette entries are set to alpha=0 so that + // GL_ALPHA_TEST (GL_GREATER, 0) skips them in the second pass. + static int texture_move = 0; static int roundCount = 0; static Uint32 roundTimeObjects = SDL_GetTicks(); @@ -813,29 +710,23 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa texture_move = 0; } - SDL_Surface* Surf_Tileset; + // Determine tileset texture + int tilesetIdx; switch(type) { case MAP_GREENLAND: - default: - Surf_Tileset = global::bmpArray[global::s2->getMapObj()->getBitsPerPixel() == 8 ? TILESET_GREENLAND_8BPP : - TILESET_GREENLAND_32BPP] - .surface.get(); - break; - case MAP_WASTELAND: - Surf_Tileset = global::bmpArray[global::s2->getMapObj()->getBitsPerPixel() == 8 ? TILESET_WASTELAND_8BPP : - TILESET_WASTELAND_32BPP] - .surface.get(); - break; - case MAP_WINTERLAND: - Surf_Tileset = global::bmpArray[global::s2->getMapObj()->getBitsPerPixel() == 8 ? TILESET_WINTERLAND_8BPP : - TILESET_WINTERLAND_32BPP] - .surface.get(); - break; + default: tilesetIdx = TILESET_GREENLAND; break; + case MAP_WASTELAND: tilesetIdx = TILESET_WASTELAND; break; + case MAP_WINTERLAND: tilesetIdx = TILESET_WINTERLAND; break; } - bool const isRSU = p1.y < p2.y; + auto& tilesetTex = Texture::getBmpTexture(tilesetIdx); + if(!tilesetTex.isValid()) + return; + glBindTexture(GL_TEXTURE_2D, tilesetTex.getHandle()); + const float texW = static_cast(global::bmpArray[tilesetIdx].w); + const float texH = static_cast(global::bmpArray[tilesetIdx].h); if(drawTextures) { // upper2, ..... are for special use in winterland. @@ -844,37 +735,75 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa TriangleTerrainType((isRSU ? P1.rsuTexture : P2.usdTexture) & ~0x40); // Mask out harbor bit GetTerrainTextureCoords(type, texture, isRSU, texture_move, upper, left, right, upper2, left2, right2); + const float uvs[3][2] = {{static_cast(upper.x) / texW, static_cast(upper.y) / texH}, + {static_cast(left.x) / texW, static_cast(left.y) / texH}, + {static_cast(right.x) / texW, static_cast(right.y) / texH}}; + + const float vertCoord[3][2] = { + {float(p1.x), float(p1.y)}, {float(p2.x), float(p2.y)}, {float(p3.x), float(p3.y)}}; + const MapNode* verts[3] = {&P1, &P2, &P3}; + // draw the triangle // do not shade water and lava if(const auto* terrainDesc = getTerrainDesc(myMap, texture); terrainDesc && (terrainDesc->kind == TerrainKind::Water || terrainDesc->kind == TerrainKind::Lava)) - sge_TexturedTrigon(display, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, Surf_Tileset, upper.x, upper.y, left.x, - left.y, right.x, right.y); - else + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); + glBegin(GL_TRIANGLES); + for(int k = 0; k < 3; k++) + { + glTexCoord2f(uvs[k][0], uvs[k][1]); + glColor4ub(128, 128, 128, 255); + glVertex2f(vertCoord[k][0], vertCoord[k][1]); + } + glEnd(); + } else { // draw special winterland textures with moving water (ice floe textures) if(type == MAP_WINTERLAND && (texture == TRIANGLE_TEXTURE_SNOW || texture == TRIANGLE_TEXTURE_SWAMP)) { - sge_TexturedTrigon(display, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, Surf_Tileset, upper2.x, upper2.y, - left2.x, left2.y, right2.x, right2.y); - if(global::s2->getMapObj()->getBitsPerPixel() == 8) - sge_PreCalcFadedTexturedTrigonColorKeys(display, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, Surf_Tileset, - upper.x, upper.y, left.x, left.y, right.x, right.y, - P1.shading << 8, P2.shading << 8, P3.shading << 8, - gouData[type], colorkeys.data(), colorkeys.size()); - else - sge_FadedTexturedTrigonColorKeys(display, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, Surf_Tileset, upper.x, - upper.y, left.x, left.y, right.x, right.y, P1.i, P2.i, P3.i, - colorkeys.data(), colorkeys.size()); + const float wuvs[3][2] = {{static_cast(upper2.x) / texW, static_cast(upper2.y) / texH}, + {static_cast(left2.x) / texW, static_cast(left2.y) / texH}, + {static_cast(right2.x) / texW, static_cast(right2.y) / texH}}; + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBegin(GL_TRIANGLES); + for(int k = 0; k < 3; k++) + { + glTexCoord2f(wuvs[k][0], wuvs[k][1]); + glColor4ub(128, 128, 128, 255); + glVertex2f(vertCoord[k][0], vertCoord[k][1]); + } + glEnd(); + + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); + glBegin(GL_TRIANGLES); + for(int k = 0; k < 3; k++) + { + glTexCoord2f(uvs[k][0], uvs[k][1]); + glColor4ub(intensityToColor(verts[k]->i), intensityToColor(verts[k]->i), + intensityToColor(verts[k]->i), 255); + glVertex2f(vertCoord[k][0], vertCoord[k][1]); + } + glEnd(); + glDisable(GL_ALPHA_TEST); } else { - if(global::s2->getMapObj()->getBitsPerPixel() == 8) - sge_PreCalcFadedTexturedTrigon(display, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, Surf_Tileset, upper.x, - upper.y, left.x, left.y, right.x, right.y, P1.shading << 8, - P2.shading << 8, P3.shading << 8, gouData[type]); - else - sge_FadedTexturedTrigon(display, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, Surf_Tileset, upper.x, upper.y, - left.x, left.y, right.x, right.y, P1.i, P2.i, P3.i); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); + glBegin(GL_TRIANGLES); + for(int k = 0; k < 3; k++) + { + glTexCoord2f(uvs[k][0], uvs[k][1]); + glColor4ub(intensityToColor(verts[k]->i), intensityToColor(verts[k]->i), + intensityToColor(verts[k]->i), 255); + glVertex2f(vertCoord[k][0], vertCoord[k][1]); + } + glEnd(); } } return; @@ -892,7 +821,7 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa Uint16 col = (P1.VertexX - 1 < 0 ? myMap.width - 1 : P1.VertexX - 1); MapNode tempP = myMap.getVertex(col, P1.VertexY); - SDL_Rect BorderRect; + Rect BorderRect; auto borderSide = CalcBorders(myMap, tempP.usdTexture, P1.rsuTexture, BorderRect); if(borderSide != BorderPreference::None) { @@ -904,7 +833,7 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa { tmpP1 += Point16(1, 0); tmpP2 += Point16(1, 0); - thirdPt = Point32(tempP.x, tempP.y) - displayRect.getOrigin(); + thirdPt = Point32(tempP.x, tempP.y); // Shift it close to p1 auto diff = thirdPt - p1; if(diff.x < -myMap.width_pixel / 2) @@ -918,17 +847,13 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa } Point16 tipPt{(p1 + p2 + thirdPt) / 3}; - if(global::s2->getMapObj()->getBitsPerPixel() == 8) - DrawPreCalcFadedTexturedTrigon(display, tmpP1, tmpP2, tipPt, Surf_Tileset, BorderRect, - P1.shading << 8, P2.shading << 8, gouData[type]); - else - DrawFadedTexturedTrigon(display, tmpP1, tmpP2, tipPt, Surf_Tileset, BorderRect, P1.i, P2.i); + DrawFadedTexturedTrigon(tmpP1, tmpP2, tipPt, BorderRect, P1.i, P2.i, texW, texH); } } // USD-Triangle else { - SDL_Rect BorderRect; + Rect BorderRect; // left lower / right upper auto borderSide = CalcBorders(myMap, P2.rsuTexture, P2.usdTexture, BorderRect); @@ -946,7 +871,7 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa tmpP2 -= Point16(1, 0); } else { - thirdPt = Point32(tempP.x, tempP.y) - displayRect.getOrigin(); + thirdPt = Point32(tempP.x, tempP.y); // Shift it close to p1 auto diff = thirdPt - p1; if(diff.x < -myMap.width_pixel / 2) @@ -961,11 +886,7 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa Point16 tipPt{(p1 + p2 + thirdPt) / 3}; - if(global::s2->getMapObj()->getBitsPerPixel() == 8) - DrawPreCalcFadedTexturedTrigon(display, tmpP1, tmpP2, tipPt, Surf_Tileset, BorderRect, - P1.shading << 8, P2.shading << 8, gouData[type]); - else - DrawFadedTexturedTrigon(display, tmpP1, tmpP2, tipPt, Surf_Tileset, BorderRect, P1.i, P2.i); + DrawFadedTexturedTrigon(tmpP1, tmpP2, tipPt, BorderRect, P1.i, P2.i, texW, texH); } // top / bottom - therefore get the rsu-texture one line above to compare @@ -981,7 +902,7 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa thirdPt = p1; else { - thirdPt = Point32(tempP.x, tempP.y) - displayRect.getOrigin(); + thirdPt = Point32(tempP.x, tempP.y); // Shift it close to p2 auto diff = thirdPt - p2; if(diff.x < -myMap.width_pixel / 2) @@ -995,16 +916,13 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa } Point16 tipPt{(p2 + p3 + thirdPt) / 3}; - if(global::s2->getMapObj()->getBitsPerPixel() == 8) - DrawPreCalcFadedTexturedTrigon(display, Point16(p2), Point16(p3), tipPt, Surf_Tileset, BorderRect, - P2.shading << 8, P3.shading << 8, gouData[type]); - else - DrawFadedTexturedTrigon(display, Point16(p2), Point16(p3), tipPt, Surf_Tileset, BorderRect, P2.i, - P3.i); + DrawFadedTexturedTrigon(Point16(p2), Point16(p3), tipPt, BorderRect, P2.i, P3.i, texW, texH); } } } + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + // blit picture to vertex (trees, animals, buildings and so on) --> BUT ONLY AT node1 ON RIGHTSIDEUP-TRIANGLES // blit objects @@ -1136,12 +1054,10 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa //%7 cause in the original game there are only 7 players and 7 different flags objIdx = FLAG_BLUE_DARK + P2.objectType % 7; break; - default: break; } if(objIdx != 0) - Draw(display, global::bmpArray[objIdx].surface, (int)(p2.x - global::bmpArray[objIdx].nx), - (int)(p2.y - global::bmpArray[objIdx].ny)); + Texture::getBmpTexture(objIdx).drawSprite(p2.x, p2.y); } // blit resources @@ -1150,37 +1066,25 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa if(P2.resource >= 0x41 && P2.resource <= 0x47) { for(char i = 0x41; i <= P2.resource; i++) - Draw(display, global::bmpArray[PICTURE_RESOURCE_COAL].surface, - (int)(p2.x - global::bmpArray[PICTURE_RESOURCE_COAL].nx), - (int)(p2.y - global::bmpArray[PICTURE_RESOURCE_COAL].ny - (4 * (i - 0x40)))); + Texture::getBmpTexture(PICTURE_RESOURCE_COAL).drawSprite(p2.x, p2.y - 4 * (i - 0x40)); } else if(P2.resource >= 0x49 && P2.resource <= 0x4F) { for(char i = 0x49; i <= P2.resource; i++) - Draw(display, global::bmpArray[PICTURE_RESOURCE_ORE].surface, - (int)(p2.x - global::bmpArray[PICTURE_RESOURCE_ORE].nx), - (int)(p2.y - global::bmpArray[PICTURE_RESOURCE_ORE].ny - (4 * (i - 0x48)))); + Texture::getBmpTexture(PICTURE_RESOURCE_ORE).drawSprite(p2.x, p2.y - 4 * (i - 0x48)); } if(P2.resource >= 0x51 && P2.resource <= 0x57) { for(char i = 0x51; i <= P2.resource; i++) - Draw(display, global::bmpArray[PICTURE_RESOURCE_GOLD].surface, - (int)(p2.x - global::bmpArray[PICTURE_RESOURCE_GOLD].nx), - (int)(p2.y - global::bmpArray[PICTURE_RESOURCE_GOLD].ny - (4 * (i - 0x50)))); + Texture::getBmpTexture(PICTURE_RESOURCE_GOLD).drawSprite(p2.x, p2.y - 4 * (i - 0x50)); } if(P2.resource >= 0x59 && P2.resource <= 0x5F) { for(char i = 0x59; i <= P2.resource; i++) - Draw(display, global::bmpArray[PICTURE_RESOURCE_GRANITE].surface, - (int)(p2.x - global::bmpArray[PICTURE_RESOURCE_GRANITE].nx), - (int)(p2.y - global::bmpArray[PICTURE_RESOURCE_GRANITE].ny - (4 * (i - 0x58)))); + Texture::getBmpTexture(PICTURE_RESOURCE_GRANITE).drawSprite(p2.x, p2.y - 4 * (i - 0x58)); } // blit animals if(P2.animal > 0x00 && P2.animal <= 0x06) - { - Draw(display, global::bmpArray[PICTURE_SMALL_BEAR + P2.animal].surface, - (int)(p2.x - global::bmpArray[PICTURE_SMALL_BEAR + P2.animal].nx), - (int)(p2.y - global::bmpArray[PICTURE_SMALL_BEAR + P2.animal].ny)); - } + Texture::getBmpTexture(PICTURE_SMALL_BEAR + P2.animal).drawSprite(p2.x, p2.y); } // blit buildings @@ -1190,34 +1094,16 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa { switch(P2.build % 8) { - case 0x01: - Draw(display, global::bmpArray[MAPPIC_FLAG].surface, (int)(p2.x - global::bmpArray[MAPPIC_FLAG].nx), - (int)(p2.y - global::bmpArray[MAPPIC_FLAG].ny)); - break; - case 0x02: - Draw(display, global::bmpArray[MAPPIC_HOUSE_SMALL].surface, - (int)(p2.x - global::bmpArray[MAPPIC_HOUSE_SMALL].nx), - (int)(p2.y - global::bmpArray[MAPPIC_HOUSE_SMALL].ny)); - break; - case 0x03: - Draw(display, global::bmpArray[MAPPIC_HOUSE_MIDDLE].surface, - (int)(p2.x - global::bmpArray[MAPPIC_HOUSE_MIDDLE].nx), - (int)(p2.y - global::bmpArray[MAPPIC_HOUSE_MIDDLE].ny)); - break; + case 0x01: Texture::getBmpTexture(MAPPIC_FLAG).drawSprite(p2.x, p2.y); break; + case 0x02: Texture::getBmpTexture(MAPPIC_HOUSE_SMALL).drawSprite(p2.x, p2.y); break; + case 0x03: Texture::getBmpTexture(MAPPIC_HOUSE_MIDDLE).drawSprite(p2.x, p2.y); break; case 0x04: if(P2.rsuTexture & 0x40) - Draw(display, global::bmpArray[MAPPIC_HOUSE_HARBOUR].surface, - (int)(p2.x - global::bmpArray[MAPPIC_HOUSE_HARBOUR].nx), - (int)(p2.y - global::bmpArray[MAPPIC_HOUSE_HARBOUR].ny)); + Texture::getBmpTexture(MAPPIC_HOUSE_HARBOUR).drawSprite(p2.x, p2.y); else - Draw(display, global::bmpArray[MAPPIC_HOUSE_BIG].surface, - (int)(p2.x - global::bmpArray[MAPPIC_HOUSE_BIG].nx), - (int)(p2.y - global::bmpArray[MAPPIC_HOUSE_BIG].ny)); - break; - case 0x05: - Draw(display, global::bmpArray[MAPPIC_MINE].surface, (int)(p2.x - global::bmpArray[MAPPIC_MINE].nx), - (int)(p2.y - global::bmpArray[MAPPIC_MINE].ny)); + Texture::getBmpTexture(MAPPIC_HOUSE_BIG).drawSprite(p2.x, p2.y); break; + case 0x05: Texture::getBmpTexture(MAPPIC_MINE).drawSprite(p2.x, p2.y); break; default: break; } } diff --git a/CSurface.h b/CSurface.h index 3677579..8081ab1 100644 --- a/CSurface.h +++ b/CSurface.h @@ -5,7 +5,6 @@ #pragma once -#include "SdlSurface.h" #include "defines.h" #include @@ -21,9 +20,7 @@ class CSurface static bool Draw(SDL_Surface* Surf_Dest, SdlSurface& Surf_Src, int X, int Y); static bool Draw(SdlSurface& Surf_Dest, SdlSurface& Surf_Src, Position pos = {0, 0}); static bool Draw(SdlSurface& Surf_Dest, SDL_Surface* Surf_Src, int X = 0, int Y = 0); - // blits from source on destination to position X,Y and rotates (angle --> degrees --> 90, 180, 270) - static bool Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y, int angle); - static bool Draw(SdlSurface& Surf_Dest, SdlSurface& Surf_Src, int X, int Y, int angle); + // blits rectangle from source on destination static bool Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, Position dest, Position srcOffset, Extent srcSize); static bool Draw(SDL_Surface* Surf_Dest, SdlSurface& Surf_Src, Position dest, Position srcOffset, Extent srcSize); @@ -52,10 +49,14 @@ class CSurface DrawPixel_RGB(screen.get(), pos, R, G, B); } static void DrawPixel_RGBA(SDL_Surface* screen, Position pos, Uint8 R, Uint8 G, Uint8 B, Uint8 A); - static Uint32 GetPixel(SDL_Surface* surface, Position pos); - static void DrawTriangleField(SDL_Surface* display, const DisplayRectangle& displayRect, const bobMAP& myMap); - static void DrawTriangle(SDL_Surface* display, const DisplayRectangle& displayRect, const bobMAP& myMap, - MapType type, const MapNode& P1, const MapNode& P2, const MapNode& P3); + + /// Render terrain into the current GL framebuffer. + /// displayRect specifies the visible area in map-pixel coordinates. + static void DrawTriangleField(const DisplayRectangle& displayRect, const bobMAP& myMap); + + /// Draw a single triangle given its three vertices. + static void DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& myMap, MapType type, const MapNode& P1, + const MapNode& P2, const MapNode& P3); static void get_nodeVectors(bobMAP& myMap); static void update_shading(bobMAP& myMap, Position pos); @@ -73,6 +74,7 @@ class CSurface static void update_flatVectors(bobMAP& myMap, Position pos); // update nodeVector based on new flatVectors around it static void update_nodeVector(bobMAP& myMap, Position pos); + static void GetTerrainTextureCoords(MapType mapType, TriangleTerrainType texture, bool isRSU, int texture_move, Point16& upper, Point16& left, Point16& right, Point16& upper2, Point16& left2, Point16& right2); diff --git a/LICENSES/LGPL-2.1-or-later.txt b/LICENSES/LGPL-2.1-or-later.txt deleted file mode 100644 index c9aa530..0000000 --- a/LICENSES/LGPL-2.1-or-later.txt +++ /dev/null @@ -1,175 +0,0 @@ -GNU LESSER GENERAL PUBLIC LICENSE - -Version 2.1, February 1999 - -Copyright (C) 1991, 1999 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] - -Preamble - -The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. - -This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. - -When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. - -To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. - -For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. - -We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. - -To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. - -Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. - -Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. - -When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. - -We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. - -For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. - -In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. - -Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. - -The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". - -A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. - -The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) - -"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. - -Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. - -1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. - -You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. - -(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. - -3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. - -Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. - -This option is useful when you wish to copy part of the code of the Library into a program that is not a library. - -4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. - -If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. - -5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. - -However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. - -When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. - -If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) - -Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - -6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. - -You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: - - a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. - - e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. - -For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. - -It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. - -7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. - - b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. - -8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. - -9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. - -10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. - -11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - -12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. - -13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. - -14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - -NO WARRANTY - -15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Libraries - -If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). - -To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - one line to give the library's name and an idea of what it does. - Copyright (C) year name of author - - This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: - -Yoyodyne, Inc., hereby disclaims all copyright interest in -the library `Frob' (a library for tweaking knobs) written -by James Random Hacker. - -signature of Ty Coon, 1 April 1990 -Ty Coon, President of Vice -That's all there is to it! diff --git a/SGE/CMakeLists.txt b/SGE/CMakeLists.txt deleted file mode 100644 index 108bdd8..0000000 --- a/SGE/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -# Copyright (C) 2009 - 2021 Settlers Freaks -# -# SPDX-License-Identifier: GPL-3.0-or-later - -FIND_PACKAGE(SDL2 REQUIRED) - -file(GLOB_RECURSE SGE_SOURCES *.cpp *.h) -add_library(SGE STATIC ${SGE_SOURCES}) -target_link_libraries(SGE PUBLIC Boost::boost SDL2::SDL2) -target_include_directories(SGE PRIVATE include/SGE PUBLIC include) -target_compile_features(SGE PUBLIC cxx_std_17) -set_target_properties(SGE PROPERTIES CXX_EXTENSIONS OFF) - -include(EnableWarnings) -enable_warnings(SGE) - -if(ClangFormat_FOUND) - add_clangFormat_files(${SGE_SOURCES}) -endif() diff --git a/SGE/LICENSE b/SGE/LICENSE deleted file mode 100644 index 5e64908..0000000 --- a/SGE/LICENSE +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/SGE/README.md b/SGE/README.md deleted file mode 100644 index 17a640d..0000000 --- a/SGE/README.md +++ /dev/null @@ -1,227 +0,0 @@ - - -SDL Graphics Extension (SGE) -==================================================================================== -http://freshmeat.net/projects/sge/ -http://www.etek.chalmers.se/~e8cal1/sge/index.html -http://www.digitalfanatics.org/cal/sge/index.html - -Author: Anders Lindström - email: cal@swipnet.se - - -1. Intro -2. Requirements -3. Compiling -4. Library usage -5. Makefile options - 5.1 Using pure C with SGE (C_COMP) - 5.2 FreeType (USE_FT) - 5.3 The SDL_Image library (USE_IMG) - 5.4 The QUIET option (QUIET) -6. Cross compiling SGE to W32 -7. Compiling SGE under W32 with MS VisC/C++ -8. Thanks -9. Misc. - - -==================================================================================== -1. Intro - -SGE is an add-on graphics library for the Simple Direct Media Layer. SGE provides -pixel operations, graphics primitives, FreeType rendering, rotation/scaling and much -more. - -This is free software (LGPL), read LICENSE for details. - -SGE has the following parts: -[sge_surface] Pixel operations, blitting and some pallete stuff. -[sge_primitives] Drawing primitives. -[sge_tt_text] FreeType font support. -[sge_bm_text] Bitmapfont and SFont support. -[sge_textpp] Classes for handling and rendering text. -[sge_shape] Classes for blitting and sprites. -[sge_collision] Basic collision detection. -[sge_rotation] Rotation and scaling of surfaces. -[sge_blib] Normal, filled, gourand shaded and texture mapped polygons. -[sge_misc] Random number and delay functions. - - -Read docs/index.html for API documentation. - -Always check WhatsNew for important (API) changes! - -There is a "Beginners guide to SGE" in the html documentation about how to compile and -use SGE in your own project, please read it if you're new to Unix/Linux development. - -Read INSTALL for quick compile and install instructions. - - -==================================================================================== -2. Requirements - --GNU Make. --SDL 1.2+. --An ANSI/ISO C++ compiler. SGE should conform to ANSI/ISO C++. --Optional: - -FreeType 2+ - -SDL_Image (see section 5.3) --Some SDL knowledge. - -First you need SDL (http://www.libsdl.org/) and the FreeType (2.x) library -at http://www.freetype.org/ (you only need the FreeType library if you want -to use SGE's truetype font routines, see section 5.2). The FreeType library is -included in most Linux distributions (RPM users: install the freetype dev rpm -package from the install cd). - -After installing SDL and FreeType, don't forget to check that the dynamic -linker can find them (check /etc/ld.so.conf and run ldconfig). - -You must also have a good C++ compiler (should be able to handle templates). Recent -versions of GNU c++ works fine. SGE will use gcc/g++ as default, but this can be -changed in the file "Makefile.conf". - - -==================================================================================== -3. Compiling - -Before compiling you might want to change some Makefile.conf options, see section 5. - -Just do 'make install' to compile and install SGE. This will install SGE to the same -place as SDL. You can change the install location by editing the PREFIX and PREFIX_H -lines in the file "Makefile.conf". - -If you just want to test the examples (and not install anything) you can just do -'make'. This will build a static version of SGE (libSGE.a). - -If you want a dynamic version of SGE (libSGE.so) but don't want the makefile to -install SGE, do 'make shared'. - -To build the examples, goto the directory examples/ and do 'make'. - -See the file INSTALL for more information. You can also read the file -"docs/guide.html" - - -==================================================================================== -4. Library usage - -Do "#include "sge.h"" in your code after the normal "#include "SDL.h"" line. - -The normal way to compile code that uses SGE is with the flag -"`sdl-config --cflags`", but also add the flag "-I/path/to/SGE/headers" if the SGE -headers are installed at any other place than the SDL headers. - -The normal way to link code that uses SGE is with the flags -"-lSGE `sdl-config --libs` -lstdc++", but also add the flag "-L/path/to/SGE/library" -if SGE is installed at any other place than SDL. If you're using static linking then -the flags "`freetype-config --libs`" and/or "-lSDL_image" also needs to be added if -FreeType and/or SDL_Image support is enabled. - -Example: -g++ -Wall -O3 `sdl-config --cflags` -c my_sge_app.cxx -g++ -o my_sge_app my_sge_app.o -lSGE `sdl-config --libs` -lstdc++ - -See "docs/guide.html" and the code in examples/ for more information. - - -==================================================================================== -5. Makefile options - -Edit Makefile.conf to turn on/off (y/n) these options. - - -5.1 Using pure C with SGE (C_COMP) - -Setting 'C_COMP = y' should allow both C and C++ projects to use SGE. However, you -will not be able to use any of the overloaded functions (only the Uint32 color -version of the overloaded functions will be available) or C++ classes from a C -project. C++ projects should not be affected. Default is 'y'. - - -5.2 FreeType (USE_FT) - -If you don't need the TT font routines or just don't want do depend on FreeType, -uncomment 'USE_FT = n' in Makefile.conf. Default behavior is to autodetect -FreeType. - - -5.3 The SDL_Image library (USE_IMG) - -The SDL_Image library (http://www.libsdl.org/projects/SDL_image/index.html) will be -autodetected with the default setting. SDL_Image support enables SGE to load png -images and thus use Karl Bartel's very nice SFont bitmapfonts -(http://www.linux-games.com/sfont/). The use of SDL_Image can also be controlled by -setting 'USE_IMG = y/n' manually. - - -5.4 The QUIET option (QUIT) -Set 'QUIET = y' if you don't want the makefile to output any SGE specific messages. - - -==================================================================================== -6. Cross compiling SGE to W32 - -SGE can be compiled by a win32 crosscompiler. You need a crosscompiled version of -SDL (and FreeType or SDL_Image if used). Check SDL's documentation (README.Win32) on how to get and setup -a cross-compiler. - -A crosscompiler can be found at http://www.libsdl.org/Xmingw32/index.html. This -crosscompiler uses the new MS C-Run-time library "msvcrt.dll", you can get it from -www.microsoft.com/downloads (do a keyword search for "libraries update") if you -don't already have it. - -If you want to build a dll ('cross-make dll' or 'dll-strip') then you might want to -do 'ln -s ../../bin/i386-mingw32msvc-dllwrap dllwrap' in -/usr/local/cross-tools/i386-mingw32msvc/bin. - - -==================================================================================== -7. Compiling SGE under W32 with MS VisC/C++ - -Should work. Check the download page on SGEs homepage for project files (these are -untested by me and are often outdated but may be of some help). - -Note that if you don't use the makefile system to build SGE (as with VisC/C++) then -you must edit sge_config.h manually to change build options. The options in section -5 corresponds to defining the following symbols in sge_config.h: -_SGE_C_AND_CPP - C_COMP=y -_SGE_NOTTF - USE_FT=n -_SGE_HAVE_IMG - USE_IMG=y - -For example: -/* SGE Config header */ -#define SGE_VER 030809 -#define _SGE_C_AND_CPP -#define _SGE_HAVE_IMG - - -==================================================================================== -8. Thanks. - -Thanks goes to... --Sam Lantinga for the excellent SDL library. --The FreeType library developers. --John Garrison for the PowerPak library. --Karl Bartel for the SFont library (http://www.linux-games.com/). --Garrett Banuk for his bitmap font routines (http://www.mongeese.org/SDL_Console/). --Seung Chan Lim (limsc@maya.com or slim@djslim.com). --Idigoras Inaki (IIdigoras@ikerlan.es). --Andreas Schiffler (http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html). --Nicolas Roard (http://www.twinlib.org). - -and many more... - -==================================================================================== -9. Misc. - -Read the html documentation and study the examples. - - - -/Anders Lindstr�m - email: cal@swipnet.se diff --git a/SGE/include/SGE/FixedPoint.h b/SGE/include/SGE/FixedPoint.h deleted file mode 100644 index 67adfd0..0000000 --- a/SGE/include/SGE/FixedPoint.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include -#include - -namespace s25edit { -template -class FixedPoint -{ - using UnsignedData = std::make_unsigned_t; - using SignedData = std::make_unsigned_t; - static constexpr size_t factor = 1 << T_decimals; - T_Underlying data; - -public: - constexpr explicit FixedPoint(T_Underlying value = 0) : data(value * factor) {} - constexpr explicit operator T_Underlying() const noexcept { return data / factor; } - constexpr SignedData toInt() const noexcept { return data / factor; } - constexpr UnsignedData toUnsigned() const noexcept - { - assert(data / factor >= 0); - return data / factor; - } - FixedPoint& operator+=(FixedPoint rhs) noexcept - { - data += rhs.data; - return *this; - } - FixedPoint& operator-=(FixedPoint rhs) noexcept - { - data -= rhs.data; - return *this; - } - FixedPoint& operator*=(T_Underlying rhs) noexcept - { - data *= rhs; - return *this; - } - FixedPoint& operator/=(T_Underlying rhs) noexcept - { - data /= rhs; - return *this; - } - friend FixedPoint operator+(FixedPoint lhs, FixedPoint rhs) { return lhs += rhs; } - friend FixedPoint operator-(FixedPoint lhs, FixedPoint rhs) { return lhs -= rhs; } - friend FixedPoint operator*(FixedPoint lhs, T_Underlying rhs) { return lhs *= rhs; } - friend FixedPoint operator*(T_Underlying lhs, FixedPoint rhs) { return rhs *= lhs; } - friend FixedPoint operator/(FixedPoint lhs, T_Underlying rhs) { return lhs /= rhs; } -}; -} // namespace s25edit diff --git a/SGE/include/SGE/sge.h b/SGE/include/SGE/sge.h deleted file mode 100644 index 9063d72..0000000 --- a/SGE/include/SGE/sge.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * - * Started 990815 - */ - -#pragma once - -#include "sge_blib.h" -#include "sge_collision.h" -#include "sge_misc.h" -#include "sge_primitives.h" -#include "sge_rotation.h" -#include "sge_shape.h" -#include "sge_surface.h" diff --git a/SGE/include/SGE/sge_blib.h b/SGE/include/SGE/sge_blib.h deleted file mode 100644 index 79dce7b..0000000 --- a/SGE/include/SGE/sge_blib.h +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (C) 2000 - 2003 Anders Lindström & Johan E. Thelin -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Johan E. Thelin's BLib (header) - * - * Started 000428 - */ - -#pragma once - -#include "sge_internal.h" - -#ifdef _SGE_C -extern "C" -{ -#endif - DECLSPEC void sge_FadedLine(SDL_Surface* dest, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r1, Uint8 g1, Uint8 b1, - Uint8 r2, Uint8 g2, Uint8 b2); - // works at the moment only if destination and source surface have both 32bpp - DECLSPEC void sge_FadedTexturedLine(SDL_Surface* dest, Sint16 x1, Sint16 x2, Sint16 y, SDL_Surface* source, - Sint16 sx1, Sint16 sy1, Sint16 sx2, Sint16 sy2, Sint32 i1, Sint32 i2); - - DECLSPEC void sge_Trigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint32 color); - DECLSPEC void sge_TrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint32 color, Uint8 alpha); - DECLSPEC void sge_AATrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint32 color); - DECLSPEC void sge_AATrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint32 color, Uint8 alpha); - - DECLSPEC void sge_FilledTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint32 color); - DECLSPEC void sge_FilledTrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, - Sint16 y3, Uint32 color, Uint8 alpha); - - DECLSPEC void sge_FadedTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint32 c1, Uint32 c2, Uint32 c3); - DECLSPEC void sge_TexturedTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, - Sint16 y3, SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, Sint16 sy2, - Sint16 sx3, Sint16 sy3); - // works at the moment only if destination and source surface have both 32bpp - DECLSPEC void sge_FadedTexturedTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, - Sint16 y3, SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, - Sint16 sy2, Sint16 sx3, Sint16 sy3, Sint32 I1, Sint32 I2, Sint32 I3); - // works at the moment only if destination and source surface have both 8bpp - DECLSPEC void sge_PreCalcFadedTexturedTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, - Sint16 x3, Sint16 y3, SDL_Surface* source, Sint16 sx1, Sint16 sy1, - Sint16 sx2, Sint16 sy2, Sint16 sx3, Sint16 sy3, Uint16 I1, Uint16 I2, - Uint16 I3, Uint8 PreCalcPalettes[][256]); - // if destination and source surface have both 32bpp then a few colorkeys will be respected - DECLSPEC void sge_FadedTexturedTrigonColorKeys(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, - Sint16 x3, Sint16 y3, SDL_Surface* source, Sint16 sx1, Sint16 sy1, - Sint16 sx2, Sint16 sy2, Sint16 sx3, Sint16 sy3, Sint32 I1, Sint32 I2, - Sint32 I3, Uint32 keys[], int keycount); - // if destination and source surface have both 8bpp then a few colorkeys will be respected - DECLSPEC void sge_PreCalcFadedTexturedTrigonColorKeys(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, - Sint16 x3, Sint16 y3, SDL_Surface* source, Sint16 sx1, - Sint16 sy1, Sint16 sx2, Sint16 sy2, Sint16 sx3, Sint16 sy3, - Uint16 I1, Uint16 I2, Uint16 I3, Uint8 PreCalcPalettes[][256], - Uint32 keys[], int keycount); - - // NOTE: Sort of the coords P1 P2 - // P3 P4 - DECLSPEC void sge_TexturedRect(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Sint16 x4, Sint16 y4, SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, - Sint16 sy2, Sint16 sx3, Sint16 sy3, Sint16 sx4, Sint16 sy4); - - DECLSPEC int sge_FilledPolygon(SDL_Surface* dest, Uint16 n, Sint16* x, Sint16* y, Uint32 color); - DECLSPEC int sge_FilledPolygonAlpha(SDL_Surface* dest, Uint16 n, const Sint16* x, const Sint16* y, Uint32 color, - Uint8 alpha); - DECLSPEC int sge_AAFilledPolygon(SDL_Surface* dest, Uint16 n, const Sint16* x, const Sint16* y, Uint32 color); - - DECLSPEC int sge_FadedPolygon(SDL_Surface* dest, Uint16 n, Sint16* x, Sint16* y, Uint8* R, Uint8* G, Uint8* B); - DECLSPEC int sge_FadedPolygonAlpha(SDL_Surface* dest, Uint16 n, const Sint16* x, const Sint16* y, const Uint8* R, - const Uint8* G, const Uint8* B, Uint8 alpha); - DECLSPEC int sge_AAFadedPolygon(SDL_Surface* dest, Uint16 n, const Sint16* x, const Sint16* y, const Uint8* R, - const Uint8* G, const Uint8* B); -#ifdef _SGE_C -} -#endif - -#ifndef sge_C_ONLY -DECLSPEC void sge_Trigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 R, - Uint8 G, Uint8 B); -DECLSPEC void sge_TrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint8 R, Uint8 G, Uint8 B, Uint8 alpha); -DECLSPEC void sge_AATrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 R, - Uint8 G, Uint8 B); -DECLSPEC void sge_AATrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint8 R, Uint8 G, Uint8 B, Uint8 alpha); -DECLSPEC void sge_FilledTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_FilledTrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint8 R, Uint8 G, Uint8 B, Uint8 alpha); -DECLSPEC int sge_FilledPolygon(SDL_Surface* dest, Uint16 n, Sint16* x, Sint16* y, Uint8 r, Uint8 g, Uint8 b); -DECLSPEC int sge_FilledPolygonAlpha(SDL_Surface* dest, Uint16 n, Sint16* x, Sint16* y, Uint8 r, Uint8 g, Uint8 b, - Uint8 alpha); -DECLSPEC int sge_AAFilledPolygon(SDL_Surface* dest, Uint16 n, Sint16* x, Sint16* y, Uint8 r, Uint8 g, Uint8 b); -#endif /* sge_C_ONLY */ diff --git a/SGE/include/SGE/sge_collision.h b/SGE/include/SGE/sge_collision.h deleted file mode 100644 index 3d15eb3..0000000 --- a/SGE/include/SGE/sge_collision.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Collision routines (header) - * - * Started 000625 - */ - -#pragma once - -#include "sge_internal.h" - -/* The collision struct */ -struct sge_cdata -{ - Uint8* map; - Uint16 w, h; -}; - -#ifdef _SGE_C -extern "C" -{ -#endif - DECLSPEC sge_cdata* sge_make_cmap(SDL_Surface* img); - DECLSPEC int sge_bbcheck(sge_cdata* cd1, Sint16 x1, Sint16 y1, sge_cdata* cd2, Sint16 x2, Sint16 y2); - DECLSPEC int _sge_bbcheck(Sint16 x1, Sint16 y1, Sint16 w1, Sint16 h1, Sint16 x2, Sint16 y2, Sint16 w2, Sint16 h2); - DECLSPEC int _sge_cmcheck(sge_cdata* cd1, Sint16 x1, Sint16 y1, sge_cdata* cd2, Sint16 x2, Sint16 y2); - DECLSPEC int sge_cmcheck(sge_cdata* cd1, Sint16 x1, Sint16 y1, sge_cdata* cd2, Sint16 x2, Sint16 y2); - DECLSPEC Sint16 sge_get_cx(); - DECLSPEC Sint16 sge_get_cy(); - DECLSPEC void sge_destroy_cmap(sge_cdata* cd); - DECLSPEC void sge_unset_cdata(sge_cdata* cd, Sint16 x, Sint16 y, Sint16 w, Sint16 h); - DECLSPEC void sge_set_cdata(sge_cdata* cd, Sint16 x, Sint16 y, Sint16 w, Sint16 h); -#ifdef _SGE_C -} -#endif - -#ifndef _SGE_NO_CLASSES -class DECLSPEC sge_shape; -DECLSPEC int sge_bbcheck_shape(sge_shape* shape1, sge_shape* shape2); -#endif /* _SGE_NO_CLASSES */ diff --git a/SGE/include/SGE/sge_config.h b/SGE/include/SGE/sge_config.h deleted file mode 100644 index a8ca097..0000000 --- a/SGE/include/SGE/sge_config.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström & Johan E. Thelin -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -#pragma once - -/* SGE Config header (generated automatically) */ -#define SGE_VER 030809 -#define _SGE_C_AND_CPP -#define _SGE_NOTTF diff --git a/SGE/include/SGE/sge_internal.h b/SGE/include/SGE/sge_internal.h deleted file mode 100644 index c65bf15..0000000 --- a/SGE/include/SGE/sge_internal.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (C) 2000 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * SGE internal header - * - * Started 000627 - */ - -#pragma once - -/* This header is included in all sge_*.h files */ - -#include "sge_config.h" -#include - -/* - * C compatibility - * Thanks to Ohbayashi Ippei (ohai@kmc.gr.jp) for this clever hack! - */ -#ifdef _SGE_C_AND_CPP -# ifdef __cplusplus -# define _SGE_C /* use extern "C" on base functions */ -# include -template -constexpr auto absDiff(T a, T b) -{ - using U = std::make_unsigned_t; - return static_cast(a > b ? a - b : b - a); -} -# else -# define sge_C_ONLY /* remove overloaded functions */ -# define _SGE_NO_CLASSES /* no C++ classes */ -# endif -#endif - -/* - * Bit flags - */ -#define SGE_FLAG0 0x00 -#define SGE_FLAG1 0x01 -#define SGE_FLAG2 0x02 -#define SGE_FLAG3 0x04 -#define SGE_FLAG4 0x08 -#define SGE_FLAG5 0x10 -#define SGE_FLAG6 0x20 -#define SGE_FLAG7 0x40 -#define SGE_FLAG8 0x80 - -/* - * Macro to get clipping - */ -inline auto sge_clip_xmin(const SDL_Surface* pnt) -{ - return pnt->clip_rect.x; -} -inline auto sge_clip_xmax(const SDL_Surface* pnt) -{ - return (pnt->clip_rect.x + pnt->clip_rect.w - 1); -} -inline auto sge_clip_ymin(const SDL_Surface* pnt) -{ - return pnt->clip_rect.y; -} -inline auto sge_clip_ymax(const SDL_Surface* pnt) -{ - return (pnt->clip_rect.y + pnt->clip_rect.h - 1); -} - -/* - * Some compilers use a special export keyword - * Thanks to Seung Chan Lim (limsc@maya.com or slim@djslim.com) to pointing this out - * (From SDL) - */ -#ifndef DECLSPEC -# ifdef __BEOS__ -# if defined(__GNUC__) -# define DECLSPEC __declspec(dllexport) -# else -# define DECLSPEC __declspec(export) -# endif -# elif defined(WIN32) -# define DECLSPEC __declspec(dllexport) -# else -# define DECLSPEC -# endif -#endif - -#ifdef __GNUC__ -# define SGE_ATTRIBUTE_FORMAT(fmtStringIdx, firstArgIdx) __attribute__((format(printf, fmtStringIdx, firstArgIdx))) -#else -# define SGE_ATTRIBUTE_FORMAT(fmtStringIdx, firstArgIdx) -#endif diff --git a/SGE/include/SGE/sge_misc.cpp b/SGE/include/SGE/sge_misc.cpp deleted file mode 100644 index 8c1640f..0000000 --- a/SGE/include/SGE/sge_misc.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Misc functions - * - * Started 990819 - */ - -#include "sge_misc.h" -#include -#include - -Uint32 delay_res = 10; - -//================================================================================== -// Returns a random integer between min and max -//================================================================================== -int sge_Random(int min, int max) -{ - return min + (rand() % (max - min + 1)); -} - -//================================================================================== -// Seed the random number generator with a number from the system clock. -// Should be called once before the first use of sge_Random. -//================================================================================== -void sge_Randomize() -{ - srand(static_cast(time(nullptr))); -} - -//================================================================================== -// Test the resolution of SDL_Delay() -//================================================================================== -Uint32 sge_CalibrateDelay() -{ - SDL_Delay(10); - delay_res = SDL_GetTicks(); - SDL_Delay(1); - delay_res = SDL_GetTicks() - delay_res; - - return delay_res; -} - -//================================================================================== -// Get the resolution of SDL_Delay() -//================================================================================== -Uint32 sge_DelayRes() -{ - return delay_res; -} - -//================================================================================== -// Delay 'ticks' ms. -// Tries to burn time in SDL_Delay() if possible -// Returns the exact delay time -//================================================================================== -Uint32 sge_Delay(Uint32 ticks) -{ - Uint32 start = SDL_GetTicks(); - auto time_left = (Sint32)ticks; - Uint32 tmp; - - if(ticks >= delay_res) - { - tmp = ticks - (ticks % delay_res); - SDL_Delay(tmp); - time_left = (Sint32)(ticks - (SDL_GetTicks() - start)); // Possible error for large ticks... nah - } - - while(time_left > 0) - { - time_left = (Sint32)(ticks - (SDL_GetTicks() - start)); - } - - return SDL_GetTicks() - start; -} diff --git a/SGE/include/SGE/sge_misc.h b/SGE/include/SGE/sge_misc.h deleted file mode 100644 index f9f6391..0000000 --- a/SGE/include/SGE/sge_misc.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Misc functions (header) - * - * Started 990819 - */ - -#pragma once - -#include "sge_internal.h" - -#ifdef _SGE_C -extern "C" -{ -#endif - DECLSPEC int sge_Random(int min, int max); - DECLSPEC void sge_Randomize(); - - DECLSPEC Uint32 sge_CalibrateDelay(); - DECLSPEC Uint32 sge_DelayRes(); - DECLSPEC Uint32 sge_Delay(Uint32 ticks); -#ifdef _SGE_C -} -#endif diff --git a/SGE/include/SGE/sge_primitives.h b/SGE/include/SGE/sge_primitives.h deleted file mode 100644 index c31b212..0000000 --- a/SGE/include/SGE/sge_primitives.h +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Drawing primitives (header) - * - * Started 990815 (split from sge_draw 010611) - */ - -#pragma once - -#include "sge_internal.h" - -#ifdef _SGE_C -extern "C" -{ -#endif - DECLSPEC void sge_HLine(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color); - DECLSPEC void sge_HLineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color, Uint8 alpha); - DECLSPEC void sge_VLine(SDL_Surface* Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color); - DECLSPEC void sge_VLineAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color, Uint8 alpha); - DECLSPEC void sge_DoLine(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)); - DECLSPEC void sge_Line(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color); - DECLSPEC void sge_LineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, - Uint8 alpha); - DECLSPEC void sge_AALine(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); - DECLSPEC void sge_AALineAlpha(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, - Uint8 alpha); - DECLSPEC void sge_DomcLine(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, - Uint8 b1, Uint8 r2, Uint8 g2, Uint8 b2, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)); - DECLSPEC void sge_mcLine(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, - Uint8 b1, Uint8 r2, Uint8 g2, Uint8 b2); - DECLSPEC void sge_mcLineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, - Uint8 b1, Uint8 r2, Uint8 g2, Uint8 b2, Uint8 alpha); - DECLSPEC void sge_AAmcLine(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, - Uint8 b1, Uint8 r2, Uint8 g2, Uint8 b2); - DECLSPEC void sge_AAmcLineAlpha(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, - Uint8 b1, Uint8 r2, Uint8 g2, Uint8 b2, Uint8 alpha); - - DECLSPEC void sge_Rect(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); - DECLSPEC void sge_RectAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, - Uint8 alpha); - DECLSPEC void sge_FilledRect(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); - DECLSPEC void sge_FilledRectAlpha(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, - Uint8 alpha); - - DECLSPEC void sge_DoEllipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint32 color, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)); - DECLSPEC void sge_Ellipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint32 color); - DECLSPEC void sge_EllipseAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint32 color, - Uint8 alpha); - DECLSPEC void sge_FilledEllipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint32 color); - DECLSPEC void sge_FilledEllipseAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint32 color, - Uint8 alpha); - DECLSPEC void sge_AAFilledEllipse(SDL_Surface* surface, Sint16 xc, Sint16 yc, Uint16 rx, Uint16 ry, Uint32 color); - - DECLSPEC void sge_DoCircle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint32 color, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)); - DECLSPEC void sge_Circle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint32 color); - DECLSPEC void sge_CircleAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint32 color, Uint8 alpha); - DECLSPEC void sge_FilledCircle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint32 color); - DECLSPEC void sge_FilledCircleAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint32 color, Uint8 alpha); - DECLSPEC void sge_AAFilledCircle(SDL_Surface* surface, Sint16 xc, Sint16 yc, Uint16 r, Uint32 color); - - DECLSPEC void sge_Bezier(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Sint16 x4, Sint16 y4, int level, Uint32 color); - DECLSPEC void sge_BezierAlpha(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, - Sint16 y3, Sint16 x4, Sint16 y4, int level, Uint32 color, Uint8 alpha); - DECLSPEC void sge_AABezier(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Sint16 x4, Sint16 y4, int level, Uint32 color); - DECLSPEC void sge_AABezierAlpha(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, - Sint16 y3, Sint16 x4, Sint16 y4, int level, Uint32 color, Uint8 alpha); -#ifdef _SGE_C -} -#endif - -#ifndef sge_C_ONLY -DECLSPEC void sge_HLine(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_HLineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha); -DECLSPEC void sge_VLine(SDL_Surface* Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_VLineAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha); -DECLSPEC void sge_DoLine(SDL_Surface* Surface, Sint16 X1, Sint16 Y1, Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)); -DECLSPEC void sge_Line(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_LineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha); -DECLSPEC void sge_AALine(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b); -DECLSPEC void sge_AALineAlpha(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, - Uint8 alpha); -DECLSPEC void sge_Rect(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_RectAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha); -DECLSPEC void sge_FilledRect(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, - Uint8 B); -DECLSPEC void sge_FilledRectAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, - Uint8 B, Uint8 alpha); -DECLSPEC void sge_DoEllipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, Uint8 B, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)); -DECLSPEC void sge_Ellipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_EllipseAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, - Uint8 B, Uint8 alpha); -DECLSPEC void sge_FilledEllipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, - Uint8 B); -DECLSPEC void sge_FilledEllipseAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, - Uint8 B, Uint8 alpha); -DECLSPEC void sge_AAFilledEllipse(SDL_Surface* surface, Sint16 xc, Sint16 yc, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, - Uint8 B); -DECLSPEC void sge_DoCircle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint8 R, Uint8 G, Uint8 B, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)); -DECLSPEC void sge_Circle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_CircleAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha); -DECLSPEC void sge_FilledCircle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_FilledCircleAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha); -DECLSPEC void sge_AAFilledCircle(SDL_Surface* surface, Sint16 xc, Sint16 yc, Uint16 r, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_Bezier(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Sint16 x4, Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_BezierAlpha(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Sint16 x4, Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha); -DECLSPEC void sge_AABezier(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Sint16 x4, Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_AABezierAlpha(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Sint16 x4, Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha); -#endif /* sge_C_ONLY */ diff --git a/SGE/include/SGE/sge_rotation.h b/SGE/include/SGE/sge_rotation.h deleted file mode 100644 index ba32962..0000000 --- a/SGE/include/SGE/sge_rotation.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Rotation routines (header) - * - * Started 000625 - */ - -#pragma once - -#include "sge_internal.h" - -/* Transformation flags */ -#define SGE_TAA SGE_FLAG1 -#define SGE_TSAFE SGE_FLAG2 -#define SGE_TTMAP SGE_FLAG3 - -#ifdef _SGE_C -extern "C" -{ -#endif - DECLSPEC SDL_Rect sge_transform(SDL_Surface* src, SDL_Surface* dst, float angle, float xscale, float yscale, - Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags); - DECLSPEC SDL_Surface* sge_transform_surface(SDL_Surface* src, Uint32 bcol, float angle, float xscale, float yscale, - Uint8 flags); - -#ifdef _SGE_C -} -#endif diff --git a/SGE/include/SGE/sge_shape.h b/SGE/include/SGE/sge_shape.h deleted file mode 100644 index 5036279..0000000 --- a/SGE/include/SGE/sge_shape.h +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright (C) 2000 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * SGE shape (header) - * - * Started 000430 - */ - -#pragma once - -#include "sge_internal.h" -#include - -#ifndef _SGE_NO_CLASSES - -// Remove "class 'std::list<>' needs to have dll-interface to be used" warnings -// from MS VisualC++ -# ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4251) -# endif - -# include -# include - -struct sge_cdata; -class DECLSPEC sge_shape; - -//================================================================================== -// sge_shape -// Abstract base class for different shapes (surfaces, sprites, ...) -//================================================================================== -class sge_shape -{ -protected: - SDL_Rect current_pos; // The *current* (maybe undrawn) position of the shape - SDL_Rect last_pos; // The *last* drawn position of shape - SDL_Rect prev_pos; // The previous drawn position of shape (used to update a cleared area) - - SDL_Surface* dest; // The surface to perform operations on - -public: - virtual ~sge_shape() = default; // Destructor - virtual void draw() = 0; // Draws the shape - prev_pos = last_pos; last_pos = the new position of shape - - // Some functions to clear (remove) shape - virtual void clear(Uint32 color) = 0; // Clears to color - virtual void clear(SDL_Surface* src, Sint16 srcX, Sint16 srcY) = 0; // Clears by blitting src - - SDL_Rect get_pos() const { return current_pos; } // Returns the current position - SDL_Rect get_last_pos() const { return last_pos; } // Returns the last updated position - - SDL_Surface* get_dest() const { return dest; } - - /* - //NW N NE - // \|/ - // W-C-E - // /|\ - //SW S SE - // - //Returns some usefull coords in shape (current) - */ - Sint16 c_x() const { return current_pos.x + current_pos.w / 2; } - Sint16 c_y() const { return current_pos.y + current_pos.h / 2; } - - Sint16 nw_x() const { return current_pos.x; } - Sint16 nw_y() const { return current_pos.y; } - - Sint16 n_x() const { return current_pos.x + current_pos.w / 2; } - Sint16 n_y() const { return current_pos.y; } - - Sint16 ne_x() const { return current_pos.x + current_pos.w - 1; } - Sint16 ne_y() const { return current_pos.y; } - - Sint16 e_x() const { return current_pos.x + current_pos.w - 1; } - Sint16 e_y() const { return current_pos.y + current_pos.h / 2; } - - Sint16 se_x() const { return current_pos.x + current_pos.w - 1; } - Sint16 se_y() const { return current_pos.y + current_pos.h - 1; } - - Sint16 s_x() const { return current_pos.x + current_pos.w / 2; } - Sint16 s_y() const { return current_pos.y + current_pos.h - 1; } - - Sint16 sw_x() const { return current_pos.x; } - Sint16 sw_y() const { return current_pos.y + current_pos.h - 1; } - - Sint16 w_x() const { return current_pos.x; } - Sint16 w_y() const { return current_pos.y + current_pos.h / 2; } - - Sint16 get_xpos() const { return current_pos.x; } - Sint16 get_ypos() const { return current_pos.y; } - Uint16 get_w() const { return current_pos.w; } - Uint16 get_h() const { return current_pos.h; } -}; - -//================================================================================== -// sge_surface (derived from sge_shape) -// A class for moving/blitting surfaces -//================================================================================== -class DECLSPEC sge_surface : public sge_shape -{ -protected: - SDL_Surface* surface; // The source surface *NOT COPIED* - - // Do warp logic - bool check_warp(); - - // Handles outside screen problems (But not in this class) - virtual bool check_border() { return check_warp(); } - - // The border box (default: the screen size) - SDL_Rect border; - - // Should we warp around the border box? (not in this class - // but some methods here must know) - bool warp_border; - - // Decode a warp pos rectangle - int get_warp(SDL_Rect rec, SDL_Rect& r1, SDL_Rect& r2, SDL_Rect& r3, SDL_Rect& r4) const; - - // Helper functions - void warp_draw(); - void warp_clear(Uint32 color); - void warp_clear(SDL_Surface* src, Sint16 srcX, Sint16 srcY); - -public: - sge_surface(SDL_Surface* dest, SDL_Surface* src, Sint16 x = 0, Sint16 y = 0); - ~sge_surface(); - - // Draws the surface - virtual void draw() override; - - virtual void clear(Uint32 color) override; - virtual void clear(SDL_Surface* src, Sint16 srcX, Sint16 srcY) override; - // virtual void clear(SDL_Surface *src){clear(src,last_pos.x,last_pos.y);} - - // Move the surface - virtual void move_to(Sint16 x, Sint16 y) - { - current_pos.x = x; - current_pos.y = y; - check_border(); - } - virtual void move(Sint16 x_step, Sint16 y_step) - { - current_pos.x += x_step; - current_pos.y += y_step; - check_border(); - } - - // Get pointer to surface - SDL_Surface* get_img() const { return surface; } - - // Sets the border box - void set_border(SDL_Rect box) { border = box; } -}; - -//================================================================================== -// The frame struct (for sge_ssprite) -//================================================================================== -struct sge_frame -{ - // The image - SDL_Surface* img; - - // Collision data - sge_cdata* cdata; -}; - -//================================================================================== -// sge_ssprite (derived from sge_surface) -// A simple sprite class -//================================================================================== -class DECLSPEC sge_ssprite : public sge_surface -{ -public: - enum playing_mode - { - loop, - play_once, - stop - }; // This must be public - -protected: - // Linked list with the frames - // Obs! 'surface' always points to the current frame image - std::list frames; - using FI = std::list::const_iterator; // List iterator (for frames) - - FI current_fi; - FI fi_start; // first frame in the playing sequence loop - FI fi_stop; // last frame + 1 - - // The pointer to the current frame - sge_frame* current_frame; // Should at all times be *current_fi - - // The speed of the sprite (pixels/update) - Sint16 xvel, yvel; - - bool bounce_border; // Do we want the sprite to bounce at the border? - virtual bool check_border() override; - - // Playing sequence mode - playing_mode seq_mode; - -public: - // Constructor and destructor - sge_ssprite(SDL_Surface* screen, SDL_Surface* img, Sint16 x = 0, Sint16 y = 0); - sge_ssprite(SDL_Surface* screen, SDL_Surface* img, sge_cdata* cdata, Sint16 x = 0, Sint16 y = 0); - ~sge_ssprite(); - - // Updates the internal status - // Returns true if the sprite moved - virtual bool update(); - - // Sets the speed - void set_vel(Sint16 x, Sint16 y) - { - xvel = x; - yvel = y; - } - void set_xvel(Sint16 x) { xvel = x; } - void set_yvel(Sint16 y) { yvel = y; } - - // Gets the speed - Sint16 get_xvel() const { return xvel; } - Sint16 get_yvel() const { return yvel; } - - // Add a frame - // Obs! Resets playing sequence - void add_frame(SDL_Surface* img); - void add_frame(SDL_Surface* img, sge_cdata* cdata); - - // Change frame - void skip_frame(int skips); // A negative 'skips' indicates backwards - void next_frame() { skip_frame(1); } - void prev_frame() { skip_frame(-1); } - void first_frame(); // Does NOT change the sequence - void last_frame(); // " - - // Changes playing sequence (0- first frame) - // playing_mode: - // sge_ssprite::loop - loops forever - // sge_ssprite::play_once - just once then stops - // sge_ssprite::stop - is returned by get_PlayingMode() if stoped - void set_seq(int start, int stop, playing_mode mode = loop); - void reset_seq(); - playing_mode get_PlayingMode() { return seq_mode; } - - // Get cdata for current frame - sge_cdata* get_cdata() { return current_frame->cdata; } - - // Get the current frame - sge_frame* get_frame() { return current_frame; } - - // Get the frame list - // DO NOT ADD OR REMOVE ELEMENTS without using - // reset_seq() when done!! - std::list* get_list() { return &frames; } - - // Set border mode: - // Bounce - sprite bounces (default) - // Warp - sprite warps at border - void border_bounce(bool mode) - { - bounce_border = mode; - if(warp_border) - { - warp_border = false; - } - } - void border_warp(bool mode) - { - warp_border = mode; - if(bounce_border) - { - bounce_border = false; - } - } -}; - -//================================================================================== -// sge_sprite (derived from sge_ssprite) -// A timed sprite class -//================================================================================== -class DECLSPEC sge_sprite : public sge_ssprite -{ -protected: - // Pixels/ms - double xppms, yppms; - - // Frames/ms - double fpms; - - // The float pos - double xpos, ypos, fpos; - - // Ticks since last pos update - Uint32 tlast; - - virtual bool check_border() override; - -public: - // Constructor - sge_sprite(SDL_Surface* screen, SDL_Surface* img, Sint16 x = 0, Sint16 y = 0) : sge_ssprite(screen, img, x, y) - { - xppms = yppms = fpms = 0; - tlast = 0; - xpos = x; - ypos = y; - fpos = 0; - } - - sge_sprite(SDL_Surface* screen, SDL_Surface* img, sge_cdata* cdata, Sint16 x = 0, Sint16 y = 0) - : sge_ssprite(screen, img, cdata, x, y) - { - xppms = yppms = fpms = 0; - tlast = 0; - xpos = x; - ypos = y; - fpos = 0; - } - - // Change the speeds - void set_pps(Sint16 x, Sint16 y) - { - xppms = x / 1000.0; - yppms = y / 1000.0; - } - void set_xpps(Sint16 x) { xppms = x / 1000.0; } - void set_ypps(Sint16 y) { yppms = y / 1000.0; } - void set_fps(Sint16 f) { fpms = f / 1000.0; } - - // Get the speeds - Sint16 get_xpps() const { return Sint16(xppms * 1000); } - Sint16 get_ypps() const { return Sint16(yppms * 1000); } - Sint16 get_fps() const { return Sint16(fpms * 1000); } - - // Update position and frame - // Returns true if something changed - bool update(Uint32 ticks); - bool update() override { return update(SDL_GetTicks()); } - - // Correct move members for this class - void move_to(Sint16 x, Sint16 y) override - { - sge_surface::move_to(x, y); - xpos = current_pos.x; - ypos = current_pos.y; - } - void move(Sint16 x_step, Sint16 y_step) override - { - sge_surface::move(x_step, y_step); - xpos = current_pos.x; - ypos = current_pos.y; - } - - // Freeze time until next update - void pause() { tlast = 0; } -}; - -# ifdef _MSC_VER -# pragma warning(pop) -# endif - -#endif /* _SGE_NO_CLASSES */ diff --git a/SGE/include/SGE/sge_surface.h b/SGE/include/SGE/sge_surface.h deleted file mode 100644 index 0a06354..0000000 --- a/SGE/include/SGE/sge_surface.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later -/* - * SDL Graphics Extension - * Pixel, surface and color functions (header) - * - * Started 990815 (split from sge_draw 010611) - */ - -#pragma once - -#include "sge_internal.h" - -/* - * Obsolete function names - */ -#define sge_copy_sblock8 sge_write_block8 -#define sge_copy_sblock16 sge_write_block16 -#define sge_copy_sblock32 sge_write_block32 -#define sge_get_sblock8 sge_read_block8 -#define sge_get_sblock16 sge_read_block16 -#define sge_get_sblock32 sge_read_block32 - -#ifdef _SGE_C -extern "C" -{ -#endif - DECLSPEC void sge_Lock_OFF(); - DECLSPEC void sge_Lock_ON(); - DECLSPEC Uint8 sge_getLock(); - DECLSPEC SDL_Surface* sge_CreateAlphaSurface(Uint32 flags, int width, int height); - DECLSPEC Uint32 sge_MapAlpha(Uint8 R, Uint8 G, Uint8 B, Uint8 A); - - DECLSPEC void _PutPixel(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color); - DECLSPEC void _PutPixel8(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color); - DECLSPEC void _PutPixel16(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color); - DECLSPEC void _PutPixel24(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color); - DECLSPEC void _PutPixel32(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color); - DECLSPEC void _PutPixelX(SDL_Surface* dest, Sint16 x, Sint16 y, Uint32 color); - - DECLSPEC Sint32 sge_CalcYPitch(SDL_Surface* dest, Sint16 y); - DECLSPEC void sge_pPutPixel(SDL_Surface* surface, Sint16 x, Sint32 ypitch, Uint32 color); - - DECLSPEC void sge_PutPixel(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color); - DECLSPEC Uint32 sge_GetPixel(SDL_Surface* surface, Sint16 x, Sint16 y); - - DECLSPEC void _PutPixelAlpha(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha); - DECLSPEC void sge_PutPixelAlpha(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha); - - DECLSPEC void sge_write_block8(SDL_Surface* Surface, Uint8* block, Sint16 y); - DECLSPEC void sge_write_block16(SDL_Surface* Surface, Uint16* block, Sint16 y); - DECLSPEC void sge_write_block32(SDL_Surface* Surface, Uint32* block, Sint16 y); - DECLSPEC void sge_read_block8(SDL_Surface* Surface, Uint8* block, Sint16 y); - DECLSPEC void sge_read_block16(SDL_Surface* Surface, Uint16* block, Sint16 y); - DECLSPEC void sge_read_block32(SDL_Surface* Surface, Uint32* block, Sint16 y); - - DECLSPEC void sge_ClearSurface(SDL_Surface* Surface, Uint32 color); - DECLSPEC int sge_BlitTransparent(SDL_Surface* Src, SDL_Surface* Dest, Sint16 SrcX, Sint16 SrcY, Sint16 DestX, - Sint16 DestY, Sint16 W, Sint16 H, Uint32 Clear, Uint8 Alpha); - DECLSPEC int sge_Blit(SDL_Surface* Src, SDL_Surface* Dest, Sint16 SrcX, Sint16 SrcY, Sint16 DestX, Sint16 DestY, - Sint16 W, Sint16 H); - DECLSPEC SDL_Surface* sge_copy_surface(SDL_Surface* src); - - DECLSPEC SDL_Color sge_GetRGB(SDL_Surface* Surface, Uint32 Color); - DECLSPEC SDL_Color sge_FillPaletteEntry(Uint8 R, Uint8 G, Uint8 B); - DECLSPEC void sge_Fader(SDL_Surface* Surface, Uint8 sR, Uint8 sG, Uint8 sB, Uint8 dR, Uint8 dG, Uint8 dB, - Uint32* ctab, int start, int stop); - DECLSPEC void sge_AlphaFader(Uint8 sR, Uint8 sG, Uint8 sB, Uint8 sA, Uint8 dR, Uint8 dG, Uint8 dB, Uint8 dA, - Uint32* ctab, int start, int stop); - DECLSPEC void sge_SetupRainbowPalette(SDL_Surface* Surface, Uint32* ctab, int intensity, int start, int stop); - DECLSPEC void sge_SetupBWPalette(SDL_Surface* Surface, Uint32* ctab, int start, int stop); -#ifdef _SGE_C -} -#endif - -#ifndef sge_C_ONLY -DECLSPEC void _PutPixel(SDL_Surface* surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void sge_PutPixel(SDL_Surface* surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B); -DECLSPEC void _PutPixelAlpha(SDL_Surface* surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha); -DECLSPEC void sge_PutPixelAlpha(SDL_Surface* surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha); -DECLSPEC void sge_ClearSurface(SDL_Surface* Surface, Uint8 R, Uint8 G, Uint8 B); -#endif /* sge_C_ONLY */ diff --git a/SGE/sge_blib.cpp b/SGE/sge_blib.cpp deleted file mode 100644 index 8242e27..0000000 --- a/SGE/sge_blib.cpp +++ /dev/null @@ -1,2437 +0,0 @@ -// Copyright (C) 2000 - 2003 Anders Lindström & Johan E. Thelin -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Triangles of every sort - * - * Started 000428 - */ - -/* - * Written with some help from Johan E. Thelin. - */ - -#include "sge_blib.h" -#include "FixedPoint.h" -#include "sge_primitives.h" -#include "sge_primitives_int.h" -#include "sge_surface.h" -#include -#include - -using FixedPoint = s25edit::FixedPoint; -using UFixedPoint = s25edit::FixedPoint; - -#define SWAP(x, y, temp) \ - (temp) = x; \ - (x) = y; \ - (y) = temp - -/* Globals used for sge_Lock (defined in sge_surface) */ -extern Uint8 _sge_lock; -extern Uint8 _sge_alpha_hack; - -namespace { - -constexpr Uint32 MapRGB(const SDL_PixelFormat& format, Uint8 r, Uint8 g, Uint8 b) -{ - return ((Uint32)r >> format.Rloss) << format.Rshift | ((Uint32)g >> format.Gloss) << format.Gshift - | ((Uint32)b >> format.Bloss) << format.Bshift | format.Amask; -} - -constexpr Uint32 MapRGB(const SDL_PixelFormat& format, FixedPoint R, FixedPoint G, FixedPoint B) -{ - return MapRGB(format, static_cast(R.toUnsigned()), static_cast(G.toUnsigned()), - static_cast(B.toUnsigned())); -} - -constexpr Uint32 MapRGB(Uint8 r, Uint8 g, Uint8 b) -{ - return (Uint32)r << 16 | (Uint32)g << 8 | (Uint32)b; -} - -Uint32 ScaleRGB(Uint32 value, Sint32 factor) -{ - const auto r = (Sint32((value & 0xFF0000) >> 16) * factor) >> 16; - const auto g = (Sint32((value & 0x00FF00) >> 8) * factor) >> 16; - const auto b = (Sint32((value & 0x0000FF)) * factor) >> 16; - const auto r8 = (Uint8)(r > 255 ? 255 : (r < 0 ? 0 : r)); - const auto g8 = (Uint8)(g > 255 ? 255 : (g < 0 ? 0 : g)); - const auto b8 = (Uint8)(b > 255 ? 255 : (b < 0 ? 0 : b)); - return MapRGB(r8, g8, b8); -} -} // namespace -//================================================================================== -// Draws a horisontal line, fading the colors -//================================================================================== -static void _FadedLine(SDL_Surface* dest, Sint16 x1, Sint16 x2, Sint16 y, FixedPoint r1, FixedPoint g1, FixedPoint b1, - FixedPoint r2, FixedPoint g2, FixedPoint b2) -{ - Sint16 x; - FixedPoint t; - - /* Fix coords */ - if(x1 > x2) - { - SWAP(x1, x2, x); - SWAP(r1, r2, t); - SWAP(g1, g2, t); - SWAP(b1, b2, t); - } - - /* We use fixedpoint math */ - auto R = r1; - auto G = g1; - auto B = b1; - - /* Color step value */ - auto rstep = (r2 - r1) / Sint32(x2 - x1 + 1); - auto gstep = (g2 - g1) / Sint32(x2 - x1 + 1); - auto bstep = (b2 - b1) / Sint32(x2 - x1 + 1); - - /* Clipping */ - if(x2 < sge_clip_xmin(dest) || x1 > sge_clip_xmax(dest) || y < sge_clip_ymin(dest) || y > sge_clip_ymax(dest)) - return; - if(x1 < sge_clip_xmin(dest)) - { - /* Update start colors */ - R += (sge_clip_xmin(dest) - x1) * rstep; - G += (sge_clip_xmin(dest) - x1) * gstep; - B += (sge_clip_xmin(dest) - x1) * bstep; - x1 = sge_clip_xmin(dest); - } - if(x2 > sge_clip_xmax(dest)) - x2 = sge_clip_xmax(dest); - - const auto dstFormat = *dest->format; - switch(dstFormat.BytesPerPixel) - { - case 1: - { /* Assuming 8-bpp */ - Uint8* pixel; - Uint8* row = (Uint8*)dest->pixels + y * dest->pitch; - - for(x = x1; x <= x2; x++) - { - pixel = row + x; - - *pixel = MapRGB(*dest->format, R, G, B); - - R += rstep; - G += gstep; - B += bstep; - } - } - break; - - case 2: - { /* Probably 15-bpp or 16-bpp */ - Uint16* pixel; - Uint16* row = (Uint16*)dest->pixels + y * dest->pitch / 2; - - for(x = x1; x <= x2; x++) - { - pixel = row + x; - - *pixel = MapRGB(*dest->format, R, G, B); - - R += rstep; - G += gstep; - B += bstep; - } - } - break; - - case 3: - { /* Slow 24-bpp mode, usually not used */ - Uint8* pixel; - Uint8* row = (Uint8*)dest->pixels + y * dest->pitch; - - Uint8 rshift8 = dstFormat.Rshift / 8; - Uint8 gshift8 = dstFormat.Gshift / 8; - Uint8 bshift8 = dstFormat.Bshift / 8; - - for(x = x1; x <= x2; x++) - { - pixel = row + x * 3; - - *(pixel + rshift8) = R.toUnsigned(); - *(pixel + gshift8) = G.toUnsigned(); - *(pixel + bshift8) = B.toUnsigned(); - - R += rstep; - G += gstep; - B += bstep; - } - } - break; - - case 4: - { /* Probably 32-bpp */ - Uint32* pixel; - Uint32* row = (Uint32*)dest->pixels + y * dest->pitch / 4; - - for(x = x1; x <= x2; x++) - { - pixel = row + x; - - *pixel = MapRGB(*dest->format, R, G, B); - - R += rstep; - G += gstep; - B += bstep; - } - } - break; - } -} - -void sge_FadedLine(SDL_Surface* dest, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r1, Uint8 g1, Uint8 b1, Uint8 r2, Uint8 g2, - Uint8 b2) -{ - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return; - - _FadedLine(dest, x1, x2, y, FixedPoint(r1), FixedPoint(g1), FixedPoint(b1), FixedPoint(r2), FixedPoint(g2), - FixedPoint(b2)); - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); -} - -template -static void _CopyPixelsWithDifferentFormat(SDL_Surface* dest, Sint16 y, Sint16 x1, Sint16 x2, SDL_Surface* source, - FixedPoint srcx, FixedPoint srcy, const SDL_PixelFormat* srcFormat, - FixedPoint xstep, FixedPoint ystep) -{ - switch(dstBytesPerPixel) - { - case 1: - { /* Assuming 8-bpp */ - Uint8* pixel; - Uint8* row = (Uint8*)dest->pixels + y * dest->pitch; - - for(int x = x1; x <= x2; x++) - { - pixel = row + x; - - Uint8 r, g, b; - SDL_GetRGB(sge_GetPixel(source, srcx.toInt(), srcy.toInt()), srcFormat, &r, &g, &b); - *pixel = SDL_MapRGB(dest->format, r, g, b); - - srcx += xstep; - srcy += ystep; - } - } - break; - - case 2: - { /* Probably 15-bpp or 16-bpp */ - Uint16* pixel; - Uint16* row = (Uint16*)dest->pixels + y * dest->pitch / sizeof(Uint16); - - for(int x = x1; x <= x2; x++) - { - pixel = row + x; - - Uint8 r, g, b; - SDL_GetRGB(sge_GetPixel(source, srcx.toInt(), srcy.toInt()), srcFormat, &r, &g, &b); - *pixel = MapRGB(*dest->format, r, g, b); - - srcx += xstep; - srcy += ystep; - } - } - break; - - case 3: - { /* Slow 24-bpp mode, usually not used */ - Uint8* pixel; - Uint8* row = (Uint8*)dest->pixels + y * dest->pitch; - - Uint8 rshift8 = dest->format->Rshift / 8; - Uint8 gshift8 = dest->format->Gshift / 8; - Uint8 bshift8 = dest->format->Bshift / 8; - - for(int x = x1; x <= x2; x++) - { - pixel = row + x * 3; - - Uint8 r, g, b; - SDL_GetRGB(sge_GetPixel(source, srcx.toInt(), srcy.toInt()), srcFormat, &r, &g, &b); - - *(pixel + rshift8) = r; - *(pixel + gshift8) = g; - *(pixel + bshift8) = b; - - srcx += xstep; - srcy += ystep; - } - } - break; - - case 4: - { /* Probably 32-bpp */ - Uint32* pixel; - Uint32* row = (Uint32*)dest->pixels + y * dest->pitch / sizeof(Uint32); - - for(int x = x1; x <= x2; x++) - { - pixel = row + x; - - Uint8 r, g, b; - SDL_GetRGB(sge_GetPixel(source, srcx.toInt(), srcy.toInt()), srcFormat, &r, &g, &b); - *pixel = MapRGB(r, g, b); - - srcx += xstep; - srcy += ystep; - } - } - break; - } -} - -static Uint32 _GetColorKey(SDL_Surface* surf) -{ - Uint32 colorkey; - if(SDL_GetColorKey(surf, &colorkey) != 0) - throw std::invalid_argument("No colorkey set"); - return colorkey; -} - -//================================================================================== -// Draws a horisontal, textured line -//================================================================================== -template -static void _TexturedLine(SDL_Surface* dest, Sint16 x1, Sint16 x2, Sint16 y, SDL_Surface* source, FixedPoint sx1, - FixedPoint sy1, FixedPoint sx2, FixedPoint sy2) -{ - Sint16 _tmp1; - FixedPoint _tmp2; - - /* Fix coords */ - if(x1 > x2) - { - SWAP(x1, x2, _tmp1); - SWAP(sx1, sx2, _tmp2); - SWAP(sy1, sy2, _tmp2); - } - if(x2 < sge_clip_xmin(dest)) - return; - - /* Fixed point texture starting coords */ - auto srcx = sx1; - auto srcy = sy1; - - /* Texture coords stepping value */ - FixedPoint xstep = (sx2 - sx1) / Sint32(x2 - x1 + 1); - FixedPoint ystep = (sy2 - sy1) / Sint32(x2 - x1 + 1); - - /* Clipping */ - assert(y >= sge_clip_ymin(dest) && y <= sge_clip_ymax(dest)); - assert(x1 <= sge_clip_xmax(dest) && x2 <= sge_clip_xmax(dest)); - - if(x1 < sge_clip_xmin(dest)) - { - /* Fix texture starting coord */ - srcx += (sge_clip_xmin(dest) - x1) * xstep; - srcy += (sge_clip_xmin(dest) - x1) * ystep; - x1 = sge_clip_xmin(dest); - } - - if(dstBytesPerPixel == srcBytesPerPixel) - { - /* Fast mode. Just copy the pixel */ - - switch(dstBytesPerPixel) - { - case 1: - { /* Assuming 8-bpp */ - const Uint32 colorkey = _GetColorKey(source); - Uint8* row = (Uint8*)dest->pixels + y * dest->pitch; - - for(int x = x1; x <= x2; x++) - { - auto* pixel = row + x; - - const auto pixel_value = *((Uint8*)source->pixels + srcy.toInt() * source->pitch + srcx.toInt()); - - if(pixel_value != colorkey) - *pixel = pixel_value; - - srcx += xstep; - srcy += ystep; - } - } - break; - - case 2: - { /* Probably 15-bpp or 16-bpp */ - Uint16* row = (Uint16*)dest->pixels + y * dest->pitch / 2; - - Uint16 pitch = source->pitch / 2; - - for(int x = x1; x <= x2; x++) - { - auto* pixel = row + x; - - *pixel = *((Uint16*)source->pixels + srcy.toInt() * pitch + srcx.toInt()); - - srcx += xstep; - srcy += ystep; - } - } - break; - - case 3: - { /* Slow 24-bpp mode, usually not used */ - const auto dstFormat = *dest->format; - Uint8* row = (Uint8*)dest->pixels + y * dest->pitch; - - Uint8 rshift8 = dstFormat.Rshift / 8; - Uint8 gshift8 = dstFormat.Gshift / 8; - Uint8 bshift8 = dstFormat.Bshift / 8; - - for(int x = x1; x <= x2; x++) - { - auto* pixel = row + x * 3; - auto* srcpixel = (Uint8*)source->pixels + srcy.toInt() * source->pitch + srcx.toInt() * 3; - - *(pixel + rshift8) = *(srcpixel + rshift8); - *(pixel + gshift8) = *(srcpixel + gshift8); - *(pixel + bshift8) = *(srcpixel + bshift8); - - srcx += xstep; - srcy += ystep; - } - } - break; - - case 4: - { /* Probably 32-bpp */ - Uint32* pixel = (Uint32*)dest->pixels + y * dest->pitch / sizeof(Uint32) + x1; - - const Uint16 pitch = source->pitch / sizeof(Uint32); - const Uint32 colorkey = _GetColorKey(source); - - for(int x = x1; x <= x2; x++, ++pixel) - { - const auto pixel_value = *((Uint32*)source->pixels + srcy.toInt() * pitch + srcx.toInt()); - if(pixel_value != colorkey) - *pixel = pixel_value; - - srcx += xstep; - srcy += ystep; - } - } - break; - } - } else - { - /* Slow mode. We must translate every pixel color! */ - _CopyPixelsWithDifferentFormat(dest, y, x1, x2, source, srcx, srcy, source->format, xstep, - ystep); - } -} - -static auto makeIsColorKey() -{ - return [](const Uint32) { return false; }; -} - -static auto makeIsColorKey(Uint32 colorKey) -{ - return [colorKey](const Uint32 color) { return color == colorKey; }; -} - -static auto makeIsColorKey(const Uint32 keys[], int keycount) -{ - return [keys, keycount](const Uint32 color) { - for(int i = 0; i < keycount; i++) - { - if(keys[i] == color) - return true; - } - return false; - }; -} - -//================================================================================== -// Draws a horisontal, gouraud shaded and textured line -//================================================================================== -template -static void _FadedTexturedLine(SDL_Surface* dest, Sint16 x1, Sint16 x2, Sint16 y, SDL_Surface* source, FixedPoint sx1, - FixedPoint sy1, FixedPoint sx2, FixedPoint sy2, Sint32 i1, Sint32 i2, - T_IsColorKey isColorKey) -{ - /* Fix coords */ - if(x1 > x2) - { - Sint16 _tmp1; - FixedPoint _tmp2; - Sint32 _tmp3; - SWAP(x1, x2, _tmp1); - SWAP(sx1, sx2, _tmp2); - SWAP(sy1, sy2, _tmp2); - SWAP(i1, i2, _tmp3); - } - if(x2 < sge_clip_xmin(dest)) - return; - - /* We use fixedpoint math */ - Sint32 I = i1; - - /* Color step value */ - Sint32 istep = (i2 - i1) / Sint32(x2 - x1 + 1); - - /* Texture coords stepping value */ - auto xstep = (sx2 - sx1) / Sint32(x2 - x1 + 1); - auto ystep = (sy2 - sy1) / Sint32(x2 - x1 + 1); - - /* Clipping */ - assert(y >= sge_clip_ymin(dest) && y <= sge_clip_ymax(dest)); - assert(x1 <= sge_clip_xmax(dest) && x2 <= sge_clip_xmax(dest)); - - if(x1 < sge_clip_xmin(dest)) - { - /* Update start colors */ - I += (sge_clip_xmin(dest) - x1) * istep; - /* Fix texture starting coord */ - sx1 += (sge_clip_xmin(dest) - x1) * xstep; - sy1 += (sge_clip_xmin(dest) - x1) * ystep; - x1 = sge_clip_xmin(dest); - } - - assert(dest->format->BytesPerPixel == source->format->BytesPerPixel); - assert(dest->format->BytesPerPixel == 4); - - Uint32* pixel = (Uint32*)dest->pixels + y * dest->pitch / sizeof(Uint32) + x1; - const Uint16 pitch = source->pitch / sizeof(Uint32); - - for(int x = x1; x <= x2; x++, ++pixel) - { - const Uint32 pixel_value = *((Uint32*)source->pixels + sy1.toInt() * pitch + sx1.toInt()); - if(!isColorKey(pixel_value)) - { - *pixel = ScaleRGB(pixel_value, I); - } - - I += istep; - - sx1 += xstep; - sy1 += ystep; - } -} - -//================================================================================== -// Draws a horisontal, textured line with precalculated gouraud shading -//================================================================================== -template -static void _FadedTexturedLine(SDL_Surface* dest, Sint16 x1, Sint16 x2, Sint16 y, SDL_Surface* source, FixedPoint sx1, - FixedPoint sy1, FixedPoint sx2, FixedPoint sy2, Uint16 i1, Uint16 i2, - T_IsColorKey isColorKey, Uint8 PreCalcPalettes[][256]) -{ - /* Fix coords */ - if(x1 > x2) - { - Sint16 _tmp1; - FixedPoint _tmp2; - Uint16 _tmp3; - SWAP(x1, x2, _tmp1); - SWAP(sx1, sx2, _tmp2); - SWAP(sy1, sy2, _tmp2); - SWAP(i1, i2, _tmp3); - } - if(x2 < sge_clip_xmin(dest)) - return; - - /* We use fixedpoint math */ - Uint16 I = i1; - - /* Color step value */ - Sint16 istep = (i2 - i1) / (x2 - x1 + 1); - - /* Texture coords stepping value */ - auto xstep = (sx2 - sx1) / Sint32(x2 - x1 + 1); - auto ystep = (sy2 - sy1) / Sint32(x2 - x1 + 1); - - /* Clipping */ - assert(y >= sge_clip_ymin(dest) && y <= sge_clip_ymax(dest)); - assert(x1 <= sge_clip_xmax(dest) && x2 <= sge_clip_xmax(dest)); - - if(x1 < sge_clip_xmin(dest)) - { - /* Update start colors */ - I += (sge_clip_xmin(dest) - x1) * istep; - /* Fix texture starting coord */ - sx1 += (sge_clip_xmin(dest) - x1) * xstep; - sy1 += (sge_clip_xmin(dest) - x1) * ystep; - x1 = sge_clip_xmin(dest); - } - - assert(dest->format->BytesPerPixel == source->format->BytesPerPixel); - assert(dest->format->BytesPerPixel == 1); - - Uint8* pixel = (Uint8*)dest->pixels + y * dest->pitch + x1; - const Uint16 pitch = source->pitch; - - for(int x = x1; x <= x2; x++, ++pixel) - { - const auto pixel_value = *((Uint8*)source->pixels + sy1.toInt() * pitch + sx1.toInt()); - - if(!isColorKey(pixel_value)) - { - *pixel = PreCalcPalettes[(Uint8)(I >> 8)][pixel_value]; - } - - sx1 += xstep; - sy1 += ystep; - - I += istep; - } -} - -void sge_FadedTexturedLine(SDL_Surface* dest, Sint16 x1, Sint16 x2, Sint16 y, SDL_Surface* source, Sint16 sx1, - Sint16 sy1, Sint16 sx2, Sint16 sy2, Sint32 i1, Sint32 i2) -{ - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return; - if(_sge_lock && SDL_MUSTLOCK(source)) - if(SDL_LockSurface(source) < 0) - return; - - { - const auto maxX = sge_clip_xmax(dest); - x1 = std::min(x1, maxX); - x2 = std::min(x2, maxX); - } - - _FadedTexturedLine(dest, x1, x2, y, source, FixedPoint(sx1), FixedPoint(sy1), FixedPoint(sx2), FixedPoint(sy2), i1, - i2, makeIsColorKey()); - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); - if(_sge_lock && SDL_MUSTLOCK(source)) - SDL_UnlockSurface(source); -} - -//================================================================================== -// Draws a trigon -//================================================================================== -void sge_Trigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) -{ - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return; - - _Line(dest, x1, y1, x2, y2, color); - _Line(dest, x1, y1, x3, y3, color); - _Line(dest, x3, y3, x2, y2, color); - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); -} - -void sge_Trigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 R, Uint8 G, - Uint8 B) -{ - sge_Trigon(dest, x1, y1, x2, y2, x3, y3, SDL_MapRGB(dest->format, R, G, B)); -} - -//================================================================================== -// Draws a trigon (alpha) -//================================================================================== -void sge_TrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color, - Uint8 alpha) -{ - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return; - - _LineAlpha(dest, x1, y1, x2, y2, color, alpha); - _LineAlpha(dest, x1, y1, x3, y3, color, alpha); - _LineAlpha(dest, x3, y3, x2, y2, color, alpha); - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); -} - -void sge_TrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 R, - Uint8 G, Uint8 B, Uint8 alpha) -{ - sge_TrigonAlpha(dest, x1, y1, x2, y2, x3, y3, SDL_MapRGB(dest->format, R, G, B), alpha); -} - -//================================================================================== -// Draws an AA trigon (alpha) -//================================================================================== -void sge_AATrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint32 color, Uint8 alpha) -{ - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return; - - _AALineAlpha(dest, x1, y1, x2, y2, color, alpha); - _AALineAlpha(dest, x1, y1, x3, y3, color, alpha); - _AALineAlpha(dest, x3, y3, x2, y2, color, alpha); - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); -} - -void sge_AATrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 R, - Uint8 G, Uint8 B, Uint8 alpha) -{ - sge_AATrigonAlpha(dest, x1, y1, x2, y2, x3, y3, SDL_MapRGB(dest->format, R, G, B), alpha); -} - -void sge_AATrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) -{ - sge_AATrigonAlpha(dest, x1, y1, x2, y2, x3, y3, color, 255); -} - -void sge_AATrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 R, Uint8 G, - Uint8 B) -{ - sge_AATrigonAlpha(dest, x1, y1, x2, y2, x3, y3, SDL_MapRGB(dest->format, R, G, B), 255); -} - -//================================================================================== -// Draws a filled trigon -//================================================================================== -void sge_FilledTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) -{ - Sint16 y; - - if(y1 == y3) - return; - - /* Sort coords */ - if(y1 > y2) - { - SWAP(y1, y2, y); - SWAP(x1, x2, y); - } - if(y2 > y3) - { - SWAP(y2, y3, y); - SWAP(x2, x3, y); - } - if(y1 > y2) - { - SWAP(y1, y2, y); - SWAP(x1, x2, y); - } - - /* - * How do we calculate the starting and ending x coordinate of the horizontal line - * on each y coordinate? We can do this by using a standard line algorithm but - * instead of plotting pixels, use the x coordinates as start and stop - * coordinates for the horizontal line. - * So we will simply trace the outlining of the triangle; this will require 3 lines. - * Line 1 is the line between (x1,y1) and (x2,y2) - * Line 2 is the line between (x1,y1) and (x3,y3) - * Line 3 is the line between (x2,y2) and (x3,y3) - * - * We can divide the triangle into 2 halfs. The upper half will be outlined by line - * 1 and 2. The lower half will be outlined by line line 2 and 3. - */ - - /* Starting coords for the three lines */ - auto xa = FixedPoint(x1); - auto xb = xa; - auto xc = FixedPoint(x2); - - /* Lines step values */ - auto m2 = FixedPoint(x3 - x1) / Sint32(y3 - y1); - - /* Upper half of the triangle */ - if(y1 == y2) - _HLine(dest, x1, x2, y1, color); - else - { - auto m1 = (xc - xa) / Sint32(y2 - y1); - - for(y = y1; y <= y2; y++) - { - _HLine(dest, xa.toInt(), xb.toInt(), y, color); - - xa += m1; - xb += m2; - } - } - - /* Lower half of the triangle */ - if(y2 == y3) - _HLine(dest, x2, x3, y2, color); - else - { - auto m3 = FixedPoint(x3 - x2) / Sint32(y3 - y2); - - for(y = y2 + 1; y <= y3; y++) - { - _HLine(dest, xb.toInt(), xc.toInt(), y, color); - - xb += m2; - xc += m3; - } - } -} - -void sge_FilledTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 R, - Uint8 G, Uint8 B) -{ - sge_FilledTrigon(dest, x1, y1, x2, y2, x3, y3, SDL_MapRGB(dest->format, R, G, B)); -} - -//================================================================================== -// Draws a filled trigon (alpha) -//================================================================================== -void sge_FilledTrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Uint32 color, Uint8 alpha) -{ - Sint16 y; - - if(y1 == y3) - return; - - /* Sort coords */ - if(y1 > y2) - { - SWAP(y1, y2, y); - SWAP(x1, x2, y); - } - if(y2 > y3) - { - SWAP(y2, y3, y); - SWAP(x2, x3, y); - } - if(y1 > y2) - { - SWAP(y1, y2, y); - SWAP(x1, x2, y); - } - - auto xa = FixedPoint(x1); - auto xb = xa; - auto xc = FixedPoint(x2); - - auto m2 = FixedPoint(x3 - x1) / Sint32(y3 - y1); - - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return; - - /* Upper half of the triangle */ - if(y1 == y2) - _HLineAlpha(dest, x1, x2, y1, color, alpha); - else - { - auto m1 = (xc - xa) / Sint32(y2 - y1); - - for(y = y1; y <= y2; y++) - { - _HLineAlpha(dest, xa.toInt(), xb.toInt(), y, color, alpha); - - xa += m1; - xb += m2; - } - } - - /* Lower half of the triangle */ - if(y2 == y3) - _HLineAlpha(dest, x2, x3, y2, color, alpha); - else - { - auto m3 = FixedPoint(x3 - x2) / Sint32(y3 - y2); - - for(y = y2 + 1; y <= y3; y++) - { - _HLineAlpha(dest, xb.toInt(), xc.toInt(), y, color, alpha); - - xb += m2; - xc += m3; - } - } - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); -} - -void sge_FilledTrigonAlpha(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint8 R, - Uint8 G, Uint8 B, Uint8 alpha) -{ - sge_FilledTrigonAlpha(dest, x1, y1, x2, y2, x3, y3, SDL_MapRGB(dest->format, R, G, B), alpha); -} - -//================================================================================== -// Draws a gourand shaded trigon -//================================================================================== -void sge_FadedTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 c1, - Uint32 c2, Uint32 c3) -{ - Sint16 y; - - if(y1 == y3) - return; - - Uint8 c = 0; - SDL_Color col1; - SDL_Color col2; - SDL_Color col3; - - col1 = sge_GetRGB(dest, c1); - col2 = sge_GetRGB(dest, c2); - col3 = sge_GetRGB(dest, c3); - - /* Sort coords */ - if(y1 > y2) - { - SWAP(y1, y2, y); - SWAP(x1, x2, y); - SWAP(col1.r, col2.r, c); - SWAP(col1.g, col2.g, c); - SWAP(col1.b, col2.b, c); - } - if(y2 > y3) - { - SWAP(y2, y3, y); - SWAP(x2, x3, y); - SWAP(col2.r, col3.r, c); - SWAP(col2.g, col3.g, c); - SWAP(col2.b, col3.b, c); - } - if(y1 > y2) - { - SWAP(y1, y2, y); - SWAP(x1, x2, y); - SWAP(col1.r, col2.r, c); - SWAP(col1.g, col2.g, c); - SWAP(col1.b, col2.b, c); - } - - /* - * We trace three lines exactly like in sge_FilledTrigon(), but here we - * must also keep track of the colors. We simply calculate how the color - * will change along the three lines. - */ - - /* Starting coords for the three lines */ - auto xa = FixedPoint(x1); - auto xb = xa; - auto xc = FixedPoint(x2); - - /* Starting colors (rgb) for the three lines */ - auto r1 = FixedPoint(col1.r); - auto r2 = r1; - auto r3 = FixedPoint(col2.r); - - auto g1 = FixedPoint(col1.g); - auto g2 = g1; - auto g3 = FixedPoint(col2.g); - - auto b1 = FixedPoint(col1.b); - auto b2 = b1; - auto b3 = FixedPoint(col2.b); - - /* Lines step values */ - auto m2 = FixedPoint(x3 - x1) / Sint32(y3 - y1); - - /* Colors step values */ - auto rstep2 = FixedPoint(col3.r - col1.r) / Sint32(y3 - y1); - - auto gstep2 = FixedPoint(col3.g - col1.g) / Sint32(y3 - y1); - - auto bstep2 = FixedPoint(col3.b - col1.b) / Sint32(y3 - y1); - - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return; - - /* Upper half of the triangle */ - if(y1 == y2) - _FadedLine(dest, x1, x2, y1, r1, g1, b1, r3, g3, b3); - else - { - auto m1 = (xc - xa) / Sint32(y2 - y1); - - auto rstep1 = (r3 - r1) / Sint32(y2 - y1); - auto gstep1 = (g3 - g1) / Sint32(y2 - y1); - auto bstep1 = (b3 - b1) / Sint32(y2 - y1); - - for(y = y1; y <= y2; y++) - { - _FadedLine(dest, xa.toInt(), xb.toInt(), y, r1, g1, b1, r2, g2, b2); - - xa += m1; - xb += m2; - - r1 += rstep1; - g1 += gstep1; - b1 += bstep1; - - r2 += rstep2; - g2 += gstep2; - b2 += bstep2; - } - } - - /* Lower half of the triangle */ - if(y2 == y3) - _FadedLine(dest, x2, x3, y2, r3, g3, b3, FixedPoint(col3.r), FixedPoint(col3.g), FixedPoint(col3.b)); - else - { - auto m3 = FixedPoint(x3 - x2) / Sint32(y3 - y2); - - auto rstep3 = FixedPoint(col3.r - col2.r) / Sint32(y3 - y2); - auto gstep3 = FixedPoint(col3.g - col2.g) / Sint32(y3 - y2); - auto bstep3 = FixedPoint(col3.b - col2.b) / Sint32(y3 - y2); - - for(y = y2 + 1; y <= y3; y++) - { - _FadedLine(dest, xb.toInt(), xc.toInt(), y, r2, g2, b2, r3, g3, b3); - - xb += m2; - xc += m3; - - r2 += rstep2; - g2 += gstep2; - b2 += bstep2; - - r3 += rstep3; - g3 += gstep3; - b3 += bstep3; - } - } - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); -} - -//================================================================================== -// Draws a texured trigon (fast) -//================================================================================== -template -static void _TexturedTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, Sint16 sy2, Sint16 sx3, Sint16 sy3) -{ - Sint16 y; - - if(y1 == y3) - return; - - /* Sort coords */ - if(y1 > y2) - { - SWAP(y1, y2, y); - SWAP(x1, x2, y); - SWAP(sx1, sx2, y); - SWAP(sy1, sy2, y); - } - if(y2 > y3) - { - SWAP(y2, y3, y); - SWAP(x2, x3, y); - SWAP(sx2, sx3, y); - SWAP(sy2, sy3, y); - } - if(y1 > y2) - { - SWAP(y1, y2, y); - SWAP(x1, x2, y); - SWAP(sx1, sx2, y); - SWAP(sy1, sy2, y); - } - { - const auto maxX = sge_clip_xmax(dest); - x1 = std::min(x1, maxX); - x2 = std::min(x2, maxX); - x3 = std::min(x3, maxX); - } - const auto minY = sge_clip_ymin(dest); - const auto maxY = sge_clip_ymax(dest); - - /* - * Again we do the same thing as in sge_FilledTrigon(). But here we must keep track of how the - * texture coords change along the lines. - */ - - /* Starting coords for the three lines */ - auto xa = FixedPoint(x1); - auto xb = xa; - auto xc = FixedPoint(x2); - - /* Lines step values */ - auto m2 = FixedPoint(x3 - x1) / Sint32(y3 - y1); - - /* Starting texture coords for the three lines */ - auto srcx1 = FixedPoint(sx1); - auto srcx1_2 = srcx1; - auto srcx2 = FixedPoint(sx2); - - auto srcy1 = FixedPoint(sy1); - auto srcy1_2 = srcy1; - auto srcy2 = FixedPoint(sy2); - - /* Texture coords stepping value */ - auto xstep2 = FixedPoint(sx3 - sx1) / Sint32(y3 - y1); - auto ystep2 = FixedPoint(sy3 - sy1) / Sint32(y3 - y1); - - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return; - if(_sge_lock && SDL_MUSTLOCK(source)) - if(SDL_LockSurface(source) < 0) - return; - - /* Upper half of the triangle */ - if(y1 == y2) - { - if(y1 >= minY && y1 <= maxY) - _TexturedLine(dest, x1, x2, y1, source, srcx1, srcy1, srcx2, srcy2); - } else - { - auto m1 = (xc - xa) / Sint32(y2 - y1); - - auto xstep1 = (srcx2 - srcx1) / Sint32(y2 - y1); - auto ystep1 = (srcy2 - srcy1) / Sint32(y2 - y1); - - for(y = y1; y <= std::min(y2, maxY); y++) - { - if(y >= minY) - _TexturedLine(dest, xa.toInt(), xb.toInt(), y, source, srcx1, srcy1, - srcx1_2, srcy1_2); - - xa += m1; - xb += m2; - - srcx1 += xstep1; - srcx1_2 += xstep2; - srcy1 += ystep1; - srcy1_2 += ystep2; - } - } - - /* Lower half of the triangle */ - if(y2 == y3) - { - if(y2 >= minY && y2 <= maxY) - _TexturedLine(dest, x2, x3, y2, source, srcx2, srcy2, FixedPoint(sx3), - FixedPoint(sy3)); - } else - { - auto m3 = FixedPoint(x3 - x2) / Sint32(y3 - y2); - - auto xstep3 = FixedPoint(sx3 - sx2) / Sint32(y3 - y2); - auto ystep3 = FixedPoint(sy3 - sy2) / Sint32(y3 - y2); - - for(y = y2 + 1; y <= std::min(y3, maxY); y++) - { - if(y >= minY) - _TexturedLine(dest, xb.toInt(), xc.toInt(), y, source, srcx1_2, - srcy1_2, srcx2, srcy2); - - xb += m2; - xc += m3; - - srcx1_2 += xstep2; - srcx2 += xstep3; - srcy1_2 += ystep2; - srcy2 += ystep3; - } - } - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); - if(_sge_lock && SDL_MUSTLOCK(source)) - SDL_UnlockSurface(source); -} - -void sge_TexturedTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, Sint16 sy2, Sint16 sx3, Sint16 sy3) -{ - switch(dest->format->BytesPerPixel) - { - case 1: - if(source->format->BytesPerPixel == 1) - return _TexturedTrigon<1, 1>(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3); - if(source->format->BytesPerPixel == 4) - return _TexturedTrigon<4, 1>(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3); - break; - case 4: - if(source->format->BytesPerPixel == 1) - return _TexturedTrigon<1, 4>(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3); - if(source->format->BytesPerPixel == 4) - return _TexturedTrigon<4, 4>(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3); - break; - } - assert(false); -} - -//================================================================================== -// Draws a gouraud shaded and texured trigon (fast) (respecting colorkeys) -//================================================================================== -// Aditional args: isColorKey, (opt) Uint8 PreCalcPalettes[][256] -template -static void _FadedTexturedTrigonColorKeys(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, - Sint16 y3, SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, - Sint16 sy2, Sint16 sx3, Sint16 sy3, Sint32 I1, Sint32 I2, Sint32 I3, - T_Args... args) -{ - if(y1 == y3) - return; - - /* Sort coords */ - if(y1 > y2) - { - Sint32 i = 0; - Sint16 _tmp; - SWAP(y1, y2, _tmp); - SWAP(x1, x2, _tmp); - SWAP(sx1, sx2, _tmp); - SWAP(sy1, sy2, _tmp); - SWAP(I1, I2, i); - } - if(y2 > y3) - { - Sint32 i = 0; - Sint16 _tmp; - SWAP(y2, y3, _tmp); - SWAP(x2, x3, _tmp); - SWAP(sx2, sx3, _tmp); - SWAP(sy2, sy3, _tmp); - SWAP(I2, I3, i); - } - if(y1 > y2) - { - Sint32 i = 0; - Sint16 _tmp; - SWAP(y1, y2, _tmp); - SWAP(x1, x2, _tmp); - SWAP(sx1, sx2, _tmp); - SWAP(sy1, sy2, _tmp); - SWAP(I1, I2, i); - } - { - const auto maxX = sge_clip_xmax(dest); - x1 = std::min(x1, maxX); - x2 = std::min(x2, maxX); - x3 = std::min(x3, maxX); - } - const auto minY = sge_clip_ymin(dest); - const auto maxY = sge_clip_ymax(dest); - - /* - * Again we do the same thing as in sge_FilledTrigon(). But here we must keep track of how the - * texture coords change along the lines. - */ - - /* Starting coords for the three lines */ - auto xa = FixedPoint(x1); - auto xb = xa; - auto xc = FixedPoint(x2); - - /* Starting colors (rgb) for the three lines */ - Sint32 i1 = I1; - Sint32 i2 = i1; - Sint32 i3 = I2; - - /* Lines step values */ - auto m2 = FixedPoint(x3 - x1) / Sint32(y3 - y1); - - /* Colors step values */ - Sint32 istep2 = (I3 - i1) / Sint32(y3 - y1); - - /* Starting texture coords for the three lines */ - auto srcx1 = FixedPoint(sx1); - auto srcx1_2 = srcx1; - auto srcx2 = FixedPoint(sx2); - auto srcx3 = FixedPoint(sx3); - - auto srcy1 = FixedPoint(sy1); - auto srcy1_2 = srcy1; - auto srcy2 = FixedPoint(sy2); - auto srcy3 = FixedPoint(sy3); - - /* Texture coords stepping value */ - auto xstep2 = (srcx3 - srcx1) / Sint32(y3 - y1); - - auto ystep2 = (srcy3 - srcy1) / Sint32(y3 - y1); - - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return; - if(_sge_lock && SDL_MUSTLOCK(source)) - if(SDL_LockSurface(source) < 0) - return; - - /* Upper half of the triangle */ - if(y1 == y2) - { - if(y1 >= minY && y1 <= maxY) - _FadedTexturedLine(dest, x1, x2, y1, source, srcx1, srcy1, srcx2, srcy2, I1, I2, args...); - } else - { - auto m1 = (xc - xa) / Sint32(y2 - y1); - - auto istep1 = (I2 - I1) / Sint32(y2 - y1); - - auto xstep1 = (srcx2 - srcx1) / Sint32(y2 - y1); - auto ystep1 = (srcy2 - srcy1) / Sint32(y2 - y1); - - for(int y = y1; y <= std::min(y2, maxY); y++) - { - if(y >= minY) - _FadedTexturedLine(dest, xa.toInt(), xb.toInt(), y, source, srcx1, srcy1, srcx1_2, srcy1_2, i1, i2, - args...); - - xa += m1; - xb += m2; - - i1 += istep1; - - i2 += istep2; - - srcx1 += xstep1; - srcx1_2 += xstep2; - srcy1 += ystep1; - srcy1_2 += ystep2; - } - } - - /* Lower half of the triangle */ - if(y2 == y3) - { - if(y2 >= minY && y2 <= maxY) - _FadedTexturedLine(dest, x2, x3, y2, source, srcx2, srcy2, srcx3, srcy3, I2, I3, args...); - } else - { - auto m3 = FixedPoint(x3 - x2) / Sint32(y3 - y2); - - Sint32 istep3 = (I3 - I2) / Sint32(y3 - y2); - - auto xstep3 = (srcx3 - srcx2) / Sint32(y3 - y2); - auto ystep3 = (srcy3 - srcy2) / Sint32(y3 - y2); - - for(int y = y2 + 1; y <= std::min(y3, maxY); y++) - { - if(y >= minY) - _FadedTexturedLine(dest, xb.toInt(), xc.toInt(), y, source, srcx1_2, srcy1_2, srcx2, srcy2, i2, i3, - args...); - - xb += m2; - xc += m3; - - i2 += istep2; - - i3 += istep3; - - srcx1_2 += xstep2; - srcx2 += xstep3; - srcy1_2 += ystep2; - srcy2 += ystep3; - } - } - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); - if(_sge_lock && SDL_MUSTLOCK(source)) - SDL_UnlockSurface(source); -} - -void sge_FadedTexturedTrigonColorKeys(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, - Sint16 y3, SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, Sint16 sy2, - Sint16 sx3, Sint16 sy3, Sint32 I1, Sint32 I2, Sint32 I3, Uint32 keys[], - int keycount) -{ - if(keycount == 0) - _FadedTexturedTrigonColorKeys(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3, I1, I2, I3, - makeIsColorKey()); - else if(keycount == 1) - _FadedTexturedTrigonColorKeys(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3, I1, I2, I3, - makeIsColorKey(keys[0])); - else - _FadedTexturedTrigonColorKeys(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3, I1, I2, I3, - makeIsColorKey(keys, keycount)); -} - -void sge_FadedTexturedTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, Sint16 sy2, Sint16 sx3, - Sint16 sy3, Sint32 I1, Sint32 I2, Sint32 I3) -{ - _FadedTexturedTrigonColorKeys(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3, I1, I2, I3, - makeIsColorKey()); -} - -void sge_PreCalcFadedTexturedTrigonColorKeys(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, - Sint16 y3, SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, - Sint16 sy2, Sint16 sx3, Sint16 sy3, Uint16 I1, Uint16 I2, Uint16 I3, - Uint8 PreCalcPalettes[][256], Uint32 keys[], int keycount) -{ - if(keycount == 0) - _FadedTexturedTrigonColorKeys(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3, I1, I2, I3, - makeIsColorKey(), PreCalcPalettes); - else if(keycount == 1) - _FadedTexturedTrigonColorKeys(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3, I1, I2, I3, - makeIsColorKey(keys[0]), PreCalcPalettes); - else - _FadedTexturedTrigonColorKeys(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3, I1, I2, I3, - makeIsColorKey(keys, keycount), PreCalcPalettes); -} - -void sge_PreCalcFadedTexturedTrigon(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, Sint16 sy2, Sint16 sx3, - Sint16 sy3, Uint16 I1, Uint16 I2, Uint16 I3, Uint8 PreCalcPalettes[][256]) -{ - _FadedTexturedTrigonColorKeys(dest, x1, y1, x2, y2, x3, y3, source, sx1, sy1, sx2, sy2, sx3, sy3, I1, I2, I3, - makeIsColorKey(), PreCalcPalettes); -} - -//================================================================================== -// Draws a texured *RECTANGLE* -//================================================================================== -template -static void _TexturedRect(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Sint16 x4, Sint16 y4, SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, Sint16 sy2, - Sint16 sx3, Sint16 sy3, Sint16 sx4, Sint16 sy4) -{ - Sint16 y; - - if(y1 == y3 || y1 == y4 || y4 == y2) - return; - - /* Sort the coords */ - if(y1 > y2) - { - SWAP(x1, x2, y); - SWAP(y1, y2, y); - SWAP(sx1, sx2, y); - SWAP(sy1, sy2, y); - } - if(y2 > y3) - { - SWAP(x3, x2, y); - SWAP(y3, y2, y); - SWAP(sx3, sx2, y); - SWAP(sy3, sy2, y); - } - if(y1 > y2) - { - SWAP(x1, x2, y); - SWAP(y1, y2, y); - SWAP(sx1, sx2, y); - SWAP(sy1, sy2, y); - } - if(y3 > y4) - { - SWAP(x3, x4, y); - SWAP(y3, y4, y); - SWAP(sx3, sx4, y); - SWAP(sy3, sy4, y); - } - if(y2 > y3) - { - SWAP(x3, x2, y); - SWAP(y3, y2, y); - SWAP(sx3, sx2, y); - SWAP(sy3, sy2, y); - } - if(y1 > y2) - { - SWAP(x1, x2, y); - SWAP(y1, y2, y); - SWAP(sx1, sx2, y); - SWAP(sy1, sy2, y); - } - { - const auto maxX = sge_clip_xmax(dest); - x1 = std::min(x1, maxX); - x2 = std::min(x2, maxX); - x3 = std::min(x3, maxX); - x4 = std::min(x4, maxX); - } - const auto minY = sge_clip_ymin(dest); - const auto maxY = sge_clip_ymax(dest); - - /* - * We do this exactly like sge_TexturedTrigon(), but here we must trace four lines. - */ - - auto xa = FixedPoint(x1); - auto xb = xa; - auto xc = FixedPoint(x2); - auto xd = FixedPoint(x3); - - auto m2 = FixedPoint(x3 - x1) / Sint32(y3 - y1); - auto m3 = FixedPoint(x4 - x2) / Sint32(y4 - y2); - - auto srcx1 = FixedPoint(sx1); - auto srcx1_2 = srcx1; - auto srcx2 = FixedPoint(sx2); - auto srcx3 = FixedPoint(sx3); - - auto srcy1 = FixedPoint(sy1); - auto srcy1_2 = srcy1; - auto srcy2 = FixedPoint(sy2); - auto srcy3 = FixedPoint(sy3); - - auto xstep2 = (srcx3 - srcx1) / Sint32(y3 - y1); - auto xstep3 = FixedPoint(sx4 - sx2) / Sint32(y4 - y2); - - auto ystep2 = (srcy3 - srcy1) / Sint32(y3 - y1); - auto ystep3 = FixedPoint(sy4 - sy2) / Sint32(y4 - y2); - - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return; - - /* Upper bit of the rectangle */ - if(y1 == y2) - { - if(y1 >= minY && y1 <= maxY) - _TexturedLine(dest, x1, x2, y1, source, srcx1, srcy1, srcx2, srcy2); - } else - { - auto m1 = (xc - xa) / Sint32(y2 - y1); - - auto xstep1 = (srcx2 - srcx1) / Sint32(y2 - y1); - auto ystep1 = (srcy2 - srcy1) / Sint32(y2 - y1); - - for(y = y1; y <= std::min(y2, maxY); y++) - { - if(y >= minY) - _TexturedLine(dest, xa.toInt(), xb.toInt(), y, source, srcx1, srcy1, - srcx1_2, srcy1_2); - - xa += m1; - xb += m2; - - srcx1 += xstep1; - srcx1_2 += xstep2; - srcy1 += ystep1; - srcy1_2 += ystep2; - } - } - - /* Middle bit of the rectangle */ - for(y = y2 + 1; y <= std::min(y3, maxY); y++) - { - if(y >= minY) - _TexturedLine(dest, xb.toInt(), xc.toInt(), y, source, srcx1_2, srcy1_2, - srcx2, srcy2); - - xb += m2; - xc += m3; - - srcx1_2 += xstep2; - srcx2 += xstep3; - srcy1_2 += ystep2; - srcy2 += ystep3; - } - - /* Lower bit of the rectangle */ - if(y3 == y4) - { - if(y3 >= minY && y3 <= maxY) - _TexturedLine(dest, x3, x4, y3, source, srcx3, srcy3, FixedPoint(sx4), - FixedPoint(sy4)); - } else - { - auto m4 = FixedPoint(x4 - x3) / Sint32(y4 - y3); - - auto xstep4 = FixedPoint(sx4 - sx3) / Sint32(y4 - y3); - auto ystep4 = FixedPoint(sy4 - sy3) / Sint32(y4 - y3); - - for(y = y3 + 1; y <= std::min(y4, maxY); y++) - { - if(y >= minY) - _TexturedLine(dest, xc.toInt(), xd.toInt(), y, source, srcx2, srcy2, - srcx3, srcy3); - - xc += m3; - xd += m4; - - srcx2 += xstep3; - srcx3 += xstep4; - srcy2 += ystep3; - srcy3 += ystep4; - } - } - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); -} - -void sge_TexturedRect(SDL_Surface* dest, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Sint16 x4, - Sint16 y4, SDL_Surface* source, Sint16 sx1, Sint16 sy1, Sint16 sx2, Sint16 sy2, Sint16 sx3, - Sint16 sy3, Sint16 sx4, Sint16 sy4) -{ - switch(dest->format->BytesPerPixel) - { - case 1: - if(source->format->BytesPerPixel == 4) - return _TexturedRect<4, 1>(dest, x1, y1, x2, y2, x3, y3, x4, y4, source, sx1, sy1, sx2, sy2, sx3, sy3, - sx4, sy4); - if(source->format->BytesPerPixel == 1) - return _TexturedRect<1, 1>(dest, x1, y1, x2, y2, x3, y3, x4, y4, source, sx1, sy1, sx2, sy2, sx3, sy3, - sx4, sy4); - break; - case 4: - if(source->format->BytesPerPixel == 1) - return _TexturedRect<1, 4>(dest, x1, y1, x2, y2, x3, y3, x4, y4, source, sx1, sy1, sx2, sy2, sx3, sy3, - sx4, sy4); - if(source->format->BytesPerPixel == 4) - return _TexturedRect<4, 4>(dest, x1, y1, x2, y2, x3, y3, x4, y4, source, sx1, sy1, sx2, sy2, sx3, sy3, - sx4, sy4); - break; - } - assert(false); -} - -//================================================================================== -// And now to something completly different: Polygons! -//================================================================================== - -/* Base polygon structure */ -class pline -{ -public: - virtual ~pline() = default; - pline* next; - - Sint16 x1, x2, y1, y2; - - FixedPoint fx, fm; - - Sint16 x; - - virtual void update() - { - x = fx.toInt(); - fx += fm; - } -}; - -/* Pointer storage (to preserve polymorphism) */ -struct pline_p -{ - pline* p; -}; - -/* Radix sort */ -static pline* rsort(pline* inlist) -{ - if(!inlist) - return nullptr; - - // 16 radix-buckets - std::array bucket = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; - std::array bi; // bucket itterator (points to last element in bucket) - - pline* plist = inlist; - - int i, k; - pline* j; - Uint8 nr; - - // Radix sort in 4 steps (16-bit numbers) - for(i = 0; i < 4; i++) - { - for(j = plist; j; j = j->next) - { - nr = Uint8((j->x >> (4 * i)) & 0x000F); // Get bucket number - - if(!bucket[nr]) - bucket[nr] = j; // First in bucket - else - bi[nr]->next = j; // Put last in bucket - - bi[nr] = j; // Update bucket itterator - } - - // Empty buckets (recombine list) - j = nullptr; - for(k = 0; k < 16; k++) - { - if(bucket[k]) - { - if(j) - j->next = bucket[k]; // Connect elements in buckets - else - plist = bucket[k]; // First element - - j = bi[k]; - } - bucket[k] = nullptr; // Empty - } - j->next = nullptr; // Terminate list - } - - return plist; -} - -/* Calculate the scanline for y */ -static pline* get_scanline(pline_p* plist, Uint16 n, Sint32 y) -{ - pline* p = nullptr; - pline* list = nullptr; - pline* li = nullptr; - - for(int i = 0; i < n; i++) - { - // Is polyline on this scanline? - p = plist[i].p; - if(p->y1 <= y && p->y2 >= y && (p->y1 != p->y2)) - { - if(list) - li->next = p; // Add last in list - else - list = p; // Add first in list - - li = p; // Update itterator - - // Calculate x - p->update(); - } - } - - if(li) - li->next = nullptr; // terminate - - // Sort list - return rsort(list); -} - -/* Removes duplicates if needed */ -inline void remove_dup(pline* li, Sint16 y) -{ - if(li->next) - if((y == li->y1 || y == li->y2) && (y == li->next->y1 || y == li->next->y2)) - if(((y == li->y1) ? -1 : 1) != ((y == li->next->y1) ? -1 : 1)) - li->next = li->next->next; -} - -//================================================================================== -// Draws a n-points filled polygon -//================================================================================== - -int sge_FilledPolygonAlpha(SDL_Surface* dest, Uint16 n, const Sint16* x, const Sint16* y, Uint32 color, Uint8 alpha) -{ - if(n < 3) - return -1; - - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return -2; - - auto* line = new pline[n]; - auto* plist = new pline_p[n]; - - Sint16 y1, y2, x1, x2, tmp, sy; - Sint16 ymin = y[1], ymax = y[1]; - Sint16 xmin = x[1], xmax = x[1]; - Uint16 i; - - /* Decompose polygon into straight lines */ - for(i = 0; i < n; i++) - { - y1 = y[i]; - x1 = x[i]; - - if(i == n - 1) - { - // Last point == First point - y2 = y[0]; - x2 = x[0]; - } else - { - y2 = y[i + 1]; - x2 = x[i + 1]; - } - - // Make sure y1 <= y2 - if(y1 > y2) - { - SWAP(y1, y2, tmp); - SWAP(x1, x2, tmp); - } - - // Reject polygons with negative coords - if(y1 < 0 || x1 < 0 || x2 < 0) - { - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); - - delete[] line; - delete[] plist; - return -1; - } - - if(y1 < ymin) - ymin = y1; - if(y2 > ymax) - ymax = y2; - if(x1 < xmin) - xmin = x1; - else if(x1 > xmax) - xmax = x1; - if(x2 < xmin) - xmin = x2; - else if(x2 > xmax) - xmax = x2; - - // Fill structure - line[i].y1 = y1; - line[i].y2 = y2; - line[i].x1 = x1; - line[i].x2 = x2; - - // Start x-value (fixed point) - line[i].fx = FixedPoint(x1); - - // Lines step value (fixed point) - if(y1 != y2) - line[i].fm = FixedPoint(x2 - x1) / Sint32(y2 - y1); - else - line[i].fm = FixedPoint(0); - - line[i].next = nullptr; - - // Add to list - plist[i].p = &line[i]; - - // Draw the polygon outline (looks nicer) - if(alpha == SDL_ALPHA_OPAQUE) - _Line(dest, x1, y1, x2, y2, color); // Can't do this with alpha, might overlap with the filling - } - - /* Remove surface lock if _HLine() is to be used */ - if(_sge_lock && SDL_MUSTLOCK(dest) && alpha == SDL_ALPHA_OPAQUE) - SDL_UnlockSurface(dest); - - pline* list = nullptr; - pline* li = nullptr; // list itterator - - // Scan y-lines - for(sy = ymin; sy <= ymax; sy++) - { - list = get_scanline(plist, n, sy); - - if(!list) - continue; // nothing in list... hmmmm - - x1 = x2 = -1; - - // Draw horizontal lines between pairs - for(li = list; li; li = li->next) - { - remove_dup(li, sy); - - if(x1 < 0) - x1 = li->x + 1; - else if(x2 < 0) - x2 = li->x; - - if(x1 >= 0 && x2 >= 0) - { - if(x2 - x1 < 0 && alpha == SDL_ALPHA_OPAQUE) - { - // Already drawn by the outline - x1 = x2 = -1; - continue; - } - - if(alpha == SDL_ALPHA_OPAQUE) - _HLine(dest, x1, x2, sy, color); - else - _HLineAlpha(dest, x1 - 1, x2, sy, color, alpha); - - x1 = x2 = -1; - } - } - } - - if(_sge_lock && SDL_MUSTLOCK(dest) && alpha != SDL_ALPHA_OPAQUE) - SDL_UnlockSurface(dest); - - delete[] line; - delete[] plist; - - return 0; -} - -int sge_FilledPolygonAlpha(SDL_Surface* dest, Uint16 n, Sint16* x, Sint16* y, Uint8 r, Uint8 g, Uint8 b, Uint8 alpha) -{ - return sge_FilledPolygonAlpha(dest, n, x, y, SDL_MapRGB(dest->format, r, g, b), alpha); -} - -int sge_FilledPolygon(SDL_Surface* dest, Uint16 n, Sint16* x, Sint16* y, Uint32 color) -{ - return sge_FilledPolygonAlpha(dest, n, x, y, color, SDL_ALPHA_OPAQUE); -} - -int sge_FilledPolygon(SDL_Surface* dest, Uint16 n, Sint16* x, Sint16* y, Uint8 r, Uint8 g, Uint8 b) -{ - return sge_FilledPolygonAlpha(dest, n, x, y, SDL_MapRGB(dest->format, r, g, b), SDL_ALPHA_OPAQUE); -} - -//================================================================================== -// Draws a n-points (AA) filled polygon -//================================================================================== - -int sge_AAFilledPolygon(SDL_Surface* dest, Uint16 n, const Sint16* x, const Sint16* y, Uint32 color) -{ - if(n < 3) - return -1; - - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return -2; - - auto* line = new pline[n]; - auto* plist = new pline_p[n]; - - Sint16 y1, y2, x1, x2, tmp, sy; - Sint16 ymin = y[1], ymax = y[1]; - Sint16 xmin = x[1], xmax = x[1]; - Uint16 i; - - /* Decompose polygon into straight lines */ - for(i = 0; i < n; i++) - { - y1 = y[i]; - x1 = x[i]; - - if(i == n - 1) - { - // Last point == First point - y2 = y[0]; - x2 = x[0]; - } else - { - y2 = y[i + 1]; - x2 = x[i + 1]; - } - - // Make sure y1 <= y2 - if(y1 > y2) - { - SWAP(y1, y2, tmp); - SWAP(x1, x2, tmp); - } - - // Reject polygons with negative coords - if(y1 < 0 || x1 < 0 || x2 < 0) - { - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); - - delete[] line; - delete[] plist; - return -1; - } - - if(y1 < ymin) - ymin = y1; - if(y2 > ymax) - ymax = y2; - if(x1 < xmin) - xmin = x1; - else if(x1 > xmax) - xmax = x1; - if(x2 < xmin) - xmin = x2; - else if(x2 > xmax) - xmax = x2; - - // Fill structure - line[i].y1 = y1; - line[i].y2 = y2; - line[i].x1 = x1; - line[i].x2 = x2; - - // Start x-value (fixed point) - line[i].fx = FixedPoint(x1); - - // Lines step value (fixed point) - if(y1 != y2) - line[i].fm = FixedPoint(x2 - x1) / Sint32(y2 - y1); - else - line[i].fm = FixedPoint(0); - - line[i].next = nullptr; - - // Add to list - plist[i].p = &line[i]; - - // Draw AA Line - _AALineAlpha(dest, x1, y1, x2, y2, color, SDL_ALPHA_OPAQUE); - } - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); - - pline* list = nullptr; - pline* li = nullptr; // list itterator - - // Scan y-lines - for(sy = ymin; sy <= ymax; sy++) - { - list = get_scanline(plist, n, sy); - - if(!list) - continue; // nothing in list... hmmmm - - x1 = x2 = -1; - - // Draw horizontal lines between pairs - for(li = list; li; li = li->next) - { - remove_dup(li, sy); - - if(x1 < 0) - x1 = li->x + 1; - else if(x2 < 0) - x2 = li->x; - - if(x1 >= 0 && x2 >= 0) - { - if(x2 - x1 < 0) - { - x1 = x2 = -1; - continue; - } - - _HLine(dest, x1, x2, sy, color); - - x1 = x2 = -1; - } - } - } - - delete[] line; - delete[] plist; - - return 0; -} - -int sge_AAFilledPolygon(SDL_Surface* dest, Uint16 n, Sint16* x, Sint16* y, Uint8 r, Uint8 g, Uint8 b) -{ - return sge_AAFilledPolygon(dest, n, x, y, SDL_MapRGB(dest->format, r, g, b)); -} - -//================================================================================== -// Draws a n-points gourand shaded polygon -//================================================================================== - -/* faded polygon structure */ -class fpline final : public pline -{ -public: - Uint8 r1, r2; - Uint8 g1, g2; - Uint8 b1, b2; - - UFixedPoint fr, fg, fb; - UFixedPoint fmr, fmg, fmb; - - Uint8 r, g, b; - - void update() override - { - x = fx.toInt(); - fx += fm; - - r = static_cast(fr.toUnsigned()); - g = static_cast(fg.toUnsigned()); - b = static_cast(fb.toUnsigned()); - - fr += fmr; - fg += fmg; - fb += fmb; - } -}; - -int sge_FadedPolygonAlpha(SDL_Surface* dest, Uint16 n, const Sint16* x, const Sint16* y, const Uint8* R, const Uint8* G, - const Uint8* B, Uint8 alpha) -{ - if(n < 3) - return -1; - - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return -2; - - auto* line = new fpline[n]; - auto* plist = new pline_p[n]; - - Sint16 y1, y2, x1, x2, tmp, sy; - Sint16 ymin = y[1], ymax = y[1]; - Sint16 xmin = x[1], xmax = x[1]; - Uint16 i; - Uint8 r1 = 0, g1 = 0, b1 = 0, r2 = 0, g2 = 0, b2 = 0, t; - - // Decompose polygon into straight lines - for(i = 0; i < n; i++) - { - y1 = y[i]; - x1 = x[i]; - r1 = R[i]; - g1 = G[i]; - b1 = B[i]; - - if(i == n - 1) - { - // Last point == First point - y2 = y[0]; - x2 = x[0]; - r2 = R[0]; - g2 = G[0]; - b2 = B[0]; - } else - { - y2 = y[i + 1]; - x2 = x[i + 1]; - r2 = R[i + 1]; - g2 = G[i + 1]; - b2 = B[i + 1]; - } - - // Make sure y1 <= y2 - if(y1 > y2) - { - SWAP(y1, y2, tmp); - SWAP(x1, x2, tmp); - SWAP(r1, r2, t); - SWAP(g1, g2, t); - SWAP(b1, b2, t); - } - - // Reject polygons with negative coords - if(y1 < 0 || x1 < 0 || x2 < 0) - { - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); - - delete[] line; - delete[] plist; - return -1; - } - - if(y1 < ymin) - ymin = y1; - if(y2 > ymax) - ymax = y2; - if(x1 < xmin) - xmin = x1; - else if(x1 > xmax) - xmax = x1; - if(x2 < xmin) - xmin = x2; - else if(x2 > xmax) - xmax = x2; - - // Fill structure - line[i].y1 = y1; - line[i].y2 = y2; - line[i].x1 = x1; - line[i].x2 = x2; - line[i].r1 = r1; - line[i].g1 = g1; - line[i].b1 = b1; - line[i].r2 = r2; - line[i].g2 = g2; - line[i].b2 = b2; - - // Start x-value (fixed point) - line[i].fx = FixedPoint(x1); - - line[i].fr = UFixedPoint(r1); - line[i].fg = UFixedPoint(g1); - line[i].fb = UFixedPoint(b1); - - // Lines step value (fixed point) - if(y1 != y2) - { - line[i].fm = FixedPoint(x2 - x1) / Sint32(y2 - y1); - - line[i].fmr = UFixedPoint(r2 - r1) / Uint32(y2 - y1); - line[i].fmg = UFixedPoint(g2 - g1) / Uint32(y2 - y1); - line[i].fmb = UFixedPoint(b2 - b1) / Uint32(y2 - y1); - } else - { - line[i].fm = FixedPoint(0); - line[i].fmr = UFixedPoint(0); - line[i].fmg = UFixedPoint(0); - line[i].fmb = UFixedPoint(0); - } - - line[i].next = nullptr; - - // Add to list - plist[i].p = &line[i]; - - // Draw the polygon outline (looks nicer) - if(alpha == SDL_ALPHA_OPAQUE) - sge_DomcLine(dest, x1, y1, x2, y2, r1, g1, b1, r2, g2, b2, - _PutPixel); // Can't do this with alpha, might overlap with the filling - } - - fpline* list = nullptr; - fpline* li = nullptr; // list itterator - - // Scan y-lines - for(sy = ymin; sy <= ymax; sy++) - { - list = (fpline*)get_scanline(plist, n, sy); - - if(!list) - continue; // nothing in list... hmmmm - - x1 = x2 = -1; - - // Draw horizontal lines between pairs - for(li = list; li; li = (fpline*)li->next) - { - remove_dup(li, sy); - - if(x1 < 0) - { - x1 = li->x + 1; - r1 = li->r; - g1 = li->g; - b1 = li->b; - } else if(x2 < 0) - { - x2 = li->x; - r2 = li->r; - g2 = li->g; - b2 = li->b; - } - - if(x1 >= 0 && x2 >= 0) - { - if(x2 - x1 < 0 && alpha == SDL_ALPHA_OPAQUE) - { - x1 = x2 = -1; - continue; - } - - if(alpha == SDL_ALPHA_OPAQUE) - _FadedLine(dest, x1, x2, sy, FixedPoint(r1), FixedPoint(g1), FixedPoint(b1), FixedPoint(r2), - FixedPoint(g2), FixedPoint(b2)); - else - { - _sge_alpha_hack = alpha; - sge_DomcLine(dest, x1 - 1, sy, x2, sy, r1, g1, b1, r2, g2, b2, callback_alpha_hack); - } - - x1 = x2 = -1; - } - } - } - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); - - delete[] line; - delete[] plist; - - return 0; -} - -int sge_FadedPolygon(SDL_Surface* dest, Uint16 n, Sint16* x, Sint16* y, Uint8* R, Uint8* G, Uint8* B) -{ - return sge_FadedPolygonAlpha(dest, n, x, y, R, G, B, SDL_ALPHA_OPAQUE); -} - -//================================================================================== -// Draws a n-points (AA) gourand shaded polygon -//================================================================================== -int sge_AAFadedPolygon(SDL_Surface* dest, Uint16 n, const Sint16* x, const Sint16* y, const Uint8* R, const Uint8* G, - const Uint8* B) -{ - if(n < 3) - return -1; - - if(_sge_lock && SDL_MUSTLOCK(dest)) - if(SDL_LockSurface(dest) < 0) - return -2; - - auto* line = new fpline[n]; - auto* plist = new pline_p[n]; - - Sint16 y1, y2, x1, x2, tmp, sy; - Sint16 ymin = y[1], ymax = y[1]; - Sint16 xmin = x[1], xmax = x[1]; - Uint16 i; - Uint8 r1 = 0, g1 = 0, b1 = 0, r2 = 0, g2 = 0, b2 = 0, t; - - // Decompose polygon into straight lines - for(i = 0; i < n; i++) - { - y1 = y[i]; - x1 = x[i]; - r1 = R[i]; - g1 = G[i]; - b1 = B[i]; - - if(i == n - 1) - { - // Last point == First point - y2 = y[0]; - x2 = x[0]; - r2 = R[0]; - g2 = G[0]; - b2 = B[0]; - } else - { - y2 = y[i + 1]; - x2 = x[i + 1]; - r2 = R[i + 1]; - g2 = G[i + 1]; - b2 = B[i + 1]; - } - - // Make sure y1 <= y2 - if(y1 > y2) - { - SWAP(y1, y2, tmp); - SWAP(x1, x2, tmp); - SWAP(r1, r2, t); - SWAP(g1, g2, t); - SWAP(b1, b2, t); - } - - // Reject polygons with negative coords - if(y1 < 0 || x1 < 0 || x2 < 0) - { - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); - - delete[] line; - delete[] plist; - return -1; - } - - if(y1 < ymin) - ymin = y1; - if(y2 > ymax) - ymax = y2; - if(x1 < xmin) - xmin = x1; - else if(x1 > xmax) - xmax = x1; - if(x2 < xmin) - xmin = x2; - else if(x2 > xmax) - xmax = x2; - - // Fill structure - line[i].y1 = y1; - line[i].y2 = y2; - line[i].x1 = x1; - line[i].x2 = x2; - line[i].r1 = r1; - line[i].g1 = g1; - line[i].b1 = b1; - line[i].r2 = r2; - line[i].g2 = g2; - line[i].b2 = b2; - - // Start x-value (fixed point) - line[i].fx = FixedPoint(x1); - - line[i].fr = UFixedPoint(r1); - line[i].fg = UFixedPoint(g1); - line[i].fb = UFixedPoint(b1); - - // Lines step value (fixed point) - if(y1 != y2) - { - line[i].fm = FixedPoint(x2 - x1) / Sint32(y2 - y1); - - line[i].fmr = UFixedPoint(r2 - r1) / Uint32(y2 - y1); - line[i].fmg = UFixedPoint(g2 - g1) / Uint32(y2 - y1); - line[i].fmb = UFixedPoint(b2 - b1) / Uint32(y2 - y1); - } else - { - line[i].fm = FixedPoint(0); - line[i].fmr = UFixedPoint(0); - line[i].fmg = UFixedPoint(0); - line[i].fmb = UFixedPoint(0); - } - - line[i].next = nullptr; - - // Add to list - plist[i].p = &line[i]; - - // Draw the polygon outline (AA) - _AAmcLineAlpha(dest, x1, y1, x2, y2, r1, g1, b1, r2, g2, b2, SDL_ALPHA_OPAQUE); - } - - fpline* list = nullptr; - fpline* li = nullptr; // list itterator - - // Scan y-lines - for(sy = ymin; sy <= ymax; sy++) - { - list = (fpline*)get_scanline(plist, n, sy); - - if(!list) - continue; // nothing in list... hmmmm - - x1 = x2 = -1; - - // Draw horizontal lines between pairs - for(li = list; li; li = (fpline*)li->next) - { - remove_dup(li, sy); - - if(x1 < 0) - { - x1 = li->x + 1; - r1 = li->r; - g1 = li->g; - b1 = li->b; - } else if(x2 < 0) - { - x2 = li->x; - r2 = li->r; - g2 = li->g; - b2 = li->b; - } - - if(x1 >= 0 && x2 >= 0) - { - if(x2 - x1 < 0) - { - x1 = x2 = -1; - continue; - } - - _FadedLine(dest, x1, x2, sy, FixedPoint(r1), FixedPoint(g1), FixedPoint(b1), FixedPoint(r2), - FixedPoint(g2), FixedPoint(b2)); - - x1 = x2 = -1; - } - } - } - - if(_sge_lock && SDL_MUSTLOCK(dest)) - SDL_UnlockSurface(dest); - - delete[] line; - delete[] plist; - - return 0; -} diff --git a/SGE/sge_collision.cpp b/SGE/sge_collision.cpp deleted file mode 100644 index 54e65cf..0000000 --- a/SGE/sge_collision.cpp +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Collision routines - * - * Started 000625 - */ -#include "sge_collision.h" -#include "sge_shape.h" -#include "sge_surface.h" -#include -#include -#include - -using namespace std; - -std::array sge_mask = {SGE_FLAG1, SGE_FLAG2, SGE_FLAG3, SGE_FLAG4, - SGE_FLAG5, SGE_FLAG6, SGE_FLAG7, SGE_FLAG8}; -SDL_Rect _ua; -Sint16 _cx = 0, _cy = 0; - -int memand(Uint8* s1, Uint8* s2, int shift1, int shift2, int N); - -//================================================================================== -// Makes a new collision map from img. Set colorkey first! -//================================================================================== -sge_cdata* sge_make_cmap(SDL_Surface* img) -{ - sge_cdata* cdata; - Uint8* map; - Sint16 x, y; - int i; - - Uint32 colorkey; - if(SDL_GetColorKey(img, &colorkey) != 0) - { - SDL_SetError("SGE - No colorkey set"); - return nullptr; - } - cdata = new(nothrow) sge_cdata; - if(!cdata) - { - SDL_SetError("SGE - Out of memory"); - return nullptr; - } - cdata->w = img->w; - cdata->h = img->h; - const Uint32 offs = (Uint32)(img->w * img->h) / 8; - cdata->map = new(nothrow) Uint8[offs + 2]; - if(!cdata->map) - { - SDL_SetError("SGE - Out of memory"); - delete cdata; - return nullptr; - } - memset(cdata->map, 0x00, offs + 2); - - map = cdata->map; - i = 0; - for(y = 0; y < img->h; y++) - { - for(x = 0; x < img->w; x++) - { - if(i > 7) - { - i = 0; - map++; - } - if(sge_GetPixel(img, Sint16(x), Sint16(y)) != colorkey) - { - *map = *map | sge_mask[i]; - } - i++; - } - } - return cdata; -} - -//================================================================================== -// Checks bounding boxes for collision: 0-no collision 1-collision -//================================================================================== -int sge_bbcheck(sge_cdata* cd1, Sint16 x1, Sint16 y1, sge_cdata* cd2, Sint16 x2, Sint16 y2) -{ - const Uint16 w1 = cd1->w; - const Uint16 h1 = cd1->h; - const Uint16 w2 = cd2->w; - const Uint16 h2 = cd2->h; - - if(x1 < x2) - { - if(x1 + w1 > x2) - { - if(y1 < y2) - { - if(y1 + h1 > y2) - { - _ua.x = x2; - _ua.y = y2; - return 1; - } - } else - { - if(y2 + h2 > y1) - { - _ua.x = x2; - _ua.y = y1; - return 1; - } - } - } - } else - { - if(x2 + w2 > x1) - { - if(y2 < y1) - { - if(y2 + h2 > y1) - { - _ua.x = x1; - _ua.y = y1; - return 1; - } - } else - { - if(y1 + h1 > y2) - { - _ua.x = x1; - _ua.y = y2; - return 1; - } - } - } - } - - return 0; -} - -//================================================================================== -// Checks bounding boxes for collision: 0-no collision 1-collision -//================================================================================== -static int _sge_bbcheck(Sint16 x1, Sint16 y1, Uint16 w1, Uint16 h1, Sint16 x2, Sint16 y2, Uint16 w2, Uint16 h2) -{ - if(x1 < x2) - { - if(x1 + w1 > x2) - { - if(y1 < y2) - { - if(y1 + h1 > y2) - { - _ua.x = x2; - _ua.y = y2; - return 1; - } - } else - { - if(y2 + h2 > y1) - { - _ua.x = x2; - _ua.y = y1; - return 1; - } - } - } - } else - { - if(x2 + w2 > x1) - { - if(y2 < y1) - { - if(y2 + h2 > y1) - { - _ua.x = x1; - _ua.y = y1; - return 1; - } - } else - { - if(y1 + h1 > y2) - { - _ua.x = x1; - _ua.y = y2; - return 1; - } - } - } - } - - return 0; -} - -//================================================================================== -// AND N bits of s1 and s2 -// Returns the number of the bit (or zero) -//================================================================================== -int memand(Uint8* s1, Uint8* s2, int shift1, int shift2, int N) -{ - int b, i1 = shift1, i2 = shift2; - - for(b = 0; b < N; b++) - { - if(i1 > 7) - { - i1 = 0; - s1++; - } - if(i2 > 7) - { - i2 = 0; - s2++; - } - if((*s1 & sge_mask[i1]) && (*s2 & sge_mask[i2])) - return b + 1; - i1++; - i2++; - } - return 0; -} - -//================================================================================== -// Checks for pixel perfect collision: 0-no collision 1-collision -// sge_bbcheck MUST be called first!!! -//================================================================================== -int _sge_cmcheck(sge_cdata* cd1, Sint16 x1, Sint16 y1, sge_cdata* cd2, Sint16 x2, Sint16 y2) -{ - if(!cd1->map || !cd2->map) - return 0; - - const Uint16 w1 = cd1->w; - const Uint16 h1 = cd1->h; - const Uint16 w2 = cd2->w; - const Uint16 h2 = cd2->h; - - // masks - - Sint32 x1o = 0, x2o = 0, y1o = 0, y2o = 0, offs; // offsets - int i1 = 0, i2 = 0; - - Uint8* map1 = cd1->map; - Uint8* map2 = cd2->map; - - // Calculate correct starting point - if(_ua.x == x2 && _ua.y == y2) - { - x1o = x2 - x1; - y1o = y2 - y1; - - offs = w1 * y1o + x1o; - map1 += offs / 8; - i1 = offs % 8; - } else if(_ua.x == x2 && _ua.y == y1) - { - x1o = x2 - x1; - y2o = y1 - y2; - - map1 += x1o / 8; - i1 = x1o % 8; - - offs = w2 * y2o; - map2 += offs / 8; - i2 = offs % 8; - } else if(_ua.x == x1 && _ua.y == y1) - { - x2o = x1 - x2; - y2o = y1 - y2; - - offs = w2 * y2o + x2o; - map2 += offs / 8; - i2 = offs % 8; - } else if(_ua.x == x1 && _ua.y == y2) - { - x2o = x1 - x2; - y1o = y2 - y1; - - offs = w1 * y1o; - map1 += offs / 8; - i1 = offs % 8; - - map2 += x2o / 8; - i2 = x2o % 8; - } else - return 0; - - Sint16 y; - - Sint16 lenght; - - if(x1 + w1 < x2 + w2) - lenght = w1 - x1o; - else - lenght = w2 - x2o; - - // AND(map1,map2) - for(y = _ua.y; y <= y1 + h1 && y <= y2 + h2; y++) - { - offs = memand(map1, map2, i1, i2, lenght); - if(offs) - { - _cx = _ua.x + offs - 1; - _cy = y; - return 1; - } - - // goto the new line - offs = (y - y1) * w1 + x1o; - map1 = cd1->map; // reset pointer - map1 += offs / 8; - i1 = offs % 8; - - offs = (y - y2) * w2 + x2o; - map2 = cd2->map; // reset pointer - map2 += offs / 8; - i2 = offs % 8; - } - - return 0; -} - -//================================================================================== -// Checks pixel perfect collision: 0-no collision 1-collision -// calls sge_bbcheck automaticly -//================================================================================== -int sge_cmcheck(sge_cdata* cd1, Sint16 x1, Sint16 y1, sge_cdata* cd2, Sint16 x2, Sint16 y2) -{ - if(!sge_bbcheck(cd1, x1, y1, cd2, x2, y2)) - return 0; - - if(!cd1->map || !cd2->map) - return 1; - - return _sge_cmcheck(cd1, x1, y1, cd2, x2, y2); -} - -//================================================================================== -// Get the position of the last collision -//================================================================================== -Sint16 sge_get_cx() -{ - return _cx; -} -Sint16 sge_get_cy() -{ - return _cy; -} - -//================================================================================== -// Removes collision map from memory -//================================================================================== -void sge_destroy_cmap(sge_cdata* cd) -{ - delete[] cd->map; - delete cd; -} - -//================================================================================== -// Checks bounding boxes for collision: 0-no collision 1-collision -// (sprites) -//================================================================================== -#ifndef _SGE_NO_CLASSES -int sge_bbcheck_shape(sge_shape* shape1, sge_shape* shape2) -{ - return _sge_bbcheck(shape1->get_xpos(), shape1->get_ypos(), shape1->get_w(), shape1->get_h(), shape2->get_xpos(), - shape2->get_ypos(), shape2->get_w(), shape2->get_h()); -} -#endif - -//================================================================================== -// Clears an area in a cmap -//================================================================================== -void sge_unset_cdata(sge_cdata* cd, Sint16 x, Sint16 y, Sint16 w, Sint16 h) -{ - Uint8* map = cd->map; - Sint16 offs, len; - int i, n = 0; - - offs = y * cd->w + x; - map += offs / 8; - i = offs % 8; - - while(h--) - { - len = w; - while(len--) - { - if(i > 7) - { - i = 0; - map++; - } - *map &= ~sge_mask[i]; - i++; - } - n++; - map = cd->map; - offs = (y + n) * cd->w + x; - map += offs / 8; - i = offs % 8; - } -} - -//================================================================================== -// Fills an area in a cmap -//================================================================================== -void sge_set_cdata(sge_cdata* cd, Sint16 x, Sint16 y, Sint16 w, Sint16 h) -{ - Uint8* map = cd->map; - Sint16 offs, len; - int i, n = 0; - - offs = y * cd->w + x; - map += offs / 8; - i = offs % 8; - - while(h--) - { - len = w; - while(len--) - { - if(i > 7) - { - i = 0; - map++; - } - *map |= sge_mask[i]; - i++; - } - n++; - map = cd->map; - offs = (y + n) * cd->w + x; - map += offs / 8; - i = offs % 8; - } -} diff --git a/SGE/sge_primitives.cpp b/SGE/sge_primitives.cpp deleted file mode 100644 index 96d02fe..0000000 --- a/SGE/sge_primitives.cpp +++ /dev/null @@ -1,2265 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Drawing primitives - * - * Started 990815 (split from sge_draw 010611) - */ - -/* - * Some of this code is taken from the "Introduction to SDL" and - * John Garrison's PowerPak - */ - -#include "sge_primitives.h" -#include "sge_primitives_int.h" -#include "sge_surface.h" -#include -#include -#include - -/* Globals used for sge_Lock (defined in sge_surface) */ -extern Uint8 _sge_lock; - -using std::swap; - -/**********************************************************************************/ -/** Line functions **/ -/**********************************************************************************/ - -//================================================================================== -// Internal draw horizontal line -//================================================================================== -void _HLine(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color) -{ - if(x1 > x2) - { - Sint16 tmp = x1; - x1 = x2; - x2 = tmp; - } - - SDL_Rect l; - l.x = x1; - l.y = y; - l.w = (Uint16)(x2 - x1) + 1; - l.h = 1; - - SDL_FillRect(Surface, &l, Color); -} - -//================================================================================== -// Draw horizontal line -//================================================================================== -void sge_HLine(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color) -{ - if(x1 > x2) - { - Sint16 tmp = x1; - x1 = x2; - x2 = tmp; - } - - SDL_Rect l; - l.x = x1; - l.y = y; - l.w = (Uint16)(x2 - x1) + 1; - l.h = 1; - - SDL_FillRect(Surface, &l, Color); -} - -//================================================================================== -// Draw horizontal line (RGB) -//================================================================================== -void sge_HLine(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint8 R, Uint8 G, Uint8 B) -{ - sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B)); -} - -//================================================================================== -// Internal draw horizontal line (alpha) -//================================================================================== -void _HLineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color, Uint8 alpha) -{ - Uint8 lock = _sge_lock; - _sge_lock = 0; - sge_FilledRectAlpha(Surface, x1, y, x2, y, Color, alpha); - _sge_lock = lock; -} - -//================================================================================== -// Draw horizontal line (alpha) -//================================================================================== -void sge_HLineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color, Uint8 alpha) -{ - sge_FilledRectAlpha(Surface, x1, y, x2, y, Color, alpha); -} - -//================================================================================== -// Draw horizontal line (alpha RGB) -//================================================================================== -void sge_HLineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha) -{ - sge_HLineAlpha(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B), alpha); -} - -//================================================================================== -// Internal draw vertical line -//================================================================================== -static void _VLine(SDL_Surface* Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color) -{ - if(y1 > y2) - { - Sint16 tmp = y1; - y1 = y2; - y2 = tmp; - } - - SDL_Rect l; - l.x = x; - l.y = y1; - l.w = 1; - l.h = (Uint16)(y2 - y1) + 1; - - SDL_FillRect(Surface, &l, Color); -} - -//================================================================================== -// Draw vertical line -//================================================================================== -void sge_VLine(SDL_Surface* Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color) -{ - if(y1 > y2) - { - Sint16 tmp = y1; - y1 = y2; - y2 = tmp; - } - - SDL_Rect l; - l.x = x; - l.y = y1; - l.w = 1; - l.h = (Uint16)(y2 - y1) + 1; - - SDL_FillRect(Surface, &l, Color); -} - -//================================================================================== -// Draw vertical line (RGB) -//================================================================================== -void sge_VLine(SDL_Surface* Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint8 R, Uint8 G, Uint8 B) -{ - sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B)); -} - -//================================================================================== -// Internal draw vertical line (alpha - no update) -//================================================================================== -static void _VLineAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color, Uint8 alpha) -{ - Uint8 lock = _sge_lock; - _sge_lock = 0; - sge_FilledRectAlpha(Surface, x, y1, x, y2, Color, alpha); - _sge_lock = lock; -} - -//================================================================================== -// Draw vertical line (alpha) -//================================================================================== -void sge_VLineAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color, Uint8 alpha) -{ - sge_FilledRectAlpha(Surface, x, y1, x, y2, Color, alpha); -} - -//================================================================================== -// Draw vertical line (alpha RGB) -//================================================================================== -void sge_VLineAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha) -{ - sge_VLineAlpha(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B), alpha); -} - -//================================================================================== -// Performs Callback at each line point. (From PowerPak) -//================================================================================== -void sge_DoLine(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)) -{ - Sint16 dx, dy, sdx, sdy, x, y, px, py; - - dx = x2 - x1; - dy = y2 - y1; - - sdx = (dx < 0) ? -1 : 1; - sdy = (dy < 0) ? -1 : 1; - - dx = sdx * dx + 1; - dy = sdy * dy + 1; - - x = y = 0; - - px = x1; - py = y1; - - if(dx >= dy) - { - for(x = 0; x < dx; x++) - { - Callback(Surface, px, py, Color); - - y += dy; - if(y >= dx) - { - y -= dx; - py += sdy; - } - px += sdx; - } - } else - { - for(y = 0; y < dy; y++) - { - Callback(Surface, px, py, Color); - - x += dx; - if(x >= dy) - { - x -= dy; - px += sdx; - } - py += sdy; - } - } -} - -//================================================================================== -// Performs Callback at each line point. (RGB) -//================================================================================== -void sge_DoLine(SDL_Surface* Surface, Sint16 X1, Sint16 Y1, Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)) -{ - sge_DoLine(Surface, X1, Y1, X2, Y2, SDL_MapRGB(Surface->format, R, G, B), Callback); -} - -//================================================================================== -// Line clipping -// Standard Cohen-Sutherland algorithm (from gfxPrimitives) -//================================================================================== -#define CLIP_LEFT_EDGE 0x1 -#define CLIP_RIGHT_EDGE 0x2 -#define CLIP_BOTTOM_EDGE 0x4 -#define CLIP_TOP_EDGE 0x8 -#define CLIP_INSIDE(a) (!(a)) -#define CLIP_REJECT(a, b) ((a) & (b)) -#define CLIP_ACCEPT(a, b) (!((a) | (b))) - -static int clipEncode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom) -{ - int code = 0; - - if(x < left) - code |= CLIP_LEFT_EDGE; - else if(x > right) - code |= CLIP_RIGHT_EDGE; - - if(y < top) - code |= CLIP_TOP_EDGE; - else if(y > bottom) - code |= CLIP_BOTTOM_EDGE; - - return code; -} - -static int clipLine(SDL_Surface* dst, Sint16* x1, Sint16* y1, Sint16* x2, Sint16* y2) -{ - bool draw = false; - - float m; - - /* Get clipping boundary */ - Sint16 left, right, top, bottom; - left = sge_clip_xmin(dst); - right = sge_clip_xmax(dst); - top = sge_clip_ymin(dst); - bottom = sge_clip_ymax(dst); - - while(true) - { - int code1 = clipEncode(*x1, *y1, left, top, right, bottom); - int code2 = clipEncode(*x2, *y2, left, top, right, bottom); - - if(CLIP_ACCEPT(code1, code2)) - { - draw = true; - break; - } else if(CLIP_REJECT(code1, code2)) - break; - else - { - if(CLIP_INSIDE(code1)) - { - swap(*x1, *x2); - swap(*y1, *y2); - swap(code1, code2); - } - if(*x2 != *x1) - m = (*y2 - *y1) / float(*x2 - *x1); - else - m = 1.0; - - if(code1 & CLIP_LEFT_EDGE) - { - *y1 += Sint16((left - *x1) * m); - *x1 = left; - } else if(code1 & CLIP_RIGHT_EDGE) - { - *y1 += Sint16((right - *x1) * m); - *x1 = right; - } else if(code1 & CLIP_BOTTOM_EDGE) - { - if(*x2 != *x1) - { - *x1 += Sint16((bottom - *y1) / m); - } - *y1 = bottom; - } else if(code1 & CLIP_TOP_EDGE) - { - if(*x2 != *x1) - { - *x1 += Sint16((top - *y1) / m); - } - *y1 = top; - } - } - } - - return draw; -} - -//================================================================================== -// Draws a line -//================================================================================== -void _Line(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) -{ - if(!clipLine(surface, &x1, &y1, &x2, &y2)) - return; - - Sint16 dx, dy, sdx, sdy; - - dx = x2 - x1; - dy = y2 - y1; - - sdx = (dx < 0) ? -1 : 1; - sdy = (dy < 0) ? -1 : 1; - - dx = sdx * dx + 1; - dy = sdy * dy + 1; - - Sint16 y = 0; - - Sint16 pixx = surface->format->BytesPerPixel; - auto pixy = (Sint16)surface->pitch; - Uint8* pixel = (Uint8*)surface->pixels + y1 * pixy + x1 * pixx; - - pixx *= sdx; - pixy *= sdy; - - if(dx < dy) - { - Sint32 tmp = dx; - dx = dy; - dy = Sint16(tmp); - tmp = pixx; - pixx = pixy; - pixy = tmp; - } - - switch(surface->format->BytesPerPixel) - { - case 1: - { - for(int x = 0; x < dx; x++) - { - *pixel = color; - - y += dy; - if(y >= dx) - { - y -= dx; - pixel += pixy; - } - pixel += pixx; - } - } - break; - - case 2: - { - for(int x = 0; x < dx; x++) - { - *(Uint16*)pixel = color; - - y += dy; - if(y >= dx) - { - y -= dx; - pixel += pixy; - } - pixel += pixx; - } - } - break; - - case 3: - { - Uint8 rshift8 = surface->format->Rshift / 8; - Uint8 gshift8 = surface->format->Gshift / 8; - Uint8 bshift8 = surface->format->Bshift / 8; - Uint8 ashift8 = surface->format->Ashift / 8; - - Uint8 R = (color >> surface->format->Rshift) & 0xff; - Uint8 G = (color >> surface->format->Gshift) & 0xff; - Uint8 B = (color >> surface->format->Bshift) & 0xff; - Uint8 A = (color >> surface->format->Ashift) & 0xff; - - for(int x = 0; x < dx; x++) - { - *(pixel + rshift8) = R; - *(pixel + gshift8) = G; - *(pixel + bshift8) = B; - *(pixel + ashift8) = A; - - y += dy; - if(y >= dx) - { - y -= dx; - pixel += pixy; - } - pixel += pixx; - } - } - break; - - case 4: - { - for(int x = 0; x < dx; x++) - { - *(Uint32*)pixel = color; - - y += dy; - if(y >= dx) - { - y -= dx; - pixel += pixy; - } - pixel += pixx; - } - } - break; - } -} - -void sge_Line(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color) -{ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - if(SDL_LockSurface(Surface) < 0) - return; - } - - /* Draw the line */ - _Line(Surface, x1, y1, x2, y2, Color); - - /* unlock the display */ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -//================================================================================== -// Draws a line (RGB) -//================================================================================== -void sge_Line(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B) -{ - sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B)); -} - -//================================================================================== -// A quick hack to get alpha working with callbacks -//================================================================================== -Uint8 _sge_alpha_hack = 0; -void callback_alpha_hack(SDL_Surface* surf, Sint16 x, Sint16 y, Uint32 color) -{ - _PutPixelAlpha(surf, x, y, color, _sge_alpha_hack); -} - -//================================================================================== -// Draws a line (alpha) -//================================================================================== -void _LineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, Uint8 alpha) -{ - _sge_alpha_hack = alpha; - - /* Draw the line */ - sge_DoLine(Surface, x1, y1, x2, y2, Color, callback_alpha_hack); -} - -void sge_LineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, Uint8 alpha) -{ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - if(SDL_LockSurface(Surface) < 0) - return; - - _LineAlpha(Surface, x1, y1, x2, y2, Color, alpha); - - /* unlock the display */ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -//================================================================================== -// Draws a line (alpha - RGB) -//================================================================================== -void sge_LineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha) -{ - sge_LineAlpha(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B), alpha); -} - -//================================================================================== -// Anti-aliased line -// From SDL_gfxPrimitives written by A. Schiffler (aschiffler@home.com) -//================================================================================== -#define AAbits 8 -#define AAlevels 256 /* 2^AAbits */ -void _AALineAlpha(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha) -{ - Uint32 erracc = 0, erradj; - Uint32 erracctmp, wgt; - Sint16 y0p1, x0pxdir; - Uint8 a; - - /* Keep on working with 32bit numbers */ - Sint32 xx0 = x1; - Sint32 yy0 = y1; - Sint32 xx1 = x2; - Sint32 yy1 = y2; - - /* Reorder points if required */ - if(yy0 > yy1) - { - swap(yy0, yy1); - swap(xx0, xx1); - } - - /* Calculate distance */ - Sint16 dx = xx1 - xx0; - Uint16 dy = yy1 - yy0; - - /* Adjust for negative dx and set xdir */ - Sint16 xdir = 1; - if(dx < 0) - { - xdir = -1; - dx = (-dx); - } - - /* Check for special cases */ - if(dx == 0 || dy == 0 || dx == dy) - { - if(alpha == SDL_ALPHA_OPAQUE) - _Line(dst, x1, y1, x2, y2, color); - else - _LineAlpha(dst, x1, y1, x2, y2, color, alpha); - return; - } - - float alpha_pp = float(alpha) / 255; /* Used to calculate alpha level if alpha != 255 */ - - Uint32 intshift = 32 - AAbits; /* # of bits by which to shift erracc to get intensity level */ - - /* Draw the initial pixel in the foreground color */ - if(alpha == SDL_ALPHA_OPAQUE) - _PutPixel(dst, x1, y1, color); - else - _PutPixelAlpha(dst, x1, y1, color, alpha); - - /* x-major or y-major? */ - if(dy > dx) - { - /* y-major. Calculate 16-bit fixed point fractional part of a pixel that - X advances every time Y advances 1 pixel, truncating the result so that - we won't overrun the endpoint along the X axis */ - erradj = ((Uint32)(dx << 16) / dy) << 16; - - /* draw all pixels other than the first and last */ - x0pxdir = xx0 + xdir; - while(--dy) - { - erracctmp = erracc; - erracc += erradj; - if(erracc <= erracctmp) - { - /* rollover in error accumulator, x coord advances */ - xx0 = x0pxdir; - x0pxdir += xdir; - } - yy0++; /* y-major so always advance Y */ - - /* the AAbits most significant bits of erracc give us the intensity - weighting for this pixel, and the complement of the weighting for - the paired pixel. */ - wgt = (erracc >> intshift) & 255; - - a = Uint8(255 - wgt); - if(alpha != SDL_ALPHA_OPAQUE) - a = Uint8(a * alpha_pp); - - _PutPixelAlpha(dst, xx0, yy0, color, a); - - a = Uint8(wgt); - if(alpha != SDL_ALPHA_OPAQUE) - a = Uint8(a * alpha_pp); - - _PutPixelAlpha(dst, x0pxdir, yy0, color, a); - } - } else - { - /* x-major line. Calculate 16-bit fixed-point fractional part of a pixel - that Y advances each time X advances 1 pixel, truncating the result so - that we won't overrun the endpoint along the X axis. */ - erradj = (((Uint32)dy << 16) / (Uint32)dx) << 16; - - /* draw all pixels other than the first and last */ - y0p1 = yy0 + 1; - while(--dx) - { - erracctmp = erracc; - erracc += erradj; - if(erracc <= erracctmp) - { - /* Accumulator turned over, advance y */ - yy0 = y0p1; - y0p1++; - } - xx0 += xdir; /* x-major so always advance X */ - - /* the AAbits most significant bits of erracc give us the intensity - weighting for this pixel, and the complement of the weighting for - the paired pixel. */ - wgt = (erracc >> intshift) & 255; - - a = Uint8(255 - wgt); - if(alpha != SDL_ALPHA_OPAQUE) - a = Uint8(a * alpha_pp); - - _PutPixelAlpha(dst, xx0, yy0, color, a); - - a = Uint8(wgt); - if(alpha != SDL_ALPHA_OPAQUE) - a = Uint8(a * alpha_pp); - - _PutPixelAlpha(dst, xx0, y0p1, color, a); - } - } - - /* Draw final pixel, always exactly intersected by the line and doesn't - need to be weighted. */ - if(alpha == SDL_ALPHA_OPAQUE) - _PutPixel(dst, x2, y2, color); - else - _PutPixelAlpha(dst, x2, y2, color, alpha); -} - -void sge_AALineAlpha(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha) -{ - /* Lock surface */ - if(_sge_lock && SDL_MUSTLOCK(dst)) - if(SDL_LockSurface(dst) < 0) - return; - - _AALineAlpha(dst, x1, y1, x2, y2, color, alpha); - - /* unlock the display */ - if(_sge_lock && SDL_MUSTLOCK(dst)) - { - SDL_UnlockSurface(dst); - } -} - -void sge_AALineAlpha(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, - Uint8 alpha) -{ - sge_AALineAlpha(dst, x1, y1, x2, y2, SDL_MapRGB(dst->format, r, g, b), alpha); -} - -void sge_AALine(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) -{ - sge_AALineAlpha(dst, x1, y1, x2, y2, color, SDL_ALPHA_OPAQUE); -} - -void sge_AALine(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b) -{ - sge_AALineAlpha(dst, x1, y1, x2, y2, SDL_MapRGB(dst->format, r, g, b), SDL_ALPHA_OPAQUE); -} - -//================================================================================== -// Draws a multicolored line -//================================================================================== -void sge_DomcLine(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, Uint8 b1, - Uint8 r2, Uint8 g2, Uint8 b2, void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)) -{ - Sint16 dx, dy, sdx, sdy, x, y, px, py; - - dx = x2 - x1; - dy = y2 - y1; - - sdx = (dx < 0) ? -1 : 1; - sdy = (dy < 0) ? -1 : 1; - - dx = sdx * dx + 1; - dy = sdy * dy + 1; - - x = y = 0; - - px = x1; - py = y1; - - /* We use fixedpoint math for the color fading */ - Sint32 R = r1 << 16; - Sint32 G = g1 << 16; - Sint32 B = b1 << 16; - Sint32 rstep; - Sint32 gstep; - Sint32 bstep; - - if(dx >= dy) - { - rstep = Sint32((r2 - r1) << 16) / Sint32(dx); - gstep = Sint32((g2 - g1) << 16) / Sint32(dx); - bstep = Sint32((b2 - b1) << 16) / Sint32(dx); - - for(x = 0; x < dx; x++) - { - Callback(surface, px, py, SDL_MapRGB(surface->format, Uint8(R >> 16), Uint8(G >> 16), Uint8(B >> 16))); - - y += dy; - if(y >= dx) - { - y -= dx; - py += sdy; - } - px += sdx; - - R += rstep; - G += gstep; - B += bstep; - } - } else - { - rstep = Sint32((r2 - r1) << 16) / Sint32(dy); - gstep = Sint32((g2 - g1) << 16) / Sint32(dy); - bstep = Sint32((b2 - b1) << 16) / Sint32(dy); - - for(y = 0; y < dy; y++) - { - Callback(surface, px, py, SDL_MapRGB(surface->format, Uint8(R >> 16), Uint8(G >> 16), Uint8(B >> 16))); - - x += dx; - if(x >= dy) - { - x -= dy; - px += sdx; - } - py += sdy; - - R += rstep; - G += gstep; - B += bstep; - } - } -} - -void sge_mcLine(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, Uint8 b1, - Uint8 r2, Uint8 g2, Uint8 b2) -{ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - if(SDL_LockSurface(Surface) < 0) - return; - } - - /* Draw the line */ - sge_DomcLine(Surface, x1, y1, x2, y2, r1, g1, b1, r2, g2, b2, _PutPixel); - - /* unlock the display */ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -void sge_mcLineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, Uint8 b1, - Uint8 r2, Uint8 g2, Uint8 b2, Uint8 alpha) -{ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - if(SDL_LockSurface(Surface) < 0) - return; - - _sge_alpha_hack = alpha; - - /* Draw the line */ - sge_DomcLine(Surface, x1, y1, x2, y2, r1, g1, b1, r2, g2, b2, callback_alpha_hack); - - /* unlock the display */ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -//================================================================================== -// Draws a anti-aliased multicolored line -//================================================================================== -void _AAmcLineAlpha(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, Uint8 b1, - Uint8 r2, Uint8 g2, Uint8 b2, Uint8 alpha) -{ - Uint32 erracc = 0, erradj; - Uint32 erracctmp, wgt; - Sint16 y0p1, x0pxdir; - - /* Keep on working with 32bit numbers */ - Sint32 xx0 = x1; - Sint32 yy0 = y1; - Sint32 xx1 = x2; - Sint32 yy1 = y2; - - /* Reorder points if required */ - if(yy0 > yy1) - { - swap(yy0, yy1); - swap(xx0, xx1); - - swap(r1, r2); - swap(g1, g2); - swap(b1, b2); - } - - /* Calculate distance */ - Sint16 dx = xx1 - xx0; - Uint16 dy = yy1 - yy0; - - /* Adjust for negative dx and set xdir */ - Sint16 xdir = 1; - if(dx < 0) - { - xdir = -1; - dx = (-dx); - } - - /* Check for special cases */ - if(dx == 0 || dy == 0 || dx == dy) - { - sge_mcLineAlpha(dst, x1, y1, x2, y2, r1, g1, b1, r2, g2, b2, alpha); - return; - } - - /* We use fixedpoint math for the color fading */ - Sint32 R = r1 << 16; - Sint32 G = g1 << 16; - Sint32 B = b1 << 16; - Sint32 rstep; - Sint32 gstep; - Sint32 bstep; - - float alpha_pp = float(alpha) / 255; /* Used to calculate alpha level if alpha != 255 */ - Uint32 intshift = 32 - AAbits; /* # of bits by which to shift erracc to get intensity level */ - - if(alpha == 255) - _PutPixel(dst, x1, y1, - SDL_MapRGB(dst->format, r1, g1, b1)); /* Draw the initial pixel in the foreground color */ - else - _PutPixelAlpha(dst, x1, y1, SDL_MapRGB(dst->format, r1, g1, b1), alpha); - - /* x-major or y-major? */ - if(dy > dx) - { - /* y-major. Calculate 16-bit fixed point fractional part of a pixel that - X advances every time Y advances 1 pixel, truncating the result so that - we won't overrun the endpoint along the X axis */ - erradj = (((Uint32)dx << 16) / (Uint32)dy) << 16; - - rstep = Sint32((r2 - r1) << 16) / Sint32(dy); - gstep = Sint32((g2 - g1) << 16) / Sint32(dy); - bstep = Sint32((b2 - b1) << 16) / Sint32(dy); - - /* draw all pixels other than the first and last */ - x0pxdir = xx0 + xdir; - while(--dy) - { - R += rstep; - G += gstep; - B += bstep; - - erracctmp = erracc; - erracc += erradj; - if(erracc <= erracctmp) - { - /* rollover in error accumulator, x coord advances */ - xx0 = x0pxdir; - x0pxdir += xdir; - } - yy0++; /* y-major so always advance Y */ - - /* the AAbits most significant bits of erracc give us the intensity - weighting for this pixel, and the complement of the weighting for - the paired pixel. */ - wgt = (erracc >> intshift) & 255; - - auto a = Uint8(255 - wgt); - if(alpha != 255) - a = Uint8(a * alpha_pp); - - _PutPixelAlpha(dst, xx0, yy0, SDL_MapRGB(dst->format, Uint8(R >> 16), Uint8(G >> 16), Uint8(B >> 16)), a); - - a = Uint8(wgt); - if(alpha != 255) - a = Uint8(a * alpha_pp); - - _PutPixelAlpha(dst, x0pxdir, yy0, SDL_MapRGB(dst->format, Uint8(R >> 16), Uint8(G >> 16), Uint8(B >> 16)), - a); - } - } else - { - /* x-major line. Calculate 16-bit fixed-point fractional part of a pixel - that Y advances each time X advances 1 pixel, truncating the result so - that we won't overrun the endpoint along the X axis. */ - erradj = (((Uint32)dy << 16) / (Uint32)dx) << 16; - - rstep = Sint32((r2 - r1) << 16) / Sint32(dx); - gstep = Sint32((g2 - g1) << 16) / Sint32(dx); - bstep = Sint32((b2 - b1) << 16) / Sint32(dx); - - /* draw all pixels other than the first and last */ - y0p1 = yy0 + 1; - while(--dx) - { - R += rstep; - G += gstep; - B += bstep; - - erracctmp = erracc; - erracc += erradj; - if(erracc <= erracctmp) - { - /* Accumulator turned over, advance y */ - yy0 = y0p1; - y0p1++; - } - xx0 += xdir; /* x-major so always advance X */ - - /* the AAbits most significant bits of erracc give us the intensity - weighting for this pixel, and the complement of the weighting for - the paired pixel. */ - wgt = (erracc >> intshift) & 255; - - auto a = Uint8(255 - wgt); - if(alpha != 255) - a = Uint8(a * alpha_pp); - - _PutPixelAlpha(dst, xx0, yy0, SDL_MapRGB(dst->format, Uint8(R >> 16), Uint8(G >> 16), Uint8(B >> 16)), a); - - a = Uint8(wgt); - if(alpha != 255) - a = Uint8(a * alpha_pp); - - _PutPixelAlpha(dst, xx0, y0p1, SDL_MapRGB(dst->format, Uint8(R >> 16), Uint8(G >> 16), Uint8(B >> 16)), a); - } - } - - /* Draw final pixel, always exactly intersected by the line and doesn't - need to be weighted. */ - if(alpha == 255) - _PutPixel(dst, x2, y2, SDL_MapRGB(dst->format, r2, g2, b2)); - else - _PutPixelAlpha(dst, x2, y2, SDL_MapRGB(dst->format, r2, g2, b2), alpha); -} - -void sge_AAmcLineAlpha(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, Uint8 b1, - Uint8 r2, Uint8 g2, Uint8 b2, Uint8 alpha) -{ - if(_sge_lock && SDL_MUSTLOCK(dst)) - if(SDL_LockSurface(dst) < 0) - return; - - _AAmcLineAlpha(dst, x1, y1, x2, y2, r1, g1, b1, r2, g2, b2, alpha); - - if(_sge_lock && SDL_MUSTLOCK(dst)) - SDL_UnlockSurface(dst); -} - -void sge_AAmcLine(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, Uint8 b1, - Uint8 r2, Uint8 g2, Uint8 b2) -{ - sge_AAmcLineAlpha(Surface, x1, y1, x2, y2, r1, g1, b1, r2, g2, b2, SDL_ALPHA_OPAQUE); -} - -/**********************************************************************************/ -/** Figure functions **/ -/**********************************************************************************/ - -//================================================================================== -// Draws a rectangle -//================================================================================== -void sge_Rect(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) -{ - _HLine(Surface, x1, x2, y1, color); - _HLine(Surface, x1, x2, y2, color); - _VLine(Surface, x1, y1, y2, color); - _VLine(Surface, x2, y1, y2, color); -} - -//================================================================================== -// Draws a rectangle (RGB) -//================================================================================== -void sge_Rect(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B) -{ - sge_Rect(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B)); -} - -//================================================================================== -// Draws a rectangle (alpha) -//================================================================================== -void sge_RectAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha) -{ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - if(SDL_LockSurface(Surface) < 0) - return; - - _HLineAlpha(Surface, x1, x2, y1, color, alpha); - _HLineAlpha(Surface, x1, x2, y2, color, alpha); - _VLineAlpha(Surface, x1, y1, y2, color, alpha); - _VLineAlpha(Surface, x2, y1, y2, color, alpha); - - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -//================================================================================== -// Draws a rectangle (RGB) -//================================================================================== -void sge_RectAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha) -{ - sge_RectAlpha(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B), alpha); -} - -//================================================================================== -// Draws a filled rectangle -//================================================================================== -void sge_FilledRect(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) -{ - Sint16 tmp; - if(x1 > x2) - { - tmp = x1; - x1 = x2; - x2 = tmp; - } - if(y1 > y2) - { - tmp = y1; - y1 = y2; - y2 = tmp; - } - - SDL_Rect area; - area.x = x1; - area.y = y1; - area.w = static_cast(x2 - x1) + 1; - area.h = static_cast(y2 - y1) + 1; - - SDL_FillRect(Surface, &area, color); -} - -//================================================================================== -// Draws a filled rectangle (RGB) -//================================================================================== -void sge_FilledRect(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B) -{ - sge_FilledRect(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B)); -} - -//================================================================================== -// Draws a filled rectangle (alpha) -//================================================================================== -void sge_FilledRectAlpha(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha) -{ - /*if( alpha == 255 ){ - sge_FilledRect(surface,x1,y1,x2,y2,color); - return; - }*/ - - /* Fix coords */ - Sint16 tmp; - if(x1 > x2) - { - tmp = x1; - x1 = x2; - x2 = tmp; - } - if(y1 > y2) - { - tmp = y1; - y1 = y2; - y2 = tmp; - } - - /* Clipping */ - if(x2 < sge_clip_xmin(surface) || x1 > sge_clip_xmax(surface) || y2 < sge_clip_ymin(surface) - || y1 > sge_clip_ymax(surface)) - return; - if(x1 < sge_clip_xmin(surface)) - x1 = sge_clip_xmin(surface); - if(x2 > sge_clip_xmax(surface)) - x2 = sge_clip_xmax(surface); - if(y1 < sge_clip_ymin(surface)) - y1 = sge_clip_ymin(surface); - if(y2 > sge_clip_ymax(surface)) - y2 = sge_clip_ymax(surface); - - Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, - Amask = surface->format->Amask; - Uint32 R, G, B, A = 0; - Sint16 x, y; - - if(_sge_lock && SDL_MUSTLOCK(surface)) - if(SDL_LockSurface(surface) < 0) - return; - - switch(surface->format->BytesPerPixel) - { - case 1: - { /* Assuming 8-bpp */ - Uint8 *row, *pixel; - Uint8 dR, dG, dB; - - Uint8 sR = surface->format->palette->colors[color].r; - Uint8 sG = surface->format->palette->colors[color].g; - Uint8 sB = surface->format->palette->colors[color].b; - - for(y = y1; y <= y2; y++) - { - row = (Uint8*)surface->pixels + y * surface->pitch; - for(x = x1; x <= x2; x++) - { - pixel = row + x; - - dR = surface->format->palette->colors[*pixel].r; - dG = surface->format->palette->colors[*pixel].g; - dB = surface->format->palette->colors[*pixel].b; - - dR = dR + (((sR - dR) * alpha) >> 8); - dG = dG + (((sG - dG) * alpha) >> 8); - dB = dB + (((sB - dB) * alpha) >> 8); - - *pixel = SDL_MapRGB(surface->format, dR, dG, dB); - } - } - } - break; - - case 2: - { /* Probably 15-bpp or 16-bpp */ - Uint16 *row, *pixel; - Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask); - - for(y = y1; y <= y2; y++) - { - row = (Uint16*)surface->pixels + y * surface->pitch / 2; - for(x = x1; x <= x2; x++) - { - pixel = row + x; - - R = ((*pixel & Rmask) + (((dR - (*pixel & Rmask)) * alpha) >> 8)) & Rmask; - G = ((*pixel & Gmask) + (((dG - (*pixel & Gmask)) * alpha) >> 8)) & Gmask; - B = ((*pixel & Bmask) + (((dB - (*pixel & Bmask)) * alpha) >> 8)) & Bmask; - if(Amask) - A = ((*pixel & Amask) + (((dA - (*pixel & Amask)) * alpha) >> 8)) & Amask; - - *pixel = R | G | B | A; - } - } - } - break; - - case 3: - { /* Slow 24-bpp mode, usually not used */ - Uint8 *row, *pix; - Uint8 dR, dG, dB, dA; - Uint8 rshift8 = surface->format->Rshift / 8; - Uint8 gshift8 = surface->format->Gshift / 8; - Uint8 bshift8 = surface->format->Bshift / 8; - Uint8 ashift8 = surface->format->Ashift / 8; - - Uint8 sR = (color >> surface->format->Rshift) & 0xff; - Uint8 sG = (color >> surface->format->Gshift) & 0xff; - Uint8 sB = (color >> surface->format->Bshift) & 0xff; - Uint8 sA = (color >> surface->format->Ashift) & 0xff; - - for(y = y1; y <= y2; y++) - { - row = (Uint8*)surface->pixels + y * surface->pitch; - for(x = x1; x <= x2; x++) - { - pix = row + x * 3; - - dR = *((pix) + rshift8); - dG = *((pix) + gshift8); - dB = *((pix) + bshift8); - dA = *((pix) + ashift8); - - dR = dR + (((sR - dR) * alpha) >> 8); - dG = dG + (((sG - dG) * alpha) >> 8); - dB = dB + (((sB - dB) * alpha) >> 8); - dA = dA + (((sA - dA) * alpha) >> 8); - - *((pix) + rshift8) = dR; - *((pix) + gshift8) = dG; - *((pix) + bshift8) = dB; - *((pix) + ashift8) = dA; - } - } - } - break; - - case 4: - { /* Probably 32-bpp */ - Uint32 *row, *pixel; - Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask), dA = (color & Amask); - - for(y = y1; y <= y2; y++) - { - row = (Uint32*)surface->pixels + y * surface->pitch / 4; - for(x = x1; x <= x2; x++) - { - pixel = row + x; - - R = ((*pixel & Rmask) + (((dR - (*pixel & Rmask)) * alpha) >> 8)) & Rmask; - G = ((*pixel & Gmask) + (((dG - (*pixel & Gmask)) * alpha) >> 8)) & Gmask; - B = ((*pixel & Bmask) + (((dB - (*pixel & Bmask)) * alpha) >> 8)) & Bmask; - if(Amask) - A = ((*pixel & Amask) + (((dA - (*pixel & Amask)) * alpha) >> 8)) & Amask; - - *pixel = R | G | B | A; - } - } - } - break; - } - - if(_sge_lock && SDL_MUSTLOCK(surface)) - { - SDL_UnlockSurface(surface); - } -} - -void sge_FilledRectAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha) -{ - sge_FilledRectAlpha(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B), alpha); -} - -//================================================================================== -// Performs Callback at each ellipse point. -// (from Allegro) -//================================================================================== -void sge_DoEllipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint32 color, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)) -{ - int ix, iy; - int h, i, j, k; - int oh, oi, oj, ok; - - if(rx < 1) - rx = 1; - - if(ry < 1) - ry = 1; - - h = i = j = k = 0xFFFF; - - if(rx > ry) - { - ix = 0; - iy = rx * 64; - - do - { - oh = h; - oi = i; - oj = j; - ok = k; - - h = (ix + 32) >> 6; - i = (iy + 32) >> 6; - j = (h * ry) / rx; - k = (i * ry) / rx; - - if(((h != oh) || (k != ok)) && (h < oi)) - { - Callback(Surface, x + h, y + k, color); - if(h) - Callback(Surface, x - h, y + k, color); - if(k) - { - Callback(Surface, x + h, y - k, color); - if(h) - Callback(Surface, x - h, y - k, color); - } - } - - if(((i != oi) || (j != oj)) && (h < i)) - { - Callback(Surface, x + i, y + j, color); - if(i) - Callback(Surface, x - i, y + j, color); - if(j) - { - Callback(Surface, x + i, y - j, color); - if(i) - Callback(Surface, x - i, y - j, color); - } - } - - ix = ix + iy / rx; - iy = iy - ix / rx; - - } while(i > h); - } else - { - ix = 0; - iy = ry * 64; - - do - { - oh = h; - oi = i; - oj = j; - ok = k; - - h = (ix + 32) >> 6; - i = (iy + 32) >> 6; - j = (h * rx) / ry; - k = (i * rx) / ry; - - if(((j != oj) || (i != oi)) && (h < i)) - { - Callback(Surface, x + j, y + i, color); - if(j) - Callback(Surface, x - j, y + i, color); - if(i) - { - Callback(Surface, x + j, y - i, color); - if(j) - Callback(Surface, x - j, y - i, color); - } - } - - if(((k != ok) || (h != oh)) && (h < oi)) - { - Callback(Surface, x + k, y + h, color); - if(k) - Callback(Surface, x - k, y + h, color); - if(h) - { - Callback(Surface, x + k, y - h, color); - if(k) - Callback(Surface, x - k, y - h, color); - } - } - - ix = ix + iy / ry; - iy = iy - ix / ry; - - } while(i > h); - } -} - -//================================================================================== -// Performs Callback at each ellipse point. (RGB) -//================================================================================== -void sge_DoEllipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, Uint8 B, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)) -{ - sge_DoEllipse(Surface, x, y, rx, ry, SDL_MapRGB(Surface->format, R, G, B), Callback); -} - -//================================================================================== -// Draws an ellipse -//================================================================================== -void sge_Ellipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint32 color) -{ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - if(SDL_LockSurface(Surface) < 0) - return; - } - - sge_DoEllipse(Surface, x, y, rx, ry, color, _PutPixel); - - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -//================================================================================== -// Draws an ellipse (RGB) -//================================================================================== -void sge_Ellipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, Uint8 B) -{ - sge_Ellipse(Surface, x, y, rx, ry, SDL_MapRGB(Surface->format, R, G, B)); -} - -//================================================================================== -// Draws an ellipse (alpha) -//================================================================================== -void sge_EllipseAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint32 color, Uint8 alpha) -{ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - if(SDL_LockSurface(Surface) < 0) - return; - - _sge_alpha_hack = alpha; - sge_DoEllipse(Surface, x, y, rx, ry, color, callback_alpha_hack); - - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -//================================================================================== -// Draws an ellipse (alpha - RGB) -//================================================================================== -void sge_EllipseAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha) -{ - sge_EllipseAlpha(Surface, x, y, rx, ry, SDL_MapRGB(Surface->format, R, G, B), alpha); -} - -//================================================================================== -// Draws a filled ellipse -//================================================================================== -void sge_FilledEllipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint32 color) -{ - int ix, iy; - int h, i, j, k; - int oh, oi, oj, ok; - - if(rx < 1) - rx = 1; - - if(ry < 1) - ry = 1; - - oh = oi = oj = ok = 0xFFFF; - - if(rx > ry) - { - ix = 0; - iy = rx * 64; - - do - { - h = (ix + 32) >> 6; - i = (iy + 32) >> 6; - j = (h * ry) / rx; - k = (i * ry) / rx; - - if((k != ok) && (k != oj)) - { - if(k) - { - _HLine(Surface, x - h, x + h, y - k, color); - _HLine(Surface, x - h, x + h, y + k, color); - } else - _HLine(Surface, x - h, x + h, y, color); - ok = k; - } - - if((j != oj) && (j != ok) && (k != j)) - { - if(j) - { - _HLine(Surface, x - i, x + i, y - j, color); - _HLine(Surface, x - i, x + i, y + j, color); - } else - _HLine(Surface, x - i, x + i, y, color); - oj = j; - } - - ix = ix + iy / rx; - iy = iy - ix / rx; - - } while(i > h); - } else - { - ix = 0; - iy = ry * 64; - - do - { - h = (ix + 32) >> 6; - i = (iy + 32) >> 6; - j = (h * rx) / ry; - k = (i * rx) / ry; - - if((i != oi) && (i != oh)) - { - if(i) - { - _HLine(Surface, x - j, x + j, y - i, color); - _HLine(Surface, x - j, x + j, y + i, color); - } else - _HLine(Surface, x - j, x + j, y, color); - oi = i; - } - - if((h != oh) && (h != oi) && (i != h)) - { - if(h) - { - _HLine(Surface, x - k, x + k, y - h, color); - _HLine(Surface, x - k, x + k, y + h, color); - } else - _HLine(Surface, x - k, x + k, y, color); - oh = h; - } - - ix = ix + iy / ry; - iy = iy - ix / ry; - - } while(i > h); - } -} - -//================================================================================== -// Draws a filled ellipse (RGB) -//================================================================================== -void sge_FilledEllipse(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, Uint8 B) -{ - sge_FilledEllipse(Surface, x, y, rx, ry, SDL_MapRGB(Surface->format, R, G, B)); -} - -//================================================================================== -// Draws a filled ellipse (alpha) -//================================================================================== -void sge_FilledEllipseAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint32 color, Uint8 alpha) -{ - int ix, iy; - int h, i, j, k; - int oh, oi, oj, ok; - - if(_sge_lock && SDL_MUSTLOCK(Surface)) - if(SDL_LockSurface(Surface) < 0) - return; - - if(rx < 1) - rx = 1; - - if(ry < 1) - ry = 1; - - oh = oi = oj = ok = 0xFFFF; - - if(rx > ry) - { - ix = 0; - iy = rx * 64; - - do - { - h = (ix + 32) >> 6; - i = (iy + 32) >> 6; - j = (h * ry) / rx; - k = (i * ry) / rx; - - if((k != ok) && (k != oj)) - { - if(k) - { - _HLineAlpha(Surface, x - h, x + h, y - k, color, alpha); - _HLineAlpha(Surface, x - h, x + h, y + k, color, alpha); - } else - _HLineAlpha(Surface, x - h, x + h, y, color, alpha); - ok = k; - } - - if((j != oj) && (j != ok) && (k != j)) - { - if(j) - { - _HLineAlpha(Surface, x - i, x + i, y - j, color, alpha); - _HLineAlpha(Surface, x - i, x + i, y + j, color, alpha); - } else - _HLineAlpha(Surface, x - i, x + i, y, color, alpha); - oj = j; - } - - ix = ix + iy / rx; - iy = iy - ix / rx; - - } while(i > h); - } else - { - ix = 0; - iy = ry * 64; - - do - { - h = (ix + 32) >> 6; - i = (iy + 32) >> 6; - j = (h * rx) / ry; - k = (i * rx) / ry; - - if((i != oi) && (i != oh)) - { - if(i) - { - _HLineAlpha(Surface, x - j, x + j, y - i, color, alpha); - _HLineAlpha(Surface, x - j, x + j, y + i, color, alpha); - } else - _HLineAlpha(Surface, x - j, x + j, y, color, alpha); - oi = i; - } - - if((h != oh) && (h != oi) && (i != h)) - { - if(h) - { - _HLineAlpha(Surface, x - k, x + k, y - h, color, alpha); - _HLineAlpha(Surface, x - k, x + k, y + h, color, alpha); - } else - _HLineAlpha(Surface, x - k, x + k, y, color, alpha); - oh = h; - } - - ix = ix + iy / ry; - iy = iy - ix / ry; - - } while(i > h); - } - - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -//================================================================================== -// Draws a filled ellipse (alpha - RGB) -//================================================================================== -void sge_FilledEllipseAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, Uint8 B, - Uint8 alpha) -{ - sge_FilledEllipseAlpha(Surface, x, y, rx, ry, SDL_MapRGB(Surface->format, R, G, B), alpha); -} - -//================================================================================== -// Draws a filled anti-aliased ellipse -// This is just a quick hack... -//================================================================================== -void sge_AAFilledEllipse(SDL_Surface* surface, Sint16 xc, Sint16 yc, Uint16 rx, Uint16 ry, Uint32 color) -{ - /* Sanity check */ - if(rx < 1) - rx = 1; - if(ry < 1) - ry = 1; - - int a2 = rx * rx; - int b2 = ry * ry; - - int ds = 2 * a2; - int dt = 2 * b2; - - auto dxt = int(a2 / sqrt(a2 + b2)); - - int t = 0; - int s = -2 * a2 * ry; - int d = 0; - - Sint16 x = xc; - Sint16 y = yc - ry; - - Sint16 xs, ys, dyt; - float cp, is, ip, imax = 1.0; - - /* Lock surface */ - if(_sge_lock && SDL_MUSTLOCK(surface)) - if(SDL_LockSurface(surface) < 0) - return; - - /* "End points" */ - _PutPixel(surface, x, y, color); - _PutPixel(surface, 2 * xc - x, y, color); - - _PutPixel(surface, x, 2 * yc - y, color); - _PutPixel(surface, 2 * xc - x, 2 * yc - y, color); - - /* unlock surface */ - if(_sge_lock && SDL_MUSTLOCK(surface)) - SDL_UnlockSurface(surface); - - _VLine(surface, x, y + 1, 2 * yc - y - 1, color); - - int i; - - for(i = 1; i <= dxt; i++) - { - x--; - d += t - b2; - - if(d >= 0) - ys = y - 1; - else if((d - s - a2) > 0) - { - if((2 * d - s - a2) >= 0) - ys = y + 1; - else - { - ys = y; - y++; - d -= s + a2; - s += ds; - } - } else - { - y++; - ys = y + 1; - d -= s + a2; - s += ds; - } - - t -= dt; - - /* Calculate alpha */ - cp = (float)abs(d) / abs(s); - is = cp * imax; - ip = imax - is; - - /* Lock surface */ - if(_sge_lock && SDL_MUSTLOCK(surface)) - if(SDL_LockSurface(surface) < 0) - return; - - /* Upper half */ - _PutPixelAlpha(surface, x, y, color, Uint8(ip * 255)); - _PutPixelAlpha(surface, 2 * xc - x, y, color, Uint8(ip * 255)); - - _PutPixelAlpha(surface, x, ys, color, Uint8(is * 255)); - _PutPixelAlpha(surface, 2 * xc - x, ys, color, Uint8(is * 255)); - - /* Lower half */ - _PutPixelAlpha(surface, x, 2 * yc - y, color, Uint8(ip * 255)); - _PutPixelAlpha(surface, 2 * xc - x, 2 * yc - y, color, Uint8(ip * 255)); - - _PutPixelAlpha(surface, x, 2 * yc - ys, color, Uint8(is * 255)); - _PutPixelAlpha(surface, 2 * xc - x, 2 * yc - ys, color, Uint8(is * 255)); - - /* unlock surface */ - if(_sge_lock && SDL_MUSTLOCK(surface)) - SDL_UnlockSurface(surface); - - /* Fill */ - _VLine(surface, x, y + 1, 2 * yc - y - 1, color); - _VLine(surface, 2 * xc - x, y + 1, 2 * yc - y - 1, color); - _VLine(surface, x, ys + 1, 2 * yc - ys - 1, color); - _VLine(surface, 2 * xc - x, ys + 1, 2 * yc - ys - 1, color); - } - - dyt = abs(y - yc); - - for(i = 1; i <= dyt; i++) - { - y++; - d -= s + a2; - - if(d <= 0) - xs = x + 1; - else if((d + t - b2) < 0) - { - if((2 * d + t - b2) <= 0) - xs = x - 1; - else - { - xs = x; - x--; - d += t - b2; - t -= dt; - } - } else - { - x--; - xs = x - 1; - d += t - b2; - t -= dt; - } - - s += ds; - - /* Calculate alpha */ - cp = (float)abs(d) / abs(t); - is = cp * imax; - ip = imax - is; - - /* Lock surface */ - if(_sge_lock && SDL_MUSTLOCK(surface)) - if(SDL_LockSurface(surface) < 0) - return; - - /* Upper half */ - _PutPixelAlpha(surface, x, y, color, Uint8(ip * 255)); - _PutPixelAlpha(surface, 2 * xc - x, y, color, Uint8(ip * 255)); - - _PutPixelAlpha(surface, xs, y, color, Uint8(is * 255)); - _PutPixelAlpha(surface, 2 * xc - xs, y, color, Uint8(is * 255)); - - /* Lower half*/ - _PutPixelAlpha(surface, x, 2 * yc - y, color, Uint8(ip * 255)); - _PutPixelAlpha(surface, 2 * xc - x, 2 * yc - y, color, Uint8(ip * 255)); - - _PutPixelAlpha(surface, xs, 2 * yc - y, color, Uint8(is * 255)); - _PutPixelAlpha(surface, 2 * xc - xs, 2 * yc - y, color, Uint8(is * 255)); - - /* unlock surface */ - if(_sge_lock && SDL_MUSTLOCK(surface)) - SDL_UnlockSurface(surface); - - /* Fill */ - _HLine(surface, x + 1, 2 * xc - x - 1, y, color); - _HLine(surface, xs + 1, 2 * xc - xs - 1, y, color); - _HLine(surface, x + 1, 2 * xc - x - 1, 2 * yc - y, color); - _HLine(surface, xs + 1, 2 * xc - xs - 1, 2 * yc - y, color); - } -} - -//================================================================================== -// Draws a filled anti-aliased ellipse (RGB) -//================================================================================== -void sge_AAFilledEllipse(SDL_Surface* surface, Sint16 xc, Sint16 yc, Uint16 rx, Uint16 ry, Uint8 R, Uint8 G, Uint8 B) -{ - sge_AAFilledEllipse(surface, xc, yc, rx, ry, SDL_MapRGB(surface->format, R, G, B)); -} - -//================================================================================== -// Performs Callback at each circle point. -//================================================================================== -void sge_DoCircle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint32 color, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)) -{ - Sint16 cx = 0; - auto cy = (Sint16)r; - Sint16 df = 1 - (Sint16)r; - Sint16 d_e = 3; - Sint16 d_se = -2 * r + 5; - - do - { - Callback(Surface, x + cx, y + cy, color); - Callback(Surface, x - cx, y + cy, color); - Callback(Surface, x + cx, y - cy, color); - Callback(Surface, x - cx, y - cy, color); - Callback(Surface, x + cy, y + cx, color); - Callback(Surface, x + cy, y - cx, color); - Callback(Surface, x - cy, y + cx, color); - Callback(Surface, x - cy, y - cx, color); - - if(df < 0) - { - df += d_e; - d_e += 2; - d_se += 2; - } else - { - df += d_se; - d_e += 2; - d_se += 4; - cy--; - } - - cx++; - - } while(cx <= cy); -} - -//================================================================================== -// Performs Callback at each circle point. (RGB) -//================================================================================== -void sge_DoCircle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint8 R, Uint8 G, Uint8 B, - void Callback(SDL_Surface* Surf, Sint16 X, Sint16 Y, Uint32 Color)) -{ - sge_DoCircle(Surface, x, y, r, SDL_MapRGB(Surface->format, R, G, B), Callback); -} - -//================================================================================== -// Draws a circle -//================================================================================== -void sge_Circle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint32 color) -{ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - if(SDL_LockSurface(Surface) < 0) - return; - } - - sge_DoCircle(Surface, x, y, r, color, _PutPixel); - - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -//================================================================================== -// Draws a circle (RGB) -//================================================================================== -void sge_Circle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint8 R, Uint8 G, Uint8 B) -{ - sge_Circle(Surface, x, y, r, SDL_MapRGB(Surface->format, R, G, B)); -} - -//================================================================================== -// Draws a circle (alpha) -//================================================================================== -void sge_CircleAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint32 color, Uint8 alpha) -{ - if(_sge_lock && SDL_MUSTLOCK(Surface)) - if(SDL_LockSurface(Surface) < 0) - return; - - _sge_alpha_hack = alpha; - sge_DoCircle(Surface, x, y, r, color, callback_alpha_hack); - - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -//================================================================================== -// Draws a circle (alpha - RGB) -//================================================================================== -void sge_CircleAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha) -{ - sge_CircleAlpha(Surface, x, y, r, SDL_MapRGB(Surface->format, R, G, B), alpha); -} - -//================================================================================== -// Draws a filled circle -//================================================================================== -void sge_FilledCircle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint32 color) -{ - Sint16 cx = 0; - auto cy = (Sint16)r; - bool draw = true; - Sint16 df = 1 - (Sint16)r; - Sint16 d_e = 3; - Sint16 d_se = -2 * r + 5; - - do - { - if(draw) - { - _HLine(Surface, x - cx, x + cx, y + cy, color); - _HLine(Surface, x - cx, x + cx, y - cy, color); - draw = false; - } - if(cx != cy) - { - if(cx) - { - _HLine(Surface, x - cy, x + cy, y - cx, color); - _HLine(Surface, x - cy, x + cy, y + cx, color); - } else - _HLine(Surface, x - cy, x + cy, y, color); - } - - if(df < 0) - { - df += d_e; - d_e += 2; - d_se += 2; - } else - { - df += d_se; - d_e += 2; - d_se += 4; - cy--; - draw = true; - } - cx++; - } while(cx <= cy); -} - -//================================================================================== -// Draws a filled circle (RGB) -//================================================================================== -void sge_FilledCircle(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint8 R, Uint8 G, Uint8 B) -{ - sge_FilledCircle(Surface, x, y, r, SDL_MapRGB(Surface->format, R, G, B)); -} - -//================================================================================== -// Draws a filled circle (alpha) -//================================================================================== -void sge_FilledCircleAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint32 color, Uint8 alpha) -{ - Sint16 cx = 0; - auto cy = (Sint16)r; - bool draw = true; - Sint16 df = 1 - (Sint16)r; - Sint16 d_e = 3; - Sint16 d_se = -2 * r + 5; - - if(_sge_lock && SDL_MUSTLOCK(Surface)) - if(SDL_LockSurface(Surface) < 0) - return; - - do - { - if(draw) - { - _HLineAlpha(Surface, x - cx, x + cx, y + cy, color, alpha); - _HLineAlpha(Surface, x - cx, x + cx, y - cy, color, alpha); - draw = false; - } - if(cx != cy) - { - if(cx) - { - _HLineAlpha(Surface, x - cy, x + cy, y - cx, color, alpha); - _HLineAlpha(Surface, x - cy, x + cy, y + cx, color, alpha); - } else - _HLineAlpha(Surface, x - cy, x + cy, y, color, alpha); - } - - if(df < 0) - { - df += d_e; - d_e += 2; - d_se += 2; - } else - { - df += d_se; - d_e += 2; - d_se += 4; - cy--; - draw = true; - } - cx++; - } while(cx <= cy); - - if(_sge_lock && SDL_MUSTLOCK(Surface)) - { - SDL_UnlockSurface(Surface); - } -} - -//================================================================================== -// Draws a filled circle (alpha - RGB) -//================================================================================== -void sge_FilledCircleAlpha(SDL_Surface* Surface, Sint16 x, Sint16 y, Uint16 r, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha) -{ - sge_FilledCircleAlpha(Surface, x, y, r, SDL_MapRGB(Surface->format, R, G, B), alpha); -} - -//================================================================================== -// Draws a filled anti-aliased circle -//================================================================================== -void sge_AAFilledCircle(SDL_Surface* surface, Sint16 xc, Sint16 yc, Uint16 r, Uint32 color) -{ - sge_AAFilledEllipse(surface, xc, yc, r, r, color); -} - -//================================================================================== -// Draws a filled anti-aliased circle (RGB) -//================================================================================== -void sge_AAFilledCircle(SDL_Surface* surface, Sint16 xc, Sint16 yc, Uint16 r, Uint8 R, Uint8 G, Uint8 B) -{ - sge_AAFilledEllipse(surface, xc, yc, r, r, SDL_MapRGB(surface->format, R, G, B)); -} - -//================================================================================== -// Draws a bezier line -//================================================================================== -/* Macro to do the line... 'function' is the line drawing routine */ -#define DO_BEZIER(function) \ - /* */ \ - /* Note: I don't think there is any great performance win in translating this to fixed-point integer math, */ \ - /* most of the time is spent in the line drawing routine. */ \ - /* */ \ - auto x = float(x1), y = float(y1); \ - float xp = x, yp = y; \ - float delta; \ - float dx, d2x, d3x; \ - float dy, d2y, d3y; \ - float a, b, c; \ - \ - /* compute number of iterations */ \ - if(level < 1) \ - level = 1; \ - if(level >= 15) \ - level = 15; \ - const int n = 1 << level; \ - delta = float(1.0 / float(n)); \ - \ - /* compute finite differences */ \ - /* a, b, c are the coefficient of the polynom in t defining the parametric curve */ \ - /* The computation is done independently for x and y */ \ - a = float(-x1 + 3 * x2 - 3 * x3 + x4); \ - b = float(3 * x1 - 6 * x2 + 3 * x3); \ - c = float(-3 * x1 + 3 * x2); \ - \ - d3x = 6 * a * delta * delta * delta; \ - d2x = d3x + 2 * b * delta * delta; \ - dx = a * delta * delta * delta + b * delta * delta + c * delta; \ - \ - a = float(-y1 + 3 * y2 - 3 * y3 + y4); \ - b = float(3 * y1 - 6 * y2 + 3 * y3); \ - c = float(-3 * y1 + 3 * y2); \ - \ - d3y = 6 * a * delta * delta * delta; \ - d2y = d3y + 2 * b * delta * delta; \ - dy = a * delta * delta * delta + b * delta * delta + c * delta; \ - \ - if(_sge_lock && SDL_MUSTLOCK(surface)) \ - { \ - if(SDL_LockSurface(surface) < 0) \ - return; \ - } \ - \ - /* iterate */ \ - for(int i = 0; i < n; i++) \ - { \ - x += dx; \ - dx += d2x; \ - d2x += d3x; \ - y += dy; \ - dy += d2y; \ - d2y += d3y; \ - if(Sint16(xp) != Sint16(x) || Sint16(yp) != Sint16(y)) \ - { \ - function; \ - } \ - xp = x; \ - yp = y; \ - } \ - \ - /* unlock the display */ \ - if(_sge_lock && SDL_MUSTLOCK(surface)) \ - { \ - SDL_UnlockSurface(surface); \ - } - -//================================================================================== -// Draws a bezier line -//================================================================================== -void sge_Bezier(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Sint16 x4, - Sint16 y4, int level, Uint32 color) -{ - DO_BEZIER(_Line(surface, Sint16(xp), Sint16(yp), Sint16(x), Sint16(y), color)); -} - -//================================================================================== -// Draws a bezier line (RGB) -//================================================================================== -void sge_Bezier(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Sint16 x4, - Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B) -{ - sge_Bezier(surface, x1, y1, x2, y2, x3, y3, x4, y4, level, SDL_MapRGB(surface->format, R, G, B)); -} - -//================================================================================== -// Draws a bezier line (alpha) -//================================================================================== -void sge_BezierAlpha(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Sint16 x4, - Sint16 y4, int level, Uint32 color, Uint8 alpha) -{ - _sge_alpha_hack = alpha; - - DO_BEZIER(sge_DoLine(surface, Sint16(xp), Sint16(yp), Sint16(x), Sint16(y), color, callback_alpha_hack)); -} - -//================================================================================== -// Draws a bezier line (alpha - RGB) -//================================================================================== -void sge_BezierAlpha(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Sint16 x4, - Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha) -{ - sge_BezierAlpha(surface, x1, y1, x2, y2, x3, y3, x4, y4, level, SDL_MapRGB(surface->format, R, G, B), alpha); -} - -//================================================================================== -// Draws an AA bezier line (alpha) -//================================================================================== -void sge_AABezierAlpha(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Sint16 x4, Sint16 y4, int level, Uint32 color, Uint8 alpha) -{ - Uint8 lock = _sge_lock; - _sge_lock = 0; - - if(SDL_MUSTLOCK(surface) && lock) - if(SDL_LockSurface(surface) < 0) - return; - - DO_BEZIER(sge_AALineAlpha(surface, Sint16(xp), Sint16(yp), Sint16(x), Sint16(y), color, alpha)); - - if(SDL_MUSTLOCK(surface) && lock) - { - SDL_UnlockSurface(surface); - } - - _sge_lock = lock; -} - -//================================================================================== -// Draws an AA bezier line (alpha - RGB) -//================================================================================== -void sge_AABezierAlpha(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, - Sint16 x4, Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha) -{ - sge_AABezierAlpha(surface, x1, y1, x2, y2, x3, y3, x4, y4, level, SDL_MapRGB(surface->format, R, G, B), alpha); -} - -//================================================================================== -// Draws an AA bezier line -//================================================================================== -void sge_AABezier(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Sint16 x4, - Sint16 y4, int level, Uint32 color) -{ - sge_AABezierAlpha(surface, x1, y1, x2, y2, x3, y3, x4, y4, level, color, 255); -} - -//================================================================================== -// Draws an AA bezier line (RGB) -//================================================================================== -void sge_AABezier(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Sint16 x4, - Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B) -{ - sge_AABezierAlpha(surface, x1, y1, x2, y2, x3, y3, x4, y4, level, SDL_MapRGB(surface->format, R, G, B), 255); -} diff --git a/SGE/sge_primitives_int.h b/SGE/sge_primitives_int.h deleted file mode 100644 index 8fc8336..0000000 --- a/SGE/sge_primitives_int.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Drawing primitives (header) - * - * Started 990815 (split from sge_draw 010611) - */ - -#pragma once - -#include "sge_internal.h" -#include - -void _Line(SDL_Surface* surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color); -void _LineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, Uint8 alpha); -void _HLine(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color); -void _HLineAlpha(SDL_Surface* Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color, Uint8 alpha); -void callback_alpha_hack(SDL_Surface* surf, Sint16 x, Sint16 y, Uint32 color); -void _AALineAlpha(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha); -void _AAmcLineAlpha(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, Uint8 b1, - Uint8 r2, Uint8 g2, Uint8 b2, Uint8 alpha); diff --git a/SGE/sge_rotation.cpp b/SGE/sge_rotation.cpp deleted file mode 100644 index 025e246..0000000 --- a/SGE/sge_rotation.cpp +++ /dev/null @@ -1,669 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Rotation routines - * - * Started 000625 - */ - -#define _USE_MATH_DEFINES -#define HAVE_M_PI 1 -#include "sge_rotation.h" -#include "sge_blib.h" -#include "sge_surface.h" -#include -#include - -extern Uint8 _sge_lock; - -SDL_Rect sge_transform_tmap(SDL_Surface* src, SDL_Surface* dst, float angle, float xscale, float yscale, Uint16 qx, - Uint16 qy); - -//================================================================================== -// Helper function to sge_transform() -// Returns the bounding box -//================================================================================== -static void _calcRect(SDL_Surface* src, SDL_Surface* dst, float theta, float xscale, float yscale, Uint16 px, Uint16 py, - Uint16 qx, Uint16 qy, Sint16* xmin, Sint16* ymin, Sint16* xmax, Sint16* ymax) -{ - Sint16 x, y, rx, ry; - - // Clip to src surface - Sint16 sxmin = sge_clip_xmin(src); - Sint16 sxmax = sge_clip_xmax(src); - Sint16 symin = sge_clip_ymin(src); - Sint16 symax = sge_clip_ymax(src); - std::array sx = {sxmin, sxmax, sxmin, sxmax}; - std::array sy = {symin, symax, symax, symin}; - - // We don't really need fixed-point here - // but why not? - auto const istx = Sint32((std::sin(theta) * xscale) * 8192.0); /* Inverse transform */ - auto const ictx = Sint32((std::cos(theta) * xscale) * 8192.2); - auto const isty = Sint32((std::sin(theta) * yscale) * 8192.0); - auto const icty = Sint32((std::cos(theta) * yscale) * 8192.2); - - // Calculate the four corner points - for(int i = 0; i < 4; i++) - { - rx = sx[i] - px; - ry = sy[i] - py; - - x = Sint16(((ictx * rx - isty * ry) >> 13) + qx); - y = Sint16(((icty * ry + istx * rx) >> 13) + qy); - - if(i == 0) - { - *xmax = *xmin = x; - *ymax = *ymin = y; - } else - { - if(x > *xmax) - *xmax = x; - else if(x < *xmin) - *xmin = x; - - if(y > *ymax) - *ymax = y; - else if(y < *ymin) - *ymin = y; - } - } - - // Better safe than sorry... - *xmin -= 1; - *ymin -= 1; - *xmax += 1; - *ymax += 1; - - // Clip to dst surface - if(!dst) - return; - if(*xmin < sge_clip_xmin(dst)) - *xmin = sge_clip_xmin(dst); - if(*xmax > sge_clip_xmax(dst)) - *xmax = sge_clip_xmax(dst); - if(*ymin < sge_clip_ymin(dst)) - *ymin = sge_clip_ymin(dst); - if(*ymax > sge_clip_ymax(dst)) - *ymax = sge_clip_ymax(dst); -} - -/*================================================================================== -** Rotate by angle about pivot (px,py) scale by scale and place at -** position (qx,qy). -** -** Transformation matrix application (rotated coords "R"): -** -** / rx \ / cos(theta) sin(theta) \ / dx \ -** | | = | | | | -** \ ry / \ -sin(theta) cos(theta) / \ dy / -** -** => rx = cos(theta) dx + sin(theta) dy -** ry = cos(theta) dy - sin(theta) dx -** but represented as a fixed-point float using integer math -** -** Developed with the help from Terry Hancock (hancock@earthlink.net) -** -**==================================================================================*/ -// First we need some macros to handle different bpp -// I'm sorry about this... -#define TRANSFORM(UintXX_T, DIV) \ - using UintXX = UintXX_T; \ - Sint32 const src_pitch = src->pitch / (DIV); \ - Sint32 const dst_pitch = dst->pitch / (DIV); \ - UintXX const* src_row = (UintXX*)src->pixels; \ - UintXX* dst_row; \ - \ - for(y = ymin; y < ymax; y++) \ - { \ - dy = y - qy; \ - \ - sx = Sint32(ctdx + stx * dy + mx); /* Compute source anchor points */ \ - sy = Sint32(cty * dy - stdx + my); \ - \ - /* Calculate pointer to dst surface */ \ - dst_row = (UintXX*)dst->pixels + y * dst_pitch; \ - \ - for(x = xmin; x < xmax; x++) \ - { \ - rx = Sint16(sx >> 13); /* Convert from fixed-point */ \ - ry = Sint16(sy >> 13); \ - \ - /* Make sure the source pixel is actually in the source image. */ \ - if((rx >= sxmin) && (rx <= sxmax) && (ry >= symin) && (ry <= symax)) \ - *(dst_row + x) = *(src_row + ry * src_pitch + rx); \ - \ - sx += ctx; /* Incremental transformations */ \ - sy -= sty; \ - } \ - } - -#define TRANSFORM_GENERIC \ - Uint8 R, G, B, A; \ - \ - for(y = ymin; y < ymax; y++) \ - { \ - dy = y - qy; \ - \ - sx = Sint32(ctdx + stx * dy + mx); /* Compute source anchor points */ \ - sy = Sint32(cty * dy - stdx + my); \ - \ - for(x = xmin; x < xmax; x++) \ - { \ - rx = Sint16(sx >> 13); /* Convert from fixed-point */ \ - ry = Sint16(sy >> 13); \ - \ - /* Make sure the source pixel is actually in the source image. */ \ - if((rx >= sxmin) && (rx <= sxmax) && (ry >= symin) && (ry <= symax)) \ - { \ - SDL_GetRGBA(sge_GetPixel(src, rx, ry), src->format, &R, &G, &B, &A); \ - _PutPixelX(dst, x, y, SDL_MapRGBA(dst->format, R, G, B, A)); \ - } \ - sx += ctx; /* Incremental transformations */ \ - sy -= sty; \ - } \ - } - -// Interpolated transform -#define TRANSFORM_AA(UintXX_T, DIV) \ - using UintXX = UintXX_T; \ - Sint32 const src_pitch = src->pitch / (DIV); \ - Sint32 const dst_pitch = dst->pitch / (DIV); \ - UintXX const* src_row = (UintXX*)src->pixels; \ - UintXX* dst_row; \ - UintXX c1, c2, c3, c4; \ - Uint32 R, G, B, A = 0; \ - UintXX Rmask = src->format->Rmask, Gmask = src->format->Gmask, Bmask = src->format->Bmask, \ - Amask = src->format->Amask; \ - Uint32 wx, wy; \ - Uint32 p1, p2, p3, p4; \ - \ - /* */ \ - /* Interpolation: */ \ - /* We calculate the distances from our point to the four nearest pixels, d1..d4. */ \ - /* d(a,b) = sqrt(a²+b²) ~= 0.707(a+b) (Pythagoras (Taylor) expanded around (0.5;0.5)) */ \ - /* */ \ - /* 1 wx 2 */ \ - /* *-|-* (+ = our point at (x,y)) */ \ - /* | | | (* = the four nearest pixels) */ \ - /* wy --+ | wx = float(x) - int(x) */ \ - /* | | wy = float(y) - int(y) */ \ - /* *---* */ \ - /* 3 4 */ \ - /* d1 = d(wx,wy) d2 = d(1-wx,wy) d3 = d(wx,1-wy) d4 = d(1-wx,1-wy) */ \ - /* We now want to weight each pixels importance - it's vicinity to our point: */ \ - /* w1=d4 w2=d3 w3=d2 w4=d1 (Yes it works... just think a bit about it) */ \ - /* */ \ - /* If the pixels have the colors c1..c4 then our point should have the color */ \ - /* c = (w1*c1 + w2*c2 + w3*c3 + w4*c4)/(w1+w2+w3+w4) (the weighted average) */ \ - /* but w1+w2+w3+w4 = 4*0.707 so we might as well write it as */ \ - /* c = p1*c1 + p2*c2 + p3*c3 + p4*c4 where p1..p4 = (w1..w4)/(4*0.707) */ \ - /* */ \ - /* But p1..p4 are fixed point so we can just divide the fixed point constant! */ \ - /* 8192/(4*0.71) = 2897 and we can skip 0.71 too (the division will cancel it everywhere) */ \ - /* 8192/4 = 2048 */ \ - /* */ \ - /* 020102: I changed the fixed-point representation for the variables in the weighted average */ \ - /* to 24.7 to avoid problems with 32bit colors. Everything else is still 18.13. This */ \ - /* does however not solve the problem with 32bit RGBA colors... */ \ - /* */ \ - \ - Sint32 const one = 2048 >> 6; /* 1 in Fixed-point */ \ - Sint32 const two = 2 * 2048 >> 6; /* 2 in Fixed-point */ \ - \ - for(y = ymin; y < ymax; y++) \ - { \ - dy = y - qy; \ - \ - sx = Sint32(ctdx + stx * dy + mx); /* Compute source anchor points */ \ - sy = Sint32(cty * dy - stdx + my); \ - \ - /* Calculate pointer to dst surface */ \ - dst_row = (UintXX*)dst->pixels + y * dst_pitch; \ - \ - for(x = xmin; x < xmax; x++) \ - { \ - rx = Sint16(sx >> 13); /* Convert from fixed-point */ \ - ry = Sint16(sy >> 13); \ - \ - /* Make sure the source pixel is actually in the source image. */ \ - if((rx >= sxmin) && (rx + 1 <= sxmax) && (ry >= symin) && (ry + 1 <= symax)) \ - { \ - wx = (sx & 0x00001FFF) >> 8; /* (float(x) - int(x)) / 4 */ \ - wy = (sy & 0x00001FFF) >> 8; \ - \ - p4 = wx + wy; \ - p3 = one - wx + wy; \ - p2 = wx + one - wy; \ - p1 = two - wx - wy; \ - \ - c1 = *(src_row + ry * src_pitch + rx); \ - c2 = *(src_row + ry * src_pitch + rx + 1); \ - c3 = *(src_row + (ry + 1) * src_pitch + rx); \ - c4 = *(src_row + (ry + 1) * src_pitch + rx + 1); \ - \ - /* Calculate the average */ \ - R = ((p1 * (c1 & Rmask) + p2 * (c2 & Rmask) + p3 * (c3 & Rmask) + p4 * (c4 & Rmask)) >> 7) & Rmask; \ - G = ((p1 * (c1 & Gmask) + p2 * (c2 & Gmask) + p3 * (c3 & Gmask) + p4 * (c4 & Gmask)) >> 7) & Gmask; \ - B = ((p1 * (c1 & Bmask) + p2 * (c2 & Bmask) + p3 * (c3 & Bmask) + p4 * (c4 & Bmask)) >> 7) & Bmask; \ - if(Amask) \ - A = \ - ((p1 * (c1 & Amask) + p2 * (c2 & Amask) + p3 * (c3 & Amask) + p4 * (c4 & Amask)) >> 7) & Amask; \ - \ - *(dst_row + x) = R | G | B | A; \ - } \ - sx += ctx; /* Incremental transformations */ \ - sy -= sty; \ - } \ - } - -#define TRANSFORM_GENERIC_AA \ - Uint8 R, G, B, A, R1, G1, B1, A1 = 0, R2, G2, B2, A2 = 0, R3, G3, B3, A3 = 0, R4, G4, B4, A4 = 0; \ - Sint32 wx, wy, p1, p2, p3, p4; \ - \ - Sint32 const one = 2048; /* 1 in Fixed-point */ \ - Sint32 const two = 2 * 2048; /* 2 in Fixed-point */ \ - \ - for(y = ymin; y < ymax; y++) \ - { \ - dy = y - qy; \ - \ - sx = Sint32(ctdx + stx * dy + mx); /* Compute source anchor points */ \ - sy = Sint32(cty * dy - stdx + my); \ - \ - for(x = xmin; x < xmax; x++) \ - { \ - rx = Sint16(sx >> 13); /* Convert from fixed-point */ \ - ry = Sint16(sy >> 13); \ - \ - /* Make sure the source pixel is actually in the source image. */ \ - if((rx >= sxmin) && (rx + 1 <= sxmax) && (ry >= symin) && (ry + 1 <= symax)) \ - { \ - wx = (sx & 0x00001FFF) >> 2; /* (float(x) - int(x)) / 4 */ \ - wy = (sy & 0x00001FFF) >> 2; \ - \ - p4 = wx + wy; \ - p3 = one - wx + wy; \ - p2 = wx + one - wy; \ - p1 = two - wx - wy; \ - \ - SDL_GetRGBA(sge_GetPixel(src, rx, ry), src->format, &R1, &G1, &B1, &A1); \ - SDL_GetRGBA(sge_GetPixel(src, rx + 1, ry), src->format, &R2, &G2, &B2, &A2); \ - SDL_GetRGBA(sge_GetPixel(src, rx, ry + 1), src->format, &R3, &G3, &B3, &A3); \ - SDL_GetRGBA(sge_GetPixel(src, rx + 1, ry + 1), src->format, &R4, &G4, &B4, &A4); \ - \ - /* Calculate the average */ \ - R = (p1 * R1 + p2 * R2 + p3 * R3 + p4 * R4) >> 13; \ - G = (p1 * G1 + p2 * G2 + p3 * G3 + p4 * G4) >> 13; \ - B = (p1 * B1 + p2 * B2 + p3 * B3 + p4 * B4) >> 13; \ - A = (p1 * A1 + p2 * A2 + p3 * A3 + p4 * A4) >> 13; \ - \ - _PutPixelX(dst, x, y, SDL_MapRGBA(dst->format, R, G, B, A)); \ - } \ - sx += ctx; /* Incremental transformations */ \ - sy -= sty; \ - } \ - } - -// We get better performance if AA and normal rendering is seperated into two functions (better optimization). -// sge_transform() is used as a wrapper. - -static SDL_Rect sge_transformNorm(SDL_Surface* src, SDL_Surface* dst, float angle, float xscale, float yscale, - Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags) -{ - Sint32 dy, sx, sy; - Sint16 x, y, rx, ry; - SDL_Rect r; - r.x = r.y = r.w = r.h = 0; - - auto theta = float(angle * M_PI / 180.0); /* Convert to radians. */ - - // Here we use 18.13 fixed point integer math - // Sint32 should have 31 usable bits and one for sign - // 2^13 = 8192 - - // Check scales - auto maxint = Sint32(pow(2, sizeof(Sint32) * 8 - 1 - 13)); // 2^(31-13) - - if(xscale == 0 || yscale == 0) - return r; - - if(8192.0 / xscale > maxint) - xscale = float(8192.0 / maxint); - else if(8192.0 / xscale < -maxint) - xscale = float(-8192.0 / maxint); - - if(8192.0 / yscale > maxint) - yscale = float(8192.0 / maxint); - else if(8192.0 / yscale < -maxint) - yscale = float(-8192.0 / maxint); - - // Fixed-point equivalents - auto const stx = Sint32((sin(theta) / xscale) * 8192.0); - auto const ctx = Sint32((cos(theta) / xscale) * 8192.0); - auto const sty = Sint32((sin(theta) / yscale) * 8192.0); - auto const cty = Sint32((cos(theta) / yscale) * 8192.0); - auto const mx = Sint32(px * 8192.0); - auto const my = Sint32(py * 8192.0); - - // Compute a bounding rectangle - Sint16 xmin = 0, xmax = dst->w, ymin = 0, ymax = dst->h; - _calcRect(src, dst, theta, xscale, yscale, px, py, qx, qy, &xmin, &ymin, &xmax, &ymax); - - // Clip to src surface - Sint16 sxmin = sge_clip_xmin(src); - Sint16 sxmax = sge_clip_xmax(src); - Sint16 symin = sge_clip_ymin(src); - Sint16 symax = sge_clip_ymax(src); - - // Some terms in the transform are constant - Sint32 const dx = xmin - qx; - Sint32 const ctdx = ctx * dx; - Sint32 const stdx = sty * dx; - - // Lock surfaces... hopfully less than two needs locking! - if(_sge_lock && SDL_MUSTLOCK(src)) - if(SDL_LockSurface(src) < 0) - return r; - if(_sge_lock && SDL_MUSTLOCK(dst)) - { - if(SDL_LockSurface(dst) < 0) - { - if(_sge_lock && SDL_MUSTLOCK(src)) - SDL_UnlockSurface(src); - return r; - } - } - - // Use the correct bpp - if(src->format->BytesPerPixel == dst->format->BytesPerPixel && src->format->BytesPerPixel != 3 - && !(flags & SGE_TSAFE)) - { - switch(src->format->BytesPerPixel) - { - case 1: - { /* Assuming 8-bpp */ - TRANSFORM(Uint8, 1) - } - break; - case 2: - { /* Probably 15-bpp or 16-bpp */ - TRANSFORM(Uint16, 2) - } - break; - case 4: - { /* Probably 32-bpp */ - TRANSFORM(Uint32, 4) - } - break; - } - } else - { - TRANSFORM_GENERIC - } - - // Unlock surfaces - if(_sge_lock && SDL_MUSTLOCK(src)) - SDL_UnlockSurface(src); - if(_sge_lock && SDL_MUSTLOCK(dst)) - SDL_UnlockSurface(dst); - - // Return the bounding rectangle - r.x = xmin; - r.y = ymin; - r.w = xmax - xmin; - r.h = ymax - ymin; - return r; -} - -static SDL_Rect sge_transformAA(SDL_Surface* src, SDL_Surface* dst, float angle, float xscale, float yscale, Uint16 px, - Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags) -{ - Sint32 dy, sx, sy; - Sint16 x, y, rx, ry; - SDL_Rect r; - r.x = r.y = r.w = r.h = 0; - - auto theta = float(angle * M_PI / 180.0); /* Convert to radians. */ - - // Here we use 18.13 fixed point integer math - // Sint32 should have 31 usable bits and one for sign - // 2^13 = 8192 - - // Check scales - auto maxint = Sint32(pow(2, sizeof(Sint32) * 8 - 1 - 13)); // 2^(31-13) - - if(xscale == 0 || yscale == 0) - return r; - - if(8192.0 / xscale > maxint) - xscale = float(8192.0 / maxint); - else if(8192.0 / xscale < -maxint) - xscale = float(-8192.0 / maxint); - - if(8192.0 / yscale > maxint) - yscale = float(8192.0 / maxint); - else if(8192.0 / yscale < -maxint) - yscale = float(-8192.0 / maxint); - - // Fixed-point equivalents - auto const stx = Sint32((sin(theta) / xscale) * 8192.0); - auto const ctx = Sint32((cos(theta) / xscale) * 8192.0); - auto const sty = Sint32((sin(theta) / yscale) * 8192.0); - auto const cty = Sint32((cos(theta) / yscale) * 8192.0); - auto const mx = Sint32(px * 8192.0); - auto const my = Sint32(py * 8192.0); - - // Compute a bounding rectangle - Sint16 xmin = 0, xmax = dst->w, ymin = 0, ymax = dst->h; - _calcRect(src, dst, theta, xscale, yscale, px, py, qx, qy, &xmin, &ymin, &xmax, &ymax); - - // Clip to src surface - Sint16 sxmin = sge_clip_xmin(src); - Sint16 sxmax = sge_clip_xmax(src); - Sint16 symin = sge_clip_ymin(src); - Sint16 symax = sge_clip_ymax(src); - - // Some terms in the transform are constant - Sint32 const dx = xmin - qx; - Sint32 const ctdx = ctx * dx; - Sint32 const stdx = sty * dx; - - // Lock surfaces... hopfully less than two needs locking! - if(_sge_lock && SDL_MUSTLOCK(src)) - if(SDL_LockSurface(src) < 0) - return r; - if(_sge_lock && SDL_MUSTLOCK(dst)) - { - if(SDL_LockSurface(dst) < 0) - { - if(_sge_lock && SDL_MUSTLOCK(src)) - SDL_UnlockSurface(src); - return r; - } - } - - // Use the correct bpp - if(src->format->BytesPerPixel == dst->format->BytesPerPixel && src->format->BytesPerPixel != 3 - && !(flags & SGE_TSAFE)) - { - switch(src->format->BytesPerPixel) - { - case 1: - { /* Assuming 8-bpp */ - // TRANSFORM_AA(Uint8, 1) - TRANSFORM_GENERIC_AA - } - break; - case 2: - { /* Probably 15-bpp or 16-bpp */ - TRANSFORM_AA(Uint16, 2) - } - break; - case 4: - { /* Probably 32-bpp */ - TRANSFORM_AA(Uint32, 4) - } - break; - } - } else - { - TRANSFORM_GENERIC_AA - } - - // Unlock surfaces - if(_sge_lock && SDL_MUSTLOCK(src)) - SDL_UnlockSurface(src); - if(_sge_lock && SDL_MUSTLOCK(dst)) - SDL_UnlockSurface(dst); - - // Return the bounding rectangle - r.x = xmin; - r.y = ymin; - r.w = xmax - xmin; - r.h = ymax - ymin; - return r; -} - -SDL_Rect sge_transform(SDL_Surface* src, SDL_Surface* dst, float angle, float xscale, float yscale, Uint16 px, - Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags) -{ - if(flags & SGE_TTMAP) - return sge_transform_tmap(src, dst, angle, xscale, yscale, qx, qy); - else - { - if(flags & SGE_TAA) - return sge_transformAA(src, dst, angle, xscale, yscale, px, py, qx, qy, flags); - else - return sge_transformNorm(src, dst, angle, xscale, yscale, px, py, qx, qy, flags); - } -} - -//================================================================================== -// Same as sge_transform() but returns an surface with the result -//================================================================================== -SDL_Surface* sge_transform_surface(SDL_Surface* src, Uint32 bcol, float angle, float xscale, float yscale, Uint8 flags) -{ - auto theta = float(angle * M_PI / 180.0); /* Convert to radians. */ - - // Compute a bounding rectangle - Sint16 xmin = 0, xmax = 0, ymin = 0, ymax = 0; - _calcRect(src, nullptr, theta, xscale, yscale, 0, 0, 0, 0, &xmin, &ymin, &xmax, &ymax); - - Sint16 w = xmax - xmin + 1; - Sint16 h = ymax - ymin + 1; - - Sint16 qx = -xmin; - Sint16 qy = -ymin; - - SDL_Surface* dest = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, src->format->BitsPerPixel, src->format->Rmask, - src->format->Gmask, src->format->Bmask, src->format->Amask); - if(!dest) - return nullptr; - - sge_ClearSurface(dest, bcol); // Set background color - - sge_transform(src, dest, angle, xscale, yscale, 0, 0, qx, qy, flags); - - return dest; -} - -//================================================================================== -// Rotate using texture mapping -//================================================================================== -SDL_Rect sge_transform_tmap(SDL_Surface* src, SDL_Surface* dst, float angle, float xscale, float yscale, Uint16 qx, - Uint16 qy) -{ - double rad; - double a = (sge_clip_xmax(src) - sge_clip_xmin(src)) / 2.0; - double b = (sge_clip_ymax(src) - sge_clip_ymin(src)) / 2.0; - - double cosv, sinv; - - // Get an exact value if possible - if(angle == 0.0 || angle == 360.0) - { - cosv = 1; - sinv = 0; - } else if(angle == 90.0) - { - cosv = 0; - sinv = 1; - } else if(angle == 180.0) - { - cosv = -1; - sinv = 0; - } else if(angle == 270.0) - { - cosv = 0; - sinv = -1; - } else - { // Oh well - rad = angle * (M_PI / 180.0); // Deg => rad - cosv = cos(rad); - sinv = sin(rad); - } - - // Precalculate as much as possible - double acosv = a * cosv * xscale, bcosv = b * cosv * yscale; - double asinv = a * sinv * xscale, bsinv = b * sinv * yscale; - - /* Do the maths */ - std::array xt, yt; - - xt[0] = Sint16((-acosv + bsinv) + qx); - yt[0] = Sint16((-asinv - bcosv) + qy); - - xt[1] = Sint16((acosv + bsinv) + qx); - yt[1] = Sint16((asinv - bcosv) + qy); - - xt[2] = Sint16((-acosv - bsinv) + qx); - yt[2] = Sint16((-asinv + bcosv) + qy); - - xt[3] = Sint16((acosv - bsinv) + qx); - yt[3] = Sint16((asinv + bcosv) + qy); - - // Use a texture mapped rectangle - sge_TexturedRect(dst, xt[0], yt[0], xt[1], yt[1], xt[2], yt[2], xt[3], yt[3], src, sge_clip_xmin(src), - sge_clip_ymin(src), sge_clip_xmax(src), sge_clip_ymin(src), sge_clip_xmin(src), sge_clip_ymax(src), - sge_clip_xmax(src), sge_clip_ymax(src)); - - // Or maybe two trigons... - // sge_TexturedTrigon(dest,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],src, sge_clip_xmin(src),sge_clip_ymin(src), - // sge_clip_xmax(src),sge_clip_ymin(src), sge_clip_xmin(src),sge_clip_ymax(src)); - // sge_TexturedTrigon(dest,xt[3],yt[3],xt[1],yt[1],xt[2],yt[2],src, sge_clip_xmax(src),sge_clip_ymax(src), - // sge_clip_xmax(src),sge_clip_ymin(src), sge_clip_xmin(src),sge_clip_ymax(src)); - - // For debug - // sge_Trigon(dest,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],SDL_MapRGB(dest->format,255,0,0)); - // sge_Trigon(dest,xt[3],yt[3],xt[1],yt[1],xt[2],yt[2],SDL_MapRGB(dest->format,0,255,0)); - - Sint16 xmax = xt[0], xmin = xt[0]; - xmax = (xmax > xt[1]) ? xmax : xt[1]; - xmin = (xmin < xt[1]) ? xmin : xt[1]; - xmax = (xmax > xt[2]) ? xmax : xt[2]; - xmin = (xmin < xt[2]) ? xmin : xt[2]; - xmax = (xmax > xt[3]) ? xmax : xt[3]; - xmin = (xmin < xt[3]) ? xmin : xt[3]; - - Sint16 ymax = yt[0], ymin = yt[0]; - ymax = (ymax > yt[1]) ? ymax : yt[1]; - ymin = (ymin < yt[1]) ? ymin : yt[1]; - ymax = (ymax > yt[2]) ? ymax : yt[2]; - ymin = (ymin < yt[2]) ? ymin : yt[2]; - ymax = (ymax > yt[3]) ? ymax : yt[3]; - ymin = (ymin < yt[3]) ? ymin : yt[3]; - - SDL_Rect r; - r.x = xmin; - r.y = ymin; - r.w = xmax - xmin + 1; - r.h = ymax - ymin + 1; - return r; -} diff --git a/SGE/sge_shape.cpp b/SGE/sge_shape.cpp deleted file mode 100644 index 1ad24aa..0000000 --- a/SGE/sge_shape.cpp +++ /dev/null @@ -1,573 +0,0 @@ -// Copyright (C) 2000 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * SGE shape - * - * Started 000430 - */ - -#include "sge_shape.h" -#include "sge_primitives.h" -#include "sge_surface.h" - -#ifndef _SGE_NO_CLASSES - -using namespace std; - -//================================================================================== -// sge_surface (derived from sge_shape) -// A class for moving/blitting surfaces -//================================================================================== -sge_surface::sge_surface(SDL_Surface* dest, SDL_Surface* src, Sint16 x, Sint16 y) -{ - surface = src; - sge_surface::dest = dest; - - current_pos.x = x; - current_pos.y = y; - current_pos.w = src->w; - current_pos.h = src->h; - last_pos.x = last_pos.y = last_pos.w = last_pos.h = 0; - prev_pos = last_pos; - - border.x = border.y = 0; - border.w = dest->w; - border.h = dest->h; - warp_border = false; -} - -sge_surface::~sge_surface() = default; - -bool sge_surface::check_warp() -{ - bool flag = false; - - if(warp_border) - { - if(current_pos.x + current_pos.w < border.x) - { - current_pos.x = border.x + border.w - current_pos.w; - flag = true; - } else if(current_pos.x > border.x + border.w) - { - current_pos.x = border.x; - flag = true; - } - if(current_pos.y + current_pos.h < border.y) - { - current_pos.y = border.y + border.h - current_pos.h; - flag = true; - } else if(current_pos.y > border.y + border.h) - { - current_pos.y = border.y; - flag = true; - } - } - return flag; -} - -int sge_surface::get_warp(SDL_Rect rec, SDL_Rect& r1, SDL_Rect& r2, SDL_Rect& r3, SDL_Rect& r4) const -{ - // We want to decode the pos rectangle into two or four rectangles. - - r1.x = r2.x = r3.x = r4.x = rec.x, r1.y = r2.y = r3.y = r4.y = rec.y; - r1.w = r2.w = r3.w = r4.w = rec.w, r1.h = r2.h = r3.h = r4.h = rec.h; - - int rects = 0; - - if(warp_border) - { - if(rec.x < border.x) - { - r1.w = border.x - rec.x; - r1.x = border.x + border.w - r1.w; - r2.w = abs(rec.w - r1.w); // SDL_Rect w/h is unsigned - r2.x = border.x; - rects = 2; - } else if(rec.x + rec.w > border.x + border.w) - { - r1.x = rec.x; - r1.w = border.x + border.w - rec.x; - r2.x = border.x; - r2.w = abs(rec.w - r1.w); - rects = 2; - } - - r3.x = r1.x; - r3.w = r1.w; - r4.x = r2.x; - r4.w = r2.w; - - if(rec.y < border.y) - { - if(rects == 0) - { - r1.h = border.y - rec.y; - r1.y = border.y + border.h - r1.h; - r2.h = abs(rec.h - r1.h); - r2.y = border.y; - rects = 2; - } else - { - r2.h = r1.h = border.y - rec.y; - r2.y = r1.y = border.y + border.h - r1.h; - r4.h = r3.h = abs(rec.h - r1.h); - r4.y = r3.y = border.y; - rects = 4; - } - } else if(rec.y + rec.h > border.y + border.h) - { - if(rects == 0) - { - r1.y = rec.y; - r1.h = border.y + border.h - rec.y; - r2.y = border.y; - r2.h = abs(rec.h - r1.h); - rects = 2; - } else - { - r2.y = r1.y = rec.y; - r2.h = r1.h = border.y + border.h - rec.y; - r4.y = r3.y = border.y; - r4.h = r3.h = abs(rec.h - r1.h); - rects = 4; - } - } - } - return rects; -} - -void sge_surface::warp_draw() -{ - SDL_Rect r1, r2, r3, r4; - int rects = get_warp(current_pos, r1, r2, r3, r4); - - if(rects == 2) - { - sge_Blit(surface, dest, 0, 0, r1.x, r1.y, r1.w, r1.h); - sge_Blit(surface, dest, surface->w - r2.w, surface->h - r2.h, r2.x, r2.y, r2.w, r2.h); - } else if(rects == 4) - { - sge_Blit(surface, dest, 0, 0, r1.x, r1.y, r1.w, r1.h); - sge_Blit(surface, dest, surface->w - r2.w, 0, r2.x, r2.y, r2.w, r2.h); - sge_Blit(surface, dest, 0, surface->h - r3.h, r3.x, r3.y, r3.w, r3.h); - sge_Blit(surface, dest, surface->w - r4.w, surface->h - r4.h, r4.x, r4.y, r4.w, r4.h); - } else - sge_Blit(surface, dest, 0, 0, current_pos.x, current_pos.y, surface->w, surface->h); -} - -void sge_surface::warp_clear(Uint32 color) -{ - SDL_Rect r1, r2, r3, r4; - int rects = get_warp(last_pos, r1, r2, r3, r4); - - if(rects > 0) - { - sge_FilledRect(dest, r1.x, r1.y, r1.x + r1.w - 1, r1.y + r1.h - 1, color); - sge_FilledRect(dest, r2.x, r2.y, r2.x + r2.w - 1, r2.y + r2.h - 1, color); - if(rects > 2) - { - sge_FilledRect(dest, r3.x, r3.y, r3.x + r3.w - 1, r3.y + r3.h - 1, color); - sge_FilledRect(dest, r4.x, r4.y, r4.x + r4.w - 1, r4.y + r4.h - 1, color); - } - } else - sge_FilledRect(dest, last_pos.x, last_pos.y, last_pos.x + last_pos.w - 1, last_pos.y + last_pos.h - 1, color); -} - -void sge_surface::warp_clear(SDL_Surface* src, Sint16 srcX, Sint16 srcY) -{ - SDL_Rect r1, r2, r3, r4; - int rects = get_warp(current_pos, r1, r2, r3, r4); - - if(rects > 0) - { - sge_Blit(src, dest, r1.x, r1.y, r1.x, r1.y, r1.w, r1.h); - sge_Blit(src, dest, r2.x, r2.y, r2.x, r2.y, r2.w, r2.h); - if(rects > 2) - { - sge_Blit(src, dest, r3.x, r3.y, r3.x, r3.y, r3.w, r3.h); - sge_Blit(src, dest, r4.x, r4.y, r4.x, r4.y, r4.w, r4.h); - } - } else - sge_Blit(src, dest, srcX, srcY, last_pos.x, last_pos.y, last_pos.w, last_pos.h); -} - -// Draws the surface -void sge_surface::draw() -{ - if(!surface) - return; - - current_pos.w = surface->w; - current_pos.h = surface->h; - - if(warp_border) - warp_draw(); - else - sge_Blit(surface, dest, 0, 0, current_pos.x, current_pos.y, surface->w, surface->h); - - prev_pos = last_pos; - last_pos = current_pos; -} - -void sge_surface::clear(Uint32 color) -{ - if(warp_border) - warp_clear(color); - else - sge_FilledRect(dest, last_pos.x, last_pos.y, last_pos.x + last_pos.w - 1, last_pos.y + last_pos.h - 1, color); -} - -void sge_surface::clear(SDL_Surface* src, Sint16 srcX, Sint16 srcY) -{ - if(warp_border) - warp_clear(src, srcX, srcY); - else - sge_Blit(src, dest, srcX, srcY, last_pos.x, last_pos.y, last_pos.w, last_pos.h); -} - -//================================================================================== -// sge_ssprite (derived from sge_surface) -// A simple sprite class -//================================================================================== -sge_ssprite::sge_ssprite(SDL_Surface* screen, SDL_Surface* img, Sint16 x, Sint16 y) : sge_surface(screen, img, x, y) -{ - // Create the first frame - current_frame = new sge_frame; // User has to catch bad_alloc himself - current_frame->img = img; - current_frame->cdata = nullptr; - frames.push_back(current_frame); - - current_fi = frames.begin(); - fi_start = current_fi; - fi_stop = frames.end(); - - // Default - xvel = yvel = 0; - seq_mode = stop; - - bounce_border = true; -} - -sge_ssprite::sge_ssprite(SDL_Surface* screen, SDL_Surface* img, sge_cdata* cdata, Sint16 x, Sint16 y) - : sge_surface(screen, img, x, y) -{ - // Create the first frame - current_frame = new sge_frame; // User has to catch bad_alloc himself - current_frame->img = img; - current_frame->cdata = cdata; - frames.push_back(current_frame); - - current_fi = frames.begin(); - fi_start = current_fi; - fi_stop = frames.end(); - - // Default - xvel = yvel = 0; - seq_mode = stop; - - bounce_border = true; -} - -sge_ssprite::~sge_ssprite() -{ - // Empty the list - for(auto* frame : frames) - delete frame; - - frames.clear(); -} - -bool sge_ssprite::check_border() -{ - if(!bounce_border) - return sge_surface::check_border(); - - bool flag = false; - - if(current_pos.x < border.x) - { - current_pos.x = border.x; - xvel = -xvel; - flag = true; - } - if(current_pos.x + current_pos.w > border.x + border.w) - { - current_pos.x = border.x + border.w - current_pos.w; - xvel = -xvel; - flag = true; - } - if(current_pos.y < border.y) - { - current_pos.y = border.y; - yvel = -yvel; - flag = true; - } - if(current_pos.y + current_pos.h > border.y + border.h) - { - current_pos.y = border.y + border.h - current_pos.h; - yvel = -yvel; - flag = true; - } - return flag; -} - -void sge_ssprite::add_frame(SDL_Surface* img) -{ - add_frame(img, nullptr); -} - -void sge_ssprite::add_frame(SDL_Surface* img, sge_cdata* cdata) -{ - // Create a new frame - auto* frame = new sge_frame; // User has to catch bad_alloc himself - frame->img = img; - frame->cdata = cdata; - frames.push_back(frame); - - fi_start = frames.begin(); - fi_stop = frames.end(); - - seq_mode = loop; -} - -void sge_ssprite::skip_frame(int skips) -{ - if(skips > 0) - { - for(int i = 0; i < skips; i++) - { - ++current_fi; - if(current_fi == fi_stop) - { - if(seq_mode != play_once) - current_fi = fi_start; // loop - else - { // stop - seq_mode = stop; - --current_fi; // current_fi = fi_stop -1 - fi_start = current_fi; - } - } - } - } else if(skips < 0) - { - for(int i = 0; i > skips; i--) - { - if(current_fi == fi_start) - { - if(seq_mode != play_once) - current_fi = fi_stop; // loop - else - { // stop - seq_mode = stop; - ++current_fi; //+1 - fi_stop = current_fi; - } - } - --current_fi; - } - } else - return; - - current_frame = *current_fi; - surface = current_frame->img; - current_pos.w = surface->w; - current_pos.h = surface->h; -} - -bool sge_ssprite::update() -{ - move(xvel, yvel); - return (xvel != 0) || (yvel != 0); -} - -void sge_ssprite::set_seq(int start, int stop, playing_mode mode) -{ - // Handle stupid user errors - if(start < 0 || start > int(frames.size()) - 1) - return; - if(stop < start || stop > int(frames.size()) - 1) - return; - - seq_mode = loop; - if(mode == play_once) - seq_mode = play_once; - if(start == stop) - seq_mode = sge_ssprite::stop; - - fi_start = fi_stop = frames.begin(); - - for(int i = 0; i <= stop; i++) - { - if(i < start) - ++fi_start; - - ++fi_stop; - - if(fi_stop == frames.end()) - { - if(fi_start == frames.end()) - --fi_start; - break; - } - } - - current_fi = fi_start; - - current_frame = *current_fi; - surface = current_frame->img; - current_pos.w = surface->w; - current_pos.h = surface->h; -} - -void sge_ssprite::reset_seq() -{ - fi_start = frames.begin(); - fi_stop = frames.end(); - - current_fi = fi_start; - - current_frame = *current_fi; - surface = current_frame->img; - current_pos.w = surface->w; - current_pos.h = surface->h; - - if(frames.size() > 1) - seq_mode = loop; - else - seq_mode = stop; -} - -void sge_ssprite::first_frame() -{ - current_fi = fi_start; - - current_frame = *current_fi; - surface = current_frame->img; - current_pos.w = surface->w; - current_pos.h = surface->h; -} - -void sge_ssprite::last_frame() -{ - current_fi = fi_stop; - --current_fi; - - current_frame = *current_fi; - surface = current_frame->img; - current_pos.w = surface->w; - current_pos.h = surface->h; -} - -//================================================================================== -// sge_sprite (derived from sge_ssprite) -// A timed sprite class -//================================================================================== -bool sge_sprite::update(Uint32 ticks) -{ - if(tlast == 0) - { - tlast = ticks; - return false; - } - - Sint16 tmp; - Uint32 time = ticks - tlast; - tlast = ticks; // Reset time - - bool ret = false; - - // Calculate new pos - if(xppms != 0) - { - xpos += time * xppms; - tmp = int(xpos); - if(current_pos.x != tmp) - { - current_pos.x = tmp; - ret = true; - } - } - if(yppms != 0) - { - ypos += time * yppms; - tmp = int(ypos); - if(current_pos.y != tmp) - { - current_pos.y = tmp; - ret = true; - } - } - - if(ret) // Are we off-screen? - check_border(); - - // Calculate new frame - if(fpms != 0) - { - fpos += time * fpms; - tmp = int(fpos); - if(tmp != 0) - { - skip_frame(tmp); - fpos -= tmp; - ret = true; - } - } - - return ret; -} - -bool sge_sprite::check_border() -{ - if(warp_border) - { - if(sge_surface::check_warp()) - { - xpos = current_pos.x; - ypos = current_pos.y; - return true; - } - return false; - } - if(!bounce_border) - return false; - - bool flag = false; - - if(current_pos.x < border.x) - { - current_pos.x = border.x; - xpos = current_pos.x; - xppms = -xppms; - flag = true; - } else if(current_pos.x + current_pos.w > border.x + border.w) - { - current_pos.x = border.x + border.w - current_pos.w; - xpos = current_pos.x; - xppms = -xppms; - flag = true; - } - if(current_pos.y < border.y) - { - current_pos.y = border.y; - ypos = current_pos.y; - yppms = -yppms; - flag = true; - } else if(current_pos.y + current_pos.h > border.y + border.h) - { - current_pos.y = border.y + border.h - current_pos.h; - ypos = current_pos.y; - yppms = -yppms; - flag = true; - } - return flag; -} - -#endif /* _SGE_NO_CLASSES */ diff --git a/SGE/sge_surface.cpp b/SGE/sge_surface.cpp deleted file mode 100644 index 6f288b6..0000000 --- a/SGE/sge_surface.cpp +++ /dev/null @@ -1,723 +0,0 @@ -// Copyright (C) 1999 - 2003 Anders Lindström -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -/* - * SDL Graphics Extension - * Pixel, surface and color functions - * - * Started 990815 (split from sge_draw 010611) - */ - -/* - * Some of this code is taken from the "Introduction to SDL" and - * John Garrison's PowerPak - */ - -#include "sge_surface.h" -#include -#include -#include - -/* Globals used for sge_Lock */ -Uint8 _sge_lock = 1; - -/**********************************************************************************/ -/** Misc. functions **/ -/**********************************************************************************/ - -//================================================================================== -// Turns off automatic locking of surfaces -//================================================================================== -void sge_Lock_OFF() -{ - _sge_lock = 0; -} - -//================================================================================== -// Turns on automatic locking (default) -//================================================================================== -void sge_Lock_ON() -{ - _sge_lock = 1; -} - -//================================================================================== -// Returns locking mode (1-on and 0-off) -//================================================================================== -Uint8 sge_getLock() -{ - return _sge_lock; -} - -//================================================================================== -// Creates a 32bit (8/8/8/8) alpha surface -// Map colors with sge_MapAlpha() and then use the Uint32 color versions of -// SGEs routines -//================================================================================== -SDL_Surface* sge_CreateAlphaSurface(Uint32 flags, int width, int height) -{ - return SDL_CreateRGBSurface(flags, width, height, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); -} - -//================================================================================== -// Returns the Uint32 color value for a 32bit (8/8/8/8) alpha surface -//================================================================================== -Uint32 sge_MapAlpha(Uint8 R, Uint8 G, Uint8 B, Uint8 A) -{ - Uint32 color = 0; - - color |= R << 24; - color |= G << 16; - color |= B << 8; - color |= A; - - return color; -} - -/**********************************************************************************/ -/** Pixel functions **/ -/**********************************************************************************/ - -//================================================================================== -// Fast put pixel -//================================================================================== -void _PutPixel(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color) -{ - if(x >= sge_clip_xmin(surface) && x <= sge_clip_xmax(surface) && y >= sge_clip_ymin(surface) - && y <= sge_clip_ymax(surface)) - { - switch(surface->format->BytesPerPixel) - { - case 1: - { /* Assuming 8-bpp */ - *((Uint8*)surface->pixels + y * surface->pitch + x) = color; - } - break; - - case 2: - { /* Probably 15-bpp or 16-bpp */ - *((Uint16*)surface->pixels + y * surface->pitch / 2 + x) = color; - } - break; - - case 3: - { /* Slow 24-bpp mode, usually not used */ - Uint8* pix = (Uint8*)surface->pixels + y * surface->pitch + x * 3; - - /* Gack - slow, but endian correct */ - *(pix + surface->format->Rshift / 8) = color >> surface->format->Rshift; - *(pix + surface->format->Gshift / 8) = color >> surface->format->Gshift; - *(pix + surface->format->Bshift / 8) = color >> surface->format->Bshift; - *(pix + surface->format->Ashift / 8) = color >> surface->format->Ashift; - } - break; - - case 4: - { /* Probably 32-bpp */ - *((Uint32*)surface->pixels + y * surface->pitch / 4 + x) = color; - } - break; - } - } -} - -//================================================================================== -// Fast put pixel (RGB) -//================================================================================== -void _PutPixel(SDL_Surface* surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B) -{ - _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B)); -} - -//================================================================================== -// Fastest put pixel functions (don't mess up indata, thank you) -//================================================================================== -void _PutPixel8(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color) -{ - *((Uint8*)surface->pixels + y * surface->pitch + x) = color; -} -void _PutPixel16(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color) -{ - *((Uint16*)surface->pixels + y * surface->pitch / 2 + x) = color; -} -void _PutPixel24(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color) -{ - Uint8* pix = (Uint8*)surface->pixels + y * surface->pitch + x * 3; - - /* Gack - slow, but endian correct */ - *(pix + surface->format->Rshift / 8) = color >> surface->format->Rshift; - *(pix + surface->format->Gshift / 8) = color >> surface->format->Gshift; - *(pix + surface->format->Bshift / 8) = color >> surface->format->Bshift; - *(pix + surface->format->Ashift / 8) = color >> surface->format->Ashift; -} -void _PutPixel32(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color) -{ - *((Uint32*)surface->pixels + y * surface->pitch / 4 + x) = color; -} -void _PutPixelX(SDL_Surface* dest, Sint16 x, Sint16 y, Uint32 color) -{ - switch(dest->format->BytesPerPixel) - { - case 1: *((Uint8*)dest->pixels + y * dest->pitch + x) = color; break; - case 2: *((Uint16*)dest->pixels + y * dest->pitch / 2 + x) = color; break; - case 3: _PutPixel24(dest, x, y, color); break; - case 4: *((Uint32*)dest->pixels + y * dest->pitch / 4 + x) = color; break; - } -} - -//================================================================================== -// Safe put pixel -//================================================================================== -void sge_PutPixel(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color) -{ - if(_sge_lock && SDL_MUSTLOCK(surface)) - { - if(SDL_LockSurface(surface) < 0) - { - return; - } - } - - _PutPixel(surface, x, y, color); - - if(_sge_lock && SDL_MUSTLOCK(surface)) - { - SDL_UnlockSurface(surface); - } -} - -//================================================================================== -// Safe put pixel (RGB) -//================================================================================== -void sge_PutPixel(SDL_Surface* surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B) -{ - sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B)); -} - -//================================================================================== -// Calculate y pitch offset -// (the y pitch offset is constant for the same y coord and surface) -//================================================================================== -Sint32 sge_CalcYPitch(SDL_Surface* dest, Sint16 y) -{ - if(y >= sge_clip_ymin(dest) && y <= sge_clip_ymax(dest)) - { - switch(dest->format->BytesPerPixel) - { - case 1: return y * dest->pitch; break; - case 2: return y * dest->pitch / 2; break; - case 3: return y * dest->pitch; break; - case 4: return y * dest->pitch / 4; break; - } - } - - return -1; -} - -//================================================================================== -// Put pixel with precalculated y pitch offset -//================================================================================== -void sge_pPutPixel(SDL_Surface* surface, Sint16 x, Sint32 ypitch, Uint32 color) -{ - if(x >= sge_clip_xmin(surface) && x <= sge_clip_xmax(surface) && ypitch >= 0) - { - switch(surface->format->BytesPerPixel) - { - case 1: - { /* Assuming 8-bpp */ - *((Uint8*)surface->pixels + ypitch + x) = color; - } - break; - - case 2: - { /* Probably 15-bpp or 16-bpp */ - *((Uint16*)surface->pixels + ypitch + x) = color; - } - break; - - case 3: - { /* Slow 24-bpp mode, usually not used */ - /* Gack - slow, but endian correct */ - Uint8* pix = (Uint8*)surface->pixels + ypitch + x * 3; - - *(pix + surface->format->Rshift / 8) = color >> surface->format->Rshift; - *(pix + surface->format->Gshift / 8) = color >> surface->format->Gshift; - *(pix + surface->format->Bshift / 8) = color >> surface->format->Bshift; - *(pix + surface->format->Ashift / 8) = color >> surface->format->Ashift; - } - break; - - case 4: - { /* Probably 32-bpp */ - *((Uint32*)surface->pixels + ypitch + x) = color; - } - break; - } - } -} - -//================================================================================== -// Get pixel -//================================================================================== -Uint32 sge_GetPixel(SDL_Surface* surface, Sint16 x, Sint16 y) -{ - if(x < 0 || x >= surface->w || y < 0 || y >= surface->h) - return 0; - - switch(surface->format->BytesPerPixel) - { - case 1: - { /* Assuming 8-bpp */ - return *((Uint8*)surface->pixels + y * surface->pitch + x); - } - break; - - case 2: - { /* Probably 15-bpp or 16-bpp */ - return *((Uint16*)surface->pixels + y * surface->pitch / 2 + x); - } - break; - - case 3: - { /* Slow 24-bpp mode, usually not used */ - Uint8* pix; - int shift; - Uint32 color = 0; - - pix = (Uint8*)surface->pixels + y * surface->pitch + x * 3; - shift = surface->format->Rshift; - color = *(pix + shift / 8) << shift; - shift = surface->format->Gshift; - color |= *(pix + shift / 8) << shift; - shift = surface->format->Bshift; - color |= *(pix + shift / 8) << shift; - shift = surface->format->Ashift; - color |= *(pix + shift / 8) << shift; - return color; - } - break; - - case 4: - { /* Probably 32-bpp */ - return *((Uint32*)surface->pixels + y * surface->pitch / 4 + x); - } - break; - } - return 0; -} - -//================================================================================== -// Put pixel with alpha blending -//================================================================================== -void _PutPixelAlpha(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha) -{ - if(x >= sge_clip_xmin(surface) && x <= sge_clip_xmax(surface) && y >= sge_clip_ymin(surface) - && y <= sge_clip_ymax(surface)) - { - Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, - Amask = surface->format->Amask; - Uint32 R, G, B, A = 0; - - switch(surface->format->BytesPerPixel) - { - case 1: - { /* Assuming 8-bpp */ - if(alpha == 255) - { - *((Uint8*)surface->pixels + y * surface->pitch + x) = color; - } else - { - Uint8* pixel = (Uint8*)surface->pixels + y * surface->pitch + x; - - Uint8 dR = surface->format->palette->colors[*pixel].r; - Uint8 dG = surface->format->palette->colors[*pixel].g; - Uint8 dB = surface->format->palette->colors[*pixel].b; - Uint8 sR = surface->format->palette->colors[color].r; - Uint8 sG = surface->format->palette->colors[color].g; - Uint8 sB = surface->format->palette->colors[color].b; - - dR = dR + (((sR - dR) * alpha) >> 8); - dG = dG + (((sG - dG) * alpha) >> 8); - dB = dB + (((sB - dB) * alpha) >> 8); - - *pixel = SDL_MapRGB(surface->format, dR, dG, dB); - } - } - break; - - case 2: - { /* Probably 15-bpp or 16-bpp */ - if(alpha == 255) - { - *((Uint16*)surface->pixels + y * surface->pitch / 2 + x) = color; - } else - { - Uint16* pixel = (Uint16*)surface->pixels + y * surface->pitch / 2 + x; - Uint32 dc = *pixel; - - R = ((dc & Rmask) + ((((color & Rmask) - (dc & Rmask)) * alpha) >> 8)) & Rmask; - G = ((dc & Gmask) + ((((color & Gmask) - (dc & Gmask)) * alpha) >> 8)) & Gmask; - B = ((dc & Bmask) + ((((color & Bmask) - (dc & Bmask)) * alpha) >> 8)) & Bmask; - if(Amask) - A = ((dc & Amask) + ((((color & Amask) - (dc & Amask)) * alpha) >> 8)) & Amask; - - *pixel = R | G | B | A; - } - } - break; - - case 3: - { /* Slow 24-bpp mode, usually not used */ - Uint8* pix = (Uint8*)surface->pixels + y * surface->pitch + x * 3; - Uint8 rshift8 = surface->format->Rshift / 8; - Uint8 gshift8 = surface->format->Gshift / 8; - Uint8 bshift8 = surface->format->Bshift / 8; - Uint8 ashift8 = surface->format->Ashift / 8; - - if(alpha == 255) - { - *(pix + rshift8) = color >> surface->format->Rshift; - *(pix + gshift8) = color >> surface->format->Gshift; - *(pix + bshift8) = color >> surface->format->Bshift; - *(pix + ashift8) = color >> surface->format->Ashift; - } else - { - Uint8 dR, dG, dB, dA = 0; - Uint8 sR, sG, sB, sA = 0; - - pix = (Uint8*)surface->pixels + y * surface->pitch + x * 3; - - dR = *((pix) + rshift8); - dG = *((pix) + gshift8); - dB = *((pix) + bshift8); - dA = *((pix) + ashift8); - - sR = (color >> surface->format->Rshift) & 0xff; - sG = (color >> surface->format->Gshift) & 0xff; - sB = (color >> surface->format->Bshift) & 0xff; - sA = (color >> surface->format->Ashift) & 0xff; - - dR = dR + (((sR - dR) * alpha) >> 8); - dG = dG + (((sG - dG) * alpha) >> 8); - dB = dB + (((sB - dB) * alpha) >> 8); - dA = dA + (((sA - dA) * alpha) >> 8); - - *((pix) + rshift8) = dR; - *((pix) + gshift8) = dG; - *((pix) + bshift8) = dB; - *((pix) + ashift8) = dA; - } - } - break; - - case 4: - { /* Probably 32-bpp */ - if(alpha == 255) - { - *((Uint32*)surface->pixels + y * surface->pitch / 4 + x) = color; - } else - { - Uint32* pixel = (Uint32*)surface->pixels + y * surface->pitch / 4 + x; - Uint32 dc = *pixel; - - R = ((dc & Rmask) + ((((color & Rmask) - (dc & Rmask)) * alpha) >> 8)) & Rmask; - G = ((dc & Gmask) + ((((color & Gmask) - (dc & Gmask)) * alpha) >> 8)) & Gmask; - B = ((dc & Bmask) + ((((color & Bmask) - (dc & Bmask)) * alpha) >> 8)) & Bmask; - if(Amask) - A = ((dc & Amask) + ((((color & Amask) - (dc & Amask)) * alpha) >> 8)) & Amask; - - *pixel = R | G | B | A; - } - } - break; - } - } -} - -void sge_PutPixelAlpha(SDL_Surface* surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha) -{ - if(_sge_lock && SDL_MUSTLOCK(surface)) - if(SDL_LockSurface(surface) < 0) - return; - - _PutPixelAlpha(surface, x, y, color, alpha); - - /* unlock the display */ - if(_sge_lock && SDL_MUSTLOCK(surface)) - { - SDL_UnlockSurface(surface); - } -} - -void _PutPixelAlpha(SDL_Surface* surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha) -{ - _PutPixelAlpha(surface, x, y, SDL_MapRGB(surface->format, R, G, B), alpha); -} -void sge_PutPixelAlpha(SDL_Surface* surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha) -{ - sge_PutPixelAlpha(surface, x, y, SDL_MapRGB(surface->format, R, G, B), alpha); -} - -/**********************************************************************************/ -/** Block functions **/ -/**********************************************************************************/ - -//================================================================================== -// The sge_write_block* functions copies the given block (a surface line) directly -// to the surface. This is *much* faster then using the put pixel functions to -// update a line. The block consist of Surface->w (the width of the surface) numbers -// of color values. Note the difference in byte size for the block elements for -// different color dephts. 24 bpp is slow and not included! -//================================================================================== -void sge_write_block8(SDL_Surface* Surface, Uint8* block, Sint16 y) -{ - memcpy((Uint8*)Surface->pixels + y * Surface->pitch, block, sizeof(Uint8) * Surface->w); -} -void sge_write_block16(SDL_Surface* Surface, Uint16* block, Sint16 y) -{ - memcpy((Uint16*)Surface->pixels + y * Surface->pitch / 2, block, sizeof(Uint16) * Surface->w); -} -void sge_write_block32(SDL_Surface* Surface, Uint32* block, Sint16 y) -{ - memcpy((Uint32*)Surface->pixels + y * Surface->pitch / 4, block, sizeof(Uint32) * Surface->w); -} - -//================================================================================== -// ...and get -//================================================================================== -void sge_read_block8(SDL_Surface* Surface, Uint8* block, Sint16 y) -{ - memcpy(block, (Uint8*)Surface->pixels + y * Surface->pitch, sizeof(Uint8) * Surface->w); -} -void sge_read_block16(SDL_Surface* Surface, Uint16* block, Sint16 y) -{ - memcpy(block, (Uint16*)Surface->pixels + y * Surface->pitch / 2, sizeof(Uint16) * Surface->w); -} -void sge_read_block32(SDL_Surface* Surface, Uint32* block, Sint16 y) -{ - memcpy(block, (Uint32*)Surface->pixels + y * Surface->pitch / 4, sizeof(Uint32) * Surface->w); -} - -/**********************************************************************************/ -/** Blitting/surface functions **/ -/**********************************************************************************/ - -//================================================================================== -// Clear surface to color -//================================================================================== -void sge_ClearSurface(SDL_Surface* Surface, Uint32 color) -{ - SDL_FillRect(Surface, nullptr, color); -} - -//================================================================================== -// Clear surface to color (RGB) -//================================================================================== -void sge_ClearSurface(SDL_Surface* Surface, Uint8 R, Uint8 G, Uint8 B) -{ - sge_ClearSurface(Surface, SDL_MapRGB(Surface->format, R, G, B)); -} - -//================================================================================== -// Blit from one surface to another -// Warning! Alpha and color key is lost (=0) on Src surface -//================================================================================== -int sge_BlitTransparent(SDL_Surface* Src, SDL_Surface* Dest, Sint16 SrcX, Sint16 SrcY, Sint16 DestX, Sint16 DestY, - Sint16 W, Sint16 H, Uint32 Clear, Uint8 Alpha) -{ - SDL_Rect src, dest; - int ret; - - /* Initialize our rectangles */ - src.x = SrcX; - src.y = SrcY; - src.w = W; - src.h = H; - - dest.x = DestX; - dest.y = DestY; - dest.w = W; - dest.h = H; - - /* Set the color to be transparent */ - SDL_SetColorKey(Src, SDL_TRUE, Clear); - - /* Set the alpha value */ - Uint8 oldAlpha; - SDL_GetSurfaceAlphaMod(Src, &oldAlpha); - SDL_SetSurfaceAlphaMod(Src, Alpha); - - /* Blit */ - ret = SDL_BlitSurface(Src, &src, Dest, &dest); - - /* Set normal levels */ - SDL_SetSurfaceAlphaMod(Src, oldAlpha); - SDL_SetColorKey(Src, SDL_FALSE, 0); - - return ret; -} - -//================================================================================== -// Blit from one surface to another (not touching alpha or color key - -// use SDL_SetColorKey and SDL_SetAlpha) -//================================================================================== -int sge_Blit(SDL_Surface* Src, SDL_Surface* Dest, Sint16 SrcX, Sint16 SrcY, Sint16 DestX, Sint16 DestY, Sint16 W, - Sint16 H) -{ - SDL_Rect src, dest; - int ret; - - /* Initialize our rectangles */ - src.x = SrcX; - src.y = SrcY; - src.w = W; - src.h = H; - - dest.x = DestX; - dest.y = DestY; - dest.w = W; - dest.h = H; - - /* Blit */ - ret = SDL_BlitSurface(Src, &src, Dest, &dest); - - return ret; -} - -//================================================================================== -// Copies a surface to a new... -//================================================================================== -SDL_Surface* sge_copy_surface(SDL_Surface* src) -{ - return SDL_ConvertSurface(src, src->format, SDL_SWSURFACE); -} - -/**********************************************************************************/ -/** Palette functions **/ -/**********************************************************************************/ -//================================================================================== -// Fill in a palette entry with R, G, B componenets -//================================================================================== -SDL_Color sge_FillPaletteEntry(Uint8 R, Uint8 G, Uint8 B) -{ - SDL_Color color; - - color.r = R; - color.g = G; - color.b = B; - color.a = 0; - - return color; -} - -//================================================================================== -// Get the RGB of a color value -// Needed in those dark days before SDL 1.0 -//================================================================================== -SDL_Color sge_GetRGB(SDL_Surface* Surface, Uint32 Color) -{ - SDL_Color rgb; - SDL_GetRGB(Color, Surface->format, &(rgb.r), &(rgb.g), &(rgb.b)); - - return (rgb); -} - -//================================================================================== -// Fades from (sR,sG,sB) to (dR,dG,dB), puts result in ctab[start] to ctab[stop] -//================================================================================== -void sge_Fader(SDL_Surface* Surface, Uint8 sR, Uint8 sG, Uint8 sB, Uint8 dR, Uint8 dG, Uint8 dB, Uint32* ctab, - int start, int stop) -{ - // (sR,sG,sB) and (dR,dG,dB) are two points in space (the RGB cube). - - /* The vector for the straight line */ - std::array v; - v[0] = dR - sR; - v[1] = dG - sG; - v[2] = dB - sB; - - /* Ref. point */ - int x0 = sR, y0 = sG, z0 = sB; - - // The line's equation is: - // x= x0 + v[0] * t - // y= y0 + v[1] * t - // z= z0 + v[2] * t - // - // (x,y,z) will travel between the two points when t goes from 0 to 1. - - int i = start; - double step = 1.0 / ((stop + 1) - start); - - for(double t = 0.0; t <= 1.0 && i <= stop; t += step) - { - ctab[i++] = SDL_MapRGB(Surface->format, (Uint8)(x0 + v[0] * t), (Uint8)(y0 + v[1] * t), (Uint8)(z0 + v[2] * t)); - } -} - -//================================================================================== -// Fades from (sR,sG,sB,sA) to (dR,dG,dB,dA), puts result in ctab[start] to ctab[stop] -//================================================================================== -void sge_AlphaFader(Uint8 sR, Uint8 sG, Uint8 sB, Uint8 sA, Uint8 dR, Uint8 dG, Uint8 dB, Uint8 dA, Uint32* ctab, - int start, int stop) -{ - // (sR,sG,sB,sA) and (dR,dG,dB,dA) are two points in hyperspace (the RGBA hypercube). - - /* The vector for the straight line */ - std::array v; - v[0] = dR - sR; - v[1] = dG - sG; - v[2] = dB - sB; - v[3] = dA - sA; - - /* Ref. point */ - int x0 = sR, y0 = sG, z0 = sB, w0 = sA; - - // The line's equation is: - // x= x0 + v[0] * t - // y= y0 + v[1] * t - // z= z0 + v[2] * t - // w= w0 + v[3] * t - // - // (x,y,z,w) will travel between the two points when t goes from 0 to 1. - - int i = start; - double step = 1.0 / ((stop + 1) - start); - - for(double t = 0.0; t <= 1.0 && i <= stop; t += step) - ctab[i++] = - sge_MapAlpha((Uint8)(x0 + v[0] * t), (Uint8)(y0 + v[1] * t), (Uint8)(z0 + v[2] * t), (Uint8)(w0 + v[3] * t)); -} - -//================================================================================== -// Copies a nice rainbow palette to the color table (ctab[start] to ctab[stop]). -// You must also set the intensity of the palette (0-bright 255-dark) -//================================================================================== -void sge_SetupRainbowPalette(SDL_Surface* Surface, Uint32* ctab, int intensity, int start, int stop) -{ - auto slice = (int)((stop - start) / 6); - - /* Red-Yellow */ - sge_Fader(Surface, 255, intensity, intensity, 255, 255, intensity, ctab, start, slice); - /* Yellow-Green */ - sge_Fader(Surface, 255, 255, intensity, intensity, 255, intensity, ctab, slice + 1, 2 * slice); - /* Green-Turquoise blue */ - sge_Fader(Surface, intensity, 255, intensity, intensity, 255, 255, ctab, 2 * slice + 1, 3 * slice); - /* Turquoise blue-Blue */ - sge_Fader(Surface, intensity, 255, 255, intensity, intensity, 255, ctab, 3 * slice + 1, 4 * slice); - /* Blue-Purple */ - sge_Fader(Surface, intensity, intensity, 255, 255, intensity, 255, ctab, 4 * slice + 1, 5 * slice); - /* Purple-Red */ - sge_Fader(Surface, 255, intensity, 255, 255, intensity, intensity, ctab, 5 * slice + 1, stop); -} - -//================================================================================== -// Copies a B&W palette to the color table (ctab[start] to ctab[stop]). -//================================================================================== -void sge_SetupBWPalette(SDL_Surface* Surface, Uint32* ctab, int start, int stop) -{ - sge_Fader(Surface, 0, 0, 0, 255, 255, 255, ctab, start, stop); -} diff --git a/Texture.cpp b/Texture.cpp index bac0849..b0b5464 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -7,6 +7,8 @@ #include "globals.h" #include #include +#include +#include #include #include @@ -78,6 +80,36 @@ bool Texture::load(SDL_Surface* surface, bool filterLinear) const bool hasCK = SDL_GetColorKey(surface, &ck) == 0; const Uint8 ckIdx = hasCK ? static_cast(ck & 0xFF) : 0; + // Water color keys used by the ice floe rendering (two-pass alpha test). + // These are the RGB values decoded from the old 32-bit SGE colorkeys + // that were used to punch holes in the snow/swamp texture so that + // the animated water underneath shows through. + static constexpr std::array kWaterColorKeys = {{ + {0, 55, 111, 0}, + {0, 55, 115, 0}, + {0, 51, 111, 0}, + {0, 51, 103, 0}, + {0, 43, 111, 0}, + }}; + + // Build set of transparent palette indices. + // Start with the SDL colorkey (if any), then add any palette entries + // that match the water color keys. + std::set transparentIdxs; + if(hasCK) + transparentIdxs.insert(ckIdx); + for(const auto& key : kWaterColorKeys) + { + for(int i = 0; i < 256; i++) + { + if(pal->colors[i].r == key.r && pal->colors[i].g == key.g && pal->colors[i].b == key.b) + { + transparentIdxs.insert(static_cast(i)); + break; + } + } + } + SDL_LockSurface(surface); for(int row = 0; row < h; row++) { @@ -85,7 +117,7 @@ bool Texture::load(SDL_Surface* surface, bool filterLinear) for(int col = 0; col < w; col++) { const Uint8 idx = src[col]; - if(hasCK && idx == ckIdx) + if(transparentIdxs.count(idx)) pixels[row * w + col] = 0; // transparent else { @@ -101,24 +133,9 @@ bool Texture::load(SDL_Surface* surface, bool filterLinear) return true; } - // 32-bit surface: convert to destination format (BGRA), force full opacity - SDL_Surface* converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0); - if(!converted) - return false; - - // Force alpha to opaque (LBM palette entries often have alpha=0) - SDL_LockSurface(converted); - for(int y = 0; y < converted->h; y++) - { - auto* row = (Uint32*)((Uint8*)converted->pixels + y * converted->pitch); - for(int x = 0; x < converted->w; x++) - row[x] |= 0xFF000000u; - } - SDL_UnlockSurface(converted); - - load(converted->pixels, Extent(converted->w, converted->h), filterLinear); - SDL_FreeSurface(converted); - return true; + // Only 8-bit paletted surfaces are used (LBM files). + // 32-bit surfaces are not expected from any current caller. + return false; } void Texture::draw(const Rect& destRect) const @@ -126,6 +143,7 @@ void Texture::draw(const Rect& destRect) const if(!texture_) return; + glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); glTexCoord2f(0, 0); @@ -144,6 +162,7 @@ void Texture::draw(Position pos) const if(!texture_) return; + glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); glTexCoord2f(0, 0); @@ -190,6 +209,38 @@ void Texture::drawTiled(const Rect& destRect) const glEnd(); } +void Texture::draw(const Rect& destRect, const Rect& srcRect) const +{ + if(!texture_) + return; + + // Clamp source rect to texture bounds + int srcL = std::max(0, srcRect.left); + int srcT = std::max(0, srcRect.top); + int srcR = std::min(static_cast(size_.x), srcRect.right); + int srcB = std::min(static_cast(size_.y), srcRect.bottom); + if(srcL >= srcR || srcT >= srcB) + return; + + const float u0 = float(srcL) / float(size_.x); + const float v0 = float(srcT) / float(size_.y); + const float u1 = float(srcR) / float(size_.x); + const float v1 = float(srcB) / float(size_.y); + + glColor4f(1, 1, 1, 1); + glBindTexture(GL_TEXTURE_2D, texture_); + glBegin(GL_QUADS); + glTexCoord2f(u0, v0); + glVertex2i(destRect.left, destRect.top); + glTexCoord2f(u1, v0); + glVertex2i(destRect.right, destRect.top); + glTexCoord2f(u1, v1); + glVertex2i(destRect.right, destRect.bottom); + glTexCoord2f(u0, v1); + glVertex2i(destRect.left, destRect.bottom); + glEnd(); +} + void drawRect(const Rect& rect, unsigned color) { glDisable(GL_TEXTURE_2D); @@ -204,28 +255,14 @@ void drawRect(const Rect& rect, unsigned color) glColor4f(1, 1, 1, 1); } -Texture& getBmpTexture(unsigned idx, bool filterLinear) +Texture& getBmpTexture(int idx, bool filterLinear) { - static std::vector cache; - static std::vector linearFlags; - if(idx >= global::bmpArray.size()) + if(idx < 0 || static_cast(idx) >= global::bmpArray.size()) { static Texture dummy; return dummy; } - if(idx >= cache.size()) - { - cache.resize(static_cast(idx) + 1); - linearFlags.resize(static_cast(idx) + 1, false); - } - if(!cache[idx].isValid() || linearFlags[idx] != filterLinear) - { - linearFlags[idx] = filterLinear; - auto& bmp = global::bmpArray[idx]; - if(bmp.surface) - cache[idx].load(bmp.surface.get(), filterLinear); - } - return cache[idx]; + return Texture::getBmpTexture(idx, filterLinear); } void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned faceTex) @@ -249,3 +286,65 @@ void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned fa const Rect fgRect(area.getOrigin() + Position(2, 2), sz - Extent(4, 4)); getBmpTexture(faceTex).drawTiled(fgRect); } + +// --------------------------------------------------------------------------- +// Bitmap-texture cache (static members) +// --------------------------------------------------------------------------- + +std::vector> Texture::s_bmpTexCache; +std::vector Texture::s_bmpTexLinearFlags; + +Texture& Texture::getBmpTexture(int idx, bool filterLinear) +{ + if(idx < 0 || idx >= static_cast(global::bmpArray.size())) + { + static Texture dummy; + return dummy; + } + if(static_cast(s_bmpTexCache.size()) <= idx) + { + s_bmpTexCache.resize(idx + 1); + s_bmpTexLinearFlags.resize(idx + 1, false); + } + if(!s_bmpTexCache[idx] || s_bmpTexLinearFlags[idx] != filterLinear || !s_bmpTexCache[idx]->isValid()) + { + if(!s_bmpTexCache[idx]) + s_bmpTexCache[idx] = std::make_unique(); + s_bmpTexLinearFlags[idx] = filterLinear; + auto& bmp = global::bmpArray[idx]; + if(bmp.surface) + { + s_bmpTexCache[idx]->load(bmp.surface.get(), filterLinear); + s_bmpTexCache[idx]->anchorX_ = bmp.nx; + s_bmpTexCache[idx]->anchorY_ = bmp.ny; + } + } + return *s_bmpTexCache[idx]; +} + +void Texture::drawSprite(int baseX, int baseY) const +{ + if(!isValid()) + return; + draw(Position(baseX - anchorX_, baseY - anchorY_)); +} + +void Texture::ensureBmpTex(int idx) +{ + if(idx < 0 || idx >= static_cast(global::bmpArray.size())) + return; + getBmpTexture(idx); +} + +void Texture::invalidateBmpCache(int start, int end) +{ + if(start > end) + return; + if(end >= static_cast(s_bmpTexCache.size())) + end = static_cast(s_bmpTexCache.size()) - 1; + for(int i = start; i <= end; i++) + { + if(i >= 0 && i < static_cast(s_bmpTexCache.size())) + s_bmpTexCache[i].reset(); + } +} diff --git a/Texture.h b/Texture.h index b306c67..c13c8d1 100644 --- a/Texture.h +++ b/Texture.h @@ -5,8 +5,11 @@ #pragma once #include "Rect.h" +#include #include #include +#include +#include /// Wraps a texture with RAII and provides draw methods. class Texture @@ -41,18 +44,40 @@ class Texture /// Tile the texture to fill the given rectangle. void drawTiled(const Rect& destRect) const; - /// Returns the raw GL texture name (for use with glBindTexture). - unsigned getHandle() const { return texture_; } + /// Direct handle access for manual GL ops. + GLuint getHandle() const { return texture_; } /// Size in pixels. Extent getSize() const { return size_; } + /// Draw a sub-rect of the texture stretched to fill the given dest rect. + void draw(const Rect& destRect, const Rect& srcRect) const; + /// Returns true if the texture has been created. bool isValid() const { return texture_ != 0; } + /// Draw at native size at (baseX, baseY) adjusted by the sprite anchor. + void drawSprite(int baseX, int baseY) const; + + // ---- Static bitmap-texture cache (used by CFont::draw) ---- + + /// Return (or create on first use) a cached GL texture for a bobBMP entry. + static Texture& getBmpTexture(int idx, bool filterLinear = false); + + /// Ensure the bitmap at idx has a cached GL texture (pre-warm). + static void ensureBmpTex(int idx); + + /// Invalidate the texture cache for entries [start, end] so the next getBmpTexture() re-uploads. + static void invalidateBmpCache(int start, int end); + private: - unsigned int texture_ = 0; + GLuint texture_ = 0; Extent size_; + Sint16 anchorX_ = 0, anchorY_ = 0; // sprite anchor offset, set by getBmpTexture + + // ---- Bitmap-texture cache internals ---- + static std::vector> s_bmpTexCache; + static std::vector s_bmpTexLinearFlags; /// Internal: create or recreate texture from raw BGRA pixel data. void load(const void* bgraPixels, Extent size, bool filterLinear); diff --git a/include/defines.h b/include/defines.h index 5adf11c..39f3738 100644 --- a/include/defines.h +++ b/include/defines.h @@ -962,18 +962,15 @@ enum // END: /DATA/EDITBOB.LST // BEGIN: /GFX/TEXTURES/TEX5.LBM - TILESET_GREENLAND_8BPP, - TILESET_GREENLAND_32BPP, + TILESET_GREENLAND, // END: /GFX/TEXTURES/TEX5.LBM // BEGIN: /GFX/TEXTURES/TEX6.LBM - TILESET_WASTELAND_8BPP, - TILESET_WASTELAND_32BPP, + TILESET_WASTELAND, // END: /GFX/TEXTURES/TEX6.LBM // BEGIN: /GFX/TEXTURES/TEX7.LBM - TILESET_WINTERLAND_8BPP, - TILESET_WINTERLAND_32BPP, + TILESET_WINTERLAND, // END: /GFX/TEXTURES/TEX7.LBM // BEGIN: /DATA/MIS*BOBS.LST * = 0,1,2,3,4,5 From cf24b9138f0edf03e157f3d61471cbd82a9f017a Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Wed, 8 Jul 2026 23:40:16 +0200 Subject: [PATCH 02/16] libsiedler2 --- CGame.cpp | 2 - CGame.h | 1 + CGame_Event.cpp | 5 +- CGame_Init.cpp | 207 +++++--- CGame_Render.cpp | 4 +- CIO/CButton.cpp | 2 +- CIO/CControlContainer.cpp | 31 +- CIO/CControlContainer.h | 22 +- CIO/CFile.cpp | 1029 +------------------------------------ CIO/CFile.h | 40 +- CIO/CFont.cpp | 370 +++++++------ CIO/CFont.h | 11 - CIO/CMenu.cpp | 4 +- CIO/CMenu.h | 3 +- CIO/CMinimapWindow.cpp | 11 +- CIO/CPicture.cpp | 19 +- CIO/CPicture.h | 4 +- CIO/CSelectBox.cpp | 2 +- CIO/CTextfield.cpp | 2 +- CIO/CWindow.cpp | 113 ++-- CIO/CWindow.h | 6 +- CMap.cpp | 210 ++++---- CSurface.cpp | 466 ++++++++--------- CSurface.h | 42 +- Texture.cpp | 172 ++----- Texture.h | 50 +- callbacks.cpp | 379 ++++++-------- callbacks.h | 1 - globals.cpp | 148 +++++- globals.h | 63 ++- include/ArchiveID.h | 66 +++ include/SdlSurface.h | 38 +- include/defines.h | 950 +++++++++++++++++----------------- 33 files changed, 1767 insertions(+), 2706 deletions(-) create mode 100644 include/ArchiveID.h diff --git a/CGame.cpp b/CGame.cpp index e399ac8..c35b739 100644 --- a/CGame.cpp +++ b/CGame.cpp @@ -37,8 +37,6 @@ CGame::CGame(Extent GameResolution_, bool fullscreen_) : GameResolution(GameResolution_), fullscreen(fullscreen_), Running(true), showLoadScreen(true), lastFps("", Position{0, 0}, FontSize::Medium) { - global::bmpArray.resize(MAXBOBBMP); - global::shadowArray.resize(MAXBOBSHADOW); global::s2 = this; } diff --git a/CGame.h b/CGame.h index be79019..c1ee0c6 100644 --- a/CGame.h +++ b/CGame.h @@ -6,6 +6,7 @@ #pragma once #include "CIO/CFont.h" +#include "SdlSurface.h" #include "Texture.h" #include #include diff --git a/CGame_Event.cpp b/CGame_Event.cpp index 93ed86c..4ef42cb 100644 --- a/CGame_Event.cpp +++ b/CGame_Event.cpp @@ -79,10 +79,7 @@ void CGame::EventHandling(SDL_Event* Event) // if (SDL_GetModState() == (KMOD_LCTRL | KMOD_LALT)) callback::debugger(INITIALIZING_CALL); break; - case SDLK_F4: // if CTRL and ALT are pressed - // if (SDL_GetModState() == (KMOD_LCTRL | KMOD_LALT)) - callback::viewer(INITIALIZING_CALL); - break; + #endif // F5 - F7 is ZOOM, F5 = zoom in, F6 = normal view, F7 = zoom out case SDLK_F5: diff --git a/CGame_Init.cpp b/CGame_Init.cpp index c386977..1c63020 100644 --- a/CGame_Init.cpp +++ b/CGame_Init.cpp @@ -11,6 +11,11 @@ #include "callbacks.h" #include "globals.h" #include "lua/GameDataLoader.h" +#include +#include +#include +#include +#include #include #include @@ -138,8 +143,6 @@ bool CGame::Init() std::cout << "failure"; return false; } - CFile::init(); - /*NOTE: its important to load a palette at first, * otherwise all images will be black (in exception of the LBM-Files, they have their own palette). * if its necessary to load pictures from a @@ -153,12 +156,12 @@ bool CGame::Init() // load some pictures (after all the splash-screens) // at first GFX/PICS/SETUP997.LBM, cause this is the S2-loading picture std::cout << "\nLoading file: GFX/PICS/SETUP997.LBM..."; - if(!CFile::open_file(global::gameDataFilePath / "GFX/PICS/SETUP997.LBM", LBM)) + if(!global::loadArchive(ArchiveID::SETUP997, global::gameDataFilePath / "GFX/PICS/SETUP997.LBM", nullptr)) { std::cout << "failure"; // if SETUP997.LBM doesn't exist, it's probably settlers2+mission cd and there we have SETUP998.LBM instead std::cout << "\nTry to load file: GFX/PICS/SETUP998.LBM instead..."; - if(!CFile::open_file(global::gameDataFilePath / "GFX/PICS/SETUP998.LBM", LBM)) + if(!global::loadArchive(ArchiveID::SETUP997, global::gameDataFilePath / "GFX/PICS/SETUP998.LBM", nullptr)) { std::cout << "failure"; return false; @@ -166,7 +169,12 @@ bool CGame::Init() } // Create texture for splash background - splashBg_.load(global::bmpArray[SPLASHSCREEN_LOADING_S2SCREEN].surface.get(), true); + { + auto& archiv = global::typedArchives[ArchiveID::SETUP997]; + auto* bmp = dynamic_cast(archiv.get(0)); + if(bmp) + splashBg_.load(*bmp, true); + } // std::cout << "\nShow loading screen..."; showLoadScreen = true; @@ -182,17 +190,25 @@ bool CGame::Init() } // continue loading pictures - for(const std::string file : - {"GFX/PICS/SETUP000.LBM", "GFX/PICS/SETUP010.LBM", "GFX/PICS/SETUP011.LBM", "GFX/PICS/SETUP012.LBM", - "GFX/PICS/SETUP013.LBM", "GFX/PICS/SETUP014.LBM", "GFX/PICS/SETUP015.LBM"}) + const struct { - std::cout << "\nLoading file: " << file << "..."; - if(!CFile::open_file(global::gameDataFilePath / file, LBM)) + ArchiveID id; + const char* path; + } setupFiles[] = { + {ArchiveID::SETUP000, "GFX/PICS/SETUP000.LBM"}, {ArchiveID::SETUP010, "GFX/PICS/SETUP010.LBM"}, + {ArchiveID::SETUP011, "GFX/PICS/SETUP011.LBM"}, {ArchiveID::SETUP012, "GFX/PICS/SETUP012.LBM"}, + {ArchiveID::SETUP013, "GFX/PICS/SETUP013.LBM"}, {ArchiveID::SETUP014, "GFX/PICS/SETUP014.LBM"}, + {ArchiveID::SETUP015, "GFX/PICS/SETUP015.LBM"}, + }; + for(const auto& sf : setupFiles) + { + std::cout << "\nLoading file: " << sf.path << "..."; + if(!global::loadArchive(sf.id, global::gameDataFilePath / sf.path, nullptr)) { std::cout << "failure"; // if it doesn't exist, it's probably settlers2+missioncd and we simply load SETUP010.LBM instead std::cout << "\nLoading file: GFX/PICS/SETUP010.LBM instead..."; - if(!CFile::open_file(global::gameDataFilePath / "GFX/PICS/SETUP010.LBM", LBM)) + if(!global::loadArchive(ArchiveID::SETUP010, global::gameDataFilePath / "GFX/PICS/SETUP010.LBM", nullptr)) { std::cout << "failure"; return false; @@ -200,28 +216,23 @@ bool CGame::Init() } } - for(const std::string file : - {"GFX/PICS/SETUP666.LBM", "GFX/PICS/SETUP667.LBM", "GFX/PICS/SETUP801.LBM", "GFX/PICS/SETUP802.LBM", - "GFX/PICS/SETUP803.LBM", "GFX/PICS/SETUP804.LBM", "GFX/PICS/SETUP805.LBM", "GFX/PICS/SETUP806.LBM", - "GFX/PICS/SETUP810.LBM", "GFX/PICS/SETUP811.LBM", "GFX/PICS/SETUP895.LBM", "GFX/PICS/SETUP896.LBM"}) - { - std::cout << "\nLoading file: " << file << "..."; - if(!CFile::open_file(global::gameDataFilePath / file, LBM)) + { // batch 2: SETUP666-896 + const struct { - std::cout << "failure"; - return false; - } - } - - for(const std::string file : {"GFX/PICS/SETUP897.LBM", "GFX/PICS/SETUP898.LBM"}) - { - std::cout << "\nLoading file: " << file << "..."; - if(!CFile::open_file(global::gameDataFilePath / file, LBM)) + ArchiveID id; + const char* path; + } files[] = { + {ArchiveID::SETUP666, "GFX/PICS/SETUP666.LBM"}, {ArchiveID::SETUP667, "GFX/PICS/SETUP667.LBM"}, + {ArchiveID::SETUP801, "GFX/PICS/SETUP801.LBM"}, {ArchiveID::SETUP802, "GFX/PICS/SETUP802.LBM"}, + {ArchiveID::SETUP803, "GFX/PICS/SETUP803.LBM"}, {ArchiveID::SETUP804, "GFX/PICS/SETUP804.LBM"}, + {ArchiveID::SETUP805, "GFX/PICS/SETUP805.LBM"}, {ArchiveID::SETUP806, "GFX/PICS/SETUP806.LBM"}, + {ArchiveID::SETUP810, "GFX/PICS/SETUP810.LBM"}, {ArchiveID::SETUP811, "GFX/PICS/SETUP811.LBM"}, + {ArchiveID::SETUP895, "GFX/PICS/SETUP895.LBM"}, {ArchiveID::SETUP896, "GFX/PICS/SETUP896.LBM"}, + }; + for(const auto& f : files) { - std::cout << "failure"; - // if it doesn't exist, it's probably settlers2+missioncd and we simply load SETUP896.LBM instead - std::cout << "\nLoading file: GFX/PICS/SETUP896.LBM instead..."; - if(!CFile::open_file(global::gameDataFilePath / "GFX/PICS/SETUP896.LBM", LBM)) + std::cout << "\nLoading file: " << f.path << "..."; + if(!global::loadArchive(f.id, global::gameDataFilePath / f.path, nullptr)) { std::cout << "failure"; return false; @@ -229,78 +240,107 @@ bool CGame::Init() } } - for(const std::string file : - {"GFX/PICS/SETUP899.LBM", "GFX/PICS/SETUP990.LBM", "GFX/PICS/WORLD.LBM", "GFX/PICS/WORLDMSK.LBM"}) - { - std::cout << "\nLoading file: " << file << "..."; - if(!CFile::open_file(global::gameDataFilePath / file, LBM)) + { // batch 3: SETUP897-898 with fallback to SETUP896 + const struct { - std::cout << "failure"; - return false; + ArchiveID id; + const char* path; + } files[] = { + {ArchiveID::SETUP897, "GFX/PICS/SETUP897.LBM"}, + {ArchiveID::SETUP898, "GFX/PICS/SETUP898.LBM"}, + }; + for(const auto& f : files) + { + std::cout << "\nLoading file: " << f.path << "..."; + if(!global::loadArchive(f.id, global::gameDataFilePath / f.path, nullptr)) + { + std::cout << "failure"; + std::cout << "\nLoading file: GFX/PICS/SETUP896.LBM instead..."; + if(!global::loadArchive(f.id, global::gameDataFilePath / "GFX/PICS/SETUP896.LBM", nullptr)) + { + std::cout << "failure"; + return false; + } + } } } - // load gouraud data - for(const std::string file : {"DATA/TEXTURES/GOU5.DAT", "DATA/TEXTURES/GOU6.DAT", "DATA/TEXTURES/GOU7.DAT"}) - { - std::cout << "\nLoading file: " << file << "..."; - if(!CFile::open_file(global::gameDataFilePath / file, GOU)) + { // batch 4: remaining loading screens + const struct { - std::cout << "failure"; - return false; + ArchiveID id; + const char* path; + } files[] = { + {ArchiveID::SETUP899, "GFX/PICS/SETUP899.LBM"}, + {ArchiveID::SETUP990, "GFX/PICS/SETUP990.LBM"}, + {ArchiveID::WORLD_LBM, "GFX/PICS/WORLD.LBM"}, + {ArchiveID::WORLDMSK_LBM, "GFX/PICS/WORLDMSK.LBM"}, + }; + for(const auto& f : files) + { + std::cout << "\nLoading file: " << f.path << "..."; + if(!global::loadArchive(f.id, global::gameDataFilePath / f.path, nullptr)) + { + std::cout << "failure"; + return false; + } } } - // load only the palette at this time from editres.idx - std::cout << "\nLoading palette from file: DATA/EDITRES.IDX..."; - if(!CFile::open_file(global::gameDataFilePath / "DATA/EDITRES.IDX", IDX, true)) + // Load the default palette first so all subsequent loads have it available + std::cout << "\nLoading default palette from file: GFX/PALETTE/PAL5.BBM..."; + if(!global::loadPalette(global::gameDataFilePath / "GFX/PALETTE/PAL5.BBM")) { std::cout << "failure"; return false; } - // set the right palette - CFile::set_palActual(CFile::get_palArray() - 1); - std::cout << "\nLoading file: DATA/EDITRES.IDX..."; - if(!CFile::open_file(global::gameDataFilePath / "DATA/EDITRES.IDX", IDX)) - { - std::cout << "failure"; - return false; - } - // set back palette - CFile::set_palActual(CFile::get_palArray()); - // load only the palette at this time from editio.idx - std::cout << "\nLoading palette from file: DATA/IO/EDITIO.IDX..."; - if(!CFile::open_file(global::gameDataFilePath / "DATA/IO/EDITIO.IDX", IDX, true)) + + // Load EDITRES.IDX as a complete bundle in typedArchives { - std::cout << "failure"; - return false; + libsiedler2::Archiv editres; + int ec = libsiedler2::Load(global::gameDataFilePath / "DATA/EDITRES.IDX", editres, global::currentPalette); + if(ec) + { + std::cout << "\nError loading EDITRES.IDX: " << libsiedler2::getErrorString(ec) << std::endl; + return false; + } + // The palette in EDITRES (item 1) may override the default + auto* pal = dynamic_cast(editres.get(1)); + if(pal) + global::currentPalette = pal; + // Store the complete Archiv in typedArchives — fonts stay inside for CFont to read directly + // Indices match file positions: 0=Font, 1=Palette, 2=Font, 3=Font, 4-56=Bitmaps + global::typedArchives[ArchiveID::EDITRES] = std::move(editres); } - // set the right palette - CFile::set_palActual(CFile::get_palArray() - 1); + std::cout << "\nLoading file: DATA/IO/EDITIO.IDX..."; - if(!CFile::open_file(global::gameDataFilePath / "DATA/IO/EDITIO.IDX", IDX)) + if(!global::loadArchive(ArchiveID::EDITIO, global::gameDataFilePath / "DATA/IO/EDITIO.IDX", global::currentPalette)) { std::cout << "failure"; return false; } - // set back palette - CFile::set_palActual(CFile::get_palArray()); + std::cout << "done"; + std::cout << "\nLoading file: DATA/EDITBOB.LST..."; - if(!CFile::open_file(global::gameDataFilePath / "DATA/EDITBOB.LST", LST)) + if(!global::loadArchive(ArchiveID::EDITBOB, global::gameDataFilePath / "DATA/EDITBOB.LST", global::currentPalette)) { std::cout << "failure"; return false; } + std::cout << "done"; // texture tilesets - for(const std::string file : {"GFX/TEXTURES/TEX5.LBM", "GFX/TEXTURES/TEX6.LBM", "GFX/TEXTURES/TEX7.LBM"}) + const ArchiveID texArchives[3] = {ArchiveID::TEX5, ArchiveID::TEX6, ArchiveID::TEX7}; + const std::string texFiles[3] = {"GFX/TEXTURES/TEX5.LBM", "GFX/TEXTURES/TEX6.LBM", "GFX/TEXTURES/TEX7.LBM"}; + for(unsigned ti = 0; ti < 3; ti++) { - std::cout << "\nLoading file: " << file << "..."; - if(!CFile::open_file(global::gameDataFilePath / file, LBM)) + std::cout << "\nLoading file: " << texFiles[ti] << "..."; + if(!global::loadTileset(texArchives[ti], ti, global::gameDataFilePath / texFiles[ti])) { std::cout << "failure"; return false; } + std::cout << "done"; } /* @@ -313,11 +353,14 @@ bool CGame::Init() */ // EVERY MISSION-FILE SHOULD BE LOADED SEPARATLY IF THE SPECIFIED MISSION GOES ON -- SO THIS IS TEMPORARY - for(const std::string file : {"DATA/MIS0BOBS.LST", "DATA/MIS1BOBS.LST", "DATA/MIS2BOBS.LST", "DATA/MIS3BOBS.LST", - "DATA/MIS4BOBS.LST", "DATA/MIS5BOBS.LST"}) + const ArchiveID misArchives[] = {ArchiveID::MIS0BOBS, ArchiveID::MIS1BOBS, ArchiveID::MIS2BOBS, + ArchiveID::MIS3BOBS, ArchiveID::MIS4BOBS, ArchiveID::MIS5BOBS}; + const std::string misFiles[] = {"DATA/MIS0BOBS.LST", "DATA/MIS1BOBS.LST", "DATA/MIS2BOBS.LST", + "DATA/MIS3BOBS.LST", "DATA/MIS4BOBS.LST", "DATA/MIS5BOBS.LST"}; + for(unsigned mi = 0; mi < 6; mi++) { - std::cout << "\nLoading file: " << file << "..."; - if(!CFile::open_file(global::gameDataFilePath / file, LST)) + std::cout << "\nLoading file: " << misFiles[mi] << "..."; + if(!global::loadArchive(misArchives[mi], global::gameDataFilePath / misFiles[mi], global::currentPalette)) { std::cout << "failure"; return false; @@ -327,10 +370,14 @@ bool CGame::Init() // create the mainmenu callback::mainmenu(INITIALIZING_CALL); - // Create textures for cursor - cursor_.load(global::bmpArray[CURSOR].surface.get()); - cursorClicked_.load(global::bmpArray[CURSOR_CLICKED].surface.get()); - cross_.load(global::bmpArray[CROSS].surface.get()); + // Create textures for cursor (from typed archive) + auto& resArchiv = global::typedArchives[ArchiveID::EDITRES]; + if(auto* bmp = dynamic_cast(resArchiv.get(CURSOR))) + cursor_.load(*bmp); + if(auto* bmp = dynamic_cast(resArchiv.get(CURSOR_CLICKED))) + cursorClicked_.load(*bmp); + if(auto* bmp = dynamic_cast(resArchiv.get(CROSS))) + cross_.load(*bmp); return true; } diff --git a/CGame_Render.cpp b/CGame_Render.cpp index 9071ae9..7c163d3 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -78,12 +78,12 @@ void CGame::Render() std::array textBuffer; // text for x and y of vertex (shown in upper left corner) std::snprintf(textBuffer.data(), textBuffer.size(), "%d %d", MapObj->getVertexX(), MapObj->getVertexY()); - CFont::draw(textBuffer.data(), Position(20, 20), FontSize::Medium); + CFont::draw(textBuffer.data(), Position(20, 20)); // text for MinReduceHeight and MaxRaiseHeight std::snprintf(textBuffer.data(), textBuffer.size(), "min. height: %#04x/0x3C max. height: %#04x/0x3C NormalNull: 0x0A", MapObj->getMinReduceHeight(), MapObj->getMaxRaiseHeight()); - CFont::draw(textBuffer.data(), Position(100, 20), FontSize::Medium); + CFont::draw(textBuffer.data(), Position(100, 20)); // text for MovementLocked if(MapObj->isHorizontalMovementLocked() && MapObj->isVerticalMovementLocked()) CFont::draw("Movement locked (F9 or F10 to unlock)", Position(20, 40), FontSize::Large, FontColor::Orange); diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index cb25536..c715595 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -134,7 +134,7 @@ void CButton::draw(Position parentOrigin) const // 4. Draw picture or text centered inside the button if(button_picture >= 0) { - auto& picTex = getBmpTexture(button_picture); + auto& picTex = getTexture(ArchiveID::EDITIO, button_picture); const Position picPos = absPos + size_ / 2 - Position(picTex.getSize()) / 2; picTex.draw(picPos); } else if(button_text) diff --git a/CIO/CControlContainer.cpp b/CIO/CControlContainer.cpp index df98926..7bd08c4 100644 --- a/CIO/CControlContainer.cpp +++ b/CIO/CControlContainer.cpp @@ -13,16 +13,26 @@ #include "CTextfield.h" #include "helpers/containerUtils.h" -CControlContainer::CControlContainer(int pic_background) : CControlContainer(pic_background, BorderSizes{}) {} -CControlContainer::CControlContainer(int pic_background, BorderSizes border) - : border(border), pic_background(pic_background) +BorderSizes::BorderSizes(ArchiveID archive, int leftIdx, int topIdx, int rightIdx, int bottomIdx) + : left(static_cast(global::getBitmapSize(archive, leftIdx).x)), + top(static_cast(global::getBitmapSize(archive, topIdx).y)), + right(static_cast(global::getBitmapSize(archive, rightIdx).x)), + bottom(static_cast(global::getBitmapSize(archive, bottomIdx).y)) +{} + +CControlContainer::CControlContainer(int pic_background, ArchiveID archive) + : CControlContainer(pic_background, BorderSizes{}, archive) +{} +CControlContainer::CControlContainer(int pic_background, BorderSizes border, ArchiveID archive) + : backgroundArchive_(archive), border(border), pic_background(pic_background) {} CControlContainer::~CControlContainer() noexcept = default; -void CControlContainer::setBackgroundPicture(int pic_background) +void CControlContainer::setBackgroundPicture(int pic_background, ArchiveID archive) { this->pic_background = pic_background; + backgroundArchive_ = archive; } void CControlContainer::setMouseData(const SDL_MouseMotionEvent motion) @@ -108,11 +118,12 @@ bool CControlContainer::delText(CFont* TextToDelete) return eraseElement(texts, TextToDelete); } -CPicture* CControlContainer::addPicture(void callback(int), int clickedParam, Position pos, int picture) +CPicture* CControlContainer::addPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, + int localIndex) { pos = pos + Position(border.left, border.top); - pictures.emplace_back(std::make_unique(callback, clickedParam, pos, picture)); + pictures.emplace_back(std::make_unique(callback, clickedParam, pos, archive, localIndex)); return pictures.back().get(); } @@ -121,14 +132,14 @@ bool CControlContainer::delPicture(CPicture* PictureToDelete) return eraseElement(pictures, PictureToDelete); } -int CControlContainer::addStaticPicture(Position pos, int picture) +int CControlContainer::addStaticPicture(Position pos, ArchiveID archive, int localIndex) { - if(picture < 0) + if(localIndex < 0) return -1; pos = pos + Position(border.left, border.top); unsigned id = static_pictures.empty() ? 0u : static_pictures.back().id + 1u; - static_pictures.emplace_back(Picture{pos, picture, id}); + static_pictures.emplace_back(Picture{pos, archive, localIndex, id}); return id; } @@ -189,6 +200,6 @@ void CControlContainer::drawChildren(Position origin) button->draw(origin); for(const auto& static_picture : static_pictures) { - getBmpTexture(static_picture.pic).draw(origin + static_picture.pos); + getTexture(static_picture.archive, static_picture.pic).draw(origin + static_picture.pos); } } diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index 2f945dd..8b9ecec 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -5,6 +5,7 @@ #pragma once +#include "ArchiveID.h" #include "defines.h" #include #include @@ -22,6 +23,13 @@ struct BorderSizes int top = 0; int right = 0; int bottom = 0; + + BorderSizes() = default; + + /// Construct border sizes from four bitmap indices in an archive. + /// Each field is set to the relevant dimension of the corresponding bitmap: + /// left/right = bitmap width, top/bottom = bitmap height. + BorderSizes(ArchiveID archive, int leftIdx, int topIdx, int rightIdx, int bottomIdx); }; class CControlContainer @@ -32,10 +40,14 @@ class CControlContainer struct Picture { Position pos; + ArchiveID archive; int pic; unsigned id; }; +protected: + ArchiveID backgroundArchive_; + // if waste is true, the menu will be delete within the game loop BorderSizes border; bool waste = false; @@ -62,8 +74,8 @@ class CControlContainer int getBackground() const { return pic_background; } public: - CControlContainer(int pic_background); - CControlContainer(int pic_background, BorderSizes border); + CControlContainer(int pic_background, ArchiveID archive); + CControlContainer(int pic_background, BorderSizes border, ArchiveID archive); virtual ~CControlContainer() noexcept; // Access BorderSizes getBorderSizes() const { return border; } @@ -71,7 +83,7 @@ class CControlContainer { return {static_cast(border.left + border.right), static_cast(border.top + border.bottom)}; } - void setBackgroundPicture(int pic_background); + void setBackgroundPicture(int pic_background, ArchiveID archive); virtual void setMouseData(SDL_MouseMotionEvent motion); virtual void setMouseData(SDL_MouseButtonEvent button); void setKeyboardData(const SDL_KeyboardEvent& key); @@ -83,9 +95,9 @@ class CControlContainer bool delButton(CButton* ButtonToDelete); CFont* addText(std::string string, Position pos, FontSize fontsize, FontColor color = FontColor::Yellow); bool delText(CFont* TextToDelete); - CPicture* addPicture(void callback(int), int clickedParam, Position pos, int picture); + CPicture* addPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, int localIndex); bool delPicture(CPicture* PictureToDelete); - int addStaticPicture(Position pos, int picture); + int addStaticPicture(Position pos, ArchiveID archive, int localIndex); bool delStaticPicture(int picId); CTextfield* addTextfield(Position pos = {0, 0}, Uint16 cols = 10, Uint16 rows = 1, FontSize fontsize = FontSize::Large, FontColor text_color = FontColor::Yellow, diff --git a/CIO/CFile.cpp b/CIO/CFile.cpp index 20af7bf..eee26c6 100644 --- a/CIO/CFile.cpp +++ b/CIO/CFile.cpp @@ -4,495 +4,68 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CFile.h" -#include "../CSurface.h" #include "../globals.h" #include "libendian/libendian.h" #include "s25util/file_handle.h" #include #include +#include #include #include #include -//-V:fseek:303 -//-V:ftell:303 - -bobBMP* CFile::bmpArray = nullptr; -bobSHADOW* CFile::shadowArray = nullptr; -bobPAL* CFile::palArray = nullptr; -bobPAL* CFile::palActual = nullptr; -bool CFile::loadPAL = false; - -#define STRINGIZE(x) STRINGIZE2(x) -#define STRINGIZE2(x) #x -#define LINE_STRING STRINGIZE(__LINE__) #define CHECK_READ(readCmd) \ if(!(readCmd)) \ - throw std::runtime_error("Read failed at line " LINE_STRING) - -void CFile::init() -{ - bmpArray = global::bmpArray.data(); - shadowArray = global::shadowArray.data(); - palArray = global::palArray.data(); - palActual = global::palArray.data(); - loadPAL = false; -} + throw std::runtime_error("Read failed") -void* CFile::open_file(const boost::filesystem::path& filepath, char filetype, bool only_loadPAL) +void* CFile::open_file(const boost::filesystem::path& filepath, char filetype) { - void* return_value = nullptr; - - if(filepath.empty() || !bmpArray || !shadowArray || !palArray || !palActual) + if(filepath.empty()) return nullptr; s25util::file_handle fh(boost::nowide::fopen(filepath.string().c_str(), "rb")); if(!fh) return nullptr; - - if(only_loadPAL) - loadPAL = true; - try { switch(filetype) { - case LST: - if(read_lst(*fh)) - return_value = (void*)-1; - - break; - - case BOB: - if(read_bob(*fh)) - return_value = (void*)-1; - - break; - - case IDX: - if(open_idx(filepath)) - return_value = (void*)-1; - - break; - - case BBM: - if(read_bbm(*fh)) - return_value = (void*)-1; - - break; - - case LBM: - if(read_lbm(*fh, filepath)) - return_value = (void*)-1; - - break; - - case GOU: - if(read_gou(*fh)) - return_value = (void*)-1; - - break; - - case WLD: return_value = read_wld(*fh); break; - - case SWD: return_value = read_swd(*fh); break; - - default: // no valid data type - break; + case WLD: return read_wld(*fh); + case SWD: return read_swd(*fh); + default: break; } } catch(const std::exception& e) { - std::cerr << "Error while reading " << filepath << ": " << e.what() << std::endl; - } - - loadPAL = false; - - return return_value; -} - -bool CFile::read_lst(FILE* fp) -{ - // type of entry (used or unused entry) - Uint16 entrytype; - // bobtype of the entry - Uint16 bobtype; - - // skip: id (2x 1 Bytes) + count (1x 4 Bytes) = 6 Bytes - fseek(fp, 6, SEEK_SET); - - // main loop for reading entries - while(!feof(fp)) - { - // entry type (2 Bytes) - unused (=0x0000) or used (=0x0001) - - if(!libendian::le_read_us(&entrytype, fp)) - { - if(feof(fp)) - break; - CHECK_READ(false); - } - - // if entry is unused, go back to 'while' --- and by the way: after the last entry there are always zeros in the - // file, so the following case will happen till we have reached the end of the file and the 'while' will break - - // PERFECT! - if(entrytype == 0x0000) - continue; - - // bobtype (2 Bytes) - CHECK_READ(libendian::le_read_us(&bobtype, fp)); - - switch(bobtype) - { - case BOBTYPE01: - if(!read_bob01(fp)) - return false; - break; - - case BOBTYPE02: - if(!read_bob02(fp)) - return false; - break; - - case BOBTYPE03: - if(!read_bob03(fp)) - return false; - break; - - case BOBTYPE04: - if(!read_bob04(fp, PLAYER_BLUE)) - return false; - break; - - case BOBTYPE05: - if(!read_bob05(fp)) - return false; - break; - - case BOBTYPE07: - if(!read_bob07(fp)) - return false; - break; - - case BOBTYPE14: - if(!read_bob14(fp)) - return false; - break; - - default: // Something is wrong? Maybe the last entry was really the LAST, so we should not return false - break; - } + std::cerr << "Error reading " << filepath << ": " << e.what() << std::endl; } - - return true; -} - -bool CFile::read_bob(FILE*) -{ - return false; + return nullptr; } -bool CFile::open_idx(const boost::filesystem::path& filepath) +bool CFile::save_file(const boost::filesystem::path& filepath, char filetype, void* data) { - // starting adress of data in the corresponding '******.DAT'-File - Uint32 offset; - // bobtype of the entry - Uint16 bobtype; - // bobtype is repeated in the corresponding '******.DAT'-File, so we have to check this is correct - Uint16 bobtype_check; - - // '******.IDX'-File - const s25util::file_handle fh_idx(boost::nowide::fopen(filepath.string().c_str(), "rb")); - // corresponding '******.DAT'-File - auto filename_dat = filepath; - filename_dat.replace_extension(".DAT"); - const s25util::file_handle fh_dat(boost::nowide::fopen(filename_dat.string().c_str(), "rb")); - if(!fh_idx || !fh_dat) + if(filepath.empty() || !data) return false; - - // we are finished opening the files now we can handle the content - - // skip: unknown data (1x 4 Bytes) at the beginning of the file - fseek(*fh_idx, 4, SEEK_SET); - - // main loop for reading entries - while(!feof(*fh_idx) && !feof(*fh_dat)) + s25util::file_handle fh(boost::nowide::fopen(filepath.string().c_str(), "wb")); + if(!fh) + return false; + try { - // skip: name (1x 16 Bytes) - fseek(*fh_idx, 16, SEEK_CUR); - // offset (4 Bytes) - if(!libendian::le_read_ui(&offset, *fh_idx)) - { - if(feof(*fh_idx)) - break; - CHECK_READ(false); - } - // skip unknown data (6x 1 Byte) - fseek(*fh_idx, 6, SEEK_CUR); - // bobtype (2 Bytes) - CHECK_READ(libendian::le_read_us(&bobtype, *fh_idx)); - // set fp_dat to the position in 'offset' - fseek(*fh_dat, offset, SEEK_SET); - // read bobtype again, now from 'DAT'-File - CHECK_READ(libendian::le_read_us(&bobtype_check, *fh_dat)); - // check if data in 'DAT'-File is the data that it should be (bobtypes are equal) - if(bobtype != bobtype_check) - return false; - - switch(bobtype) + switch(filetype) { - case BOBTYPE01: - if(!read_bob01(*fh_dat)) - return false; - break; - - case BOBTYPE02: - if(!read_bob02(*fh_dat)) - return false; + case WLD: + if(save_wld(*fh, data)) + return true; break; - - case BOBTYPE03: - if(!read_bob03(*fh_dat)) - return false; + case SWD: + if(save_swd(*fh, data)) + return true; break; - - case BOBTYPE04: - if(!read_bob04(*fh_dat)) - return false; - break; - - case BOBTYPE05: - if(!read_bob05(*fh_dat)) - return false; - break; - - case BOBTYPE07: - if(!read_bob07(*fh_dat)) - return false; - break; - - case BOBTYPE14: - if(!read_bob14(*fh_dat)) - return false; - break; - - default: // Something is wrong? Maybe the last entry was really the LAST, so we should not return false - break; - } - } - - return true; -} - -bool CFile::read_bbm(FILE* fp) -{ - // skip header (48 Bytes) - fseek(fp, 48, SEEK_CUR); - - for(auto& color : palArray->colors) - { - CHECK_READ(libendian::read(&(color.r), 1, fp)); - CHECK_READ(libendian::read(&(color.g), 1, fp)); - CHECK_READ(libendian::read(&(color.b), 1, fp)); - color.a = 255; - } - - palArray++; - - return true; -} - -bool CFile::read_lbm(FILE* fp, const boost::filesystem::path& filepath) -{ - // IMPORTANT NOTE: LBM (also ILBM) is the Interchange File Format (IFF) and the 4-byte-blocks are originally - // organized as Big Endian, so a convertion is needed - - // identifier for the kind of data follows (FORM, BMHD, CMAP, BODY) - std::array chunk_identifier; - - // length of data block - Uint32 length; - // color depth of the picture - Uint16 color_depth; - // is the picture rle-compressed? - Uint8 compression_flag; - // compression type - Sint8 ctype; - // array for palette colors - std::array colors; - // color value for read pixel - Uint8 color_value; - - // skip File-Identifier "FORM" (1x 4 Bytes) + unknown data (4x 1 Byte) + Header-Identifier "PBM " (1x 4 Bytes) = 12 - // Bytes - fseek(fp, 12, SEEK_CUR); - - /* READ FIRST CHUNK "BMHD" */ - - // chunk-identifier (4 Bytes) - CHECK_READ(libendian::read(chunk_identifier.data(), 4, fp)); - chunk_identifier[4] = '\0'; - // should be "BMHD" at this time - if(strcmp(chunk_identifier.data(), "BMHD") != 0) - return false; - // length of data block - CHECK_READ(libendian::be_read_ui(&length, fp)); - // width of picture (2 Bytes) - CHECK_READ(libendian::be_read_us(&(bmpArray->w), fp)); - // heigth of picture (2 Bytes) - CHECK_READ(libendian::be_read_us(&(bmpArray->h), fp)); - // skip unknown data (4x 1 Bytes) - fseek(fp, 4, SEEK_CUR); - // color depth of the picture (1x 2 Bytes) - CHECK_READ(libendian::be_read_us(&color_depth, fp)); - // compression_flag (1x 1 Bytes) - CHECK_READ(libendian::read(&compression_flag, 1, fp)); - fseek(fp, 9, SEEK_CUR); - // skip unknown data (length - 20 x 1 Byte) - // fseek(fp, length-20, SEEK_CUR); - - /* READ SECOND CHUNK "CMAP" */ - - // chunk-identifier (4 Bytes) - // search for the "CMAP" and skip other chunk-types - while(!feof(fp)) - { - CHECK_READ(libendian::read(chunk_identifier.data(), 4, fp)); - - if(strcmp(chunk_identifier.data(), "CMAP") == 0) - break; - else - { - Uint32 chunkLen; - CHECK_READ(libendian::be_read_ui(&chunkLen, fp)); - if(chunkLen & 1) - chunkLen++; - fseek(fp, chunkLen, SEEK_CUR); + default: break; } - } - if(feof(fp)) - return false; - // length of data block - CHECK_READ(libendian::be_read_ui(&length, fp)); - // must be 768 (RGB = 3 Byte x 256 Colors) - if(length != 3u * 256u) - return false; - // palette - for(auto& color : colors) - { - CHECK_READ(libendian::read(&color.r, 1, fp)); - CHECK_READ(libendian::read(&color.g, 1, fp)); - CHECK_READ(libendian::read(&color.b, 1, fp)); - } - - /* READ THIRD CHUNK "BODY" */ - - // chunk-identifier (4 Bytes) - // search for the "BODY" and skip other chunk-types - while(!feof(fp)) - { - CHECK_READ(libendian::read(chunk_identifier.data(), 4, fp)); - - if(strcmp(chunk_identifier.data(), "BODY") == 0) - break; - else - { - Uint32 chunkLen; - CHECK_READ(libendian::be_read_ui(&chunkLen, fp)); - if(chunkLen & 1) - chunkLen++; - fseek(fp, chunkLen, SEEK_CUR); - } - } - if(feof(fp)) - return false; - // length of data block - CHECK_READ(libendian::be_read_ui(&length, fp)); - - // now we are ready to read the picture lines and fill the surface, so lets create one - if(!(bmpArray->surface = makePalSurface(bmpArray->w, bmpArray->h, colors))) + } catch(const std::exception& e) { - std::cerr << "Failed to create surface: " << SDL_GetError() << std::endl; - return false; + std::cerr << "Error saving " << filepath << ": " << e.what() << std::endl; } - - if(compression_flag == 0) - { - // picture uncompressed - // main loop for reading picture lines - for(Position pos{0, 0}; pos.y < bmpArray->h; pos.y++) - { - // loop for reading pixels of the actual picture line - for(pos.x = 0; pos.x < bmpArray->w; pos.x++) - { - // read color value (1 Byte) - CHECK_READ(libendian::read(&color_value, 1, fp)); - // draw - CSurface::DrawPixel_Color(bmpArray->surface.get(), pos, (Uint32)color_value); - } - } - - } else if(compression_flag == 1) - { - // picture compressed - - // main loop for reading picture lines - for(Position pos{0, 0}; pos.y < bmpArray->h; pos.y++) - { - // loop for reading pixels of the actual picture line - //(cause of a kind of RLE-Compression we cannot read the pixels sequentially) - //'x' will be incremented WITHIN the loop - for(pos.x = 0; pos.x < bmpArray->w;) - { - // read compression type - CHECK_READ(libendian::read(&ctype, 1, fp)); - - if(ctype >= 0) - { - // following 'ctype + 1' pixels are uncompressed - for(int k = 0; k < ctype + 1; k++, pos.x++) - { - // read color value (1 Byte) - CHECK_READ(libendian::read(&color_value, 1, fp)); - // draw - CSurface::DrawPixel_Color(bmpArray->surface.get(), pos, (Uint32)color_value); - } - } else if(ctype >= -127) - { - // draw the following byte '-ctype + 1' times to the surface - CHECK_READ(libendian::read(&color_value, 1, fp)); - - for(int k = 0; k < -ctype + 1; k++, pos.x++) - CSurface::DrawPixel_Color(bmpArray->surface.get(), pos, (Uint32)color_value); - } else // if (ctype == -128) - { - // ignore - } - } - } - } else - return false; - - // if this is a texture file, set a color key for transparency - if(filepath.filename() == "TEX5.LBM" || filepath.filename() == "TEX6.LBM" || filepath.filename() == "TEX7.LBM" - || filepath.filename() == "TEXTUR_0.LBM" || filepath.filename() == "TEXTUR_3.LBM") - SDL_SetColorKey(bmpArray->surface.get(), SDL_TRUE, 0); - - // we are finished, the surface is filled - // increment bmpArray for the next picture - bmpArray++; - - return true; -} - -bool CFile::read_gou(FILE* fp) -{ - static int internalArrayCtr = 0; // maximum is two cause there are only 3 GOUx.DAT-Files - - if(internalArrayCtr > 2) - return false; - - CHECK_READ(libendian::read(gouData[internalArrayCtr][0], sizeof(gouData[internalArrayCtr]), fp)); - internalArrayCtr++; - - return true; + return false; } bobMAP* CFile::read_wld(FILE* fp) @@ -674,54 +247,6 @@ bobMAP* CFile::read_swd(FILE* fp) return read_wld(fp); } -bool CFile::save_file(const boost::filesystem::path& filepath, char filetype, void* data) -{ - if(filepath.empty() || !data) - return false; - - s25util::file_handle fh(boost::nowide::fopen(filepath.string().c_str(), "wb")); - if(!fh) - return false; - - switch(filetype) - { - case LST: return save_lst(*fh, data); - case BOB: return save_bob(*fh, data); - case IDX: return save_idx(*fh, data); - case BBM: return save_bbm(*fh, data); - case LBM: return save_lbm(*fh, data); - case WLD: return save_wld(*fh, data); - case SWD: return save_swd(*fh, data); - default: // no valid data type - return false; - } -} - -bool CFile::save_lst(FILE*, void*) -{ - return false; -} - -bool CFile::save_bob(FILE*, void*) -{ - return false; -} - -bool CFile::save_idx(FILE*, void*) -{ - return false; -} - -bool CFile::save_bbm(FILE*, void*) -{ - return false; -} - -bool CFile::save_lbm(FILE*, void*) -{ - return false; -} - bool CFile::save_wld(FILE* fp, void* data) { char zero = 0; // to fill bytes @@ -940,505 +465,3 @@ bool CFile::save_swd(FILE* fp, void* data) { return save_wld(fp, data); } - -bool CFile::read_bob01(FILE*) -{ - return false; -} - -bool CFile::read_bob02(FILE* fp) -{ - // length of data block - Uint32 length; - // offset of next entry in file - Uint32 next_entry; - // endmark - to test, if a data block has correctly read - Uint8 endmark; - - // Pic-Data - // start adresses of picture lines in the file (offsets) - Uint16* starts; - // starting point for start adresses (starting_point + starts[i] = beginning of i. picture line) - Uint32 starting_point; - // number of following colored pixels in data block - Uint8 count_color; - // number of transparent pixels - Uint8 count_trans; - // color value for read pixel - Uint8 color_value; - - // coordinate for zeropoint x (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->nx), fp)); - // coordinate for zeropoint y (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->ny), fp)); - // skip unknown data (4x 1 Byte) - fseek(fp, 4, SEEK_CUR); - // width of picture (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->w), fp)); - // height of picture (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->h), fp)); - // skip unknown data (1x 2 Bytes) - fseek(fp, 2, SEEK_CUR); - // length of data block (1x 4 Bytes) - CHECK_READ(libendian::le_read_ui(&length, fp)); - // fp points now ON the first start adress, so "actual position + length = first offset of next entry in the file" - starting_point = ftell(fp); - next_entry = starting_point + length; - - // if we only want to read a palette at the moment (loadPAL == 1) so skip this and set the filepointer to the next - // entry - if(loadPAL) - { - fseek(fp, (long int)next_entry, SEEK_SET); - return true; - } - - // array for start addresses of picture lines - starts = new Uint16[bmpArray->h]; - - // read start addresses - for(int y = 0; y < bmpArray->h; y++) - CHECK_READ(libendian::le_read_us(&starts[y], fp)); - - // now we are ready to read the picture lines and fill the surface, so lets create one - if((bmpArray->surface = makePalSurface(bmpArray->w, bmpArray->h, palActual->colors)) == nullptr) - return false; - SDL_SetColorKey(bmpArray->surface.get(), SDL_TRUE, 0); - // SDL_SetAlpha(bmpArray->surface, SDL_SRCALPHA, 128); - - // main loop for reading picture lines - for(Position pos{0, 0}; pos.y < bmpArray->h; pos.y++) - { - // set fp to the needed offset (where the picture line starts) - fseek(fp, starting_point + (Uint32)starts[pos.y], SEEK_SET); - - // loop for reading pixels of the actual picture line - //(cause of a kind of RLE-Compression we cannot read the pixels sequentially) - //'x' will be incremented WITHIN the loop - for(pos.x = 0; pos.x < bmpArray->w;) - { - // number of following colored pixels (1 Byte) - CHECK_READ(libendian::read(&count_color, 1, fp)); - - // loop for drawing the colored pixels to the surface - for(int k = 0; k < count_color; k++, pos.x++) - { - // read color value (1 Byte) - CHECK_READ(libendian::read(&color_value, 1, fp)); - // draw - CSurface::DrawPixel_Color(bmpArray->surface.get(), pos, (Uint32)color_value); - } - - // number of transparent pixels to draw now (1 Byte) - CHECK_READ(libendian::read(&count_trans, 1, fp)); - - // loop for drawing the transparent pixels to the surface - for(int k = 0; k < count_trans; k++, pos.x++) - { - CSurface::DrawPixel_RGBA(bmpArray->surface.get(), pos, 0, 0, 0, 0); - } - } - - // the end of line should be 0xFF, otherwise an error has occurred (1 Byte) - CHECK_READ(libendian::read(&endmark, 1, fp)); - if(endmark != 0xFF) - return false; - } - - // at the end of the block (after the last line) there should be another 0xFF, otherwise an error has occurred (1 - // Byte) - CHECK_READ(libendian::read(&endmark, 1, fp)); - if(endmark != 0xFF) - return false; - - // we are finished, the surface is filled - // fp should now point to the first offset of the next entry, this is the last check if this is REALLY the RIGHT - // position - if(ftell(fp) != (long int)next_entry) - { - fseek(fp, (long int)next_entry, SEEK_SET); - return false; - } - - // increment bmpArray for the next picture - bmpArray++; - - delete[] starts; - - return true; -} - -bool CFile::read_bob03(FILE* fp) -{ - // temporary skip x- and y-spacing (2x 1 Byte) --> we will handle this later - fseek(fp, 2, SEEK_CUR); - - // read bobtype04 115 times (for 115 ansi chars) - for(int i = 1; i <= 115; i++) - { - // bobtype of the entry - Uint16 bobtype; - // following data blocks are bobtype04 for some ascii chars, bobtype is repeated at the beginning of each data - // block - CHECK_READ(libendian::le_read_us(&bobtype, fp)); - - // bobtype should be 04. if not, it's possible that there are a lot of zeros till the next block begins - if(bobtype != BOBTYPE04) - { - // read the zeros (2 Bytes for each zero) - while(bobtype == 0) - CHECK_READ(libendian::le_read_us(&bobtype, fp)); - - // at the end of all the zeros --> if bobtype is STILL NOT 04, an error has occured - if(bobtype != BOBTYPE04) - return false; - } - - // now read the picture for each player color - const auto offset = ftell(fp); - constexpr std::array player_colors{ - PLAYER_BLUE, PLAYER_RED, PLAYER_ORANGE, PLAYER_GREEN, PLAYER_MINTGREEN, PLAYER_YELLOW, PLAYER_RED_BRIGHT, - }; - for(const int player_color : player_colors) - { - fseek(fp, offset, SEEK_SET); - if(!read_bob04(fp, player_color)) - return false; - } - } - - return true; -} - -bool CFile::read_bob04(FILE* fp, int player_color) -{ - // length of data block - Uint32 length; - // offset of next entry in file - Uint32 next_entry; - - // Pic-Data - //'shift' (1 Byte) --> to decide what pixels and how many we have to draw - Uint8 shift; - // start adresses of picture lines in the file (offsets) - Uint16* starts; - // starting point for start adresses (starting_point + starts[i] = beginning of i. picture line) - Uint32 starting_point; - // color value for read pixel - Uint8 color_value; - - // coordinate for zeropoint x (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->nx), fp)); - // coordinate for zeropoint y (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->ny), fp)); - // skip unknown data (4x 1 Byte) - fseek(fp, 4, SEEK_CUR); - // width of picture (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->w), fp)); - // heigth of picture (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->h), fp)); - // skip unknown data (1x 2 Bytes) - fseek(fp, 2, SEEK_CUR); - // length of datablock (1x 4 Bytes) - CHECK_READ(libendian::le_read_ui(&length, fp)); - // fp points now ON the first start adress, so "actual position + length = first offset of next entry in the file" - starting_point = ftell(fp); - next_entry = starting_point + length; - - // if we only want to read a palette at the moment (loadPAL == 1) so skip this and set the filepointer to the next - // entry - if(loadPAL) - { - fseek(fp, (long int)next_entry, SEEK_SET); - return true; - } - - // array for start addresses of picture lines - starts = new Uint16[bmpArray->h]; - - // read start addresses - for(int y = 0; y < bmpArray->h; y++) - CHECK_READ(libendian::le_read_us(&starts[y], fp)); - - // now we are ready to read the picture lines and fill the surface, so lets create one - if((bmpArray->surface = makePalSurface(bmpArray->w, bmpArray->h, palActual->colors)) == nullptr) - return false; - - SDL_SetColorKey(bmpArray->surface.get(), SDL_TRUE, 0); - - // main loop for reading picture lines - for(Position pos{0, 0}; pos.y < bmpArray->h; pos.y++) - { - // set fp to the needed offset (where the picture line starts) - fseek(fp, starting_point + (Uint32)starts[pos.y], SEEK_SET); - - // loop for reading pixels of the actual picture line - //(cause of a kind of RLE-Compression we cannot read the pixels sequentially) - //'x' will be incremented WITHIN the loop - for(pos.x = 0; pos.x < bmpArray->w;) - { - // read our 'shift' (1 Byte) - CHECK_READ(libendian::read(&shift, 1, fp)); - - if(shift < 0x41) - { - for(int i = 1; i <= shift; i++, pos.x++) - { - CSurface::DrawPixel_RGBA(bmpArray->surface.get(), pos, 0, 0, 0, 0); - } - } else if(shift < 0x81) - { - CHECK_READ(libendian::read(&color_value, 1, fp)); - - for(int i = 1; i <= shift - 0x40; i++, pos.x++) - { - CSurface::DrawPixel_Color(bmpArray->surface.get(), pos, /*0x80 - 0x40*/ +(Uint32)color_value); - } - } else if(shift < 0xC1) - { - CHECK_READ(libendian::read(&color_value, 1, fp)); - - for(int i = 1; i <= shift - 0x80; i++, pos.x++) - { - CSurface::DrawPixel_Color(bmpArray->surface.get(), pos, player_color + (Uint32)color_value); - } - } else // if (shift > 0xC0) - { - CHECK_READ(libendian::read(&color_value, 1, fp)); - - for(int i = 1; i <= shift - 0xC0; i++, pos.x++) - { - CSurface::DrawPixel_Color(bmpArray->surface.get(), pos, (Uint32)color_value); - } - } - } - } - - // we are finished, the surface is filled - // fp should now point to the first offset of the next entry, this is the last check if this is REALLY the RIGHT - // position - if(ftell(fp) != (long int)next_entry) - { - fseek(fp, (long int)next_entry, SEEK_SET); - // return false; - } - - // increment bmpArray for the next picture - bmpArray++; - - delete[] starts; - - return true; -} - -bool CFile::read_bob05(FILE* fp) -{ - // skip: unknown data (1x 2 Bytes) - fseek(fp, 2, SEEK_CUR); - - for(auto& color : palArray->colors) - { - CHECK_READ(libendian::read(&(color.r), 1, fp)); - CHECK_READ(libendian::read(&(color.g), 1, fp)); - CHECK_READ(libendian::read(&(color.b), 1, fp)); - color.a = 255; - } - - palArray++; - - return true; -} - -bool CFile::read_bob07(FILE* fp) -{ - // length of data block - Uint32 length; - // offset of next entry in file - Uint32 next_entry; - // endmark - to test, if a data block has correctly read - Uint8 endmark; - - // Pic-Data - // start adresses of picture lines in the file (offsets) - Uint16* starts; - // starting point for start adresses (starting_point + starts[i] = beginning of i. picture line) - Uint32 starting_point; - // number of half-transparent black pixels in data block - Uint8 count_black; - // number of transparent pixels - Uint8 count_trans; - - // coordinate for zeropoint x (2 Bytes) - CHECK_READ(libendian::le_read_us(&(shadowArray->nx), fp)); - // coordinate for zeropoint y (2 Bytes) - CHECK_READ(libendian::le_read_us(&(shadowArray->ny), fp)); - // skip unknown data (4x 1 Byte) - fseek(fp, 4, SEEK_CUR); - // width of picture (2 Bytes) - CHECK_READ(libendian::le_read_us(&(shadowArray->w), fp)); - // heigth of picture (2 Bytes) - CHECK_READ(libendian::le_read_us(&(shadowArray->h), fp)); - // skip unknown data (1x 2 Bytes) - fseek(fp, 2, SEEK_CUR); - // length of datablock (1x 4 Bytes) - CHECK_READ(libendian::le_read_ui(&length, fp)); - // fp points now ON the first start adress, so "actual position + length = first offset of next entry in the file" - starting_point = ftell(fp); - next_entry = starting_point + length; - - // if we only want to read a palette at the moment (loadPAL == 1) so skip this and set the filepointer to the next - // entry - if(loadPAL) - { - fseek(fp, (long int)next_entry, SEEK_SET); - return true; - } - - // array for start addresses of picture lines - starts = new Uint16[shadowArray->h]; - - // read start addresses - for(int y = 0; y < shadowArray->h; y++) - CHECK_READ(libendian::le_read_us(&starts[y], fp)); - - // now we are ready to read the picture lines and fill the surface, so lets create one - if((shadowArray->surface = makePalSurface(shadowArray->w, shadowArray->h, palActual->colors)) == nullptr) - return false; - // SDL_SetAlpha(shadowArray->surface, SDL_SRCALPHA, 128); - - // main loop for reading picture lines - for(Position pos{0, 0}; pos.y < shadowArray->h; pos.y++) - { - // set fp to the needed offset (where the picture line starts) - fseek(fp, starting_point + (Uint32)starts[pos.y], SEEK_SET); - - // loop for reading pixels of the actual picture line - //(cause of a kind of RLE-Compression we cannot read the pixels sequentially) - //'x' will be incremented WITHIN the loop - for(pos.x = 0; pos.x < shadowArray->w;) - { - // number of half-transparent black (alpha value = 0x40) pixels (1 Byte) - CHECK_READ(libendian::read(&count_black, 1, fp)); - - // loop for drawing the black pixels to the surface - for(int k = 0; k < count_black; k++, pos.x++) - { - // draw - CSurface::DrawPixel_RGBA(shadowArray->surface.get(), pos, 0, 0, 0, 0x40); - } - - // number of transparent pixels to draw now (1 Byte) - CHECK_READ(libendian::read(&count_trans, 1, fp)); - - // loop for drawing the transparent pixels to the surface - for(int k = 0; k < count_trans; k++, pos.x++) - { - CSurface::DrawPixel_RGBA(shadowArray->surface.get(), pos, 0, 0, 0, 0); - } - } - - // the end of line should be 0xFF, otherwise an error has occurred (1 Byte) - CHECK_READ(libendian::read(&endmark, 1, fp)); - if(endmark != 0xFF) - return false; - } - - // at the end of the block (after the last line) there should be another 0xFF, otherwise an error has occurred (1 - // Byte) - CHECK_READ(libendian::read(&endmark, 1, fp)); - if(endmark != 0xFF) - return false; - - // we are finished, the surface is filled - // fp should now point to the first offset of the next entry, this is the last check if this is REALLY the RIGHT - // position - if(ftell(fp) != (long int)next_entry) - { - fseek(fp, (long int)next_entry, SEEK_SET); - return false; - } - - /**FOLLOWING COMMENTS ARE ABSOLUTLY TEMPORARY, UNTIL I KNOW HOW TO HANDLE SHADOWS WITH ALPHA-BLENDING AND THEN - *BLITTING - ***---THIS CODE IS NOT USEFUL.**/ - // We have to blit picture and shadow together and because of transparency we need to set the colorkey - // SDL_SetColorKey(shadowArray->surface, SDL_SRCCOLORKEY, SDL_MapRGBA(shadowArray->surface->format, 0, 0, 0, 0)); - // SDL_BlitSurface(shadowArray->surface, nullptr, (shadowArray-1)->surface, nullptr); - // SDL_FreeSurface(shadowArray->surface); - // increment shadowArray - shadowArray++; - - delete[] starts; - - return true; -} - -bool CFile::read_bob14(FILE* fp) -{ - // length of data block - Uint32 length; - // offset of next entry in file - long int next_entry; - - // Pic-Data - // offset for the first byte of the data block - long int data_start; - // color value for read pixel - Uint8 color_value; - - // skip unknown data (1x 2 Bytes) - fseek(fp, 2, SEEK_CUR); - // length of datablock (1x 4 Bytes) - CHECK_READ(libendian::le_read_ui(&length, fp)); - // start offset of data block - data_start = ftell(fp); - // jump to first offset after data block - fseek(fp, length, SEEK_CUR); - // coordinate for zero point x (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->nx), fp)); - // coordinate for zero point y (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->ny), fp)); - // width of picture (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->w), fp)); - // heigth of picture (2 Bytes) - CHECK_READ(libendian::le_read_us(&(bmpArray->h), fp)); - // skip unknown data (8x 1 Byte) - fseek(fp, 8, SEEK_CUR); - - // fp points now ON the first adress of the next entry in the file - next_entry = ftell(fp); - - // if we only want to read a palette at the moment (loadPAL == 1) so skip this and let fp on the adress of the next - // entry - if(loadPAL) - return true; - - // now we are ready to read the picture lines and fill the surface, so lets create one - if((bmpArray->surface = makePalSurface(bmpArray->w, bmpArray->h, palActual->colors)) == nullptr) - return false; - - // set fp to back to the first offset of data block - fseek(fp, data_start, SEEK_SET); - - // main loop for reading picture lines - for(Position pos{0, 0}; pos.y < bmpArray->h; pos.y++) - { - // loop for reading pixels of the actual picture line - for(pos.x = 0; pos.x < bmpArray->w; pos.x++) - { - // read color value (1 Byte) - CHECK_READ(libendian::read(&color_value, 1, fp)); - // draw - CSurface::DrawPixel_Color(bmpArray->surface.get(), pos, (Uint32)color_value); - } - } - - // we are finished, the surface is filled - // fp should now point to nx again, so set it to the next entry in the file - fseek(fp, (long int)next_entry, SEEK_SET); - - // increment bmpArray for the next picture - bmpArray++; - - return true; -} diff --git a/CIO/CFile.h b/CIO/CFile.h index 1dc14b6..54fe30e 100644 --- a/CIO/CFile.h +++ b/CIO/CFile.h @@ -3,8 +3,6 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -// handling of the files and data types is mostly based on the file specification from the 'Return to the Roots'-Team - #pragma once #include "defines.h" @@ -12,53 +10,17 @@ #include #include -struct bobBMP; -struct bobSHADOW; -struct bobPAL; struct bobMAP; class CFile { private: - static bool loadPAL; - static bobBMP* bmpArray; - static bobSHADOW* shadowArray; - static bobPAL* palArray; - static bobPAL* palActual; // surfaces for new pictures will use this palette -public: - // Access Methods - static void set_palActual(bobPAL* Actual) { palActual = Actual; } - static bobPAL* get_palArray() { return palArray; } - static void set_palArray(bobPAL* Array) { palArray = Array; } - static void set_bmpArray(bobBMP* new_bmpArray) { bmpArray = new_bmpArray; } - -private: - // Methods - static bool read_lst(FILE* fp); - static bool read_bob(FILE* fp); // not implemented yet - static bool open_idx(const boost::filesystem::path& filepath); - static bool read_bbm(FILE* fp); - static bool read_lbm(FILE* fp, const boost::filesystem::path& filepath); - static bool read_gou(FILE* fp); static bobMAP* read_wld(FILE* fp); static bobMAP* read_swd(FILE* fp); - static bool save_lst(FILE* fp, void* data); // not implemented yet - static bool save_bob(FILE* fp, void* data); // not implemented yet - static bool save_idx(FILE* fp, void* data); // not implemented yet - static bool save_bbm(FILE* fp, void* data); // not implemented yet - static bool save_lbm(FILE* fp, void* data); // not implemented yet static bool save_wld(FILE* fp, void* data); static bool save_swd(FILE* fp, void* data); - static bool read_bob01(FILE* fp); // not implemented yet - static bool read_bob02(FILE* fp); - static bool read_bob03(FILE* fp); - static bool read_bob04(FILE* fp, int player_color = PLAYER_BLUE); - static bool read_bob05(FILE* fp); - static bool read_bob07(FILE* fp); - static bool read_bob14(FILE* fp); public: - static void init(); - static void* open_file(const boost::filesystem::path& filepath, char filetype, bool only_loadPAL = false); + static void* open_file(const boost::filesystem::path& filepath, char filetype); static bool save_file(const boost::filesystem::path& filepath, char filetype, void* data); }; diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp index 77b12be..1c08f12 100644 --- a/CIO/CFont.cpp +++ b/CIO/CFont.cpp @@ -4,11 +4,19 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CFont.h" +#include "../CIO/CFile.h" #include "../CSurface.h" #include "../Texture.h" #include "../globals.h" #include "CollisionDetection.h" +#include +#include +#include +#include +#include #include +#include +#include CFont::CFont(std::string text, Position pos, FontSize fontsize, FontColor color) : pos_(pos), string_(std::move(text)), fontsize_(fontsize), color_(color), initialColor_(color), clickedParam(0) @@ -64,230 +72,198 @@ void CFont::setMouseData(SDL_MouseButtonEvent button) } } -namespace { -unsigned getIndexForChar(uint8_t c) +// atlas-based rendering +struct GlyphPos { - // subtract 32 shows that we start by spacebar as 'zero-position' - if(c >= 32 && c <= 90) - return c - 32; - /* \ */ - else if(c == 92) - return 59; - // _ - else if(c == 95) - return 60; - // between 'a' and 'z' - else if(c >= 97 && c <= 122) - return c - 32 - 4; - // © - else if(c == 169) - return 114; - // Ä - else if(c == 196) - return 100; - // Ç - else if(c == 199) - return 87; - // Ö - else if(c == 214) - return 106; - // Ü - else if(c == 220) - return 107; - // ß - else if(c == 223) - return 113; - // à - else if(c == 224) - return 92; - // á - else if(c == 225) - return 108; - // â - else if(c == 226) - return 90; - // ä - else if(c == 228) - return 91; - // ç - else if(c == 231) - return 93; - // è - else if(c == 232) - return 96; - // é - else if(c == 233) - return 89; - // ê - else if(c == 234) - return 94; - // ë - else if(c == 235) - return 95; - // ì - else if(c == 236) - return 99; - // í - else if(c == 237) - return 109; - // î - else if(c == 238) - return 98; - // ï - else if(c == 239) - return 97; - // ñ - else if(c == 241) - return 112; - // ò - else if(c == 242) - return 103; - // ó - else if(c == 243) - return 110; - // ô - else if(c == 244) - return 101; - // ö - else if(c == 246) - return 102; - // ù - else if(c == 249) - return 105; - // ú - else if(c == 250) - return 111; - // û - else if(c == 251) - return 104; - // ü - else if(c == 252) - return 88; - // chiffre not available, use '_' instead - return 60; -} + unsigned x, y, w; +}; +struct FontAtlas +{ + Texture tex; + unsigned lineHeight = 0; + unsigned maxWidth = 0; + std::array glyphs{}; +}; -unsigned getIndexForChar(uint8_t c, FontSize fontsize, FontColor color) +static libsiedler2::ColorRGB getPlayerColor(FontColor color) { - unsigned offset; - switch(fontsize) + switch(color) { - case FontSize::Small: offset = FONT9_SPACE; break; - default: - case FontSize::Medium: offset = FONT11_SPACE; break; - case FontSize::Large: offset = FONT14_SPACE; break; + case FontColor::Blue: return {64, 128, 255}; + case FontColor::Red: return {255, 64, 64}; + case FontColor::Orange: return {255, 165, 0}; + case FontColor::Green: return {64, 192, 64}; + case FontColor::MintGreen: return {64, 255, 160}; + case FontColor::Yellow: return {255, 255, 0}; + case FontColor::BrightRed: return {255, 32, 32}; } - return offset + getIndexForChar(c) * NUM_FONT_COLORS + static_cast(color); -} - -unsigned getCharWidth(uint8_t c, FontSize fontsize, FontColor color) -{ - // NOTE: there is a bug in the ansi 236 'ì' at fontsize 9, the width is 39, this is not useable, we will use the - // width of ansi 237 'í' instead - if(fontsize == FontSize::Small && c == 236) - c = 109; - return global::bmpArray[getIndexForChar(c, fontsize, color)].w; + return {255, 255, 0}; } -} // namespace -void CFont::draw(const std::string& string, Position pos, FontSize fontsize, FontColor color, FontAlign align) +static FontAtlas& getAtlas(FontSize size, FontColor color) { - if(string.empty()) - return; - - // Measure text width for alignment - unsigned totalWidth = 0; - for(unsigned char c : string) - totalWidth += getCharWidth(c, fontsize, color); - - // Apply alignment - switch(align) + static FontAtlas atlases[3][7]; + int ci = static_cast(color); + if(ci < 0 || ci > 6) + ci = 0; + int si; + switch(size) { - case FontAlign::Middle: pos.x -= static_cast(totalWidth / 2); break; - case FontAlign::Right: pos.x -= static_cast(totalWidth); break; - case FontAlign::Left: break; // no adjustment + case FontSize::Small: si = 0; break; + case FontSize::Medium: si = 1; break; + case FontSize::Large: si = 2; break; + default: si = 0; break; } - - // Draw each character as a textured quad - Position curPos = pos; - for(unsigned char c : string) + if(!atlases[si][ci].tex.isValid()) { - auto& tex = getBmpTexture(getIndexForChar(c, fontsize, color)); - tex.draw(Rect(curPos, tex.getSize())); - curPos.x += tex.getSize().x; - } -} + auto& a = atlases[si][ci]; + // Resolve the font from the EDITRES archive by height + unsigned targetDy = static_cast(size); + auto& archiv = global::typedArchives[ArchiveID::EDITRES]; + const libsiedler2::ArchivItem_Font* font = nullptr; + for(unsigned i = 0; i < archiv.size(); i++) + { + auto* f = dynamic_cast(archiv.get(i)); + if(!f) + continue; + unsigned dy = f->getDy(); + if(dy + 1 >= targetDy && dy <= targetDy + 1) + { + font = f; + break; + } + } + if(!font) + return a; -bool CFont::writeText(SDL_Surface* Surf_Dest, const std::string& string, unsigned x, unsigned y, FontSize fontsize, - FontColor color, FontAlign align) -{ - // data for necessary counting pixels depending on alignment - unsigned pixel_ctr_w = 0; - // counter for the drawed pixels (cause we dont want to draw outside of the surface) - unsigned pos_x = x; - unsigned pos_y = y; + a.lineHeight = font->getDy() + 1; + unsigned advW = font->getDx(); + a.maxWidth = advW; - if(!Surf_Dest || string.empty()) - return false; + unsigned numGlyphs = 0; + for(unsigned i = 32; i < font->size(); ++i) + { + if(font->get(i)) + numGlyphs++; + } + if(numGlyphs == 0) + return a; - // are there enough vertical pixels to draw the chiffres? - if(Surf_Dest->h < static_cast(y + static_cast(fontsize))) - return false; + auto numCols = static_cast(std::sqrt(static_cast(numGlyphs))); + if(numCols < 1) + numCols = 1; + unsigned numRows = (numGlyphs + numCols - 1) / numCols; + constexpr Extent spacing(1, 1); + Extent cellSize(advW + spacing.x * 2, font->getDy() + spacing.y * 2); + Extent texSize = cellSize * Extent(numCols, numRows) + spacing * 2u; - // in case of right or middle alignment we must count the pixels first - auto pixel_count_loop = (align == FontAlign::Middle) || (align == FontAlign::Right); + libsiedler2::PixelBufferBGRA buffer(texSize.x, texSize.y); - // now lets draw the chiffres - auto chiffre = string.begin(); - while(chiffre != string.end()) - { - const auto charW = getCharWidth(*chiffre, fontsize, color); - // if we only count pixels in this round - if(pixel_count_loop) + // Build a palette where player-color indices 128-135 map to the + // requested FontColor, and everything else is dark outline. + auto playerClr = getPlayerColor(color); + auto atlasPal = std::make_unique(); { - pixel_ctr_w += charW; - - // if text is to long to go further left, stop loop and begin writing at x=0 - if((align == FontAlign::Middle && pixel_ctr_w / 2 > x) || static_cast(pixel_ctr_w) >= Surf_Dest->w) + const auto* srcPal = global::currentPalette; + if(!srcPal) + return a; + for(int i = 0; i < 256; i++) { - pos_x = 0; - chiffre = string.begin(); - pixel_count_loop = false; - continue; + if(i >= 128 && i < 136) + atlasPal->set(i, playerClr); + else if(i == 0) + atlasPal->set(i, libsiedler2::ColorRGB(0, 0, 0)); // transparent background + else + atlasPal->set(i, libsiedler2::ColorRGB(32, 32, 32)); // dark outline } + } - ++chiffre; - - // if this was the last chiffre go in normal mode and write the text to the specified position - if(chiffre == string.end()) - { - chiffre = string.begin(); + unsigned gi = 0; + for(unsigned ci = 32; ci < font->size(); ++ci) + { + auto* sub = font->get(ci); + const auto* pg = dynamic_cast(sub); + if(!pg) + continue; - if(align == FontAlign::Middle) - pos_x = x - pixel_ctr_w / 2; - else if(align == FontAlign::Right) - pos_x = Surf_Dest->w - pixel_ctr_w; + unsigned col = gi % numCols, row = gi / numCols; + unsigned px = spacing.x + col * cellSize.x; + unsigned py = spacing.y + row * cellSize.y; - pixel_count_loop = false; - } - continue; + const_cast(pg)->print(buffer, atlasPal.get(), 128, px, py, 0, 0, 0, + 0); + a.glyphs[ci] = GlyphPos{px, py, pg->getWidth()}; + if(pg->getWidth() > a.maxWidth) + a.maxWidth = pg->getWidth(); + gi++; } - // if right end of surface is reached, stop drawing chiffres - if(Surf_Dest->w < static_cast(pos_x + charW)) - break; + a.tex.load(buffer.getPixelPtr(), texSize); + } + return atlases[si][ci]; +} + +static unsigned getCharWidth(uint8_t c, FontSize fontsize) +{ + if(fontsize == FontSize::Small && c == 236) + c = 109; + auto& atlas = getAtlas(fontsize, FontColor::Yellow); + if(!atlas.tex.isValid()) + return 8; + auto& g = atlas.glyphs[c]; + if(g.w > 0) + return g.w; + return atlas.maxWidth; // fallback +} - // draw the chiffre to the destination - CSurface::Draw(Surf_Dest, global::bmpArray[getIndexForChar(*chiffre, fontsize, color)].surface, pos_x, pos_y); +void CFont::draw(const std::string& string, Position pos, FontSize fontsize, FontColor color, FontAlign align) +{ + if(string.empty()) + return; + auto& atlas = getAtlas(fontsize, color); + if(!atlas.tex.isValid()) + return; - // set position for next chiffre - pos_x += charW; + unsigned totalW = CFont::getTextWidth(string, fontsize); + if(align == FontAlign::Middle) + pos.x -= static_cast(totalW / 2); + else if(align == FontAlign::Right) + pos.x -= static_cast(totalW); - // go to next chiffre - ++chiffre; - } + float texW = static_cast(atlas.tex.getSize().x); + float texH = static_cast(atlas.tex.getSize().y); - return true; + glBindTexture(GL_TEXTURE_2D, atlas.tex.getHandle()); + glColor4f(1, 1, 1, 1); + glBegin(GL_QUADS); + + int curX = pos.x; + for(char c : string) + { + unsigned char uc = static_cast(c); + auto& g = atlas.glyphs[uc]; + if(g.w == 0) + { + curX += atlas.maxWidth / 2; + continue; + } + int gh = static_cast(atlas.lineHeight); + float u0 = static_cast(g.x) / texW; + float v0 = static_cast(g.y) / texH; + float u1 = static_cast(g.x + g.w) / texW; + float v1 = static_cast(g.y + gh) / texH; + + glTexCoord2f(u0, v0); + glVertex2i(curX, pos.y); + glTexCoord2f(u1, v0); + glVertex2i(curX + g.w, pos.y); + glTexCoord2f(u1, v1); + glVertex2i(curX + g.w, pos.y + gh); + glTexCoord2f(u0, v1); + glVertex2i(curX, pos.y + gh); + curX += g.w; // advance by glyph width + } + glEnd(); } unsigned CFont::getTextWidth(const std::string& string, FontSize fontsize) @@ -297,7 +273,7 @@ unsigned CFont::getTextWidth(const std::string& string, FontSize fontsize) { if(c == '\n') break; - w += getCharWidth(c, fontsize, FontColor::Yellow); // width is same for all colors + w += getCharWidth(c, fontsize); } return w; } diff --git a/CIO/CFont.h b/CIO/CFont.h index 698eb5b..0dc2125 100644 --- a/CIO/CFont.h +++ b/CIO/CFont.h @@ -55,17 +55,6 @@ class CFont static void draw(const std::string& string, Position pos, FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow, FontAlign align = FontAlign::Left); - /// Static helper: draw text onto an SDL surface (for terrain / minimap rendering). - static bool writeText(SDL_Surface* Surf_Dest, const std::string& string, unsigned x = 0, unsigned y = 0, - FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow, - FontAlign align = FontAlign::Left); - static bool writeText(SdlSurface& Surf_Dest, const std::string& string, Position pos, - FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow, - FontAlign align = FontAlign::Left) - { - return writeText(Surf_Dest.get(), string, pos.x, pos.y, fontsize, color, align); - } - /// Compute the pixel width of a string without drawing it. static unsigned getTextWidth(const std::string& string, FontSize fontsize); }; diff --git a/CIO/CMenu.cpp b/CIO/CMenu.cpp index fe1d3fb..7edcdd6 100644 --- a/CIO/CMenu.cpp +++ b/CIO/CMenu.cpp @@ -8,13 +8,13 @@ #include "../Texture.h" #include "../globals.h" -CMenu::CMenu(int pic_background) : CControlContainer(pic_background) {} +CMenu::CMenu(int pic_background, ArchiveID archive) : CControlContainer(pic_background, BorderSizes{}, archive) {} void CMenu::draw(Position /*parentOrigin*/) { // Draw full-screen background texture const auto res = global::s2->getRes(); - getBmpTexture(getBackground(), true).draw(Rect(0, 0, res.x, res.y)); + getTexture(backgroundArchive_, getBackground()).draw(Rect(0, 0, res.x, res.y)); drawChildren(Position(0, 0)); } diff --git a/CIO/CMenu.h b/CIO/CMenu.h index 0b4fedb..49ff572 100644 --- a/CIO/CMenu.h +++ b/CIO/CMenu.h @@ -5,6 +5,7 @@ #pragma once +#include "ArchiveID.h" #include "CControlContainer.h" class CMenu final : public CControlContainer @@ -13,7 +14,7 @@ class CMenu final : public CControlContainer bool active = true; public: - CMenu(int pic_background); + CMenu(int pic_background, ArchiveID archive); void setActive() { active = true; } void setInactive() { active = false; } bool isActive() const { return active; } diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index 6b7f4e5..080093f 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -8,6 +8,7 @@ #include "../Texture.h" #include "../globals.h" #include "CFont.h" +#include void CMinimapWindow::draw(Position /*parentOrigin*/) { @@ -45,8 +46,7 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) const int flagIdx = FLAG_BLUE_DARK + i % 7; const Position hqPos = Position(hqX, hqY) / scale; - const Position flagOffset(global::bmpArray[flagIdx].nx, global::bmpArray[flagIdx].ny); - getBmpTexture(flagIdx).draw(contentPos + hqPos - flagOffset); + Texture::getTexture(ArchiveID::EDITBOB, flagIdx).drawSprite(contentPos + hqPos); // Player number CFont::draw(std::to_string(i + 1), contentPos + hqPos, FontSize::Small, FontColor::MintGreen); @@ -57,8 +57,9 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) const int arrowIdx = MAPPIC_ARROWCROSS_ORANGE; const auto& dispRect = map->getDisplayRect(); const Position arrowCenter = dispRect.getOrigin() + dispRect.getSize() / 2u; - const Position arrowPos = contentPos + arrowCenter / Position(triangleWidth, triangleHeight) / scale - - Position(global::bmpArray[arrowIdx].nx, global::bmpArray[arrowIdx].ny); - getBmpTexture(arrowIdx).draw(arrowPos); + auto& tex = Texture::getTexture(ArchiveID::MAP00, arrowIdx); + const Position arrowPos = + contentPos + arrowCenter / Position(triangleWidth, triangleHeight) / scale - tex.anchor(); + tex.draw(arrowPos); } } diff --git a/CIO/CPicture.cpp b/CIO/CPicture.cpp index abe2f41..c17bd87 100644 --- a/CIO/CPicture.cpp +++ b/CIO/CPicture.cpp @@ -7,17 +7,20 @@ #include "../Texture.h" #include "../globals.h" #include "CollisionDetection.h" +#include +#include -CPicture::CPicture(void callback(int), int clickedParam, Position pos, int picture) : pos_(pos) +CPicture::CPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, int picture) + : pos_(pos), archive_(archive), picture_(picture >= 0 ? picture : 0) { marked = false; clicked = false; - if(picture >= 0) - this->picture_ = picture; - else - this->picture_ = 0; - this->size_.x = global::bmpArray[picture].w; - this->size_.y = global::bmpArray[picture].h; + auto& archiv = global::typedArchives[archive]; + if(picture >= 0 && static_cast(picture) < archiv.size()) + { + if(auto* bmp = dynamic_cast(archiv.get(picture))) + size_ = Extent(bmp->getWidth(), bmp->getHeight()); + } this->callback = callback; this->clickedParam = clickedParam; motionEntryParam = -1; @@ -66,5 +69,5 @@ void CPicture::setMouseData(const SDL_MouseButtonEvent& button) void CPicture::draw(Position parentOrigin) const { - getBmpTexture(picture_).draw(parentOrigin + pos_); + getTexture(archive_, picture_).draw(parentOrigin + pos_); } diff --git a/CIO/CPicture.h b/CIO/CPicture.h index 5a88a57..dab853b 100644 --- a/CIO/CPicture.h +++ b/CIO/CPicture.h @@ -5,6 +5,7 @@ #pragma once +#include "ArchiveID.h" #include "Point.h" #include "defines.h" @@ -15,6 +16,7 @@ class CPicture private: Position pos_; Extent size_; + ArchiveID archive_; int picture_; bool marked; bool clicked; @@ -24,7 +26,7 @@ class CPicture int motionLeaveParam; public: - CPicture(void callback(int), int clickedParam, Position pos = {0, 0}, int picture = -1); + CPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, int picture); // Access int getX() const { return pos_.x; }; int getY() const { return pos_.y; }; diff --git a/CIO/CSelectBox.cpp b/CIO/CSelectBox.cpp index a8cc946..399f99d 100644 --- a/CIO/CSelectBox.cpp +++ b/CIO/CSelectBox.cpp @@ -213,7 +213,7 @@ void CSelectBox::draw(Position parentOrigin) // Draw background if(pic_background >= 0 && pic_foreground >= 0) { - getBmpTexture(pic_foreground).drawTiled(area); + getTexture(ArchiveID::EDITIO, pic_foreground).drawTiled(area); } else { // Fill with black diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index 365ab56..23dd456 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -246,7 +246,7 @@ void CTextfield::draw(Position parentOrigin) if(button_style) drawButtonBox(area, active, pic_background, pic_foreground); else - getBmpTexture(pic_foreground).drawTiled(area); + getTexture(ArchiveID::EDITIO, pic_foreground).drawTiled(area); } else { // Fill with black diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 7696e9d..cb1c80e 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -14,13 +14,16 @@ #include "CTextfield.h" #include "CollisionDetection.h" #include "helpers/containerUtils.h" +#include #include #include CWindow::CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title, int color, - Uint8 flags) - : CControlContainer(color, {global::bmpArray[WINDOW_LEFT_FRAME].w, global::bmpArray[WINDOW_UPPER_FRAME].h, - global::bmpArray[WINDOW_RIGHT_FRAME].w, global::bmpArray[WINDOW_LOWER_FRAME].h}), + Uint8 flags, ArchiveID bgArchive) + : CControlContainer( + color, + BorderSizes(ArchiveID::EDITRES, WINDOW_LEFT_FRAME, WINDOW_UPPER_FRAME, WINDOW_RIGHT_FRAME, WINDOW_LOWER_FRAME), + bgArchive), pos_(pos), size_(size), title(title), callback_(callback), callbackQuitMessage(callbackQuitMessage) { assert(callback); @@ -39,8 +42,9 @@ static Position makePos(WindowPos pos, Extent size) } CWindow::CWindow(void callback(int), int callbackQuitMessage, WindowPos pos, Extent size, - const char* title /*= nullptr*/, int color /*= WINDOW_GREEN1*/, Uint8 flags /*= 0*/) - : CWindow(callback, callbackQuitMessage, makePos(pos, size), size, title, color, flags) + const char* title /*= nullptr*/, int color /*= WINDOW_GREEN1*/, Uint8 flags /*= 0*/, + ArchiveID bgArchive /*= ArchiveID::EDITRES*/) + : CWindow(callback, callbackQuitMessage, makePos(pos, size), size, title, color, flags, bgArchive) {} void CWindow::setTitle(const char* title) @@ -48,11 +52,6 @@ void CWindow::setTitle(const char* title) this->title = title; } -void CWindow::setColor(int color) -{ - setBackgroundPicture(color); -} - bool CWindow::hasActiveInputElement() { return helpers::contains_if(getTextFields(), [](const auto& text) { return text->isActive(); }); @@ -61,10 +60,14 @@ bool CWindow::hasActiveInputElement() void CWindow::setMouseData(SDL_MouseMotionEvent motion) { // cursor is on the title frame (+/-2 and +/-4 are only for a good optic) - const Position titleFrameLT = pos_ + Position(global::bmpArray[WINDOW_LEFT_UPPER_CORNER].w + 2, 4); + const Position titleFrameLT = + pos_ + Position(static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_LEFT_UPPER_CORNER).x), 0) + + Position(2, 4); const Position titleFrameRB = - Position(pos_.x + static_cast(size_.x) - global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].w - 2, - pos_.y + global::bmpArray[WINDOW_UPPER_FRAME].h - 4); + pos_ + + Position(static_cast(size_.x), + static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).y)) + - Position(static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_RIGHT_UPPER_CORNER).x) + 2, 4); if(IsPointInRect(motion.x, motion.y, Rect(titleFrameLT, Extent(titleFrameRB - titleFrameLT)))) { // left button was pressed while moving @@ -88,27 +91,30 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) if(canClose) { // cursor is on the button (+/-2 is only for the optic) - canClose_marked = (motion.x >= pos_.x + 2) && (motion.x < pos_.x + global::bmpArray[WINDOW_BUTTON_CLOSE].w - 2) - && (motion.y >= pos_.y + 2) - && (motion.y < pos_.y + global::bmpArray[WINDOW_BUTTON_CLOSE].h - 2); + const auto closeSize = global::getBitmapSize(ArchiveID::EDITRES, WINDOW_BUTTON_CLOSE); + canClose_marked = + IsPointInRect(Position(motion.x, motion.y), Rect(pos_ + Position(2, 2), closeSize - Extent(4, 4))); } // check whats happen to the minimize button if(canMinimize) { // cursor is on the button (+/-2 is only for the optic) + const auto minSize = global::getBitmapSize(ArchiveID::EDITRES, WINDOW_BUTTON_MINIMIZE); canMinimize_marked = - (motion.x >= pos_.x + static_cast(size_.x) - global::bmpArray[WINDOW_BUTTON_MINIMIZE].w + 2) - && (motion.x < pos_.x + static_cast(size_.x) - 2) && (motion.y >= pos_.y + 2) - && (motion.y < pos_.y + global::bmpArray[WINDOW_BUTTON_MINIMIZE].h - 2); + IsPointInRect(Position(motion.x, motion.y), + Rect(pos_ + Position(static_cast(size_.x) - static_cast(minSize.x) + 2, 2), + minSize - Extent(4, 4))); } // check whats happen to the resize button if(canResize) { // cursor is on the button (+/-2 is only for the optic) - if((motion.x >= pos_.x + static_cast(size_.x) - global::bmpArray[WINDOW_BUTTON_RESIZE].w + 2) - && (motion.x < pos_.x + static_cast(size_.x) - 2) - && (motion.y >= pos_.y + static_cast(size_.y) - global::bmpArray[WINDOW_BUTTON_RESIZE].h + 2) - && (motion.y < pos_.y + static_cast(size_.y) - 2)) + const auto resizeSize = global::getBitmapSize(ArchiveID::EDITRES, WINDOW_BUTTON_RESIZE); + if(IsPointInRect(Position(motion.x, motion.y), + Rect(pos_ + + Position(static_cast(size_.x) - static_cast(resizeSize.x) + 2, + static_cast(size_.y) - static_cast(resizeSize.y) + 2), + resizeSize - Extent(4, 4)))) { // left button was pressed while moving if(SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(SDL_BUTTON_LEFT)) @@ -157,7 +163,8 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) // save width and height in case we minimize the window (the initializing values are for preventing any mistakes and // compilerwarning --- in fact: uninitialized values are only a problem if the window is created minimized, but this // will not happen) - static int maximized_h = global::bmpArray[WINDOW_UPPER_FRAME].h + global::bmpArray[WINDOW_CORNER_RECTANGLE].h; + static int maximized_h = global::getBitmapSize(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).y + + global::getBitmapSize(ArchiveID::EDITRES, WINDOW_CORNER_RECTANGLE).y; if(!minimized) maximized_h = static_cast(size_.y); @@ -165,10 +172,14 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) if(button.button == SDL_BUTTON_LEFT) { // cursor is on the title frame (+/-2 and +/-4 are only for a good optic) - if((button.x >= pos_.x + global::bmpArray[WINDOW_LEFT_UPPER_CORNER].w + 2) - && (button.x < pos_.x + static_cast(size_.x) - global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].w - 2) + if((button.x + >= pos_.x + static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_LEFT_UPPER_CORNER).x) + 2) + && (button.x < pos_.x + static_cast(size_.x) + - static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_RIGHT_UPPER_CORNER).x) + - 2) && (button.y >= pos_.y + 4) - && (button.y < pos_.y + static_cast(global::bmpArray[WINDOW_UPPER_FRAME].h) - 4)) + && (button.y + < pos_.y + static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).y) - 4)) { marked = true; clicked = true; @@ -211,7 +222,8 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) minimized = false; } else // minimize now { - size_.y = global::bmpArray[WINDOW_UPPER_FRAME].h + global::bmpArray[WINDOW_CORNER_RECTANGLE].h; + size_.y = global::getBitmapSize(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).y + + global::getBitmapSize(ArchiveID::EDITRES, WINDOW_CORNER_RECTANGLE).y; minimized = true; } } @@ -243,7 +255,7 @@ void CWindow::draw(Position /*parentOrigin*/) { // 1. Background fill (tiled) if(getBackground() != WINDOW_NOTHING) - getBmpTexture(getBackground()).drawTiled(getRect()); + getTexture(backgroundArchive_, getBackground()).drawTiled(getRect()); // 2. Content (if not minimized) — clipped to the area inside frames if(!minimized) @@ -273,51 +285,52 @@ void CWindow::draw(Position /*parentOrigin*/) // Draw upper frame tile across the top of the window { - const Rect upperFrameRect(pos_, Extent(size_.x, getBmpTexture(upperframe).getSize().y)); - getBmpTexture(upperframe).drawTiled(upperFrameRect); + const Rect upperFrameRect(pos_, Extent(size_.x, getTexture(ArchiveID::EDITRES, upperframe).getSize().y)); + getTexture(ArchiveID::EDITRES, upperframe).drawTiled(upperFrameRect); } // 4. Title text if(title) { - const int titleY = pos_.y + (getBmpTexture(WINDOW_UPPER_FRAME).getSize().y - 9) / 2; + const int titleY = pos_.y + (getTexture(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).getSize().y - 9) / 2; CFont::draw(title, Position(pos_.x + static_cast(size_.x) / 2, titleY), FontSize::Small, FontColor::Yellow, FontAlign::Middle); } // 5. Lower frame (tiled across bottom) { - const int lowerH = getBmpTexture(WINDOW_LOWER_FRAME).getSize().y; + const int lowerH = getTexture(ArchiveID::EDITRES, WINDOW_LOWER_FRAME).getSize().y; const Rect lowerFrameRect(Position(pos_.x, pos_.y + static_cast(size_.y) - lowerH), Extent(size_.x, lowerH)); - getBmpTexture(WINDOW_LOWER_FRAME).drawTiled(lowerFrameRect); + getTexture(ArchiveID::EDITRES, WINDOW_LOWER_FRAME).drawTiled(lowerFrameRect); } // 6. Left frame (tiled down left side) { - const Rect leftFrameRect(pos_, Extent(getBmpTexture(WINDOW_LEFT_FRAME).getSize().x, size_.y)); - getBmpTexture(WINDOW_LEFT_FRAME).drawTiled(leftFrameRect); + const Rect leftFrameRect(pos_, Extent(getTexture(ArchiveID::EDITRES, WINDOW_LEFT_FRAME).getSize().x, size_.y)); + getTexture(ArchiveID::EDITRES, WINDOW_LEFT_FRAME).drawTiled(leftFrameRect); } // 7. Right frame (tiled down right side) { - const int rightW = getBmpTexture(WINDOW_RIGHT_FRAME).getSize().x; + const int rightW = getTexture(ArchiveID::EDITRES, WINDOW_RIGHT_FRAME).getSize().x; const Rect rightFrameRect(Position(pos_.x + static_cast(size_.x) - rightW, pos_.y), Extent(rightW, size_.y)); - getBmpTexture(WINDOW_RIGHT_FRAME).drawTiled(rightFrameRect); + getTexture(ArchiveID::EDITRES, WINDOW_RIGHT_FRAME).drawTiled(rightFrameRect); } // 8. Corners { - getBmpTexture(WINDOW_LEFT_UPPER_CORNER).draw(pos_); + getTexture(ArchiveID::EDITRES, WINDOW_LEFT_UPPER_CORNER).draw(pos_); - const int ruW = getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).getSize().x; - getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).draw(pos_ + Position(static_cast(size_.x) - ruW, 0)); + const Extent ru = getTexture(ArchiveID::EDITRES, WINDOW_RIGHT_UPPER_CORNER).getSize(); + getTexture(ArchiveID::EDITRES, WINDOW_RIGHT_UPPER_CORNER) + .draw(pos_ + Position(static_cast(size_.x) - ru.x, 0)); - const int crW = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().x; - const int crH = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().y; - getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(pos_ + Position(0, static_cast(size_.y) - crH)); - getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(pos_ + size_ - Position(crW, crH)); + const Extent cr = getTexture(ArchiveID::EDITRES, WINDOW_CORNER_RECTANGLE).getSize(); + getTexture(ArchiveID::EDITRES, WINDOW_CORNER_RECTANGLE) + .draw(pos_ + Position(0, static_cast(size_.y) - cr.y)); + getTexture(ArchiveID::EDITRES, WINDOW_CORNER_RECTANGLE).draw(pos_ + size_ - cr); } // 9. Close button @@ -330,7 +343,7 @@ void CWindow::draw(Position /*parentOrigin*/) closebutton = WINDOW_BUTTON_CLOSE_MARKED; else closebutton = WINDOW_BUTTON_CLOSE; - getBmpTexture(closebutton).draw(pos_); + getTexture(ArchiveID::EDITRES, closebutton).draw(pos_); } // 10. Minimize button @@ -343,8 +356,9 @@ void CWindow::draw(Position /*parentOrigin*/) minimizebutton = WINDOW_BUTTON_MINIMIZE_MARKED; else minimizebutton = WINDOW_BUTTON_MINIMIZE; - getBmpTexture(minimizebutton) - .draw(pos_ + Position(static_cast(size_.x) - getBmpTexture(minimizebutton).getSize().x, 0)); + const Extent minBtnSize = getTexture(ArchiveID::EDITRES, minimizebutton).getSize(); + getTexture(ArchiveID::EDITRES, minimizebutton) + .draw(pos_ + Position(static_cast(size_.x) - minBtnSize.x, 0)); } // 11. Resize button @@ -357,7 +371,8 @@ void CWindow::draw(Position /*parentOrigin*/) resizebutton = WINDOW_BUTTON_RESIZE_MARKED; else resizebutton = WINDOW_BUTTON_RESIZE; - getBmpTexture(resizebutton).draw(pos_ + size_ - getBmpTexture(resizebutton).getSize()); + const Extent resBtnSize = getTexture(ArchiveID::EDITRES, resizebutton).getSize(); + getTexture(ArchiveID::EDITRES, resizebutton).draw(pos_ + size_ - resBtnSize); } } diff --git a/CIO/CWindow.h b/CIO/CWindow.h index eb0ed8b..670d70a 100644 --- a/CIO/CWindow.h +++ b/CIO/CWindow.h @@ -5,6 +5,7 @@ #pragma once +#include "ArchiveID.h" #include "CControlContainer.h" enum class WindowPos @@ -49,9 +50,9 @@ class CWindow : public CControlContainer void draw(Position parentOrigin) override; CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title = nullptr, - int color = WINDOW_GREEN1, Uint8 flags = 0); + int color = WINDOW_GREEN1, Uint8 flags = 0, ArchiveID bgArchive = ArchiveID::EDITRES); CWindow(void callback(int), int callbackQuitMessage, WindowPos pos, Extent size, const char* title = nullptr, - int color = WINDOW_GREEN1, Uint8 flags = 0); + int color = WINDOW_GREEN1, Uint8 flags = 0, ArchiveID bgArchive = ArchiveID::EDITRES); // Access Position getPos() const { return pos_; } Extent getSize() const { return size_; } @@ -76,5 +77,4 @@ class CWindow : public CControlContainer // minimized surface bool isMinimized() { return minimized; }; we need an information if a input-element (textfield // etc.) is active to not deliver the input to other gui-element in the event system bool hasActiveInputElement(); - void setColor(int color); }; diff --git a/CMap.cpp b/CMap.cpp index 5139377..ebc5e12 100644 --- a/CMap.cpp +++ b/CMap.cpp @@ -13,6 +13,7 @@ #include "globals.h" #include "gameData/LandscapeDesc.h" #include "gameData/TerrainDesc.h" +#include #include #include #include @@ -424,26 +425,12 @@ void CMap::loadMapPics() palFile = "GFX/PALETTE/PAL5.BBM"; break; } - CFile::set_palArray(&global::palArray[PAL_MAPxx]); - // load only the palette at this time from MAP0x.LST - std::cout << "\nLoading palette from file: " << picFile << "..."; - if(!CFile::open_file(global::gameDataFilePath / picFile, LST, true)) - { - std::cout << "failure"; - } - // set the right palette - CFile::set_palActual(CFile::get_palArray() - 1); - std::cout << "\nLoading file: " << picFile << "..."; - if(!CFile::open_file(global::gameDataFilePath / picFile, LST)) - { - std::cout << "failure"; - } - // set back palette - CFile::set_palActual(CFile::get_palArray()); - CFile::set_palArray(&global::palArray[PAL_xBBM]); - // load palette file for the map (for precalculated shading) + // Load the palette file first so the LST load has it available std::cout << "\nLoading palette from file: " << palFile << "..."; - if(!CFile::open_file(global::gameDataFilePath / palFile, BBM, true)) + global::loadPalette(global::gameDataFilePath / palFile); + // Load map graphics into typed archive (bitmap items only) + std::cout << "\nLoading file: " << picFile << "..."; + if(!global::loadBitmapArchive(ArchiveID::MAP00, global::gameDataFilePath / picFile, global::currentPalette)) { std::cout << "failure"; } @@ -451,13 +438,9 @@ void CMap::loadMapPics() void CMap::unloadMapPics() { - // Invalidate GL textures so next getBmpTexture() re-uploads from the new surfaces - Texture::invalidateBmpCache(MAPPIC_ARROWCROSS_YELLOW, MAPPIC_LAST_ENTRY); - // set back bmpArray-pointer, cause MAP0x.LST is no longer needed - CFile::set_bmpArray(&global::bmpArray[MAPPIC_ARROWCROSS_YELLOW]); - // set back palArray-pointer, cause PALx.BBM is no longer needed - CFile::set_palActual(&global::palArray[PAL_IO]); - CFile::set_palArray(&global::palArray[PAL_IO + 1]); + auto it = global::typedArchives.find(ArchiveID::MAP00); + if(it != global::typedArchives.end()) + global::typedArchives.erase(it); } void CMap::moveMap(Position offset) @@ -1065,11 +1048,11 @@ void CMap::render() modifyVertex(); } - // ---- 1. Draw terrain with OpenGL ---- + // 1. Draw terrain with OpenGL if(!map->vertex.empty()) CSurface::DrawTriangleField(displayRect, *map); - // ---- 2. Draw editor UI chrome on top (screen-space) ---- + // 2. Draw editor UI chrome on top (screen-space) // Switch to screen-space projection for UI chrome glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -1109,34 +1092,46 @@ void CMap::render() } for(int i = 0; i < VertexCounter; i++) { - if(Vertices[i].active) + if(!Vertices[i].active) + continue; + const bool isMapPicSymbol = + (mode == EDITOR_MODE_HEIGHT_MAKE_BIG_HOUSE || mode == EDITOR_MODE_TEXTURE_MAKE_HARBOUR); + if(isMapPicSymbol) + { + // MAPPIC textures + Texture::getTexture(ArchiveID::MAP00, symbol_index) + .draw(Position(Vertices[i].blit.x - 10, Vertices[i].blit.y - 10)); + } else { - Texture::getBmpTexture(symbol_index).draw(Position(Vertices[i].blit.x - 10, Vertices[i].blit.y - 10)); + // Cursor symbols from EDITBOB.LST + Texture::getTexture(ArchiveID::EDITBOB, symbol_index) + .draw(Position(Vertices[i].blit.x - 10, Vertices[i].blit.y - 10)); if(symbol_index2 >= 0) - Texture::getBmpTexture(symbol_index2).draw(Position(Vertices[i].blit.x, Vertices[i].blit.y - 7)); + Texture::getTexture(ArchiveID::EDITBOB, symbol_index2) + .draw(Position(Vertices[i].blit.x, Vertices[i].blit.y - 7)); } } // draw the frame if(displayRect.getSize() == Extent(640, 480)) - Texture::getBmpTexture(MAINFRAME_640_480).draw(Position(0, 0)); + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480).draw(Position(0, 0)); else if(displayRect.getSize() == Extent(800, 600)) - Texture::getBmpTexture(MAINFRAME_800_600).draw(Position(0, 0)); + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_800_600).draw(Position(0, 0)); else if(displayRect.getSize() == Extent(1024, 768)) - Texture::getBmpTexture(MAINFRAME_1024_768).draw(Position(0, 0)); + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_1024_768).draw(Position(0, 0)); else if(displayRect.getSize() == Extent(1280, 1024)) { - Texture::getBmpTexture(MAINFRAME_LEFT_1280_1024).draw(Position(0, 0)); - Texture::getBmpTexture(MAINFRAME_RIGHT_1280_1024).draw(Position(640, 0)); + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_LEFT_1280_1024).draw(Position(0, 0)); + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_RIGHT_1280_1024).draw(Position(640, 0)); } else { // draw the corners - Texture::getBmpTexture(MAINFRAME_640_480).draw(Rect(0, 0, 150, 150), Rect(0, 0, 150, 150)); - Texture::getBmpTexture(MAINFRAME_640_480) + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480).draw(Rect(0, 0, 150, 150), Rect(0, 0, 150, 150)); + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) .draw(Rect(0, static_cast(displayRect.getSize().y) - 150, 150, 150), Rect(0, 480 - 150, 150, 150)); - Texture::getBmpTexture(MAINFRAME_640_480) + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) .draw(Rect(static_cast(displayRect.getSize().x) - 150, 0, 150, 150), Rect(640 - 150, 0, 150, 150)); - Texture::getBmpTexture(MAINFRAME_640_480) + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) .draw(Rect(static_cast(displayRect.getSize().x) - 150, static_cast(displayRect.getSize().y) - 150, 150, 150), Rect(640 - 150, 480 - 150, 150, 150)); @@ -1144,18 +1139,18 @@ void CMap::render() unsigned x = 150, y = 150; while(x + 150 < displayRect.getSize().x) { - Texture::getBmpTexture(MAINFRAME_640_480) + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) .draw(Rect(static_cast(x), 0, 150, 12), Rect(150, 0, 150, 12)); - Texture::getBmpTexture(MAINFRAME_640_480) + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) .draw(Rect(static_cast(x), static_cast(displayRect.getSize().y) - 12, 150, 12), Rect(150, 0, 150, 12)); x += 150; } while(y + 150 < displayRect.getSize().y) { - Texture::getBmpTexture(MAINFRAME_640_480) + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) .draw(Rect(0, static_cast(y), 12, 150), Rect(0, 150, 12, 150)); - Texture::getBmpTexture(MAINFRAME_640_480) + Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) .draw(Rect(static_cast(displayRect.getSize().x) - 12, static_cast(y), 12, 150), Rect(0, 150, 12, 150)); y += 150; @@ -1163,78 +1158,83 @@ void CMap::render() } // draw the statues at the frame - Texture::getBmpTexture(STATUE_UP_LEFT).draw(Position(12, 12)); - Texture::getBmpTexture(STATUE_UP_RIGHT) - .draw(Position(static_cast(displayRect.getSize().x) - global::bmpArray[STATUE_UP_RIGHT].w - 12, 12)); - Texture::getBmpTexture(STATUE_DOWN_LEFT) - .draw(Position(12, static_cast(displayRect.getSize().y) - global::bmpArray[STATUE_DOWN_LEFT].h - 12)); - Texture::getBmpTexture(STATUE_DOWN_RIGHT) - .draw(Position(static_cast(displayRect.getSize().x) - global::bmpArray[STATUE_DOWN_RIGHT].w - 12, - static_cast(displayRect.getSize().y) - global::bmpArray[STATUE_DOWN_RIGHT].h - 12)); + Texture::getTexture(ArchiveID::EDITRES, STATUE_UP_LEFT).draw(Position(12, 12)); + Texture::getTexture(ArchiveID::EDITRES, STATUE_UP_RIGHT) + .draw(Position(static_cast(displayRect.getSize().x) + - static_cast(global::getBitmapSize(ArchiveID::EDITRES, STATUE_UP_RIGHT).x) - 12, + 12)); + Texture::getTexture(ArchiveID::EDITRES, STATUE_DOWN_LEFT) + .draw(Position(12, static_cast(displayRect.getSize().y) + - static_cast(global::getBitmapSize(ArchiveID::EDITRES, STATUE_DOWN_LEFT).y) - 12)); + Texture::getTexture(ArchiveID::EDITRES, STATUE_DOWN_RIGHT) + .draw(Position(static_cast(displayRect.getSize().x) + - static_cast(global::getBitmapSize(ArchiveID::EDITRES, STATUE_DOWN_RIGHT).x) - 12, + static_cast(displayRect.getSize().y) + - static_cast(global::getBitmapSize(ArchiveID::EDITRES, STATUE_DOWN_RIGHT).y) - 12)); // lower menubar const Position menubarPos = Position(static_cast(displayRect.getSize().x) / 2, static_cast(displayRect.getSize().y)); // draw lower menubar - Texture::getBmpTexture(MENUBAR).draw(Position(menubarPos.x - static_cast(global::bmpArray[MENUBAR].w / 2), - menubarPos.y - global::bmpArray[MENUBAR].h)); + Texture::getTexture(ArchiveID::EDITRES, MENUBAR) + .draw(Position(menubarPos.x - static_cast(global::getBitmapSize(ArchiveID::EDITRES, MENUBAR).x) / 2, + menubarPos.y - static_cast(global::getBitmapSize(ArchiveID::EDITRES, MENUBAR).y))); // draw pictures to lower menubar // backgrounds (use button background texture for each slot) - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x - 236, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x - 199, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x - 162, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x - 125, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x - 88, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x - 51, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x - 14, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x + 92, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x + 129, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x + 166, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(menubarPos.x + 203, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); // pictures - Texture::getBmpTexture(MENUBAR_HEIGHT).draw(Position(menubarPos.x - 232, menubarPos.y - 35)); - Texture::getBmpTexture(MENUBAR_TEXTURE).draw(Position(menubarPos.x - 195, menubarPos.y - 35)); - Texture::getBmpTexture(MENUBAR_TREE).draw(Position(menubarPos.x - 158, menubarPos.y - 37)); - Texture::getBmpTexture(MENUBAR_RESOURCE).draw(Position(menubarPos.x - 121, menubarPos.y - 32)); - Texture::getBmpTexture(MENUBAR_LANDSCAPE).draw(Position(menubarPos.x - 84, menubarPos.y - 37)); - Texture::getBmpTexture(MENUBAR_ANIMAL).draw(Position(menubarPos.x - 48, menubarPos.y - 36)); - Texture::getBmpTexture(MENUBAR_PLAYER).draw(Position(menubarPos.x - 10, menubarPos.y - 34)); - - Texture::getBmpTexture(MENUBAR_BUILDHELP).draw(Position(menubarPos.x + 96, menubarPos.y - 35)); - Texture::getBmpTexture(MENUBAR_MINIMAP).draw(Position(menubarPos.x + 131, menubarPos.y - 37)); - Texture::getBmpTexture(MENUBAR_NEWWORLD).draw(Position(menubarPos.x + 166, menubarPos.y - 37)); - Texture::getBmpTexture(MENUBAR_COMPUTER).draw(Position(menubarPos.x + 207, menubarPos.y - 35)); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_HEIGHT).draw(Position(menubarPos.x - 232, menubarPos.y - 35)); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_TEXTURE).draw(Position(menubarPos.x - 195, menubarPos.y - 35)); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_TREE).draw(Position(menubarPos.x - 158, menubarPos.y - 37)); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_RESOURCE).draw(Position(menubarPos.x - 121, menubarPos.y - 32)); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_LANDSCAPE).draw(Position(menubarPos.x - 84, menubarPos.y - 37)); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_ANIMAL).draw(Position(menubarPos.x - 48, menubarPos.y - 36)); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_PLAYER).draw(Position(menubarPos.x - 10, menubarPos.y - 34)); + + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_BUILDHELP).draw(Position(menubarPos.x + 96, menubarPos.y - 35)); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_MINIMAP).draw(Position(menubarPos.x + 131, menubarPos.y - 37)); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_NEWWORLD).draw(Position(menubarPos.x + 166, menubarPos.y - 37)); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_COMPUTER).draw(Position(menubarPos.x + 207, menubarPos.y - 35)); // right menubar: draw the MENUBAR sprite rotated 270 degrees via OpenGL { - const auto& bmp = global::bmpArray[MENUBAR]; - const int mw = bmp.w; - const int mh = bmp.h; + auto& tex = Texture::getTexture(ArchiveID::EDITRES, MENUBAR); + const auto sz = tex.getSize(); const Position rmPos = Position(static_cast(displayRect.getSize().x), static_cast(displayRect.getSize().y) / 2); - auto& tex = Texture::getBmpTexture(MENUBAR); if(tex.isValid()) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); // Shift right menubar 1px right, 2px down to align button backgrounds - glTranslatef(static_cast(rmPos.x - mh / 2 + 1), static_cast(rmPos.y + 2), 0.f); + glTranslatef(static_cast(rmPos.x - static_cast(sz.y) / 2 + 1), static_cast(rmPos.y + 2), + 0.f); glRotatef(270.f, 0.f, 0.f, 1.f); - tex.draw(Rect(-mw / 2, -mh / 2, mw, mh)); + tex.draw(Rect(-static_cast(sz.x) / 2, -static_cast(sz.y) / 2, sz.x, sz.y)); glPopMatrix(); } } @@ -1242,40 +1242,46 @@ void CMap::render() // draw pictures to right menubar const Position rightMenubarPos = Position(static_cast(displayRect.getSize().x), static_cast(displayRect.getSize().y) / 2); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 239, 32, 37), Rect(0, 0, 32, 37)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 202, 32, 37), Rect(0, 0, 32, 37)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 165, 32, 37), Rect(0, 0, 32, 37)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 128, 32, 37), Rect(0, 0, 32, 37)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 22, 32, 37), Rect(0, 0, 32, 37)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 15, 32, 37), Rect(0, 0, 32, 37)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 52, 32, 37), Rect(0, 0, 32, 37)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 89, 32, 37), Rect(0, 0, 32, 37)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 126, 32, 37), Rect(0, 0, 32, 37)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 163, 32, 37), Rect(0, 0, 32, 37)); - Texture::getBmpTexture(BUTTON_GREEN1_DARK) + Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 200, 32, 37), Rect(0, 0, 32, 37)); // pictures - Texture::getBmpTexture(CURSOR_SYMBOL_ARROW_UP).draw(Position(rightMenubarPos.x - 33, rightMenubarPos.y - 237)); - Texture::getBmpTexture(CURSOR_SYMBOL_ARROW_DOWN).draw(Position(rightMenubarPos.x - 20, rightMenubarPos.y - 235)); - Texture::getBmpTexture(CURSOR_SYMBOL_ARROW_DOWN).draw(Position(rightMenubarPos.x - 33, rightMenubarPos.y - 220)); - Texture::getBmpTexture(CURSOR_SYMBOL_ARROW_UP).draw(Position(rightMenubarPos.x - 20, rightMenubarPos.y - 220)); + Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP) + .draw(Position(rightMenubarPos.x - 33, rightMenubarPos.y - 237)); + Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN) + .draw(Position(rightMenubarPos.x - 20, rightMenubarPos.y - 235)); + Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN) + .draw(Position(rightMenubarPos.x - 33, rightMenubarPos.y - 220)); + Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP) + .draw(Position(rightMenubarPos.x - 20, rightMenubarPos.y - 220)); // bugkill picture for quickload with text - Texture::getBmpTexture(MENUBAR_BUGKILL).draw(Position(rightMenubarPos.x - 37, rightMenubarPos.y + 162)); - CFont::draw("Load", Position(rightMenubarPos.x - 35, rightMenubarPos.y + 193), FontSize::Medium); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_BUGKILL) + .draw(Position(rightMenubarPos.x - 37, rightMenubarPos.y + 162)); + CFont::draw("Load", Position(rightMenubarPos.x - 35, rightMenubarPos.y + 193)); // bugkill picture for quicksave with text - Texture::getBmpTexture(MENUBAR_BUGKILL).draw(Position(rightMenubarPos.x - 37, rightMenubarPos.y + 200)); - CFont::draw("Save", Position(rightMenubarPos.x - 35, rightMenubarPos.y + 231), FontSize::Medium); + Texture::getTexture(ArchiveID::EDITIO, MENUBAR_BUGKILL) + .draw(Position(rightMenubarPos.x - 37, rightMenubarPos.y + 200)); + CFont::draw("Save", Position(rightMenubarPos.x - 35, rightMenubarPos.y + 231)); // Restore matrices glMatrixMode(GL_PROJECTION); diff --git a/CSurface.cpp b/CSurface.cpp index e60cdad..0c55310 100644 --- a/CSurface.cpp +++ b/CSurface.cpp @@ -11,11 +11,17 @@ #include "globals.h" #include "gameData/EdgeDesc.h" #include "gameData/TerrainDesc.h" +#include +#include +#include +#include +#include #include #include #include #include +#include static uint8_t intensityToColor(Sint32 val) { @@ -76,111 +82,6 @@ static void DrawFadedTexturedTrigon(const Point16& p1, const Point16& p2, const bool CSurface::drawTextures = false; -bool CSurface::Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y) -{ - if(!Surf_Dest || !Surf_Src) - return false; - - SDL_Rect DestR; - - DestR.x = X; - DestR.y = Y; - - SDL_BlitSurface(Surf_Src, nullptr, Surf_Dest, &DestR); - - return true; -} - -bool CSurface::Draw(SDL_Surface* Surf_Dest, SdlSurface& Surf_Src, int X, int Y) -{ - return Draw(Surf_Dest, Surf_Src.get(), X, Y); -} - -bool CSurface::Draw(SdlSurface& Surf_Dest, SdlSurface& Surf_Src, Position pos) -{ - return Draw(Surf_Dest.get(), Surf_Src.get(), pos.x, pos.y); -} - -bool CSurface::Draw(SdlSurface& Surf_Dest, SDL_Surface* Surf_Src, int X, int Y) -{ - return Draw(Surf_Dest.get(), Surf_Src, X, Y); -} - -bool CSurface::Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, Position dest, Position srcOffset, Extent srcSize) -{ - if(!Surf_Dest || !Surf_Src) - return false; - - SDL_Rect DestR; - - DestR.x = dest.x; - DestR.y = dest.y; - - SDL_Rect SrcR; - - SrcR.x = srcOffset.x; - SrcR.y = srcOffset.y; - SrcR.w = static_cast(srcSize.x); - SrcR.h = static_cast(srcSize.y); - - SDL_BlitSurface(Surf_Src, &SrcR, Surf_Dest, &DestR); - - return true; -} - -bool CSurface::Draw(SDL_Surface* Surf_Dest, SdlSurface& Surf_Src, Position dest, Position srcOffset, Extent srcSize) -{ - return Draw(Surf_Dest, Surf_Src.get(), dest, srcOffset, srcSize); -} - -// this is the example function from the SDL-documentation to draw pixels -void CSurface::DrawPixel_Color(SDL_Surface* screen, Position pos, Uint32 color) -{ - int bpp = screen->format->BytesPerPixel; - /* Here p is the address to the pixel we want to retrieve */ - Uint8* p = (Uint8*)screen->pixels + static_cast(pos.y) * screen->pitch + static_cast(pos.x) * bpp; - - if(SDL_MUSTLOCK(screen)) - SDL_LockSurface(screen); - - switch(bpp) - { - case 1: *p = color; break; - - case 2: *(Uint16*)p = color; break; - - case 3: - if((SDL_BYTEORDER) == SDL_LIL_ENDIAN) - { - p[0] = color; - p[1] = color >> 8; - p[2] = color >> 16; - } else - { - p[2] = color; - p[1] = color >> 8; - p[0] = color >> 16; - } - break; - - case 4: *(Uint32*)p = color; break; - } - - if(SDL_MUSTLOCK(screen)) - SDL_UnlockSurface(screen); -} - -// this is the example function from the sdl-documentation to draw pixels -void CSurface::DrawPixel_RGB(SDL_Surface* screen, Position pos, Uint8 R, Uint8 G, Uint8 B) -{ - DrawPixel_Color(screen, pos, SDL_MapRGB(screen->format, R, G, B)); -} - -void CSurface::DrawPixel_RGBA(SDL_Surface* screen, Position pos, Uint8 R, Uint8 G, Uint8 B, Uint8 A) -{ - DrawPixel_Color(screen, pos, SDL_MapRGBA(screen->format, R, G, B, A)); -} - void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobMAP& myMap) { Uint16 width = myMap.width; @@ -516,11 +417,125 @@ bool GetAdjustedPoints(const DisplayRectangle& displayRect, const bobMAP& myMap, } } // namespace -void CSurface::GetTerrainTextureCoords(MapType mapType, TriangleTerrainType texture, bool isRSU, int texture_move, - Point16& upper, Point16& left, Point16& right, Point16& upper2, Point16& left2, - Point16& right2) +// palette animation helpers + +/// Holds pre-rendered frames for one palette-animated terrain. +struct AnimFrames +{ + std::vector frames; +}; + +static std::map, AnimFrames> s_animFrameCache; + +static const AnimFrames* getAnimFrames(const TerrainDesc& td, MapType mapType) +{ + // Determine tileset index from map type + auto& ta = global::tilesetAnims[static_cast(mapType)]; + if(ta.anims.empty()) + return nullptr; + // palAnimIdx is the index in the tileset Archiv (0 = bitmap, 1+ = animations) + // ta.anims[0] = Archiv[1], ta.anims[1] = Archiv[2], etc. + if(td.palAnimIdx < 1) + return nullptr; + size_t animIdx = static_cast(td.palAnimIdx) - 1; + if(animIdx >= ta.anims.size()) + return nullptr; + const auto* anim = ta.anims[animIdx]; + if(!anim || !anim->isActive) + return nullptr; + + unsigned numFrames = anim->lastClr - anim->firstClr + 1; + if(numFrames < 2) + return nullptr; + if(numFrames > 32) + numFrames = 32; + + auto key = std::make_pair(&td, static_cast(mapType)); + auto it = s_animFrameCache.find(key); + if(it != s_animFrameCache.end()) + return &it->second; + + // Get the tileset bitmap from the typed archive + const libsiedler2::baseArchivItem_Bitmap* tsBmp = + dynamic_cast(global::typedArchives[ta.archive].get(ta.bmpIdx)); + if(!tsBmp) + return nullptr; + const auto* srcPal = tsBmp->getPalette(); + if(!srcPal) + return nullptr; + + // Extract the terrain sub-rect from the tileset + auto r = td.posInTexture; + Extent texSize = r.getSize(); + if(texSize.x == 0 || texSize.y == 0) + return nullptr; + + // Create paletted pixel buffer with the sub-rect + libsiedler2::PixelBufferPaletted buffer(texSize.x, texSize.y); + if(tsBmp->print(buffer, nullptr, 0, 0, r.left, r.top, texSize.x, texSize.y)) + return nullptr; + + // Build the per-frame animation object (direction hardcoded to false, + // matching s25client's ExtractAnimatedTexture which ignores the CRNG flags) + libsiedler2::ArchivItem_PaletteAnimation frameStep; + frameStep.isActive = true; + frameStep.moveUp = false; + frameStep.firstClr = anim->firstClr; + frameStep.lastClr = anim->lastClr; + + auto& result = s_animFrameCache[key]; + result.frames.reserve(numFrames); + + std::unique_ptr curPal; + for(unsigned fi = 0; fi < numFrames; fi++) + { + auto pal = (fi == 0) ? std::make_unique(*srcPal) : frameStep.apply(*curPal); + if(!pal) + continue; + + // Render frame to BGRA + libsiedler2::PixelBufferBGRA bgraBuf(texSize.x, texSize.y); + for(unsigned y = 0; y < texSize.y; y++) + { + for(unsigned x = 0; x < texSize.x; x++) + { + auto idx = buffer.get(x, y); + auto c = pal->get(idx); + uint32_t* dst = reinterpret_cast(bgraBuf.getPixelPtr()) + y * texSize.x + x; + *dst = (0xFFu << 24) | (uint32_t(c.r) << 16) | (uint32_t(c.g) << 8) | uint32_t(c.b); + } + } + + Texture tex; + libsiedler2::ArchivItem_Bitmap_Raw tmpBmp; + tmpBmp.create(texSize.x, texSize.y, bgraBuf.getPixelPtr(), texSize.x, texSize.y, + libsiedler2::TextureFormat::BGRA, nullptr); + tex.load(tmpBmp, false); + result.frames.push_back(std::move(tex)); + + curPal = std::move(pal); + } + + return result.frames.empty() ? nullptr : &result; +} + +/// Choose the current animation frame based on elapsed wall-clock time. +/// Matches s25client: each frame is shown for 630*5/16 = ~197 ms. +static unsigned getAnimFrameIdx(const AnimFrames& af) +{ + unsigned numFrames = af.frames.size(); + if(numFrames <= 1) + return 0; + // Match s25client's GetGlobalAnimation(numFrames, 5*numFrames, 16, 0): + // unit = 630ms * 5 * numFrames / 16 → 197ms per frame + constexpr unsigned unitPerFrame = 630 * 5 / 16; // ≈ 197 ms + uint32_t now = SDL_GetTicks(); + return (now / unitPerFrame) % numFrames; +} + +void CSurface::GetTerrainTextureCoords(MapType mapType, TriangleTerrainType texture, bool isRSU, Point16& upper, + Point16& left, Point16& right, Point16& upper2, Point16& left2, Point16& right2) { - const auto animOffset = Point16(-texture_move, texture_move); switch(texture) { // in case of USD-Triangle "upper.x" and "upper.y" means "lowerX" and "lowerY" @@ -550,14 +565,14 @@ void CSurface::GetTerrainTextureCoords(MapType mapType, TriangleTerrainType text { if(isRSU) { - upper2 = Point16(231, 61) + animOffset; - left2 = Point16(207, 62) + animOffset; - right2 = Point16(223, 78) + animOffset; + upper2 = Point16(231, 61); + left2 = Point16(207, 62); + right2 = Point16(223, 78); } else { - upper2 = Point16(224, 79) + animOffset; - left2 = Point16(232, 62) + animOffset; - right2 = Point16(245, 76) + animOffset; + upper2 = Point16(224, 79); + left2 = Point16(232, 62); + right2 = Point16(245, 76); } } break; @@ -569,14 +584,14 @@ void CSurface::GetTerrainTextureCoords(MapType mapType, TriangleTerrainType text { if(isRSU) { - upper2 = Point16(231, 61) + animOffset; - left2 = Point16(207, 62) + animOffset; - right2 = Point16(223, 78) + animOffset; + upper2 = Point16(231, 61); + left2 = Point16(207, 62); + right2 = Point16(223, 78); } else { - upper2 = Point16(224, 79) + animOffset; - left2 = Point16(232, 62) + animOffset; - right2 = Point16(245, 76) + animOffset; + upper2 = Point16(224, 79); + left2 = Point16(232, 62); + right2 = Point16(245, 76); } } break; @@ -593,14 +608,14 @@ void CSurface::GetTerrainTextureCoords(MapType mapType, TriangleTerrainType text case TRIANGLE_TEXTURE_WATER__: if(isRSU) { - upper = Point16(231, 61) + animOffset; - left = Point16(207, 62) + animOffset; - right = Point16(223, 78) + animOffset; + upper = Point16(231, 61); + left = Point16(207, 62); + right = Point16(223, 78); } else { - upper = Point16(224, 79) + animOffset; - left = Point16(232, 62) + animOffset; - right = Point16(245, 76) + animOffset; + upper = Point16(224, 79); + left = Point16(232, 62); + right = Point16(245, 76); } break; case TRIANGLE_TEXTURE_MEADOW1: @@ -646,14 +661,14 @@ void CSurface::GetTerrainTextureCoords(MapType mapType, TriangleTerrainType text case TRIANGLE_TEXTURE_LAVA: if(isRSU) { - upper = Point16(231, 117) + animOffset; - left = Point16(207, 118) + animOffset; - right = Point16(223, 134) + animOffset; + upper = Point16(231, 117); + left = Point16(207, 118); + right = Point16(223, 134); } else { - upper = Point16(224, 135) + animOffset; - left = Point16(232, 118) + animOffset; - right = Point16(245, 132) + animOffset; + upper = Point16(224, 135); + left = Point16(232, 118); + right = Point16(245, 132); } break; case TRIANGLE_TEXTURE_MINING_MEADOW: @@ -680,20 +695,8 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m if(!GetAdjustedPoints(displayRect, myMap, p1, p2, p3)) return; - // for moving water, lava, objects and so on - // This is very tricky: there are ice floes in the winterland and the water under this floes is moving. - // I don't know how this works in original settlers 2 but i solved it this way: - // i texture the triangle with normal water and then draw the floe over it. To Extract the floe - // from it's surrounded water, i use color keys. These are the color values for the water texture. - // The OpenGL renderer approximates this via a two-pass draw with GL_ALPHA_TEST. - // The water color keys are handled in Texture::load() when converting the 8-bit paletted - // tileset surface to RGBA — matching palette entries are set to alpha=0 so that - // GL_ALPHA_TEST (GL_GREATER, 0) skips them in the second pass. - - static int texture_move = 0; static int roundCount = 0; static Uint32 roundTimeObjects = SDL_GetTicks(); - static Uint32 roundTimeTextures = SDL_GetTicks(); if(SDL_GetTicks() - roundTimeObjects > 30) { roundTimeObjects = SDL_GetTicks(); @@ -702,38 +705,32 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m else roundCount++; } - if(SDL_GetTicks() - roundTimeTextures > 170) - { - roundTimeTextures = SDL_GetTicks(); - texture_move++; - if(texture_move > 14) - texture_move = 0; - } // Determine tileset texture - int tilesetIdx; + ArchiveID tsArchive; switch(type) { case MAP_GREENLAND: - default: tilesetIdx = TILESET_GREENLAND; break; - case MAP_WASTELAND: tilesetIdx = TILESET_WASTELAND; break; - case MAP_WINTERLAND: tilesetIdx = TILESET_WINTERLAND; break; + default: tsArchive = ArchiveID::TEX5; break; + case MAP_WASTELAND: tsArchive = ArchiveID::TEX6; break; + case MAP_WINTERLAND: tsArchive = ArchiveID::TEX7; break; } bool const isRSU = p1.y < p2.y; - auto& tilesetTex = Texture::getBmpTexture(tilesetIdx); + auto& tilesetTex = Texture::getTexture(tsArchive, 0); if(!tilesetTex.isValid()) return; glBindTexture(GL_TEXTURE_2D, tilesetTex.getHandle()); - const float texW = static_cast(global::bmpArray[tilesetIdx].w); - const float texH = static_cast(global::bmpArray[tilesetIdx].h); + const auto* tsBmp = + dynamic_cast(global::typedArchives[tsArchive].get(0)); + const float texW = tsBmp ? static_cast(tsBmp->getWidth()) : 0.0f; + const float texH = tsBmp ? static_cast(tsBmp->getHeight()) : 0.0f; if(drawTextures) { - // upper2, ..... are for special use in winterland. Point16 upper, left, right, upper2, left2, right2; auto const texture = TriangleTerrainType((isRSU ? P1.rsuTexture : P2.usdTexture) & ~0x40); // Mask out harbor bit - GetTerrainTextureCoords(type, texture, isRSU, texture_move, upper, left, right, upper2, left2, right2); + GetTerrainTextureCoords(type, texture, isRSU, upper, left, right, upper2, left2, right2); const float uvs[3][2] = {{static_cast(upper.x) / texW, static_cast(upper.y) / texH}, {static_cast(left.x) / texW, static_cast(left.y) / texH}, @@ -743,69 +740,53 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m {float(p1.x), float(p1.y)}, {float(p2.x), float(p2.y)}, {float(p3.x), float(p3.y)}}; const MapNode* verts[3] = {&P1, &P2, &P3}; - // draw the triangle - // do not shade water and lava - if(const auto* terrainDesc = getTerrainDesc(myMap, texture); - terrainDesc && (terrainDesc->kind == TerrainKind::Water || terrainDesc->kind == TerrainKind::Lava)) + // --- palette animation: any terrain with palAnimIdx >= 0 --- + if(const auto* terrainDesc = getTerrainDesc(myMap, texture); terrainDesc && terrainDesc->palAnimIdx >= 0) { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); - glBegin(GL_TRIANGLES); - for(int k = 0; k < 3; k++) + const auto* af = getAnimFrames(*terrainDesc, type); + if(af && !af->frames.empty()) { - glTexCoord2f(uvs[k][0], uvs[k][1]); - glColor4ub(128, 128, 128, 255); - glVertex2f(vertCoord[k][0], vertCoord[k][1]); - } - glEnd(); - } else - { - // draw special winterland textures with moving water (ice floe textures) - if(type == MAP_WINTERLAND && (texture == TRIANGLE_TEXTURE_SNOW || texture == TRIANGLE_TEXTURE_SWAMP)) - { - const float wuvs[3][2] = {{static_cast(upper2.x) / texW, static_cast(upper2.y) / texH}, - {static_cast(left2.x) / texW, static_cast(left2.y) / texH}, - {static_cast(right2.x) / texW, static_cast(right2.y) / texH}}; + unsigned frameIdx = getAnimFrameIdx(*af); + glBindTexture(GL_TEXTURE_2D, af->frames[frameIdx].getHandle()); + + // Use the GDL triangle UVs (the animated texture covers only the terrain sub-rect) + auto tri = isRSU ? terrainDesc->GetRSUTriangle() : terrainDesc->GetUSDTriangle(); + auto r = terrainDesc->posInTexture; + float ox = static_cast(r.left); + float oy = static_cast(r.top); + float sx = static_cast(r.getSize().x); + float sy = static_cast(r.getSize().y); + float nu[3][2] = {{(tri.tip.x - ox) / sx, (tri.tip.y - oy) / sy}, + {(tri.left.x - ox) / sx, (tri.left.y - oy) / sy}, + {(tri.right.x - ox) / sx, (tri.right.y - oy) / sy}}; - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBegin(GL_TRIANGLES); - for(int k = 0; k < 3; k++) - { - glTexCoord2f(wuvs[k][0], wuvs[k][1]); - glColor4ub(128, 128, 128, 255); - glVertex2f(vertCoord[k][0], vertCoord[k][1]); - } - glEnd(); - - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); glBegin(GL_TRIANGLES); for(int k = 0; k < 3; k++) { - glTexCoord2f(uvs[k][0], uvs[k][1]); - glColor4ub(intensityToColor(verts[k]->i), intensityToColor(verts[k]->i), - intensityToColor(verts[k]->i), 255); - glVertex2f(vertCoord[k][0], vertCoord[k][1]); - } - glEnd(); - glDisable(GL_ALPHA_TEST); - } else - { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); - glBegin(GL_TRIANGLES); - for(int k = 0; k < 3; k++) - { - glTexCoord2f(uvs[k][0], uvs[k][1]); + glTexCoord2f(nu[k][0], nu[k][1]); glColor4ub(intensityToColor(verts[k]->i), intensityToColor(verts[k]->i), intensityToColor(verts[k]->i), 255); glVertex2f(vertCoord[k][0], vertCoord[k][1]); } glEnd(); + return; } } + + // Most terrains: draw from the tileset with standard shading + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); + glBegin(GL_TRIANGLES); + for(int k = 0; k < 3; k++) + { + glTexCoord2f(uvs[k][0], uvs[k][1]); + glColor4ub(intensityToColor(verts[k]->i), intensityToColor(verts[k]->i), intensityToColor(verts[k]->i), + 255); + glVertex2f(vertCoord[k][0], vertCoord[k][1]); + } + glEnd(); return; } @@ -1029,13 +1010,34 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m case 0x16: objIdx = MAPPIC_DOOR; break; - case 0x18: objIdx = MIS1BOBS_STONE1; break; - case 0x19: objIdx = MIS1BOBS_STONE2; break; - case 0x1A: objIdx = MIS1BOBS_STONE3; break; - case 0x1B: objIdx = MIS1BOBS_STONE4; break; - case 0x1C: objIdx = MIS1BOBS_STONE5; break; - case 0x1D: objIdx = MIS1BOBS_STONE6; break; - case 0x1E: objIdx = MIS1BOBS_STONE7; break; + case 0x18: + Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE1).drawSprite(p2); + objIdx = 0; + break; + case 0x19: + Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE2).drawSprite(p2); + objIdx = 0; + break; + case 0x1A: + Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE3).drawSprite(p2); + objIdx = 0; + break; + case 0x1B: + Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE4).drawSprite(p2); + objIdx = 0; + break; + case 0x1C: + Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE5).drawSprite(p2); + objIdx = 0; + break; + case 0x1D: + Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE6).drawSprite(p2); + objIdx = 0; + break; + case 0x1E: + Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE7).drawSprite(p2); + objIdx = 0; + break; case 0x22: objIdx = MAPPIC_MUSHROOM3; break; @@ -1052,12 +1054,12 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m // headquarter case 0x80: // node2.objectType is the number of the player beginning with 0x00 //%7 cause in the original game there are only 7 players and 7 different flags - objIdx = FLAG_BLUE_DARK + P2.objectType % 7; - break; + Texture::getTexture(ArchiveID::EDITBOB, FLAG_BLUE_DARK + P2.objectType % 7).drawSprite(p2); + break; // don't set objIdx — drawn directly from typed archive default: break; } if(objIdx != 0) - Texture::getBmpTexture(objIdx).drawSprite(p2.x, p2.y); + Texture::getTexture(ArchiveID::MAP00, objIdx).drawSprite(p2); } // blit resources @@ -1066,25 +1068,29 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m if(P2.resource >= 0x41 && P2.resource <= 0x47) { for(char i = 0x41; i <= P2.resource; i++) - Texture::getBmpTexture(PICTURE_RESOURCE_COAL).drawSprite(p2.x, p2.y - 4 * (i - 0x40)); + Texture::getTexture(ArchiveID::EDITIO, PICTURE_RESOURCE_COAL) + .drawSprite(Position(p2.x, p2.y - 4 * (i - 0x40))); } else if(P2.resource >= 0x49 && P2.resource <= 0x4F) { for(char i = 0x49; i <= P2.resource; i++) - Texture::getBmpTexture(PICTURE_RESOURCE_ORE).drawSprite(p2.x, p2.y - 4 * (i - 0x48)); + Texture::getTexture(ArchiveID::EDITIO, PICTURE_RESOURCE_ORE) + .drawSprite(Position(p2.x, p2.y - 4 * (i - 0x48))); } if(P2.resource >= 0x51 && P2.resource <= 0x57) { for(char i = 0x51; i <= P2.resource; i++) - Texture::getBmpTexture(PICTURE_RESOURCE_GOLD).drawSprite(p2.x, p2.y - 4 * (i - 0x50)); + Texture::getTexture(ArchiveID::EDITIO, PICTURE_RESOURCE_GOLD) + .drawSprite(Position(p2.x, p2.y - 4 * (i - 0x50))); } if(P2.resource >= 0x59 && P2.resource <= 0x5F) { for(char i = 0x59; i <= P2.resource; i++) - Texture::getBmpTexture(PICTURE_RESOURCE_GRANITE).drawSprite(p2.x, p2.y - 4 * (i - 0x58)); + Texture::getTexture(ArchiveID::EDITIO, PICTURE_RESOURCE_GRANITE) + .drawSprite(Position(p2.x, p2.y - 4 * (i - 0x58))); } // blit animals if(P2.animal > 0x00 && P2.animal <= 0x06) - Texture::getBmpTexture(PICTURE_SMALL_BEAR + P2.animal).drawSprite(p2.x, p2.y); + Texture::getTexture(ArchiveID::EDITBOB, PICTURE_SMALL_BEAR + P2.animal).drawSprite(p2); } // blit buildings @@ -1094,16 +1100,16 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m { switch(P2.build % 8) { - case 0x01: Texture::getBmpTexture(MAPPIC_FLAG).drawSprite(p2.x, p2.y); break; - case 0x02: Texture::getBmpTexture(MAPPIC_HOUSE_SMALL).drawSprite(p2.x, p2.y); break; - case 0x03: Texture::getBmpTexture(MAPPIC_HOUSE_MIDDLE).drawSprite(p2.x, p2.y); break; + case 0x01: Texture::getTexture(ArchiveID::MAP00, MAPPIC_FLAG).drawSprite(p2); break; + case 0x02: Texture::getTexture(ArchiveID::MAP00, MAPPIC_HOUSE_SMALL).drawSprite(p2); break; + case 0x03: Texture::getTexture(ArchiveID::MAP00, MAPPIC_HOUSE_MIDDLE).drawSprite(p2); break; case 0x04: if(P2.rsuTexture & 0x40) - Texture::getBmpTexture(MAPPIC_HOUSE_HARBOUR).drawSprite(p2.x, p2.y); + Texture::getTexture(ArchiveID::MAP00, MAPPIC_HOUSE_HARBOUR).drawSprite(p2); else - Texture::getBmpTexture(MAPPIC_HOUSE_BIG).drawSprite(p2.x, p2.y); + Texture::getTexture(ArchiveID::MAP00, MAPPIC_HOUSE_BIG).drawSprite(p2); break; - case 0x05: Texture::getBmpTexture(MAPPIC_MINE).drawSprite(p2.x, p2.y); break; + case 0x05: Texture::getTexture(ArchiveID::MAP00, MAPPIC_MINE).drawSprite(p2); break; default: break; } } diff --git a/CSurface.h b/CSurface.h index 8081ab1..8f2dd11 100644 --- a/CSurface.h +++ b/CSurface.h @@ -6,50 +6,12 @@ #pragma once #include "defines.h" -#include struct vector; class CSurface { - friend class CDebug; - public: - // blits from source on destination to position X,Y - static bool Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y); - static bool Draw(SDL_Surface* Surf_Dest, SdlSurface& Surf_Src, int X, int Y); - static bool Draw(SdlSurface& Surf_Dest, SdlSurface& Surf_Src, Position pos = {0, 0}); - static bool Draw(SdlSurface& Surf_Dest, SDL_Surface* Surf_Src, int X = 0, int Y = 0); - - // blits rectangle from source on destination - static bool Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, Position dest, Position srcOffset, Extent srcSize); - static bool Draw(SDL_Surface* Surf_Dest, SdlSurface& Surf_Src, Position dest, Position srcOffset, Extent srcSize); - static bool Draw(SdlSurface& Surf_Dest, SdlSurface& Surf_Src, Position dest, Position srcOffset, Extent srcSize) - { - return Draw(Surf_Dest.get(), Surf_Src.get(), dest, srcOffset, srcSize); - } - // convenience overload for non-UI callers - static bool Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y, int X2, int Y2, int W, int H) - { - return Draw(Surf_Dest, Surf_Src, Position(X, Y), Position(X2, Y2), - Extent(static_cast(W), static_cast(H))); - } - static bool Draw(SDL_Surface* Surf_Dest, SdlSurface& Surf_Src, int X, int Y, int X2, int Y2, int W, int H) - { - return Draw(Surf_Dest, Surf_Src.get(), X, Y, X2, Y2, W, H); - } - static bool Draw(SdlSurface& Surf_Dest, SdlSurface& Surf_Src, int X, int Y, int X2, int Y2, int W, int H) - { - return Draw(Surf_Dest.get(), Surf_Src.get(), X, Y, X2, Y2, W, H); - } - static void DrawPixel_Color(SDL_Surface* screen, Position pos, Uint32 color); - static void DrawPixel_RGB(SDL_Surface* screen, Position pos, Uint8 R, Uint8 G, Uint8 B); - static void DrawPixel_RGB(SdlSurface& screen, Position pos, Uint8 R, Uint8 G, Uint8 B) - { - DrawPixel_RGB(screen.get(), pos, R, G, B); - } - static void DrawPixel_RGBA(SDL_Surface* screen, Position pos, Uint8 R, Uint8 G, Uint8 B, Uint8 A); - /// Render terrain into the current GL framebuffer. /// displayRect specifies the visible area in map-pixel coordinates. static void DrawTriangleField(const DisplayRectangle& displayRect, const bobMAP& myMap); @@ -75,7 +37,7 @@ class CSurface // update nodeVector based on new flatVectors around it static void update_nodeVector(bobMAP& myMap, Position pos); - static void GetTerrainTextureCoords(MapType mapType, TriangleTerrainType texture, bool isRSU, int texture_move, - Point16& upper, Point16& left, Point16& right, Point16& upper2, Point16& left2, + static void GetTerrainTextureCoords(MapType mapType, TriangleTerrainType texture, bool isRSU, Point16& upper, + Point16& left, Point16& right, Point16& upper2, Point16& left2, Point16& right2); }; diff --git a/Texture.cpp b/Texture.cpp index b0b5464..1be0169 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -8,10 +8,14 @@ #include #include #include +#include #include #include #include +#include +#include + Texture::~Texture() { if(texture_) @@ -34,7 +38,7 @@ Texture& Texture::operator=(Texture&& other) noexcept return *this; } -void Texture::load(const void* bgraPixels, Extent size, bool filterLinear) +void Texture::load(const uint8_t* bgraPixels, Extent size) { if(texture_) glDeleteTextures(1, &texture_); @@ -64,78 +68,43 @@ void Texture::upload(const void* bgraPixels) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size_.x, size_.y, GL_BGRA, GL_UNSIGNED_BYTE, bgraPixels); } -bool Texture::load(SDL_Surface* surface, bool filterLinear) +bool Texture::load(const libsiedler2::baseArchivItem_Bitmap& bitmap, bool filterLinear) { - if(!surface) + const auto w = bitmap.getWidth(); + const auto h = bitmap.getHeight(); + if(w == 0 || h == 0) return false; - // For 8-bit paletted surfaces, honour colorkey if set. - if(surface->format->palette) + // Render the bitmap to a BGRA buffer via libsiedler2's print method. + // This handles both paletted and BGRA source formats. + std::vector bgra(static_cast(w) * h * 4); + if(bitmap.print(bgra.data(), w, h, libsiedler2::TextureFormat::BGRA) != 0) { - const int w = surface->w, h = surface->h; - std::vector pixels(static_cast(w) * h); - - SDL_Palette* pal = surface->format->palette; - Uint32 ck; - const bool hasCK = SDL_GetColorKey(surface, &ck) == 0; - const Uint8 ckIdx = hasCK ? static_cast(ck & 0xFF) : 0; - - // Water color keys used by the ice floe rendering (two-pass alpha test). - // These are the RGB values decoded from the old 32-bit SGE colorkeys - // that were used to punch holes in the snow/swamp texture so that - // the animated water underneath shows through. - static constexpr std::array kWaterColorKeys = {{ - {0, 55, 111, 0}, - {0, 55, 115, 0}, - {0, 51, 111, 0}, - {0, 51, 103, 0}, - {0, 43, 111, 0}, - }}; - - // Build set of transparent palette indices. - // Start with the SDL colorkey (if any), then add any palette entries - // that match the water color keys. - std::set transparentIdxs; - if(hasCK) - transparentIdxs.insert(ckIdx); - for(const auto& key : kWaterColorKeys) - { - for(int i = 0; i < 256; i++) - { - if(pal->colors[i].r == key.r && pal->colors[i].g == key.g && pal->colors[i].b == key.b) - { - transparentIdxs.insert(static_cast(i)); - break; - } - } - } - - SDL_LockSurface(surface); - for(int row = 0; row < h; row++) + // If print fails (e.g. paletted bitmap without a palette), try manual conversion + if(bitmap.getFormat() == libsiedler2::TextureFormat::Paletted) { - const auto* src = (const Uint8*)surface->pixels + row * surface->pitch; - for(int col = 0; col < w; col++) + const auto* pal = bitmap.getPalette(); + if(!pal) + return false; + const auto& src = bitmap.getPixelData(); + if(src.size() < static_cast(w) * h) + return false; + for(unsigned y = 0; y < h; y++) { - const Uint8 idx = src[col]; - if(transparentIdxs.count(idx)) - pixels[row * w + col] = 0; // transparent - else + for(unsigned x = 0; x < w; x++) { - const SDL_Color& c = pal->colors[idx]; - // BGRA layout: A<<24 | R<<16 | G<<8 | B (little-endian GL_BGRA) - pixels[row * w + col] = (0xFFu << 24) | (Uint32(c.r) << 16) | (Uint32(c.g) << 8) | Uint32(c.b); + uint8_t idx = src[y * w + x]; + auto c = pal->get(idx); + uint32_t& dst = reinterpret_cast(bgra.data())[y * w + x]; + dst = (0xFFu << 24) | (uint32_t(c.r) << 16) | (uint32_t(c.g) << 8) | uint32_t(c.b); } } - } - SDL_UnlockSurface(surface); - - load(pixels.data(), Extent(w, h), filterLinear); - return true; + } else + return false; } - // Only 8-bit paletted surfaces are used (LBM files). - // 32-bit surfaces are not expected from any current caller. - return false; + load(bgra.data(), Extent(w, h), filterLinear); + return true; } void Texture::draw(const Rect& destRect) const @@ -255,19 +224,14 @@ void drawRect(const Rect& rect, unsigned color) glColor4f(1, 1, 1, 1); } -Texture& getBmpTexture(int idx, bool filterLinear) +Texture& getTexture(ArchiveID archive, int index, bool filterLinear) { - if(idx < 0 || static_cast(idx) >= global::bmpArray.size()) - { - static Texture dummy; - return dummy; - } - return Texture::getBmpTexture(idx, filterLinear); + return Texture::getTexture(archive, index, filterLinear); } void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned faceTex) { - getBmpTexture(baseTex).drawTiled(area); + getTexture(ArchiveID::EDITIO, baseTex).drawTiled(area); const auto sz = area.getSize(); @@ -283,68 +247,42 @@ void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned fa } // Foreground inset by 2px - const Rect fgRect(area.getOrigin() + Position(2, 2), sz - Extent(4, 4)); - getBmpTexture(faceTex).drawTiled(fgRect); + const Extent fgSz(sz.x - 4u, sz.y - 4u); + const Rect fgRect(area.getOrigin() + Position(2, 2), fgSz); + getTexture(ArchiveID::EDITIO, faceTex).drawTiled(fgRect); } -// --------------------------------------------------------------------------- -// Bitmap-texture cache (static members) -// --------------------------------------------------------------------------- +// Bitmap-texture cache (static members) +// Cache for typed-archive textures: (archive, index) → Texture +static std::map, std::unique_ptr> s_typedTexCache; -std::vector> Texture::s_bmpTexCache; -std::vector Texture::s_bmpTexLinearFlags; - -Texture& Texture::getBmpTexture(int idx, bool filterLinear) +Texture& Texture::getTexture(ArchiveID archive, int index, bool filterLinear) { - if(idx < 0 || idx >= static_cast(global::bmpArray.size())) + auto& archiv = global::typedArchives[archive]; + if(index < 0 || static_cast(index) >= archiv.size()) { static Texture dummy; return dummy; } - if(static_cast(s_bmpTexCache.size()) <= idx) - { - s_bmpTexCache.resize(idx + 1); - s_bmpTexLinearFlags.resize(idx + 1, false); - } - if(!s_bmpTexCache[idx] || s_bmpTexLinearFlags[idx] != filterLinear || !s_bmpTexCache[idx]->isValid()) + const auto key = std::make_pair(archive, index); + auto it = s_typedTexCache.find(key); + if(it == s_typedTexCache.end() || !it->second->isValid()) { - if(!s_bmpTexCache[idx]) - s_bmpTexCache[idx] = std::make_unique(); - s_bmpTexLinearFlags[idx] = filterLinear; - auto& bmp = global::bmpArray[idx]; - if(bmp.surface) + auto tex = std::make_unique(); + const auto* bmp = dynamic_cast(archiv.get(index)); + if(bmp) { - s_bmpTexCache[idx]->load(bmp.surface.get(), filterLinear); - s_bmpTexCache[idx]->anchorX_ = bmp.nx; - s_bmpTexCache[idx]->anchorY_ = bmp.ny; + tex->load(*bmp, filterLinear); + tex->anchor_ = {bmp->getNx(), bmp->getNy()}; } + it = s_typedTexCache.emplace(key, std::move(tex)).first; } - return *s_bmpTexCache[idx]; + return *it->second; } -void Texture::drawSprite(int baseX, int baseY) const +void Texture::drawSprite(Position pos) const { if(!isValid()) return; - draw(Position(baseX - anchorX_, baseY - anchorY_)); -} - -void Texture::ensureBmpTex(int idx) -{ - if(idx < 0 || idx >= static_cast(global::bmpArray.size())) - return; - getBmpTexture(idx); -} - -void Texture::invalidateBmpCache(int start, int end) -{ - if(start > end) - return; - if(end >= static_cast(s_bmpTexCache.size())) - end = static_cast(s_bmpTexCache.size()) - 1; - for(int i = start; i <= end; i++) - { - if(i >= 0 && i < static_cast(s_bmpTexCache.size())) - s_bmpTexCache[i].reset(); - } + draw(pos - anchor_); } diff --git a/Texture.h b/Texture.h index c13c8d1..8af748f 100644 --- a/Texture.h +++ b/Texture.h @@ -4,6 +4,7 @@ #pragma once +#include "ArchiveID.h" #include "Rect.h" #include #include @@ -11,6 +12,10 @@ #include #include +namespace libsiedler2 { +class baseArchivItem_Bitmap; +} // namespace libsiedler2 + /// Wraps a texture with RAII and provides draw methods. class Texture { @@ -25,9 +30,11 @@ class Texture Texture(const Texture&) = delete; Texture& operator=(const Texture&) = delete; - /// Load from a 32-bit or 8-bit paletted SDL surface. - /// For 8-bit surfaces, optional colorkey is respected (keyed pixels become transparent). - bool load(SDL_Surface* surface, bool filterLinear = false); + /// Load from a libsiedler2 bitmap (paletted or BGRA). + bool load(const libsiedler2::baseArchivItem_Bitmap& bitmap, bool filterLinear = false); + + /// Load raw BGRA pixel data directly. + void load(const uint8_t* bgraPixels, Extent size); /// Create an empty texture of the given size (for use as a render-target). void createEmpty(Extent size, bool filterLinear = false); @@ -44,9 +51,6 @@ class Texture /// Tile the texture to fill the given rectangle. void drawTiled(const Rect& destRect) const; - /// Direct handle access for manual GL ops. - GLuint getHandle() const { return texture_; } - /// Size in pixels. Extent getSize() const { return size_; } @@ -56,41 +60,33 @@ class Texture /// Returns true if the texture has been created. bool isValid() const { return texture_ != 0; } - /// Draw at native size at (baseX, baseY) adjusted by the sprite anchor. - void drawSprite(int baseX, int baseY) const; + /// Draw at native size at the given position adjusted by the sprite anchor. + void drawSprite(Position pos) const; - // ---- Static bitmap-texture cache (used by CFont::draw) ---- + /// Sprite anchor offset (set by getTexture). + Position anchor() const { return anchor_; } - /// Return (or create on first use) a cached GL texture for a bobBMP entry. - static Texture& getBmpTexture(int idx, bool filterLinear = false); + /// Direct handle access for manual GL ops. + GLuint getHandle() const { return texture_; } - /// Ensure the bitmap at idx has a cached GL texture (pre-warm). - static void ensureBmpTex(int idx); + // Static bitmap-texture cache - /// Invalidate the texture cache for entries [start, end] so the next getBmpTexture() re-uploads. - static void invalidateBmpCache(int start, int end); + /// Return (or create on first use) a cached GL texture from a typed archive. + static Texture& getTexture(ArchiveID archive, int index, bool filterLinear = false); private: GLuint texture_ = 0; Extent size_; - Sint16 anchorX_ = 0, anchorY_ = 0; // sprite anchor offset, set by getBmpTexture - - // ---- Bitmap-texture cache internals ---- - static std::vector> s_bmpTexCache; - static std::vector s_bmpTexLinearFlags; + Position anchor_ = {0, 0}; // sprite anchor offset, set by getTexture - /// Internal: create or recreate texture from raw BGRA pixel data. - void load(const void* bgraPixels, Extent size, bool filterLinear); }; /// Draw a filled rectangle with a 32-bit ARGB colour. void drawRect(const Rect& rect, unsigned color); /// Draw a 3D-style button box: tiled background, 2px black frame (sunken if pressed, raised otherwise), -/// and tiled foreground inset by 2px. +/// and tiled foreground inset by 2px. All button textures from EDITIO.IDX. void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned faceTex); -/// Get or create the cached OpenGL texture for a bitmap index. -/// The texture is loaded from the SDL surface on first access. -/// @param filterLinear Whether to use linear filtering (for scaled backgrounds). -Texture& getBmpTexture(int idx, bool filterLinear = false); +/// Get or create the cached OpenGL texture from a typed archive. +Texture& getTexture(ArchiveID archive, int index, bool filterLinear = false); diff --git a/callbacks.cpp b/callbacks.cpp index 338891e..601e26f 100644 --- a/callbacks.cpp +++ b/callbacks.cpp @@ -21,6 +21,7 @@ #include "globals.h" #include "helpers/format.hpp" #include "s25util/strAlgos.h" +#include #include #include #include @@ -145,7 +146,7 @@ void callback::mainmenu(int Param) switch(Param) { case INITIALIZING_CALL: - MainMenu = global::s2->RegisterMenu(std::make_unique(SPLASHSCREEN_MAINMENU)); + MainMenu = global::s2->RegisterMenu(std::make_unique(SPLASHSCREEN_MAINMENU, ArchiveID::SETUP010)); MainMenu->addButton(mainmenu, ENDGAME, Position(50, 400), Extent(200, 20), BUTTON_RED1, "Quit program"); MainMenu->addButton(mainmenu, STARTEDITOR, Position(50, 160), Extent(200, 20), BUTTON_RED1, "Start editor"); MainMenu->addButton(mainmenu, LOADMAP, Position(50, 200), Extent(200, 20), BUTTON_GREEN2, "Load map"); @@ -239,7 +240,7 @@ void callback::submenuOptions(int Param) switch(Param) { case INITIALIZING_CALL: - SubMenu = global::s2->RegisterMenu(std::make_unique(SPLASHSCREEN_SUBMENU3)); + SubMenu = global::s2->RegisterMenu(std::make_unique(SPLASHSCREEN_SUBMENU3, ArchiveID::SETUP013)); // add button for "back to main menu" SubMenu->addButton(submenuOptions, MAINMENU, Position(global::s2->GameResolution.x / 2 - 100, 440), Extent(200, 20), BUTTON_RED1, "back"); @@ -611,9 +612,9 @@ void callback::EditorHelpMenu(int Param) case INITIALIZING_CALL: if(WNDHelp) break; - WNDHelp = global::s2->RegisterWindow( - std::make_unique(EditorHelpMenu, WINDOWQUIT, WindowPos::Center, Extent(640, 380), "Hilfe", - WINDOW_GREEN2, WINDOW_CLOSE | WINDOW_MOVE | WINDOW_RESIZE | WINDOW_MINIMIZE)); + WNDHelp = global::s2->RegisterWindow(std::make_unique( + EditorHelpMenu, WINDOWQUIT, WindowPos::Center, Extent(640, 380), "Hilfe", WINDOW_GREEN2, + WINDOW_CLOSE | WINDOW_MOVE | WINDOW_RESIZE | WINDOW_MINIMIZE, ArchiveID::EDITIO)); SelectBoxHelp = WNDHelp->addSelectBox(Position(0, 0), Extent(WNDHelp->getSize() - WNDHelp->getBorderSize()), FontSize::Medium, FontColor::Yellow, BUTTON_GREEN1); @@ -811,10 +812,10 @@ void callback::EditorLoadMenu(int Param) if(!WNDLoad || !CB_Filename || !BtnLoad || !BtnAbort) break; - int borderL = global::bmpArray[WINDOW_LEFT_FRAME].w; - int borderR = global::bmpArray[WINDOW_RIGHT_FRAME].w; - int borderT = global::bmpArray[WINDOW_UPPER_FRAME].h; - int borderB = global::bmpArray[WINDOW_LOWER_FRAME].h; + int borderL = static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_LEFT_FRAME).x); + int borderR = static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_RIGHT_FRAME).x); + int borderT = static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).y); + int borderB = static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_LOWER_FRAME).y); int window_w = static_cast(WNDLoad->getSize().x); int window_h = static_cast(WNDLoad->getSize().y); @@ -1094,24 +1095,28 @@ void callback::EditorTextureMenu(int Param) MapObj->setMode(EDITOR_MODE_TEXTURE); MapObj->setModeContent(TRIANGLE_TEXTURE_SNOW); - WNDTexture->addPicture(EditorTextureMenu, PICSNOW, Position(2, 2), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICSTEPPE, Position(36, 2), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICSWAMP, Position(70, 2), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICFLOWER, Position(104, 2), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMINING1, Position(138, 2), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMINING2, Position(172, 2), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMINING3, Position(2, 36), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMINING4, Position(36, 36), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICSTEPPE_MEADOW1, Position(70, 36), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMEADOW1, Position(104, 36), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMEADOW2, Position(138, 36), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMEADOW3, Position(172, 36), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICSTEPPE_MEADOW2, Position(2, 70), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMINING_MEADOW, Position(36, 70), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICWATER, Position(70, 70), textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICLAVA, Position(104, 70), textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICSNOW, Position(2, 2), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICSTEPPE, Position(36, 2), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICSWAMP, Position(70, 2), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICFLOWER, Position(104, 2), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICMINING1, Position(138, 2), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICMINING2, Position(172, 2), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICMINING3, Position(2, 36), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICMINING4, Position(36, 36), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICSTEPPE_MEADOW1, Position(70, 36), ArchiveID::EDITIO, + textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICMEADOW1, Position(104, 36), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICMEADOW2, Position(138, 36), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICMEADOW3, Position(172, 36), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICSTEPPE_MEADOW2, Position(2, 70), ArchiveID::EDITIO, + textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICMINING_MEADOW, Position(36, 70), ArchiveID::EDITIO, + textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICWATER, Position(70, 70), ArchiveID::EDITIO, textureIndex++); + WNDTexture->addPicture(EditorTextureMenu, PICLAVA, Position(104, 70), ArchiveID::EDITIO, textureIndex++); if(map->type != MAP_WASTELAND) - WNDTexture->addPicture(EditorTextureMenu, PICMEADOW_MIXED, Position(138, 70), textureIndex); + WNDTexture->addPicture(EditorTextureMenu, PICMEADOW_MIXED, Position(138, 70), ArchiveID::EDITIO, + textureIndex); break; case PICSNOW: MapObj->setModeContent(TRIANGLE_TEXTURE_SNOW); break; @@ -1218,30 +1223,45 @@ void callback::EditorTreeMenu(int Param) switch(map->type) { case MAP_GREENLAND: - WNDTree->addPicture(EditorTreeMenu, PICPINE, Position(2, 2), PICTURE_TREE_PINE); - WNDTree->addPicture(EditorTreeMenu, PICBIRCH, Position(36, 2), PICTURE_TREE_BIRCH); - WNDTree->addPicture(EditorTreeMenu, PICOAK, Position(70, 2), PICTURE_TREE_OAK); - WNDTree->addPicture(EditorTreeMenu, PICPALM1, Position(104, 2), PICTURE_TREE_PALM1); - WNDTree->addPicture(EditorTreeMenu, PICPALM2, Position(2, 36), PICTURE_TREE_PALM2); - WNDTree->addPicture(EditorTreeMenu, PICPINEAPPLE, Position(36, 36), PICTURE_TREE_PINEAPPLE); - WNDTree->addPicture(EditorTreeMenu, PICCYPRESS, Position(70, 36), PICTURE_TREE_CYPRESS); - WNDTree->addPicture(EditorTreeMenu, PICCHERRY, Position(104, 36), PICTURE_TREE_CHERRY); - WNDTree->addPicture(EditorTreeMenu, PICFIR, Position(2, 72), PICTURE_TREE_FIR); - WNDTree->addPicture(EditorTreeMenu, PICWOOD_MIXED, Position(36, 70), PICTURE_TREE_WOOD_MIXED); - WNDTree->addPicture(EditorTreeMenu, PICPALM_MIXED, Position(70, 70), PICTURE_TREE_PALM_MIXED); + WNDTree->addPicture(EditorTreeMenu, PICPINE, Position(2, 2), ArchiveID::EDITIO, PICTURE_TREE_PINE); + WNDTree->addPicture(EditorTreeMenu, PICBIRCH, Position(36, 2), ArchiveID::EDITIO, + PICTURE_TREE_BIRCH); + WNDTree->addPicture(EditorTreeMenu, PICOAK, Position(70, 2), ArchiveID::EDITIO, PICTURE_TREE_OAK); + WNDTree->addPicture(EditorTreeMenu, PICPALM1, Position(104, 2), ArchiveID::EDITIO, + PICTURE_TREE_PALM1); + WNDTree->addPicture(EditorTreeMenu, PICPALM2, Position(2, 36), ArchiveID::EDITIO, + PICTURE_TREE_PALM2); + WNDTree->addPicture(EditorTreeMenu, PICPINEAPPLE, Position(36, 36), ArchiveID::EDITIO, + PICTURE_TREE_PINEAPPLE); + WNDTree->addPicture(EditorTreeMenu, PICCYPRESS, Position(70, 36), ArchiveID::EDITIO, + PICTURE_TREE_CYPRESS); + WNDTree->addPicture(EditorTreeMenu, PICCHERRY, Position(104, 36), ArchiveID::EDITIO, + PICTURE_TREE_CHERRY); + WNDTree->addPicture(EditorTreeMenu, PICFIR, Position(2, 72), ArchiveID::EDITIO, PICTURE_TREE_FIR); + WNDTree->addPicture(EditorTreeMenu, PICWOOD_MIXED, Position(36, 70), ArchiveID::EDITIO, + PICTURE_TREE_WOOD_MIXED); + WNDTree->addPicture(EditorTreeMenu, PICPALM_MIXED, Position(70, 70), ArchiveID::EDITIO, + PICTURE_TREE_PALM_MIXED); break; case MAP_WASTELAND: - WNDTree->addPicture(EditorTreeMenu, PICFLAPHAT, Position(2, 2), PICTURE_TREE_FLAPHAT); - WNDTree->addPicture(EditorTreeMenu, PICSPIDER, Position(36, 2), PICTURE_TREE_SPIDER); - WNDTree->addPicture(EditorTreeMenu, PICPINEAPPLE, Position(70, 2), PICTURE_TREE_PINEAPPLE); - WNDTree->addPicture(EditorTreeMenu, PICCHERRY, Position(104, 2), PICTURE_TREE_CHERRY); + WNDTree->addPicture(EditorTreeMenu, PICFLAPHAT, Position(2, 2), ArchiveID::EDITIO, + PICTURE_TREE_FLAPHAT); + WNDTree->addPicture(EditorTreeMenu, PICSPIDER, Position(36, 2), ArchiveID::EDITIO, + PICTURE_TREE_SPIDER); + WNDTree->addPicture(EditorTreeMenu, PICPINEAPPLE, Position(70, 2), ArchiveID::EDITIO, + PICTURE_TREE_PINEAPPLE); + WNDTree->addPicture(EditorTreeMenu, PICCHERRY, Position(104, 2), ArchiveID::EDITIO, + PICTURE_TREE_CHERRY); break; case MAP_WINTERLAND: - WNDTree->addPicture(EditorTreeMenu, PICPINE, Position(2, 2), PICTURE_TREE_PINE); - WNDTree->addPicture(EditorTreeMenu, PICBIRCH, Position(36, 2), PICTURE_TREE_BIRCH); - WNDTree->addPicture(EditorTreeMenu, PICCYPRESS, Position(70, 2), PICTURE_TREE_CYPRESS); - WNDTree->addPicture(EditorTreeMenu, PICFIR, Position(104, 2), PICTURE_TREE_FIR); - WNDTree->addPicture(EditorTreeMenu, PICWOOD_MIXED, Position(2, 36), PICTURE_TREE_WOOD_MIXED); + WNDTree->addPicture(EditorTreeMenu, PICPINE, Position(2, 2), ArchiveID::EDITIO, PICTURE_TREE_PINE); + WNDTree->addPicture(EditorTreeMenu, PICBIRCH, Position(36, 2), ArchiveID::EDITIO, + PICTURE_TREE_BIRCH); + WNDTree->addPicture(EditorTreeMenu, PICCYPRESS, Position(70, 2), ArchiveID::EDITIO, + PICTURE_TREE_CYPRESS); + WNDTree->addPicture(EditorTreeMenu, PICFIR, Position(104, 2), ArchiveID::EDITIO, PICTURE_TREE_FIR); + WNDTree->addPicture(EditorTreeMenu, PICWOOD_MIXED, Position(2, 36), ArchiveID::EDITIO, + PICTURE_TREE_WOOD_MIXED); break; default: // should not happen break; @@ -1404,10 +1424,14 @@ void callback::EditorResourceMenu(int Param) WINDOW_GREEN1, WINDOW_CLOSE | WINDOW_MINIMIZE | WINDOW_MOVE)); MapObj = global::s2->getMapObj(); - WNDResource->addPicture(EditorResourceMenu, PICGOLD, Position(2, 2), PICTURE_RESOURCE_GOLD); - WNDResource->addPicture(EditorResourceMenu, PICORE, Position(36, 2), PICTURE_RESOURCE_ORE); - WNDResource->addPicture(EditorResourceMenu, PICCOAL, Position(70, 2), PICTURE_RESOURCE_COAL); - WNDResource->addPicture(EditorResourceMenu, PICGRANITE, Position(104, 2), PICTURE_RESOURCE_GRANITE); + WNDResource->addPicture(EditorResourceMenu, PICGOLD, Position(2, 2), ArchiveID::EDITIO, + PICTURE_RESOURCE_GOLD); + WNDResource->addPicture(EditorResourceMenu, PICORE, Position(36, 2), ArchiveID::EDITIO, + PICTURE_RESOURCE_ORE); + WNDResource->addPicture(EditorResourceMenu, PICCOAL, Position(70, 2), ArchiveID::EDITIO, + PICTURE_RESOURCE_COAL); + WNDResource->addPicture(EditorResourceMenu, PICGRANITE, Position(104, 2), ArchiveID::EDITIO, + PICTURE_RESOURCE_GRANITE); MapObj->setMode(EDITOR_MODE_RESOURCE_RAISE); MapObj->setModeContent(0x51); @@ -1509,52 +1533,64 @@ void callback::EditorLandscapeMenu(int Param) switch(map->type) { case MAP_GREENLAND: - WNDLandscape->addPicture(EditorLandscapeMenu, PICGRANITE, Position(2, 2), + WNDLandscape->addPicture(EditorLandscapeMenu, PICGRANITE, Position(2, 2), ArchiveID::EDITIO, PICTURE_LANDSCAPE_GRANITE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICTREEDEAD, Position(36, 2), + WNDLandscape->addPicture(EditorLandscapeMenu, PICTREEDEAD, Position(36, 2), ArchiveID::EDITIO, PICTURE_LANDSCAPE_TREE_DEAD); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSTONE, Position(70, 2), PICTURE_LANDSCAPE_STONE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICCACTUS, Position(2, 36), PICTURE_LANDSCAPE_CACTUS); - WNDLandscape->addPicture(EditorLandscapeMenu, PICPEBBLE, Position(36, 36), + WNDLandscape->addPicture(EditorLandscapeMenu, PICSTONE, Position(70, 2), ArchiveID::EDITIO, + PICTURE_LANDSCAPE_STONE); + WNDLandscape->addPicture(EditorLandscapeMenu, PICCACTUS, Position(2, 36), ArchiveID::EDITIO, + PICTURE_LANDSCAPE_CACTUS); + WNDLandscape->addPicture(EditorLandscapeMenu, PICPEBBLE, Position(36, 36), ArchiveID::EDITIO, PICTURE_LANDSCAPE_PEBBLE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICBUSH, Position(70, 36), PICTURE_LANDSCAPE_BUSH); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSHRUB, Position(2, 70), PICTURE_LANDSCAPE_SHRUB); - WNDLandscape->addPicture(EditorLandscapeMenu, PICBONE, Position(36, 70), PICTURE_LANDSCAPE_BONE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICMUSHROOM, Position(70, 70), + WNDLandscape->addPicture(EditorLandscapeMenu, PICBUSH, Position(70, 36), ArchiveID::EDITIO, + PICTURE_LANDSCAPE_BUSH); + WNDLandscape->addPicture(EditorLandscapeMenu, PICSHRUB, Position(2, 70), ArchiveID::EDITIO, + PICTURE_LANDSCAPE_SHRUB); + WNDLandscape->addPicture(EditorLandscapeMenu, PICBONE, Position(36, 70), ArchiveID::EDITIO, + PICTURE_LANDSCAPE_BONE); + WNDLandscape->addPicture(EditorLandscapeMenu, PICMUSHROOM, Position(70, 70), ArchiveID::EDITIO, PICTURE_LANDSCAPE_MUSHROOM); - WNDLandscape->addPicture(EditorLandscapeMenu, PICFLOWERS, Position(5, 107), MAPPIC_FLOWERS); + WNDLandscape->addPicture(EditorLandscapeMenu, PICFLOWERS, Position(5, 107), ArchiveID::MAP00, + MAPPIC_FLOWERS); break; case MAP_WASTELAND: - WNDLandscape->addPicture(EditorLandscapeMenu, PICGRANITE, Position(2, 2), + WNDLandscape->addPicture(EditorLandscapeMenu, PICGRANITE, Position(2, 2), ArchiveID::EDITIO, PICTURE_LANDSCAPE_GRANITE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICTREEDEAD, Position(36, 2), + WNDLandscape->addPicture(EditorLandscapeMenu, PICTREEDEAD, Position(36, 2), ArchiveID::EDITIO, PICTURE_LANDSCAPE_TREE_DEAD); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSTONE, Position(70, 2), PICTURE_LANDSCAPE_STONE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSTALAGMITE, Position(2, 36), + WNDLandscape->addPicture(EditorLandscapeMenu, PICSTONE, Position(70, 2), ArchiveID::EDITIO, + PICTURE_LANDSCAPE_STONE); + WNDLandscape->addPicture(EditorLandscapeMenu, PICSTALAGMITE, Position(2, 36), ArchiveID::EDITIO, PICTURE_LANDSCAPE_STALAGMITE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICPEBBLE, Position(36, 36), + WNDLandscape->addPicture(EditorLandscapeMenu, PICPEBBLE, Position(36, 36), ArchiveID::EDITIO, PICTURE_LANDSCAPE_PEBBLE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICBUSH, Position(70, 36), PICTURE_LANDSCAPE_BUSH); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSHRUB, Position(2, 70), PICTURE_LANDSCAPE_SHRUB); - WNDLandscape->addPicture(EditorLandscapeMenu, PICBONE, Position(36, 70), PICTURE_LANDSCAPE_BONE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICMUSHROOM, Position(70, 70), + WNDLandscape->addPicture(EditorLandscapeMenu, PICBUSH, Position(70, 36), ArchiveID::EDITIO, + PICTURE_LANDSCAPE_BUSH); + WNDLandscape->addPicture(EditorLandscapeMenu, PICSHRUB, Position(2, 70), ArchiveID::EDITIO, + PICTURE_LANDSCAPE_SHRUB); + WNDLandscape->addPicture(EditorLandscapeMenu, PICBONE, Position(36, 70), ArchiveID::EDITIO, + PICTURE_LANDSCAPE_BONE); + WNDLandscape->addPicture(EditorLandscapeMenu, PICMUSHROOM, Position(70, 70), ArchiveID::EDITIO, PICTURE_LANDSCAPE_MUSHROOM); - WNDLandscape->addPicture(EditorLandscapeMenu, PICFLOWERS, Position(5, 107), MAPPIC_FLOWERS); + WNDLandscape->addPicture(EditorLandscapeMenu, PICFLOWERS, Position(5, 107), ArchiveID::MAP00, + MAPPIC_FLOWERS); break; case MAP_WINTERLAND: - WNDLandscape->addPicture(EditorLandscapeMenu, PICGRANITE, Position(2, 2), + WNDLandscape->addPicture(EditorLandscapeMenu, PICGRANITE, Position(2, 2), ArchiveID::EDITIO, PICTURE_LANDSCAPE_GRANITE_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICTREEDEAD, Position(36, 2), + WNDLandscape->addPicture(EditorLandscapeMenu, PICTREEDEAD, Position(36, 2), ArchiveID::EDITIO, PICTURE_LANDSCAPE_TREE_DEAD_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSTONE, Position(70, 2), + WNDLandscape->addPicture(EditorLandscapeMenu, PICSTONE, Position(70, 2), ArchiveID::EDITIO, PICTURE_LANDSCAPE_STONE_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICPEBBLE, Position(2, 36), + WNDLandscape->addPicture(EditorLandscapeMenu, PICPEBBLE, Position(2, 36), ArchiveID::EDITIO, PICTURE_LANDSCAPE_PEBBLE_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICBONE, Position(36, 36), + WNDLandscape->addPicture(EditorLandscapeMenu, PICBONE, Position(36, 36), ArchiveID::EDITIO, PICTURE_LANDSCAPE_BONE_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICMUSHROOM, Position(70, 36), + WNDLandscape->addPicture(EditorLandscapeMenu, PICMUSHROOM, Position(70, 36), ArchiveID::EDITIO, PICTURE_LANDSCAPE_MUSHROOM_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICFLOWERS, Position(73, 73), MAPPIC_FLOWERS); + WNDLandscape->addPicture(EditorLandscapeMenu, PICFLOWERS, Position(73, 73), ArchiveID::MAP00, + MAPPIC_FLOWERS); break; default: // should not happen break; @@ -1705,12 +1741,14 @@ void callback::EditorAnimalMenu(int Param) WNDAnimal = global::s2->RegisterWindow( std::make_unique(EditorAnimalMenu, WINDOWQUIT, Pos, Extent(116, 106), "Animals", WINDOW_GREEN1, WINDOW_CLOSE | WINDOW_MINIMIZE | WINDOW_MOVE)); - WNDAnimal->addPicture(EditorAnimalMenu, PICRABBIT, Position(2, 2), PICTURE_ANIMAL_RABBIT); - WNDAnimal->addPicture(EditorAnimalMenu, PICFOX, Position(36, 2), PICTURE_ANIMAL_FOX); - WNDAnimal->addPicture(EditorAnimalMenu, PICSTAG, Position(70, 2), PICTURE_ANIMAL_STAG); - WNDAnimal->addPicture(EditorAnimalMenu, PICROE, Position(2, 36), PICTURE_ANIMAL_ROE); - WNDAnimal->addPicture(EditorAnimalMenu, PICDUCK, Position(36, 36), PICTURE_ANIMAL_DUCK); - WNDAnimal->addPicture(EditorAnimalMenu, PICSHEEP, Position(70, 36), PICTURE_ANIMAL_SHEEP); + WNDAnimal->addPicture(EditorAnimalMenu, PICRABBIT, Position(2, 2), ArchiveID::EDITIO, + PICTURE_ANIMAL_RABBIT); + WNDAnimal->addPicture(EditorAnimalMenu, PICFOX, Position(36, 2), ArchiveID::EDITIO, PICTURE_ANIMAL_FOX); + WNDAnimal->addPicture(EditorAnimalMenu, PICSTAG, Position(70, 2), ArchiveID::EDITIO, PICTURE_ANIMAL_STAG); + WNDAnimal->addPicture(EditorAnimalMenu, PICROE, Position(2, 36), ArchiveID::EDITIO, PICTURE_ANIMAL_ROE); + WNDAnimal->addPicture(EditorAnimalMenu, PICDUCK, Position(36, 36), ArchiveID::EDITIO, PICTURE_ANIMAL_DUCK); + WNDAnimal->addPicture(EditorAnimalMenu, PICSHEEP, Position(70, 36), ArchiveID::EDITIO, + PICTURE_ANIMAL_SHEEP); MapObj = global::s2->getMapObj(); MapObj->setMode(EDITOR_MODE_ANIMAL); @@ -1939,8 +1977,10 @@ void callback::EditorCursorMenu(int Param) CursorRandomButton = WNDCursor->addButton(EditorCursorMenu, CURSORRANDOM, Position(2, 34), Extent(196, 32), BUTTON_GREY, "Cursor-Activity: static"); WNDCursor->addButton(EditorCursorMenu, TRIANGLE, Position(2, 66), Extent(32, 32), BUTTON_GREY, nullptr); - trianglePictureArrowUp = WNDCursor->addStaticPicture(Position(8, 74), CURSOR_SYMBOL_ARROW_UP); - trianglePictureArrowDown = WNDCursor->addStaticPicture(Position(17, 77), CURSOR_SYMBOL_ARROW_DOWN); + trianglePictureArrowUp = + WNDCursor->addStaticPicture(Position(8, 74), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP); + trianglePictureArrowDown = + WNDCursor->addStaticPicture(Position(17, 77), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN); if(MapObj) { MapObj->setVertexFillRSU(true); @@ -1963,8 +2003,8 @@ void callback::EditorCursorMenu(int Param) trianglePictureArrowDown = -1; // add random if necessary if(trianglePictureRandom == -1) - trianglePictureRandom = - WNDCursor->addStaticPicture(Position(14, 76), FONT14_SPACE + 31 * 7 + 5); // Interrogation point + trianglePictureRandom = WNDCursor->addStaticPicture( + Position(14, 76), ArchiveID::EDITIO, FONT14_SPACE + 31 * 7 + 5); // Interrogation point MapObj->setVertexFillRSU(false); MapObj->setVertexFillUSD(false); MapObj->setVertexFillRandom(true); @@ -1972,10 +2012,12 @@ void callback::EditorCursorMenu(int Param) { // only arrow down is shown, so upgrade to both arrows // add arrow up - trianglePictureArrowUp = WNDCursor->addStaticPicture(Position(8, 74), CURSOR_SYMBOL_ARROW_UP); + trianglePictureArrowUp = + WNDCursor->addStaticPicture(Position(8, 74), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP); // add arrow down if necessary if(trianglePictureArrowDown == -1) - trianglePictureArrowDown = WNDCursor->addStaticPicture(Position(17, 77), CURSOR_SYMBOL_ARROW_DOWN); + trianglePictureArrowDown = + WNDCursor->addStaticPicture(Position(17, 77), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN); MapObj->setVertexFillRSU(true); MapObj->setVertexFillUSD(true); MapObj->setVertexFillRandom(false); @@ -1988,7 +2030,8 @@ void callback::EditorCursorMenu(int Param) WNDCursor->delStaticPicture(trianglePictureArrowUp); trianglePictureArrowUp = -1; } - trianglePictureArrowDown = WNDCursor->addStaticPicture(Position(17, 77), CURSOR_SYMBOL_ARROW_DOWN); + trianglePictureArrowDown = + WNDCursor->addStaticPicture(Position(17, 77), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN); MapObj->setVertexFillRSU(false); MapObj->setVertexFillUSD(true); MapObj->setVertexFillRandom(false); @@ -1999,7 +2042,8 @@ void callback::EditorCursorMenu(int Param) trianglePictureRandom = -1; // add arrow up if necessary if(trianglePictureArrowUp == -1) - trianglePictureArrowUp = WNDCursor->addStaticPicture(Position(8, 74), CURSOR_SYMBOL_ARROW_UP); + trianglePictureArrowUp = + WNDCursor->addStaticPicture(Position(8, 74), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP); // delete arrow down if necessary if(trianglePictureArrowDown != -1) { @@ -2174,7 +2218,7 @@ void callback::EditorCreateMenu(int Param) WNDCreate->addText("Main area", Position(82, 120), FontSize::Small, FontColor::Yellow); WNDCreate->addButton(EditorCreateMenu, TEXTURE_PREVIOUS, Position(45, 139), Extent(35, 20), BUTTON_GREY, "-"); - PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), PicTextureIndexGlobal); + PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), ArchiveID::EDITIO, PicTextureIndexGlobal); WNDCreate->addButton(EditorCreateMenu, TEXTURE_NEXT, Position(158, 139), Extent(35, 20), BUTTON_GREY, "+"); WNDCreate->addText("Border size", Position(103, 175), FontSize::Small, FontColor::Yellow); @@ -2186,7 +2230,8 @@ void callback::EditorCreateMenu(int Param) WNDCreate->addText("Border area", Position(65, 215), FontSize::Small, FontColor::Yellow); WNDCreate->addButton(EditorCreateMenu, BORDER_TEXTURE_PREVIOUS, Position(45, 234), Extent(35, 20), BUTTON_GREY, "-"); - PicBorderTextureIndex = WNDCreate->addStaticPicture(Position(102, 228), PicBorderTextureIndexGlobal); + PicBorderTextureIndex = + WNDCreate->addStaticPicture(Position(102, 228), ArchiveID::EDITIO, PicBorderTextureIndexGlobal); WNDCreate->addButton(EditorCreateMenu, BORDER_TEXTURE_NEXT, Position(158, 234), Extent(35, 20), BUTTON_GREY, "+"); @@ -2331,8 +2376,9 @@ void callback::EditorCreateMenu(int Param) } WNDCreate->delStaticPicture(PicTextureIndex); WNDCreate->delStaticPicture(PicBorderTextureIndex); - PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), PicTextureIndexGlobal); - PicBorderTextureIndex = WNDCreate->addStaticPicture(Position(102, 228), PicBorderTextureIndexGlobal); + PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), ArchiveID::EDITIO, PicTextureIndexGlobal); + PicBorderTextureIndex = + WNDCreate->addStaticPicture(Position(102, 228), ArchiveID::EDITIO, PicBorderTextureIndexGlobal); break; case TEXTURE_PREVIOUS: @@ -2435,7 +2481,7 @@ void callback::EditorCreateMenu(int Param) texture = TRIANGLE_TEXTURE_LAVA; } WNDCreate->delStaticPicture(PicTextureIndex); - PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), PicTextureIndexGlobal); + PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), ArchiveID::EDITIO, PicTextureIndexGlobal); break; case TEXTURE_NEXT: PicTextureIndexGlobal++; @@ -2537,7 +2583,7 @@ void callback::EditorCreateMenu(int Param) texture = TRIANGLE_TEXTURE_LAVA; } WNDCreate->delStaticPicture(PicTextureIndex); - PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), PicTextureIndexGlobal); + PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), ArchiveID::EDITIO, PicTextureIndexGlobal); break; case REDUCE_BORDER: @@ -2653,7 +2699,8 @@ void callback::EditorCreateMenu(int Param) border_texture = TRIANGLE_TEXTURE_LAVA; } WNDCreate->delStaticPicture(PicBorderTextureIndex); - PicBorderTextureIndex = WNDCreate->addStaticPicture(Position(102, 228), PicBorderTextureIndexGlobal); + PicBorderTextureIndex = + WNDCreate->addStaticPicture(Position(102, 228), ArchiveID::EDITIO, PicBorderTextureIndexGlobal); break; case BORDER_TEXTURE_NEXT: PicBorderTextureIndexGlobal++; @@ -2755,7 +2802,8 @@ void callback::EditorCreateMenu(int Param) border_texture = TRIANGLE_TEXTURE_LAVA; } WNDCreate->delStaticPicture(PicBorderTextureIndex); - PicBorderTextureIndex = WNDCreate->addStaticPicture(Position(102, 228), PicBorderTextureIndexGlobal); + PicBorderTextureIndex = + WNDCreate->addStaticPicture(Position(102, 228), ArchiveID::EDITIO, PicBorderTextureIndexGlobal); break; case CREATE_WORLD: @@ -2871,10 +2919,10 @@ void callback::MinimapMenu(int Param) mouse, Rect(WNDMinimap->getPos() + Position(6, 20), WNDMinimap->getSize() - Extent(12, 30)))) { DisplayRectangle displayRect = MapObj->getDisplayRect(); - displayRect.setOrigin((mouse - WNDMinimap->getRect().getOrigin() - Position(6, 20) - - Position(global::bmpArray[MAPPIC_ARROWCROSS_ORANGE].nx, - global::bmpArray[MAPPIC_ARROWCROSS_ORANGE].ny)) - * Position(triangleWidth, triangleHeight) * scaleNum); + displayRect.setOrigin( + (mouse - WNDMinimap->getRect().getOrigin() - Position(6, 20) + - Texture::getTexture(ArchiveID::MAP00, MAPPIC_ARROWCROSS_ORANGE).anchor()) + * Position(triangleWidth, triangleHeight) * scaleNum); MapObj->setDisplayRect(displayRect); } } @@ -2924,112 +2972,6 @@ void callback::debugger(int Param) } } -// this is the picture-viewer -void callback::viewer(int Param) -{ - static CWindow* WNDViewer = nullptr; - static int index = 0; - static int PicInWndIndex = -1; - static CFont* PicInfosText = nullptr; - - enum - { - BACKWARD_1, - BACKWARD_10, - BACKWARD_100, - FORWARD_1, - FORWARD_10, - FORWARD_100, - WINDOWQUIT - }; - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - { - assert(WNDViewer); - } - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDViewer) - break; - WNDViewer = global::s2->RegisterWindow( - std::make_unique(viewer, WINDOWQUIT, Position(0, 0), Extent(250, 140), "Viewer", WINDOW_GREEN1, - WINDOW_CLOSE | WINDOW_MOVE | WINDOW_RESIZE | WINDOW_MINIMIZE)); - global::s2->RegisterCallback(viewer); - WNDViewer->addButton(viewer, BACKWARD_100, Position(0, 0), Extent(35, 20), BUTTON_GREY, "100<-"); - WNDViewer->addButton(viewer, BACKWARD_10, Position(35, 0), Extent(35, 20), BUTTON_GREY, "10<-"); - WNDViewer->addButton(viewer, BACKWARD_1, Position(70, 0), Extent(35, 20), BUTTON_GREY, "1<-"); - WNDViewer->addButton(viewer, FORWARD_1, Position(105, 0), Extent(35, 20), BUTTON_GREY, "->1"); - WNDViewer->addButton(viewer, FORWARD_10, Position(140, 0), Extent(35, 20), BUTTON_GREY, "->10"); - WNDViewer->addButton(viewer, FORWARD_100, Position(175, 0), Extent(35, 20), BUTTON_GREY, "->100"); - break; - - case CALL_FROM_GAMELOOP: - if(PicInWndIndex >= 0) - WNDViewer->delStaticPicture(PicInWndIndex); - PicInWndIndex = WNDViewer->addStaticPicture(Position(5, 30), index); - - if(PicInfosText) - { - if(WNDViewer->delText(PicInfosText)) - PicInfosText = nullptr; - } - if(!PicInfosText) - { - const auto infos = - helpers::format("index=%d, w=%d, h=%d, nx=%d, ny=%d", index, global::bmpArray[index].w, - global::bmpArray[index].h, global::bmpArray[index].nx, global::bmpArray[index].ny); - PicInfosText = WNDViewer->addText(infos, Position(220, 3), FontSize::Large, FontColor::Red); - } - - break; - - case BACKWARD_100: - if(index - 100 >= 0) - index -= 100; - else - index = 0; - break; - case BACKWARD_10: - if(index - 10 >= 0) - index -= 10; - else - index = 0; - break; - case BACKWARD_1: - if(index - 1 >= 0) - index -= 1; - else - index = 0; - break; - case FORWARD_1: - if(index < MAXBOBBMP - 1) - index++; - break; - case FORWARD_10: - if(index + 10 < MAXBOBBMP - 1) - index += 10; - break; - case FORWARD_100: - if(index + 100 < MAXBOBBMP - 1) - index += 100; - break; - - case WINDOWQUIT: - if(WNDViewer) - { - WNDViewer->setWaste(); - WNDViewer = nullptr; - global::s2->UnregisterCallback(viewer); - index = 0; - PicInWndIndex = -1; - } - break; - - default: break; - } -} - // this is a submenu for testing void callback::submenu1(int Param) { @@ -3085,19 +3027,22 @@ void callback::submenu1(int Param) switch(Param) { case INITIALIZING_CALL: - SubMenu = global::s2->RegisterMenu(std::make_unique(SPLASHSCREEN_SUBMENU1)); + SubMenu = global::s2->RegisterMenu(std::make_unique(SPLASHSCREEN_SUBMENU1, ArchiveID::SETUP011)); SubMenu->addButton(submenu1, MAINMENU, Position(400, 440), Extent(200, 20), BUTTON_RED1, "back"); greatMoon = SubMenu->addButton(submenu1, GREATMOON, Position(100, 100), Extent(200, 200), BUTTON_STONE, nullptr, MOON); greatMoon->setMotionParams(GREATMOONENTRY, GREATMOONLEAVE); SubMenu->addButton(submenu1, SMALLMOON, Position(100, 350), - Extent(global::bmpArray[MOON].w, global::bmpArray[MOON].h), BUTTON_STONE, nullptr, MOON); + Extent(static_cast(global::getBitmapSize(ArchiveID::EDITRES, MOON).x), + static_cast(global::getBitmapSize(ArchiveID::EDITRES, MOON).y)), + BUTTON_STONE, nullptr, MOON); SubMenu->addButton(submenu1, TOOSMALL, Position(100, 400), - Extent(global::bmpArray[MOON].w - 1, global::bmpArray[MOON].h - 1), BUTTON_STONE, - nullptr, MOON); + Extent(static_cast(global::getBitmapSize(ArchiveID::EDITRES, MOON).x) - 1, + static_cast(global::getBitmapSize(ArchiveID::EDITRES, MOON).y) - 1), + BUTTON_STONE, nullptr, MOON); SubMenu->addButton(submenu1, CREATEWINDOW, Position(500, 10), Extent(130, 30), BUTTON_GREEN1, "Create window"); - picObject = SubMenu->addPicture(submenu1, PICOBJECT, Position(200, 30), MIS0BOBS_SHIP); + picObject = SubMenu->addPicture(submenu1, PICOBJECT, Position(200, 30), ArchiveID::MIS0BOBS, MIS0BOBS_SHIP); picObject->setMotionParams(PICOBJECTENTRY, PICOBJECTLEAVE); SubMenu->addText("Textblock", Position(400, 200), FontSize::Large); testTextfield = SubMenu->addTextfield(Position(400, 300), 10, 3); @@ -3149,7 +3094,7 @@ void callback::submenu1(int Param) case TOOSMALL: if(picIndex == -1) - picIndex = SubMenu->addStaticPicture(Position(0, 0), MAINFRAME_640_480); + picIndex = SubMenu->addStaticPicture(Position(0, 0), ArchiveID::EDITRES, MAINFRAME_640_480); break; case CREATEWINDOW: @@ -3161,8 +3106,8 @@ void callback::submenu1(int Param) testWindow->addText("Text inside the window", Position(10, 10), FontSize::Large); testWindow->addButton(submenu1, -10, Position(150, 100), Extent(210, 30), BUTTON_GREEN2, "Button inside the window"); - testWindowPicture = - testWindow->addPicture(submenu1, TESTWINDOWPICTURE, Position(10, 60), MIS2BOBS_FORTRESS); + testWindowPicture = testWindow->addPicture(submenu1, TESTWINDOWPICTURE, Position(10, 60), + ArchiveID::MIS2BOBS, MIS2BOBS_FORTRESS); testWindowPicture->setMotionParams(TESTWINDOWPICTUREENTRY, TESTWINDOWPICTURELEAVE); testTextfield_testWindow = testWindow->addTextfield(Position(130, 30), 10, 3, FontSize::Large, FontColor::Red, BUTTON_GREY, true); diff --git a/callbacks.h b/callbacks.h index 4eb9578..fee5926 100644 --- a/callbacks.h +++ b/callbacks.h @@ -36,7 +36,6 @@ void EditorCursorMenu(int Param); #ifdef _ADMINMODE void debugger(int Param); -void viewer(int Param); void submenu1(int Param); #endif } // namespace callback diff --git a/globals.cpp b/globals.cpp index da4edcf..ce98c72 100644 --- a/globals.cpp +++ b/globals.cpp @@ -4,14 +4,143 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "globals.h" -#include "defines.h" - -// array for all pictures -std::vector global::bmpArray(MAXBOBBMP); -// array for all shadows -std::vector global::shadowArray(MAXBOBSHADOW); -// array for all palettes -std::vector global::palArray(MAXBOBPAL); +#include +#include +#include +#include +#include +#include +#include + +// single archive for all loaded assets +// typed archive storage +std::map global::typedArchives; + +// currently active palette +const libsiedler2::ArchivItem_Palette* global::currentPalette = nullptr; + +bool global::loadArchive(ArchiveID archive, const boost::filesystem::path& filepath, + const libsiedler2::ArchivItem_Palette* palette) +{ + libsiedler2::Archiv tmp; + int ec = libsiedler2::Load(filepath, tmp, palette); + if(ec) + { + std::cerr << "loadArchive(" << static_cast(archive) << ") error for " << filepath << ": " + << libsiedler2::getErrorString(ec) << std::endl; + return false; + } + typedArchives[archive] = std::move(tmp); + return true; +} + +bool global::loadBitmapArchive(ArchiveID archive, const boost::filesystem::path& filepath, + const libsiedler2::ArchivItem_Palette* palette) +{ + libsiedler2::Archiv tmp; + int ec = libsiedler2::Load(filepath, tmp, palette); + if(ec) + { + std::cerr << "loadBitmapArchive(" << static_cast(archive) << ") error for " << filepath << ": " + << libsiedler2::getErrorString(ec) << std::endl; + return false; + } + + // Keep only bitmap-type items (skip nulls, shadows, palettes, fonts) + libsiedler2::Archiv filtered; + for(unsigned i = 0; i < tmp.size(); i++) + { + auto* item = tmp.get(i); + if(!item) + continue; + auto bt = item->getBobType(); + if(bt == libsiedler2::BobType::Bitmap || bt == libsiedler2::BobType::BitmapRLE + || bt == libsiedler2::BobType::Raw || bt == libsiedler2::BobType::BitmapPlayer) + { + filtered.push(std::unique_ptr(tmp.release(i).release())); + } + } + + typedArchives[archive] = std::move(filtered); + return true; +} + +bool global::loadPalette(const boost::filesystem::path& filepath) +{ + libsiedler2::Archiv tmp; + int ec = libsiedler2::Load(filepath, tmp, nullptr); + if(ec) + { + auto datPath = filepath; + datPath.replace_extension(".DAT"); + ec = libsiedler2::Load(datPath, tmp, nullptr); + } + if(ec || tmp.empty()) + { + std::cerr << "loadPalette error for " << filepath << ": " << (ec ? libsiedler2::getErrorString(ec) : "empty") + << std::endl; + return false; + } + currentPalette = dynamic_cast(tmp.get(0)); + if(!currentPalette) + { + std::cerr << "loadPalette: first item is not a palette in " << filepath << std::endl; + return false; + } + static libsiedler2::Archiv s_paletteStorage; + s_paletteStorage = std::move(tmp); + return true; +} + +Extent global::getBitmapSize(ArchiveID archive, unsigned index) +{ + auto& archiv = typedArchives[archive]; + if(index >= archiv.size()) + return {0u, 0u}; + auto* bmp = dynamic_cast(archiv.get(index)); + if(!bmp) + return {0u, 0u}; + return {bmp->getWidth(), bmp->getHeight()}; +} + +bool global::loadTileset(ArchiveID archive, int tsIdx, const boost::filesystem::path& filepath) +{ + // LBM files contain their own palette, so no external palette needed + libsiedler2::Archiv tmp; + int ec = libsiedler2::Load(filepath, tmp, nullptr); + if(ec || tmp.empty()) + { + std::cerr << "loadTileset(" << static_cast(archive) << ") error for " << filepath << ": " + << (ec ? libsiedler2::getErrorString(ec) : "empty") << std::endl; + return false; + } + + // Store in typed archive (index 0 = main bitmap, 1+ = palette animations) + auto& dest = typedArchives[archive]; + dest = std::move(tmp); + + // Extract palette animations into tilesetAnims[tsIdx] + auto& ta = tilesetAnims[tsIdx]; + ta.archive = archive; + ta.bmpIdx = 0; // index 0 within this archive = main bitmap + ta.anims.clear(); + ta.storage.clear(); + for(unsigned ai = 1; ai < dest.size(); ai++) + { + auto* anim = dynamic_cast(dest.get(ai)); + if(!anim) + continue; + // We need mutable pointers for the animation system; clone them + auto clone = std::unique_ptr(dest.release(ai).release()); + ta.anims.push_back(static_cast(clone.get())); + ta.storage.push_back(std::move(clone)); + } + + return true; +} + +// font archives loaded at startup +std::array global::tilesetAnims; // the game object CGame* global::s2; @@ -22,6 +151,3 @@ WorldDescription global::worldDesc; unsigned char triangleHeight = TRIANGLE_HEIGHT_DEFAULT; unsigned char triangleWidth = TRIANGLE_WIDTH_DEFAULT; unsigned char triangleIncrease = TRIANGLE_INCREASE_DEFAULT; - -// three-dimensional array for the GOUx.DAT-Files (3 files * 256 * 256 values) -Uint8 gouData[3][256][256]; diff --git a/globals.h b/globals.h index 5b4dbaf..0292a1c 100644 --- a/globals.h +++ b/globals.h @@ -5,23 +5,66 @@ #pragma once +#include "ArchiveID.h" +#include "Texture.h" #include "gameData/WorldDescription.h" +#include #include #include +#include +#include #include class CGame; -struct bobBMP; -struct bobSHADOW; -struct bobPAL; + +namespace libsiedler2 { +class ArchivItem_Palette; +class ArchivItem_PaletteAnimation; +class baseArchivItem_Bitmap; +struct ColorBGRA; +} // namespace libsiedler2 namespace global { -// array for all pictures -extern std::vector bmpArray; -// array for all shadows -extern std::vector shadowArray; -// array for all palettes -extern std::vector palArray; + +// ── Typed archive storage ───────────────────────────────────────────── +/// Per-ArchiveID archives, loaded and kept intact. +extern std::map typedArchives; + +/// Load a file into typedArchives[archive] using libsiedler2::Load directly. +/// Returns true on success. +bool loadArchive(ArchiveID archive, const boost::filesystem::path& filepath, + const libsiedler2::ArchivItem_Palette* palette = nullptr); + +/// Get the size of a bitmap from a typed archive. +Extent getBitmapSize(ArchiveID archive, unsigned index); + +/// Load a palette BBM file into currentPalette. Returns true on success. +bool loadPalette(const boost::filesystem::path& filepath); + +/// Load a file into typedArchives[archive], keeping only bitmap-type items +/// (Bitmap, BitmapRLE, Raw, BitmapPlayer), skipping nulls and other types. +/// Used for archives like MAP00.LST that contain non-bitmap items. +bool loadBitmapArchive(ArchiveID archive, const boost::filesystem::path& filepath, + const libsiedler2::ArchivItem_Palette* palette = nullptr); + +/// Load a terrain tileset (TEX5/6/7.LBM) into typedArchives and extract +/// palette animations into tilesetAnims[tsIdx]. The old flat-archive +/// path is NOT used — call this instead of CFile::open_file. +bool loadTileset(ArchiveID archive, int tsIdx, const boost::filesystem::path& filepath); + +// Palette animations per tileset (greenland=0, wasteland=1, winterland=2). +struct TilesetAnim +{ + ArchiveID archive = ArchiveID::EDITRES; // which archive contains the bitmap + unsigned bmpIdx = 0; // index of the tileset bitmap within the archive + std::vector anims; + std::vector> storage; // keeps animations alive +}; +extern std::array tilesetAnims; + +/// Currently active palette (loaded from PAL*.BBM). +extern const libsiedler2::ArchivItem_Palette* currentPalette; + // the game object extern CGame* s2; // Path to game data (must not be empty!) @@ -48,5 +91,3 @@ constexpr unsigned char ZOOM_STEP_INCREASE = 1; // Zoom boundaries (based on triangleIncrease) constexpr unsigned char ZOOM_INCREASE_MAX = 9; constexpr unsigned char ZOOM_INCREASE_MIN = 1; - -extern Uint8 gouData[3][256][256]; diff --git a/include/ArchiveID.h b/include/ArchiveID.h new file mode 100644 index 0000000..496f6e1 --- /dev/null +++ b/include/ArchiveID.h @@ -0,0 +1,66 @@ +// Copyright (C) 2026 - 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +/// Identifies a loaded resource archive. +/// Each value corresponds to one file (or group of related files) that is loaded +/// and kept as a separate libsiedler2::Archiv, keyed by this type. +enum class ArchiveID : uint8_t +{ + // ── Editor / UI archives ────────────────────────────────────────── + EDITBOB = 0, // DATA/EDITBOB.LST + EDITIO, // DATA/IO/EDITIO.IDX + EDITRES, // DATA/EDITRES.IDX (or RESOURCE.IDX/DAT) + + // ── Loading screens ─────────────────────────────────────────────── + SETUP997, + SETUP998, + SETUP000, + SETUP010, + SETUP011, + SETUP012, + SETUP013, + SETUP014, + SETUP015, + SETUP666, + SETUP667, + SETUP801, + SETUP802, + SETUP803, + SETUP804, + SETUP805, + SETUP806, + SETUP810, + SETUP811, + SETUP895, + SETUP896, + SETUP897, + SETUP898, + SETUP899, + SETUP990, + WORLD_LBM, + WORLDMSK_LBM, + + // ── Mission BOBs ────────────────────────────────────────────────── + MIS0BOBS, + MIS1BOBS, + MIS2BOBS, + MIS3BOBS, + MIS4BOBS, + MIS5BOBS, + + // ── Terrain tilesets (landscape-specific, one per landscape) ───── + TEX5, // GFX/TEXTURES/TEX5.LBM (greenland) + TEX6, // GFX/TEXTURES/TEX6.LBM (wasteland) + TEX7, // GFX/TEXTURES/TEX7.LBM (winterland) + + // ── Map object sprites (MAP00.LST) ─────────────────────────────── + MAP00, // DATA/MAP00.LST + + // ── Palettes (keyed separately) ─────────────────────────────────── + // (not in this enum — palettes have their own storage) +}; diff --git a/include/SdlSurface.h b/include/SdlSurface.h index 0275c12..fa716f4 100644 --- a/include/SdlSurface.h +++ b/include/SdlSurface.h @@ -1,50 +1,14 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks +// Copyright (C) 2009 - 2025 Settlers Freaks // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include -#include #include -struct SdlSurfaceDeleter -{ - void operator()(SDL_Surface* p) { SDL_FreeSurface(p); } -}; -struct SdlTextureDeleter -{ - void operator()(SDL_Texture* p) { SDL_DestroyTexture(p); } -}; struct SDLWindowDestroyer { void operator()(SDL_Window* p) const { SDL_DestroyWindow(p); } }; -struct SDLRendererDestroyer -{ - void operator()(SDL_Renderer* p) const { SDL_DestroyRenderer(p); } -}; - -using SdlRenderer = std::unique_ptr; using SdlWindow = std::unique_ptr; -using SdlSurface = std::unique_ptr; -using SdlTexture = std::unique_ptr; - -inline SdlSurface makeRGBSurface(unsigned width, unsigned height, bool withAlpha = false) -{ - return SdlSurface(SDL_CreateRGBSurface(0, static_cast(width), static_cast(height), 32, 0xFF0000, 0xFF00, - 0xFF, withAlpha ? 0xFF000000 : 0)); -} -inline SdlSurface makePalSurface(unsigned width, unsigned height, const std::array& palette) -{ - auto surf = SdlSurface(SDL_CreateRGBSurface(0, static_cast(width), static_cast(height), 8, 0, 0, 0, 0)); - if(surf) - SDL_SetPaletteColors(surf->format->palette, palette.data(), 0, palette.size()); - return surf; -} - -inline SdlTexture makeSdlTexture(const SdlRenderer& renderer, Uint32 format, int access, int w, int h) -{ - return SdlTexture(SDL_CreateTexture(renderer.get(), format, access, w, h)); -} diff --git a/include/defines.h b/include/defines.h index 39f3738..f00636f 100644 --- a/include/defines.h +++ b/include/defines.h @@ -7,7 +7,6 @@ #include "Point.h" #include "Rect.h" -#include "SdlSurface.h" #include "gameData/DescIdx.h" #include #include @@ -70,36 +69,14 @@ enum BBM, LBM, WLD, - SWD, - GOU + SWD }; -// Structure for Bobtypes 2 (RLE-Bitmaps), 4 (specific Bitmaps), 14 (uncompressed Bitmaps) -struct bobBMP -{ - Uint16 nx; - Uint16 ny; - Uint16 w; - Uint16 h; - Extent16 getSize() const { return {w, h}; } - SdlSurface surface; -}; - -// Structure for Bobtype 5 (Palette) -struct bobPAL -{ - std::array colors; -}; - -// Structure for Bobtype 7 (Shadow-Bitmaps) -struct bobSHADOW -{ - Uint16 nx; - Uint16 ny; - Uint16 w; - Uint16 h; - SdlSurface surface; -}; +// bobBMP, bobPAL, bobSHADOW replaced by libsiedler2 types +// bobBMP -> libsiedler2::ArchivItem_Bitmap +// bobPAL -> libsiedler2::ArchivItem_Palette +// bobSHADOW -> libsiedler2::ArchivItem_Bitmap_Shadow +// Use the helper functions declared in globals.h for access // Datatypes for the Map // vector structure @@ -271,119 +248,122 @@ enum PLAYER_RED_BRIGHT = 0x10 }; -// enumeration for BobtypeBMP (pics) -enum -{ - // BEGIN: /GFX/PICS/SETUP997.LBM - SPLASHSCREEN_LOADING_S2SCREEN = 0, - // END: /GFX/PICS/SETUP997.LBM +// BEGIN: /GFX/PICS/SETUP997.LBM +constexpr int SPLASHSCREEN_LOADING_S2SCREEN = 0; +// END: /GFX/PICS/SETUP997.LBM - // BEGIN: /GFX/PICS/SETUP000.LBM - SPLASHSCREEN_MAINMENU_BROWN, - // END: /GFX/PICS/SETUP000.LBM +// BEGIN: /GFX/PICS/SETUP000.LBM +constexpr int SPLASHSCREEN_MAINMENU_BROWN = 0; +// END: /GFX/PICS/SETUP000.LBM - // BEGIN: /GFX/PICS/SETUP010.LBM - SPLASHSCREEN_MAINMENU, - // END: /GFX/PICS/SETUP010.LBM +// BEGIN: /GFX/PICS/SETUP010.LBM +constexpr int SPLASHSCREEN_MAINMENU = 0; +// END: /GFX/PICS/SETUP010.LBM - // BEGIN: /GFX/PICS/SETUP011.LBM - SPLASHSCREEN_SUBMENU1, - // END: /GFX/PICS/SETUP011.LBM +// BEGIN: /GFX/PICS/SETUP011.LBM +constexpr int SPLASHSCREEN_SUBMENU1 = 0; +// END: /GFX/PICS/SETUP011.LBM - // BEGIN: /GFX/PICS/SETUP012.LBM - SPLASHSCREEN_SUBMENU2, - // END: /GFX/PICS/SETUP012.LBM +// BEGIN: /GFX/PICS/SETUP012.LBM +constexpr int SPLASHSCREEN_SUBMENU2 = 0; +// END: /GFX/PICS/SETUP012.LBM - // BEGIN: /GFX/PICS/SETUP013.LBM - SPLASHSCREEN_SUBMENU3, - // END: /GFX/PICS/SETUP013.LBM +// BEGIN: /GFX/PICS/SETUP013.LBM +constexpr int SPLASHSCREEN_SUBMENU3 = 0; +// END: /GFX/PICS/SETUP013.LBM - // BEGIN: /GFX/PICS/SETUP014.LBM - SPLASHSCREEN_SUBMENU4, - // END: /GFX/PICS/SETUP014.LBM +// BEGIN: /GFX/PICS/SETUP014.LBM +constexpr int SPLASHSCREEN_SUBMENU4 = 0; +// END: /GFX/PICS/SETUP014.LBM - // BEGIN: /GFX/PICS/SETUP015.LBM - SPLASHSCREEN_SUBMENU5, - // END: /GFX/PICS/SETUP015.LBM +// BEGIN: /GFX/PICS/SETUP015.LBM +constexpr int SPLASHSCREEN_SUBMENU5 = 0; +// END: /GFX/PICS/SETUP015.LBM - // BEGIN: /GFX/PICS/SETUP666.LBM - SPLASHSCREEN_UNIVERSE1, - // END: /GFX/PICS/SETUP666.LBM +// BEGIN: /GFX/PICS/SETUP666.LBM +constexpr int SPLASHSCREEN_UNIVERSE1 = 0; +// END: /GFX/PICS/SETUP666.LBM - // BEGIN: /GFX/PICS/SETUP667.LBM - SPLASHSCREEN_SUN1, - // END: /GFX/PICS/SETUP667.LBM +// BEGIN: /GFX/PICS/SETUP667.LBM +constexpr int SPLASHSCREEN_SUN1 = 0; +// END: /GFX/PICS/SETUP667.LBM - // BEGIN: /GFX/PICS/SETUP801.LBM - SPLASHSCREEN_SETUP801, - // END: /GFX/PICS/SETUP801.LBM +// BEGIN: /GFX/PICS/SETUP801.LBM +constexpr int SPLASHSCREEN_SETUP801 = 0; +// END: /GFX/PICS/SETUP801.LBM - // BEGIN: /GFX/PICS/SETUP802.LBM - SPLASHSCREEN_LOADING_STANDARD, - // END: /GFX/PICS/SETUP802.LBM +// BEGIN: /GFX/PICS/SETUP802.LBM +constexpr int SPLASHSCREEN_LOADING_STANDARD = 0; +// END: /GFX/PICS/SETUP802.LBM - // BEGIN: /GFX/PICS/SETUP803.LBM - SPLASHSCREEN_LOADING_GREENLAND1, - // END: /GFX/PICS/SETUP803.LBM +// BEGIN: /GFX/PICS/SETUP803.LBM +constexpr int SPLASHSCREEN_LOADING_GREENLAND1 = 0; +// END: /GFX/PICS/SETUP803.LBM - // BEGIN: /GFX/PICS/SETUP804.LBM - SPLASHSCREEN_LOADING_WASTELAND, - // END: /GFX/PICS/SETUP804.LBM +// BEGIN: /GFX/PICS/SETUP804.LBM +constexpr int SPLASHSCREEN_LOADING_WASTELAND = 0; +// END: /GFX/PICS/SETUP804.LBM - // BEGIN: /GFX/PICS/SETUP805.LBM - SPLASHSCREEN_LOADING_GREENLAND2, - // END: /GFX/PICS/SETUP805.LBM +// BEGIN: /GFX/PICS/SETUP805.LBM +constexpr int SPLASHSCREEN_LOADING_GREENLAND2 = 0; +// END: /GFX/PICS/SETUP805.LBM - // BEGIN: /GFX/PICS/SETUP806.LBM - SPLASHSCREEN_LOADING_GREENLAND3, - // END: /GFX/PICS/SETUP806.LBM +// BEGIN: /GFX/PICS/SETUP806.LBM +constexpr int SPLASHSCREEN_LOADING_GREENLAND3 = 0; +// END: /GFX/PICS/SETUP806.LBM - // BEGIN: /GFX/PICS/SETUP810.LBM - SPLASHSCREEN_LOADING_WINTER1, - // END: /GFX/PICS/SETUP810.LBM +// BEGIN: /GFX/PICS/SETUP810.LBM +constexpr int SPLASHSCREEN_LOADING_WINTER1 = 0; +// END: /GFX/PICS/SETUP810.LBM - // BEGIN: /GFX/PICS/SETUP811.LBM - SPLASHSCREEN_LOADING_WINTER2, - // END: /GFX/PICS/SETUP811.LBM +// BEGIN: /GFX/PICS/SETUP811.LBM +constexpr int SPLASHSCREEN_LOADING_WINTER2 = 0; +// END: /GFX/PICS/SETUP811.LBM - // BEGIN: /GFX/PICS/SETUP895.LBM - SPLASHSCREEN_LOADING_SETUP895, - // END: /GFX/PICS/SETUP895.LBM +// BEGIN: /GFX/PICS/SETUP895.LBM +constexpr int SPLASHSCREEN_LOADING_SETUP895 = 0; +// END: /GFX/PICS/SETUP895.LBM - // BEGIN: /GFX/PICS/SETUP896.LBM - SPLASHSCREEN_LOADING_ROMANCAMPAIGN1, - // END: /GFX/PICS/SETUP896.LBM +// BEGIN: /GFX/PICS/SETUP896.LBM +constexpr int SPLASHSCREEN_LOADING_ROMANCAMPAIGN1 = 0; +// END: /GFX/PICS/SETUP896.LBM - // BEGIN: /GFX/PICS/SETUP897.LBM - SPLASHSCREEN_LOADING_ROMANCAMPAIGN2, - // END: /GFX/PICS/SETUP897.LBM +// BEGIN: /GFX/PICS/SETUP897.LBM +constexpr int SPLASHSCREEN_LOADING_ROMANCAMPAIGN2 = 0; +// END: /GFX/PICS/SETUP897.LBM - // BEGIN: /GFX/PICS/SETUP898.LBM - SPLASHSCREEN_LOADING_ROMANCAMPAIGN3, - // END: /GFX/PICS/SETUP898.LBM +// BEGIN: /GFX/PICS/SETUP898.LBM +constexpr int SPLASHSCREEN_LOADING_ROMANCAMPAIGN3 = 0; +// END: /GFX/PICS/SETUP898.LBM - // BEGIN: /GFX/PICS/SETUP899.LBM - SPLASHSCREEN_LOADING_ROMANCAMPAIGN_GREY, - // END: /GFX/PICS/SETUP899.LBM +// BEGIN: /GFX/PICS/SETUP899.LBM +constexpr int SPLASHSCREEN_LOADING_ROMANCAMPAIGN_GREY = 0; +// END: /GFX/PICS/SETUP899.LBM - // BEGIN: /GFX/PICS/SETUP990.LBM - SPLASHSCREEN_SETUP990, - // END: /GFX/PICS/SETUP990.LBM +// BEGIN: /GFX/PICS/SETUP990.LBM +constexpr int SPLASHSCREEN_SETUP990 = 0; +// END: /GFX/PICS/SETUP990.LBM - // BEGIN: /GFX/PICS/WORLD.LBM - SPLASHSCREEN_WORLDCAMPAIGN, - // END: /GFX/PICS/WORLD.LBM +// BEGIN: /GFX/PICS/WORLD.LBM +constexpr int SPLASHSCREEN_WORLDCAMPAIGN = 0; +// END: /GFX/PICS/WORLD.LBM - // BEGIN: /GFX/PICS/WORLDMSK.LBM - SPLASHSCREEN_WORLDCAMPAIGN_SECTIONS, - // END: /GFX/PICS/WORLDMSK.LBM +// BEGIN: /GFX/PICS/WORLDMSK.LBM +constexpr int SPLASHSCREEN_WORLDCAMPAIGN_SECTIONS = 0; +// END: /GFX/PICS/WORLDMSK.LBM - // BEGIN: /DATA/RESOURCE.IDX (AND /DATA/RESOURCE.DAT) OR /DATA/EDITRES.IDX (AND /DATA/EDITRES.DAT) - // BEGIN: FONT +// BEGIN: /DATA/RESOURCE.IDX (AND /DATA/RESOURCE.DAT) OR /DATA/EDITRES.IDX (AND /DATA/EDITRES.DAT) +// (bitmap section only — fonts are in the standalone FontIndices enum below) +// BEGIN: FONT - /// IMPORTANT: BECAUSE OF MULTIPLE COLORS FOR EACH CHARACTER THIS FONT-ENUMERATION IS NO LONGER CONSISTENT. - /// ONLY THE START-VALUES (FONT9_SPACE, FONT11_SPACE, FONT14_SPACE) HAVE THE RIGHT INDEX! +/// IMPORTANT: BECAUSE OF MULTIPLE COLORS FOR EACH CHARACTER THIS FONT-ENUMERATION IS NO LONGER CONSISTENT. +/// ONLY THE START-VALUES (FONT9_SPACE, FONT11_SPACE, FONT14_SPACE) HAVE THE RIGHT INDEX! +// ── Font glyph indices (documentation of S2 font file format) ───────── +// Fonts live in typedArchives[ArchiveID::EDITRES] and are read directly +// by CFont through findFont(). These constants are for reference only. +enum +{ // fontsize 11 FONT11_SPACE, // spacebar FONT11_EXCLAMATION_POINT, // ! @@ -733,366 +713,377 @@ enum FONT14_ANSI_223, // ß FONT14_ANSI_169, // © // END: FONT - - // now the main resources will follow (frames, cursor, ...) - // resolution behind means not resolution of the pic but window resolution the pic belongs to - MAINFRAME_640_480 = 2441, - SPLITFRAME_LEFT_640_480, - SPLITFRAME_RIGHT_640_480, - MAINFRAME_800_600, - SPLITFRAME_LEFT_800_600, - SPLITFRAME_RIGHT_800_600, - MAINFRAME_1024_768, - SPLITFRAME_LEFT_1024_768, - SPLITFRAME_RIGHT_1024_768, - MAINFRAME_LEFT_1280_1024, - MAINFRAME_RIGHT_1280_1024, - SPLITFRAME_LEFT_1280_1024, - SPLITFRAME_RIGHT_1280_1024, - STATUE_UP_LEFT, - STATUE_UP_RIGHT, - STATUE_DOWN_LEFT, - STATUE_DOWN_RIGHT, - SPLITFRAME_ADDITIONAL_LEFT_640_480, - SPLITFRAME_ADDITIONAL_RIGHT_640_480, - SPLITFRAME_ADDITIONAL_LEFT_800_600, - SPLITFRAME_ADDITIONAL_RIGHT_800_600, - SPLITFRAME_ADDITIONAL_LEFT_1024_768, - SPLITFRAME_ADDITIONAL_RIGHT_1024_768, - SPLITFRAME_ADDITIONAL_LEFT_1280_1024, - SPLITFRAME_ADDITIONAL_RIGHT_1280_1024, - MENUBAR, - CURSOR, - CURSOR_CLICKED, - CROSS, - MOON, - CIRCLE_HIGH_GREY, - CIRCLE_FLAT_GREY, - WINDOW_LEFT_UPPER_CORNER, - WINDOW_RIGHT_UPPER_CORNER, - WINDOW_LEFT_FRAME, - WINDOW_RIGHT_FRAME, - WINDOW_LOWER_FRAME, - WINDOW_BACKGROUND, - WINDOW_UPPER_FRAME, - WINDOW_UPPER_FRAME_MARKED, - WINDOW_UPPER_FRAME_CLICKED, - WINDOW_CORNER_RECTANGLE, - WINDOW_BUTTON_RESIZE, - WINDOW_BUTTON_CLOSE, - WINDOW_BUTTON_MINIMIZE, - WINDOW_CORNER_RECTANGLE_2, // unknown function - WINDOW_BUTTON_RESIZE_CLICKED, - WINDOW_BUTTON_CLOSE_CLICKED, - WINDOW_BUTTON_MINIMIZE_CLICKED, - WINDOW_CORNER_RECTANGLE_3, // unknown function - WINDOW_BUTTON_RESIZE_MARKED, - WINDOW_BUTTON_CLOSE_MARKED, - WINDOW_BUTTON_MINIMIZE_MARKED, - // END: /DATA/RESOURCE.IDX (AND /DATA/RESOURCE.DAT) OR /DATA/EDITRES.IDX (AND /DATA/EDITRES.DAT) - - // BEGIN: /DATA/IO/EDITIO.IDX (AND /DATA/IO/EDITIO.DAT) - BUTTON_GREY_BRIGHT, - BUTTON_GREY_DARK, - BUTTON_RED1_BRIGHT, - BUTTON_RED1_DARK, - BUTTON_GREEN1_BRIGHT, - BUTTON_GREEN1_DARK, - BUTTON_GREEN2_BRIGHT, - BUTTON_GREEN2_DARK, - BUTTON_RED2_BRIGHT, - BUTTON_RED2_DARK, - BUTTON_STONE_BRIGHT, - BUTTON_STONE_DARK, - BUTTON_GREY_BACKGROUND, - BUTTON_RED1_BACKGROUND, - BUTTON_GREEN1_BACKGROUND, - BUTTON_GREEN2_BACKGROUND, - BUTTON_RED2_BACKGROUND, - BUTTON_STONE_BACKGROUND, - MENUBAR_BUILDHELP, - PICTURE_SHOW_POLITICAL_EDGES, - CIRCLE_BANG, - MENUBAR_BUGKILL, - PICTURE_SMALL_ARROW_UP, - PICTURE_SMALL_ARROW_DOWN, - PICTURE_SMALL_CIRCLE, - PICTURE_TROWEL, - MENUBAR_COMPUTER, - MENUBAR_LOUPE, - PICTURE_SMALL_TICK, - PICTURE_SMALL_CROSS, - MENUBAR_MINIMAP, - PICTURE_SMALL_ARROW_LEFT, - PICTURE_SMALL_ARROW_RIGHT, - PICTURE_LETTER_I, - PICTURE_GREENLAND_TEXTURE_SNOW, - PICTURE_GREENLAND_TEXTURE_STEPPE, - PICTURE_GREENLAND_TEXTURE_SWAMP, - PICTURE_GREENLAND_TEXTURE_FLOWER, - PICTURE_GREENLAND_TEXTURE_MINING1, - PICTURE_GREENLAND_TEXTURE_MINING2, - PICTURE_GREENLAND_TEXTURE_MINING3, - PICTURE_GREENLAND_TEXTURE_MINING4, - PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW1, - PICTURE_GREENLAND_TEXTURE_MEADOW1, - PICTURE_GREENLAND_TEXTURE_MEADOW2, - PICTURE_GREENLAND_TEXTURE_MEADOW3, - PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW2, - PICTURE_GREENLAND_TEXTURE_MINING_MEADOW, - PICTURE_GREENLAND_TEXTURE_WATER, - PICTURE_GREENLAND_TEXTURE_LAVA, - PICTURE_GREENLAND_TEXTURE_MEADOW_MIXED, - PICTURE_WASTELAND_TEXTURE_SNOW, - PICTURE_WASTELAND_TEXTURE_STEPPE, - PICTURE_WASTELAND_TEXTURE_SWAMP, - PICTURE_WASTELAND_TEXTURE_FLOWER, - PICTURE_WASTELAND_TEXTURE_MINING1, - PICTURE_WASTELAND_TEXTURE_MINING2, - PICTURE_WASTELAND_TEXTURE_MINING3, - PICTURE_WASTELAND_TEXTURE_MINING4, - PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW1, - PICTURE_WASTELAND_TEXTURE_MEADOW1, - PICTURE_WASTELAND_TEXTURE_MEADOW2, - PICTURE_WASTELAND_TEXTURE_MEADOW3, - PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW2, - PICTURE_WASTELAND_TEXTURE_MINING_MEADOW, - PICTURE_WASTELAND_TEXTURE_WATER, - PICTURE_WASTELAND_TEXTURE_LAVA, - PICTURE_WINTERLAND_TEXTURE_SNOW, - PICTURE_WINTERLAND_TEXTURE_STEPPE, - PICTURE_WINTERLAND_TEXTURE_SWAMP, - PICTURE_WINTERLAND_TEXTURE_FLOWER, - PICTURE_WINTERLAND_TEXTURE_MINING1, - PICTURE_WINTERLAND_TEXTURE_MINING2, - PICTURE_WINTERLAND_TEXTURE_MINING3, - PICTURE_WINTERLAND_TEXTURE_MINING4, - PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW1, - PICTURE_WINTERLAND_TEXTURE_MEADOW1, - PICTURE_WINTERLAND_TEXTURE_MEADOW2, - PICTURE_WINTERLAND_TEXTURE_MEADOW3, - PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW2, - PICTURE_WINTERLAND_TEXTURE_MINING_MEADOW, - PICTURE_WINTERLAND_TEXTURE_WATER, - PICTURE_WINTERLAND_TEXTURE_LAVA, - PICTURE_WINTERLAND_TEXTURE_MEADOW_MIXED, - PICTURE_TREE_CYPRESS, - PICTURE_TREE_PINE, - PICTURE_TREE_PALM2, - PICTURE_TREE_PINEAPPLE, - PICTURE_TREE_FIR, - PICTURE_TREE_OAK, - PICTURE_TREE_BIRCH, - PICTURE_TREE_CHERRY, - PICTURE_TREE_PALM1, - PICTURE_TREE_FLAPHAT, - PICTURE_TREE_SPIDER, - PICTURE_TREE_WOOD_MIXED, - PICTURE_TREE_PALM_MIXED, - PICTURE_SQUARE_CIRCLE1, - PICTURE_SQUARE_CIRCLE2, - PICTURE_SQUARE_CIRCLE3, - PICTURE_SQUARE_CIRCLE4, - PICTURE_RESOURCE_GOLD, - PICTURE_RESOURCE_ORE, - PICTURE_RESOURCE_COAL, - PICTURE_RESOURCE_GRANITE, - // some bobtype 14 pictures missing here - MENUBAR_TREE = 538 + 2069, - MENUBAR_RESOURCE, - MENUBAR_TEXTURE, - MENUBAR_HEIGHT, - MENUBAR_PLAYER, - MENUBAR_LANDSCAPE, - MENUBAR_ANIMAL, - MENUBAR_NEWWORLD, - PICTURE_EYE_CROSS, - MENUBAR_COMPUTER_DOUBLE_ENTRY, - // some bobtype 14 pictures missing here - PICTURE_LANDSCAPE_GRANITE = MENUBAR_COMPUTER_DOUBLE_ENTRY + 4, - PICTURE_LANDSCAPE_TREE_DEAD, - PICTURE_LANDSCAPE_STONE, - PICTURE_LANDSCAPE_CACTUS, - PICTURE_LANDSCAPE_PEBBLE, - PICTURE_LANDSCAPE_BUSH, - PICTURE_LANDSCAPE_SHRUB, - PICTURE_LANDSCAPE_BONE, - PICTURE_LANDSCAPE_MUSHROOM, - PICTURE_LANDSCAPE_STALAGMITE, - PICTURE_LANDSCAPE_GRANITE_WINTER, - PICTURE_LANDSCAPE_TREE_DEAD_WINTER, - PICTURE_LANDSCAPE_STONE_WINTER, - PICTURE_LANDSCAPE_PEBBLE_WINTER, - PICTURE_LANDSCAPE_BONE_WINTER, - PICTURE_LANDSCAPE_MUSHROOM_WINTER, - PICTURE_ANIMAL_BEAR, - PICTURE_ANIMAL_RABBIT, - PICTURE_ANIMAL_FOX, - PICTURE_ANIMAL_STAG, - PICTURE_ANIMAL_ROE, - PICTURE_ANIMAL_DUCK, - PICTURE_ANIMAL_SHEEP, - // END: /DATA/IO/EDITIO.IDX (AND /DATA/IO/EDITIO.DAT) - - // BEGIN: /DATA/EDITBOB.LST - CURSOR_SYMBOL_SCISSORS, - CURSOR_SYMBOL_TREE, - CURSOR_SYMBOL_ARROW_UP, - CURSOR_SYMBOL_ARROW_DOWN, - CURSOR_SYMBOL_TEXTURE, - CURSOR_SYMBOL_LANDSCAPE, - CURSOR_SYMBOL_FLAG, - CURSOR_SYMBOL_PICKAXE_MINUS, - CURSOR_SYMBOL_PICKAXE_PLUS, - CURSOR_SYMBOL_ANIMAL, - FLAG_BLUE_DARK, - FLAG_YELLOW, - FLAG_RED, - FLAG_BLUE_BRIGHT, - FLAG_GREEN_DARK, - FLAG_GREEN_BRIGHT, - FLAG_ORANGE, - PICTURE_SMALL_BEAR, - PICTURE_SMALL_RABBIT, - PICTURE_SMALL_FOX, - PICTURE_SMALL_STAG, - PICTURE_SMALL_DEER, - PICTURE_SMALL_DUCK, - PICTURE_SMALL_SHEEP, - // END: /DATA/EDITBOB.LST - - // BEGIN: /GFX/TEXTURES/TEX5.LBM - TILESET_GREENLAND, - // END: /GFX/TEXTURES/TEX5.LBM - - // BEGIN: /GFX/TEXTURES/TEX6.LBM - TILESET_WASTELAND, - // END: /GFX/TEXTURES/TEX6.LBM - - // BEGIN: /GFX/TEXTURES/TEX7.LBM - TILESET_WINTERLAND, - // END: /GFX/TEXTURES/TEX7.LBM - - // BEGIN: /DATA/MIS*BOBS.LST * = 0,1,2,3,4,5 - MIS0BOBS_SHIP, - MIS0BOBS_TENT, - MIS1BOBS_STONE1, - MIS1BOBS_STONE2, - MIS1BOBS_STONE3, - MIS1BOBS_STONE4, - MIS1BOBS_STONE5, - MIS1BOBS_STONE6, - MIS1BOBS_STONE7, - MIS1BOBS_TREE1, - MIS1BOBS_TREE2, - MIS1BOBS_SKELETON, - MIS2BOBS_TENT, - MIS2BOBS_GUARDHOUSE, - MIS2BOBS_GUARDTOWER, - MIS2BOBS_FORTRESS, - MIS2BOBS_PUPPY, - MIS3BOBS_VIKING, - MIS4BOBS_SCROLLS, - MIS5BOBS_SKELETON1, - MIS5BOBS_SKELETON2, - MIS5BOBS_CAVE, - MIS5BOBS_VIKING, - // END: /DATA/MIS*BOBS.LST - - // BEGIN: /DATA/MAP00.LST (ONLY IF A MAP IS ACTIVE) - MAPPIC_ARROWCROSS_YELLOW, - MAPPIC_CIRCLE_YELLOW, - MAPPIC_ARROWCROSS_RED, - MAPPIC_ARROWCROSS_ORANGE, - MAPPIC_ARROWCROSS_RED_FLAG, - MAPPIC_ARROWCROSS_RED_MINE, - MAPPIC_ARROWCROSS_RED_HOUSE_SMALL, - MAPPIC_ARROWCROSS_RED_HOUSE_MIDDLE, - MAPPIC_ARROWCROSS_RED_HOUSE_BIG, - MAPPIC_ARROWCROSS_RED_HOUSE_HARBOUR, - MAPPIC_PAPER_RED_CROSS, - MAPPIC_FLAG, - MAPPIC_HOUSE_SMALL, - MAPPIC_HOUSE_MIDDLE, - MAPPIC_HOUSE_BIG, - MAPPIC_MINE, - MAPPIC_HOUSE_HARBOUR, - // some pictures missing here - MAPPIC_TREE_PINE = MAPPIC_HOUSE_HARBOUR + 10, - MAPPIC_TREE_BIRCH = MAPPIC_TREE_PINE + 15, - MAPPIC_TREE_OAK = MAPPIC_TREE_PINE + 30, - MAPPIC_TREE_PALM1 = MAPPIC_TREE_PINE + 45, - MAPPIC_TREE_PALM2 = MAPPIC_TREE_PINE + 60, - MAPPIC_TREE_PINEAPPLE = MAPPIC_TREE_PINE + 75, - MAPPIC_TREE_CYPRESS = MAPPIC_TREE_PINE + 83, - MAPPIC_TREE_CHERRY = MAPPIC_TREE_PINE + 98, - MAPPIC_TREE_FIR = MAPPIC_TREE_PINE + 113, - MAPPIC_MUSHROOM1 = MAPPIC_TREE_FIR + 15, - MAPPIC_MUSHROOM2, - MAPPIC_STONE1, - MAPPIC_STONE2, - MAPPIC_STONE3, - MAPPIC_TREE_TRUNK_DEAD, - MAPPIC_TREE_DEAD, - MAPPIC_BONE1, - MAPPIC_BONE2, - MAPPIC_FLOWERS, - MAPPIC_BUSH1, - MAPPIC_ROCK4, - MAPPIC_CACTUS1, - MAPPIC_CACTUS2, - MAPPIC_SHRUB1, - MAPPIC_SHRUB2, - MAPPIC_GRANITE_1_1, - MAPPIC_GRANITE_1_2, - MAPPIC_GRANITE_1_3, - MAPPIC_GRANITE_1_4, - MAPPIC_GRANITE_1_5, - MAPPIC_GRANITE_1_6, - MAPPIC_GRANITE_2_1, - MAPPIC_GRANITE_2_2, - MAPPIC_GRANITE_2_3, - MAPPIC_GRANITE_2_4, - MAPPIC_GRANITE_2_5, - MAPPIC_GRANITE_2_6, - MAPPIC_UNKNOWN_PICTURE, - MAPPIC_FIELD_1_1, - MAPPIC_FIELD_1_2, - MAPPIC_FIELD_1_3, - MAPPIC_FIELD_1_4, - MAPPIC_FIELD_1_5, - MAPPIC_FIELD_2_1, - MAPPIC_FIELD_2_2, - MAPPIC_FIELD_2_3, - MAPPIC_FIELD_2_4, - MAPPIC_FIELD_2_5, - MAPPIC_BUSH2, - MAPPIC_BUSH3, - MAPPIC_BUSH4, - MAPPIC_SHRUB3, - MAPPIC_SHRUB4, - MAPPIC_BONE3, - MAPPIC_BONE4, - MAPPIC_MUSHROOM3, - MAPPIC_STONE4, - MAPPIC_STONE5, - MAPPIC_PEBBLE1, - MAPPIC_PEBBLE2, - MAPPIC_PEBBLE3, - MAPPIC_SHRUB5, - MAPPIC_SHRUB6, - MAPPIC_SHRUB7, - MAPPIC_SNOWMAN, - MAPPIC_DOOR, - // some pictures missing here - MAPPIC_LAST_ENTRY = 1432 + 2070 - // END: /DATA/MAP00.LST }; -// enumeration for BobtypeSHADOW (shadows for the pics) +// now the main resources will follow (frames, cursor, ...) +// resolution behind means not resolution of the pic but window resolution the pic belongs to +constexpr int MAINFRAME_640_480 = 4; +constexpr int SPLITFRAME_LEFT_640_480 = 5; +constexpr int SPLITFRAME_RIGHT_640_480 = 6; +constexpr int MAINFRAME_800_600 = 7; +constexpr int SPLITFRAME_LEFT_800_600 = 8; +constexpr int SPLITFRAME_RIGHT_800_600 = 9; +constexpr int MAINFRAME_1024_768 = 10; +constexpr int SPLITFRAME_LEFT_1024_768 = 11; +constexpr int SPLITFRAME_RIGHT_1024_768 = 12; +constexpr int MAINFRAME_LEFT_1280_1024 = 13; +constexpr int MAINFRAME_RIGHT_1280_1024 = 14; +constexpr int SPLITFRAME_LEFT_1280_1024 = 15; +constexpr int SPLITFRAME_RIGHT_1280_1024 = 16; +constexpr int STATUE_UP_LEFT = 17; +constexpr int STATUE_UP_RIGHT = 18; +constexpr int STATUE_DOWN_LEFT = 19; +constexpr int STATUE_DOWN_RIGHT = 20; +constexpr int SPLITFRAME_ADDITIONAL_LEFT_640_480 = 21; +constexpr int SPLITFRAME_ADDITIONAL_RIGHT_640_480 = 22; +constexpr int SPLITFRAME_ADDITIONAL_LEFT_800_600 = 23; +constexpr int SPLITFRAME_ADDITIONAL_RIGHT_800_600 = 24; +constexpr int SPLITFRAME_ADDITIONAL_LEFT_1024_768 = 25; +constexpr int SPLITFRAME_ADDITIONAL_RIGHT_1024_768 = 26; +constexpr int SPLITFRAME_ADDITIONAL_LEFT_1280_1024 = 27; +constexpr int SPLITFRAME_ADDITIONAL_RIGHT_1280_1024 = 28; +constexpr int MENUBAR = 29; +constexpr int CURSOR = 30; +constexpr int CURSOR_CLICKED = 31; +constexpr int CROSS = 32; +constexpr int MOON = 33; +constexpr int CIRCLE_HIGH_GREY = 34; +constexpr int CIRCLE_FLAT_GREY = 35; +constexpr int WINDOW_LEFT_UPPER_CORNER = 36; +constexpr int WINDOW_RIGHT_UPPER_CORNER = 37; +constexpr int WINDOW_LEFT_FRAME = 38; +constexpr int WINDOW_RIGHT_FRAME = 39; +constexpr int WINDOW_LOWER_FRAME = 40; +constexpr int WINDOW_BACKGROUND = 41; +constexpr int WINDOW_UPPER_FRAME = 42; +constexpr int WINDOW_UPPER_FRAME_MARKED = 43; +constexpr int WINDOW_UPPER_FRAME_CLICKED = 44; +constexpr int WINDOW_CORNER_RECTANGLE = 45; +constexpr int WINDOW_BUTTON_RESIZE = 46; +constexpr int WINDOW_BUTTON_CLOSE = 47; +constexpr int WINDOW_BUTTON_MINIMIZE = 48; +constexpr int WINDOW_CORNER_RECTANGLE_2 = 49; +constexpr int WINDOW_BUTTON_RESIZE_CLICKED = 50; +constexpr int WINDOW_BUTTON_CLOSE_CLICKED = 51; +constexpr int WINDOW_BUTTON_MINIMIZE_CLICKED = 52; +constexpr int WINDOW_CORNER_RECTANGLE_3 = 53; +constexpr int WINDOW_BUTTON_RESIZE_MARKED = 54; +constexpr int WINDOW_BUTTON_CLOSE_MARKED = 55; +constexpr int WINDOW_BUTTON_MINIMIZE_MARKED = 56; +// END: /DATA/RESOURCE.IDX (AND /DATA/RESOURCE.DAT) OR /DATA/EDITRES.IDX (AND /DATA/EDITRES.DAT) + +// BEGIN: /DATA/IO/EDITIO.IDX (AND /DATA/IO/EDITIO.DAT) +constexpr int BUTTON_GREY_BRIGHT = 0; +constexpr int BUTTON_GREY_DARK = 1; +constexpr int BUTTON_RED1_BRIGHT = 2; +constexpr int BUTTON_RED1_DARK = 3; +constexpr int BUTTON_GREEN1_BRIGHT = 4; +constexpr int BUTTON_GREEN1_DARK = 5; +constexpr int BUTTON_GREEN2_BRIGHT = 6; +constexpr int BUTTON_GREEN2_DARK = 7; +constexpr int BUTTON_RED2_BRIGHT = 8; +constexpr int BUTTON_RED2_DARK = 9; +constexpr int BUTTON_STONE_BRIGHT = 10; +constexpr int BUTTON_STONE_DARK = 11; +constexpr int BUTTON_GREY_BACKGROUND = 12; +constexpr int BUTTON_RED1_BACKGROUND = 13; +constexpr int BUTTON_GREEN1_BACKGROUND = 14; +constexpr int BUTTON_GREEN2_BACKGROUND = 15; +constexpr int BUTTON_RED2_BACKGROUND = 16; +constexpr int BUTTON_STONE_BACKGROUND = 17; +constexpr int MENUBAR_BUILDHELP = 18; +constexpr int PICTURE_SHOW_POLITICAL_EDGES = 19; +constexpr int CIRCLE_BANG = 20; +constexpr int MENUBAR_BUGKILL = 21; +constexpr int PICTURE_SMALL_ARROW_UP = 22; +constexpr int PICTURE_SMALL_ARROW_DOWN = 23; +constexpr int PICTURE_SMALL_CIRCLE = 24; +constexpr int PICTURE_TROWEL = 25; +constexpr int MENUBAR_COMPUTER = 26; +constexpr int MENUBAR_LOUPE = 27; +constexpr int PICTURE_SMALL_TICK = 28; +constexpr int PICTURE_SMALL_CROSS = 29; +constexpr int MENUBAR_MINIMAP = 30; +constexpr int PICTURE_SMALL_ARROW_LEFT = 31; +constexpr int PICTURE_SMALL_ARROW_RIGHT = 32; +constexpr int PICTURE_LETTER_I = 33; +constexpr int PICTURE_GREENLAND_TEXTURE_SNOW = 34; +constexpr int PICTURE_GREENLAND_TEXTURE_STEPPE = 35; +constexpr int PICTURE_GREENLAND_TEXTURE_SWAMP = 36; +constexpr int PICTURE_GREENLAND_TEXTURE_FLOWER = 37; +constexpr int PICTURE_GREENLAND_TEXTURE_MINING1 = 38; +constexpr int PICTURE_GREENLAND_TEXTURE_MINING2 = 39; +constexpr int PICTURE_GREENLAND_TEXTURE_MINING3 = 40; +constexpr int PICTURE_GREENLAND_TEXTURE_MINING4 = 41; +constexpr int PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW1 = 42; +constexpr int PICTURE_GREENLAND_TEXTURE_MEADOW1 = 43; +constexpr int PICTURE_GREENLAND_TEXTURE_MEADOW2 = 44; +constexpr int PICTURE_GREENLAND_TEXTURE_MEADOW3 = 45; +constexpr int PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW2 = 46; +constexpr int PICTURE_GREENLAND_TEXTURE_MINING_MEADOW = 47; +constexpr int PICTURE_GREENLAND_TEXTURE_WATER = 48; +constexpr int PICTURE_GREENLAND_TEXTURE_LAVA = 49; +constexpr int PICTURE_GREENLAND_TEXTURE_MEADOW_MIXED = 50; +constexpr int PICTURE_WASTELAND_TEXTURE_SNOW = 51; +constexpr int PICTURE_WASTELAND_TEXTURE_STEPPE = 52; +constexpr int PICTURE_WASTELAND_TEXTURE_SWAMP = 53; +constexpr int PICTURE_WASTELAND_TEXTURE_FLOWER = 54; +constexpr int PICTURE_WASTELAND_TEXTURE_MINING1 = 55; +constexpr int PICTURE_WASTELAND_TEXTURE_MINING2 = 56; +constexpr int PICTURE_WASTELAND_TEXTURE_MINING3 = 57; +constexpr int PICTURE_WASTELAND_TEXTURE_MINING4 = 58; +constexpr int PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW1 = 59; +constexpr int PICTURE_WASTELAND_TEXTURE_MEADOW1 = 60; +constexpr int PICTURE_WASTELAND_TEXTURE_MEADOW2 = 61; +constexpr int PICTURE_WASTELAND_TEXTURE_MEADOW3 = 62; +constexpr int PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW2 = 63; +constexpr int PICTURE_WASTELAND_TEXTURE_MINING_MEADOW = 64; +constexpr int PICTURE_WASTELAND_TEXTURE_WATER = 65; +constexpr int PICTURE_WASTELAND_TEXTURE_LAVA = 66; +constexpr int PICTURE_WINTERLAND_TEXTURE_SNOW = 67; +constexpr int PICTURE_WINTERLAND_TEXTURE_STEPPE = 68; +constexpr int PICTURE_WINTERLAND_TEXTURE_SWAMP = 69; +constexpr int PICTURE_WINTERLAND_TEXTURE_FLOWER = 70; +constexpr int PICTURE_WINTERLAND_TEXTURE_MINING1 = 71; +constexpr int PICTURE_WINTERLAND_TEXTURE_MINING2 = 72; +constexpr int PICTURE_WINTERLAND_TEXTURE_MINING3 = 73; +constexpr int PICTURE_WINTERLAND_TEXTURE_MINING4 = 74; +constexpr int PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW1 = 75; +constexpr int PICTURE_WINTERLAND_TEXTURE_MEADOW1 = 76; +constexpr int PICTURE_WINTERLAND_TEXTURE_MEADOW2 = 77; +constexpr int PICTURE_WINTERLAND_TEXTURE_MEADOW3 = 78; +constexpr int PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW2 = 79; +constexpr int PICTURE_WINTERLAND_TEXTURE_MINING_MEADOW = 80; +constexpr int PICTURE_WINTERLAND_TEXTURE_WATER = 81; +constexpr int PICTURE_WINTERLAND_TEXTURE_LAVA = 82; +constexpr int PICTURE_WINTERLAND_TEXTURE_MEADOW_MIXED = 83; +constexpr int PICTURE_TREE_CYPRESS = 84; +constexpr int PICTURE_TREE_PINE = 85; +constexpr int PICTURE_TREE_PALM2 = 86; +constexpr int PICTURE_TREE_PINEAPPLE = 87; +constexpr int PICTURE_TREE_FIR = 88; +constexpr int PICTURE_TREE_OAK = 89; +constexpr int PICTURE_TREE_BIRCH = 90; +constexpr int PICTURE_TREE_CHERRY = 91; +constexpr int PICTURE_TREE_PALM1 = 92; +constexpr int PICTURE_TREE_FLAPHAT = 93; +constexpr int PICTURE_TREE_SPIDER = 94; +constexpr int PICTURE_TREE_WOOD_MIXED = 95; +constexpr int PICTURE_TREE_PALM_MIXED = 96; +constexpr int PICTURE_SQUARE_CIRCLE1 = 97; +constexpr int PICTURE_SQUARE_CIRCLE2 = 98; +constexpr int PICTURE_SQUARE_CIRCLE3 = 99; +constexpr int PICTURE_SQUARE_CIRCLE4 = 100; +constexpr int PICTURE_RESOURCE_GOLD = 101; +constexpr int PICTURE_RESOURCE_ORE = 102; +constexpr int PICTURE_RESOURCE_COAL = 103; +constexpr int PICTURE_RESOURCE_GRANITE = 104; +constexpr int MENUBAR_TREE = 113; +constexpr int MENUBAR_RESOURCE = 114; +constexpr int MENUBAR_TEXTURE = 115; +constexpr int MENUBAR_HEIGHT = 116; +constexpr int MENUBAR_PLAYER = 117; +constexpr int MENUBAR_LANDSCAPE = 118; +constexpr int MENUBAR_ANIMAL = 119; +constexpr int MENUBAR_NEWWORLD = 120; +constexpr int PICTURE_EYE_CROSS = 121; +constexpr int MENUBAR_COMPUTER_DOUBLE_ENTRY = 122; +constexpr int PICTURE_LANDSCAPE_GRANITE = 126; +constexpr int PICTURE_LANDSCAPE_TREE_DEAD = 127; +constexpr int PICTURE_LANDSCAPE_STONE = 128; +constexpr int PICTURE_LANDSCAPE_CACTUS = 129; +constexpr int PICTURE_LANDSCAPE_PEBBLE = 130; +constexpr int PICTURE_LANDSCAPE_BUSH = 131; +constexpr int PICTURE_LANDSCAPE_SHRUB = 132; +constexpr int PICTURE_LANDSCAPE_BONE = 133; +constexpr int PICTURE_LANDSCAPE_MUSHROOM = 134; +constexpr int PICTURE_LANDSCAPE_STALAGMITE = 135; +constexpr int PICTURE_LANDSCAPE_GRANITE_WINTER = 136; +constexpr int PICTURE_LANDSCAPE_TREE_DEAD_WINTER = 137; +constexpr int PICTURE_LANDSCAPE_STONE_WINTER = 138; +constexpr int PICTURE_LANDSCAPE_PEBBLE_WINTER = 139; +constexpr int PICTURE_LANDSCAPE_BONE_WINTER = 140; +constexpr int PICTURE_LANDSCAPE_MUSHROOM_WINTER = 141; +constexpr int PICTURE_ANIMAL_BEAR = 142; +constexpr int PICTURE_ANIMAL_RABBIT = 143; +constexpr int PICTURE_ANIMAL_FOX = 144; +constexpr int PICTURE_ANIMAL_STAG = 145; +constexpr int PICTURE_ANIMAL_ROE = 146; +constexpr int PICTURE_ANIMAL_DUCK = 147; +constexpr int PICTURE_ANIMAL_SHEEP = 148; +// END: /DATA/IO/EDITIO.IDX (AND /DATA/IO/EDITIO.DAT) + +// BEGIN: /DATA/EDITBOB.LST +constexpr int CURSOR_SYMBOL_SCISSORS = 1; +constexpr int CURSOR_SYMBOL_TREE = 2; +constexpr int CURSOR_SYMBOL_ARROW_UP = 3; +constexpr int CURSOR_SYMBOL_ARROW_DOWN = 4; +constexpr int CURSOR_SYMBOL_TEXTURE = 5; +constexpr int CURSOR_SYMBOL_LANDSCAPE = 6; +constexpr int CURSOR_SYMBOL_FLAG = 7; +constexpr int CURSOR_SYMBOL_PICKAXE_MINUS = 8; +constexpr int CURSOR_SYMBOL_PICKAXE_PLUS = 9; +constexpr int CURSOR_SYMBOL_ANIMAL = 10; +constexpr int FLAG_BLUE_DARK = 11; +constexpr int FLAG_YELLOW = 12; +constexpr int FLAG_RED = 13; +constexpr int FLAG_BLUE_BRIGHT = 14; +constexpr int FLAG_GREEN_DARK = 15; +constexpr int FLAG_GREEN_BRIGHT = 16; +constexpr int FLAG_ORANGE = 17; +constexpr int PICTURE_SMALL_BEAR = 18; +constexpr int PICTURE_SMALL_RABBIT = 19; +constexpr int PICTURE_SMALL_FOX = 20; +constexpr int PICTURE_SMALL_STAG = 21; +constexpr int PICTURE_SMALL_DEER = 22; +constexpr int PICTURE_SMALL_DUCK = 23; +constexpr int PICTURE_SMALL_SHEEP = 24; +// END: /DATA/EDITBOB.LST + +// BEGIN: /GFX/TEXTURES/TEX5.LBM +constexpr int TILESET_GREENLAND = 0; +// END: /GFX/TEXTURES/TEX5.LBM + +// BEGIN: /GFX/TEXTURES/TEX6.LBM +constexpr int TILESET_WASTELAND = 0; +// END: /GFX/TEXTURES/TEX6.LBM + +// BEGIN: /GFX/TEXTURES/TEX7.LBM +constexpr int TILESET_WINTERLAND = 0; +// END: /GFX/TEXTURES/TEX7.LBM + +// BEGIN: /DATA/MIS*BOBS.LST * = 0,1,2,3,4,5 + +// MIS0BOBS.LST: bitmap at 0 (ship), shadow at 1, nulls 2-5, bitmap at 6 (tent) +constexpr int MIS0BOBS_SHIP = 0; +constexpr int MIS0BOBS_TENT = 6; + +// MIS1BOBS.LST: 7 stones (bitmaps at 0,2,4,6,8,10,12), 2 trees (20,22), skeleton (30) +constexpr int MIS1BOBS_STONE1 = 0; +constexpr int MIS1BOBS_STONE2 = 2; +constexpr int MIS1BOBS_STONE3 = 4; +constexpr int MIS1BOBS_STONE4 = 6; +constexpr int MIS1BOBS_STONE5 = 8; +constexpr int MIS1BOBS_STONE6 = 10; +constexpr int MIS1BOBS_STONE7 = 12; +constexpr int MIS1BOBS_TREE1 = 20; +constexpr int MIS1BOBS_TREE2 = 22; +constexpr int MIS1BOBS_SKELETON = 30; + +// MIS2BOBS.LST: tent (0), guardhouse (2), guardtower (4), fortress (6), puppy (8) +constexpr int MIS2BOBS_TENT = 0; +constexpr int MIS2BOBS_GUARDHOUSE = 2; +constexpr int MIS2BOBS_GUARDTOWER = 4; +constexpr int MIS2BOBS_FORTRESS = 6; +constexpr int MIS2BOBS_PUPPY = 8; + +// MIS3BOBS.LST: viking (0) +constexpr int MIS3BOBS_VIKING = 0; + +// MIS4BOBS.LST: scrolls (0) +constexpr int MIS4BOBS_SCROLLS = 0; + +// MIS5BOBS.LST: skeleton1 (0), skeleton2 (2), cave (4), viking (6) +constexpr int MIS5BOBS_SKELETON1 = 0; +constexpr int MIS5BOBS_SKELETON2 = 2; +constexpr int MIS5BOBS_CAVE = 4; +constexpr int MIS5BOBS_VIKING = 6; +// END: /DATA/MIS*BOBS.LST + +// BEGIN: /DATA/MAP00.LST (ONLY IF A MAP IS ACTIVE) +constexpr int MAPPIC_ARROWCROSS_YELLOW = 0; +constexpr int MAPPIC_CIRCLE_YELLOW = 1; +constexpr int MAPPIC_ARROWCROSS_RED = 2; +constexpr int MAPPIC_ARROWCROSS_ORANGE = 3; +constexpr int MAPPIC_ARROWCROSS_RED_FLAG = 4; +constexpr int MAPPIC_ARROWCROSS_RED_MINE = 5; +constexpr int MAPPIC_ARROWCROSS_RED_HOUSE_SMALL = 6; +constexpr int MAPPIC_ARROWCROSS_RED_HOUSE_MIDDLE = 7; +constexpr int MAPPIC_ARROWCROSS_RED_HOUSE_BIG = 8; +constexpr int MAPPIC_ARROWCROSS_RED_HOUSE_HARBOUR = 9; +constexpr int MAPPIC_PAPER_RED_CROSS = 10; +constexpr int MAPPIC_FLAG = 11; +constexpr int MAPPIC_HOUSE_SMALL = 12; +constexpr int MAPPIC_HOUSE_MIDDLE = 13; +constexpr int MAPPIC_HOUSE_BIG = 14; +constexpr int MAPPIC_MINE = 15; +constexpr int MAPPIC_HOUSE_HARBOUR = 16; +constexpr int MAPPIC_TREE_PINE = 26; +constexpr int MAPPIC_TREE_BIRCH = 41; +constexpr int MAPPIC_TREE_OAK = 56; +constexpr int MAPPIC_TREE_PALM1 = 71; +constexpr int MAPPIC_TREE_PALM2 = 86; +constexpr int MAPPIC_TREE_PINEAPPLE = 101; +constexpr int MAPPIC_TREE_CYPRESS = 109; +constexpr int MAPPIC_TREE_CHERRY = 124; +constexpr int MAPPIC_TREE_FIR = 139; +constexpr int MAPPIC_MUSHROOM1 = 154; +constexpr int MAPPIC_MUSHROOM2 = 155; +constexpr int MAPPIC_STONE1 = 156; +constexpr int MAPPIC_STONE2 = 157; +constexpr int MAPPIC_STONE3 = 158; +constexpr int MAPPIC_TREE_TRUNK_DEAD = 159; +constexpr int MAPPIC_TREE_DEAD = 160; +constexpr int MAPPIC_BONE1 = 161; +constexpr int MAPPIC_BONE2 = 162; +constexpr int MAPPIC_FLOWERS = 163; +constexpr int MAPPIC_BUSH1 = 164; +constexpr int MAPPIC_ROCK4 = 165; +constexpr int MAPPIC_CACTUS1 = 166; +constexpr int MAPPIC_CACTUS2 = 167; +constexpr int MAPPIC_SHRUB1 = 168; +constexpr int MAPPIC_SHRUB2 = 169; +constexpr int MAPPIC_GRANITE_1_1 = 170; +constexpr int MAPPIC_GRANITE_1_2 = 171; +constexpr int MAPPIC_GRANITE_1_3 = 172; +constexpr int MAPPIC_GRANITE_1_4 = 173; +constexpr int MAPPIC_GRANITE_1_5 = 174; +constexpr int MAPPIC_GRANITE_1_6 = 175; +constexpr int MAPPIC_GRANITE_2_1 = 176; +constexpr int MAPPIC_GRANITE_2_2 = 177; +constexpr int MAPPIC_GRANITE_2_3 = 178; +constexpr int MAPPIC_GRANITE_2_4 = 179; +constexpr int MAPPIC_GRANITE_2_5 = 180; +constexpr int MAPPIC_GRANITE_2_6 = 181; +constexpr int MAPPIC_UNKNOWN_PICTURE = 182; +constexpr int MAPPIC_FIELD_1_1 = 183; +constexpr int MAPPIC_FIELD_1_2 = 184; +constexpr int MAPPIC_FIELD_1_3 = 185; +constexpr int MAPPIC_FIELD_1_4 = 186; +constexpr int MAPPIC_FIELD_1_5 = 187; +constexpr int MAPPIC_FIELD_2_1 = 188; +constexpr int MAPPIC_FIELD_2_2 = 189; +constexpr int MAPPIC_FIELD_2_3 = 190; +constexpr int MAPPIC_FIELD_2_4 = 191; +constexpr int MAPPIC_FIELD_2_5 = 192; +constexpr int MAPPIC_BUSH2 = 193; +constexpr int MAPPIC_BUSH3 = 194; +constexpr int MAPPIC_BUSH4 = 195; +constexpr int MAPPIC_SHRUB3 = 196; +constexpr int MAPPIC_SHRUB4 = 197; +constexpr int MAPPIC_BONE3 = 198; +constexpr int MAPPIC_BONE4 = 199; +constexpr int MAPPIC_MUSHROOM3 = 200; +constexpr int MAPPIC_STONE4 = 201; +constexpr int MAPPIC_STONE5 = 202; +constexpr int MAPPIC_PEBBLE1 = 203; +constexpr int MAPPIC_PEBBLE2 = 204; +constexpr int MAPPIC_PEBBLE3 = 205; +constexpr int MAPPIC_SHRUB5 = 206; +constexpr int MAPPIC_SHRUB6 = 207; +constexpr int MAPPIC_SHRUB7 = 208; +constexpr int MAPPIC_SNOWMAN = 209; +constexpr int MAPPIC_DOOR = 210; +// Upper bound for cache invalidation (past last named entry, not exact) +constexpr int MAPPIC_LAST_ENTRY = 211; +// END: /DATA/MAP00.LST + +// ── Shadow index documentation (documents file format, unused in code) ── +constexpr auto MAXBOBBMP = 5000; +constexpr auto MAXBOBSHADOW = 5000; enum { - MIS0BOBS_SHIP_SHADOW = 0, + MIS0BOBS_SHIP_SHADOW = MAXBOBBMP, MIS0BOBS_TENT_SHADOW, MIS1BOBS_STONE1_SHADOW, MIS1BOBS_STONE2_SHADOW, @@ -1117,15 +1108,6 @@ enum MIS5BOBS_VIKING_SHADOW }; -// enumeration for BobtypePAL (palettes for the pics) -enum -{ - PAL_RESOURCE = 0, - PAL_IO, - PAL_MAPxx, - PAL_xBBM -}; - // Button-Colors (after all used by CButton and other Objects using CButton) enum { @@ -1190,17 +1172,9 @@ enum EDITOR_MODE_ANIMAL }; -// maximum range for the cursor in editor mode (user can increase or decrease by pressing '+' or '-') --> Must be >= 0. +// maximum range for the cursor in editor mode constexpr auto MAX_CHANGE_SECTION = 10; -// maximum values for global arrays -// maximum pics -constexpr auto MAXBOBBMP = 5000; -// maximum shadows -constexpr auto MAXBOBSHADOW = 5000; -// maximum palettes -constexpr auto MAXBOBPAL = 100; - // maximum players for a map constexpr auto MAXPLAYERS = 16; // maximum map size From b13d98fb66739bfd5c823eab13b55e69a213f647 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 00:48:00 +0200 Subject: [PATCH 03/16] Remove getTexture() filterLinear arg --- CGame_Init.cpp | 2 +- CSurface.cpp | 2 +- Texture.cpp | 20 ++++++++++---------- Texture.h | 9 ++++----- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/CGame_Init.cpp b/CGame_Init.cpp index 1c63020..89c4219 100644 --- a/CGame_Init.cpp +++ b/CGame_Init.cpp @@ -173,7 +173,7 @@ bool CGame::Init() auto& archiv = global::typedArchives[ArchiveID::SETUP997]; auto* bmp = dynamic_cast(archiv.get(0)); if(bmp) - splashBg_.load(*bmp, true); + splashBg_.load(*bmp); } // std::cout << "\nShow loading screen..."; diff --git a/CSurface.cpp b/CSurface.cpp index 0c55310..f105062 100644 --- a/CSurface.cpp +++ b/CSurface.cpp @@ -510,7 +510,7 @@ static const AnimFrames* getAnimFrames(const TerrainDesc& td, MapType mapType) libsiedler2::ArchivItem_Bitmap_Raw tmpBmp; tmpBmp.create(texSize.x, texSize.y, bgraBuf.getPixelPtr(), texSize.x, texSize.y, libsiedler2::TextureFormat::BGRA, nullptr); - tex.load(tmpBmp, false); + tex.load(tmpBmp); result.frames.push_back(std::move(tex)); curPal = std::move(pal); diff --git a/Texture.cpp b/Texture.cpp index 1be0169..4117408 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -47,17 +47,17 @@ void Texture::load(const uint8_t* bgraPixels, Extent size) glGenTextures(1, &texture_); glBindTexture(GL_TEXTURE_2D, texture_); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterLinear ? GL_LINEAR : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterLinear ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0, GL_BGRA, GL_UNSIGNED_BYTE, bgraPixels); size_ = size; } -void Texture::createEmpty(Extent size, bool filterLinear) +void Texture::createEmpty(Extent size) { - load(nullptr, size, filterLinear); + load(nullptr, size); } void Texture::upload(const void* bgraPixels) @@ -68,7 +68,7 @@ void Texture::upload(const void* bgraPixels) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size_.x, size_.y, GL_BGRA, GL_UNSIGNED_BYTE, bgraPixels); } -bool Texture::load(const libsiedler2::baseArchivItem_Bitmap& bitmap, bool filterLinear) +bool Texture::load(const libsiedler2::baseArchivItem_Bitmap& bitmap) { const auto w = bitmap.getWidth(); const auto h = bitmap.getHeight(); @@ -103,7 +103,7 @@ bool Texture::load(const libsiedler2::baseArchivItem_Bitmap& bitmap, bool filter return false; } - load(bgra.data(), Extent(w, h), filterLinear); + load(bgra.data(), Extent(w, h)); return true; } @@ -224,9 +224,9 @@ void drawRect(const Rect& rect, unsigned color) glColor4f(1, 1, 1, 1); } -Texture& getTexture(ArchiveID archive, int index, bool filterLinear) +Texture& getTexture(ArchiveID archive, int index) { - return Texture::getTexture(archive, index, filterLinear); + return Texture::getTexture(archive, index); } void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned faceTex) @@ -256,7 +256,7 @@ void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned fa // Cache for typed-archive textures: (archive, index) → Texture static std::map, std::unique_ptr> s_typedTexCache; -Texture& Texture::getTexture(ArchiveID archive, int index, bool filterLinear) +Texture& Texture::getTexture(ArchiveID archive, int index) { auto& archiv = global::typedArchives[archive]; if(index < 0 || static_cast(index) >= archiv.size()) @@ -272,7 +272,7 @@ Texture& Texture::getTexture(ArchiveID archive, int index, bool filterLinear) const auto* bmp = dynamic_cast(archiv.get(index)); if(bmp) { - tex->load(*bmp, filterLinear); + tex->load(*bmp); tex->anchor_ = {bmp->getNx(), bmp->getNy()}; } it = s_typedTexCache.emplace(key, std::move(tex)).first; diff --git a/Texture.h b/Texture.h index 8af748f..dbe9501 100644 --- a/Texture.h +++ b/Texture.h @@ -31,13 +31,13 @@ class Texture Texture& operator=(const Texture&) = delete; /// Load from a libsiedler2 bitmap (paletted or BGRA). - bool load(const libsiedler2::baseArchivItem_Bitmap& bitmap, bool filterLinear = false); + bool load(const libsiedler2::baseArchivItem_Bitmap& bitmap); /// Load raw BGRA pixel data directly. void load(const uint8_t* bgraPixels, Extent size); /// Create an empty texture of the given size (for use as a render-target). - void createEmpty(Extent size, bool filterLinear = false); + void createEmpty(Extent size); /// Upload new pixel data to an existing texture (glTexSubImage2D). void upload(const void* bgraPixels); @@ -72,13 +72,12 @@ class Texture // Static bitmap-texture cache /// Return (or create on first use) a cached GL texture from a typed archive. - static Texture& getTexture(ArchiveID archive, int index, bool filterLinear = false); + static Texture& getTexture(ArchiveID archive, int index); private: GLuint texture_ = 0; Extent size_; Position anchor_ = {0, 0}; // sprite anchor offset, set by getTexture - }; /// Draw a filled rectangle with a 32-bit ARGB colour. @@ -89,4 +88,4 @@ void drawRect(const Rect& rect, unsigned color); void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned faceTex); /// Get or create the cached OpenGL texture from a typed archive. -Texture& getTexture(ArchiveID archive, int index, bool filterLinear = false); +Texture& getTexture(ArchiveID archive, int index); From ec7e92fd16055a7ea41c9dde58e8de6b36eca419 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 02:45:31 +0200 Subject: [PATCH 04/16] fixup! libsiedler2 --- CIO/CControlContainer.cpp | 6 ++---- CIO/CControlContainer.h | 6 +++--- CIO/CPicture.cpp | 11 +++-------- CIO/CPicture.h | 4 ++-- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/CIO/CControlContainer.cpp b/CIO/CControlContainer.cpp index 7bd08c4..39fe95c 100644 --- a/CIO/CControlContainer.cpp +++ b/CIO/CControlContainer.cpp @@ -119,7 +119,7 @@ bool CControlContainer::delText(CFont* TextToDelete) } CPicture* CControlContainer::addPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, - int localIndex) + unsigned localIndex) { pos = pos + Position(border.left, border.top); @@ -132,10 +132,8 @@ bool CControlContainer::delPicture(CPicture* PictureToDelete) return eraseElement(pictures, PictureToDelete); } -int CControlContainer::addStaticPicture(Position pos, ArchiveID archive, int localIndex) +int CControlContainer::addStaticPicture(Position pos, ArchiveID archive, unsigned localIndex) { - if(localIndex < 0) - return -1; pos = pos + Position(border.left, border.top); unsigned id = static_pictures.empty() ? 0u : static_pictures.back().id + 1u; diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index 8b9ecec..e531f9b 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -41,7 +41,7 @@ class CControlContainer { Position pos; ArchiveID archive; - int pic; + unsigned pic; unsigned id; }; @@ -95,9 +95,9 @@ class CControlContainer bool delButton(CButton* ButtonToDelete); CFont* addText(std::string string, Position pos, FontSize fontsize, FontColor color = FontColor::Yellow); bool delText(CFont* TextToDelete); - CPicture* addPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, int localIndex); + CPicture* addPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, unsigned localIndex); bool delPicture(CPicture* PictureToDelete); - int addStaticPicture(Position pos, ArchiveID archive, int localIndex); + int addStaticPicture(Position pos, ArchiveID archive, unsigned localIndex); bool delStaticPicture(int picId); CTextfield* addTextfield(Position pos = {0, 0}, Uint16 cols = 10, Uint16 rows = 1, FontSize fontsize = FontSize::Large, FontColor text_color = FontColor::Yellow, diff --git a/CIO/CPicture.cpp b/CIO/CPicture.cpp index c17bd87..5f0289d 100644 --- a/CIO/CPicture.cpp +++ b/CIO/CPicture.cpp @@ -10,17 +10,12 @@ #include #include -CPicture::CPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, int picture) - : pos_(pos), archive_(archive), picture_(picture >= 0 ? picture : 0) +CPicture::CPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, unsigned picture) + : pos_(pos), archive_(archive), picture_(picture) { marked = false; clicked = false; - auto& archiv = global::typedArchives[archive]; - if(picture >= 0 && static_cast(picture) < archiv.size()) - { - if(auto* bmp = dynamic_cast(archiv.get(picture))) - size_ = Extent(bmp->getWidth(), bmp->getHeight()); - } + size_ = global::getBitmapSize(archive, picture); this->callback = callback; this->clickedParam = clickedParam; motionEntryParam = -1; diff --git a/CIO/CPicture.h b/CIO/CPicture.h index dab853b..6ab665d 100644 --- a/CIO/CPicture.h +++ b/CIO/CPicture.h @@ -17,7 +17,7 @@ class CPicture Position pos_; Extent size_; ArchiveID archive_; - int picture_; + unsigned picture_; bool marked; bool clicked; void (*callback)(int); @@ -26,7 +26,7 @@ class CPicture int motionLeaveParam; public: - CPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, int picture); + CPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, unsigned picture); // Access int getX() const { return pos_.x; }; int getY() const { return pos_.y; }; From 4fa88dd8e963e68faeb19d337225597f9e2e1eba Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 08:22:18 +0200 Subject: [PATCH 05/16] VideoDriver migration --- CDebug.cpp | 4 +- CGame.cpp | 61 ++-- CGame.h | 22 +- CGame_Event.cpp | 198 +++++++---- CGame_Init.cpp | 83 +++-- CGame_Render.cpp | 33 +- CIO/CButton.cpp | 6 +- CIO/CFont.cpp | 11 +- CIO/CMenu.cpp | 20 -- CIO/CMenu.h | 23 -- CIO/CMinimapWindow.cpp | 2 +- CMakeLists.txt | 2 +- CMap.cpp | 172 ++++++---- CMap.h | 5 +- CSurface.cpp | 88 ++--- CSurface.h | 4 +- EditorWorld.h | 54 +++ EditorWorldLoader.cpp | 25 ++ EditorWorldLoader.h | 3 + callbacks.cpp | 728 +---------------------------------------- callbacks.h | 5 +- dskEditorInterface.cpp | 208 ++++++++++++ dskEditorInterface.h | 59 ++++ dskMainMenu.cpp | 56 ++++ dskMainMenu.h | 27 ++ dskOptions.cpp | 93 ++++++ dskOptions.h | 28 ++ globals.cpp | 4 +- globals.h | 19 +- include/defines.h | 36 +- 30 files changed, 1008 insertions(+), 1071 deletions(-) delete mode 100644 CIO/CMenu.cpp delete mode 100644 CIO/CMenu.h create mode 100644 EditorWorld.h create mode 100644 EditorWorldLoader.cpp create mode 100644 EditorWorldLoader.h create mode 100644 dskEditorInterface.cpp create mode 100644 dskEditorInterface.h create mode 100644 dskMainMenu.cpp create mode 100644 dskMainMenu.h create mode 100644 dskOptions.cpp create mode 100644 dskOptions.h diff --git a/CDebug.cpp b/CDebug.cpp index bf0e583..cd2ae14 100644 --- a/CDebug.cpp +++ b/CDebug.cpp @@ -157,7 +157,7 @@ void CDebug::actualizeData() if(!RegisteredMenusText) RegisteredMenusText = dbgWnd->addText("", Position(0, 60), fontsize); // write new RegisteredMenusText and draw it - RegisteredMenusText->setText(helpers::format("Registered Menus: %d", global::s2->Menus.size())); + RegisteredMenusText->setText("Registered Menus: 0"); // del RegisteredWindowsText before drawing new if(!RegisteredWindowsText) @@ -183,7 +183,7 @@ void CDebug::actualizeData() if(MapObj) { map = MapObj->getMap(); - const MapNode& vertex = map->getVertex(MapObj->Vertex_); + const EditorMapNode& vertex = map->getVertex(MapObj->Vertex_); if(!MapNameText) MapNameText = dbgWnd->addText("", Position(260, 10), fontsize); diff --git a/CGame.cpp b/CGame.cpp index c35b739..5845e5e 100644 --- a/CGame.cpp +++ b/CGame.cpp @@ -4,7 +4,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CGame.h" -#include "CIO/CMenu.h" #include "CIO/CWindow.h" #include "CMap.h" #include "RttrConfig.h" @@ -13,6 +12,7 @@ #include "s25util/file_handle.h" #include #include +#include "drivers/VideoDriverWrapper.h" #include #include #include @@ -35,7 +35,7 @@ boost::program_options::variables_map parse_cmdline_args(int argc, char* argv[]) CGame::CGame(Extent GameResolution_, bool fullscreen_) : GameResolution(GameResolution_), fullscreen(fullscreen_), Running(true), showLoadScreen(true), - lastFps("", Position{0, 0}, FontSize::Medium) + lastFps("", Position{0, 0}, FontSize::Normal) { global::s2 = this; } @@ -55,7 +55,6 @@ int CGame::Execute() if(!Init()) return -1; - SDL_Event Event; lastFps.setText(""); lastFpsTick = SDL_GetTicks(); lastFrameTime = SDL_GetTicks(); @@ -63,8 +62,12 @@ int CGame::Execute() while(Running) { - while(SDL_PollEvent(&Event)) - EventHandling(&Event); + // Let the video driver poll and dispatch events to the WindowManager + if(!VIDEODRIVER.Run()) + Running = false; + + // Old-style event handling for CWindows/CMap is disabled during migration. + // TODO: Reinstate when old windows are migrated to Desktop/IngameWindow. GameLoop(); Render(); @@ -78,29 +81,7 @@ void CGame::RenderPresent() const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; cursorImg.draw(Cursor.pos); - SDL_GL_SwapWindow(window_.get()); -} - -CMenu* CGame::RegisterMenu(std::unique_ptr Menu) -{ - for(auto& i : Menus) - i->setInactive(); - - Menu->setActive(); - Menus.emplace_back(std::move(Menu)); - - return Menus.back().get(); -} - -bool CGame::UnregisterMenu(CMenu* Menu) -{ - auto it = std::find_if(Menus.begin(), Menus.end(), [Menu](const auto& cur) { return cur.get() == Menu; }); - if(it == Menus.end()) - return false; - if(it != Menus.begin()) - it[-1]->setActive(); - Menus.erase(it); - return true; + VIDEODRIVER.SwapBuffers(); } CWindow* CGame::RegisterWindow(std::unique_ptr Window) @@ -164,8 +145,6 @@ void CGame::delMapObj() void CGame::enterEditor(const boost::filesystem::path& filepath) { - for(auto& menu : Menus) - menu->setWaste(); setMapObj(std::make_unique(filepath)); } @@ -200,12 +179,6 @@ void CGame::GameLoop() for(auto&& callback : Callbacks) callback(CALL_FROM_GAMELOOP); const auto isWaste = [](const auto& p) { return p->isWaste(); }; - auto itMenu = std::find_if(Menus.begin(), Menus.end(), isWaste); - while(itMenu != Menus.end()) - { - UnregisterMenu(itMenu->get()); - itMenu = std::find_if(Menus.begin(), Menus.end(), isWaste); - } auto itWnd = std::find_if(Windows.begin(), Windows.end(), isWaste); while(itWnd != Windows.end()) { @@ -405,3 +378,19 @@ boost::program_options::variables_map parse_cmdline_args(int argc, char* argv[]) return result; } + +// VideoDriverLoaderInterface callbacks +// These are called by the video driver's MessageLoop. +// We currently use our own SDL_PollEvent loop, so these are no-ops for now. +void CGame::Msg_LeftDown(MouseCoords /*mc*/) {} +void CGame::Msg_LeftUp(MouseCoords /*mc*/) {} +void CGame::Msg_RightDown(const MouseCoords& /*mc*/) {} +void CGame::Msg_RightUp(const MouseCoords& /*mc*/) {} +void CGame::Msg_MiddleDown(const MouseCoords& /*mc*/) {} +void CGame::Msg_MiddleUp(const MouseCoords& /*mc*/) {} +void CGame::Msg_WheelUp(const MouseCoords& /*mc*/) {} +void CGame::Msg_WheelDown(const MouseCoords& /*mc*/) {} +void CGame::Msg_MouseMove(const MouseCoords& /*mc*/) {} +void CGame::Msg_KeyDown(const KeyEvent& /*ke*/) {} +void CGame::WindowResized() {} + diff --git a/CGame.h b/CGame.h index c1ee0c6..68f4ce0 100644 --- a/CGame.h +++ b/CGame.h @@ -8,6 +8,7 @@ #include "CIO/CFont.h" #include "SdlSurface.h" #include "Texture.h" +#include "driver/VideoDriverLoaderInterface.h" #include #include #include @@ -15,9 +16,8 @@ class CWindow; class CMap; -class CMenu; -class CGame +class CGame : public VideoDriverLoaderInterface { friend class CDebug; @@ -63,8 +63,6 @@ class CGame } button; } Cursor; - // Object for Menu Screens - std::vector> Menus; // Object for Windows std::vector> Windows; // Object for Callbacks @@ -76,6 +74,19 @@ class CGame void setGLViewport(); bool CreateWindow(); + // VideoDriverLoaderInterface callbacks + void Msg_LeftDown(MouseCoords mc) override; + void Msg_LeftUp(MouseCoords mc) override; + void Msg_RightDown(const MouseCoords& mc) override; + void Msg_RightUp(const MouseCoords& mc) override; + void Msg_MiddleDown(const MouseCoords& mc) override; + void Msg_MiddleUp(const MouseCoords& mc) override; + void Msg_WheelUp(const MouseCoords& mc) override; + void Msg_WheelDown(const MouseCoords& mc) override; + void Msg_MouseMove(const MouseCoords& mc) override; + void Msg_KeyDown(const KeyEvent& ke) override; + void WindowResized() override; + public: // Apply current GameResolution and fullscreen settings to the window/display. void ApplyWindowChanges(); @@ -92,6 +103,7 @@ class CGame void UpdateDisplaySize(const Extent& newSize); void EventHandling(SDL_Event* Event); + void ForwardEventToWindowManager(SDL_Event* Event); void GameLoop(); @@ -99,8 +111,6 @@ class CGame void RenderPresent(); - CMenu* RegisterMenu(std::unique_ptr Menu); - bool UnregisterMenu(CMenu* Menu); CWindow* RegisterWindow(std::unique_ptr Window); bool UnregisterWindow(CWindow* Window); void RegisterCallback(void (*callback)(int)); diff --git a/CGame_Event.cpp b/CGame_Event.cpp index 4ef42cb..8642cd0 100644 --- a/CGame_Event.cpp +++ b/CGame_Event.cpp @@ -4,13 +4,16 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CGame.h" -#include "CIO/CMenu.h" #include "CIO/CWindow.h" #include "CMap.h" #include "CSurface.h" #include "CollisionDetection.h" +#include "WindowManager.h" #include "callbacks.h" +#include "drivers/VideoDriverWrapper.h" +#include "enum_cast.hpp" #include "globals.h" +#include "s25util/utf8.h" void CGame::EventHandling(SDL_Event* Event) { @@ -54,12 +57,7 @@ void CGame::EventHandling(SDL_Event* Event) // break; } - // deliver keyboard data to active menus - for(auto& Menu : Menus) - { - if(Menu->isActive() && !Menu->isWaste()) - Menu->setKeyboardData(Event->key); - } + } switch(Event->key.keysym.sym) @@ -81,48 +79,7 @@ void CGame::EventHandling(SDL_Event* Event) break; #endif - // F5 - F7 is ZOOM, F5 = zoom in, F6 = normal view, F7 = zoom out - case SDLK_F5: - if(triangleIncrease < ZOOM_INCREASE_MAX && MapObj->getMap()) - { - callback::PleaseWait(INITIALIZING_CALL); - triangleHeight += ZOOM_STEP_HEIGHT; - triangleWidth += ZOOM_STEP_WIDTH; - triangleIncrease += ZOOM_STEP_INCREASE; - bobMAP* myMap = MapObj->getMap(); - myMap->updateVertexCoords(); - CSurface::get_nodeVectors(*myMap); - callback::PleaseWait(WINDOW_QUIT_MESSAGE); - } - break; - case SDLK_F6: - { - if(MapObj->getMap()) - { - callback::PleaseWait(INITIALIZING_CALL); - triangleHeight = TRIANGLE_HEIGHT_DEFAULT; - triangleWidth = TRIANGLE_WIDTH_DEFAULT; - triangleIncrease = TRIANGLE_INCREASE_DEFAULT; - bobMAP* myMap = MapObj->getMap(); - myMap->updateVertexCoords(); - CSurface::get_nodeVectors(*myMap); - callback::PleaseWait(WINDOW_QUIT_MESSAGE); - } - } - break; - case SDLK_F7: - if(triangleIncrease > ZOOM_INCREASE_MIN && MapObj->getMap()) - { - callback::PleaseWait(INITIALIZING_CALL); - triangleHeight -= ZOOM_STEP_HEIGHT; - triangleWidth -= ZOOM_STEP_WIDTH; - triangleIncrease -= ZOOM_STEP_INCREASE; - bobMAP* myMap = MapObj->getMap(); - myMap->updateVertexCoords(); - CSurface::get_nodeVectors(*myMap); - callback::PleaseWait(WINDOW_QUIT_MESSAGE); - } - break; + // Zoom keys removed — TerrainRenderer handles zoom via glScale default: break; } @@ -219,15 +176,7 @@ void CGame::EventHandling(SDL_Event* Event) break; } - // deliver mouse motion data to active menus - for(auto& Menu : Menus) - { - if(Menu->isActive() && !Menu->isWaste()) - { - Menu->setMouseData(Event->motion); - break; - } - } + break; } @@ -297,13 +246,6 @@ void CGame::EventHandling(SDL_Event* Event) break; } - // deliver mouse button data to active menus - for(auto& Menu : Menus) - { - if(Menu->isActive() && !Menu->isWaste()) - Menu->setMouseData(Event->button); - } - break; } @@ -368,12 +310,6 @@ void CGame::EventHandling(SDL_Event* Event) if(delivered) break; - // deliver mouse button data to active menus - for(auto& Menu : Menus) - { - if(Menu->isActive() && !Menu->isWaste()) - Menu->setMouseData(Event->button); - } break; } @@ -400,3 +336,123 @@ void CGame::EventHandling(SDL_Event* Event) default: break; } } + +void CGame::ForwardEventToWindowManager(SDL_Event* ev) +{ + static MouseCoords mouse_xy; + + switch(ev->type) + { + case SDL_WINDOWEVENT: + if(ev->window.event == SDL_WINDOWEVENT_RESIZED) + WINDOWMANAGER.WindowResized(); + break; + + case SDL_KEYDOWN: + { + KeyEvent ke; + switch(ev->key.keysym.sym) + { + case SDLK_RETURN: ke.kt = KeyType::Return; break; + case SDLK_SPACE: ke.kt = KeyType::Space; break; + case SDLK_LEFT: ke.kt = KeyType::Left; break; + case SDLK_RIGHT: ke.kt = KeyType::Right; break; + case SDLK_UP: ke.kt = KeyType::Up; break; + case SDLK_DOWN: ke.kt = KeyType::Down; break; + case SDLK_BACKSPACE: ke.kt = KeyType::Backspace; break; + case SDLK_DELETE: ke.kt = KeyType::Delete; break; + case SDLK_TAB: ke.kt = KeyType::Tab; break; + case SDLK_HOME: ke.kt = KeyType::Home; break; + case SDLK_END: ke.kt = KeyType::End; break; + case SDLK_ESCAPE: ke.kt = KeyType::Escape; break; + case SDLK_PRINTSCREEN: ke.kt = KeyType::Print; break; + default: + if(ev->key.keysym.sym >= SDLK_F1 && ev->key.keysym.sym <= SDLK_F12) + ke.kt = static_cast(rttr::enum_cast(KeyType::F1) + ev->key.keysym.sym - SDLK_F1); + break; + } + ke.alt = (ev->key.keysym.mod & KMOD_ALT) != 0; + ke.ctrl = (ev->key.keysym.mod & KMOD_CTRL) != 0; + ke.shift = (ev->key.keysym.mod & KMOD_SHIFT) != 0; + if(ke.kt != KeyType::Invalid) + WINDOWMANAGER.Msg_KeyDown(ke); + break; + } + + case SDL_TEXTINPUT: + { + const std::u32string text = s25util::utf8to32(ev->text.text); + KeyEvent ke; + for(char32_t c : text) + { + ke.c = c; + WINDOWMANAGER.Msg_KeyDown(ke); + } + break; + } + + case SDL_MOUSEBUTTONDOWN: + mouse_xy.pos = Position(ev->button.x, ev->button.y); + VIDEODRIVER.SetMousePos(mouse_xy.pos); + switch(ev->button.button) + { + case SDL_BUTTON_LEFT: + mouse_xy.ldown = true; + WINDOWMANAGER.Msg_LeftDown(mouse_xy); + break; + case SDL_BUTTON_RIGHT: + mouse_xy.rdown = true; + WINDOWMANAGER.Msg_RightDown(mouse_xy); + break; + case SDL_BUTTON_MIDDLE: + mouse_xy.mdown = true; + WINDOWMANAGER.Msg_MiddleDown(mouse_xy); + break; + } + break; + + case SDL_MOUSEBUTTONUP: + mouse_xy.pos = Position(ev->button.x, ev->button.y); + VIDEODRIVER.SetMousePos(mouse_xy.pos); + switch(ev->button.button) + { + case SDL_BUTTON_LEFT: + mouse_xy.ldown = false; + WINDOWMANAGER.Msg_LeftUp(mouse_xy); + break; + case SDL_BUTTON_RIGHT: + mouse_xy.rdown = false; + WINDOWMANAGER.Msg_RightUp(mouse_xy); + break; + case SDL_BUTTON_MIDDLE: + mouse_xy.mdown = false; + WINDOWMANAGER.Msg_MiddleUp(mouse_xy); + break; + } + break; + + case SDL_MOUSEWHEEL: + { + int y = ev->wheel.y; + if(ev->wheel.direction == SDL_MOUSEWHEEL_FLIPPED) + y = -y; + if(y > 0) + WINDOWMANAGER.Msg_WheelUp(mouse_xy); + else if(y < 0) + WINDOWMANAGER.Msg_WheelDown(mouse_xy); + break; + } + + case SDL_MOUSEMOTION: + { + const Position newPos(ev->motion.x, ev->motion.y); + if(newPos != mouse_xy.pos) + { + mouse_xy.pos = newPos; + VIDEODRIVER.SetMousePos(newPos); + WINDOWMANAGER.Msg_MouseMove(mouse_xy); + } + break; + } + } +} diff --git a/CGame_Init.cpp b/CGame_Init.cpp index 89c4219..0765ded 100644 --- a/CGame_Init.cpp +++ b/CGame_Init.cpp @@ -5,43 +5,65 @@ #include "CGame.h" #include "CIO/CFile.h" -#include "CIO/CMenu.h" #include "CIO/CWindow.h" #include "CMap.h" +#include "WindowManager.h" #include "callbacks.h" +#include "dskMainMenu.h" #include "globals.h" +#include "Loader.h" #include "lua/GameDataLoader.h" +#include "ogl/glAllocator.h" #include #include #include #include #include +#include "drivers/VideoDriverWrapper.h" #include #include +#include bool CGame::CreateWindow() { if(window_) return false; - window_.reset(SDL_CreateWindow("Return to the Roots Map editor [BETA]", SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, GameResolution.x, GameResolution.y, - SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE)); - if(!window_) + // Load the SDL2 video driver plugin + std::string driverName = "SDL2"; + try + { + if(!VIDEODRIVER.LoadDriver(driverName)) + { + std::cerr << "LoadDriver failed" << std::endl; + return false; + } + } catch(std::exception& e) + { + std::cerr << "LoadDriver exception: " << e.what() << std::endl; + return false; + } catch(...) + { + std::cerr << "LoadDriver unknown exception" << std::endl; return false; + } - glContext_ = SDL_GL_CreateContext(window_.get()); - if(!glContext_ || !gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) + if(!VIDEODRIVER.CreateScreen({static_cast(GameResolution.x), + static_cast(GameResolution.y)}, + DisplayMode::Windowed)) return false; + // Keep our own SDL window handle for event polling and resize handling + window_.reset(SDL_GL_GetCurrentWindow()); + glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_SCISSOR_TEST); glClearColor(0, 0, 0, 1); - SDL_ShowWindow(window_.get()); - ApplyWindowChanges(); SetAppIcon(); @@ -367,17 +389,38 @@ bool CGame::Init() } } - // create the mainmenu - callback::mainmenu(INITIALIZING_CALL); - - // Create textures for cursor (from typed archive) - auto& resArchiv = global::typedArchives[ArchiveID::EDITRES]; - if(auto* bmp = dynamic_cast(resArchiv.get(CURSOR))) - cursor_.load(*bmp); - if(auto* bmp = dynamic_cast(resArchiv.get(CURSOR_CLICKED))) - cursorClicked_.load(*bmp); - if(auto* bmp = dynamic_cast(resArchiv.get(CROSS))) - cross_.load(*bmp); + // Initialize the s25main Loader with the same files the game itself uses. + { + libsiedler2::setAllocator(new GlAllocator()); + LOADER.initResourceFolders(); + LOADER.LoadFilesAtStart(); + + // Also load the editor's EDITIO.IDX into a separate archive (keyed as "editio") + // so the editor toolbar can use its tool icons (MENUBAR_TREE=113, etc.) + // without overwriting the game's IO.IDX (needed for s25main button borders etc.). + const auto editioPath = global::gameDataFilePath / "DATA/IO/EDITIO.IDX"; + LOADER.Load(editioPath, global::currentPalette); + + // Load editor resource archives into the Loader + const auto editresPath = global::gameDataFilePath / "DATA/EDITRES.IDX"; + LOADER.Load(editresPath, global::currentPalette); + const auto editbobPath = global::gameDataFilePath / "DATA/EDITBOB.LST"; + LOADER.Load(editbobPath, global::currentPalette); + + // Use editor cursor everywhere instead of the game's default hand + auto* cursorNorm = LOADER.GetImageN("editres", CURSOR); + auto* cursorPressed = LOADER.GetImageN("editres", CURSOR_CLICKED); + if(cursorNorm) + WINDOWMANAGER.SetCursorImage(Cursor::Hand, cursorNorm, cursorPressed); + + + } + + // Show the new Desktop-based main menu via WindowManager + WINDOWMANAGER.Switch(std::make_unique()); + + // All resources loaded, dismiss the loading splash so the Desktop renders + showLoadScreen = false; return true; } diff --git a/CGame_Render.cpp b/CGame_Render.cpp index 7c163d3..39cbc2c 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -5,12 +5,13 @@ #include "CGame.h" #include "CIO/CFont.h" -#include "CIO/CMenu.h" #include "CIO/CWindow.h" #include "CMap.h" #include "CSurface.h" #include "Texture.h" +#include "WindowManager.h" #include "globals.h" +#include "drivers/VideoDriverWrapper.h" #include #ifdef _WIN32 # include "s25editResource.h" @@ -43,15 +44,31 @@ void CGame::Render() glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_SCISSOR_TEST); // if the S2 loading screen is shown, render only this until user clicks a mouse button if(showLoadScreen) { splashBg_.draw(Rect(0, 0, GameResolution.x, GameResolution.y)); - SDL_GL_SwapWindow(window_.get()); + VIDEODRIVER.SwapBuffers(); return; } + // If no map is active, let the WindowManager render the Desktop (and any IngameWindows) + if(!MapObj || !MapObj->isActive()) + { + // Reset projection to screen-space before WindowManager draws + const auto rs = VIDEODRIVER.GetRenderSize(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, rs.x, rs.y, 0, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + WINDOWMANAGER.Draw(); + } + // render the map if active if(MapObj && MapObj->isActive()) { @@ -95,13 +112,6 @@ void CGame::Render() FontColor::Orange); } - // render active menus - for(auto& Menu : Menus) - { - if(Menu->isActive()) - Menu->draw(Position(0, 0)); - } - // render windows ordered by priority int highestPriority = 0; // first find the highest priority @@ -135,10 +145,9 @@ void CGame::Render() } lastFps.draw(Position(0, 0)); - const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; - cursorImg.draw(Cursor.pos); + // Cursor is drawn by WindowManager via DrawCursor() - SDL_GL_SwapWindow(window_.get()); + VIDEODRIVER.SwapBuffers(); #ifdef _ADMINMODE FrameCounter++; diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index c715595..848b5e3 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -140,9 +140,9 @@ void CButton::draw(Position parentOrigin) const } else if(button_text) { // Draw text centered (using native-size texture drawing for each character) - const Extent textSize(CFont::getTextWidth(button_text, FontSize::Medium), - static_cast(FontSize::Medium)); + const Extent textSize(CFont::getTextWidth(button_text, FontSize::Normal), + getFontHeightPx(FontSize::Normal)); const Position textPos = absPos + (Position(size_) - textSize) / 2; - CFont::draw(button_text, textPos, FontSize::Medium, button_text_color, FontAlign::Left); + CFont::draw(button_text, textPos, FontSize::Normal, button_text_color, FontAlign::Left); } } diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp index 1c08f12..30804f2 100644 --- a/CIO/CFont.cpp +++ b/CIO/CFont.cpp @@ -106,19 +106,12 @@ static FontAtlas& getAtlas(FontSize size, FontColor color) int ci = static_cast(color); if(ci < 0 || ci > 6) ci = 0; - int si; - switch(size) - { - case FontSize::Small: si = 0; break; - case FontSize::Medium: si = 1; break; - case FontSize::Large: si = 2; break; - default: si = 0; break; - } + int si = static_cast(size); if(!atlases[si][ci].tex.isValid()) { auto& a = atlases[si][ci]; // Resolve the font from the EDITRES archive by height - unsigned targetDy = static_cast(size); + unsigned targetDy = getFontHeightPx(size); auto& archiv = global::typedArchives[ArchiveID::EDITRES]; const libsiedler2::ArchivItem_Font* font = nullptr; for(unsigned i = 0; i < archiv.size(); i++) diff --git a/CIO/CMenu.cpp b/CIO/CMenu.cpp deleted file mode 100644 index 7edcdd6..0000000 --- a/CIO/CMenu.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CMenu.h" -#include "../CGame.h" -#include "../Texture.h" -#include "../globals.h" - -CMenu::CMenu(int pic_background, ArchiveID archive) : CControlContainer(pic_background, BorderSizes{}, archive) {} - -void CMenu::draw(Position /*parentOrigin*/) -{ - // Draw full-screen background texture - const auto res = global::s2->getRes(); - getTexture(backgroundArchive_, getBackground()).draw(Rect(0, 0, res.x, res.y)); - - drawChildren(Position(0, 0)); -} diff --git a/CIO/CMenu.h b/CIO/CMenu.h deleted file mode 100644 index 49ff572..0000000 --- a/CIO/CMenu.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "ArchiveID.h" -#include "CControlContainer.h" - -class CMenu final : public CControlContainer -{ - // if active is false, the menu will not be render within the game loop - bool active = true; - -public: - CMenu(int pic_background, ArchiveID archive); - void setActive() { active = true; } - void setInactive() { active = false; } - bool isActive() const { return active; } - - void draw(Position parentOrigin) override; -}; diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index 080093f..d449bce 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -59,7 +59,7 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) const Position arrowCenter = dispRect.getOrigin() + dispRect.getSize() / 2u; auto& tex = Texture::getTexture(ArchiveID::MAP00, arrowIdx); const Position arrowPos = - contentPos + arrowCenter / Position(triangleWidth, triangleHeight) / scale - tex.anchor(); + contentPos + arrowCenter / Position(TR_W, TR_H) / scale - tex.anchor(); tex.draw(arrowPos); } } diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c62a5a..9c6cd48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ ELSE() ENDIF() add_executable(s25edit ${MAIN_SOURCES} ${CIO_SOURCES} ${icon_RC}) -target_link_libraries(s25edit PRIVATE rttrConfig s25Common gamedata siedler2 endian::static glad Boost::nowide SDL2::SDL2 PUBLIC Boost::disable_autolinking Boost::program_options) +target_link_libraries(s25edit PRIVATE rttrConfig s25Common gamedata siedler2 s25Main endian::static glad Boost::nowide SDL2::SDL2 PUBLIC Boost::disable_autolinking Boost::program_options) target_include_directories(s25edit PRIVATE include) target_compile_features(s25edit PRIVATE cxx_std_17) diff --git a/CMap.cpp b/CMap.cpp index ebc5e12..9efdd98 100644 --- a/CMap.cpp +++ b/CMap.cpp @@ -38,7 +38,7 @@ void bobMAP::initVertexCoords() { for(unsigned i = 0; i < width; i++) { - MapNode& curVertex = getVertex(i, j); + EditorMapNode& curVertex = getVertex(i, j); curVertex.VertexX = i; curVertex.VertexY = j; } @@ -48,27 +48,27 @@ void bobMAP::initVertexCoords() void bobMAP::updateVertexCoords() { - width_pixel = width * triangleWidth; - height_pixel = height * triangleHeight; + width_pixel = width * TR_W; + height_pixel = height * TR_H; Sint32 b = 0; for(unsigned j = 0; j < height; j++) { Sint32 a; if(j % 2u == 0u) - a = triangleWidth / 2u; + a = TR_W / 2u; else - a = triangleWidth; + a = TR_W; for(unsigned i = 0; i < width; i++) { - MapNode& curVertex = getVertex(i, j); + EditorMapNode& curVertex = getVertex(i, j); curVertex.x = a; - curVertex.y = b - triangleIncrease * (curVertex.h - 0x0A); - curVertex.z = triangleIncrease * (curVertex.h - 0x0A); - a += triangleWidth; + curVertex.y = b - HEIGHT_FACTOR * (curVertex.h - 0x0A); + curVertex.z = HEIGHT_FACTOR * (curVertex.h - 0x0A); + a += TR_W; } - b += triangleHeight; + b += TR_H; } } @@ -194,7 +194,7 @@ void CMap::constructMap(const boost::filesystem::path& filepath, int width, int { for(int x = 0; x < map->width; x++) { - MapNode& curVertex = map->getVertex(x, y); + EditorMapNode& curVertex = map->getVertex(x, y); if(curVertex.objectInfo == 0x80) { CountPlayers++; @@ -219,6 +219,31 @@ void CMap::constructMap(const boost::filesystem::path& filepath, int width, int HorizontalMovementLocked = false; VerticalMovementLocked = false; + + // Init EditorWorld for TerrainRenderer rendering + terrainWorld_ = std::make_unique(MapExtent(map->width, map->height), 7u); + { + auto& gameWorld = terrainWorld_->getWorld(); + const auto& terrains = gameWorld.GetDescription().terrain; + std::array, 256> texIdToDesc; + for(unsigned i = 0; i < terrains.size(); i++) + { + auto idx = DescIdx(i); + texIdToDesc[terrains.get(idx).s2Id] = idx; + } + for(unsigned y = 0; y < map->height; y++) + { + for(unsigned x = 0; x < map->width; x++) + { + const auto& src = map->getVertex(x, y); + auto& dst = gameWorld.GetNodeWriteable(MapPoint(x, y)); + dst.altitude = src.h; + dst.t1 = texIdToDesc[src.rsuTexture]; + dst.t2 = texIdToDesc[src.usdTexture]; + dst.shadow = src.shading; + } + } + } } void CMap::destructMap() { @@ -228,6 +253,7 @@ void CMap::destructMap() Vertices.clear(); // free map structure memory map.reset(); + terrainWorld_.reset(); filepath_.clear(); } @@ -256,7 +282,7 @@ std::unique_ptr CMap::generateMap(int width, int height, MapType type, T { for(int i = 0; i < myMap->width; i++) { - MapNode& curVertex = myMap->getVertex(i, j); + EditorMapNode& curVertex = myMap->getVertex(i, j); curVertex.h = 0x0A; if((j < border || myMap->height - j <= border) || (i < border || myMap->width - i <= border)) @@ -291,7 +317,7 @@ std::unique_ptr CMap::generateMap(int width, int height, MapType type, T void CMap::rotateMap() { // we allocate memory for the new triangle field but with x equals the height and y equals the width - std::vector new_vertex(map->vertex.size()); + std::vector new_vertex(map->vertex.size()); undoBuffer.clear(); redoBuffer.clear(); @@ -959,15 +985,15 @@ void CMap::storeVerticesFromMouse(Position mousePos, Uint8 /*MouseState*/) // get X // following out commented lines are the correct ones, but for tolerance (to prevent to early jumps of the cursor) - // we subtract "triangleWidth/2" Xeven = (MouseX + displayRect.left) / triangleWidth; - Xeven = (mousePos.x + displayRect.left - triangleWidth / 2) / triangleWidth; + // we subtract "TR_W/2" Xeven = (MouseX + displayRect.left) / TR_W; + Xeven = (mousePos.x + displayRect.left - TR_W / 2) / TR_W; if(Xeven < 0) Xeven += (map->width); else if(Xeven > map->width - 1) Xeven -= (map->width - 1); - // Add rows are already shifted by triangleWidth / 2 - Xodd = (mousePos.x + displayRect.left) / triangleWidth; - // Xodd = (mousePos.x + displayRect.left) / triangleWidth; + // Add rows are already shifted by TR_W / 2 + Xodd = (mousePos.x + displayRect.left) / TR_W; + // Xodd = (mousePos.x + displayRect.left) / TR_W; if(Xodd < 0) Xodd += (map->width - 1); else if(Xodd > map->width - 1) @@ -985,8 +1011,8 @@ void CMap::storeVerticesFromMouse(Position mousePos, Uint8 /*MouseState*/) { if(j % 2 == 0) { - // subtract "triangleHeight/2" is for tolerance, we did the same for X - if((MousePosY - triangleHeight / 2) > map->getVertex(Xeven, j).y) + // subtract "TR_H/2" is for tolerance, we did the same for X + if((MousePosY - TR_H / 2) > map->getVertex(Xeven, j).y) Y++; else { @@ -995,7 +1021,7 @@ void CMap::storeVerticesFromMouse(Position mousePos, Uint8 /*MouseState*/) } } else { - if((MousePosY - triangleHeight / 2) > map->getVertex(Xodd, j).y) + if((MousePosY - TR_H / 2) > map->getVertex(Xodd, j).y) Y++; else { @@ -1048,9 +1074,29 @@ void CMap::render() modifyVertex(); } - // 1. Draw terrain with OpenGL - if(!map->vertex.empty()) - CSurface::DrawTriangleField(displayRect, *map); + // 1. Draw terrain + if(terrainWorld_ && !map->vertex.empty()) + { + Position firstPt(std::max(0, displayRect.left / TR_W - 1), + std::max(0, displayRect.top / TR_H - 1)); + Position lastPt(std::min(map->width - 1, displayRect.right / TR_W + 1), + std::min(map->height - 1, displayRect.bottom / TR_H + 1)); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(static_cast(displayRect.left), + static_cast(displayRect.right), + static_cast(displayRect.bottom), + static_cast(displayRect.top), -100, 100); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + terrainWorld_->draw(firstPt, lastPt); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + } // 2. Draw editor UI chrome on top (screen-space) // Switch to screen-space projection for UI chrome @@ -1065,6 +1111,8 @@ void CMap::render() glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_SCISSOR_TEST); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // draw pictures to cursor position @@ -1302,7 +1350,7 @@ static const TerrainDesc* getTerrainDesc(const bobMAP& map, Uint8 rawTextureId) return nullptr; } -static bool nodeHasTerrainFlag(const bobMAP& map, const MapNode& node, ETerrain flag, bool checkBoth = true) +static bool nodeHasTerrainFlag(const bobMAP& map, const EditorMapNode& node, ETerrain flag, bool checkBoth = true) { const auto* rsu = getTerrainDesc(map, node.rsuTexture); const auto* usd = getTerrainDesc(map, node.usdTexture); @@ -1477,7 +1525,7 @@ void CMap::modifyHeightRaise(Position pos) { // vertex count for the points int X, Y; - MapNode* tempP = &map->getVertex(pos.x, pos.y); + EditorMapNode* tempP = &map->getVertex(pos.x, pos.y); // this is to setup the building depending on the vertices around std::array tempVertices; calculateVerticesAround(tempVertices, pos); @@ -1487,18 +1535,18 @@ void CMap::modifyHeightRaise(Position pos) even = true; // DO IT - if(tempP->z >= triangleIncrease * (MaxRaiseHeight - 0x0A)) // user specified maximum reached + if(tempP->z >= HEIGHT_FACTOR * (MaxRaiseHeight - 0x0A)) // user specified maximum reached return; - if(tempP->z >= triangleIncrease * (0x3C - 0x0A)) // maximum reached (0x3C is max) + if(tempP->z >= HEIGHT_FACTOR * (0x3C - 0x0A)) // maximum reached (0x3C is max) return; - tempP->y -= triangleIncrease; - tempP->z += triangleIncrease; + tempP->y -= HEIGHT_FACTOR; + tempP->z += HEIGHT_FACTOR; tempP->h += 0x01; CSurface::update_shading(*map, pos); - // after (5*triangleIncrease) pixel all vertices around will be raised too + // after (5*HEIGHT_FACTOR) pixel all vertices around will be raised too // update first vertex left upside X = pos.x - (even ? 1 : 0); if(X < 0) @@ -1508,7 +1556,7 @@ void CMap::modifyHeightRaise(Position pos) Y += map->height; // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * triangleIncrease)) //-V807 + if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) //-V807 modifyHeightRaise(Position(X, Y)); // update second vertex right upside X = pos.x + (even ? 0 : 1); @@ -1519,7 +1567,7 @@ void CMap::modifyHeightRaise(Position pos) Y += map->height; // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * triangleIncrease)) + if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) modifyHeightRaise(Position(X, Y)); // update third point bottom left X = pos.x - 1; @@ -1528,7 +1576,7 @@ void CMap::modifyHeightRaise(Position pos) Y = pos.y; // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * triangleIncrease)) + if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) modifyHeightRaise(Position(X, Y)); // update fourth point bottom right X = pos.x + 1; @@ -1537,7 +1585,7 @@ void CMap::modifyHeightRaise(Position pos) Y = pos.y; // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * triangleIncrease)) + if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) modifyHeightRaise(Position(X, Y)); // update fifth point down left X = pos.x - (even ? 1 : 0); @@ -1548,7 +1596,7 @@ void CMap::modifyHeightRaise(Position pos) Y -= map->height; // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * triangleIncrease)) + if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) modifyHeightRaise(Position(X, Y)); // update sixth point down right X = pos.x + (even ? 0 : 1); @@ -1559,7 +1607,7 @@ void CMap::modifyHeightRaise(Position pos) Y -= map->height; // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * triangleIncrease)) + if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) modifyHeightRaise(Position(X, Y)); // at least setup the possible building and shading at the vertex and 2 sections around @@ -1574,7 +1622,7 @@ void CMap::modifyHeightReduce(Position pos) { // vertex count for the points int X, Y; - MapNode* tempP = &map->getVertex(pos.x, pos.y); + EditorMapNode* tempP = &map->getVertex(pos.x, pos.y); // this is to setup the building depending on the vertices around std::array tempVertices; calculateVerticesAround(tempVertices, pos); @@ -1584,17 +1632,17 @@ void CMap::modifyHeightReduce(Position pos) even = true; // DO IT - if(tempP->z <= triangleIncrease * (MinReduceHeight - 0x0A)) // user specified minimum reached + if(tempP->z <= HEIGHT_FACTOR * (MinReduceHeight - 0x0A)) // user specified minimum reached return; - if(tempP->z <= triangleIncrease * (0x00 - 0x0A)) // minimum reached (0x00 is min) + if(tempP->z <= HEIGHT_FACTOR * (0x00 - 0x0A)) // minimum reached (0x00 is min) return; - tempP->y += triangleIncrease; - tempP->z -= triangleIncrease; + tempP->y += HEIGHT_FACTOR; + tempP->z -= HEIGHT_FACTOR; tempP->h -= 0x01; CSurface::update_shading(*map, pos); - // after (5*triangleIncrease) pixel all vertices around will be reduced too + // after (5*HEIGHT_FACTOR) pixel all vertices around will be reduced too // update first vertex left upside X = pos.x - (even ? 1 : 0); if(X < 0) @@ -1604,7 +1652,7 @@ void CMap::modifyHeightReduce(Position pos) Y += map->height; // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * triangleIncrease)) //-V807 + if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) //-V807 modifyHeightReduce(Position(X, Y)); // update second vertex right upside X = pos.x + (even ? 0 : 1); @@ -1615,7 +1663,7 @@ void CMap::modifyHeightReduce(Position pos) Y += map->height; // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * triangleIncrease)) + if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) modifyHeightReduce(Position(X, Y)); // update third point bottom left X = pos.x - 1; @@ -1624,7 +1672,7 @@ void CMap::modifyHeightReduce(Position pos) Y = pos.y; // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * triangleIncrease)) + if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) modifyHeightReduce(Position(X, Y)); // update fourth point bottom right X = pos.x + 1; @@ -1633,7 +1681,7 @@ void CMap::modifyHeightReduce(Position pos) Y = pos.y; // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * triangleIncrease)) + if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) modifyHeightReduce(Position(X, Y)); // update fifth point down left X = pos.x - (even ? 1 : 0); @@ -1644,7 +1692,7 @@ void CMap::modifyHeightReduce(Position pos) Y -= map->height; // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * triangleIncrease)) + if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) modifyHeightReduce(Position(X, Y)); // update sixth point down right X = pos.x + (even ? 0 : 1); @@ -1655,7 +1703,7 @@ void CMap::modifyHeightReduce(Position pos) Y -= map->height; // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * triangleIncrease)) + if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) modifyHeightReduce(Position(X, Y)); // at least setup the possible building and shading at the vertex and 2 sections around @@ -1682,7 +1730,7 @@ void CMap::modifyHeightMakeBigHouse(Position pos) std::array tempVertices; calculateVerticesAround(tempVertices, pos); - MapNode& middleVertex = map->getVertex(pos.x, pos.y); + EditorMapNode& middleVertex = map->getVertex(pos.x, pos.y); Uint8 height = middleVertex.h; // calculate the building using the height of the vertices @@ -1690,7 +1738,7 @@ void CMap::modifyHeightMakeBigHouse(Position pos) // test the whole section for(int i = 0; i < 6; i++) { - MapNode& vertex = map->getVertex(tempVertices[i]); + EditorMapNode& vertex = map->getVertex(tempVertices[i]); for(int j = height - vertex.h; j >= 0x04; --j) modifyHeightRaise(tempVertices[i]); @@ -1699,7 +1747,7 @@ void CMap::modifyHeightMakeBigHouse(Position pos) } // test vertex lower right - MapNode& vertex = map->getVertex(tempVertices[6]); + EditorMapNode& vertex = map->getVertex(tempVertices[6]); for(int j = height - vertex.h; j >= 0x04; --j) modifyHeightRaise(tempVertices[6]); @@ -1711,7 +1759,7 @@ void CMap::modifyHeightMakeBigHouse(Position pos) // test the whole section for(int i = 7; i < 19; i++) { - MapNode& vertex = map->getVertex(tempVertices[i]); + EditorMapNode& vertex = map->getVertex(tempVertices[i]); for(int j = height - vertex.h; j >= 0x03; --j) modifyHeightRaise(tempVertices[i]); @@ -1733,7 +1781,7 @@ void CMap::modifyShading(Position pos) // this is to setup the shading depending on the vertices around (2 sections from the cursor) std::array tempVertices; calculateVerticesAround(tempVertices, pos); - MapNode& middleVertex = map->getVertex(pos.x, pos.y); + EditorMapNode& middleVertex = map->getVertex(pos.x, pos.y); // shading stakes int A, B, C, D, Result; @@ -1813,7 +1861,7 @@ void CMap::modifyTexture(Position pos, bool rsu, bool usd) void CMap::modifyTextureMakeHarbour(Position pos) { - MapNode& vertex = map->getVertex(pos.x, pos.y); + EditorMapNode& vertex = map->getVertex(pos.x, pos.y); const auto* desc = getTerrainDesc(*map, vertex.rsuTexture); if(desc && desc->kind == TerrainKind::Land && desc->Is(ETerrain::Buildable)) { @@ -1823,7 +1871,7 @@ void CMap::modifyTextureMakeHarbour(Position pos) void CMap::modifyObject(Position pos) { - MapNode& curVertex = map->getVertex(pos.x, pos.y); + EditorMapNode& curVertex = map->getVertex(pos.x, pos.y); if(mode == EDITOR_MODE_CUT) { // prevent cutting a player position @@ -2011,9 +2059,9 @@ void CMap::modifyBuild(Position pos) /// 0x00 sondern 0x68) Uint8 building; - MapNode& curVertex = map->getVertex(pos.x, pos.y); + EditorMapNode& curVertex = map->getVertex(pos.x, pos.y); const Uint8 height = curVertex.h; - std::array mapVertices; + std::array mapVertices; for(unsigned i = 0; i < mapVertices.size(); i++) mapVertices[i] = &map->getVertex(tempVertices[i]); @@ -2100,7 +2148,7 @@ void CMap::modifyBuild(Position pos) { for(int i = 1; i < 7; i++) { - const MapNode& vertexI = *mapVertices[i]; + const EditorMapNode& vertexI = *mapVertices[i]; if(vertexI.objectInfo == 0xC4 // tree || vertexI.objectInfo == 0xC5 // tree || vertexI.objectInfo == 0xC6 // tree @@ -2182,8 +2230,8 @@ void CMap::modifyResource(Position pos) // at first save all vertices we need to check std::array tempVertices; calculateVerticesAround(tempVertices, pos); - MapNode& curVertex = map->getVertex(pos.x, pos.y); - std::array mapVertices; + EditorMapNode& curVertex = map->getVertex(pos.x, pos.y); + std::array mapVertices; for(unsigned i = 0; i < mapVertices.size(); i++) mapVertices[i] = &map->getVertex(tempVertices[i]); @@ -2267,7 +2315,7 @@ void CMap::modifyPlayer(Position pos) bool PlayerRePositioned = false; int oldPositionX = 0; int oldPositionY = 0; - MapNode& vertex = map->getVertex(pos.x, pos.y); + EditorMapNode& vertex = map->getVertex(pos.x, pos.y); // set player position if(mode == EDITOR_MODE_FLAG) diff --git a/CMap.h b/CMap.h index b0d6b62..5c8bc7e 100644 --- a/CMap.h +++ b/CMap.h @@ -6,6 +6,7 @@ #pragma once #include "CSurface.h" +#include "EditorWorld.h" #include "defines.h" #include #include @@ -34,7 +35,7 @@ struct SavedVertex // Using int due to signed arithmetic used later static constexpr int NODES_PER_DIR = MAX_CHANGE_SECTION + 10 + 2; static constexpr size_t NUM_NODES = NODES_PER_DIR * 2 + 1; - using PointArray = std::array, NUM_NODES>; + using PointArray = std::array, NUM_NODES>; // Use a unique pointer to not create huge stack arrays ArrayPtr PointsArroundVertex; }; @@ -47,6 +48,7 @@ class CMap private: boost::filesystem::path filepath_; std::unique_ptr map; + std::unique_ptr terrainWorld_; DisplayRectangle displayRect; bool active; Position Vertex_; @@ -137,6 +139,7 @@ class CMap int getModeContent() const { return modeContent; } int getModeContent2() const { return modeContent2; } bobMAP* getMap() { return map.get(); } + EditorWorld* getTerrainWorld() { return terrainWorld_.get(); } /// Render terrain directly with OpenGL, then draw editor UI chrome. /// Should be called from the main render loop with the correct GL projection set. void render(); diff --git a/CSurface.cpp b/CSurface.cpp index f105062..c555764 100644 --- a/CSurface.cpp +++ b/CSurface.cpp @@ -87,7 +87,7 @@ void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobM Uint16 width = myMap.width; Uint16 height = myMap.height; auto type = myMap.type; - MapNode tempP1, tempP2, tempP3; + EditorMapNode tempP1, tempP2, tempP3; // min size to avoid underflows if(width < 8 || height < 8) @@ -106,10 +106,10 @@ void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobM { // IMPORTANT: integer values like +8 or -1 are for tolerance to beware of high triangles are not shown - int row_start = std::max(0, displayRect.top / triangleHeight - 1); - int row_end = std::min(height, displayRect.bottom / triangleHeight + 2); - int col_start = std::max(0, displayRect.left / triangleWidth - 1); - int col_end = std::min(width, displayRect.right / triangleWidth + 2); + int row_start = std::max(0, displayRect.top / TR_H - 1); + int row_end = std::min(height, displayRect.bottom / TR_H + 2); + int col_start = std::max(0, displayRect.left / TR_W - 1); + int col_end = std::min(width, displayRect.right / TR_W + 2); bool view_outside_edges; if(k > 0) @@ -122,22 +122,22 @@ void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobM // at first call DrawTriangle for all triangles up or down outside if(displayRect.top < 0) { - row_start = std::max(0, height - 1 - (-displayRect.top / triangleHeight) - 1); + row_start = std::max(0, height - 1 - (-displayRect.top / TR_H) - 1); row_end = height - 1; view_outside_edges = true; } else if(displayRect.bottom > myMap.height_pixel) { row_start = 0; - row_end = (displayRect.bottom - myMap.height_pixel) / triangleHeight + 8; + row_end = (displayRect.bottom - myMap.height_pixel) / TR_H + 8; view_outside_edges = true; - } else if(displayRect.top <= 2 * triangleHeight) + } else if(displayRect.top <= 2 * TR_H) { // this is for draw triangles that are reduced under the lower map edge (have bigger y-coords as // myMap.height_pixel) row_start = height - 3; row_end = height - 1; view_outside_edges = true; - } else if(displayRect.bottom >= (myMap.height_pixel - 8 * triangleHeight)) + } else if(displayRect.bottom >= (myMap.height_pixel - 8 * TR_H)) { // this is for draw triangles that are raised over the upper map edge (have negative y-coords) row_start = 0; @@ -151,10 +151,10 @@ void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobM // now call DrawTriangle for all triangles left or right outside if(displayRect.left <= 0) { - col_start = std::max(0, width - 1 - (-displayRect.left / triangleWidth) - 1); + col_start = std::max(0, width - 1 - (-displayRect.left / TR_W) - 1); col_end = width - 1; view_outside_edges = true; - } else if(displayRect.left < triangleWidth) + } else if(displayRect.left < TR_W) { col_start = width - 2; col_end = width - 1; @@ -162,7 +162,7 @@ void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobM } else if(displayRect.right > myMap.width_pixel) { col_start = 0; - col_end = (displayRect.right - myMap.width_pixel) / triangleWidth + 1; + col_end = (displayRect.right - myMap.width_pixel) / TR_W + 1; view_outside_edges = true; } } @@ -196,7 +196,7 @@ void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobM } // last UpSideDown tempP3 = myMap.getVertex(0, y); - tempP3.x = myMap.getVertex(width - 1, y).x + triangleWidth; + tempP3.x = myMap.getVertex(width - 1, y).x + TR_W; DrawTriangle(displayRect, myMap, type, myMap.getVertex(width - 1, y + 1), myMap.getVertex(width - 1, y), tempP3); } else @@ -212,14 +212,14 @@ void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobM } // last RightSideUp tempP3 = myMap.getVertex(0, y + 1); - tempP3.x = myMap.getVertex(width - 1, y + 1).x + triangleWidth; + tempP3.x = myMap.getVertex(width - 1, y + 1).x + TR_W; DrawTriangle(displayRect, myMap, type, myMap.getVertex(width - 1, y), myMap.getVertex(width - 1, y + 1), tempP3); // last UpSideDown tempP1 = myMap.getVertex(0, y + 1); - tempP1.x = myMap.getVertex(width - 1, y + 1).x + triangleWidth; + tempP1.x = myMap.getVertex(width - 1, y + 1).x + TR_W; tempP3 = myMap.getVertex(0, y); - tempP3.x = myMap.getVertex(width - 1, y).x + triangleWidth; + tempP3.x = myMap.getVertex(width - 1, y).x + TR_W; DrawTriangle(displayRect, myMap, type, tempP1, myMap.getVertex(width - 1, y), tempP3); } } @@ -229,13 +229,13 @@ void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobM { // RightSideUp tempP2 = myMap.getVertex(x, 0); - tempP2.y = height * triangleHeight + myMap.getVertex(x, 0).y; + tempP2.y = height * TR_H + myMap.getVertex(x, 0).y; tempP3 = myMap.getVertex(x + 1, 0); - tempP3.y = height * triangleHeight + myMap.getVertex(x + 1, 0).y; + tempP3.y = height * TR_H + myMap.getVertex(x + 1, 0).y; DrawTriangle(displayRect, myMap, type, myMap.getVertex(x, height - 1), tempP2, tempP3); // UpSideDown tempP1 = myMap.getVertex(x + 1, 0); - tempP1.y = height * triangleHeight + myMap.getVertex(x + 1, 0).y; + tempP1.y = height * TR_H + myMap.getVertex(x + 1, 0).y; DrawTriangle(displayRect, myMap, type, tempP1, myMap.getVertex(x, height - 1), myMap.getVertex(x + 1, height - 1)); } @@ -243,17 +243,17 @@ void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobM // last RightSideUp tempP2 = myMap.getVertex(width - 1, 0); - tempP2.y += height * triangleHeight; + tempP2.y += height * TR_H; tempP3 = myMap.getVertex(0, 0); - tempP3.x = myMap.getVertex(width - 1, 0).x + triangleWidth; - tempP3.y += height * triangleHeight; + tempP3.x = myMap.getVertex(width - 1, 0).x + TR_W; + tempP3.y += height * TR_H; DrawTriangle(displayRect, myMap, type, myMap.getVertex(width - 1, height - 1), tempP2, tempP3); // last UpSideDown tempP1 = myMap.getVertex(0, 0); - tempP1.x = myMap.getVertex(width - 1, 0).x + triangleWidth; - tempP1.y += height * triangleHeight; + tempP1.x = myMap.getVertex(width - 1, 0).x + TR_W; + tempP1.y += height * TR_H; tempP3 = myMap.getVertex(0, height - 1); - tempP3.x = myMap.getVertex(width - 1, height - 1).x + triangleWidth; + tempP3.x = myMap.getVertex(width - 1, height - 1).x + TR_W; DrawTriangle(displayRect, myMap, type, tempP1, myMap.getVertex(width - 1, height - 1), tempP3); } } @@ -326,10 +326,10 @@ bool GetAdjustedPoints(const DisplayRectangle& displayRect, const bobMAP& myMap, p3.x -= myMap.width_pixel; triangle_shown = true; } - } else if(displayRect.left < triangleWidth) + } else if(displayRect.left < TR_W) { int outside_left = displayRect.left; - int outside_right = displayRect.left + triangleWidth; + int outside_right = displayRect.left + TR_W; if(isInRange(p1.x - myMap.width_pixel, outside_left, outside_right) || isInRange(p2.x - myMap.width_pixel, outside_left, outside_right) || isInRange(p3.x - myMap.width_pixel, outside_left, outside_right)) @@ -684,8 +684,8 @@ void CSurface::GetTerrainTextureCoords(MapType mapType, TriangleTerrainType text } } -void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& myMap, MapType type, const MapNode& P1, - const MapNode& P2, const MapNode& P3) +void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& myMap, MapType type, const EditorMapNode& P1, + const EditorMapNode& P2, const EditorMapNode& P3) { Point32 p1(P1.x, P1.y); Point32 p2(P2.x, P2.y); @@ -738,7 +738,7 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m const float vertCoord[3][2] = { {float(p1.x), float(p1.y)}, {float(p2.x), float(p2.y)}, {float(p3.x), float(p3.y)}}; - const MapNode* verts[3] = {&P1, &P2, &P3}; + const EditorMapNode* verts[3] = {&P1, &P2, &P3}; // --- palette animation: any terrain with palAnimIdx >= 0 --- if(const auto* terrainDesc = getTerrainDesc(myMap, texture); terrainDesc && terrainDesc->palAnimIdx >= 0) @@ -800,7 +800,7 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m { // left upper / right lower edge - therefore get the usd-texture from left to compare Uint16 col = (P1.VertexX - 1 < 0 ? myMap.width - 1 : P1.VertexX - 1); - MapNode tempP = myMap.getVertex(col, P1.VertexY); + EditorMapNode tempP = myMap.getVertex(col, P1.VertexY); Rect BorderRect; auto borderSide = CalcBorders(myMap, tempP.usdTexture, P1.rsuTexture, BorderRect); @@ -841,7 +841,7 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m if(borderSide != BorderPreference::None) { Uint16 col = (P1.VertexX - 1 < 0 ? myMap.width - 1 : P1.VertexX - 1); - MapNode tempP = myMap.getVertex(col, P1.VertexY); + EditorMapNode tempP = myMap.getVertex(col, P1.VertexY); Point16 tmpP1{p1}, tmpP2{p2}; Point32 thirdPt; @@ -873,7 +873,7 @@ void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& m // top / bottom - therefore get the rsu-texture one line above to compare Uint16 row = (P2.VertexY - 1 < 0 ? myMap.height - 1 : P2.VertexY - 1); Uint16 col = (P2.VertexY % 2 == 0 ? P2.VertexX : (P2.VertexX + 1 > myMap.width - 1 ? 0 : P2.VertexX + 1)); - MapNode tempP = myMap.getVertex(col, row); + EditorMapNode tempP = myMap.getVertex(col, row); borderSide = CalcBorders(myMap, tempP.rsuTexture, P2.usdTexture, BorderRect); if(borderSide != BorderPreference::None) @@ -1144,7 +1144,7 @@ void CSurface::get_nodeVectors(bobMAP& myMap) get_flatVector(myMap.getVertex(i, j), myMap.getVertex(i, j + 1), myMap.getVertex(i + 1, j + 1)); // vector of last triangle - tempP3.x = myMap.getVertex(width - 1, j + 1).x + triangleWidth; + tempP3.x = myMap.getVertex(width - 1, j + 1).x + TR_W; tempP3.y = myMap.getVertex(0, j + 1).y; tempP3.z = myMap.getVertex(0, j + 1).z; myMap.getVertex(width - 1, j).flatVector = @@ -1155,16 +1155,16 @@ void CSurface::get_nodeVectors(bobMAP& myMap) for(int i = 0; i < width - 1; i++) { tempP2 = myMap.getVertex(i, 0); - tempP2.y += height * triangleHeight; + tempP2.y += height * TR_H; tempP3 = myMap.getVertex(i + 1, 0); - tempP3.y += height * triangleHeight; + tempP3.y += height * TR_H; myMap.getVertex(i, height - 1).flatVector = get_flatVector(myMap.getVertex(i, height - 1), tempP2, tempP3); } // vector of last Triangle tempP2 = myMap.getVertex(width - 1, 0); - tempP2.y += height * triangleHeight; - tempP3.x = myMap.getVertex(width - 1, 0).x + triangleWidth; - tempP3.y = height * triangleHeight + myMap.getVertex(0, 0).y; + tempP2.y += height * TR_H; + tempP3.x = myMap.getVertex(width - 1, 0).x + TR_W; + tempP3.y = height * TR_H + myMap.getVertex(0, 0).y; tempP3.z = myMap.getVertex(0, 0).z; myMap.getVertex(width - 1, height - 1).flatVector = get_flatVector(myMap.getVertex(width - 1, height - 1), tempP2, tempP3); @@ -1176,7 +1176,7 @@ void CSurface::get_nodeVectors(bobMAP& myMap) { for(int i = 0; i < width; i++) { - MapNode& curVertex = myMap.getVertex(i, j); + EditorMapNode& curVertex = myMap.getVertex(i, j); int iM1 = (i == 0 ? width - 1 : i - 1); if(j == 0) // first line curVertex.normVector = @@ -1191,7 +1191,7 @@ void CSurface::get_nodeVectors(bobMAP& myMap) { for(int i = 0; i < width; i++) { - MapNode& curVertex = myMap.getVertex(i, j); + EditorMapNode& curVertex = myMap.getVertex(i, j); int iP1 = (i + 1 == width ? 0 : i + 1); curVertex.normVector = get_nodeVector(myMap.getVertex(i, j - 1).flatVector, @@ -1329,7 +1329,7 @@ void CSurface::update_shading(bobMAP& myMap, Position pos) void CSurface::update_flatVectors(bobMAP& myMap, Position pos) { // point structures for the triangles, Pmiddle is the point in the middle of the hexagon we will update - MapNode *P1, *P2, *P3, *Pmiddle; + EditorMapNode *P1, *P2, *P3, *Pmiddle; // vertex count for the points int P1x, P1y, P2x, P2y, P3x, P3y; @@ -1399,7 +1399,7 @@ void CSurface::update_nodeVector(bobMAP& myMap, Position pos) if(j % 2 == 0) { - MapNode& curVertex = myMap.getVertex(i, j); + EditorMapNode& curVertex = myMap.getVertex(i, j); int iM1 = (i == 0 ? width - 1 : i - 1); if(j == 0) // first line curVertex.normVector = get_nodeVector(myMap.getVertex(iM1, height - 1).flatVector, @@ -1410,7 +1410,7 @@ void CSurface::update_nodeVector(bobMAP& myMap, Position pos) curVertex.i = get_LightIntensity(curVertex.normVector); } else { - MapNode& curVertex = myMap.getVertex(i, j); + EditorMapNode& curVertex = myMap.getVertex(i, j); int iP1 = (i + 1 == width ? 0 : i + 1); curVertex.normVector = get_nodeVector(myMap.getVertex(i, j - 1).flatVector, diff --git a/CSurface.h b/CSurface.h index 8f2dd11..3c5b911 100644 --- a/CSurface.h +++ b/CSurface.h @@ -17,8 +17,8 @@ class CSurface static void DrawTriangleField(const DisplayRectangle& displayRect, const bobMAP& myMap); /// Draw a single triangle given its three vertices. - static void DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& myMap, MapType type, const MapNode& P1, - const MapNode& P2, const MapNode& P3); + static void DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& myMap, MapType type, const EditorMapNode& P1, + const EditorMapNode& P2, const EditorMapNode& P3); static void get_nodeVectors(bobMAP& myMap); static void update_shading(bobMAP& myMap, Position pos); diff --git a/EditorWorld.h b/EditorWorld.h new file mode 100644 index 0000000..f90b1f2 --- /dev/null +++ b/EditorWorld.h @@ -0,0 +1,54 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "EditorWorldLoader.h" +#include "EventManager.h" +#include "GlobalGameSettings.h" +#include "PlayerInfo.h" +#include "RttrForeachPt.h" +#include "globals.h" +#include "lua/GameDataLoader.h" +#include "notifications/NodeNote.h" +#include "world/GameWorld.h" +#include "world/GameWorldViewer.h" +#include "gameData/MapConsts.h" + +class EditorWorld +{ + EventManager em_; + GlobalGameSettings ggs_; + GameWorld world_; + std::unique_ptr viewer_; + +public: + EditorWorld(const MapExtent& size, unsigned numPlayers) + : em_(0), world_(std::vector(numPlayers), ggs_, em_) + { + world_.GetDescriptionWriteable() = global::worldDesc; + loadTexturesForEditorWorld(global::gameDataFilePath.string()); + world_.Init(size); + RTTR_FOREACH_PT(MapPoint, size) + world_.GetNodeWriteable(pt).fow[0].visibility = Visibility::Visible; + world_.InitAfterLoad(); + viewer_ = std::make_unique(0, world_); + viewer_->InitTerrainRenderer(); + } + + GameWorld& getWorld() { return world_; } + const GameWorld& getWorld() const { return world_; } + GameWorldViewer& getViewer() { return *viewer_; } + const GameWorldViewer& getViewer() const { return *viewer_; } + + void notifyChanged(MapPoint pt) + { + world_.GetNotifications().publish(NodeNote(NodeNote::Altitude, pt)); + } + + void draw(const Position& firstPt, const Position& lastPt) const + { + viewer_->GetTerrainRenderer().Draw(firstPt, lastPt, *viewer_, nullptr); + } +}; diff --git a/EditorWorldLoader.cpp b/EditorWorldLoader.cpp new file mode 100644 index 0000000..b015ac5 --- /dev/null +++ b/EditorWorldLoader.cpp @@ -0,0 +1,25 @@ +#include "EditorWorldLoader.h" +#include "Loader.h" +#include "libsiedler2/Archiv.h" +#include "libsiedler2/ArchivItem_Bitmap.h" +#include "libsiedler2/libsiedler2.h" +#include "ogl/glArchivItem_Bitmap.h" +#include "ogl/glAllocator.h" +#include "resources/ResourceId.h" +#include + +void loadTexturesForEditorWorld(const std::string& gameDataPath) +{ + static bool initDone = false; + if(initDone) return; + initDone = true; + + libsiedler2::setAllocator(new GlAllocator()); + + const std::string texFiles[] = {"GFX/TEXTURES/TEX5.LBM", "GFX/TEXTURES/TEX6.LBM", "GFX/TEXTURES/TEX7.LBM"}; + for(const auto& f : texFiles) { + auto path = boost::filesystem::path(gameDataPath) / f; + if(boost::filesystem::exists(path)) + LOADER.Load(path, nullptr); + } +} diff --git a/EditorWorldLoader.h b/EditorWorldLoader.h new file mode 100644 index 0000000..19b78e6 --- /dev/null +++ b/EditorWorldLoader.h @@ -0,0 +1,3 @@ +#pragma once +#include +void loadTexturesForEditorWorld(const std::string& gameDataPath); diff --git a/callbacks.cpp b/callbacks.cpp index 601e26f..c7d4174 100644 --- a/callbacks.cpp +++ b/callbacks.cpp @@ -7,9 +7,11 @@ #include "CDebug.h" #include "CGame.h" #include "CIO/CButton.h" +#include "WindowManager.h" +#include "dskMainMenu.h" #include "CIO/CFile.h" #include "CIO/CFont.h" -#include "CIO/CMenu.h" + #include "CIO/CMinimapWindow.h" #include "CIO/CPicture.h" #include "CIO/CSelectBox.h" @@ -131,469 +133,10 @@ void callback::ShowStatus(int Param) } } -void callback::mainmenu(int Param) -{ - static CMenu* MainMenu = nullptr; - - enum - { - ENDGAME = 1, - STARTEDITOR, - LOADMAP, - OPTIONS - }; - - switch(Param) - { - case INITIALIZING_CALL: - MainMenu = global::s2->RegisterMenu(std::make_unique(SPLASHSCREEN_MAINMENU, ArchiveID::SETUP010)); - MainMenu->addButton(mainmenu, ENDGAME, Position(50, 400), Extent(200, 20), BUTTON_RED1, "Quit program"); - MainMenu->addButton(mainmenu, STARTEDITOR, Position(50, 160), Extent(200, 20), BUTTON_RED1, "Start editor"); - MainMenu->addButton(mainmenu, LOADMAP, Position(50, 200), Extent(200, 20), BUTTON_GREEN2, "Load map"); -#ifdef _ADMINMODE - MainMenu->addButton(submenu1, INITIALIZING_CALL, Position(50, 240), Extent(200, 20), BUTTON_GREY, - "Submenu_1"); -#endif - MainMenu->addButton(mainmenu, OPTIONS, Position(50, 370), Extent(200, 20), BUTTON_GREEN2, "Options"); - break; - - case CALL_FROM_GAMELOOP: break; - - case ENDGAME: - assert(MainMenu); - MainMenu->setWaste(); - MainMenu = nullptr; - global::s2->Running = false; - break; - - case STARTEDITOR: global::s2->enterEditor(""); break; - - case LOADMAP: EditorLoadMenu(INITIALIZING_CALL); break; - - case OPTIONS: - assert(MainMenu); - MainMenu->setWaste(); - MainMenu = nullptr; - submenuOptions(INITIALIZING_CALL); - - default: break; - } -} - -void callback::submenuOptions(int Param) -{ - static CMenu* SubMenu = nullptr; - static CFont* TextResolution = nullptr; - static CButton* ButtonFullscreen = nullptr; - static CSelectBox* SelectBoxRes = nullptr; - - enum - { - MAINMENU = 1, - FULLSCREEN, - GRAPHICS_CHANGE, - SELECTBOX_800_600, - SELECTBOX_832_624, - SELECTBOX_960_540, - SELECTBOX_964_544, - SELECTBOX_960_640, - SELECTBOX_960_720, - SELECTBOX_1024_576, - SELECTBOX_1024_600, - SELECTBOX_1072_600, - SELECTBOX_1152_768, - SELECTBOX_1024_768, - SELECTBOX_1152_864, - SELECTBOX_1152_870, - SELECTBOX_1152_900, - SELECTBOX_1200_800, - SELECTBOX_1200_900, - SELECTBOX_1280_720, - SELECTBOX_1280_768, - SELECTBOX_1280_800, - SELECTBOX_1280_854, - SELECTBOX_1360_768, - SELECTBOX_1366_768, - SELECTBOX_1376_768, - SELECTBOX_1400_900, - SELECTBOX_1440_900, - SELECTBOX_1440_960, - SELECTBOX_1280_960, - SELECTBOX_1280_1024, - SELECTBOX_1360_1024, - SELECTBOX_1366_1024, - SELECTBOX_1600_768, - SELECTBOX_1600_900, - SELECTBOX_1600_1024, - SELECTBOX_1400_1050, - SELECTBOX_1680_1050, - SELECTBOX_1600_1200, - SELECTBOX_1920_1080, - SELECTBOX_1920_1200, - SELECTBOX_1920_1400, - SELECTBOX_1920_1440, - SELECTBOX_2048_1152, - SELECTBOX_2048_1536, - SELECTBOX_3840_2160 - }; - - switch(Param) - { - case INITIALIZING_CALL: - SubMenu = global::s2->RegisterMenu(std::make_unique(SPLASHSCREEN_SUBMENU3, ArchiveID::SETUP013)); - // add button for "back to main menu" - SubMenu->addButton(submenuOptions, MAINMENU, Position(global::s2->GameResolution.x / 2 - 100, 440), - Extent(200, 20), BUTTON_RED1, "back"); - // add menu title - SubMenu->addText("Options", Position(global::s2->GameResolution.x / 2 - 20, 10), FontSize::Large); - // add screen resolution - if(TextResolution) - SubMenu->delText(TextResolution); - TextResolution = SubMenu->addText( - helpers::format("Game Resolution: %d*%d / %s", global::s2->GameResolution.x, global::s2->GameResolution.y, - (global::s2->fullscreen ? "Fullscreen" : "Window")), - Position(global::s2->GameResolution.x / 2 - 110, 50), FontSize::Medium); - if(ButtonFullscreen) - SubMenu->delButton(ButtonFullscreen); - ButtonFullscreen = - SubMenu->addButton(submenuOptions, FULLSCREEN, Position(global::s2->GameResolution.x / 2 - 100, 410), - Extent(200, 20), BUTTON_RED1, (global::s2->fullscreen ? "WINDOW" : "FULLSCREEN")); - SelectBoxRes = SubMenu->addSelectBox(ButtonFullscreen->getPos() - Position(0, 340), Extent(200, 330), - FontSize::Medium, FontColor::Yellow, BUTTON_GREY); - SelectBoxRes->addOption("800 x 600 (SVGA)", submenuOptions, SELECTBOX_800_600); - SelectBoxRes->addOption("832 x 624 (Half Megapixel)", submenuOptions, SELECTBOX_832_624); - SelectBoxRes->addOption("960 x 540 (QHD)", submenuOptions, SELECTBOX_960_540); - SelectBoxRes->addOption("964 x 544", submenuOptions, SELECTBOX_964_544); - SelectBoxRes->addOption("960 x 640 (DVGA)", submenuOptions, SELECTBOX_960_640); - SelectBoxRes->addOption("960 x 720", submenuOptions, SELECTBOX_960_720); - SelectBoxRes->addOption("1024 x 576 (WXGA)", submenuOptions, SELECTBOX_1024_576); - SelectBoxRes->addOption("1024 x 600 (WSVGA)", submenuOptions, SELECTBOX_1024_600); - SelectBoxRes->addOption("1072 x 600 (WSVGA)", submenuOptions, SELECTBOX_1072_600); - SelectBoxRes->addOption("1152 x 768", submenuOptions, SELECTBOX_1152_768); - SelectBoxRes->addOption("1024 x 768 (EVGA)", submenuOptions, SELECTBOX_1024_768); - SelectBoxRes->addOption("1152 x 864 (XGA)", submenuOptions, SELECTBOX_1152_864); - SelectBoxRes->addOption("1152 x 870 (XGA)", submenuOptions, SELECTBOX_1152_870); - SelectBoxRes->addOption("1152 x 900 (XGA)", submenuOptions, SELECTBOX_1152_900); - SelectBoxRes->addOption("1200 x 800 (DSVGA)", submenuOptions, SELECTBOX_1200_800); - SelectBoxRes->addOption("1200 x 900 (OLPC)", submenuOptions, SELECTBOX_1200_900); - SelectBoxRes->addOption("1280 x 720 (720p)", submenuOptions, SELECTBOX_1280_720); - SelectBoxRes->addOption("1280 x 768 (WXGA)", submenuOptions, SELECTBOX_1280_768); - SelectBoxRes->addOption("1280 x 800 (WXGA)", submenuOptions, SELECTBOX_1280_800); - SelectBoxRes->addOption("1280 x 854 (WXGA)", submenuOptions, SELECTBOX_1280_854); - SelectBoxRes->addOption("1360 x 768 (WXGA)", submenuOptions, SELECTBOX_1360_768); - SelectBoxRes->addOption("1366 x 768 (WXGA)", submenuOptions, SELECTBOX_1366_768); - SelectBoxRes->addOption("1376 x 768 (WXGA)", submenuOptions, SELECTBOX_1376_768); - SelectBoxRes->addOption("1400 x 900 (WXGA+)", submenuOptions, SELECTBOX_1400_900); - SelectBoxRes->addOption("1440 x 900 (WXGA+)", submenuOptions, SELECTBOX_1440_900); - SelectBoxRes->addOption("1440 x 960", submenuOptions, SELECTBOX_1440_960); - SelectBoxRes->addOption("1280 x 960 (SXGA)", submenuOptions, SELECTBOX_1280_960); - SelectBoxRes->addOption("1280 x 1024 (SXGA)", submenuOptions, SELECTBOX_1280_1024); - SelectBoxRes->addOption("1360 x 1024 (XGA-2)", submenuOptions, SELECTBOX_1360_1024); - SelectBoxRes->addOption("1366 x 1024 (XGA-2)", submenuOptions, SELECTBOX_1366_1024); - SelectBoxRes->addOption("1600 x 768 (UWXGA)", submenuOptions, SELECTBOX_1600_768); - SelectBoxRes->addOption("1600 x 900 (WSXGA)", submenuOptions, SELECTBOX_1600_900); - SelectBoxRes->addOption("1600 x 1024 (WSXGA)", submenuOptions, SELECTBOX_1600_1024); - SelectBoxRes->addOption("1400 x 1050 (SXGA+)", submenuOptions, SELECTBOX_1400_1050); - SelectBoxRes->addOption("1680 x 1050 (WSXGA+)", submenuOptions, SELECTBOX_1680_1050); - SelectBoxRes->addOption("1600 x 1200 (UXGA)", submenuOptions, SELECTBOX_1600_1200); - SelectBoxRes->addOption("1920 x 1080 (1080p)", submenuOptions, SELECTBOX_1920_1080); - SelectBoxRes->addOption("1920 x 1200 (WUXGA)", submenuOptions, SELECTBOX_1920_1200); - SelectBoxRes->addOption("1920 x 1400 (TXGA)", submenuOptions, SELECTBOX_1920_1400); - SelectBoxRes->addOption("1920 x 1440", submenuOptions, SELECTBOX_1920_1440); - SelectBoxRes->addOption("2048 x 1152 (QWXGA)", submenuOptions, SELECTBOX_2048_1152); - SelectBoxRes->addOption("2048 x 1536 (SUXGA)", submenuOptions, SELECTBOX_2048_1536); - SelectBoxRes->addOption("3840 x 2160 (4K UHD)", submenuOptions, SELECTBOX_3840_2160); - break; - - case MAINMENU: - assert(SubMenu); - SubMenu->setWaste(); - TextResolution = nullptr; - ButtonFullscreen = nullptr; - SelectBoxRes = nullptr; - SubMenu = nullptr; - mainmenu(INITIALIZING_CALL); - break; - - case FULLSCREEN: - global::s2->fullscreen = !global::s2->fullscreen; - - submenuOptions(GRAPHICS_CHANGE); - break; - - case GRAPHICS_CHANGE: - assert(SubMenu); - global::s2->ApplyWindowChanges(); - global::s2->SaveSettings(); - SubMenu->setWaste(); - TextResolution = nullptr; - ButtonFullscreen = nullptr; - SelectBoxRes = nullptr; - SubMenu = nullptr; - submenuOptions(INITIALIZING_CALL); - break; - - case SELECTBOX_800_600: - global::s2->GameResolution.x = 800; - global::s2->GameResolution.y = 600; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_832_624: - global::s2->GameResolution.x = 832; - global::s2->GameResolution.y = 624; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_960_540: - global::s2->GameResolution.x = 960; - global::s2->GameResolution.y = 540; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_964_544: - global::s2->GameResolution.x = 964; - global::s2->GameResolution.y = 544; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_960_640: - global::s2->GameResolution.x = 960; - global::s2->GameResolution.y = 640; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_960_720: - global::s2->GameResolution.x = 960; - global::s2->GameResolution.y = 720; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1024_576: - global::s2->GameResolution.x = 1024; - global::s2->GameResolution.y = 576; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1024_600: - global::s2->GameResolution.x = 1024; - global::s2->GameResolution.y = 600; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1072_600: - global::s2->GameResolution.x = 1072; - global::s2->GameResolution.y = 600; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1152_768: - global::s2->GameResolution.x = 1152; - global::s2->GameResolution.y = 768; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1024_768: - global::s2->GameResolution.x = 1024; - global::s2->GameResolution.y = 768; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1152_864: - global::s2->GameResolution.x = 1152; - global::s2->GameResolution.y = 864; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1152_870: - global::s2->GameResolution.x = 1152; - global::s2->GameResolution.y = 870; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1152_900: - global::s2->GameResolution.x = 1152; - global::s2->GameResolution.y = 900; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1200_800: - global::s2->GameResolution.x = 1200; - global::s2->GameResolution.y = 800; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1200_900: - global::s2->GameResolution.x = 1200; - global::s2->GameResolution.y = 900; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1280_720: - global::s2->GameResolution.x = 1280; - global::s2->GameResolution.y = 720; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1280_768: - global::s2->GameResolution.x = 1280; - global::s2->GameResolution.y = 768; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1280_800: - global::s2->GameResolution.x = 1280; - global::s2->GameResolution.y = 800; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1280_854: - global::s2->GameResolution.x = 1280; - global::s2->GameResolution.y = 854; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1360_768: - global::s2->GameResolution.x = 1360; - global::s2->GameResolution.y = 768; - submenuOptions(GRAPHICS_CHANGE); - break; - case SELECTBOX_1366_768: - global::s2->GameResolution.x = 1366; - global::s2->GameResolution.y = 768; - submenuOptions(GRAPHICS_CHANGE); - break; - case SELECTBOX_1376_768: - global::s2->GameResolution.x = 1376; - global::s2->GameResolution.y = 768; - submenuOptions(GRAPHICS_CHANGE); - break; - case SELECTBOX_1400_900: - global::s2->GameResolution.x = 1400; - global::s2->GameResolution.y = 900; - submenuOptions(GRAPHICS_CHANGE); - break; - case SELECTBOX_1440_900: - global::s2->GameResolution.x = 1440; - global::s2->GameResolution.y = 900; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1440_960: - global::s2->GameResolution.x = 1440; - global::s2->GameResolution.y = 960; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1280_960: - global::s2->GameResolution.x = 1280; - global::s2->GameResolution.y = 960; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1280_1024: - global::s2->GameResolution.x = 1280; - global::s2->GameResolution.y = 1024; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1360_1024: - global::s2->GameResolution.x = 1360; - global::s2->GameResolution.y = 1024; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1366_1024: - global::s2->GameResolution.x = 1366; - global::s2->GameResolution.y = 1024; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1600_768: - global::s2->GameResolution.x = 1600; - global::s2->GameResolution.y = 768; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1600_900: - global::s2->GameResolution.x = 1600; - global::s2->GameResolution.y = 900; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1600_1024: - global::s2->GameResolution.x = 1600; - global::s2->GameResolution.y = 1024; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1400_1050: - global::s2->GameResolution.x = 1400; - global::s2->GameResolution.y = 1050; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1680_1050: - global::s2->GameResolution.x = 1680; - global::s2->GameResolution.y = 1050; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1600_1200: - global::s2->GameResolution.x = 1600; - global::s2->GameResolution.y = 1200; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1920_1080: - global::s2->GameResolution.x = 1920; - global::s2->GameResolution.y = 1080; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1920_1200: - global::s2->GameResolution.x = 1920; - global::s2->GameResolution.y = 1200; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1920_1400: - global::s2->GameResolution.x = 1920; - global::s2->GameResolution.y = 1400; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_1920_1440: - global::s2->GameResolution.x = 1920; - global::s2->GameResolution.y = 1440; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_2048_1152: - global::s2->GameResolution.x = 2048; - global::s2->GameResolution.y = 1152; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_2048_1536: - global::s2->GameResolution.x = 2048; - global::s2->GameResolution.y = 1536; - submenuOptions(GRAPHICS_CHANGE); - break; - - case SELECTBOX_3840_2160: - global::s2->GameResolution.x = 3840; - global::s2->GameResolution.y = 2160; - submenuOptions(GRAPHICS_CHANGE); - break; - - default: break; - } -} // now the editor callbacks will follow @@ -617,7 +160,7 @@ void callback::EditorHelpMenu(int Param) WINDOW_CLOSE | WINDOW_MOVE | WINDOW_RESIZE | WINDOW_MINIMIZE, ArchiveID::EDITIO)); SelectBoxHelp = WNDHelp->addSelectBox(Position(0, 0), Extent(WNDHelp->getSize() - WNDHelp->getBorderSize()), - FontSize::Medium, FontColor::Yellow, BUTTON_GREEN1); + FontSize::Normal, FontColor::Yellow, BUTTON_GREEN1); SelectBoxHelp->addOption("User map path: " + global::userMapsPath.string()); SelectBoxHelp->addOption(""); SelectBoxHelp->addOption("Help-Menu........................................................................" @@ -774,7 +317,7 @@ void callback::EditorLoadMenu(int Param) WNDLoad = global::s2->RegisterWindow( std::make_unique(EditorLoadMenu, WINDOWQUIT, WindowPos::Center, Extent(280, 320), "Load", WINDOW_GREEN1, WINDOW_CLOSE | WINDOW_MOVE | WINDOW_RESIZE)); - CB_Filename = WNDLoad->addSelectBox(Position(10, 5), Extent(160, 280), FontSize::Medium); + CB_Filename = WNDLoad->addSelectBox(Position(10, 5), Extent(160, 280), FontSize::Normal); curFilename.clear(); for(const auto& itFile : bfs::directory_iterator(global::userMapsPath)) { @@ -1023,7 +566,7 @@ void callback::EditorQuitMenu(int Param) EditorPlayerMenu(MAP_QUIT); EditorCreateMenu(MAP_QUIT); // go to main menu - mainmenu(INITIALIZING_CALL); + WINDOWMANAGER.Switch(std::make_unique()); break; case NOTBACKTOMAIN: @@ -1890,7 +1433,7 @@ void callback::EditorPlayerMenu(int Param) { tempRect = MapObj->getDisplayRect(); tempRect.setOrigin(Position(PlayerHQx[PlayerIdx], PlayerHQy[PlayerIdx]) - * Position(triangleWidth, triangleHeight) + * Position(TR_W, TR_H) - tempRect.getSize() / 2); MapObj->setDisplayRect(tempRect); } @@ -2922,7 +2465,7 @@ void callback::MinimapMenu(int Param) displayRect.setOrigin( (mouse - WNDMinimap->getRect().getOrigin() - Position(6, 20) - Texture::getTexture(ArchiveID::MAP00, MAPPIC_ARROWCROSS_ORANGE).anchor()) - * Position(triangleWidth, triangleHeight) * scaleNum); + * Position(TR_W, TR_H) * scaleNum); MapObj->setDisplayRect(displayRect); } } @@ -2972,261 +2515,8 @@ void callback::debugger(int Param) } } -// this is a submenu for testing +// this is a submenu for testing (removed) void callback::submenu1(int Param) { - static CMenu* SubMenu = nullptr; - static CButton* greatMoon = nullptr; - static CFont* greatMoonText = nullptr; - static CFont* counterText = nullptr; - static CPicture* picObject = nullptr; - static int counter = 0; - static CWindow* testWindow = nullptr; - static CWindow* testWindow2 = nullptr; - static CPicture* testWindowPicture = nullptr; - static CFont* testWindowText = nullptr; - static CFont* testWindowText2 = nullptr; - static CTextfield* testTextfield = nullptr; - static CFont* TextFrom_testTextfield = nullptr; - static CTextfield* testTextfield_testWindow = nullptr; - static CSelectBox* testSelectBox = nullptr; - - static int picIndex = -1; - - // if this is the first time the function is called - if(Param == INITIALIZING_CALL) - global::s2->RegisterCallback(submenu1); - - enum - { - MAINMENU = 1, - GREATMOON, - SMALLMOON, - TOOSMALL, - CREATEWINDOW, - GREATMOONENTRY, - GREATMOONLEAVE, - PICOBJECT, - PICOBJECTENTRY, - PICOBJECTLEAVE, - TESTWINDOWPICTURE, - TESTWINDOWPICTUREENTRY, - TESTWINDOWPICTURELEAVE, - TESTWINDOWQUITMESSAGE, - TESTWINDOW2QUITMESSAGE, - SELECTBOX_OPTION1, - SELECTBOX_OPTION2, - SELECTBOX_OPTION3 - }; - - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - { - assert(SubMenu); - } - - switch(Param) - { - case INITIALIZING_CALL: - SubMenu = global::s2->RegisterMenu(std::make_unique(SPLASHSCREEN_SUBMENU1, ArchiveID::SETUP011)); - SubMenu->addButton(submenu1, MAINMENU, Position(400, 440), Extent(200, 20), BUTTON_RED1, "back"); - greatMoon = SubMenu->addButton(submenu1, GREATMOON, Position(100, 100), Extent(200, 200), BUTTON_STONE, - nullptr, MOON); - greatMoon->setMotionParams(GREATMOONENTRY, GREATMOONLEAVE); - SubMenu->addButton(submenu1, SMALLMOON, Position(100, 350), - Extent(static_cast(global::getBitmapSize(ArchiveID::EDITRES, MOON).x), - static_cast(global::getBitmapSize(ArchiveID::EDITRES, MOON).y)), - BUTTON_STONE, nullptr, MOON); - SubMenu->addButton(submenu1, TOOSMALL, Position(100, 400), - Extent(static_cast(global::getBitmapSize(ArchiveID::EDITRES, MOON).x) - 1, - static_cast(global::getBitmapSize(ArchiveID::EDITRES, MOON).y) - 1), - BUTTON_STONE, nullptr, MOON); - SubMenu->addButton(submenu1, CREATEWINDOW, Position(500, 10), Extent(130, 30), BUTTON_GREEN1, - "Create window"); - picObject = SubMenu->addPicture(submenu1, PICOBJECT, Position(200, 30), ArchiveID::MIS0BOBS, MIS0BOBS_SHIP); - picObject->setMotionParams(PICOBJECTENTRY, PICOBJECTLEAVE); - SubMenu->addText("Textblock", Position(400, 200), FontSize::Large); - testTextfield = SubMenu->addTextfield(Position(400, 300), 10, 3); - testSelectBox = SubMenu->addSelectBox(Position(500, 500), Extent(300, 200)); - testSelectBox->addOption("Erste Option", submenu1, SELECTBOX_OPTION1); - testSelectBox->addOption("Zweite Option", submenu1, SELECTBOX_OPTION2); - testSelectBox->addOption("Dritte Option", submenu1, SELECTBOX_OPTION3); - break; - - case MAINMENU: - SubMenu->setWaste(); - SubMenu = nullptr; - greatMoon = nullptr; - greatMoonText = nullptr; - counterText = nullptr; - testWindowPicture = nullptr; - testWindowText = nullptr; - testWindowText2 = nullptr; - testTextfield = nullptr; - TextFrom_testTextfield = nullptr; - testTextfield_testWindow = nullptr; - testSelectBox = nullptr; - global::s2->UnregisterCallback(submenu1); - if(testWindow) - { - testWindow->setWaste(); - testWindow = nullptr; - } - if(testWindow2) - { - testWindow2->setWaste(); - testWindow2 = nullptr; - } - picIndex = -1; - break; - - case GREATMOON: - SubMenu->addText("Title!", Position(300, 10), FontSize::Large); - SubMenu->addText( - helpers::format("Window X: %d Window Y: %d", global::s2->GameResolution.x, global::s2->GameResolution.y), - Position(10, 10), FontSize::Large); - break; - - case SMALLMOON: - SubMenu->delButton(greatMoon); - SubMenu->delStaticPicture(picIndex); - picIndex = -1; - break; - - case TOOSMALL: - if(picIndex == -1) - picIndex = SubMenu->addStaticPicture(Position(0, 0), ArchiveID::EDITRES, MAINFRAME_640_480); - break; - - case CREATEWINDOW: - if(!testWindow) - { - testWindow = global::s2->RegisterWindow(std::make_unique( - submenu1, TESTWINDOWQUITMESSAGE, Position(5, 5), Extent(350, 240), "Window", WINDOW_GREEN1, - WINDOW_CLOSE | WINDOW_MOVE | WINDOW_MINIMIZE | WINDOW_RESIZE)); - testWindow->addText("Text inside the window", Position(10, 10), FontSize::Large); - testWindow->addButton(submenu1, -10, Position(150, 100), Extent(210, 30), BUTTON_GREEN2, - "Button inside the window"); - testWindowPicture = testWindow->addPicture(submenu1, TESTWINDOWPICTURE, Position(10, 60), - ArchiveID::MIS2BOBS, MIS2BOBS_FORTRESS); - testWindowPicture->setMotionParams(TESTWINDOWPICTUREENTRY, TESTWINDOWPICTURELEAVE); - testTextfield_testWindow = testWindow->addTextfield(Position(130, 30), 10, 3, FontSize::Large, - FontColor::Red, BUTTON_GREY, true); - testTextfield_testWindow->setText( - "This is a very long test text in order to destroy the text field completely once and for all"); - } - if(!testWindow2) - { - testWindow2 = global::s2->RegisterWindow(std::make_unique( - submenu1, TESTWINDOW2QUITMESSAGE, Position(200, 5), Extent(350, 240), "Another Window", WINDOW_GREEN1, - WINDOW_CLOSE | WINDOW_MOVE | WINDOW_MINIMIZE | WINDOW_RESIZE)); - testWindow2->addText("Text inside the window", Position(50, 40), FontSize::Small); - testWindow2->addButton(submenu1, -10, Position(100, 100), Extent(100, 20), BUTTON_GREEN2, "Button"); - } - break; - - case GREATMOONENTRY: - if(!greatMoonText) - greatMoonText = SubMenu->addText("Test-Text", Position(100, 10), FontSize::Large); - break; - - case GREATMOONLEAVE: - if(greatMoonText) - { - SubMenu->delText(greatMoonText); - greatMoonText = nullptr; - } - break; - - case PICOBJECT: - if(greatMoon) - { - SubMenu->delButton(greatMoon); - greatMoon = nullptr; - } - break; - - case PICOBJECTENTRY: - if(!greatMoonText) - greatMoonText = SubMenu->addText("Test-Text", Position(100, 10), FontSize::Large); - break; - - case PICOBJECTLEAVE: - if(greatMoonText) - { - SubMenu->delText(greatMoonText); - greatMoonText = nullptr; - } - break; - - case TESTWINDOWPICTURE: - assert(testWindow); - if(!testWindowText) - testWindowText = testWindow->addText("Clicked on castle", Position(10, 200), FontSize::Medium); - else - { - testWindow->delText(testWindowText); - testWindowText = nullptr; - } - break; - - case TESTWINDOWPICTUREENTRY: - assert(testWindow); - if(testWindowText2) - { - testWindow->delText(testWindowText2); - testWindowText2 = nullptr; - } - testWindowText2 = testWindow->addText("Bildbereich betreten", Position(10, 220), FontSize::Medium); - break; - - case TESTWINDOWPICTURELEAVE: - assert(testWindow); - if(testWindowText2) - { - testWindow->delText(testWindowText2); - testWindowText2 = nullptr; - } - testWindowText2 = testWindow->addText("Bildbereich verlassen", Position(10, 220), FontSize::Medium); - break; - - case TESTWINDOWQUITMESSAGE: - assert(testWindow); - testWindow->setWaste(); - testWindow = nullptr; - break; - - case TESTWINDOW2QUITMESSAGE: - assert(testWindow2); - testWindow2->setWaste(); - testWindow2 = nullptr; - break; - - case CALL_FROM_GAMELOOP: - if(counter % 10 == 0) - { - if(counterText) - { - if(SubMenu->delText(counterText)) - counterText = nullptr; - } - if(!counterText) - { - counterText = - SubMenu->addText(helpers::format("counter: %d", counter), Position(100, 20), FontSize::Small); - } - - if(TextFrom_testTextfield) - { - SubMenu->delText(TextFrom_testTextfield); - TextFrom_testTextfield = nullptr; - } - TextFrom_testTextfield = SubMenu->addText("Der Text im Textfeld lautet: " + testTextfield->getText(), - Position(200, 400), FontSize::Large); - } - counter++; - break; - - default: break; - } } #endif diff --git a/callbacks.h b/callbacks.h index fee5926..3413f93 100644 --- a/callbacks.h +++ b/callbacks.h @@ -17,8 +17,7 @@ namespace callback { // "Please wait..." void PleaseWait(int Param); void ShowStatus(int Param); -void mainmenu(int Param); -void submenuOptions(int Param); + void MinimapMenu(int Param); void EditorHelpMenu(int Param); void EditorMainMenu(int Param); @@ -36,6 +35,6 @@ void EditorCursorMenu(int Param); #ifdef _ADMINMODE void debugger(int Param); -void submenu1(int Param); + #endif } // namespace callback diff --git a/dskEditorInterface.cpp b/dskEditorInterface.cpp new file mode 100644 index 0000000..2023c4a --- /dev/null +++ b/dskEditorInterface.cpp @@ -0,0 +1,208 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dskEditorInterface.h" +#include "CGame.h" +#include "EditorWorld.h" +#include "Loader.h" +#include "WindowManager.h" +#include "controls/ctrlButton.h" +#include "defines.h" +#include "driver/MouseCoords.h" +#include "drivers/VideoDriverWrapper.h" +#include "dskMainMenu.h" +#include "globals.h" +#include "ogl/glArchivItem_Bitmap.h" +#include "s25util/colors.h" +#include + +dskEditorInterface::dskEditorInterface(std::unique_ptr world) + : Desktop(nullptr), world_(std::move(world)) +{ + AddTextButton(ID_btQuitEditor, DrawPoint(10, 10), Extent(100, 22), TextureColor::Red1, + "Main menu", NormalFont); + + // Bottom menubar tool buttons — invisible border, icon drawn by control + const auto screenSize = VIDEODRIVER.GetRenderSize(); + const int cx = static_cast(screenSize.x / 2); + auto addTool = [&](unsigned id, int texIdx, int xOff) { + auto* img = LOADER.GetImageN("editio", texIdx); + if(!img) return; + AddImageButton(id, DrawPoint(cx + xOff, screenSize.y - 36), Extent(37, 32), + TextureColor::Invisible, img, "")->SetBorder(false); + }; + addTool(ID_btToolHeightRaise, MENUBAR_HEIGHT, -236); + addTool(ID_btToolTexture, MENUBAR_TEXTURE, -199); + addTool(ID_btToolTree, MENUBAR_TREE, -162); + addTool(ID_btToolResource, MENUBAR_RESOURCE, -125); + addTool(ID_btToolLandscape, MENUBAR_LANDSCAPE, -88); + addTool(ID_btToolAnimal, MENUBAR_ANIMAL, -51); + addTool(ID_btToolPlayer, MENUBAR_PLAYER, -14); + addTool(ID_btToolCut, MENUBAR_BUILDHELP, 92); + addTool(ID_btToolFlag, MENUBAR_MINIMAP, 129); + addTool(ID_btToolHeightReduce,MENUBAR_NEWWORLD, 166); + addTool(ID_btToolSettings, MENUBAR_COMPUTER, 203); + + // Right menubar: Load/Save buttons + const int rx = static_cast(screenSize.x); + const int ry = static_cast(screenSize.y) / 2; + AddImageButton(ID_btRLoad, DrawPoint(rx - 36, ry + 163), Extent(32, 37), + TextureColor::Invisible, + LOADER.GetImageN("editio", MENUBAR_BUGKILL), "")->SetBorder(false); + AddImageButton(ID_btRSave, DrawPoint(rx - 36, ry + 200), Extent(32, 37), + TextureColor::Invisible, + LOADER.GetImageN("editio", MENUBAR_BUGKILL), "")->SetBorder(false); +} + +dskEditorInterface::~dskEditorInterface() = default; + +void dskEditorInterface::Msg_PaintBefore() +{ + Desktop::Msg_PaintBefore(); + + if(!world_) + return; + + const auto screenSize = VIDEODRIVER.GetRenderSize(); + const int w = static_cast(screenSize.x); + const int h = static_cast(screenSize.y); + + // ── Terrain ── + { + Position firstPt(0, 0); + Position lastPt( + std::min(world_->getWorld().GetWidth() - 1, screenSize.x / 56 + 2), + std::min(world_->getWorld().GetHeight() - 1, screenSize.y / 28 + 2)); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); glLoadIdentity(); + glOrtho(0, screenSize.x, screenSize.y, 0, -100, 100); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); glLoadIdentity(); + world_->draw(firstPt, lastPt); + glMatrixMode(GL_PROJECTION); glPopMatrix(); + glMatrixMode(GL_MODELVIEW); glPopMatrix(); + } + + // ── Editor frame (glArchivItem_Bitmap from "editres") ── + auto* frameTex = LOADER.GetImageN("editres", MAINFRAME_640_480); + if(!frameTex) return; + + if(w == 640 && h == 480) + frameTex->DrawFull(DrawPoint(0, 0)); + else if(w == 800 && h == 600) + LOADER.GetImageN("editres", MAINFRAME_800_600)->DrawFull(DrawPoint(0, 0)); + else if(w == 1024 && h == 768) + LOADER.GetImageN("editres", MAINFRAME_1024_768)->DrawFull(DrawPoint(0, 0)); + else if(w == 1280 && h == 1024) + { + LOADER.GetImageN("editres", MAINFRAME_LEFT_1280_1024)->DrawFull(DrawPoint(0, 0)); + LOADER.GetImageN("editres", MAINFRAME_RIGHT_1280_1024)->DrawFull(DrawPoint(640, 0)); + } else + { + // Corners + frameTex->Draw(Rect(0, 0, 150, 150), Rect(0, 0, 150, 150), COLOR_WHITE); + frameTex->Draw(Rect(0, h - 150, 150, 150), Rect(0, 480 - 150, 150, 150), COLOR_WHITE); + frameTex->Draw(Rect(w - 150, 0, 150, 150), Rect(640 - 150, 0, 150, 150), COLOR_WHITE); + frameTex->Draw(Rect(w - 150, h - 150, 150, 150), Rect(640 - 150, 480 - 150, 150, 150), COLOR_WHITE); + // Top/bottom edges + for(unsigned x = 150; x + 150 < static_cast(w); x += 150) + { + frameTex->Draw(Rect(static_cast(x), 0, 150, 12), Rect(150, 0, 150, 12), COLOR_WHITE); + frameTex->Draw(Rect(static_cast(x), h - 12, 150, 12), Rect(150, 0, 150, 12), COLOR_WHITE); + } + // Left/right edges + for(unsigned y = 150; y + 150 < static_cast(h); y += 150) + { + frameTex->Draw(Rect(0, static_cast(y), 12, 150), Rect(0, 150, 12, 150), COLOR_WHITE); + frameTex->Draw(Rect(w - 12, static_cast(y), 12, 150), Rect(0, 150, 12, 150), COLOR_WHITE); + } + } + + // Corner statues — DrawPart with (0,0) offset to match old Texture::draw(Position) + auto drawStat = [&](int idx, int x, int y) { + auto* img = LOADER.GetImageN("editres", idx); + if(!img) return; + auto sz = img->GetSize(); + img->DrawPart(Rect(x, y, sz.x, sz.y), DrawPoint(0, 0)); + }; + drawStat(STATUE_UP_LEFT, 12, 12); + drawStat(STATUE_UP_RIGHT, w - static_cast(LOADER.GetImageN("editres", STATUE_UP_RIGHT)->GetSize().x) - 12, 12); + drawStat(STATUE_DOWN_LEFT, 12, h - static_cast(LOADER.GetImageN("editres", STATUE_DOWN_LEFT)->GetSize().y) - 12); + drawStat(STATUE_DOWN_RIGHT, w - static_cast(LOADER.GetImageN("editres", STATUE_DOWN_RIGHT)->GetSize().x) - 12, + h - static_cast(LOADER.GetImageN("editres", STATUE_DOWN_RIGHT)->GetSize().y) - 12); + + // ── Menubars ── + const int cx = w / 2; + auto* menubar = LOADER.GetImageN("editres", MENUBAR); + if(!menubar) return; + auto mbSz = menubar->GetSize(); + + // Bottom menubar — top-left origin + menubar->DrawPart(Rect((w - mbSz.x) / 2, h - mbSz.y, mbSz.x, mbSz.y), DrawPoint(0, 0)); + + // Slot backgrounds from "editio" + auto* slotBg = LOADER.GetImageN("editio", BUTTON_GREEN1_DARK); + if(slotBg) + { + for(int xOff = -236; xOff <= -14; xOff += 37) + slotBg->Draw(Rect(cx + xOff, h - 36, 37, 32), Rect(0, 0, 37, 32), COLOR_WHITE); + for(int xOff = 92; xOff <= 203; xOff += 37) + slotBg->Draw(Rect(cx + xOff, h - 36, 37, 32), Rect(0, 0, 37, 32), COLOR_WHITE); + } + + // Right menubar (rotated) + { + const int rx = w; + const int ry = h / 2; + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glTranslatef(static_cast(rx - mbSz.y / 2 + 1), static_cast(ry + 2), 0.f); + glRotatef(270.f, 0.f, 0.f, 1.f); + menubar->DrawFull(Rect(-static_cast(mbSz.x) / 2, -static_cast(mbSz.y) / 2, mbSz.x, mbSz.y)); + glPopMatrix(); + + // Right menubar slots + if(slotBg) + { + for(int yOff : {-239, -202, -165, -128, -22, 15, 52, 89, 126, 163, 200}) + slotBg->Draw(Rect(rx - 36, ry + yOff, 32, 37), Rect(0, 0, 32, 37), COLOR_WHITE); + } + + // Right menubar arrow indicators drawn on top of slots + { + auto& texUp = Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP); + auto& texDn = Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN); + if(texUp.isValid() && texDn.isValid()) + { + texUp.draw(Position(rx - 33, ry - 237)); + texDn.draw(Position(rx - 20, ry - 235)); + texDn.draw(Position(rx - 33, ry - 220)); + texUp.draw(Position(rx - 20, ry - 220)); + } + } + } +} + +void dskEditorInterface::Draw_() +{ + Desktop::Draw_(); +} + +void dskEditorInterface::Msg_ButtonClick(unsigned ctrl_id) +{ + switch(ctrl_id) + { + case ID_btQuitEditor: + world_.reset(); + WINDOWMANAGER.Switch(std::make_unique()); + break; + } +} + +bool dskEditorInterface::Msg_LeftDown(const MouseCoords& mc) { return Desktop::Msg_LeftDown(mc); } +bool dskEditorInterface::Msg_LeftUp(const MouseCoords& mc) { return Desktop::Msg_LeftUp(mc); } +bool dskEditorInterface::Msg_MouseMove(const MouseCoords&) { return false; } +bool dskEditorInterface::Msg_KeyDown(const KeyEvent&) { return false; } +bool dskEditorInterface::Msg_WheelUp(const MouseCoords&) { return false; } +bool dskEditorInterface::Msg_WheelDown(const MouseCoords&) { return false; } diff --git a/dskEditorInterface.h b/dskEditorInterface.h new file mode 100644 index 0000000..0c3e32f --- /dev/null +++ b/dskEditorInterface.h @@ -0,0 +1,59 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "desktops/Desktop.h" +#include + +class EditorWorld; + +/// In-editor desktop — owns the map view, editor toolbar, and handles editor input. +/// Analogous to dskGameInterface in the game. +class dskEditorInterface : public Desktop +{ +public: + dskEditorInterface(std::unique_ptr world); + ~dskEditorInterface() override; + + void Msg_ButtonClick(unsigned ctrl_id) override; + void Msg_PaintBefore() override; + bool Msg_LeftDown(const MouseCoords& mc) override; + bool Msg_LeftUp(const MouseCoords& mc) override; + bool Msg_MouseMove(const MouseCoords& mc) override; + bool Msg_KeyDown(const KeyEvent& ke) override; + bool Msg_WheelUp(const MouseCoords& mc) override; + bool Msg_WheelDown(const MouseCoords& mc) override; + +protected: + void Draw_() override; + +private: + std::unique_ptr world_; + + enum ControlIds + { + ID_btQuitEditor, + ID_btSave, + ID_btLoad, + ID_btMinimap, + // Bottom toolbar + ID_btToolCut, + ID_btToolTree, + ID_btToolHeightRaise, + ID_btToolHeightReduce, + ID_btToolTexture, + ID_btToolLandscape, + ID_btToolFlag, + ID_btToolResource, + ID_btToolAnimal, + ID_btToolPlayer, + ID_btToolSettings, + ID_FIRST_TOOL = ID_btToolCut, + ID_LAST_TOOL = ID_btToolSettings, + // Right menubar + ID_btRLoad, + ID_btRSave, + }; +}; diff --git a/dskMainMenu.cpp b/dskMainMenu.cpp new file mode 100644 index 0000000..4b8efa3 --- /dev/null +++ b/dskMainMenu.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dskMainMenu.h" +#include "CGame.h" +#include "EditorWorld.h" +#include "Texture.h" +#include "WindowManager.h" +#include "callbacks.h" +#include "controls/ctrlButton.h" +#include "defines.h" +#include "dskEditorInterface.h" +#include "dskOptions.h" +#include "globals.h" + +dskMainMenu::dskMainMenu() + : Desktop(nullptr) +{ + AddTextButton(ID_btStartEditor, DrawPoint(50, 160), Extent(200, 22), TextureColor::Red1, "Start editor", + NormalFont); + AddTextButton(ID_btLoadMap, DrawPoint(50, 200), Extent(200, 22), TextureColor::Green2, "Load map", NormalFont); + AddTextButton(ID_btOptions, DrawPoint(50, 370), Extent(200, 22), TextureColor::Green2, "Options", NormalFont); + AddTextButton(ID_btQuit, DrawPoint(50, 400), Extent(200, 22), TextureColor::Red1, "Quit program", NormalFont); +} + +void dskMainMenu::Draw_() +{ + auto& bg = Texture::getTexture(ArchiveID::SETUP010, SPLASHSCREEN_MAINMENU); + if(bg.isValid()) + bg.draw(GetDrawRect()); + Desktop::Draw_(); +} + +void dskMainMenu::Msg_ButtonClick(unsigned ctrl_id) +{ + switch(ctrl_id) + { + case ID_btStartEditor: + { + // Create a blank EditorWorld (32x32 greenland) + auto world = std::make_unique(MapExtent(32, 32), 1); + WINDOWMANAGER.Switch(std::make_unique(std::move(world))); + break; + } + case ID_btLoadMap: + callback::EditorLoadMenu(INITIALIZING_CALL); + break; + case ID_btOptions: + WINDOWMANAGER.Switch(std::make_unique()); + break; + case ID_btQuit: + global::s2->Running = false; + break; + } +} diff --git a/dskMainMenu.h b/dskMainMenu.h new file mode 100644 index 0000000..b0434ac --- /dev/null +++ b/dskMainMenu.h @@ -0,0 +1,27 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "desktops/Desktop.h" + +class dskMainMenu : public Desktop +{ +public: + dskMainMenu(); + + void Msg_ButtonClick(unsigned ctrl_id) override; + +protected: + void Draw_() override; + +private: + enum ControlIds + { + ID_btStartEditor, + ID_btLoadMap, + ID_btOptions, + ID_btQuit + }; +}; diff --git a/dskOptions.cpp b/dskOptions.cpp new file mode 100644 index 0000000..f4abd5f --- /dev/null +++ b/dskOptions.cpp @@ -0,0 +1,93 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dskOptions.h" +#include "CGame.h" +#include "Texture.h" +#include "WindowManager.h" +#include "controls/ctrlButton.h" +#include "controls/ctrlList.h" +#include "controls/ctrlText.h" +#include "defines.h" +#include "dskMainMenu.h" +#include "globals.h" +#include "helpers/format.hpp" +#include "ogl/FontStyle.h" + +static constexpr std::pair resolutions[] = { + {800, 600}, {832, 624}, {960, 540}, {964, 544}, {960, 640}, {960, 720}, {1024, 576}, {1024, 600}, + {1072, 600}, {1152, 768}, {1024, 768}, {1152, 864}, {1152, 870}, {1152, 900}, {1200, 800}, {1200, 900}, + {1280, 720}, {1280, 768}, {1280, 800}, {1280, 854}, {1360, 768}, {1366, 768}, {1376, 768}, {1400, 900}, + {1440, 900}, {1440, 960}, {1280, 960}, {1280, 1024}, {1360, 1024}, {1366, 1024}, {1600, 768}, {1600, 900}, + {1600, 1024}, {1400, 1050},{1680, 1050},{1600, 1200}, {1920, 1080}, {1920, 1200}, {1920, 1400},{1920, 1440}, + {2048, 1152}, {2048, 1536},{3840, 2160}, +}; + +dskOptions::dskOptions() + : Desktop(nullptr) +{ + AddTextButton(ID_btBack, DrawPoint(global::s2->GameResolution.x / 2 - 100, 440), Extent(200, 22), + TextureColor::Red1, "back", NormalFont); + AddText(ID_txtResolution, DrawPoint(global::s2->GameResolution.x / 2, 10), "Options", COLOR_YELLOW, + FontStyle::CENTER, NormalFont); + AddTextButton(ID_btFullscreen, + DrawPoint(global::s2->GameResolution.x / 2 - 100, 410), Extent(200, 22), TextureColor::Red1, + global::s2->fullscreen ? "WINDOW" : "FULLSCREEN", NormalFont); + + auto* list = AddList(ID_lstResolution, DrawPoint(global::s2->GameResolution.x / 2 - 100, 80), + Extent(200, 310), TextureColor::Grey, NormalFont); + int selectedIdx = -1; + for(unsigned i = 0; i < sizeof(resolutions)/sizeof(resolutions[0]); ++i) + { + list->AddItem(helpers::format("%d x %d", resolutions[i].first, resolutions[i].second)); + if(static_cast(resolutions[i].first) == global::s2->GameResolution.x + && static_cast(resolutions[i].second) == global::s2->GameResolution.y) + selectedIdx = static_cast(i); + } + if(selectedIdx >= 0) + list->SetSelection(static_cast(selectedIdx)); +} + +void dskOptions::Draw_() +{ + auto& bg = Texture::getTexture(ArchiveID::SETUP013, SPLASHSCREEN_SUBMENU3); + if(bg.isValid()) + bg.draw(GetDrawRect()); + Desktop::Draw_(); +} + +void dskOptions::Msg_ButtonClick(unsigned ctrl_id) +{ + switch(ctrl_id) + { + case ID_btBack: + WINDOWMANAGER.Switch(std::make_unique()); + break; + case ID_btFullscreen: + global::s2->fullscreen = !global::s2->fullscreen; + global::s2->ApplyWindowChanges(); + global::s2->SaveSettings(); + WINDOWMANAGER.Switch(std::make_unique()); + break; + } +} + +void dskOptions::Msg_ListSelectItem(unsigned ctrl_id, int selection) +{ + if(ctrl_id != ID_lstResolution || selection < 0) + return; + const auto sel = static_cast(selection); + if(sel < sizeof(resolutions)/sizeof(resolutions[0])) + { + // Skip if same as current — avoids infinite loop from SetSelection in ctor + if(static_cast(resolutions[sel].first) == global::s2->GameResolution.x + && static_cast(resolutions[sel].second) == global::s2->GameResolution.y) + return; + global::s2->GameResolution.x = resolutions[sel].first; + global::s2->GameResolution.y = resolutions[sel].second; + global::s2->ApplyWindowChanges(); + global::s2->SaveSettings(); + WINDOWMANAGER.Switch(std::make_unique()); + } +} diff --git a/dskOptions.h b/dskOptions.h new file mode 100644 index 0000000..8a20146 --- /dev/null +++ b/dskOptions.h @@ -0,0 +1,28 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "desktops/Desktop.h" + +class dskOptions : public Desktop +{ +public: + dskOptions(); + + void Msg_ButtonClick(unsigned ctrl_id) override; + void Msg_ListSelectItem(unsigned ctrl_id, int selection) override; + +protected: + void Draw_() override; + +private: + enum ControlIds + { + ID_btBack, + ID_btFullscreen, + ID_lstResolution, + ID_txtResolution + }; +}; diff --git a/globals.cpp b/globals.cpp index ce98c72..c6d9112 100644 --- a/globals.cpp +++ b/globals.cpp @@ -148,6 +148,4 @@ boost::filesystem::path global::gameDataFilePath("."); boost::filesystem::path global::userMapsPath; WorldDescription global::worldDesc; -unsigned char triangleHeight = TRIANGLE_HEIGHT_DEFAULT; -unsigned char triangleWidth = TRIANGLE_WIDTH_DEFAULT; -unsigned char triangleIncrease = TRIANGLE_INCREASE_DEFAULT; + diff --git a/globals.h b/globals.h index 0292a1c..5f464d8 100644 --- a/globals.h +++ b/globals.h @@ -74,20 +74,5 @@ extern boost::filesystem::path userMapsPath; extern WorldDescription worldDesc; } // namespace global -extern unsigned char triangleHeight; -extern unsigned char triangleWidth; -extern unsigned char triangleIncrease; - -// Default / reset values for zoom -constexpr unsigned char TRIANGLE_HEIGHT_DEFAULT = 28; -constexpr unsigned char TRIANGLE_WIDTH_DEFAULT = 56; -constexpr unsigned char TRIANGLE_INCREASE_DEFAULT = 5; - -// Zoom step increments/decrements -constexpr unsigned char ZOOM_STEP_HEIGHT = 5; -constexpr unsigned char ZOOM_STEP_WIDTH = 11; -constexpr unsigned char ZOOM_STEP_INCREASE = 1; - -// Zoom boundaries (based on triangleIncrease) -constexpr unsigned char ZOOM_INCREASE_MAX = 9; -constexpr unsigned char ZOOM_INCREASE_MIN = 1; +#include "gameData/MapConsts.h" +// Triangle/zoom constants from s25main: TR_W=56, TR_H=28, HEIGHT_FACTOR=5 diff --git a/include/defines.h b/include/defines.h index f00636f..8405fea 100644 --- a/include/defines.h +++ b/include/defines.h @@ -8,6 +8,7 @@ #include "Point.h" #include "Rect.h" #include "gameData/DescIdx.h" +#include "Loader.h" #include #include #include @@ -97,7 +98,7 @@ struct MapHeaderItem Uint32 area; // number of vertices this area has }; // point structure -struct MapNode +struct EditorMapNode { Uint16 VertexX; /* number of the vertex on x-axis */ Uint16 VertexY; /* number of the vertex on y-axis */ @@ -155,11 +156,11 @@ struct bobMAP std::array HQy; // 250 items from the big map header std::array header; - std::vector vertex; - MapNode& getVertex(unsigned x, unsigned y) { return vertex[y * width + x]; } - MapNode& getVertex(Point32 pos) { return vertex[pos.y * width + pos.x]; } - const MapNode& getVertex(unsigned x, unsigned y) const { return vertex[y * width + x]; } - const MapNode& getVertex(Point32 pos) const { return vertex[pos.y * width + pos.x]; } + std::vector vertex; + EditorMapNode& getVertex(unsigned x, unsigned y) { return vertex[y * width + x]; } + EditorMapNode& getVertex(Point32 pos) { return vertex[pos.y * width + pos.x]; } + const EditorMapNode& getVertex(unsigned x, unsigned y) const { return vertex[y * width + x]; } + const EditorMapNode& getVertex(Point32 pos) const { return vertex[pos.y * width + pos.x]; } std::vector> s2IdToTerrain; // Initializes or updates the vertex indices and coordinates void initVertexCoords(); @@ -216,23 +217,26 @@ enum class FontColor }; constexpr unsigned NUM_FONT_COLORS = static_cast(FontColor::BrightRed) + 1u; -/// Font sizes with values equal to height in pixels -enum class FontSize +/// Map s25main FontSize to pixel heights used by the editor's font atlas +inline unsigned getFontHeightPx(FontSize size) { - Small = 9, - Medium = 11, - Large = 14 -}; + switch(size) + { + default: + case FontSize::Small: return 9; + case FontSize::Normal: return 11; + case FontSize::Large: return 14; + } +} /// Height of 1 line for the given font including vertical spacing inline unsigned getLineHeight(FontSize size) { - const auto fontSize = static_cast(size); switch(size) { default: - case FontSize::Small: return fontSize + 1; - case FontSize::Medium: return fontSize + 3; - case FontSize::Large: return fontSize + 4; + case FontSize::Small: return getFontHeightPx(size) + 1; + case FontSize::Normal: return getFontHeightPx(size) + 3; + case FontSize::Large: return getFontHeightPx(size) + 4; } } From 684491ccb35bd4563f3c8e8c0fe94e11f55beb46 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 09:25:21 +0200 Subject: [PATCH 06/16] VideoDriver migration --- EditorWorld.h | 33 ++++++++++++++++-- GameWorldEditor.cpp | 66 ++++++++++++++++++++++++++++++++++++ GameWorldEditor.h | 35 +++++++++++++++++++ dskEditorInterface.cpp | 51 +++++++++++++++------------- dskEditorInterface.h | 10 +++--- dskMainMenu.cpp | 4 +-- iwEditorMenu.cpp | 44 ++++++++++++++++++++++++ iwEditorMenu.h | 23 +++++++++++++ iwLoadMap.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++ iwLoadMap.h | 25 ++++++++++++++ iwSaveMap.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++ iwSaveMap.h | 28 ++++++++++++++++ 12 files changed, 438 insertions(+), 33 deletions(-) create mode 100644 GameWorldEditor.cpp create mode 100644 GameWorldEditor.h create mode 100644 iwEditorMenu.cpp create mode 100644 iwEditorMenu.h create mode 100644 iwLoadMap.cpp create mode 100644 iwLoadMap.h create mode 100644 iwSaveMap.cpp create mode 100644 iwSaveMap.h diff --git a/EditorWorld.h b/EditorWorld.h index f90b1f2..a62d78d 100644 --- a/EditorWorld.h +++ b/EditorWorld.h @@ -22,16 +22,38 @@ class EditorWorld GlobalGameSettings ggs_; GameWorld world_; std::unique_ptr viewer_; + std::string mapName_; + std::string author_; + boost::filesystem::path filepath_; public: EditorWorld(const MapExtent& size, unsigned numPlayers) - : em_(0), world_(std::vector(numPlayers), ggs_, em_) + : em_(0), world_(std::vector(numPlayers), ggs_, em_), + mapName_("Ohne Namen"), author_("Niemand") { world_.GetDescriptionWriteable() = global::worldDesc; loadTexturesForEditorWorld(global::gameDataFilePath.string()); world_.Init(size); + + // Look up terrain by s2Id (matching old CMap::generateMap defaults) + DescIdx meadow, water; + for(unsigned i = 0; i < global::worldDesc.terrain.size(); i++) + { + auto s2 = global::worldDesc.terrain.get(DescIdx(i)).s2Id; + if(s2 == 8) meadow = DescIdx(i); // TRIANGLE_TEXTURE_MEADOW1 + if(s2 == 5) water = DescIdx(i); // TRIANGLE_TEXTURE_WATER + } + int border = 4; RTTR_FOREACH_PT(MapPoint, size) - world_.GetNodeWriteable(pt).fow[0].visibility = Visibility::Visible; + { + auto& node = world_.GetNodeWriteable(pt); + node.fow[0].visibility = Visibility::Visible; + bool isBorder = (pt.x < border || pt.x >= size.x - border + || pt.y < border || pt.y >= size.y - border); + node.t1 = isBorder ? water : meadow; + node.t2 = isBorder ? water : meadow; + } + world_.InitAfterLoad(); viewer_ = std::make_unique(0, world_); viewer_->InitTerrainRenderer(); @@ -42,6 +64,13 @@ class EditorWorld GameWorldViewer& getViewer() { return *viewer_; } const GameWorldViewer& getViewer() const { return *viewer_; } + const std::string& getMapName() const { return mapName_; } + void setMapName(const std::string& name) { mapName_ = name; } + const std::string& getAuthor() const { return author_; } + void setAuthor(const std::string& author) { author_ = author; } + const boost::filesystem::path& getFilepath() const { return filepath_; } + void setFilepath(const boost::filesystem::path& fp) { filepath_ = fp; } + void notifyChanged(MapPoint pt) { world_.GetNotifications().publish(NodeNote(NodeNote::Altitude, pt)); diff --git a/GameWorldEditor.cpp b/GameWorldEditor.cpp new file mode 100644 index 0000000..6730d5b --- /dev/null +++ b/GameWorldEditor.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "GameWorldEditor.h" +#include "world/GameWorldViewer.h" +#include "world/GameWorld.h" +#include "gameData/MapConsts.h" +#include + +void GameWorldEditor::MoveBy(const DrawPoint& delta) +{ + offset_ += delta; + WrapOffset(); +} + +void GameWorldEditor::SetOffset(const DrawPoint& offset) +{ + offset_ = offset; + WrapOffset(); +} + +void GameWorldEditor::WrapOffset() +{ + // Wrap offset modulo map size — same as GameWorldView::MoveTo + DrawPoint size(world_.GetWidth() * TR_W, world_.GetHeight() * TR_H); + if(size.x && size.y) + { + offset_.x %= size.x; + offset_.y %= size.y; + if(offset_.x < 0) + offset_.x += size.x; + if(offset_.y < 0) + offset_.y += size.y; + } +} + +void GameWorldEditor::Draw(const Extent& screenSize) +{ + // Same tile range calculation as GameWorldView::CalcFxLx() + int firstX = offset_.x / TR_W - 1; + int firstY = offset_.y / TR_H - 1; + int lastX = (offset_.x + screenSize.x) / TR_W + 1; + int lastY = (offset_.y + screenSize.y + viewer_.getMaxNodeAltitude() * HEIGHT_FACTOR) / TR_H + 1; + + Position firstPt(firstX, firstY); + Position lastPt(lastX, lastY); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, screenSize.x, screenSize.y, 0, -100, 100); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + // Translate modelview to scroll position — same as GameWorldView + glTranslatef(static_cast(-offset_.x), static_cast(-offset_.y), 0.0f); + + viewer_.GetTerrainRenderer().Draw(firstPt, lastPt, viewer_, nullptr); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} diff --git a/GameWorldEditor.h b/GameWorldEditor.h new file mode 100644 index 0000000..adf6f93 --- /dev/null +++ b/GameWorldEditor.h @@ -0,0 +1,35 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "DrawPoint.h" +#include "Point.h" +#include + +#include "Point.h" + +class GameWorld; +class GameWorldViewer; + +/// Editor-specific world view — sibling of GameWorldView, no game cruft. +class GameWorldEditor +{ +public: + GameWorldEditor(GameWorldViewer& viewer, GameWorld& world, const DrawPoint& offset = DrawPoint(0, 0)) + : viewer_(viewer), world_(world), offset_(offset) {} + + void MoveBy(const DrawPoint& delta); + void SetOffset(const DrawPoint& offset); + DrawPoint GetOffset() const { return offset_; } + + void Draw(const Extent& screenSize); + +private: + void WrapOffset(); + + GameWorldViewer& viewer_; + GameWorld& world_; + DrawPoint offset_; +}; diff --git a/dskEditorInterface.cpp b/dskEditorInterface.cpp index 2023c4a..a6e4d16 100644 --- a/dskEditorInterface.cpp +++ b/dskEditorInterface.cpp @@ -5,8 +5,13 @@ #include "dskEditorInterface.h" #include "CGame.h" #include "EditorWorld.h" +#include "GameWorldEditor.h" #include "Loader.h" #include "WindowManager.h" +#include "callbacks.h" +#include "driver/KeyEvent.h" +#include "drivers/VideoDriverWrapper.h" +#include "iwEditorMenu.h" #include "controls/ctrlButton.h" #include "defines.h" #include "driver/MouseCoords.h" @@ -20,11 +25,11 @@ dskEditorInterface::dskEditorInterface(std::unique_ptr world) : Desktop(nullptr), world_(std::move(world)) { - AddTextButton(ID_btQuitEditor, DrawPoint(10, 10), Extent(100, 22), TextureColor::Red1, - "Main menu", NormalFont); + gwEditor_ = std::make_unique(world_->getViewer(), world_->getWorld()); - // Bottom menubar tool buttons — invisible border, icon drawn by control const auto screenSize = VIDEODRIVER.GetRenderSize(); + + // Bottom menubar tool buttons const int cx = static_cast(screenSize.x / 2); auto addTool = [&](unsigned id, int texIdx, int xOff) { auto* img = LOADER.GetImageN("editio", texIdx); @@ -42,7 +47,7 @@ dskEditorInterface::dskEditorInterface(std::unique_ptr world) addTool(ID_btToolCut, MENUBAR_BUILDHELP, 92); addTool(ID_btToolFlag, MENUBAR_MINIMAP, 129); addTool(ID_btToolHeightReduce,MENUBAR_NEWWORLD, 166); - addTool(ID_btToolSettings, MENUBAR_COMPUTER, 203); + addTool(ID_btEditorMenu, MENUBAR_COMPUTER, 203); // Right menubar: Load/Save buttons const int rx = static_cast(screenSize.x); @@ -68,21 +73,9 @@ void dskEditorInterface::Msg_PaintBefore() const int w = static_cast(screenSize.x); const int h = static_cast(screenSize.y); - // ── Terrain ── - { - Position firstPt(0, 0); - Position lastPt( - std::min(world_->getWorld().GetWidth() - 1, screenSize.x / 56 + 2), - std::min(world_->getWorld().GetHeight() - 1, screenSize.y / 28 + 2)); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); glLoadIdentity(); - glOrtho(0, screenSize.x, screenSize.y, 0, -100, 100); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); glLoadIdentity(); - world_->draw(firstPt, lastPt); - glMatrixMode(GL_PROJECTION); glPopMatrix(); - glMatrixMode(GL_MODELVIEW); glPopMatrix(); - } + // ── Terrain via GameWorldEditor ── + if(gwEditor_) + gwEditor_->Draw(VIDEODRIVER.GetRenderSize()); // ── Editor frame (glArchivItem_Bitmap from "editres") ── auto* frameTex = LOADER.GetImageN("editres", MAINFRAME_640_480); @@ -193,9 +186,8 @@ void dskEditorInterface::Msg_ButtonClick(unsigned ctrl_id) { switch(ctrl_id) { - case ID_btQuitEditor: - world_.reset(); - WINDOWMANAGER.Switch(std::make_unique()); + case ID_btEditorMenu: + WINDOWMANAGER.Show(std::make_unique()); break; } } @@ -203,6 +195,19 @@ void dskEditorInterface::Msg_ButtonClick(unsigned ctrl_id) bool dskEditorInterface::Msg_LeftDown(const MouseCoords& mc) { return Desktop::Msg_LeftDown(mc); } bool dskEditorInterface::Msg_LeftUp(const MouseCoords& mc) { return Desktop::Msg_LeftUp(mc); } bool dskEditorInterface::Msg_MouseMove(const MouseCoords&) { return false; } -bool dskEditorInterface::Msg_KeyDown(const KeyEvent&) { return false; } +bool dskEditorInterface::Msg_KeyDown(const KeyEvent& ke) +{ + // Arrow keys for scrolling (temporary until full map interaction is wired) + static constexpr int scrollSpeed = 20; + if(!gwEditor_) return false; + switch(ke.kt) + { + case KeyType::Left: gwEditor_->MoveBy(DrawPoint(-scrollSpeed, 0)); return true; + case KeyType::Right: gwEditor_->MoveBy(DrawPoint(scrollSpeed, 0)); return true; + case KeyType::Up: gwEditor_->MoveBy(DrawPoint(0, -scrollSpeed)); return true; + case KeyType::Down: gwEditor_->MoveBy(DrawPoint(0, scrollSpeed)); return true; + default: return false; + } +} bool dskEditorInterface::Msg_WheelUp(const MouseCoords&) { return false; } bool dskEditorInterface::Msg_WheelDown(const MouseCoords&) { return false; } diff --git a/dskEditorInterface.h b/dskEditorInterface.h index 0c3e32f..6dc7838 100644 --- a/dskEditorInterface.h +++ b/dskEditorInterface.h @@ -8,9 +8,8 @@ #include class EditorWorld; +class GameWorldEditor; -/// In-editor desktop — owns the map view, editor toolbar, and handles editor input. -/// Analogous to dskGameInterface in the game. class dskEditorInterface : public Desktop { public: @@ -31,6 +30,7 @@ class dskEditorInterface : public Desktop private: std::unique_ptr world_; + std::unique_ptr gwEditor_; enum ControlIds { @@ -38,7 +38,6 @@ class dskEditorInterface : public Desktop ID_btSave, ID_btLoad, ID_btMinimap, - // Bottom toolbar ID_btToolCut, ID_btToolTree, ID_btToolHeightRaise, @@ -49,10 +48,9 @@ class dskEditorInterface : public Desktop ID_btToolResource, ID_btToolAnimal, ID_btToolPlayer, - ID_btToolSettings, + ID_btEditorMenu, ID_FIRST_TOOL = ID_btToolCut, - ID_LAST_TOOL = ID_btToolSettings, - // Right menubar + ID_LAST_TOOL = ID_btEditorMenu, ID_btRLoad, ID_btRSave, }; diff --git a/dskMainMenu.cpp b/dskMainMenu.cpp index 4b8efa3..bab1658 100644 --- a/dskMainMenu.cpp +++ b/dskMainMenu.cpp @@ -7,12 +7,12 @@ #include "EditorWorld.h" #include "Texture.h" #include "WindowManager.h" -#include "callbacks.h" #include "controls/ctrlButton.h" #include "defines.h" #include "dskEditorInterface.h" #include "dskOptions.h" #include "globals.h" +#include "iwLoadMap.h" dskMainMenu::dskMainMenu() : Desktop(nullptr) @@ -44,7 +44,7 @@ void dskMainMenu::Msg_ButtonClick(unsigned ctrl_id) break; } case ID_btLoadMap: - callback::EditorLoadMenu(INITIALIZING_CALL); + WINDOWMANAGER.Show(std::make_unique()); break; case ID_btOptions: WINDOWMANAGER.Switch(std::make_unique()); diff --git a/iwEditorMenu.cpp b/iwEditorMenu.cpp new file mode 100644 index 0000000..b1c08ca --- /dev/null +++ b/iwEditorMenu.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwEditorMenu.h" +#include "CGame.h" +#include "WindowManager.h" +#include "controls/ctrlButton.h" +#include "iwLoadMap.h" +#include "iwSaveMap.h" +#include "defines.h" +#include "dskMainMenu.h" +#include "globals.h" +#include "Loader.h" + +iwEditorMenu::iwEditorMenu() + : IngameWindow(100, IngameWindow::posLastOrCenter, Extent(220, 320), "Main menu", + LOADER.GetImageN("resource", 41)) +{ + auto off = DrawPoint(contentOffset.x, contentOffset.y); + int cx = (GetSize().x - contentOffset.x - contentOffsetEnd.x) / 2 + contentOffset.x; + AddTextButton(ID_btLoad, DrawPoint(cx - 95, off.y + 100), Extent(190, 22), TextureColor::Green2, "Load map", NormalFont); + AddTextButton(ID_btSave, DrawPoint(cx - 95, off.y + 125), Extent(190, 22), TextureColor::Green2, "Save map", NormalFont); + AddTextButton(ID_btQuit, DrawPoint(cx - 95, off.y + 260), Extent(190, 22), TextureColor::Green2, "Leave editor", NormalFont); +} + +void iwEditorMenu::Msg_ButtonClick(unsigned ctrl_id) +{ + switch(ctrl_id) + { + case ID_btLoad: + Close(); + WINDOWMANAGER.Show(std::make_unique()); + break; + case ID_btSave: + Close(); + WINDOWMANAGER.Show(std::make_unique()); + break; + case ID_btQuit: + Close(); + WINDOWMANAGER.Switch(std::make_unique()); + break; + } +} diff --git a/iwEditorMenu.h b/iwEditorMenu.h new file mode 100644 index 0000000..8eb8cfc --- /dev/null +++ b/iwEditorMenu.h @@ -0,0 +1,23 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwEditorMenu : public IngameWindow +{ +public: + iwEditorMenu(); + + void Msg_ButtonClick(unsigned ctrl_id) override; + +private: + enum + { + ID_btLoad, + ID_btSave, + ID_btQuit + }; +}; diff --git a/iwLoadMap.cpp b/iwLoadMap.cpp new file mode 100644 index 0000000..0d107b5 --- /dev/null +++ b/iwLoadMap.cpp @@ -0,0 +1,76 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwLoadMap.h" +#include "CGame.h" +#include "WindowManager.h" +#include "controls/ctrlButton.h" +#include "controls/ctrlList.h" +#include "defines.h" +#include "globals.h" +#include "helpers/format.hpp" +#include "s25util/strAlgos.h" +#include "Loader.h" +#include + +namespace bfs = boost::filesystem; + +iwLoadMap::iwLoadMap() + : IngameWindow(101, IngameWindow::posLastOrCenter, Extent(280, 320), "Load map", + LOADER.GetImageN("resource", 41)) +{ + auto off = DrawPoint(contentOffset.x, contentOffset.y) + DrawPoint(10, 5); + auto* list = AddList(ID_lstFiles, off, Extent(150, 260), TextureColor::Grey, NormalFont); + + // Populate with .SWD and .WLD files + if(bfs::exists(global::userMapsPath)) + { + for(auto& entry : bfs::directory_iterator(global::userMapsPath)) + { + if(!bfs::is_regular_file(entry.status())) + continue; + auto ext = s25util::toLower(entry.path().extension().string()); + if(ext != ".swd" && ext != ".wld") + continue; + list->AddItem(entry.path().filename().string()); + } + } + + int btnX = off.x + 150 + 8; + AddTextButton(ID_btLoad, DrawPoint(btnX, off.y + 130), Extent(85, 22), TextureColor::Green2, "Load", NormalFont); + AddTextButton(ID_btAbort, DrawPoint(btnX, off.y + 155), Extent(85, 22), TextureColor::Red1, "Abort", NormalFont); +} + +void iwLoadMap::Msg_ListSelectItem(unsigned /*ctrl_id*/, int selection) +{ + auto* list = GetCtrl(ID_lstFiles); + if(list && selection >= 0) + selectedFile_ = list->GetItemText(selection); +} + +void iwLoadMap::Msg_ButtonClick(unsigned ctrl_id) +{ + switch(ctrl_id) + { + case ID_btLoad: + if(!selectedFile_.empty()) + { + auto path = global::userMapsPath / selectedFile_; + if(!bfs::exists(path)) + { + path.replace_extension(".swd"); + if(!bfs::exists(path)) + path.replace_extension(".wld"); + } + if(bfs::exists(path)) + global::s2->enterEditor(path); + } + Close(); + break; + case ID_btAbort: + Close(); + break; + } +} + diff --git a/iwLoadMap.h b/iwLoadMap.h new file mode 100644 index 0000000..b27e476 --- /dev/null +++ b/iwLoadMap.h @@ -0,0 +1,25 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwLoadMap : public IngameWindow +{ +public: + iwLoadMap(); + + void Msg_ButtonClick(unsigned ctrl_id) override; + void Msg_ListSelectItem(unsigned ctrl_id, int selection) override; + +private: + enum + { + ID_lstFiles, + ID_btLoad, + ID_btAbort + }; + std::string selectedFile_; +}; diff --git a/iwSaveMap.cpp b/iwSaveMap.cpp new file mode 100644 index 0000000..7b5f281 --- /dev/null +++ b/iwSaveMap.cpp @@ -0,0 +1,76 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwSaveMap.h" +#include "CGame.h" +#include "CIO/CFile.h" +#include "CMap.h" +#include +namespace bfs = boost::filesystem; +#include "WindowManager.h" +#include "controls/ctrlButton.h" +#include "controls/ctrlEdit.h" +#include "controls/ctrlText.h" +#include "defines.h" +#include "globals.h" +#include "Loader.h" + +iwSaveMap::iwSaveMap() + : IngameWindow(102, IngameWindow::posLastOrCenter, Extent(280, 200), "Save map", + LOADER.GetImageN("resource", 41)) +{ + auto off = DrawPoint(contentOffset.x, contentOffset.y); + int labelX = off.x + (GetSize().x - contentOffset.x - contentOffsetEnd.x) / 2 + contentOffset.x - 30; + + AddText(ID_lblFilename, DrawPoint(labelX, off.y + 2), "Filename", COLOR_YELLOW, FontStyle::CENTER, SmallFont); + auto* editFile = AddEdit(ID_edtFilename, off + DrawPoint(10, 13), Extent(210, 22), TextureColor::Grey, NormalFont); + auto* mapObj = global::s2->getMapObj(); + bfs::path defaultPath = mapObj ? mapObj->getFilepath() : ""; + editFile->SetText(defaultPath.empty() ? "MyMap" : defaultPath.filename().string()); + + AddText(ID_lblMapname, DrawPoint(labelX, off.y + 38), "Mapname", COLOR_YELLOW, FontStyle::CENTER, SmallFont); + auto* editName = AddEdit(ID_edtMapname, off + DrawPoint(10, 50), Extent(210, 22), TextureColor::Grey, NormalFont); + editName->SetText(mapObj ? mapObj->getMapname() : ""); + + AddText(ID_lblAuthor, DrawPoint(labelX, off.y + 75), "Author", COLOR_YELLOW, FontStyle::CENTER, SmallFont); + auto* editAuthor = AddEdit(ID_edtAuthor, off + DrawPoint(10, 87), Extent(210, 22), TextureColor::Grey, NormalFont); + editAuthor->SetText(mapObj ? mapObj->getAuthor() : ""); + + off += DrawPoint(0, 20); + AddTextButton(ID_btSave, off + DrawPoint(10, 115), Extent(100, 22), TextureColor::Green2, "Save", NormalFont); + AddTextButton(ID_btAbort, off + DrawPoint(120, 115), Extent(100, 22), TextureColor::Red1, "Abort", NormalFont); +} + +void iwSaveMap::Msg_ButtonClick(unsigned ctrl_id) +{ + switch(ctrl_id) + { + case ID_btSave: + { + auto* mapObj = global::s2->getMapObj(); + if(!mapObj) + break; + auto* editFile = GetCtrl(ID_edtFilename); + auto* editName = GetCtrl(ID_edtMapname); + auto* editAuthor = GetCtrl(ID_edtAuthor); + if(!editFile || !editName || !editAuthor) + break; + + mapObj->setMapname(editName->GetText()); + mapObj->setAuthor(editAuthor->GetText()); + + bfs::path filepath = global::userMapsPath / editFile->GetText(); + if(!filepath.has_extension()) + filepath.replace_extension("SWD"); + mapObj->setFilepath(filepath); + CFile::save_file(filepath, WLD, mapObj->getMap()); // ignore return for now + + Close(); + break; + } + case ID_btAbort: + Close(); + break; + } +} diff --git a/iwSaveMap.h b/iwSaveMap.h new file mode 100644 index 0000000..ac52c3d --- /dev/null +++ b/iwSaveMap.h @@ -0,0 +1,28 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwSaveMap : public IngameWindow +{ +public: + iwSaveMap(); + + void Msg_ButtonClick(unsigned ctrl_id) override; + +private: + enum + { + ID_lblFilename, + ID_lblMapname, + ID_lblAuthor, + ID_edtFilename, + ID_edtMapname, + ID_edtAuthor, + ID_btSave, + ID_btAbort + }; +}; From bb54ddca3286c917ded0a49b23b8432a146cc312 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 10:09:07 +0200 Subject: [PATCH 07/16] elevation tool --- dskEditorInterface.cpp | 575 ++++++++++++++++++++++++++++++++++++---- dskEditorInterface.h | 69 ++++- iwEditorAnimal.cpp | 37 +++ iwEditorAnimal.h | 13 + iwEditorCreateWorld.cpp | 54 ++++ iwEditorCreateWorld.h | 13 + iwEditorCursor.cpp | 24 ++ iwEditorCursor.h | 13 + iwEditorLandscape.cpp | 41 +++ iwEditorLandscape.h | 13 + iwEditorPlayer.cpp | 19 ++ iwEditorPlayer.h | 13 + iwEditorResource.cpp | 33 +++ iwEditorResource.h | 13 + iwEditorTexture.cpp | 48 ++++ iwEditorTexture.h | 13 + iwEditorTree.cpp | 43 +++ iwEditorTree.h | 13 + iwMinimap.cpp | 14 + iwMinimap.h | 13 + 20 files changed, 1015 insertions(+), 59 deletions(-) create mode 100644 iwEditorAnimal.cpp create mode 100644 iwEditorAnimal.h create mode 100644 iwEditorCreateWorld.cpp create mode 100644 iwEditorCreateWorld.h create mode 100644 iwEditorCursor.cpp create mode 100644 iwEditorCursor.h create mode 100644 iwEditorLandscape.cpp create mode 100644 iwEditorLandscape.h create mode 100644 iwEditorPlayer.cpp create mode 100644 iwEditorPlayer.h create mode 100644 iwEditorResource.cpp create mode 100644 iwEditorResource.h create mode 100644 iwEditorTexture.cpp create mode 100644 iwEditorTexture.h create mode 100644 iwEditorTree.cpp create mode 100644 iwEditorTree.h create mode 100644 iwMinimap.cpp create mode 100644 iwMinimap.h diff --git a/dskEditorInterface.cpp b/dskEditorInterface.cpp index a6e4d16..5d00638 100644 --- a/dskEditorInterface.cpp +++ b/dskEditorInterface.cpp @@ -3,23 +3,28 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "dskEditorInterface.h" -#include "CGame.h" #include "EditorWorld.h" #include "GameWorldEditor.h" #include "Loader.h" #include "WindowManager.h" -#include "callbacks.h" #include "driver/KeyEvent.h" +#include "driver/MouseCoords.h" #include "drivers/VideoDriverWrapper.h" #include "iwEditorMenu.h" +#include "iwEditorTexture.h" +#include "iwEditorTree.h" +#include "iwEditorResource.h" +#include "iwEditorLandscape.h" +#include "iwEditorAnimal.h" +#include "iwEditorPlayer.h" +#include "iwMinimap.h" +#include "iwEditorCreateWorld.h" +#include "iwEditorCursor.h" #include "controls/ctrlButton.h" #include "defines.h" -#include "driver/MouseCoords.h" -#include "drivers/VideoDriverWrapper.h" -#include "dskMainMenu.h" -#include "globals.h" +#include "world/MapGeometry.h" +#include "world/MapBase.h" #include "ogl/glArchivItem_Bitmap.h" -#include "s25util/colors.h" #include dskEditorInterface::dskEditorInterface(std::unique_ptr world) @@ -44,14 +49,19 @@ dskEditorInterface::dskEditorInterface(std::unique_ptr world) addTool(ID_btToolLandscape, MENUBAR_LANDSCAPE, -88); addTool(ID_btToolAnimal, MENUBAR_ANIMAL, -51); addTool(ID_btToolPlayer, MENUBAR_PLAYER, -14); - addTool(ID_btToolCut, MENUBAR_BUILDHELP, 92); - addTool(ID_btToolFlag, MENUBAR_MINIMAP, 129); - addTool(ID_btToolHeightReduce,MENUBAR_NEWWORLD, 166); + addTool(ID_btToolBuildHelp, MENUBAR_BUILDHELP, 92); + addTool(ID_btToolMinimap, MENUBAR_MINIMAP, 129); + addTool(ID_btToolNewWorld, MENUBAR_NEWWORLD, 166); addTool(ID_btEditorMenu, MENUBAR_COMPUTER, 203); - // Right menubar: Load/Save buttons + // Right menubar: Cursor, Load/Save buttons const int rx = static_cast(screenSize.x); const int ry = static_cast(screenSize.y) / 2; + + AddImageButton(ID_btCursor, DrawPoint(rx - 36, ry - 202), Extent(32, 37), + TextureColor::Invisible, + LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_UP), "")->SetBorder(false); + AddImageButton(ID_btRLoad, DrawPoint(rx - 36, ry + 163), Extent(32, 37), TextureColor::Invisible, LOADER.GetImageN("editio", MENUBAR_BUGKILL), "")->SetBorder(false); @@ -62,6 +72,334 @@ dskEditorInterface::dskEditorInterface(std::unique_ptr world) dskEditorInterface::~dskEditorInterface() = default; +// ── Coordinate helpers ──────────────────────────────────────────────── + +MapPoint dskEditorInterface::screenToMapPoint(Position screenPos) const +{ + const auto off = gwEditor_->GetOffset(); + const auto mapSize = world_->getWorld().GetSize(); + + // Map pixel position (relative to map origin) + int px = screenPos.x + off.x; + int py = screenPos.y + off.y; + + // Wrap around map edges + int mapPx = static_cast(mapSize.x) * TR_W; + int mapPy = static_cast(mapSize.y) * TR_H; + if(mapPx > 0) { px %= mapPx; if(px < 0) px += mapPx; } + if(mapPy > 0) { py %= mapPy; if(py < 0) py += mapPy; } + + // Approximate Y first (row) — round to nearest row + int y = (py + TR_H / 2) / TR_H; + y = std::clamp(y, 0, static_cast(mapSize.y) - 1); + + // Then X based on row parity using s25main convention: + // even rows: vertices at col * TR_W (0, 56, 112…) + // odd rows: vertices at col * TR_W + TR_W/2 (28, 84, 140…) + // + // For even rows we need rounding (boundary at col*TR_W + TR_W/2): + // col = (px + TR_W/2) / TR_W + // For odd rows truncation suffices (boundary at (col+1)*TR_W): + // col = px / TR_W + int x; + if(y & 1) + x = px / TR_W; // odd row — truncation + else + x = (px + TR_W / 2) / TR_W; // even row — rounding + x = std::clamp(x, 0, static_cast(mapSize.x) - 1); + + return MapPoint(static_cast(x), static_cast(y)); +} + +Position dskEditorInterface::mapPointToScreen(MapPoint pt) const +{ + // Use the altitude-adjusted node position (s25client convention) + uint8_t alt = world_->getWorld().GetNode(pt).altitude; + Position nodePos = GetNodePos(pt, alt); + + const auto off = gwEditor_->GetOffset(); + nodePos -= off; + + // Toroidal wrap using modulo (cleaner than while loops) + const int mapPx = static_cast(world_->getWorld().GetWidth() * TR_W); + const int mapPy = static_cast(world_->getWorld().GetHeight() * TR_H); + const int sx = static_cast(VIDEODRIVER.GetRenderSize().x); + + if(mapPx > 0) + { + nodePos.x %= mapPx; + if(nodePos.x < 0) nodePos.x += mapPx; + // If the copy in [0, mapPx) is past the right screen edge, + // use the copy on the left side instead + if(nodePos.x > sx) nodePos.x -= mapPx; + } + if(mapPy > 0) + { + nodePos.y %= mapPy; + if(nodePos.y < 0) nodePos.y += mapPy; + if(nodePos.y > static_cast(VIDEODRIVER.GetRenderSize().y)) + nodePos.y -= mapPy; + } + return nodePos; +} + +// ── Cursor recalculation ────────────────────────────────────────────── + +void dskEditorInterface::recalcCursor() +{ + cursorVerts_.clear(); + needRecalcCursor_ = false; + + const auto& world = world_->getWorld(); + const auto mapSize = world.GetSize(); + const int cx = static_cast(cursorPos_.x); + const int cy = static_cast(cursorPos_.y); + const bool cyEven = (cy % 2 == 0); + const auto screenSize = VIDEODRIVER.GetRenderSize(); + + for(int dy = -MAX_BRUSH; dy <= MAX_BRUSH; dy++) + { + bool dyEven = (std::abs(dy) % 2 == 0); + int rowCount = dyEven ? (MAX_BRUSH * 2 + 1) : (MAX_BRUSH * 2); + int dxStart = -MAX_BRUSH; + int dxEnd = rowCount - MAX_BRUSH; + + for(int dx = dxStart; dx < dxEnd; dx++) + { + // Hexagon brush test matching old setupVerticesActivity + int adx = std::abs(dx); + int ady = std::abs(dy); + bool active = (ady <= brushSize_); + if(active) + { + int limit = brushSize_ - ady / 2; + if(dyEven) + active = (adx <= limit); + else + { + if(dx < 0) + active = (adx <= limit); + else + active = (dx <= limit - 1); + } + } + + if(!active) + continue; + + // MapPoint offset — matching old calculateVertices(): + // Odd offset rows get +1 in X when cursor center is on an odd row + // (because the hex grid is staggered) + int offX = dx; + if(!dyEven && !cyEven) + offX = dx + 1; + + int wx = cx + offX; + int wy = cy + dy; + if(wx < 0) wx += mapSize.x; + else if(wx >= static_cast(mapSize.x)) wx -= mapSize.x; + if(wy < 0) wy += mapSize.y; + else if(wy >= static_cast(mapSize.y)) wy -= mapSize.y; + + auto pt = MapPoint(static_cast(wx), static_cast(wy)); + Position screenPos = mapPointToScreen(pt); + + // Cull off-screen + if(screenPos.x < -50 || screenPos.x > static_cast(screenSize.x + 50) + || screenPos.y < -50 || screenPos.y > static_cast(screenSize.y + 50)) + continue; + + CursorVertex cv; + cv.pt = pt; + cv.screenPos = screenPos; + cv.active = true; + cursorVerts_.push_back(cv); + } + } +} + +// ── Effective mode ──────────────────────────────────────────────────── + +EditorToolMode dskEditorInterface::effectiveMode() const +{ + Uint32 mod = SDL_GetModState(); + bool shiftHeld = (mod & KMOD_SHIFT) != 0; + bool altHeld = (mod & KMOD_ALT) != 0; + bool ctrlHeld = (mod & KMOD_CTRL) != 0; + + EditorToolMode eff = mode_; + if(ctrlHeld) + return EditorToolMode::Cut; + if(shiftHeld) + { + if(eff == EditorToolMode::HeightRaise) + eff = EditorToolMode::HeightReduce; + else if(eff == EditorToolMode::Resource) + eff = EditorToolMode::HeightReduce; + else if(eff == EditorToolMode::Flag) + eff = EditorToolMode::Cut; + } + if(altHeld && eff == EditorToolMode::HeightRaise) + eff = EditorToolMode::HeightPlane; + return eff; +} + +// ── Cursor drawing ──────────────────────────────────────────────────── + +void dskEditorInterface::drawCursor() +{ + if(needRecalcCursor_) + recalcCursor(); + + EditorToolMode drawMode = effectiveMode(); + + int sym1 = -1, sym2 = -1; + switch(drawMode) + { + case EditorToolMode::Cut: sym1 = CURSOR_SYMBOL_SCISSORS; break; + case EditorToolMode::Tree: sym1 = CURSOR_SYMBOL_TREE; break; + case EditorToolMode::HeightRaise: sym1 = CURSOR_SYMBOL_ARROW_UP; break; + case EditorToolMode::HeightReduce: sym1 = CURSOR_SYMBOL_ARROW_DOWN; break; + case EditorToolMode::HeightPlane: + sym1 = CURSOR_SYMBOL_ARROW_UP; + sym2 = CURSOR_SYMBOL_ARROW_DOWN; + break; + case EditorToolMode::Texture: sym1 = CURSOR_SYMBOL_TEXTURE; break; + case EditorToolMode::Landscape: sym1 = CURSOR_SYMBOL_LANDSCAPE; break; + case EditorToolMode::Flag: sym1 = CURSOR_SYMBOL_FLAG; break; + case EditorToolMode::Resource: sym1 = CURSOR_SYMBOL_PICKAXE_PLUS; break; + case EditorToolMode::Animal: sym1 = CURSOR_SYMBOL_ANIMAL; break; + } + + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + if(sym1 >= 0) + { + if(auto* img = LOADER.GetImageN("editbob", sym1)) + img->DrawFull(DrawPoint(cv.screenPos.x - 10, cv.screenPos.y - 10)); + } + if(sym2 >= 0) + { + if(auto* img = LOADER.GetImageN("editbob", sym2)) + img->DrawFull(DrawPoint(cv.screenPos.x, cv.screenPos.y - 7)); + } + } +} + +// ── Height propagation ─────────────────────────────────────────────── + +/// After changing a vertex's altitude, recursively adjust neighbours when +/// the height difference exceeds MAX_HEIGHT_DIFF steps, preventing cliffs. +/// This mirrors the old CMap::modifyHeightRaise/modifyHeightReduce logic. +static constexpr int MAX_HEIGHT_DIFF = 5; + +static void propagateRaise(MapPoint pt, GameWorld& world, int maxAltitude) +{ + auto& node = world.GetNodeWriteable(pt); + if(node.altitude >= maxAltitude) + return; + world.ChangeAltitude(pt, node.altitude + 1); + + // Check all 6 neighbours — if they're too low, raise them too + for(const auto& nb : world.GetNeighbours(pt)) + { + auto& nbNode = world.GetNodeWriteable(nb); + if(nbNode.altitude + MAX_HEIGHT_DIFF < node.altitude) + propagateRaise(nb, world, maxAltitude); + } +} + +static void propagateLower(MapPoint pt, GameWorld& world, int minAltitude) +{ + auto& node = world.GetNodeWriteable(pt); + if(node.altitude <= minAltitude) + return; + world.ChangeAltitude(pt, node.altitude - 1); + + for(const auto& nb : world.GetNeighbours(pt)) + { + auto& nbNode = world.GetNodeWriteable(nb); + if(node.altitude + MAX_HEIGHT_DIFF < nbNode.altitude) + propagateLower(nb, world, minAltitude); + } +} + +// ── Tool application ────────────────────────────────────────────────── + +void dskEditorInterface::applyTool() +{ + auto& world = world_->getWorld(); + + EditorToolMode effMode = effectiveMode(); + + if(needRecalcCursor_) + recalcCursor(); + + switch(effMode) + { + case EditorToolMode::HeightRaise: + { + int maxAlt = world.GetNode(cursorPos_).altitude; + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + auto alt = world.GetNode(cv.pt).altitude; + if(alt > maxAlt) maxAlt = alt; + } + // Raise all brush vertices (cap at 0x3C) with propagation + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + auto& node = world.GetNodeWriteable(cv.pt); + if(node.altitude < 0x3C) + propagateRaise(cv.pt, world, 0x3C); + } + break; + } + case EditorToolMode::HeightReduce: + { + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + auto& node = world.GetNodeWriteable(cv.pt); + if(node.altitude > 0) + propagateLower(cv.pt, world, 0); + } + break; + } + case EditorToolMode::HeightPlane: + { + int sum = 0, count = 0; + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + sum += world.GetNode(cv.pt).altitude; + count++; + } + if(count > 0) + { + uint8_t avg = static_cast(sum / count); + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + auto& node = world.GetNodeWriteable(cv.pt); + uint8_t alt = node.altitude; + if(alt < avg) + propagateRaise(cv.pt, world, avg); + else if(alt > avg) + propagateLower(cv.pt, world, avg); + } + } + break; + } + default: + break; + } +} + +// ── Event handlers ──────────────────────────────────────────────────── + void dskEditorInterface::Msg_PaintBefore() { Desktop::Msg_PaintBefore(); @@ -75,9 +413,12 @@ void dskEditorInterface::Msg_PaintBefore() // ── Terrain via GameWorldEditor ── if(gwEditor_) - gwEditor_->Draw(VIDEODRIVER.GetRenderSize()); + gwEditor_->Draw(screenSize); + + // ── Cursor sprites (under UI chrome) ── + drawCursor(); - // ── Editor frame (glArchivItem_Bitmap from "editres") ── + // ── Editor frame ── auto* frameTex = LOADER.GetImageN("editres", MAINFRAME_640_480); if(!frameTex) return; @@ -93,18 +434,15 @@ void dskEditorInterface::Msg_PaintBefore() LOADER.GetImageN("editres", MAINFRAME_RIGHT_1280_1024)->DrawFull(DrawPoint(640, 0)); } else { - // Corners frameTex->Draw(Rect(0, 0, 150, 150), Rect(0, 0, 150, 150), COLOR_WHITE); frameTex->Draw(Rect(0, h - 150, 150, 150), Rect(0, 480 - 150, 150, 150), COLOR_WHITE); frameTex->Draw(Rect(w - 150, 0, 150, 150), Rect(640 - 150, 0, 150, 150), COLOR_WHITE); frameTex->Draw(Rect(w - 150, h - 150, 150, 150), Rect(640 - 150, 480 - 150, 150, 150), COLOR_WHITE); - // Top/bottom edges for(unsigned x = 150; x + 150 < static_cast(w); x += 150) { frameTex->Draw(Rect(static_cast(x), 0, 150, 12), Rect(150, 0, 150, 12), COLOR_WHITE); frameTex->Draw(Rect(static_cast(x), h - 12, 150, 12), Rect(150, 0, 150, 12), COLOR_WHITE); } - // Left/right edges for(unsigned y = 150; y + 150 < static_cast(h); y += 150) { frameTex->Draw(Rect(0, static_cast(y), 12, 150), Rect(0, 150, 12, 150), COLOR_WHITE); @@ -112,12 +450,12 @@ void dskEditorInterface::Msg_PaintBefore() } } - // Corner statues — DrawPart with (0,0) offset to match old Texture::draw(Position) auto drawStat = [&](int idx, int x, int y) { - auto* img = LOADER.GetImageN("editres", idx); - if(!img) return; - auto sz = img->GetSize(); - img->DrawPart(Rect(x, y, sz.x, sz.y), DrawPoint(0, 0)); + if(auto* img = LOADER.GetImageN("editres", idx)) + { + auto sz = img->GetSize(); + img->DrawPart(Rect(x, y, sz.x, sz.y), DrawPoint(0, 0)); + } }; drawStat(STATUE_UP_LEFT, 12, 12); drawStat(STATUE_UP_RIGHT, w - static_cast(LOADER.GetImageN("editres", STATUE_UP_RIGHT)->GetSize().x) - 12, 12); @@ -131,10 +469,8 @@ void dskEditorInterface::Msg_PaintBefore() if(!menubar) return; auto mbSz = menubar->GetSize(); - // Bottom menubar — top-left origin menubar->DrawPart(Rect((w - mbSz.x) / 2, h - mbSz.y, mbSz.x, mbSz.y), DrawPoint(0, 0)); - // Slot backgrounds from "editio" auto* slotBg = LOADER.GetImageN("editio", BUTTON_GREEN1_DARK); if(slotBg) { @@ -155,25 +491,20 @@ void dskEditorInterface::Msg_PaintBefore() menubar->DrawFull(Rect(-static_cast(mbSz.x) / 2, -static_cast(mbSz.y) / 2, mbSz.x, mbSz.y)); glPopMatrix(); - // Right menubar slots if(slotBg) { for(int yOff : {-239, -202, -165, -128, -22, 15, 52, 89, 126, 163, 200}) slotBg->Draw(Rect(rx - 36, ry + yOff, 32, 37), Rect(0, 0, 32, 37), COLOR_WHITE); } - // Right menubar arrow indicators drawn on top of slots - { - auto& texUp = Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP); - auto& texDn = Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN); - if(texUp.isValid() && texDn.isValid()) - { - texUp.draw(Position(rx - 33, ry - 237)); - texDn.draw(Position(rx - 20, ry - 235)); - texDn.draw(Position(rx - 33, ry - 220)); - texUp.draw(Position(rx - 20, ry - 220)); - } - } + if(auto* texUp = LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_UP)) + texUp->DrawFull(DrawPoint(rx - 33, ry - 237)); + if(auto* texDn = LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_DOWN)) + texDn->DrawFull(DrawPoint(rx - 20, ry - 235)); + if(auto* texDn2 = LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_DOWN)) + texDn2->DrawFull(DrawPoint(rx - 33, ry - 220)); + if(auto* texUp2 = LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_UP)) + texUp2->DrawFull(DrawPoint(rx - 20, ry - 220)); } } @@ -186,28 +517,176 @@ void dskEditorInterface::Msg_ButtonClick(unsigned ctrl_id) { switch(ctrl_id) { + case ID_btToolHeightRaise: + mode_ = EditorToolMode::HeightRaise; + needRecalcCursor_ = true; + break; + case ID_btToolTexture: + mode_ = EditorToolMode::Texture; + WINDOWMANAGER.Show(std::make_unique()); + break; + case ID_btToolTree: + mode_ = EditorToolMode::Tree; + WINDOWMANAGER.Show(std::make_unique()); + break; + case ID_btToolResource: + mode_ = EditorToolMode::Resource; + WINDOWMANAGER.Show(std::make_unique()); + break; + case ID_btToolLandscape: + mode_ = EditorToolMode::Landscape; + WINDOWMANAGER.Show(std::make_unique()); + break; + case ID_btToolAnimal: + mode_ = EditorToolMode::Animal; + WINDOWMANAGER.Show(std::make_unique()); + break; + case ID_btToolPlayer: + mode_ = EditorToolMode::Flag; + WINDOWMANAGER.Show(std::make_unique()); + break; + case ID_btToolBuildHelp: + break; + case ID_btToolMinimap: + WINDOWMANAGER.Show(std::make_unique()); + break; + case ID_btToolNewWorld: + WINDOWMANAGER.Show(std::make_unique()); + break; case ID_btEditorMenu: WINDOWMANAGER.Show(std::make_unique()); break; + case ID_btCursor: + WINDOWMANAGER.Show(std::make_unique()); + break; + } +} + +bool dskEditorInterface::Msg_LeftDown(const MouseCoords& mc) +{ + // Check if click is on the map area (not UI chrome) + const auto screenSize = VIDEODRIVER.GetRenderSize(); + if(mc.pos.x >= 0 && mc.pos.x < static_cast(screenSize.x) - 37 + && mc.pos.y >= 0 && mc.pos.y < static_cast(screenSize.y) - 36) + { + cursorPos_ = screenToMapPoint(mc.pos); + needRecalcCursor_ = true; + isModifying_ = true; + applyTool(); + return true; } + return Desktop::Msg_LeftDown(mc); +} + +bool dskEditorInterface::Msg_LeftUp(const MouseCoords& mc) +{ + isModifying_ = false; + return Desktop::Msg_LeftUp(mc); +} + +bool dskEditorInterface::Msg_MouseMove(const MouseCoords& mc) +{ + cursorPos_ = screenToMapPoint(mc.pos); + needRecalcCursor_ = true; + + if(isModifying_) + applyTool(); + + return true; } -bool dskEditorInterface::Msg_LeftDown(const MouseCoords& mc) { return Desktop::Msg_LeftDown(mc); } -bool dskEditorInterface::Msg_LeftUp(const MouseCoords& mc) { return Desktop::Msg_LeftUp(mc); } -bool dskEditorInterface::Msg_MouseMove(const MouseCoords&) { return false; } bool dskEditorInterface::Msg_KeyDown(const KeyEvent& ke) { - // Arrow keys for scrolling (temporary until full map interaction is wired) - static constexpr int scrollSpeed = 20; - if(!gwEditor_) return false; - switch(ke.kt) + // ── Arrow keys for scrolling ── + if(ke.kt == KeyType::Left || ke.kt == KeyType::Right + || ke.kt == KeyType::Up || ke.kt == KeyType::Down) { - case KeyType::Left: gwEditor_->MoveBy(DrawPoint(-scrollSpeed, 0)); return true; - case KeyType::Right: gwEditor_->MoveBy(DrawPoint(scrollSpeed, 0)); return true; - case KeyType::Up: gwEditor_->MoveBy(DrawPoint(0, -scrollSpeed)); return true; - case KeyType::Down: gwEditor_->MoveBy(DrawPoint(0, scrollSpeed)); return true; - default: return false; + static constexpr int scrollSpeed = 20; + if(!gwEditor_) return false; + DrawPoint delta(0, 0); + switch(ke.kt) + { + case KeyType::Left: delta.x = -scrollSpeed; break; + case KeyType::Right: delta.x = scrollSpeed; break; + case KeyType::Up: delta.y = -scrollSpeed; break; + case KeyType::Down: delta.y = scrollSpeed; break; + default: break; + } + gwEditor_->MoveBy(delta); + needRecalcCursor_ = true; + return true; } + + // ── Brush size: +/- and number keys ── + if(ke.kt == KeyType::Char) + { + char32_t c = ke.c; + if(c == U'+' || c == U'=') + { + if(brushSize_ < MAX_BRUSH) + { + brushSize_++; + needRecalcCursor_ = true; + } + return true; + } + if(c == U'-' || c == U'_') + { + if(brushSize_ > 0) + { + brushSize_--; + needRecalcCursor_ = true; + } + return true; + } + if(c >= U'0' && c <= U'9') + { + int n = static_cast(c - U'0'); + if(n <= MAX_BRUSH) + { + brushSize_ = n; + needRecalcCursor_ = true; + } + return true; + } + } + + // ── Space: toggle build help (visual only for now) ── + if(ke.kt == KeyType::Space) + { + // RenderBuildHelp toggle would go here once build-help rendering exists + return true; + } + + // ── F11: toggle borders ── + if(ke.kt == KeyType::F11) + { + // RenderBorders toggle would go here once border rendering exists + return true; + } + + // ── F1: help menu ── + if(ke.kt == KeyType::F1) + { + // callback::EditorHelpMenu would open a help window + return true; + } + + // ── Ctrl+Z / Ctrl+Y undo/redo (placeholder) ── + Uint32 mod = SDL_GetModState(); + if((mod & KMOD_CTRL) && ke.kt == KeyType::Char && ke.c == U'z') + { + // Undo + return true; + } + if((mod & KMOD_CTRL) && ke.kt == KeyType::Char && ke.c == U'y') + { + // Redo + return true; + } + + return false; } + bool dskEditorInterface::Msg_WheelUp(const MouseCoords&) { return false; } bool dskEditorInterface::Msg_WheelDown(const MouseCoords&) { return false; } diff --git a/dskEditorInterface.h b/dskEditorInterface.h index 6dc7838..5ceafd4 100644 --- a/dskEditorInterface.h +++ b/dskEditorInterface.h @@ -5,11 +5,35 @@ #pragma once #include "desktops/Desktop.h" +#include "gameTypes/MapCoordinates.h" #include +#include class EditorWorld; class GameWorldEditor; +struct CursorVertex +{ + MapPoint pt; + Position screenPos; + bool active; +}; + +/// Editor tool modes (matches old EDITOR_MODE_* semantics) +enum class EditorToolMode +{ + HeightRaise, + HeightReduce, + HeightPlane, + Texture, + Tree, + Landscape, + Resource, + Animal, + Flag, + Cut +}; + class dskEditorInterface : public Desktop { public: @@ -29,28 +53,51 @@ class dskEditorInterface : public Desktop void Draw_() override; private: + /// Convert screen pixel position to the nearest MapPoint + MapPoint screenToMapPoint(Position screenPos) const; + /// Get pixel position of a map point (screen-space, accounting for scroll offset) + Position mapPointToScreen(MapPoint pt) const; + /// Recalculate cursor vertices based on cursorPos_ and brushSize_ + void recalcCursor(); + /// Draw the cursor sprites at all active vertices + void drawCursor(); + /// Apply the current tool to the vertices under the cursor + void applyTool(); + /// Effective mode considering modifier keys (read from SDL_GetModState()) + EditorToolMode effectiveMode() const; + std::unique_ptr world_; std::unique_ptr gwEditor_; + // ── Editor state ── + EditorToolMode mode_ = EditorToolMode::HeightRaise; + int brushSize_ = 1; // 0..MAX_BRUSH + MapPoint cursorPos_{0, 0}; + bool isModifying_ = false; + + // Cursor vertex field + static constexpr int MAX_BRUSH = 10; + std::vector cursorVerts_; + bool needRecalcCursor_ = true; + enum ControlIds { - ID_btQuitEditor, - ID_btSave, - ID_btLoad, - ID_btMinimap, - ID_btToolCut, - ID_btToolTree, + // Bottom menubar tools (matching CMap.cpp button order) ID_btToolHeightRaise, - ID_btToolHeightReduce, ID_btToolTexture, - ID_btToolLandscape, - ID_btToolFlag, + ID_btToolTree, ID_btToolResource, + ID_btToolLandscape, ID_btToolAnimal, ID_btToolPlayer, - ID_btEditorMenu, - ID_FIRST_TOOL = ID_btToolCut, + ID_btToolBuildHelp, // toggle, no window + ID_btToolMinimap, + ID_btToolNewWorld, + ID_btEditorMenu, // main menu + ID_FIRST_TOOL = ID_btToolHeightRaise, ID_LAST_TOOL = ID_btEditorMenu, + // Right menubar + ID_btCursor, ID_btRLoad, ID_btRSave, }; diff --git a/iwEditorAnimal.cpp b/iwEditorAnimal.cpp new file mode 100644 index 0000000..f123287 --- /dev/null +++ b/iwEditorAnimal.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwEditorAnimal.h" +#include "Loader.h" +#include "controls/ctrlButton.h" +#include "defines.h" + +iwEditorAnimal::iwEditorAnimal() + : IngameWindow(105, IngameWindow::posLastOrCenter, Extent(116, 106), "Animals", + LOADER.GetImageN("resource", 41)) +{ + const int x0 = contentOffset.x; + const int y0 = contentOffset.y; + const int step = 34; + const int picSize = 32; + + static constexpr int animalIds[] = { + PICTURE_ANIMAL_RABBIT, + PICTURE_ANIMAL_FOX, + PICTURE_ANIMAL_STAG, + PICTURE_ANIMAL_ROE, + PICTURE_ANIMAL_DUCK, + PICTURE_ANIMAL_SHEEP, + }; + + for(unsigned i = 0; i < sizeof(animalIds) / sizeof(animalIds[0]); i++) + { + auto* img = LOADER.GetImageN("editio", animalIds[i]); + if(!img) continue; + int col = i % 3; + int row = i / 3; + AddImageButton(i + 1, DrawPoint(x0 + col * step, y0 + row * step), Extent(picSize, picSize), + TextureColor::Invisible, img, "")->SetBorder(false); + } +} diff --git a/iwEditorAnimal.h b/iwEditorAnimal.h new file mode 100644 index 0000000..24373b6 --- /dev/null +++ b/iwEditorAnimal.h @@ -0,0 +1,13 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwEditorAnimal : public IngameWindow +{ +public: + iwEditorAnimal(); +}; diff --git a/iwEditorCreateWorld.cpp b/iwEditorCreateWorld.cpp new file mode 100644 index 0000000..3324cba --- /dev/null +++ b/iwEditorCreateWorld.cpp @@ -0,0 +1,54 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwEditorCreateWorld.h" +#include "Loader.h" +#include "controls/ctrlButton.h" + +iwEditorCreateWorld::iwEditorCreateWorld() + : IngameWindow(108, IngameWindow::posLastOrCenter, Extent(250, 350), "Create world", + LOADER.GetImageN("resource", 41)) +{ + const int x0 = contentOffset.x; + const int y0 = contentOffset.y; + const int btnW = 35; + const int btnH = 20; + const int row1Y = 15; + const int row2Y = 49; + const int spacing = 2; + + // Width controls + AddTextButton(1, DrawPoint(x0, y0 + row1Y), Extent(btnW, btnH), TextureColor::Grey, "128<-", NormalFont); + AddTextButton(2, DrawPoint(x0 + btnW + spacing, y0 + row1Y), Extent(btnW, btnH), TextureColor::Grey, "16<-", NormalFont); + AddTextButton(3, DrawPoint(x0 + 2 * (btnW + spacing), y0 + row1Y), Extent(btnW - 10, btnH), TextureColor::Grey, "2<-", NormalFont); + AddTextButton(4, DrawPoint(x0 + 3 * (btnW + spacing) + 5, y0 + row1Y), Extent(btnW - 10, btnH), TextureColor::Grey, "->2", NormalFont); + AddTextButton(5, DrawPoint(x0 + 4 * (btnW + spacing), y0 + row1Y), Extent(btnW, btnH), TextureColor::Grey, "->16", NormalFont); + AddTextButton(6, DrawPoint(x0 + 5 * (btnW + spacing), y0 + row1Y), Extent(btnW, btnH), TextureColor::Grey, "->128", NormalFont); + + // Height controls + AddTextButton(7, DrawPoint(x0, y0 + row2Y), Extent(btnW, btnH), TextureColor::Grey, "128<-", NormalFont); + AddTextButton(8, DrawPoint(x0 + btnW + spacing, y0 + row2Y), Extent(btnW, btnH), TextureColor::Grey, "16<-", NormalFont); + AddTextButton(9, DrawPoint(x0 + 2 * (btnW + spacing), y0 + row2Y), Extent(btnW - 10, btnH), TextureColor::Grey, "2<-", NormalFont); + AddTextButton(10, DrawPoint(x0 + 3 * (btnW + spacing) + 5, y0 + row2Y), Extent(btnW - 10, btnH), TextureColor::Grey, "->2", NormalFont); + AddTextButton(11, DrawPoint(x0 + 4 * (btnW + spacing), y0 + row2Y), Extent(btnW, btnH), TextureColor::Grey, "->16", NormalFont); + AddTextButton(12, DrawPoint(x0 + 5 * (btnW + spacing), y0 + row2Y), Extent(btnW, btnH), TextureColor::Grey, "->128", NormalFont); + + // Landscape type + AddTextButton(13, DrawPoint(x0 + 50, y0 + 80), Extent(110, 20), TextureColor::Grey, "Greenland", NormalFont); + + // Main texture prev/next + AddTextButton(14, DrawPoint(x0 + 30, y0 + 120), Extent(35, 20), TextureColor::Grey, "-", NormalFont); + AddTextButton(15, DrawPoint(x0 + 140, y0 + 120), Extent(35, 20), TextureColor::Grey, "+", NormalFont); + + // Border size + AddTextButton(16, DrawPoint(x0 + 30, y0 + 170), Extent(35, 20), TextureColor::Grey, "-", NormalFont); + AddTextButton(17, DrawPoint(x0 + 140, y0 + 170), Extent(35, 20), TextureColor::Grey, "+", NormalFont); + + // Border texture prev/next + AddTextButton(18, DrawPoint(x0 + 30, y0 + 210), Extent(35, 20), TextureColor::Grey, "-", NormalFont); + AddTextButton(19, DrawPoint(x0 + 140, y0 + 210), Extent(35, 20), TextureColor::Grey, "+", NormalFont); + + // Create world button + AddTextButton(20, DrawPoint(x0 + 30, y0 + 260), Extent(150, 40), TextureColor::Green2, "Create world", NormalFont); +} diff --git a/iwEditorCreateWorld.h b/iwEditorCreateWorld.h new file mode 100644 index 0000000..857c4d6 --- /dev/null +++ b/iwEditorCreateWorld.h @@ -0,0 +1,13 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwEditorCreateWorld : public IngameWindow +{ +public: + iwEditorCreateWorld(); +}; diff --git a/iwEditorCursor.cpp b/iwEditorCursor.cpp new file mode 100644 index 0000000..05dcd6e --- /dev/null +++ b/iwEditorCursor.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwEditorCursor.h" +#include "Loader.h" +#include "controls/ctrlButton.h" +#include "defines.h" + +iwEditorCursor::iwEditorCursor() + : IngameWindow(109, IngameWindow::posLastOrCenter, Extent(210, 130), "Cursor", + LOADER.GetImageN("resource", 41)) +{ + const int x0 = contentOffset.x; + const int y0 = contentOffset.y; + + AddTextButton(1, DrawPoint(x0 + 2, y0 + 2), Extent(96, 32), TextureColor::Grey, "Hexagon", NormalFont); + AddTextButton(2, DrawPoint(x0 + 2, y0 + 34), Extent(196, 32), TextureColor::Grey, "Cursor-Activity: static", NormalFont); + + auto* arrowUp = LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_UP); + if(arrowUp) + AddImageButton(3, DrawPoint(x0 + 2, y0 + 66), Extent(32, 32), + TextureColor::Invisible, arrowUp, "")->SetBorder(false); +} diff --git a/iwEditorCursor.h b/iwEditorCursor.h new file mode 100644 index 0000000..94f230e --- /dev/null +++ b/iwEditorCursor.h @@ -0,0 +1,13 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwEditorCursor : public IngameWindow +{ +public: + iwEditorCursor(); +}; diff --git a/iwEditorLandscape.cpp b/iwEditorLandscape.cpp new file mode 100644 index 0000000..08edd2e --- /dev/null +++ b/iwEditorLandscape.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwEditorLandscape.h" +#include "Loader.h" +#include "controls/ctrlButton.h" +#include "defines.h" + +iwEditorLandscape::iwEditorLandscape() + : IngameWindow(104, IngameWindow::posLastOrCenter, Extent(112, 174), "Landscape", + LOADER.GetImageN("resource", 41)) +{ + const int x0 = contentOffset.x; + const int y0 = contentOffset.y; + const int step = 34; + const int picSize = 32; + + // Greenland landscape objects + static constexpr int landscapeIds[] = { + PICTURE_LANDSCAPE_GRANITE, + PICTURE_LANDSCAPE_TREE_DEAD, + PICTURE_LANDSCAPE_STONE, + PICTURE_LANDSCAPE_CACTUS, + PICTURE_LANDSCAPE_PEBBLE, + PICTURE_LANDSCAPE_BUSH, + PICTURE_LANDSCAPE_SHRUB, + PICTURE_LANDSCAPE_BONE, + PICTURE_LANDSCAPE_MUSHROOM, + }; + + for(unsigned i = 0; i < sizeof(landscapeIds) / sizeof(landscapeIds[0]); i++) + { + auto* img = LOADER.GetImageN("editio", landscapeIds[i]); + if(!img) continue; + int col = i % 3; + int row = i / 3; + AddImageButton(i + 1, DrawPoint(x0 + col * step, y0 + row * step), Extent(picSize, picSize), + TextureColor::Invisible, img, "")->SetBorder(false); + } +} diff --git a/iwEditorLandscape.h b/iwEditorLandscape.h new file mode 100644 index 0000000..4a31ec1 --- /dev/null +++ b/iwEditorLandscape.h @@ -0,0 +1,13 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwEditorLandscape : public IngameWindow +{ +public: + iwEditorLandscape(); +}; diff --git a/iwEditorPlayer.cpp b/iwEditorPlayer.cpp new file mode 100644 index 0000000..6afb2fd --- /dev/null +++ b/iwEditorPlayer.cpp @@ -0,0 +1,19 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwEditorPlayer.h" +#include "Loader.h" +#include "controls/ctrlButton.h" + +iwEditorPlayer::iwEditorPlayer() + : IngameWindow(106, IngameWindow::posLastOrCenter, Extent(100, 80), "Players", + LOADER.GetImageN("resource", 41)) +{ + const int x0 = contentOffset.x; + const int y0 = contentOffset.y; + + AddTextButton(1, DrawPoint(x0, y0), Extent(20, 20), TextureColor::Grey, "-", NormalFont); + AddTextButton(2, DrawPoint(x0 + 40, y0), Extent(20, 20), TextureColor::Grey, "+", NormalFont); + AddTextButton(3, DrawPoint(x0, y0 + 20), Extent(60, 20), TextureColor::Grey, "Go to", NormalFont); +} diff --git a/iwEditorPlayer.h b/iwEditorPlayer.h new file mode 100644 index 0000000..3e62e5f --- /dev/null +++ b/iwEditorPlayer.h @@ -0,0 +1,13 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwEditorPlayer : public IngameWindow +{ +public: + iwEditorPlayer(); +}; diff --git a/iwEditorResource.cpp b/iwEditorResource.cpp new file mode 100644 index 0000000..0ee6a82 --- /dev/null +++ b/iwEditorResource.cpp @@ -0,0 +1,33 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwEditorResource.h" +#include "Loader.h" +#include "controls/ctrlButton.h" +#include "defines.h" + +iwEditorResource::iwEditorResource() + : IngameWindow(103, IngameWindow::posLastOrCenter, Extent(148, 55), "Resources", + LOADER.GetImageN("resource", 41)) +{ + const int x0 = contentOffset.x; + const int y0 = contentOffset.y; + const int step = 34; + const int picSize = 32; + + static constexpr int resourceIds[] = { + PICTURE_RESOURCE_GOLD, + PICTURE_RESOURCE_ORE, + PICTURE_RESOURCE_COAL, + PICTURE_RESOURCE_GRANITE, + }; + + for(unsigned i = 0; i < sizeof(resourceIds) / sizeof(resourceIds[0]); i++) + { + auto* img = LOADER.GetImageN("editio", resourceIds[i]); + if(!img) continue; + AddImageButton(i + 1, DrawPoint(x0 + i * step, y0), Extent(picSize, picSize), + TextureColor::Invisible, img, "")->SetBorder(false); + } +} diff --git a/iwEditorResource.h b/iwEditorResource.h new file mode 100644 index 0000000..f08f6b5 --- /dev/null +++ b/iwEditorResource.h @@ -0,0 +1,13 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwEditorResource : public IngameWindow +{ +public: + iwEditorResource(); +}; diff --git a/iwEditorTexture.cpp b/iwEditorTexture.cpp new file mode 100644 index 0000000..5c55bd1 --- /dev/null +++ b/iwEditorTexture.cpp @@ -0,0 +1,48 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwEditorTexture.h" +#include "Loader.h" +#include "controls/ctrlButton.h" +#include "defines.h" + +iwEditorTexture::iwEditorTexture() + : IngameWindow(101, IngameWindow::posLastOrCenter, Extent(220, 133), "Terrain", + LOADER.GetImageN("resource", 41)) +{ + const int x0 = contentOffset.x; + const int y0 = contentOffset.y; + const int step = 34; + const int picSize = 32; + + static constexpr int texIds[] = { + PICTURE_GREENLAND_TEXTURE_SNOW, + PICTURE_GREENLAND_TEXTURE_STEPPE, + PICTURE_GREENLAND_TEXTURE_SWAMP, + PICTURE_GREENLAND_TEXTURE_FLOWER, + PICTURE_GREENLAND_TEXTURE_MINING1, + PICTURE_GREENLAND_TEXTURE_MINING2, + PICTURE_GREENLAND_TEXTURE_MINING3, + PICTURE_GREENLAND_TEXTURE_MINING4, + PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW1, + PICTURE_GREENLAND_TEXTURE_MEADOW1, + PICTURE_GREENLAND_TEXTURE_MEADOW2, + PICTURE_GREENLAND_TEXTURE_MEADOW3, + PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW2, + PICTURE_GREENLAND_TEXTURE_MINING_MEADOW, + PICTURE_GREENLAND_TEXTURE_WATER, + PICTURE_GREENLAND_TEXTURE_LAVA, + PICTURE_GREENLAND_TEXTURE_MEADOW_MIXED, + }; + + for(unsigned i = 0; i < sizeof(texIds) / sizeof(texIds[0]); i++) + { + auto* img = LOADER.GetImageN("editio", texIds[i]); + if(!img) continue; + int col = i % 6; + int row = i / 6; + AddImageButton(i + 1, DrawPoint(x0 + col * step, y0 + row * step), Extent(picSize, picSize), + TextureColor::Invisible, img, "")->SetBorder(false); + } +} diff --git a/iwEditorTexture.h b/iwEditorTexture.h new file mode 100644 index 0000000..d70bcb9 --- /dev/null +++ b/iwEditorTexture.h @@ -0,0 +1,13 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwEditorTexture : public IngameWindow +{ +public: + iwEditorTexture(); +}; diff --git a/iwEditorTree.cpp b/iwEditorTree.cpp new file mode 100644 index 0000000..b103234 --- /dev/null +++ b/iwEditorTree.cpp @@ -0,0 +1,43 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwEditorTree.h" +#include "Loader.h" +#include "controls/ctrlButton.h" +#include "defines.h" + +iwEditorTree::iwEditorTree() + : IngameWindow(102, IngameWindow::posLastOrCenter, Extent(148, 140), "Trees", + LOADER.GetImageN("resource", 41)) +{ + const int x0 = contentOffset.x; + const int y0 = contentOffset.y; + const int step = 34; + const int picSize = 32; + + // Greenland trees (most complete set) + static constexpr int treeIds[] = { + PICTURE_TREE_PINE, + PICTURE_TREE_BIRCH, + PICTURE_TREE_OAK, + PICTURE_TREE_PALM1, + PICTURE_TREE_PALM2, + PICTURE_TREE_PINEAPPLE, + PICTURE_TREE_CYPRESS, + PICTURE_TREE_CHERRY, + PICTURE_TREE_FIR, + PICTURE_TREE_WOOD_MIXED, + PICTURE_TREE_PALM_MIXED, + }; + + for(unsigned i = 0; i < sizeof(treeIds) / sizeof(treeIds[0]); i++) + { + auto* img = LOADER.GetImageN("editio", treeIds[i]); + if(!img) continue; + int col = i % 4; + int row = i / 4; + AddImageButton(i + 1, DrawPoint(x0 + col * step, y0 + row * step), Extent(picSize, picSize), + TextureColor::Invisible, img, "")->SetBorder(false); + } +} diff --git a/iwEditorTree.h b/iwEditorTree.h new file mode 100644 index 0000000..69ccc41 --- /dev/null +++ b/iwEditorTree.h @@ -0,0 +1,13 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwEditorTree : public IngameWindow +{ +public: + iwEditorTree(); +}; diff --git a/iwMinimap.cpp b/iwMinimap.cpp new file mode 100644 index 0000000..7c166e6 --- /dev/null +++ b/iwMinimap.cpp @@ -0,0 +1,14 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "iwMinimap.h" +#include "Loader.h" + +iwMinimap::iwMinimap() + : IngameWindow(107, IngameWindow::posLastOrCenter, Extent(160, 160), "Minimap", + LOADER.GetImageN("resource", 41)) +{ + // Minimap rendering will draw the terrain overview into this window + // TODO: Render minimap content using the EditorWorld/GameWorldEditor +} diff --git a/iwMinimap.h b/iwMinimap.h new file mode 100644 index 0000000..4b63e57 --- /dev/null +++ b/iwMinimap.h @@ -0,0 +1,13 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "ingameWindows/IngameWindow.h" + +class iwMinimap : public IngameWindow +{ +public: + iwMinimap(); +}; From 6e42a48a2cdee51ebeee05198af4e9d387d169ab Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 10:20:26 +0200 Subject: [PATCH 08/16] cursor menu --- dskEditorInterface.cpp | 33 ++++++++++++++++++++------------- dskEditorInterface.h | 1 - 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/dskEditorInterface.cpp b/dskEditorInterface.cpp index 5d00638..ba73694 100644 --- a/dskEditorInterface.cpp +++ b/dskEditorInterface.cpp @@ -54,14 +54,10 @@ dskEditorInterface::dskEditorInterface(std::unique_ptr world) addTool(ID_btToolNewWorld, MENUBAR_NEWWORLD, 166); addTool(ID_btEditorMenu, MENUBAR_COMPUTER, 203); - // Right menubar: Cursor, Load/Save buttons + // Right menubar: Cursor (coord check in Msg_LeftDown), Load/Save buttons const int rx = static_cast(screenSize.x); const int ry = static_cast(screenSize.y) / 2; - AddImageButton(ID_btCursor, DrawPoint(rx - 36, ry - 202), Extent(32, 37), - TextureColor::Invisible, - LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_UP), "")->SetBorder(false); - AddImageButton(ID_btRLoad, DrawPoint(rx - 36, ry + 163), Extent(32, 37), TextureColor::Invisible, LOADER.GetImageN("editio", MENUBAR_BUGKILL), "")->SetBorder(false); @@ -497,14 +493,17 @@ void dskEditorInterface::Msg_PaintBefore() slotBg->Draw(Rect(rx - 36, ry + yOff, 32, 37), Rect(0, 0, 32, 37), COLOR_WHITE); } + // Draw arrow indicators — glArchivItem_Bitmap::Draw subtracts GetOrigin() + // (the libsiedler2 anchor nx/ny), so we add it back to match the old + // Texture::draw(Position) which did not adjust for origin. if(auto* texUp = LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_UP)) - texUp->DrawFull(DrawPoint(rx - 33, ry - 237)); + texUp->DrawFull(DrawPoint(rx - 33 + texUp->getNx(), ry - 237 + texUp->getNy())); if(auto* texDn = LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_DOWN)) - texDn->DrawFull(DrawPoint(rx - 20, ry - 235)); + texDn->DrawFull(DrawPoint(rx - 20 + texDn->getNx(), ry - 235 + texDn->getNy())); if(auto* texDn2 = LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_DOWN)) - texDn2->DrawFull(DrawPoint(rx - 33, ry - 220)); + texDn2->DrawFull(DrawPoint(rx - 33 + texDn2->getNx(), ry - 220 + texDn2->getNy())); if(auto* texUp2 = LOADER.GetImageN("editbob", CURSOR_SYMBOL_ARROW_UP)) - texUp2->DrawFull(DrawPoint(rx - 20, ry - 220)); + texUp2->DrawFull(DrawPoint(rx - 20 + texUp2->getNx(), ry - 220 + texUp2->getNy())); } } @@ -556,16 +555,24 @@ void dskEditorInterface::Msg_ButtonClick(unsigned ctrl_id) case ID_btEditorMenu: WINDOWMANAGER.Show(std::make_unique()); break; - case ID_btCursor: - WINDOWMANAGER.Show(std::make_unique()); - break; } } bool dskEditorInterface::Msg_LeftDown(const MouseCoords& mc) { - // Check if click is on the map area (not UI chrome) const auto screenSize = VIDEODRIVER.GetRenderSize(); + const int rx = static_cast(screenSize.x); + const int ry = static_cast(screenSize.y) / 2; + + // Right-menubar: cursor menu slot (coord check matching CMap.cpp) + if(mc.pos.x >= rx - 37 && mc.pos.x <= rx + && mc.pos.y >= ry - 239 && mc.pos.y <= ry - 202) + { + WINDOWMANAGER.Show(std::make_unique()); + return true; + } + + // Check if click is on the map area (not UI chrome) if(mc.pos.x >= 0 && mc.pos.x < static_cast(screenSize.x) - 37 && mc.pos.y >= 0 && mc.pos.y < static_cast(screenSize.y) - 36) { diff --git a/dskEditorInterface.h b/dskEditorInterface.h index 5ceafd4..ad3ffeb 100644 --- a/dskEditorInterface.h +++ b/dskEditorInterface.h @@ -97,7 +97,6 @@ class dskEditorInterface : public Desktop ID_FIRST_TOOL = ID_btToolHeightRaise, ID_LAST_TOOL = ID_btEditorMenu, // Right menubar - ID_btCursor, ID_btRLoad, ID_btRSave, }; From 38fd48da24d03482338eee61b451e7d3722d07bf Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 13:49:59 +0200 Subject: [PATCH 09/16] delete old --- CDebug.cpp | 385 ------ CDebug.h | 92 -- CGame.cpp | 46 +- CGame.h | 17 - CGame_Event.cpp | 326 ----- CGame_Init.cpp | 20 +- CGame_Render.cpp | 62 +- CIO/CButton.cpp | 148 --- CIO/CButton.h | 52 - CIO/CControlContainer.cpp | 203 --- CIO/CControlContainer.h | 109 -- CIO/CFont.cpp | 272 ---- CIO/CFont.h | 60 - CIO/CMinimapWindow.cpp | 65 - CIO/CMinimapWindow.h | 20 - CIO/CPicture.cpp | 68 - CIO/CPicture.h | 45 - CIO/CSelectBox.cpp | 240 ---- CIO/CSelectBox.h | 45 - CIO/CTextfield.cpp | 271 ---- CIO/CTextfield.h | 54 - CIO/CWindow.cpp | 389 ------ CIO/CWindow.h | 80 -- CMakeLists.txt | 3 +- CMap.cpp | 130 +- CMap.h | 1 - callbacks.cpp | 2522 ------------------------------------- callbacks.h | 40 - 28 files changed, 68 insertions(+), 5697 deletions(-) delete mode 100644 CDebug.cpp delete mode 100644 CDebug.h delete mode 100644 CIO/CButton.cpp delete mode 100644 CIO/CButton.h delete mode 100644 CIO/CControlContainer.cpp delete mode 100644 CIO/CControlContainer.h delete mode 100644 CIO/CFont.cpp delete mode 100644 CIO/CFont.h delete mode 100644 CIO/CMinimapWindow.cpp delete mode 100644 CIO/CMinimapWindow.h delete mode 100644 CIO/CPicture.cpp delete mode 100644 CIO/CPicture.h delete mode 100644 CIO/CSelectBox.cpp delete mode 100644 CIO/CSelectBox.h delete mode 100644 CIO/CTextfield.cpp delete mode 100644 CIO/CTextfield.h delete mode 100644 CIO/CWindow.cpp delete mode 100644 CIO/CWindow.h delete mode 100644 callbacks.cpp delete mode 100644 callbacks.h diff --git a/CDebug.cpp b/CDebug.cpp deleted file mode 100644 index cd2ae14..0000000 --- a/CDebug.cpp +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CDebug.h" -#include "CGame.h" -#include "CIO/CFont.h" -#include "CIO/CWindow.h" -#include "CMap.h" -#include "defines.h" -#include "globals.h" -#include "helpers/format.hpp" -#include - -#ifdef _ADMINMODE - -CDebug::CDebug(void dbgCallback(int), int quitParam) -{ - dbgWnd = global::s2->RegisterWindow( - std::make_unique(dbgCallback, quitParam, Position(0, 0), Extent(540, 130), "Debugger", WINDOW_GREEN1, - WINDOW_CLOSE | WINDOW_MOVE | WINDOW_MINIMIZE | WINDOW_RESIZE)); - dbgWnd->addText("Debugger started", Position(0, 0), fontsize); - this->dbgCallback_ = dbgCallback; - FrameCounterText = nullptr; - FramesPerSecText = nullptr; - msWaitText = nullptr; - RegisteredMenusText = nullptr; - RegisteredWindowsText = nullptr; - RegisteredCallbacksText = nullptr; - DisplayRectText = nullptr; - MouseText = nullptr; - MapNameText = nullptr; - MapSizeText = nullptr; - MapAuthorText = nullptr; - MapTypeText = nullptr; - MapPlayerText = nullptr; - VertexText = nullptr; - VertexDataText = nullptr; - VertexVectorText = nullptr; - FlatVectorText = nullptr; - rsuTextureText = nullptr; - usdTextureText = nullptr; - roadText = nullptr; - objectTypeText = nullptr; - objectInfoText = nullptr; - animalText = nullptr; - unknown1Text = nullptr; - buildText = nullptr; - unknown2Text = nullptr; - unknown3Text = nullptr; - resourceText = nullptr; - shadingText = nullptr; - unknown5Text = nullptr; - editorModeText = nullptr; - fontsize = FontSize::Small; - MapObj = global::s2->MapObj.get(); - map = nullptr; - global::s2->RegisterCallback(dbgCallback); - - // add buttons for in-/decrementing msWait - dbgWnd->addButton(dbgCallback, DECREMENT_MSWAIT, Position(75, 30), Extent(15, 15), BUTTON_GREY, "-"); - dbgWnd->addButton(dbgCallback, SETZERO_MSWAIT, Position(90, 30), Extent(15, 15), BUTTON_GREY, "0"); - dbgWnd->addButton(dbgCallback, INCREMENT_MSWAIT, Position(105, 30), Extent(15, 15), BUTTON_GREY, "+"); - - // we draw a vertical line to separate map data on the right side from things on the left side - dbgWnd->addText("#", Position(240, 10), fontsize); - dbgWnd->addText("#", Position(240, 20), fontsize); - dbgWnd->addText("#", Position(240, 30), fontsize); - dbgWnd->addText("#", Position(240, 40), fontsize); - dbgWnd->addText("#", Position(240, 50), fontsize); - dbgWnd->addText("#", Position(240, 60), fontsize); - dbgWnd->addText("#", Position(240, 70), fontsize); - dbgWnd->addText("#", Position(240, 80), fontsize); - dbgWnd->addText("#", Position(240, 90), fontsize); - dbgWnd->addText("#", Position(240, 100), fontsize); - dbgWnd->addText("#", Position(240, 110), fontsize); - dbgWnd->addText("#", Position(240, 120), fontsize); - dbgWnd->addText("#", Position(240, 130), fontsize); - dbgWnd->addText("#", Position(240, 140), fontsize); - dbgWnd->addText("#", Position(240, 150), fontsize); - dbgWnd->addText("#", Position(240, 160), fontsize); - dbgWnd->addText("#", Position(240, 170), fontsize); - dbgWnd->addText("#", Position(240, 180), fontsize); - dbgWnd->addText("#", Position(240, 190), fontsize); - dbgWnd->addText("#", Position(240, 200), fontsize); - dbgWnd->addText("#", Position(240, 210), fontsize); - dbgWnd->addText("#", Position(240, 220), fontsize); -} - -CDebug::~CDebug() -{ - global::s2->UnregisterCallback(dbgCallback_); - dbgWnd->setWaste(); -} - -void CDebug::sendParam(int Param) -{ - switch(Param) - { - case CALL_FROM_GAMELOOP: actualizeData(); break; - - case INCREMENT_MSWAIT: global::s2->msWait++; break; - - case DECREMENT_MSWAIT: - if(global::s2->msWait > 0) - global::s2->msWait--; - break; - - case SETZERO_MSWAIT: global::s2->msWait = 0; break; - - default: break; - } -} - -void CDebug::actualizeData() -{ - if(!FrameCounterText) - FrameCounterText = dbgWnd->addText("", Position(0, 10), fontsize); - // write new FrameCounterText and draw it - FrameCounterText->setText("Actual Frame: " + std::to_string(global::s2->FrameCounter)); - - // Frames per Second - static Uint32 tmpFrameCtr = 0, tmpTickCtr = SDL_GetTicks(); - if(tmpFrameCtr == 10) - { - // write new FramesPerSecText and draw it - if(!FramesPerSecText) - FramesPerSecText = dbgWnd->addText("", Position(0, 20), fontsize); - FramesPerSecText->setText( - helpers::format("Frames per Sec: %.2f", tmpFrameCtr / (((float)SDL_GetTicks() - tmpTickCtr) / 1000))); - // set new values - tmpFrameCtr = 0; - tmpTickCtr = SDL_GetTicks(); - } else - tmpFrameCtr++; - - // del msWaitText before drawing new - if(!msWaitText) - msWaitText = dbgWnd->addText("", Position(0, 35), fontsize); - // write new msWaitText and draw it - msWaitText->setText("Wait: " + std::to_string(global::s2->msWait)); - - // del MouseText before drawing new - if(!MouseText) - MouseText = dbgWnd->addText("", Position(0, 50), fontsize); - // write new MouseText and draw it - const char* clickedStr = - global::s2->Cursor.clicked ? - (global::s2->Cursor.button.left ? "LMB clicked" : - (global::s2->Cursor.button.right ? "RMB clicked" : "clicked")) : - "unclicked"; - MouseText->setText( - helpers::format("Mouse: x=%d y=%d %s", global::s2->Cursor.pos.x, global::s2->Cursor.pos.y, clickedStr)); - - // del RegisteredMenusText before drawing new - if(!RegisteredMenusText) - RegisteredMenusText = dbgWnd->addText("", Position(0, 60), fontsize); - // write new RegisteredMenusText and draw it - RegisteredMenusText->setText("Registered Menus: 0"); - - // del RegisteredWindowsText before drawing new - if(!RegisteredWindowsText) - RegisteredWindowsText = dbgWnd->addText("", Position(0, 70), fontsize); - // write new RegisteredWindowsText and draw it - RegisteredWindowsText->setText(helpers::format("Registered Windows: %d", global::s2->Windows.size())); - - // del RegisteredCallbacksText before drawing new - if(!RegisteredCallbacksText) - RegisteredCallbacksText = dbgWnd->addText("", Position(0, 80), fontsize); - // write new RegisteredCallbacksText and draw it - RegisteredCallbacksText->setText(helpers::format("Registered Callbacks: %d", global::s2->Callbacks.size())); - - if(!DisplayRectText) - DisplayRectText = dbgWnd->addText("", Position(0, 90), fontsize); - auto const displayRect = MapObj->getDisplayRect(); - DisplayRectText->setText(helpers::format("DisplayRect: (%d,%d)->(%d,%d)\n= size(%d, %d)", displayRect.left, - displayRect.top, displayRect.right, displayRect.bottom, - displayRect.getSize().x, displayRect.getSize().y)); - - // we will now write the map data if a map is active - MapObj = global::s2->MapObj.get(); - if(MapObj) - { - map = MapObj->getMap(); - const EditorMapNode& vertex = map->getVertex(MapObj->Vertex_); - - if(!MapNameText) - MapNameText = dbgWnd->addText("", Position(260, 10), fontsize); - MapNameText->setText("Map Name: " + map->getName()); - if(!MapSizeText) - MapSizeText = dbgWnd->addText("", Position(260, 20), fontsize); - MapSizeText->setText(helpers::format("Width: %d Height: %d", map->width, map->height)); - if(!MapAuthorText) - MapAuthorText = dbgWnd->addText("", Position(260, 30), fontsize); - MapAuthorText->setText("Author: " + map->getAuthor()); - if(!MapTypeText) - MapTypeText = dbgWnd->addText("", Position(260, 40), fontsize); - const char* ltStr = - map->type == MAP_GREENLAND ? - "Greenland" : - (map->type == MAP_WASTELAND ? "Wasteland" : (map->type == MAP_WINTERLAND ? "Winterland" : "Unknown")); - MapTypeText->setText(helpers::format("Type: %d (%s)", map->type, ltStr)); - if(!MapPlayerText) - MapPlayerText = dbgWnd->addText("", Position(260, 50), fontsize); - MapPlayerText->setText(helpers::format("Player: %d", map->player)); - if(!VertexText) - VertexText = dbgWnd->addText("", Position(260, 60), fontsize); - VertexText->setText(helpers::format("Vertex: %d, %d", MapObj->Vertex_.x, MapObj->Vertex_.y)); - if(!VertexDataText) - VertexDataText = dbgWnd->addText("", Position(260, 70), fontsize); - VertexDataText->setText(helpers::format("Vertex Data: x=%d, y=%d, z=%d i=%.2f h=%#04x", vertex.x, vertex.y, - vertex.z, ((float)vertex.i) / pow(2, 16), vertex.h)); - if(!VertexVectorText) - VertexVectorText = dbgWnd->addText("", Position(260, 80), fontsize); - VertexVectorText->setText(helpers::format("Vertex Vector: (%.2f, %.2f, %.2f)", vertex.normVector.x, - vertex.normVector.y, vertex.normVector.z)); - if(!FlatVectorText) - FlatVectorText = dbgWnd->addText("", Position(260, 90), fontsize); - FlatVectorText->setText(helpers::format("Flat Vector: (%.2f, %.2f, %.2f)", vertex.flatVector.x, - vertex.flatVector.y, vertex.flatVector.z)); - if(!rsuTextureText) - rsuTextureText = dbgWnd->addText("", Position(260, 100), fontsize); - rsuTextureText->setText(helpers::format("RSU-Texture: %#04x", vertex.rsuTexture)); - if(!usdTextureText) - usdTextureText = dbgWnd->addText("", Position(260, 110), fontsize); - usdTextureText->setText(helpers::format("USD-Texture: %#04x", vertex.usdTexture)); - if(!roadText) - roadText = dbgWnd->addText("", Position(260, 120), fontsize); - roadText->setText(helpers::format("road: %#04x", vertex.road)); - if(!objectTypeText) - objectTypeText = dbgWnd->addText("", Position(260, 130), fontsize); - objectTypeText->setText(helpers::format("objectType: %#04x", vertex.objectType)); - if(!objectInfoText) - objectInfoText = dbgWnd->addText("", Position(260, 140), fontsize); - objectInfoText->setText(helpers::format("objectInfo: %#04x", vertex.objectInfo)); - if(!animalText) - animalText = dbgWnd->addText("", Position(260, 150), fontsize); - animalText->setText(helpers::format("animal: %#04x", vertex.animal)); - if(!unknown1Text) - unknown1Text = dbgWnd->addText("", Position(260, 160), fontsize); - unknown1Text->setText(helpers::format("unknown1: %#04x", vertex.unknown1)); - if(!buildText) - buildText = dbgWnd->addText("", Position(260, 170), fontsize); - buildText->setText(helpers::format("build: %#04x", vertex.build)); - if(!unknown2Text) - unknown2Text = dbgWnd->addText("", Position(260, 180), fontsize); - unknown2Text->setText(helpers::format("unknown2: %#04x", vertex.unknown2)); - if(!unknown3Text) - unknown3Text = dbgWnd->addText("", Position(260, 190), fontsize); - unknown3Text->setText(helpers::format("unknown3: %#04x", vertex.unknown3)); - if(!resourceText) - resourceText = dbgWnd->addText("", Position(260, 200), fontsize); - resourceText->setText(helpers::format("resource: %#04x", vertex.resource)); - if(!shadingText) - shadingText = dbgWnd->addText("", Position(260, 210), fontsize); - shadingText->setText(helpers::format("shading: %#04x", vertex.shading)); - if(!unknown5Text) - unknown5Text = dbgWnd->addText("", Position(260, 220), fontsize); - unknown5Text->setText(helpers::format("unknown5: %#04x", vertex.unknown5)); - if(!editorModeText) - editorModeText = dbgWnd->addText("", Position(260, 230), fontsize); - editorModeText->setText(helpers::format("Editor --> Mode: %d Content: %#04x Content2: %#04x", MapObj->mode, - MapObj->modeContent, MapObj->modeContent2)); - } else - { - if(!MapNameText) - dbgWnd->addText("", Position(260, 10), fontsize); - // write new MapNameText and draw it - MapNameText->setText("No Map loaded!"); - if(MapSizeText) - { - dbgWnd->delText(MapSizeText); - MapSizeText = nullptr; - } - if(MapAuthorText) - { - dbgWnd->delText(MapAuthorText); - MapAuthorText = nullptr; - } - if(MapTypeText) - { - dbgWnd->delText(MapTypeText); - MapTypeText = nullptr; - } - if(MapPlayerText) - { - dbgWnd->delText(MapPlayerText); - MapPlayerText = nullptr; - } - if(VertexText) - { - dbgWnd->delText(VertexText); - VertexText = nullptr; - } - if(VertexDataText) - { - dbgWnd->delText(VertexDataText); - VertexDataText = nullptr; - } - if(VertexVectorText) - { - dbgWnd->delText(VertexVectorText); - VertexVectorText = nullptr; - } - if(FlatVectorText) - { - dbgWnd->delText(FlatVectorText); - FlatVectorText = nullptr; - } - if(rsuTextureText) - { - dbgWnd->delText(rsuTextureText); - rsuTextureText = nullptr; - } - if(usdTextureText) - { - dbgWnd->delText(usdTextureText); - usdTextureText = nullptr; - } - if(roadText) - { - dbgWnd->delText(roadText); - roadText = nullptr; - } - if(objectTypeText) - { - dbgWnd->delText(objectTypeText); - objectTypeText = nullptr; - } - if(objectInfoText) - { - dbgWnd->delText(objectInfoText); - objectInfoText = nullptr; - } - if(animalText) - { - dbgWnd->delText(animalText); - animalText = nullptr; - } - if(unknown1Text) - { - dbgWnd->delText(unknown1Text); - unknown1Text = nullptr; - } - if(buildText) - { - dbgWnd->delText(buildText); - buildText = nullptr; - } - if(unknown2Text) - { - dbgWnd->delText(unknown2Text); - unknown2Text = nullptr; - } - if(unknown3Text) - { - dbgWnd->delText(unknown3Text); - unknown3Text = nullptr; - } - if(resourceText) - { - dbgWnd->delText(resourceText); - resourceText = nullptr; - } - if(shadingText) - { - dbgWnd->delText(shadingText); - shadingText = nullptr; - } - if(unknown5Text) - { - dbgWnd->delText(unknown5Text); - unknown5Text = nullptr; - } - if(editorModeText) - { - dbgWnd->delText(editorModeText); - editorModeText = nullptr; - } - } - dbgWnd->setDirty(); -} - -#endif diff --git a/CDebug.h b/CDebug.h deleted file mode 100644 index cabda7e..0000000 --- a/CDebug.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "defines.h" - -class CFont; -class CWindow; -class CMap; -struct bobMAP; - -class CDebug -{ -private: - // callback fuction that is constructing the Debugger-Object - void (*dbgCallback_)(int); - // debugger window - CWindow* dbgWnd; - // text for FrameCounter - CFont* FrameCounterText; - // text for Frames per Second - CFont* FramesPerSecText; - // text for msWait (milliseconds to wait --> SDL_Delay()) - CFont* msWaitText; - // text for Registered Menus - CFont* RegisteredMenusText; - // text for Registered Windows - CFont* RegisteredWindowsText; - // text for Registered Callbacks - CFont* RegisteredCallbacksText; - CFont* DisplayRectText; - // text for mouse cursor data - CFont* MouseText; - // text for map name - CFont* MapNameText; - // text for map width and height - CFont* MapSizeText; - // text for map author - CFont* MapAuthorText; - // text for map type - CFont* MapTypeText; - // text for map players - CFont* MapPlayerText; - // text for position of cursor (position means the number of the triangle/vertex) - CFont* VertexText; - // text for data at the vertex the cursor is on - CFont* VertexDataText; - // text for vector at the vertex the cursor is on - CFont* VertexVectorText; - // text for vector at the triangle below the vertex the cursor is on - CFont* FlatVectorText; - // texts for map data at the vertex the cursor is on - CFont* rsuTextureText; - CFont* usdTextureText; - CFont* roadText; - CFont* objectTypeText; - CFont* objectInfoText; - CFont* animalText; - CFont* unknown1Text; - CFont* buildText; - CFont* unknown2Text; - CFont* unknown3Text; - CFont* resourceText; - CFont* shadingText; - CFont* unknown5Text; - CFont* editorModeText; - FontSize fontsize; - // temporary pointer to Map-Object - CMap* MapObj; - // temporary pointer to map - bobMAP* map; - - // enumeration for messages sent to the debugger - enum - { - WNDQUIT = 1, // debugger window closed - INCREMENT_MSWAIT, - DECREMENT_MSWAIT, - SETZERO_MSWAIT - }; - -public: - // Constructor, Destructor - CDebug(void dbgCallback_(int), int quitParam); - ~CDebug(); - // Methods - void sendParam(int Param); - void actualizeData(); -}; diff --git a/CGame.cpp b/CGame.cpp index 5845e5e..adfc87f 100644 --- a/CGame.cpp +++ b/CGame.cpp @@ -4,7 +4,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CGame.h" -#include "CIO/CWindow.h" #include "CMap.h" #include "RttrConfig.h" #include "files.h" @@ -34,8 +33,7 @@ namespace bfs = boost::filesystem; boost::program_options::variables_map parse_cmdline_args(int argc, char* argv[]); CGame::CGame(Extent GameResolution_, bool fullscreen_) - : GameResolution(GameResolution_), fullscreen(fullscreen_), Running(true), showLoadScreen(true), - lastFps("", Position{0, 0}, FontSize::Normal) + : GameResolution(GameResolution_), fullscreen(fullscreen_), Running(true), showLoadScreen(true) { global::s2 = this; } @@ -55,10 +53,7 @@ int CGame::Execute() if(!Init()) return -1; - lastFps.setText(""); - lastFpsTick = SDL_GetTicks(); lastFrameTime = SDL_GetTicks(); - framesPassedSinceLastFps = 0; while(Running) { @@ -66,9 +61,6 @@ int CGame::Execute() if(!VIDEODRIVER.Run()) Running = false; - // Old-style event handling for CWindows/CMap is disabled during migration. - // TODO: Reinstate when old windows are migrated to Desktop/IngameWindow. - GameLoop(); Render(); } @@ -84,35 +76,6 @@ void CGame::RenderPresent() VIDEODRIVER.SwapBuffers(); } -CWindow* CGame::RegisterWindow(std::unique_ptr Window) -{ - // first find the highest priority - const auto itHighestPriority = - std::max_element(Windows.cbegin(), Windows.cend(), - [](const auto& lhs, const auto& rhs) { return lhs->getPriority() < rhs->getPriority(); }); - const int highestPriority = itHighestPriority == Windows.cend() ? 0 : (*itHighestPriority)->getPriority(); - - for(auto& i : Windows) - i->setInactive(); - - Window->setActive(); - Window->setPriority(highestPriority + 1); - Windows.emplace_back(std::move(Window)); - - return Windows.back().get(); -} - -bool CGame::UnregisterWindow(CWindow* Window) -{ - auto it = std::find_if(Windows.begin(), Windows.end(), [Window](const auto& cur) { return cur.get() == Window; }); - if(it == Windows.end()) - return false; - if(it != Windows.begin()) - it[-1]->setActive(); - Windows.erase(it); - return true; -} - void CGame::RegisterCallback(void (*callback)(int)) { assert(callback); @@ -178,13 +141,6 @@ void CGame::GameLoop() { for(auto&& callback : Callbacks) callback(CALL_FROM_GAMELOOP); - const auto isWaste = [](const auto& p) { return p->isWaste(); }; - auto itWnd = std::find_if(Windows.begin(), Windows.end(), isWaste); - while(itWnd != Windows.end()) - { - UnregisterWindow(itWnd->get()); - itWnd = std::find_if(Windows.begin(), Windows.end(), isWaste); - } } namespace { diff --git a/CGame.h b/CGame.h index 68f4ce0..97b2202 100644 --- a/CGame.h +++ b/CGame.h @@ -5,7 +5,6 @@ #pragma once -#include "CIO/CFont.h" #include "SdlSurface.h" #include "Texture.h" #include "driver/VideoDriverLoaderInterface.h" @@ -14,12 +13,10 @@ #include #include -class CWindow; class CMap; class CGame : public VideoDriverLoaderInterface { - friend class CDebug; public: Extent GameResolution; @@ -31,16 +28,8 @@ class CGame : public VideoDriverLoaderInterface SdlWindow window_; private: -#ifdef _ADMINMODE - // some debugging variables - unsigned long int FrameCounter = 0; -#endif // milliseconds for SDL_Delay() Uint32 msWait = 0; - Uint32 framesPassedSinceLastFps = 0; - Uint32 lastFpsTick = 0; - CFont lastFps; - Uint32 lastFrameTime = 0; Extent appliedResolution_ = Extent{0, 0}; ///< Last resolution we applied to the window/display bool appliedFullscreen_ = false; ///< Last fullscreen state we applied @@ -63,8 +52,6 @@ class CGame : public VideoDriverLoaderInterface } button; } Cursor; - // Object for Windows - std::vector> Windows; // Object for Callbacks std::vector Callbacks; // Object for the Map @@ -102,7 +89,6 @@ class CGame : public VideoDriverLoaderInterface bool Init(); void UpdateDisplaySize(const Extent& newSize); - void EventHandling(SDL_Event* Event); void ForwardEventToWindowManager(SDL_Event* Event); void GameLoop(); @@ -111,13 +97,10 @@ class CGame : public VideoDriverLoaderInterface void RenderPresent(); - CWindow* RegisterWindow(std::unique_ptr Window); - bool UnregisterWindow(CWindow* Window); void RegisterCallback(void (*callback)(int)); bool UnregisterCallback(void (*callback)(int)); void setMapObj(std::unique_ptr MapObj); CMap* getMapObj(); void delMapObj(); void enterEditor(const boost::filesystem::path& filepath); - auto getRes() const { return GameResolution; } }; diff --git a/CGame_Event.cpp b/CGame_Event.cpp index 8642cd0..05b12a5 100644 --- a/CGame_Event.cpp +++ b/CGame_Event.cpp @@ -4,339 +4,13 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CGame.h" -#include "CIO/CWindow.h" #include "CMap.h" -#include "CSurface.h" -#include "CollisionDetection.h" #include "WindowManager.h" -#include "callbacks.h" #include "drivers/VideoDriverWrapper.h" #include "enum_cast.hpp" #include "globals.h" #include "s25util/utf8.h" -void CGame::EventHandling(SDL_Event* Event) -{ - switch(Event->type) - { - case SDL_KEYDOWN: - { - // NOTE: we will now deliver the data to menus, windows, map etc., sometimes we have to break the switch and - // stop - // delivering earlier, for doing this we make use of a variable showing us the deliver status - bool delivered = false; - // now we walk through the windows and find out, if cursor is on one of these (ordered by priority) - // we have to change the prioritys of the windows (for rendering), so find the highest one - int highestPriority = 0; - for(auto& Window : Windows) - { - if(Window->getPriority() > highestPriority) - highestPriority = Window->getPriority(); - } - - for(auto& Window : Windows) - { - if(!Window->isWaste() && Window->isMarked() && Window->getPriority() == highestPriority - && Window->hasActiveInputElement()) - { - Window->setKeyboardData(Event->key); - delivered = true; - break; - } - } - // if (delivered) - // break; - - // deliver keyboard data to map if active - if(!delivered) - { - if(MapObj && MapObj->isActive()) - { - MapObj->setKeyboardData(Event->key); - // data has been delivered to map, so no menu is in the foreground --> stop delivering - // break; - } - - - } - - switch(Event->key.keysym.sym) - { - case SDLK_RETURN: - case SDLK_KP_ENTER: - if(Event->key.keysym.mod & KMOD_ALT) - { - fullscreen = !fullscreen; - ApplyWindowChanges(); - SaveSettings(); - } - break; - -#ifdef _ADMINMODE - case SDLK_F3: // if CTRL and ALT are pressed - // if (SDL_GetModState() == (KMOD_LCTRL | KMOD_LALT)) - callback::debugger(INITIALIZING_CALL); - break; - -#endif - // Zoom keys removed — TerrainRenderer handles zoom via glScale - - default: break; - } - - break; - } - - case SDL_KEYUP: - { - // deliver keyboard data to map - if(MapObj) - MapObj->setKeyboardData(Event->key); - - break; - } - - case SDL_MOUSEMOTION: - { - // setup mouse cursor data - if(MapObj && MapObj->isActive()) - { - if((Event->motion.state & SDL_BUTTON(SDL_BUTTON_RIGHT)) == 0) - { - Cursor.pos = Position(Event->motion.x, Event->motion.y); - } - } else - { - Cursor.pos = Position(Event->motion.x, Event->motion.y); - } - /* - //NOTE: we will now deliver the data to menus, windows, map etc., sometimes we have to break the - switch and stop - // delivering earlier, for doing this we make use of a variable showing us the deliver - status int delivered = false; - //deliver mouse motion data to the active window - for (int i = 0; i < MAXWINDOWS; i++) - { - if (Windows[i] != nullptr && Windows[i]->isActive() && !Windows[i]->isWaste()) - { - Windows[i]->setMouseData(Event->motion); - if ( (Event->motion.x >= Windows[i]->getX()) && (Event->motion.x < Windows[i]->getX() + - Windows[i]->getW()) - && (Event->motion.y >= Windows[i]->getY()) && (Event->motion.y < Windows[i]->getY() + Windows[i]->getH()) - ) delivered = true; - } - } - if (delivered) - break; - */ - - // NOTE: we will now deliver the data to menus, windows, map etc., sometimes we have to break the switch and - // stop - // delivering earlier, for doing this we make use of a variable showing us the deliver status - bool delivered = false; - // now we walk through the windows and find out, if cursor is on one of these (ordered by priority) - // we have to change the prioritys of the windows (for rendering), so find the highest one - int highestPriority = 0; - for(auto& Window : Windows) - { - if(Window->getPriority() > highestPriority) - highestPriority = Window->getPriority(); - } - - for(int actualPriority = highestPriority; actualPriority >= 0; actualPriority--) - { - for(auto& Window : Windows) - { - if(!Window->isWaste() && Window->getPriority() == actualPriority) - { - // is the cursor INSIDE the window or does the user move or resize the window? - if(IsPointInRect(Event->motion.x, Event->motion.y, Rect(Window->getPos(), Window->getSize())) - || Window->isMoving() || Window->isResizing()) - { - // Windows[i]->setActive(); - // Windows[i]->setPriority(highestPriority+1); - Window->setMouseData(Event->motion); - delivered = true; - break; - } - } - } - if(delivered) - break; - } - // if mouse data has been delivered, stop delivering anymore - if(delivered) - break; - - // deliver mouse motion data to map if active - if(MapObj && MapObj->isActive()) - { - MapObj->setMouseData(Event->motion); - // data has been delivered to map, so no menu is in the foreground --> stop delivering - break; - } - - - - break; - } - - case SDL_MOUSEBUTTONDOWN: - { - // setup mouse cursor data - Cursor.clicked = true; - Cursor.button.left = false; - Cursor.button.right = false; - if(Event->button.button == SDL_BUTTON_LEFT) - Cursor.button.left = true; - else if(Event->button.button == SDL_BUTTON_RIGHT) - Cursor.button.right = true; - - // clicking a mouse button will close the S2 loading screen if it is shown - if(showLoadScreen) - { - showLoadScreen = false; - // prevent pressing another object "behind" the loading screen - break; - } - - // NOTE: we will now deliver the data to menus, windows, map etc., sometimes we have to break the switch and - // stop - // delivering earlier, for doing this we make use of a variable showing us the deliver status - bool delivered = false; - // now we walk through the windows and find out, if cursor is on one of these (ordered by priority) - // we have to change the prioritys of the windows (for rendering), so find the highest one - int highestPriority = 0; - for(auto& Window : Windows) - { - if(Window->getPriority() > highestPriority) - highestPriority = Window->getPriority(); - } - - for(int actualPriority = highestPriority; actualPriority >= 0; actualPriority--) - { - for(auto& Window : Windows) - { - if(!Window->isWaste() && Window->getPriority() == actualPriority) - { - // is the cursor INSIDE the window? - if(IsPointInRect(Event->button.x, Event->button.y, Rect(Window->getPos(), Window->getSize()))) - { - Window->setActive(); - Window->setPriority(highestPriority + 1); - Window->setMouseData(Event->button); - delivered = true; - break; - } else if(Window->isActive()) - Window->setInactive(); - } - } - if(delivered) - break; - } - // if mouse data has been deliverd, stop delivering anymore - if(delivered) - break; - - // deliver mouse button data to map if active - if(MapObj && MapObj->isActive()) - { - MapObj->setMouseData(Event->button); - // data has been delivered to map, so no menu is in the foreground --> stop delivering - break; - } - - break; - } - - case SDL_MOUSEBUTTONUP: - { - // setup mouse cursor data - Cursor.clicked = false; - - // NOTE: we will now deliver the data to menus, windows, map etc., sometimes we have to break the switch and - // stop - // delivering earlier, for doing this we make use of a variable showing us the deliver status - bool delivered = false; - // now we walk through the windows and find out, if cursor is on one of these (ordered by priority) - // we have to change the prioritys of the windows (for rendering), so find the highest one - int highestPriority = 0; - for(auto& Window : Windows) - { - if(Window->getPriority() > highestPriority) - highestPriority = Window->getPriority(); - } - - for(int actualPriority = highestPriority; actualPriority >= 0; actualPriority--) - { - for(auto& Window : Windows) - { - if(!Window->isWaste() && Window->getPriority() == actualPriority) - { - // is the cursor INSIDE the window? - if(IsPointInRect(Event->button.x, Event->button.y, Rect(Window->getPos(), Window->getSize()))) - { - // Windows[i]->setActive(); - // Windows[i]->setPriority(highestPriority+1); - Window->setMouseData(Event->button); - delivered = true; - break; - } - // else if (Windows[i]->isActive()) - // Windows[i]->setInactive(); - } - } - if(delivered) - break; - } - // if mouse data has been deliverd, stop delivering anymore - /// We can't stop here cause of problems with the map. If user has the left mouse button pressed and - /// modifies the vertices, it will cause a problem if he walks over a window with pressed mouse button and - /// releases it in the window. So the MapObj needs the "release-event" of the mouse button. - // if (delivered) - // break; - - // if still not delivered, keep delivering to secondary elements like menu or map - - // deliver mouse button data to map if active - if(MapObj && MapObj->isActive()) - { - MapObj->setMouseData(Event->button); - // data has been delivered to map, so no menu is in the foreground --> stop delivering - break; - } - - /// now we do what we commented out a few lines before - if(delivered) - break; - - break; - } - - case SDL_WINDOWEVENT: - { - if(Event->window.event == SDL_WINDOWEVENT_RESIZED) - { - // In fullscreen the compositor (e.g. Wayland) may report a size - // different from the one we requested. We already applied the - // resolution ourselves, so don't let the event override it. - if(fullscreen) - break; - const Extent newSize(Event->window.data1, Event->window.data2); - // Ignore events matching the resolution we already applied. - if(newSize == appliedResolution_) - break; - UpdateDisplaySize(newSize); - } - break; - } - - case SDL_QUIT: Running = false; break; - - default: break; - } -} - void CGame::ForwardEventToWindowManager(SDL_Event* ev) { static MouseCoords mouse_xy; diff --git a/CGame_Init.cpp b/CGame_Init.cpp index 0765ded..286bbce 100644 --- a/CGame_Init.cpp +++ b/CGame_Init.cpp @@ -4,11 +4,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CGame.h" -#include "CIO/CFile.h" -#include "CIO/CWindow.h" #include "CMap.h" #include "WindowManager.h" -#include "callbacks.h" #include "dskMainMenu.h" #include "globals.h" #include "Loader.h" @@ -167,12 +164,6 @@ bool CGame::Init() } /*NOTE: its important to load a palette at first, * otherwise all images will be black (in exception of the LBM-Files, they have their own palette). - * if its necessary to load pictures from a - * specified file with a special palette, so - * load this palette from a file and set - * CFile::palActual = CFile::palArray - 1 (--> last loaden palette) - * and after loading the images set - * CFile::palActual = CFile::palArray (--> first palette) */ // load some pictures (after all the splash-screens) @@ -330,7 +321,7 @@ bool CGame::Init() auto* pal = dynamic_cast(editres.get(1)); if(pal) global::currentPalette = pal; - // Store the complete Archiv in typedArchives — fonts stay inside for CFont to read directly + // Store the complete Archiv in typedArchives // Indices match file positions: 0=Font, 1=Palette, 2=Font, 3=Font, 4-56=Bitmaps global::typedArchives[ArchiveID::EDITRES] = std::move(editres); } @@ -365,14 +356,7 @@ bool CGame::Init() std::cout << "done"; } - /* - std::cout << "\nLoading palette from file: GFX/PALETTE/PAL5.BBM..."; - if ( !CFile::open_file(global::gameDataFilePath / "GFX/PALETTE/PAL5.BBM", BBM, true) ) - { - std::cout << "failure"; - return false; - } - */ + // EVERY MISSION-FILE SHOULD BE LOADED SEPARATLY IF THE SPECIFIED MISSION GOES ON -- SO THIS IS TEMPORARY const ArchiveID misArchives[] = {ArchiveID::MIS0BOBS, ArchiveID::MIS1BOBS, ArchiveID::MIS2BOBS, diff --git a/CGame_Render.cpp b/CGame_Render.cpp index 39cbc2c..9f81a05 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -4,8 +4,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CGame.h" -#include "CIO/CFont.h" -#include "CIO/CWindow.h" #include "CMap.h" #include "CSurface.h" #include "Texture.h" @@ -90,72 +88,14 @@ void CGame::Render() glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); - - // HUD text overlays drawn directly via OpenGL - std::array textBuffer; - // text for x and y of vertex (shown in upper left corner) - std::snprintf(textBuffer.data(), textBuffer.size(), "%d %d", MapObj->getVertexX(), MapObj->getVertexY()); - CFont::draw(textBuffer.data(), Position(20, 20)); - // text for MinReduceHeight and MaxRaiseHeight - std::snprintf(textBuffer.data(), textBuffer.size(), - "min. height: %#04x/0x3C max. height: %#04x/0x3C NormalNull: 0x0A", - MapObj->getMinReduceHeight(), MapObj->getMaxRaiseHeight()); - CFont::draw(textBuffer.data(), Position(100, 20)); - // text for MovementLocked - if(MapObj->isHorizontalMovementLocked() && MapObj->isVerticalMovementLocked()) - CFont::draw("Movement locked (F9 or F10 to unlock)", Position(20, 40), FontSize::Large, FontColor::Orange); - else if(MapObj->isHorizontalMovementLocked()) - CFont::draw("Horizontal movement locked (F9 to unlock)", Position(20, 40), FontSize::Large, - FontColor::Orange); - else if(MapObj->isVerticalMovementLocked()) - CFont::draw("Vertical movement locked (F10 to unlock)", Position(20, 40), FontSize::Large, - FontColor::Orange); - } - - // render windows ordered by priority - int highestPriority = 0; - // first find the highest priority - for(auto& Window : Windows) - { - if(Window->getPriority() > highestPriority) - highestPriority = Window->getPriority(); - } - // render from lowest priority to highest - for(int actualPriority = 0; actualPriority <= highestPriority; actualPriority++) - { - for(auto& Window : Windows) - { - if(Window->getPriority() == actualPriority) - Window->draw(Position(0, 0)); - } - } - -#ifdef _ADMINMODE - FrameCounter++; -#endif - - ++framesPassedSinceLastFps; - const auto curTicks = SDL_GetTicks(); - const auto diffTicks = curTicks - lastFpsTick; - if(diffTicks > 1000) - { - lastFps.setText(std::to_string((framesPassedSinceLastFps * 1000) / diffTicks) + " FPS"); - framesPassedSinceLastFps = 0; - lastFpsTick = curTicks; } - lastFps.draw(Position(0, 0)); - - // Cursor is drawn by WindowManager via DrawCursor() VIDEODRIVER.SwapBuffers(); -#ifdef _ADMINMODE - FrameCounter++; -#endif - if(msWait) SDL_Delay(msWait); + const auto curTicks = SDL_GetTicks(); const auto timeSinceLastFrame = curTicks - lastFrameTime; const auto targetFPS = 60; const auto targetMsPerFrame = 1000 / targetFPS; diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp deleted file mode 100644 index 848b5e3..0000000 --- a/CIO/CButton.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CButton.h" -#include "../Texture.h" -#include "../globals.h" -#include "CFont.h" -#include "CollisionDetection.h" - -CButton::CButton(void callback(int), int clickedParam, Position pos, Extent size, int color, const char* text, - int button_picture) - : pos_(pos), size_(size) -{ - marked = false; - clicked = false; - setColor(color); - this->button_picture = button_picture; - button_text = text; - button_text_color = FontColor::Yellow; - this->callback_ = callback; - this->clickedParam = clickedParam; - motionEntryParam = -1; - motionLeaveParam = -1; -} - -void CButton::setButtonPicture(int picture) -{ - this->button_picture = picture; -} - -void CButton::setButtonText(const char* text) -{ - button_text = text; -} - -void CButton::setColor(int color) -{ - switch(color) - { - case BUTTON_GREY: - pic_normal = BUTTON_GREY_DARK; - pic_marked = BUTTON_GREY_BRIGHT; - pic_background = BUTTON_GREY_BACKGROUND; - break; - - case BUTTON_RED1: - pic_normal = BUTTON_RED1_DARK; - pic_marked = BUTTON_RED1_BRIGHT; - pic_background = BUTTON_RED1_BACKGROUND; - break; - - case BUTTON_GREEN1: - pic_normal = BUTTON_GREEN1_DARK; - pic_marked = BUTTON_GREEN1_BRIGHT; - pic_background = BUTTON_GREEN1_BACKGROUND; - break; - - case BUTTON_GREEN2: - pic_normal = BUTTON_GREEN2_DARK; - pic_marked = BUTTON_GREEN2_BRIGHT; - pic_background = BUTTON_GREEN2_BACKGROUND; - break; - - case BUTTON_RED2: - pic_normal = BUTTON_RED2_DARK; - pic_marked = BUTTON_RED2_BRIGHT; - pic_background = BUTTON_RED2_BACKGROUND; - break; - - case BUTTON_STONE: - pic_normal = BUTTON_STONE_DARK; - pic_marked = BUTTON_STONE_BRIGHT; - pic_background = BUTTON_STONE_BACKGROUND; - break; - - default: - pic_normal = BUTTON_GREY_DARK; - pic_marked = BUTTON_GREY_BRIGHT; - pic_background = BUTTON_GREY_BACKGROUND; - break; - } -} - -void CButton::setMouseData(const SDL_MouseMotionEvent& motion) -{ - // cursor is on the button (and mouse button not pressed while moving on the button) - if(IsPointInRect(motion.x, motion.y, Rect(pos_, size_))) - { - if(motion.state == SDL_RELEASED) - { - marked = true; - if(motionEntryParam >= 0 && callback_) - callback_(motionEntryParam); - } - } else - { - // button was marked before and mouse cursor is on the button now, so do the callback - if(motionLeaveParam >= 0 && callback_ && marked) - callback_(motionLeaveParam); - marked = false; - } -} - -void CButton::setMouseData(const SDL_MouseButtonEvent& button) -{ - // left button is pressed - if(button.button == SDL_BUTTON_LEFT) - { - // if mouse button is pressed ON the button, set marked=true - if(button.state == SDL_PRESSED && IsPointInRect(button.x, button.y, Rect(pos_, size_))) - { - marked = true; - clicked = true; - } else if(button.state == SDL_RELEASED) - { - clicked = false; - // if mouse button is released ON the BUTTON (marked = true), then do the callback - if(marked && callback_) - callback_(clickedParam); - } - } -} - -void CButton::draw(Position parentOrigin) const -{ - const Position absPos = parentOrigin + pos_; - - // Draw 3D button box - const int foreground = (marked && !clicked) ? pic_marked : pic_normal; - drawButtonBox(Rect(absPos, size_), clicked, pic_background, foreground); - - // 4. Draw picture or text centered inside the button - if(button_picture >= 0) - { - auto& picTex = getTexture(ArchiveID::EDITIO, button_picture); - const Position picPos = absPos + size_ / 2 - Position(picTex.getSize()) / 2; - picTex.draw(picPos); - } else if(button_text) - { - // Draw text centered (using native-size texture drawing for each character) - const Extent textSize(CFont::getTextWidth(button_text, FontSize::Normal), - getFontHeightPx(FontSize::Normal)); - const Position textPos = absPos + (Position(size_) - textSize) / 2; - CFont::draw(button_text, textPos, FontSize::Normal, button_text_color, FontAlign::Left); - } -} diff --git a/CIO/CButton.h b/CIO/CButton.h deleted file mode 100644 index 27fe79d..0000000 --- a/CIO/CButton.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "defines.h" - -class CButton -{ - friend class CDebug; - -private: - Position pos_; - Extent size_; - int pic_normal; - int pic_marked; - int pic_background; - int button_picture; - const char* button_text; - FontColor button_text_color; - bool marked; - bool clicked; - void (*callback_)(int); - int clickedParam; - int motionEntryParam; - int motionLeaveParam; - -public: - CButton(void callback(int), int clickedParam, Position pos = {0, 0}, Extent size = {20, 20}, - int color = BUTTON_GREY, const char* text = nullptr, int button_picture = -1); - // Access - int getX() const { return pos_.x; }; - int getY() const { return pos_.y; }; - Position getPos() const { return pos_; } - Extent getSize() const { return size_; }; - void setX(int x) { pos_.x = x; }; - void setY(int y) { pos_.y = y; }; - void setButtonPicture(int picture); - void setButtonText(const char* text); - void setMouseData(const SDL_MouseMotionEvent& motion); - void setMouseData(const SDL_MouseButtonEvent& button); - void draw(Position parentOrigin) const; - void setColor(int color); - void setTextColor(FontColor color) { button_text_color = color; }; - void setMotionParams(int entry, int leave) - { - motionEntryParam = entry; - motionLeaveParam = leave; - }; -}; diff --git a/CIO/CControlContainer.cpp b/CIO/CControlContainer.cpp deleted file mode 100644 index 39fe95c..0000000 --- a/CIO/CControlContainer.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CControlContainer.h" -#include "../Texture.h" -#include "../globals.h" -#include "CButton.h" -#include "CFont.h" -#include "CPicture.h" -#include "CSelectBox.h" -#include "CTextfield.h" -#include "helpers/containerUtils.h" - -BorderSizes::BorderSizes(ArchiveID archive, int leftIdx, int topIdx, int rightIdx, int bottomIdx) - : left(static_cast(global::getBitmapSize(archive, leftIdx).x)), - top(static_cast(global::getBitmapSize(archive, topIdx).y)), - right(static_cast(global::getBitmapSize(archive, rightIdx).x)), - bottom(static_cast(global::getBitmapSize(archive, bottomIdx).y)) -{} - -CControlContainer::CControlContainer(int pic_background, ArchiveID archive) - : CControlContainer(pic_background, BorderSizes{}, archive) -{} -CControlContainer::CControlContainer(int pic_background, BorderSizes border, ArchiveID archive) - : backgroundArchive_(archive), border(border), pic_background(pic_background) -{} - -CControlContainer::~CControlContainer() noexcept = default; - -void CControlContainer::setBackgroundPicture(int pic_background, ArchiveID archive) -{ - this->pic_background = pic_background; - backgroundArchive_ = archive; -} - -void CControlContainer::setMouseData(const SDL_MouseMotionEvent motion) -{ - for(const auto& picture : pictures) - { - picture->setMouseData(motion); - } - for(const auto& button : buttons) - { - button->setMouseData(motion); - } - for(const auto& selectbox : selectboxes) - { - selectbox->setMouseData(motion); - } -} - -void CControlContainer::setMouseData(const SDL_MouseButtonEvent button) -{ - for(const auto& picture : pictures) - { - picture->setMouseData(button); - } - for(const auto& i : buttons) - { - i->setMouseData(button); - } - for(const auto& textfield : textfields) - { - textfield->setMouseData(button); - } - for(const auto& selectbox : selectboxes) - { - selectbox->setMouseData(button); - } -} - -void CControlContainer::setKeyboardData(const SDL_KeyboardEvent& key) -{ - for(const auto& textfield : textfields) - { - textfield->setKeyboardData(key); - } -} - -template -bool CControlContainer::eraseElement(T& collection, const U* element) -{ - const auto it = helpers::find_if(collection, [element](const auto& cur) { return cur.get() == element; }); - if(it != collection.end()) - { - collection.erase(it); - return true; - } - return false; -} - -CButton* CControlContainer::addButton(void callback(int), int clickedParam, Position pos, Extent size, int color, - const char* text, int picture) -{ - pos = pos + Position(border.left, border.top); - - buttons.emplace_back(std::make_unique(callback, clickedParam, pos, size, color, text, picture)); - return buttons.back().get(); -} - -bool CControlContainer::delButton(CButton* ButtonToDelete) -{ - return eraseElement(buttons, ButtonToDelete); -} - -CFont* CControlContainer::addText(std::string string, Position pos, FontSize fontsize, FontColor color) -{ - pos = pos + Position(border.left, border.top); - - texts.emplace_back(std::make_unique(std::move(string), pos, fontsize, color)); - return texts.back().get(); -} - -bool CControlContainer::delText(CFont* TextToDelete) -{ - return eraseElement(texts, TextToDelete); -} - -CPicture* CControlContainer::addPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, - unsigned localIndex) -{ - pos = pos + Position(border.left, border.top); - - pictures.emplace_back(std::make_unique(callback, clickedParam, pos, archive, localIndex)); - return pictures.back().get(); -} - -bool CControlContainer::delPicture(CPicture* PictureToDelete) -{ - return eraseElement(pictures, PictureToDelete); -} - -int CControlContainer::addStaticPicture(Position pos, ArchiveID archive, unsigned localIndex) -{ - pos = pos + Position(border.left, border.top); - - unsigned id = static_pictures.empty() ? 0u : static_pictures.back().id + 1u; - static_pictures.emplace_back(Picture{pos, archive, localIndex, id}); - return id; -} - -bool CControlContainer::delStaticPicture(int picId) -{ - if(picId < 0) - return false; - const auto it = - helpers::find_if(static_pictures, [picId](const auto& pic) { return static_cast(picId) == pic.id; }); - if(it != static_pictures.end()) - { - static_pictures.erase(it); - return true; - } - return false; -} - -CTextfield* CControlContainer::addTextfield(Position pos, Uint16 cols, Uint16 rows, FontSize fontsize, - FontColor text_color, int bg_color, bool button_style) -{ - pos = pos + Position(border.left, border.top); - - textfields.emplace_back( - std::make_unique(pos, cols, rows, fontsize, text_color, bg_color, button_style)); - return textfields.back().get(); -} - -bool CControlContainer::delTextfield(CTextfield* TextfieldToDelete) -{ - return eraseElement(textfields, TextfieldToDelete); -} - -CSelectBox* CControlContainer::addSelectBox(Position pos, Extent size, FontSize fontsize, FontColor text_color, - int bg_color) -{ - pos += Position(border.left, border.top); - - selectboxes.emplace_back(std::make_unique(pos, size, fontsize, text_color, bg_color)); - return selectboxes.back().get(); -} - -bool CControlContainer::delSelectBox(CSelectBox* SelectBoxToDelete) -{ - return eraseElement(selectboxes, SelectBoxToDelete); -} - -void CControlContainer::drawChildren(Position origin) -{ - for(const auto& picture : pictures) - picture->draw(origin); - for(const auto& text : texts) - text->draw(origin); - for(const auto& textfield : textfields) - textfield->draw(origin); - for(const auto& selectbox : selectboxes) - selectbox->draw(origin); - for(const auto& button : buttons) - button->draw(origin); - for(const auto& static_picture : static_pictures) - { - getTexture(static_picture.archive, static_picture.pic).draw(origin + static_picture.pos); - } -} diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h deleted file mode 100644 index e531f9b..0000000 --- a/CIO/CControlContainer.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "ArchiveID.h" -#include "defines.h" -#include -#include - -class CButton; -class CFont; -class CPicture; -class CTextfield; -class CSelectBox; - -/// Pixel thickness of a window's frame border on each edge. -struct BorderSizes -{ - int left = 0; - int top = 0; - int right = 0; - int bottom = 0; - - BorderSizes() = default; - - /// Construct border sizes from four bitmap indices in an archive. - /// Each field is set to the relevant dimension of the corresponding bitmap: - /// left/right = bitmap width, top/bottom = bitmap height. - BorderSizes(ArchiveID archive, int leftIdx, int topIdx, int rightIdx, int bottomIdx); -}; - -class CControlContainer -{ - friend class CDebug; - -private: - struct Picture - { - Position pos; - ArchiveID archive; - unsigned pic; - unsigned id; - }; - -protected: - ArchiveID backgroundArchive_; - - // if waste is true, the menu will be delete within the game loop - BorderSizes border; - bool waste = false; - int pic_background; - std::vector> buttons; - std::vector> texts; - std::vector> pictures; - std::vector> textfields; - std::vector> selectboxes; - std::vector static_pictures; - - template - bool eraseElement(T& collection, const U* element); - -protected: - /// Draw the container's background and child elements - /// @param parentOrigin Absolute position of the parent container. - virtual void draw(Position parentOrigin) = 0; - /// Draw children at the given origin (calls each child's Draw). - void drawChildren(Position origin); - - auto& getTextFields() { return textfields; } - const auto& getTextFields() const { return textfields; } - int getBackground() const { return pic_background; } - -public: - CControlContainer(int pic_background, ArchiveID archive); - CControlContainer(int pic_background, BorderSizes border, ArchiveID archive); - virtual ~CControlContainer() noexcept; - // Access - BorderSizes getBorderSizes() const { return border; } - Extent getBorderSize() const - { - return {static_cast(border.left + border.right), static_cast(border.top + border.bottom)}; - } - void setBackgroundPicture(int pic_background, ArchiveID archive); - virtual void setMouseData(SDL_MouseMotionEvent motion); - virtual void setMouseData(SDL_MouseButtonEvent button); - void setKeyboardData(const SDL_KeyboardEvent& key); - void setWaste() { waste = true; } - bool isWaste() const { return waste; } - // Methods - CButton* addButton(void callback(int), int clickedParam, Position pos = {0, 0}, Extent size = {20, 20}, - int color = BUTTON_GREY, const char* text = nullptr, int picture = -1); - bool delButton(CButton* ButtonToDelete); - CFont* addText(std::string string, Position pos, FontSize fontsize, FontColor color = FontColor::Yellow); - bool delText(CFont* TextToDelete); - CPicture* addPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, unsigned localIndex); - bool delPicture(CPicture* PictureToDelete); - int addStaticPicture(Position pos, ArchiveID archive, unsigned localIndex); - bool delStaticPicture(int picId); - CTextfield* addTextfield(Position pos = {0, 0}, Uint16 cols = 10, Uint16 rows = 1, - FontSize fontsize = FontSize::Large, FontColor text_color = FontColor::Yellow, - int bg_color = -1, bool button_style = false); - bool delTextfield(CTextfield* TextfieldToDelete); - CSelectBox* addSelectBox(Position pos, Extent size, FontSize fontsize = FontSize::Large, - FontColor text_color = FontColor::Yellow, int bg_color = -1); - bool delSelectBox(CSelectBox* SelectBoxToDelete); -}; diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp deleted file mode 100644 index 30804f2..0000000 --- a/CIO/CFont.cpp +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CFont.h" -#include "../CIO/CFile.h" -#include "../CSurface.h" -#include "../Texture.h" -#include "../globals.h" -#include "CollisionDetection.h" -#include -#include -#include -#include -#include -#include -#include -#include - -CFont::CFont(std::string text, Position pos, FontSize fontsize, FontColor color) - : pos_(pos), string_(std::move(text)), fontsize_(fontsize), color_(color), initialColor_(color), clickedParam(0) -{ - size_ = Extent(getTextWidth(string_, fontsize_), getLineHeight(fontsize_)); -} - -void CFont::setPos(Position pos) -{ - pos_ = pos; -} - -void CFont::setFontsize(FontSize fontsize) -{ - fontsize_ = fontsize; - size_ = Extent(getTextWidth(string_, fontsize_), getLineHeight(fontsize_)); -} - -void CFont::setColor(FontColor color) -{ - initialColor_ = color_ = color; -} - -void CFont::setText(std::string text) -{ - if(text == string_) - return; - this->string_ = std::move(text); - size_ = Extent(getTextWidth(string_, fontsize_), getLineHeight(fontsize_)); -} - -void CFont::setMouseData(SDL_MouseButtonEvent button) -{ - if(!callback) - return; - // left button is pressed - if(button.button == SDL_BUTTON_LEFT) - { - if(IsPointInRect(button.x, button.y, Rect(pos_, size_))) - { - // if mouse button is pressed ON the text - if(button.state == SDL_PRESSED && getColor() == initialColor_) - { - const auto tmpInitialColor = initialColor_; - setColor(FontColor::Orange); - initialColor_ = tmpInitialColor; - } else if(button.state == SDL_RELEASED && getColor() == FontColor::Orange) - { - callback(clickedParam); - } - } else if(getColor() != initialColor_) - setColor(initialColor_); - } -} - -// atlas-based rendering -struct GlyphPos -{ - unsigned x, y, w; -}; -struct FontAtlas -{ - Texture tex; - unsigned lineHeight = 0; - unsigned maxWidth = 0; - std::array glyphs{}; -}; - -static libsiedler2::ColorRGB getPlayerColor(FontColor color) -{ - switch(color) - { - case FontColor::Blue: return {64, 128, 255}; - case FontColor::Red: return {255, 64, 64}; - case FontColor::Orange: return {255, 165, 0}; - case FontColor::Green: return {64, 192, 64}; - case FontColor::MintGreen: return {64, 255, 160}; - case FontColor::Yellow: return {255, 255, 0}; - case FontColor::BrightRed: return {255, 32, 32}; - } - return {255, 255, 0}; -} - -static FontAtlas& getAtlas(FontSize size, FontColor color) -{ - static FontAtlas atlases[3][7]; - int ci = static_cast(color); - if(ci < 0 || ci > 6) - ci = 0; - int si = static_cast(size); - if(!atlases[si][ci].tex.isValid()) - { - auto& a = atlases[si][ci]; - // Resolve the font from the EDITRES archive by height - unsigned targetDy = getFontHeightPx(size); - auto& archiv = global::typedArchives[ArchiveID::EDITRES]; - const libsiedler2::ArchivItem_Font* font = nullptr; - for(unsigned i = 0; i < archiv.size(); i++) - { - auto* f = dynamic_cast(archiv.get(i)); - if(!f) - continue; - unsigned dy = f->getDy(); - if(dy + 1 >= targetDy && dy <= targetDy + 1) - { - font = f; - break; - } - } - if(!font) - return a; - - a.lineHeight = font->getDy() + 1; - unsigned advW = font->getDx(); - a.maxWidth = advW; - - unsigned numGlyphs = 0; - for(unsigned i = 32; i < font->size(); ++i) - { - if(font->get(i)) - numGlyphs++; - } - if(numGlyphs == 0) - return a; - - auto numCols = static_cast(std::sqrt(static_cast(numGlyphs))); - if(numCols < 1) - numCols = 1; - unsigned numRows = (numGlyphs + numCols - 1) / numCols; - constexpr Extent spacing(1, 1); - Extent cellSize(advW + spacing.x * 2, font->getDy() + spacing.y * 2); - Extent texSize = cellSize * Extent(numCols, numRows) + spacing * 2u; - - libsiedler2::PixelBufferBGRA buffer(texSize.x, texSize.y); - - // Build a palette where player-color indices 128-135 map to the - // requested FontColor, and everything else is dark outline. - auto playerClr = getPlayerColor(color); - auto atlasPal = std::make_unique(); - { - const auto* srcPal = global::currentPalette; - if(!srcPal) - return a; - for(int i = 0; i < 256; i++) - { - if(i >= 128 && i < 136) - atlasPal->set(i, playerClr); - else if(i == 0) - atlasPal->set(i, libsiedler2::ColorRGB(0, 0, 0)); // transparent background - else - atlasPal->set(i, libsiedler2::ColorRGB(32, 32, 32)); // dark outline - } - } - - unsigned gi = 0; - for(unsigned ci = 32; ci < font->size(); ++ci) - { - auto* sub = font->get(ci); - const auto* pg = dynamic_cast(sub); - if(!pg) - continue; - - unsigned col = gi % numCols, row = gi / numCols; - unsigned px = spacing.x + col * cellSize.x; - unsigned py = spacing.y + row * cellSize.y; - - const_cast(pg)->print(buffer, atlasPal.get(), 128, px, py, 0, 0, 0, - 0); - a.glyphs[ci] = GlyphPos{px, py, pg->getWidth()}; - if(pg->getWidth() > a.maxWidth) - a.maxWidth = pg->getWidth(); - gi++; - } - - a.tex.load(buffer.getPixelPtr(), texSize); - } - return atlases[si][ci]; -} - -static unsigned getCharWidth(uint8_t c, FontSize fontsize) -{ - if(fontsize == FontSize::Small && c == 236) - c = 109; - auto& atlas = getAtlas(fontsize, FontColor::Yellow); - if(!atlas.tex.isValid()) - return 8; - auto& g = atlas.glyphs[c]; - if(g.w > 0) - return g.w; - return atlas.maxWidth; // fallback -} - -void CFont::draw(const std::string& string, Position pos, FontSize fontsize, FontColor color, FontAlign align) -{ - if(string.empty()) - return; - auto& atlas = getAtlas(fontsize, color); - if(!atlas.tex.isValid()) - return; - - unsigned totalW = CFont::getTextWidth(string, fontsize); - if(align == FontAlign::Middle) - pos.x -= static_cast(totalW / 2); - else if(align == FontAlign::Right) - pos.x -= static_cast(totalW); - - float texW = static_cast(atlas.tex.getSize().x); - float texH = static_cast(atlas.tex.getSize().y); - - glBindTexture(GL_TEXTURE_2D, atlas.tex.getHandle()); - glColor4f(1, 1, 1, 1); - glBegin(GL_QUADS); - - int curX = pos.x; - for(char c : string) - { - unsigned char uc = static_cast(c); - auto& g = atlas.glyphs[uc]; - if(g.w == 0) - { - curX += atlas.maxWidth / 2; - continue; - } - int gh = static_cast(atlas.lineHeight); - float u0 = static_cast(g.x) / texW; - float v0 = static_cast(g.y) / texH; - float u1 = static_cast(g.x + g.w) / texW; - float v1 = static_cast(g.y + gh) / texH; - - glTexCoord2f(u0, v0); - glVertex2i(curX, pos.y); - glTexCoord2f(u1, v0); - glVertex2i(curX + g.w, pos.y); - glTexCoord2f(u1, v1); - glVertex2i(curX + g.w, pos.y + gh); - glTexCoord2f(u0, v1); - glVertex2i(curX, pos.y + gh); - curX += g.w; // advance by glyph width - } - glEnd(); -} - -unsigned CFont::getTextWidth(const std::string& string, FontSize fontsize) -{ - unsigned w = 0; - for(unsigned char c : string) - { - if(c == '\n') - break; - w += getCharWidth(c, fontsize); - } - return w; -} diff --git a/CIO/CFont.h b/CIO/CFont.h deleted file mode 100644 index 0dc2125..0000000 --- a/CIO/CFont.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "defines.h" -#include -#include -#include -#include - -class CFont -{ - friend class CDebug; - -private: - Position pos_; ///< Position of the text (top-left) - Extent size_; ///< Pixel extent of the rendered text - std::string string_; - FontSize fontsize_; - FontColor color_, initialColor_; - std::function callback; - int clickedParam; - -public: - CFont(std::string text, Position pos = {0, 0}, FontSize fontsize = FontSize::Small, - FontColor color = FontColor::Yellow); - // Access - Position getPos() const { return pos_; } - Extent getSize() const { return size_; } - void setPos(Position pos); - void setFontsize(FontSize fontsize); - void setColor(FontColor color); - FontColor getColor() const { return color_; } - void setText(std::string text); - void setCallback(std::function callback, int param) - { - this->callback = std::move(callback); - clickedParam = param; - } - void unsetCallback() - { - callback = nullptr; - clickedParam = 0; - } - void setMouseData(SDL_MouseButtonEvent button); - - /// Draw this font's text at the given absolute position - void draw(Position parentOrigin) const { draw(string_, parentOrigin + pos_, fontsize_, color_, FontAlign::Left); } - - /// Draw text directly - /// @param pos Absolute position (top-left of the text, adjusted for alignment). - static void draw(const std::string& string, Position pos, FontSize fontsize = FontSize::Small, - FontColor color = FontColor::Yellow, FontAlign align = FontAlign::Left); - - /// Compute the pixel width of a string without drawing it. - static unsigned getTextWidth(const std::string& string, FontSize fontsize); -}; diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp deleted file mode 100644 index d449bce..0000000 --- a/CIO/CMinimapWindow.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2026 - 2026 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CMinimapWindow.h" -#include "../CGame.h" -#include "../CMap.h" -#include "../Texture.h" -#include "../globals.h" -#include "CFont.h" -#include - -void CMinimapWindow::draw(Position /*parentOrigin*/) -{ - // Draw window chrome (frame, title, close button, background, child elements) - CWindow::draw(pos_); - - // Compute content area (inside the frames) - const auto& b = getBorderSizes(); - const Position contentPos = pos_ + Position(b.left, b.top); - const auto contentSize = getSize() - getBorderSize(); - if(static_cast(contentSize.x) <= 0 || static_cast(contentSize.y) <= 0) - return; - - auto* map = global::s2->getMapObj(); - if(!map) - return; - - // Fill pixel buffer with minimap terrain - int scale = 1; - map->drawMinimap(pixels_, static_cast(contentSize.x), static_cast(contentSize.y), scale); - - // Upload to texture and draw - if(!minimapTex_.isValid() || minimapTex_.getSize() != contentSize) - minimapTex_.createEmpty(contentSize); - minimapTex_.upload(pixels_.data()); - minimapTex_.draw(Rect(contentPos, contentSize)); - - // Draw player flags and numbers on top - for(int i = 0; i < MAXPLAYERS; i++) - { - const auto hqX = map->getPlayerHQx()[i]; - const auto hqY = map->getPlayerHQy()[i]; - if(hqX == 0xFFFF || hqY == 0xFFFF) - continue; - - const int flagIdx = FLAG_BLUE_DARK + i % 7; - const Position hqPos = Position(hqX, hqY) / scale; - Texture::getTexture(ArchiveID::EDITBOB, flagIdx).drawSprite(contentPos + hqPos); - - // Player number - CFont::draw(std::to_string(i + 1), contentPos + hqPos, FontSize::Small, FontColor::MintGreen); - } - - // Draw the position arrow - { - const int arrowIdx = MAPPIC_ARROWCROSS_ORANGE; - const auto& dispRect = map->getDisplayRect(); - const Position arrowCenter = dispRect.getOrigin() + dispRect.getSize() / 2u; - auto& tex = Texture::getTexture(ArchiveID::MAP00, arrowIdx); - const Position arrowPos = - contentPos + arrowCenter / Position(TR_W, TR_H) / scale - tex.anchor(); - tex.draw(arrowPos); - } -} diff --git a/CIO/CMinimapWindow.h b/CIO/CMinimapWindow.h deleted file mode 100644 index 715442b..0000000 --- a/CIO/CMinimapWindow.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2026 - 2026 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "../Texture.h" -#include "CWindow.h" -#include - -class CMinimapWindow final : public CWindow -{ - std::vector pixels_; ///< Pixel buffer for minimap terrain - Texture minimapTex_; - - void draw(Position parentOrigin) override; - -public: - using CWindow::CWindow; -}; diff --git a/CIO/CPicture.cpp b/CIO/CPicture.cpp deleted file mode 100644 index 5f0289d..0000000 --- a/CIO/CPicture.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CPicture.h" -#include "../Texture.h" -#include "../globals.h" -#include "CollisionDetection.h" -#include -#include - -CPicture::CPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, unsigned picture) - : pos_(pos), archive_(archive), picture_(picture) -{ - marked = false; - clicked = false; - size_ = global::getBitmapSize(archive, picture); - this->callback = callback; - this->clickedParam = clickedParam; - motionEntryParam = -1; - motionLeaveParam = -1; -} - -void CPicture::setMouseData(const SDL_MouseMotionEvent& motion) -{ - // cursor is on the picture - if(IsPointInRect(motion.x, motion.y, Rect(pos_, size_))) - { - if(motion.state == SDL_RELEASED) - { - marked = true; - if(motionEntryParam >= 0 && callback) - callback(motionEntryParam); - } - } else - { - // picture was marked before and mouse cursor is on the picture now, so do the callback - if(motionLeaveParam >= 0 && callback && marked) - callback(motionLeaveParam); - marked = false; - } -} - -void CPicture::setMouseData(const SDL_MouseButtonEvent& button) -{ - // left button is pressed - if(button.button == SDL_BUTTON_LEFT) - { - // if mouse button is pressed ON the button, set marked=true - if(button.state == SDL_PRESSED && IsPointInRect(button.x, button.y, Rect(pos_, size_))) - { - marked = true; - clicked = true; - } else if(button.state == SDL_RELEASED) - { - clicked = false; - // if mouse button is released ON the PICTURE (marked = true), then do the callback - if(marked && callback) - callback(clickedParam); - } - } -} - -void CPicture::draw(Position parentOrigin) const -{ - getTexture(archive_, picture_).draw(parentOrigin + pos_); -} diff --git a/CIO/CPicture.h b/CIO/CPicture.h deleted file mode 100644 index 6ab665d..0000000 --- a/CIO/CPicture.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "ArchiveID.h" -#include "Point.h" -#include "defines.h" - -class CPicture -{ - friend class CDebug; - -private: - Position pos_; - Extent size_; - ArchiveID archive_; - unsigned picture_; - bool marked; - bool clicked; - void (*callback)(int); - int clickedParam; - int motionEntryParam; - int motionLeaveParam; - -public: - CPicture(void callback(int), int clickedParam, Position pos, ArchiveID archive, unsigned picture); - // Access - int getX() const { return pos_.x; }; - int getY() const { return pos_.y; }; - Position getPos() const { return pos_; } - Extent getSize() const { return size_; }; - void setX(int x) { pos_.x = x; }; - void setY(int y) { pos_.y = y; }; - void setMouseData(const SDL_MouseMotionEvent& motion); - void setMouseData(const SDL_MouseButtonEvent& button); - void draw(Position parentOrigin) const; - void setMotionParams(int entry, int leave) - { - motionEntryParam = entry; - motionLeaveParam = leave; - }; -}; diff --git a/CIO/CSelectBox.cpp b/CIO/CSelectBox.cpp deleted file mode 100644 index 399f99d..0000000 --- a/CIO/CSelectBox.cpp +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CSelectBox.h" -#include "../CGame.h" -#include "../Texture.h" -#include "../globals.h" -#include "CButton.h" -#include "CFont.h" -#include - -CSelectBox::CSelectBox(Position pos, Extent size, FontSize fontsize, FontColor text_color, int bg_color) - : pos_(pos), size_(size), fontsize(fontsize), text_color(text_color) -{ - setColor(bg_color); - - // button position is relative to the selectbox - ScrollUpButton = std::make_unique(nullptr, 0, Position(static_cast(size_.x) - 1 - 20, 0), - Extent(20, 20), BUTTON_GREY, nullptr, PICTURE_SMALL_ARROW_UP); - ScrollDownButton = std::make_unique( - nullptr, 0, Position(static_cast(size_.x) - 1 - 20, static_cast(size_.y) - 1 - 20), Extent(20, 20), - BUTTON_GREY, nullptr, PICTURE_SMALL_ARROW_DOWN); -} - -void CSelectBox::addOption(const std::string& string, std::function callback, int param) -{ - // explanation: row_height = row_separator + fontsize - const unsigned row_height = getLineHeight(fontsize); - - auto Entry = std::make_unique(string, Position(10, last_text_pos_y), fontsize, FontColor::Yellow); - Entry->setCallback(std::move(callback), param); - Entries.emplace_back(std::move(Entry)); - last_text_pos_y += row_height; -} - -void CSelectBox::setColor(int color) -{ - switch(color) - { - case BUTTON_GREY: - pic_foreground = BUTTON_GREY_DARK; - pic_background = BUTTON_GREY_BACKGROUND; - break; - - case BUTTON_RED1: - pic_foreground = BUTTON_RED1_DARK; - pic_background = BUTTON_RED1_BACKGROUND; - break; - - case BUTTON_GREEN1: - pic_foreground = BUTTON_GREEN1_DARK; - pic_background = BUTTON_GREEN1_BACKGROUND; - break; - - case BUTTON_GREEN2: - pic_foreground = BUTTON_GREEN2_DARK; - pic_background = BUTTON_GREEN2_BACKGROUND; - break; - - case BUTTON_RED2: - pic_foreground = BUTTON_RED2_DARK; - pic_background = BUTTON_RED2_BACKGROUND; - break; - - case BUTTON_STONE: - pic_foreground = BUTTON_STONE_DARK; - pic_background = BUTTON_STONE_BACKGROUND; - break; - - default: - pic_foreground = -1; - pic_background = -1; - break; - } -} - -void CSelectBox::setMouseData(SDL_MouseMotionEvent motion) -{ - // IMPORTANT: we use the left upper corner of the selectbox as (x,y)=(0,0), so we have to manipulate - // the motion-structure before give it to the buttons: x_absolute - x_selectbox, y_absolute - y_selectbox - motion.x -= pos_.x; - motion.y -= pos_.y; - ScrollUpButton->setMouseData(motion); - ScrollDownButton->setMouseData(motion); -} - -void CSelectBox::setMouseData(SDL_MouseButtonEvent button) -{ - bool manipulated = false; - static bool scroll_up_button_marked = false; - static bool scroll_down_button_marked = false; - - // left button is pressed - if(button.button == SDL_BUTTON_LEFT) - { - // if mouse button is pressed ON the selectbox - if(button.state == SDL_PRESSED) - { - if((button.x >= pos_.x) && (button.x < pos_.x + static_cast(size_.x)) && (button.y >= pos_.y) - && (button.y < pos_.y + static_cast(size_.y))) - { - // scroll up button - if((button.x > pos_.x + static_cast(size_.x) - 20) && (button.y < pos_.y + 20)) - { - scroll_up_button_marked = true; - } - // scroll down button - else if((button.x > pos_.x + static_cast(size_.x) - 20) - && (button.y > pos_.y + static_cast(size_.y) - 20)) - { - scroll_down_button_marked = true; - } - - // IMPORTANT: we use the left upper corner of the selectbox as (x,y)=(0,0), so we have to manipulate - // the motion-structure before give it to buttons and entries: x_absolute - x_selectbox, - // y_absolute - y_selectbox - button.x -= pos_.x; - button.y -= pos_.y; - manipulated = true; - - for(auto& entry : Entries) - { - entry->setMouseData(button); - } - } - } else if(button.state == SDL_RELEASED) - { - if((button.x >= pos_.x) && (button.x < pos_.x + static_cast(size_.x)) && (button.y >= pos_.y) - && (button.y < pos_.y + static_cast(size_.y))) - { - // scroll up button - if(scroll_up_button_marked) - { - if((button.x > pos_.x + static_cast(size_.x) - 20) && (button.y < pos_.y + 20)) - { - // test if first entry is on the most upper position - if(!Entries.empty() && Entries.front()->getPos().y < 10) - { - for(auto& entry : Entries) - { - entry->setPos(Position(entry->getPos().x, entry->getPos().y + 10)); - } - } - } - } - // scroll down button - else if(scroll_down_button_marked) - { - if((button.x > pos_.x + static_cast(size_.x) - 20) - && (button.y > pos_.y + static_cast(size_.y) - 20)) - { - // test if last entry is on the most lower position - if(!Entries.empty() && Entries.back()->getPos().y > static_cast(size_.y) - 10) - { - for(auto& entry : Entries) - { - entry->setPos(Position(entry->getPos().x, entry->getPos().y - 10)); - } - } - } - } - - // IMPORTANT: we use the left upper corner of the selectbox as (x,y)=(0,0), so we have to manipulate - // the motion-structure before give it to buttons and entries: x_absolute - x_selectbox, - // y_absolute - y_selectbox - button.x -= pos_.x; - button.y -= pos_.y; - manipulated = true; - - for(auto& entry : Entries) - { - entry->setMouseData(button); - } - } - scroll_up_button_marked = false; - scroll_down_button_marked = false; - } - // IMPORTANT: we use the left upper corner of the selectbox as (x,y)=(0,0), so we have to manipulate - // the motion-structure before give it to buttons and entries: x_absolute - x_selectbox, y_absolute - - // y_selectbox - if(!manipulated) - { - button.x -= pos_.x; - button.y -= pos_.y; - } - ScrollUpButton->setMouseData(button); - ScrollDownButton->setMouseData(button); - } -} - -void CSelectBox::setSize(Extent size) -{ - if(size_ != size) - { - size_ = size; - // update scroll down button position - ScrollDownButton->setY(size_.y - 1 - 20); - } -} - -void CSelectBox::setPos(Position pos) -{ - pos_ = pos; -} - -void CSelectBox::draw(Position parentOrigin) -{ - const Position absPos = parentOrigin + pos_; - const Rect area(absPos, size_); - - // Draw background - if(pic_background >= 0 && pic_foreground >= 0) - { - getTexture(ArchiveID::EDITIO, pic_foreground).drawTiled(area); - } else - { - // Fill with black - drawRect(area, 0xFF000000); - } - - // Clip entries to the select box area - const auto viewH = global::s2->getRes().y; - glEnable(GL_SCISSOR_TEST); - glScissor(area.left, viewH - (area.top + static_cast(size_.y)), static_cast(size_.x), - static_cast(size_.y)); - - // Draw entries - for(const auto& entry : Entries) - { - entry->draw(absPos); - } - - glDisable(GL_SCISSOR_TEST); - - // Draw scroll buttons (on top, within the select box) - ScrollUpButton->draw(absPos); - ScrollDownButton->draw(absPos); -} diff --git a/CIO/CSelectBox.h b/CIO/CSelectBox.h deleted file mode 100644 index 7b149d5..0000000 --- a/CIO/CSelectBox.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "defines.h" -#include -#include -#include - -class CFont; -class CButton; - -class CSelectBox -{ - friend class CDebug; - -private: - std::vector> Entries; - Position pos_; - Extent size_; - FontSize fontsize; - int pic_background; - int pic_foreground; - FontColor text_color; - std::unique_ptr ScrollUpButton; - std::unique_ptr ScrollDownButton; - Uint16 last_text_pos_y = 10; - -public: - CSelectBox(Position pos, Extent size, FontSize fontsize = FontSize::Large, FontColor text_color = FontColor::Yellow, - int bg_color = -1); - Position getPos() const { return pos_; } - Extent getSize() const { return size_; } - void setMouseData(SDL_MouseButtonEvent button); - void setMouseData(SDL_MouseMotionEvent motion); - void draw(Position parentOrigin); - void setColor(int color); - void setTextColor(FontColor color) { text_color = color; } - void addOption(const std::string& string, std::function callback = nullptr, int param = 0); - void setSize(Extent size); - void setPos(Position pos); -}; diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp deleted file mode 100644 index 23dd456..0000000 --- a/CIO/CTextfield.cpp +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CTextfield.h" -#include "../Texture.h" -#include "../globals.h" -#include "CFont.h" -#include "CollisionDetection.h" -#include -#include - -CTextfield::CTextfield(Position pos, Uint16 cols, Uint16 rows, FontSize fontsize, FontColor text_color, int bg_color, - bool button_style) -{ - active = false; - this->cols = (cols < 1 ? 1 : cols); - this->rows = (rows < 1 ? 1 : rows); - // calc width by maximum number of chiffres (cols) + one blinking chiffre * average pixel_width of a chiffre - // (fontsize-3) + tolerance for borders - this->size_.x = (this->cols + 1) * (static_cast(fontsize) - 3) + 4; - // calc height ----------------| this is the row_separator from CFont.cpp |---- + tolerance for borders - this->size_.y = this->rows * getLineHeight(fontsize) + 4; - setColor(bg_color); - // allocate memory for the text: chiffres (cols) + '\n' for each line * rows + blinking chiffre + '\0' - text_.resize((this->cols + 1) * this->rows + 2); - - this->button_style = button_style; - textObj = std::make_unique("", pos, fontsize, text_color); -} - -Position CTextfield::getPos() const -{ - return textObj->getPos(); -} - -void CTextfield::setPos(Position pos) -{ - textObj->setPos(pos); -} - -void CTextfield::setColor(int color) -{ - switch(color) - { - case BUTTON_GREY: - pic_foreground = BUTTON_GREY_DARK; - pic_background = BUTTON_GREY_BACKGROUND; - break; - - case BUTTON_RED1: - pic_foreground = BUTTON_RED1_DARK; - pic_background = BUTTON_RED1_BACKGROUND; - break; - - case BUTTON_GREEN1: - pic_foreground = BUTTON_GREEN1_DARK; - pic_background = BUTTON_GREEN1_BACKGROUND; - break; - - case BUTTON_GREEN2: - pic_foreground = BUTTON_GREEN2_DARK; - pic_background = BUTTON_GREEN2_BACKGROUND; - break; - - case BUTTON_RED2: - pic_foreground = BUTTON_RED2_DARK; - pic_background = BUTTON_RED2_BACKGROUND; - break; - - case BUTTON_STONE: - pic_foreground = BUTTON_STONE_DARK; - pic_background = BUTTON_STONE_BACKGROUND; - break; - - default: - pic_foreground = -1; - pic_background = -1; - break; - } -} - -void CTextfield::setTextColor(FontColor color) -{ - textObj->setColor(color); -} - -void CTextfield::setText(const std::string& text) -{ - char* txtPtr = this->text_.data(); - int col_ctr = 1, row_ctr = 1; - - for(char c : text) - { - if(txtPtr >= &this->text_.back() - 2) - break; - - if(col_ctr > cols) - { - if(row_ctr < rows) - { - *txtPtr = '\n'; - txtPtr++; - row_ctr++; - } else - break; - col_ctr = 1; - } - - *txtPtr++ = c; - col_ctr++; - } - *txtPtr = '\0'; -} - -void CTextfield::setMouseData(SDL_MouseButtonEvent button) -{ - // left button is pressed - if(button.button == SDL_BUTTON_LEFT) - { - // if mouse button is pressed ON the textfield, set active=true - if(button.state == SDL_PRESSED) - { - active = IsPointInRect(button.x, button.y, Rect(getPos(), size_)); - } - } -} - -void CTextfield::setKeyboardData(const SDL_KeyboardEvent& key) -{ - unsigned char chiffre = '\0'; - char* txtPtr = text_.data(); - int col_ctr = 1, row_ctr = 1; - - if(!active) - return; - - if(key.type == SDL_KEYDOWN) - { - // go to '\0' - while(*txtPtr != '\0') - { - col_ctr++; - if(*txtPtr == '\n') - { - row_ctr++; - col_ctr = 1; - } - txtPtr++; - } - // decrement col_ctr cause '\0' is not counted - col_ctr--; - // end of text memory reached? ( 'cols'-chiffres from the user + '\n' in each row * rows + blinking chiffre + - // '\0' -1 for pointer adress range - if(txtPtr >= &text_.back() - 2) - { - // end reached, user may only delete chiffres - if(key.keysym.sym != SDLK_BACKSPACE) - return; - } - - switch(key.keysym.sym) - { - case SDLK_BACKSPACE: - if(txtPtr > text_.data()) - { - txtPtr--; - *txtPtr = '\0'; - } - break; - - case SDLK_RETURN: - if(row_ctr < rows) - { - *txtPtr = '\n'; - txtPtr++; - *txtPtr = '\0'; - } - break; - - default: - if(col_ctr >= cols) - { - if(row_ctr < rows) - { - *txtPtr = '\n'; - txtPtr++; - } else - break; - } - // decide which chiffre to save - if((key.keysym.sym >= 48 && key.keysym.sym <= 57) || key.keysym.sym == 32 || key.keysym.sym == 46 - || key.keysym.sym == 47) - chiffre = (unsigned char)key.keysym.sym; - else if(key.keysym.sym >= 97 && key.keysym.sym <= 122) - { - chiffre = (unsigned char)key.keysym.sym; - // test for capital letters (small letter and shift pressed) - if(key.keysym.mod & KMOD_SHIFT) - chiffre -= 32; - } else if(key.keysym.sym == 45) - { - chiffre = (unsigned char)key.keysym.sym; - // test for '_' ('-' and shift pressed) - if(key.keysym.mod & KMOD_SHIFT) - chiffre = 95; - } - - if(chiffre != '\0') - { - *txtPtr = chiffre; - txtPtr++; - *txtPtr = '\0'; - } - break; - } - } -} - -void CTextfield::draw(Position parentOrigin) -{ - const Position absPos = parentOrigin + getPos(); - const Rect area(absPos, size_); - - // Update cursor blink state - static Uint32 lastTime = 0; // Shared timer is OK here - if(active) - { - const Uint32 currentTime = SDL_GetTicks(); - if(lastTime == 0) - lastTime = currentTime; - if(currentTime - lastTime > 500) - { - lastTime = currentTime; - blinking_chiffre = !blinking_chiffre; - } - } else - { - blinking_chiffre = false; - } - - // Draw the background / foreground - if(pic_background >= 0 && pic_foreground >= 0) - { - if(button_style) - drawButtonBox(area, active, pic_background, pic_foreground); - else - getTexture(ArchiveID::EDITIO, pic_foreground).drawTiled(area); - } else - { - // Fill with black - drawRect(area, 0xFF000000); - } - - // Prepare text with cursor - std::string displayText = getText(); - - // Add blinking cursor if active - if(blinking_chiffre && active) - { - displayText += '>'; - } - - // Draw the text - if(!displayText.empty()) - { - textObj->setText(displayText); - textObj->draw(Position(parentOrigin.x + 2, parentOrigin.y + 4)); - } -} diff --git a/CIO/CTextfield.h b/CIO/CTextfield.h deleted file mode 100644 index 1b10415..0000000 --- a/CIO/CTextfield.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "defines.h" -#include -#include -#include - -class CFont; - -class CTextfield -{ - friend class CDebug; - -private: - std::unique_ptr textObj; - Extent size_; - Uint16 cols; - Uint16 rows; - int pic_background; - int pic_foreground; - std::vector text_; - // if active, keyboard data will be delivered and the cursor is blinking - bool active; - // if true, the textfield looks like a button - bool button_style; - // Cursor blink state - bool blinking_chiffre = false; - -public: - // Constructor - Destructor - CTextfield(Position pos = {0, 0}, Uint16 cols = 10, Uint16 rows = 1, FontSize fontsize = FontSize::Large, - FontColor text_color = FontColor::Yellow, int bg_color = -1, bool button_style = false); - // Access - Position getPos() const; - void setPos(Position pos); - Extent getSize() const { return size_; }; - int getCols() const { return cols; } - int getRows() const { return rows; } - void setText(const std::string& text); - void setActive() { active = true; } - void setInactive() { active = false; } - bool isActive() const { return active; } - void setMouseData(SDL_MouseButtonEvent button); - void setKeyboardData(const SDL_KeyboardEvent& key); - void draw(Position parentOrigin); - void setColor(int color); - void setTextColor(FontColor color); - std::string getText() const { return text_.data(); } -}; diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp deleted file mode 100644 index cb1c80e..0000000 --- a/CIO/CWindow.cpp +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CWindow.h" -#include "../CGame.h" -#include "../Texture.h" -#include "../globals.h" -#include "CButton.h" -#include "CFont.h" -#include "CPicture.h" -#include "CSelectBox.h" -#include "CTextfield.h" -#include "CollisionDetection.h" -#include "helpers/containerUtils.h" -#include -#include -#include - -CWindow::CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title, int color, - Uint8 flags, ArchiveID bgArchive) - : CControlContainer( - color, - BorderSizes(ArchiveID::EDITRES, WINDOW_LEFT_FRAME, WINDOW_UPPER_FRAME, WINDOW_RIGHT_FRAME, WINDOW_LOWER_FRAME), - bgArchive), - pos_(pos), size_(size), title(title), callback_(callback), callbackQuitMessage(callbackQuitMessage) -{ - assert(callback); - canMove = (flags & WINDOW_MOVE) != 0; - canClose = (flags & WINDOW_CLOSE) != 0; - canMinimize = (flags & WINDOW_MINIMIZE) != 0; - canResize = (flags & WINDOW_RESIZE) != 0; -} - -static Position makePos(WindowPos pos, Extent size) -{ - if(pos == WindowPos::Center) - return (global::s2->getRes() - size) / 2; - else - return {}; -} - -CWindow::CWindow(void callback(int), int callbackQuitMessage, WindowPos pos, Extent size, - const char* title /*= nullptr*/, int color /*= WINDOW_GREEN1*/, Uint8 flags /*= 0*/, - ArchiveID bgArchive /*= ArchiveID::EDITRES*/) - : CWindow(callback, callbackQuitMessage, makePos(pos, size), size, title, color, flags, bgArchive) -{} - -void CWindow::setTitle(const char* title) -{ - this->title = title; -} - -bool CWindow::hasActiveInputElement() -{ - return helpers::contains_if(getTextFields(), [](const auto& text) { return text->isActive(); }); -} - -void CWindow::setMouseData(SDL_MouseMotionEvent motion) -{ - // cursor is on the title frame (+/-2 and +/-4 are only for a good optic) - const Position titleFrameLT = - pos_ + Position(static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_LEFT_UPPER_CORNER).x), 0) - + Position(2, 4); - const Position titleFrameRB = - pos_ - + Position(static_cast(size_.x), - static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).y)) - - Position(static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_RIGHT_UPPER_CORNER).x) + 2, 4); - if(IsPointInRect(motion.x, motion.y, Rect(titleFrameLT, Extent(titleFrameRB - titleFrameLT)))) - { - // left button was pressed while moving - if(clicked) - moving = true; - } else if(!moving) - clicked = false; - - if(!(SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(SDL_BUTTON_LEFT))) - moving = false; - if(moving && canMove) - { - pos_ += Position(motion.xrel, motion.yrel); - // Clamp window position so it stays on screen - const auto res = global::s2->getRes(); - const auto maxPos = res - elMin(size_, res); - pos_ = elMin(elMax(pos_, Position(0, 0)), Position(maxPos)); - } - - // check whats happen to the close button - if(canClose) - { - // cursor is on the button (+/-2 is only for the optic) - const auto closeSize = global::getBitmapSize(ArchiveID::EDITRES, WINDOW_BUTTON_CLOSE); - canClose_marked = - IsPointInRect(Position(motion.x, motion.y), Rect(pos_ + Position(2, 2), closeSize - Extent(4, 4))); - } - // check whats happen to the minimize button - if(canMinimize) - { - // cursor is on the button (+/-2 is only for the optic) - const auto minSize = global::getBitmapSize(ArchiveID::EDITRES, WINDOW_BUTTON_MINIMIZE); - canMinimize_marked = - IsPointInRect(Position(motion.x, motion.y), - Rect(pos_ + Position(static_cast(size_.x) - static_cast(minSize.x) + 2, 2), - minSize - Extent(4, 4))); - } - // check whats happen to the resize button - if(canResize) - { - // cursor is on the button (+/-2 is only for the optic) - const auto resizeSize = global::getBitmapSize(ArchiveID::EDITRES, WINDOW_BUTTON_RESIZE); - if(IsPointInRect(Position(motion.x, motion.y), - Rect(pos_ - + Position(static_cast(size_.x) - static_cast(resizeSize.x) + 2, - static_cast(size_.y) - static_cast(resizeSize.y) + 2), - resizeSize - Extent(4, 4)))) - { - // left button was pressed while moving - if(SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(SDL_BUTTON_LEFT)) - resizing = true; - canResize_marked = true; - } else if(!resizing) - canResize_marked = false; - - if(!(SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(SDL_BUTTON_LEFT))) - resizing = false; - if(resizing) - { - // only resize if not minimized - if(!minimized) - { - size_ = Extent(static_cast(size_.x) + motion.xrel, static_cast(size_.y) + motion.yrel); - const auto res = global::s2->getRes(); - const auto maxSize = Extent(elMax(Position(res) - pos_, Position(1, 1))); - size_ = elMin(elMax(size_, Extent::all(1u)), maxSize); - callback_(WINDOW_RESIZED_CALL); - } - } - } - - // deliver mouse data to the content objects of the window (if mouse cursor is inside the window) - if(IsPointInRect(motion.x, motion.y, Rect(getPos(), getSize()))) - { - // IMPORTANT: we use the left upper corner of the window as (x,y)=(0,0), so we have to manipulate - // the motion-structure before give it to buttons, pictures....: x_absolute - x_window, y_absolute - - // y_window - motion.x -= pos_.x; - motion.y -= pos_.y; - CControlContainer::setMouseData(motion); - } -} - -void CWindow::setMouseData(SDL_MouseButtonEvent button) -{ - // at first check if the right mouse button was pressed, cause in this case we will close the window - if(button.button == SDL_BUTTON_RIGHT && button.state == SDL_PRESSED) - { - callback_(callbackQuitMessage); - return; - } - - // save width and height in case we minimize the window (the initializing values are for preventing any mistakes and - // compilerwarning --- in fact: uninitialized values are only a problem if the window is created minimized, but this - // will not happen) - static int maximized_h = global::getBitmapSize(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).y - + global::getBitmapSize(ArchiveID::EDITRES, WINDOW_CORNER_RECTANGLE).y; - if(!minimized) - maximized_h = static_cast(size_.y); - - // left button is pressed - if(button.button == SDL_BUTTON_LEFT) - { - // cursor is on the title frame (+/-2 and +/-4 are only for a good optic) - if((button.x - >= pos_.x + static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_LEFT_UPPER_CORNER).x) + 2) - && (button.x < pos_.x + static_cast(size_.x) - - static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_RIGHT_UPPER_CORNER).x) - - 2) - && (button.y >= pos_.y + 4) - && (button.y - < pos_.y + static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).y) - 4)) - { - marked = true; - clicked = true; - } - // pressed inside the window - if(button.state == SDL_PRESSED && IsPointInRect(button.x, button.y, Rect(pos_, size_))) - marked = true; - // else pressed outside of the window - else if(button.state == SDL_PRESSED) - marked = false; - - // check whats happen to the close button - // only set 'clicked' if pressed AND cursor is ON the button (marked == true) - if(button.state == SDL_PRESSED && canClose_marked) - canClose_clicked = true; - else if(button.state == SDL_RELEASED) - { - canClose_clicked = false; - // if mouse button is released ON the close button (marked = true), then send the quit message to the - // callback - if(canClose_marked) - { - callback_(callbackQuitMessage); - return; - } - } - // check whats happen to the minimize button - // only set 'clicked' if pressed AND cursor is ON the button (marked == true) - if(button.state == SDL_PRESSED && canMinimize_marked) - canMinimize_clicked = true; - else if(button.state == SDL_RELEASED) - { - canMinimize_clicked = false; - // if mouse button is released ON the BUTTON (marked = true), then minimize or maximize the window - if(canMinimize_marked) - { - if(minimized) // maximize now - { - size_.y = static_cast(maximized_h); - minimized = false; - } else // minimize now - { - size_.y = global::getBitmapSize(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).y - + global::getBitmapSize(ArchiveID::EDITRES, WINDOW_CORNER_RECTANGLE).y; - minimized = true; - } - } - } - // check whats happen to the resize button - // only set 'clicked' if pressed AND cursor is ON the button (marked == true) - if(button.state == SDL_PRESSED && canResize_marked) - canResize_clicked = true; - else if(button.state == SDL_RELEASED) - canResize_clicked = false; - } - - // deliver mouse data to the content objects of the window (if mouse cursor is inside the window) - if(IsPointInRect(button.x, button.y, Rect(getPos(), getSize()))) - { - // IMPORTANT: we use the left upper corner of the window as (x,y)=(0,0), so we have to manipulate - // the motion-structure before give it to buttons, pictures....: x_absolute - x_window, y_absolute - - // y_window - button.x -= pos_.x; - button.y -= pos_.y; - CControlContainer::setMouseData(button); - } - - // at least call the callback - callback_(WINDOW_CLICKED_CALL); -} - -void CWindow::draw(Position /*parentOrigin*/) -{ - // 1. Background fill (tiled) - if(getBackground() != WINDOW_NOTHING) - getTexture(backgroundArchive_, getBackground()).drawTiled(getRect()); - - // 2. Content (if not minimized) — clipped to the area inside frames - if(!minimized) - { - const auto viewH = global::s2->getRes().y; - const auto& b = getBorderSizes(); - const auto contentOrigin = pos_ + Position(b.left, b.top); - const auto contentSize = getSize() - getBorderSize(); - if(static_cast(contentSize.x) > 0 && static_cast(contentSize.y) > 0) - { - glEnable(GL_SCISSOR_TEST); - glScissor(contentOrigin.x, viewH - (contentOrigin.y + static_cast(contentSize.y)), - static_cast(contentSize.x), static_cast(contentSize.y)); - drawChildren(pos_); - glDisable(GL_SCISSOR_TEST); - } - } - - // 3. Upper frame - int upperframe; - if(clicked) - upperframe = WINDOW_UPPER_FRAME_CLICKED; - else if(marked) - upperframe = WINDOW_UPPER_FRAME_MARKED; - else - upperframe = WINDOW_UPPER_FRAME; - - // Draw upper frame tile across the top of the window - { - const Rect upperFrameRect(pos_, Extent(size_.x, getTexture(ArchiveID::EDITRES, upperframe).getSize().y)); - getTexture(ArchiveID::EDITRES, upperframe).drawTiled(upperFrameRect); - } - - // 4. Title text - if(title) - { - const int titleY = pos_.y + (getTexture(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).getSize().y - 9) / 2; - CFont::draw(title, Position(pos_.x + static_cast(size_.x) / 2, titleY), FontSize::Small, FontColor::Yellow, - FontAlign::Middle); - } - - // 5. Lower frame (tiled across bottom) - { - const int lowerH = getTexture(ArchiveID::EDITRES, WINDOW_LOWER_FRAME).getSize().y; - const Rect lowerFrameRect(Position(pos_.x, pos_.y + static_cast(size_.y) - lowerH), - Extent(size_.x, lowerH)); - getTexture(ArchiveID::EDITRES, WINDOW_LOWER_FRAME).drawTiled(lowerFrameRect); - } - - // 6. Left frame (tiled down left side) - { - const Rect leftFrameRect(pos_, Extent(getTexture(ArchiveID::EDITRES, WINDOW_LEFT_FRAME).getSize().x, size_.y)); - getTexture(ArchiveID::EDITRES, WINDOW_LEFT_FRAME).drawTiled(leftFrameRect); - } - - // 7. Right frame (tiled down right side) - { - const int rightW = getTexture(ArchiveID::EDITRES, WINDOW_RIGHT_FRAME).getSize().x; - const Rect rightFrameRect(Position(pos_.x + static_cast(size_.x) - rightW, pos_.y), - Extent(rightW, size_.y)); - getTexture(ArchiveID::EDITRES, WINDOW_RIGHT_FRAME).drawTiled(rightFrameRect); - } - - // 8. Corners - { - getTexture(ArchiveID::EDITRES, WINDOW_LEFT_UPPER_CORNER).draw(pos_); - - const Extent ru = getTexture(ArchiveID::EDITRES, WINDOW_RIGHT_UPPER_CORNER).getSize(); - getTexture(ArchiveID::EDITRES, WINDOW_RIGHT_UPPER_CORNER) - .draw(pos_ + Position(static_cast(size_.x) - ru.x, 0)); - - const Extent cr = getTexture(ArchiveID::EDITRES, WINDOW_CORNER_RECTANGLE).getSize(); - getTexture(ArchiveID::EDITRES, WINDOW_CORNER_RECTANGLE) - .draw(pos_ + Position(0, static_cast(size_.y) - cr.y)); - getTexture(ArchiveID::EDITRES, WINDOW_CORNER_RECTANGLE).draw(pos_ + size_ - cr); - } - - // 9. Close button - if(canClose) - { - int closebutton; - if(canClose_clicked) - closebutton = WINDOW_BUTTON_CLOSE_CLICKED; - else if(canClose_marked) - closebutton = WINDOW_BUTTON_CLOSE_MARKED; - else - closebutton = WINDOW_BUTTON_CLOSE; - getTexture(ArchiveID::EDITRES, closebutton).draw(pos_); - } - - // 10. Minimize button - if(canMinimize) - { - int minimizebutton; - if(canMinimize_clicked) - minimizebutton = WINDOW_BUTTON_MINIMIZE_CLICKED; - else if(canMinimize_marked) - minimizebutton = WINDOW_BUTTON_MINIMIZE_MARKED; - else - minimizebutton = WINDOW_BUTTON_MINIMIZE; - const Extent minBtnSize = getTexture(ArchiveID::EDITRES, minimizebutton).getSize(); - getTexture(ArchiveID::EDITRES, minimizebutton) - .draw(pos_ + Position(static_cast(size_.x) - minBtnSize.x, 0)); - } - - // 11. Resize button - if(canResize) - { - int resizebutton; - if(canResize_clicked) - resizebutton = WINDOW_BUTTON_RESIZE_CLICKED; - else if(canResize_marked) - resizebutton = WINDOW_BUTTON_RESIZE_MARKED; - else - resizebutton = WINDOW_BUTTON_RESIZE; - const Extent resBtnSize = getTexture(ArchiveID::EDITRES, resizebutton).getSize(); - getTexture(ArchiveID::EDITRES, resizebutton).draw(pos_ + size_ - resBtnSize); - } -} - -void CWindow::setInactive() -{ - active = false; - clicked = false; - marked = false; - - for(auto& textfield : getTextFields()) - { - textfield->setInactive(); - } -} diff --git a/CIO/CWindow.h b/CIO/CWindow.h deleted file mode 100644 index 670d70a..0000000 --- a/CIO/CWindow.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "ArchiveID.h" -#include "CControlContainer.h" - -enum class WindowPos -{ - Center -}; - -class CWindow : public CControlContainer -{ - friend class CDebug; - - // if active is false, the window will be render behind the active windows within the game loop - bool active = true; - -protected: - Position pos_; - Extent size_; - -private: - const char* title; - bool marked = true; - bool clicked = false; - bool canMove; - bool canClose; - bool canClose_marked = false; - bool canClose_clicked = false; - bool canMinimize; - bool canMinimize_marked = false; - bool canMinimize_clicked = false; - bool canResize; - bool canResize_marked = false; - bool canResize_clicked = false; - bool minimized = false; - bool moving = false; - bool resizing = false; - int priority = 0; // for register, blit, event - void (*callback_)(int); - int callbackQuitMessage; - -public: - /// Draw the window (frame and children). - void draw(Position parentOrigin) override; - - CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title = nullptr, - int color = WINDOW_GREEN1, Uint8 flags = 0, ArchiveID bgArchive = ArchiveID::EDITRES); - CWindow(void callback(int), int callbackQuitMessage, WindowPos pos, Extent size, const char* title = nullptr, - int color = WINDOW_GREEN1, Uint8 flags = 0, ArchiveID bgArchive = ArchiveID::EDITRES); - // Access - Position getPos() const { return pos_; } - Extent getSize() const { return size_; } - Rect getRect() const { return Rect(pos_, size_); } - int getPriority() const { return priority; } - void setPriority(int priority) { this->priority = priority; } - void setTitle(const char* title); - void setMouseData(SDL_MouseMotionEvent motion) final; - void setMouseData(SDL_MouseButtonEvent button) final; - void setActive() - { - active = true; - marked = true; - } - void setInactive(); - bool isActive() const { return active; } - bool isMoving() const { return moving; } - bool isResizing() const { return resizing; } - bool isMarked() const { return marked; } - void setDirty() {} - // we can not trust this information, cause if minimized is false, it is possible, that we still have the old - // minimized surface bool isMinimized() { return minimized; }; we need an information if a input-element (textfield - // etc.) is active to not deliver the input to other gui-element in the event system - bool hasActiveInputElement(); -}; diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c6cd48..f95a8e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,8 +19,6 @@ endif() file(GLOB MAIN_SOURCES *.cpp *.h include/*.h) file(GLOB CIO_SOURCES CIO/*.cpp CIO/*.h) -SOURCE_GROUP(Main FILES ${MAIN_SOURCES}) -SOURCE_GROUP(CIO FILES ${CIO_SOURCES}) if(WIN32) if(CMAKE_HOST_WIN32) @@ -39,6 +37,7 @@ ELSE() ENDIF() add_executable(s25edit ${MAIN_SOURCES} ${CIO_SOURCES} ${icon_RC}) +source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${MAIN_SOURCES} ${CIO_SOURCES}) target_link_libraries(s25edit PRIVATE rttrConfig s25Common gamedata siedler2 s25Main endian::static glad Boost::nowide SDL2::SDL2 PUBLIC Boost::disable_autolinking Boost::program_options) target_include_directories(s25edit PRIVATE include) target_compile_features(s25edit PRIVATE cxx_std_17) diff --git a/CMap.cpp b/CMap.cpp index 9efdd98..fb1b8bc 100644 --- a/CMap.cpp +++ b/CMap.cpp @@ -6,10 +6,8 @@ #include "CMap.h" #include "CGame.h" #include "CIO/CFile.h" -#include "CIO/CFont.h" #include "CSurface.h" #include "Texture.h" -#include "callbacks.h" #include "globals.h" #include "gameData/LandscapeDesc.h" #include "gameData/TerrainDesc.h" @@ -521,31 +519,31 @@ void CMap::onLeftMouseDown(const Point32& pos) { // the texture-mode picture was clicked mode = EDITOR_MODE_TEXTURE; - callback::EditorTextureMenu(INITIALIZING_CALL); + // callback::EditorTextureMenu() — removed, old menu system deleted } else if(pos.x >= (displaySize.x / 2 - 162) && pos.x <= (displaySize.x / 2 - 125) && pos.y >= (displaySize.y - 35) && pos.y <= (displaySize.y - 3)) { // the tree-mode picture was clicked mode = EDITOR_MODE_TREE; - callback::EditorTreeMenu(INITIALIZING_CALL); + // callback::EditorTreeMenu() — removed, old menu system deleted } else if(pos.x >= (displaySize.x / 2 - 125) && pos.x <= (displaySize.x / 2 - 88) && pos.y >= (displaySize.y - 35) && pos.y <= (displaySize.y - 3)) { // the resource-mode picture was clicked mode = EDITOR_MODE_RESOURCE_RAISE; - callback::EditorResourceMenu(INITIALIZING_CALL); + // callback::EditorResourceMenu() — removed, old menu system deleted } else if(pos.x >= (displaySize.x / 2 - 88) && pos.x <= (displaySize.x / 2 - 51) && pos.y >= (displaySize.y - 35) && pos.y <= (displaySize.y - 3)) { // the landscape-mode picture was clicked mode = EDITOR_MODE_LANDSCAPE; - callback::EditorLandscapeMenu(INITIALIZING_CALL); + // callback::EditorLandscapeMenu() — removed, old menu system deleted } else if(pos.x >= (displaySize.x / 2 - 51) && pos.x <= (displaySize.x / 2 - 14) && pos.y >= (displaySize.y - 35) && pos.y <= (displaySize.y - 3)) { // the animal-mode picture was clicked mode = EDITOR_MODE_ANIMAL; - callback::EditorAnimalMenu(INITIALIZING_CALL); + // callback::EditorAnimalMenu() — removed, old menu system deleted } else if(pos.x >= (displaySize.x / 2 - 14) && pos.x <= (displaySize.x / 2 + 23) && pos.y >= (displaySize.y - 35) && pos.y <= (displaySize.y - 3)) { @@ -553,7 +551,7 @@ void CMap::onLeftMouseDown(const Point32& pos) mode = EDITOR_MODE_FLAG; ChangeSection_ = 0; setupVerticesActivity(); - callback::EditorPlayerMenu(INITIALIZING_CALL); + // callback::EditorPlayerMenu() — removed, old menu system deleted } else if(pos.x >= (displaySize.x / 2 + 96) && pos.x <= (displaySize.x / 2 + 133) && pos.y >= (displaySize.y - 35) && pos.y <= (displaySize.y - 3)) { @@ -563,53 +561,53 @@ void CMap::onLeftMouseDown(const Point32& pos) && pos.y <= (displaySize.y - 3)) { // the minimap picture was clicked - callback::MinimapMenu(INITIALIZING_CALL); + // callback::MinimapMenu() — removed, old menu system deleted } else if(pos.x >= (displaySize.x / 2 + 166) && pos.x <= (displaySize.x / 2 + 203) && pos.y >= (displaySize.y - 35) && pos.y <= (displaySize.y - 3)) { // the create-world picture was clicked - callback::EditorCreateMenu(INITIALIZING_CALL); + // callback::EditorCreateMenu() — removed, old menu system deleted } else if(pos.x >= (displaySize.x / 2 + 203) && pos.x <= (displaySize.x / 2 + 240) && pos.y >= (displaySize.y - 35) && pos.y <= (displaySize.y - 3)) { // the editor-main-menu picture was clicked - callback::EditorMainMenu(INITIALIZING_CALL); + // callback::EditorMainMenu() — removed, old menu system deleted } // now we check the right menubar else if(pos.x >= (displaySize.x - 37) && pos.x <= (displaySize.x) && pos.y >= (displaySize.y / 2 + 162) && pos.y <= (displaySize.y / 2 + 199)) { // the bugkill picture was clicked for quickload - callback::PleaseWait(INITIALIZING_CALL); + // callback::PleaseWait() — removed, old menu system deleted // we have to close the windows and initialize them again to prevent failures - callback::EditorCursorMenu(MAP_QUIT); - callback::EditorTextureMenu(MAP_QUIT); - callback::EditorTreeMenu(MAP_QUIT); - callback::EditorLandscapeMenu(MAP_QUIT); - callback::MinimapMenu(MAP_QUIT); - callback::EditorResourceMenu(MAP_QUIT); - callback::EditorAnimalMenu(MAP_QUIT); - callback::EditorPlayerMenu(MAP_QUIT); + // callback::EditorCursorMenu() — removed, old menu system deleted + // callback::EditorTextureMenu() — removed, old menu system deleted + // callback::EditorTreeMenu() — removed, old menu system deleted + // callback::EditorLandscapeMenu() — removed, old menu system deleted + // callback::MinimapMenu() — removed, old menu system deleted + // callback::EditorResourceMenu() — removed, old menu system deleted + // callback::EditorAnimalMenu() — removed, old menu system deleted + // callback::EditorPlayerMenu() — removed, old menu system deleted destructMap(); constructMap(global::userMapsPath / "quicksave.swd"); - callback::PleaseWait(WINDOW_QUIT_MESSAGE); + // callback::PleaseWait() — removed, old menu system deleted } else if(pos.x >= (displaySize.x - 37) && pos.x <= (displaySize.x) && pos.y >= (displaySize.y / 2 + 200) && pos.y <= (displaySize.y / 2 + 237)) { // the bugkill picture was clicked for quicksave - callback::PleaseWait(INITIALIZING_CALL); + // callback::PleaseWait() — removed, old menu system deleted if(!CFile::save_file(global::userMapsPath / "quicksave.swd", SWD, getMap())) { - callback::ShowStatus(INITIALIZING_CALL); - callback::ShowStatus(2); + // callback::ShowStatus() — removed, old menu system deleted + // callback::ShowStatus() — removed, old menu system deleted } - callback::PleaseWait(WINDOW_QUIT_MESSAGE); + // callback::PleaseWait() — removed, old menu system deleted } else if(pos.x >= (displaySize.x - 37) && pos.x <= (displaySize.x) && pos.y >= (displaySize.y / 2 - 239) && pos.y <= (displaySize.y / 2 - 202)) { // the cursor picture was clicked - callback::EditorCursorMenu(INITIALIZING_CALL); + // callback::EditorCursorMenu() — removed, old menu system deleted } else { // no picture was clicked @@ -770,20 +768,20 @@ void CMap::setKeyboardData(const SDL_KeyboardEvent& key) } break; case SDLK_r: - callback::PleaseWait(INITIALIZING_CALL); + // callback::PleaseWait() — removed, old menu system deleted rotateMap(); rotateMap(); - callback::PleaseWait(WINDOW_QUIT_MESSAGE); + // callback::PleaseWait() — removed, old menu system deleted break; case SDLK_x: - callback::PleaseWait(INITIALIZING_CALL); + // callback::PleaseWait() — removed, old menu system deleted MirrorMapOnXAxis(); - callback::PleaseWait(WINDOW_QUIT_MESSAGE); + // callback::PleaseWait() — removed, old menu system deleted break; case SDLK_y: - callback::PleaseWait(INITIALIZING_CALL); + // callback::PleaseWait() — removed, old menu system deleted MirrorMapOnYAxis(); - callback::PleaseWait(WINDOW_QUIT_MESSAGE); + // callback::PleaseWait() — removed, old menu system deleted break; case SDLK_KP_PLUS: if(ChangeSection_ < MAX_CHANGE_SECTION) @@ -876,64 +874,64 @@ void CMap::setKeyboardData(const SDL_KeyboardEvent& key) } break; case SDLK_F1: // help menu - callback::EditorHelpMenu(INITIALIZING_CALL); + // callback::EditorHelpMenu() — removed, old menu system deleted break; case SDLK_g: // convert map to greenland - callback::PleaseWait(INITIALIZING_CALL); + // callback::PleaseWait() — removed, old menu system deleted // we have to close the windows and initialize them again to prevent failures - callback::EditorCursorMenu(MAP_QUIT); - callback::EditorTextureMenu(MAP_QUIT); - callback::EditorTreeMenu(MAP_QUIT); - callback::EditorLandscapeMenu(MAP_QUIT); - callback::MinimapMenu(MAP_QUIT); - callback::EditorResourceMenu(MAP_QUIT); - callback::EditorAnimalMenu(MAP_QUIT); - callback::EditorPlayerMenu(MAP_QUIT); + // callback::EditorCursorMenu() — removed, old menu system deleted + // callback::EditorTextureMenu() — removed, old menu system deleted + // callback::EditorTreeMenu() — removed, old menu system deleted + // callback::EditorLandscapeMenu() — removed, old menu system deleted + // callback::MinimapMenu() — removed, old menu system deleted + // callback::EditorResourceMenu() — removed, old menu system deleted + // callback::EditorAnimalMenu() — removed, old menu system deleted + // callback::EditorPlayerMenu() — removed, old menu system deleted map->type = MAP_GREENLAND; unloadMapPics(); loadMapPics(); - callback::PleaseWait(WINDOW_QUIT_MESSAGE); + // callback::PleaseWait() — removed, old menu system deleted break; case SDLK_o: // convert map to wasteland - callback::PleaseWait(INITIALIZING_CALL); + // callback::PleaseWait() — removed, old menu system deleted // we have to close the windows and initialize them again to prevent failures - callback::EditorCursorMenu(MAP_QUIT); - callback::EditorTextureMenu(MAP_QUIT); - callback::EditorTreeMenu(MAP_QUIT); - callback::EditorLandscapeMenu(MAP_QUIT); - callback::MinimapMenu(MAP_QUIT); - callback::EditorResourceMenu(MAP_QUIT); - callback::EditorAnimalMenu(MAP_QUIT); - callback::EditorPlayerMenu(MAP_QUIT); + // callback::EditorCursorMenu() — removed, old menu system deleted + // callback::EditorTextureMenu() — removed, old menu system deleted + // callback::EditorTreeMenu() — removed, old menu system deleted + // callback::EditorLandscapeMenu() — removed, old menu system deleted + // callback::MinimapMenu() — removed, old menu system deleted + // callback::EditorResourceMenu() — removed, old menu system deleted + // callback::EditorAnimalMenu() — removed, old menu system deleted + // callback::EditorPlayerMenu() — removed, old menu system deleted map->type = MAP_WASTELAND; unloadMapPics(); loadMapPics(); - callback::PleaseWait(WINDOW_QUIT_MESSAGE); + // callback::PleaseWait() — removed, old menu system deleted break; case SDLK_w: // convert map to winterland - callback::PleaseWait(INITIALIZING_CALL); + // callback::PleaseWait() — removed, old menu system deleted // we have to close the windows and initialize them again to prevent failures - callback::EditorCursorMenu(MAP_QUIT); - callback::EditorTextureMenu(MAP_QUIT); - callback::EditorTreeMenu(MAP_QUIT); - callback::EditorLandscapeMenu(MAP_QUIT); - callback::MinimapMenu(MAP_QUIT); - callback::EditorResourceMenu(MAP_QUIT); - callback::EditorAnimalMenu(MAP_QUIT); - callback::EditorPlayerMenu(MAP_QUIT); + // callback::EditorCursorMenu() — removed, old menu system deleted + // callback::EditorTextureMenu() — removed, old menu system deleted + // callback::EditorTreeMenu() — removed, old menu system deleted + // callback::EditorLandscapeMenu() — removed, old menu system deleted + // callback::MinimapMenu() — removed, old menu system deleted + // callback::EditorResourceMenu() — removed, old menu system deleted + // callback::EditorAnimalMenu() — removed, old menu system deleted + // callback::EditorPlayerMenu() — removed, old menu system deleted map->type = MAP_WINTERLAND; unloadMapPics(); loadMapPics(); - callback::PleaseWait(WINDOW_QUIT_MESSAGE); + // callback::PleaseWait() — removed, old menu system deleted break; case SDLK_F9: // lock horizontal movement @@ -1322,14 +1320,12 @@ void CMap::render() .draw(Position(rightMenubarPos.x - 33, rightMenubarPos.y - 220)); Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP) .draw(Position(rightMenubarPos.x - 20, rightMenubarPos.y - 220)); - // bugkill picture for quickload with text + // bugkill picture for quickload Texture::getTexture(ArchiveID::EDITIO, MENUBAR_BUGKILL) .draw(Position(rightMenubarPos.x - 37, rightMenubarPos.y + 162)); - CFont::draw("Load", Position(rightMenubarPos.x - 35, rightMenubarPos.y + 193)); - // bugkill picture for quicksave with text + // bugkill picture for quicksave Texture::getTexture(ArchiveID::EDITIO, MENUBAR_BUGKILL) .draw(Position(rightMenubarPos.x - 37, rightMenubarPos.y + 200)); - CFont::draw("Save", Position(rightMenubarPos.x - 35, rightMenubarPos.y + 231)); // Restore matrices glMatrixMode(GL_PROJECTION); diff --git a/CMap.h b/CMap.h index 5c8bc7e..3fb4fa8 100644 --- a/CMap.h +++ b/CMap.h @@ -42,7 +42,6 @@ struct SavedVertex class CMap { - friend class CDebug; friend class CSurface; private: diff --git a/callbacks.cpp b/callbacks.cpp deleted file mode 100644 index c7d4174..0000000 --- a/callbacks.cpp +++ /dev/null @@ -1,2522 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "callbacks.h" -#include "CDebug.h" -#include "CGame.h" -#include "CIO/CButton.h" -#include "WindowManager.h" -#include "dskMainMenu.h" -#include "CIO/CFile.h" -#include "CIO/CFont.h" - -#include "CIO/CMinimapWindow.h" -#include "CIO/CPicture.h" -#include "CIO/CSelectBox.h" -#include "CIO/CTextfield.h" -#include "CIO/CWindow.h" -#include "CMap.h" -#include "CSurface.h" -#include "CollisionDetection.h" -#include "globals.h" -#include "helpers/format.hpp" -#include "s25util/strAlgos.h" -#include -#include -#include -#include -#include - -namespace bfs = boost::filesystem; - -void callback::PleaseWait(int Param) -{ - // NOTE: This "Please wait"-window is shown until the PleaseWait-callback is called with 'WINDOW_QUIT_MESSAGE'. - // The window will be registered by the game. To do it the other way (create and then let it automatically - // destroy by the gameloop), you don't need to register the window, but register the callback. - - static CWindow* WNDWait; - - enum - { - WINDOWQUIT - }; - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDWait) - break; - WNDWait = global::s2->RegisterWindow( - std::make_unique(PleaseWait, WINDOWQUIT, WindowPos::Center, Extent(212, 70), "Please wait")); - // we don't register this window cause we will destroy it manually if we need - // global::s2->RegisterCallback(PleaseWait); - - WNDWait->addText("Please wait ...", Position(10, 10), FontSize::Large); - // we need to render this window NOW, cause the render loop will do it too late (when the operation - // is done and we don't need the "Please wait"-window anymore) - glClear(GL_COLOR_BUFFER_BIT); - WNDWait->draw(Position(0, 0)); - global::s2->RenderPresent(); - break; - - case CALL_FROM_GAMELOOP: // This window gives a "Please Wait"-string, so it is shown while there is an intensive - // operation - // during ONE gameloop. Therefore it is only shown DURING this ONE operation. If the next gameloop - // appears, the operation MUST have been finished and we can destroy this window. - if(WNDWait) - { - global::s2->UnregisterCallback(PleaseWait); - WNDWait->setWaste(); - WNDWait = nullptr; - } - break; - - case WINDOW_QUIT_MESSAGE: // this is the global window quit message, callback is explicit called with this - // value, so destroy the window - if(WNDWait) - { - WNDWait->setWaste(); - WNDWait = nullptr; - } - break; - - default: break; - } -} - -void callback::ShowStatus(int Param) -{ - static CWindow* WND = nullptr; - static CFont* txt = nullptr; - - enum - { - WINDOWQUIT, - SHOW_SUCCESS, - SHOW_FAILURE - }; - - switch(Param) - { - case INITIALIZING_CALL: - if(WND) - break; - WND = global::s2->RegisterWindow(std::make_unique(ShowStatus, WINDOWQUIT, WindowPos::Center, - Extent(250, 90), "Status", WINDOW_GREEN1, - WINDOW_CLOSE | WINDOW_MINIMIZE | WINDOW_MOVE)); - txt = WND->addText("", Position(26, 20), FontSize::Large, FontColor::Yellow); - break; - case SHOW_SUCCESS: - assert(txt); - txt->setText("Operation finished successfully"); - txt->setColor(FontColor::Green); - break; - case SHOW_FAILURE: - assert(txt); - txt->setText("Operation failed! :("); - txt->setColor(FontColor::BrightRed); - break; - - case WINDOWQUIT: - case MAP_QUIT: - if(WND) - { - WND->setWaste(); - WND = nullptr; - } - break; - - default: break; - } -} - - - - - - -// now the editor callbacks will follow - -void callback::EditorHelpMenu(int Param) -{ - static CWindow* WNDHelp; - - enum - { - WINDOWQUIT - }; - - CSelectBox* SelectBoxHelp; - switch(Param) - { - case INITIALIZING_CALL: - if(WNDHelp) - break; - WNDHelp = global::s2->RegisterWindow(std::make_unique( - EditorHelpMenu, WINDOWQUIT, WindowPos::Center, Extent(640, 380), "Hilfe", WINDOW_GREEN2, - WINDOW_CLOSE | WINDOW_MOVE | WINDOW_RESIZE | WINDOW_MINIMIZE, ArchiveID::EDITIO)); - - SelectBoxHelp = WNDHelp->addSelectBox(Position(0, 0), Extent(WNDHelp->getSize() - WNDHelp->getBorderSize()), - FontSize::Normal, FontColor::Yellow, BUTTON_GREEN1); - SelectBoxHelp->addOption("User map path: " + global::userMapsPath.string()); - SelectBoxHelp->addOption(""); - SelectBoxHelp->addOption("Help-Menu........................................................................" - "..............................F1"); - SelectBoxHelp->addOption( - "Window/" - "Fullscreen...................................................................................Alt+Enter"); - SelectBoxHelp->addOption( - "Zoom in/normal/out......................................................................F5/F6/" - "F7"); - SelectBoxHelp->addOption( - "Scroll..........................................................................................." - "..................Arrow keys"); - SelectBoxHelp->addOption( - "Cursor size 1-9 (of " - "11)....................................................................................1-9"); - SelectBoxHelp->addOption( - "Make Cursor bigger/smaller........................................................................+/-"); - SelectBoxHelp->addOption("Scissors-Mode...................................................................." - "...........................Ctrl"); - SelectBoxHelp->addOption("Invert " - "mode............................................................................." - ".......................Shift"); - SelectBoxHelp->addOption("(e.g. Lower altitude, remove player, lower resources)"); - SelectBoxHelp->addOption("Plane " - "mode............................................................................." - "........................Alt"); - SelectBoxHelp->addOption( - "Reduce/default/enlarge maximum height.....................................................Ins/Pos1/" - "PageUp"); - SelectBoxHelp->addOption("(can't increase beyond this)"); - SelectBoxHelp->addOption("Reduce/default/enlarge minimum " - "height......................................................Del/End/" - "PageDown"); - SelectBoxHelp->addOption("(can't decrease below this)"); - SelectBoxHelp->addOption( - "Undo............................................................................................." - ".......................Q"); - SelectBoxHelp->addOption( - "Redo............................................................................................." - ".................SHIFT+Q"); - SelectBoxHelp->addOption("(just actions made with the cursor)"); - SelectBoxHelp->addOption( - "Build help " - "on/" - "off.............................................................................................Space"); - SelectBoxHelp->addOption("Castle-Mode......................................................................" - "..............................B"); - SelectBoxHelp->addOption("(planes the surrounding terrain"); - SelectBoxHelp->addOption(" so a castle can be build)"); - SelectBoxHelp->addOption("Harbour-Mode....................................................................." - "...........................H"); - SelectBoxHelp->addOption("(changes the surrounding terrain,"); - SelectBoxHelp->addOption(" so that a harbour can be build)"); - SelectBoxHelp->addOption( - "Convert map \"on-the-fly\" (Greenland/Winterworld/Wasteland).................G/W/O"); - SelectBoxHelp->addOption( - "New/Original shadows (experimental)..........................................................P"); - SelectBoxHelp->addOption( - "Lock/Unlock horizontal movement................................................................F9"); - SelectBoxHelp->addOption( - "Lock/Unlock vertical movement....................................................................F10"); - SelectBoxHelp->addOption( - "Turn borders " - "on/off......................................................................................F11"); - - break; - - case CALL_FROM_GAMELOOP: break; - - case WINDOW_QUIT_MESSAGE: // this is the global window quit message, callback is explicit called with this - // value, so destroy the window - case WINDOWQUIT: // this is the own window quit message of the callback - case MAP_QUIT: // this is the global window quit message, callback is explicit called with this value, so - // destroy the window - if(WNDHelp) - { - WNDHelp->setWaste(); - WNDHelp = nullptr; - SelectBoxHelp = nullptr; - } - break; - - default: break; - } -} - -void callback::EditorMainMenu(int Param) -{ - static CWindow* WNDMain = nullptr; - - enum - { - LOADMENU, - SAVEMENU, - QUITMENU, - WINDOWQUIT - }; - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDMain) - break; - WNDMain = global::s2->RegisterWindow( - std::make_unique(EditorMainMenu, WINDOWQUIT, WindowPos::Center, Extent(220, 320), "Main menu", - WINDOW_GREEN1, WINDOW_CLOSE | WINDOW_MOVE)); - WNDMain->addButton(EditorMainMenu, LOADMENU, Position(8, 100), Extent(190, 20), BUTTON_GREEN2, "Load map"); - WNDMain->addButton(EditorMainMenu, SAVEMENU, Position(8, 125), Extent(190, 20), BUTTON_GREEN2, "Save map"); - - WNDMain->addButton(EditorMainMenu, QUITMENU, Position(8, 260), Extent(190, 20), BUTTON_GREEN2, - "Leave editor"); - break; - - case WINDOWQUIT: - case MAP_QUIT: - if(WNDMain) - { - WNDMain->setWaste(); - WNDMain = nullptr; - } - break; - - case QUITMENU: EditorQuitMenu(INITIALIZING_CALL); break; - - case LOADMENU: EditorLoadMenu(INITIALIZING_CALL); break; - - case SAVEMENU: EditorSaveMenu(INITIALIZING_CALL); break; - - default: break; - } -} - -void callback::EditorLoadMenu(int Param) -{ - static CWindow* WNDLoad = nullptr; - static CSelectBox* CB_Filename = nullptr; - static CButton* BtnLoad = nullptr; - static CButton* BtnAbort = nullptr; - static std::string curFilename; - - enum - { - LOADMAP, - WINDOWQUIT - }; - - switch(Param) - { - case INITIALIZING_CALL: - { - if(WNDLoad) - break; - WNDLoad = global::s2->RegisterWindow( - std::make_unique(EditorLoadMenu, WINDOWQUIT, WindowPos::Center, Extent(280, 320), "Load", - WINDOW_GREEN1, WINDOW_CLOSE | WINDOW_MOVE | WINDOW_RESIZE)); - CB_Filename = WNDLoad->addSelectBox(Position(10, 5), Extent(160, 280), FontSize::Normal); - curFilename.clear(); - for(const auto& itFile : bfs::directory_iterator(global::userMapsPath)) - { - if(is_regular_file(itFile.status())) - { - // filter to supported map file extensions - const std::string ext = s25util::toLower(itFile.path().extension().string()); - if(ext != ".swd" && ext != ".wld") - continue; - - const std::string filename = itFile.path().filename().string(); - CB_Filename->addOption(filename, [filename](int) { curFilename = filename; }); - } - } - BtnLoad = - WNDLoad->addButton(EditorLoadMenu, LOADMAP, Position(175, 140), Extent(90, 20), BUTTON_GREY, "Load"); - BtnAbort = - WNDLoad->addButton(EditorLoadMenu, WINDOWQUIT, Position(175, 165), Extent(90, 20), BUTTON_RED1, "Abort"); - break; - } - case WINDOWQUIT: - case MAP_QUIT: - if(WNDLoad) - { - WNDLoad->setWaste(); - WNDLoad = nullptr; - CB_Filename = nullptr; - BtnLoad = nullptr; - BtnAbort = nullptr; - } - break; - - case WINDOW_RESIZED_CALL: - { - if(!WNDLoad || !CB_Filename || !BtnLoad || !BtnAbort) - break; - - int borderL = static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_LEFT_FRAME).x); - int borderR = static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_RIGHT_FRAME).x); - int borderT = static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_UPPER_FRAME).y); - int borderB = static_cast(global::getBitmapSize(ArchiveID::EDITRES, WINDOW_LOWER_FRAME).y); - - int window_w = static_cast(WNDLoad->getSize().x); - int window_h = static_cast(WNDLoad->getSize().y); - int client_w = window_w - borderL - borderR; - int client_h = window_h - borderT - borderB; - - // minimum size - if(client_w < 200) - client_w = 200; - if(client_h < 150) - client_h = 150; - - // selectbox: fills most of the client area - const int btn_w = 90; - const int margin = 10; - const int gap = 5; - - int sb_x = borderL + margin; - int sb_y = borderT + gap; - int sb_w = client_w - margin - gap - btn_w - margin; // left margin + gap to buttons + button + right margin - int sb_h = client_h - gap - gap; // top gap + bottom gap - if(sb_w < 50) - sb_w = 50; - if(sb_h < 50) - sb_h = 50; - - CB_Filename->setPos(Position(sb_x, sb_y)); - CB_Filename->setSize(Extent(sb_w, sb_h)); - - // buttons: same Y as original (140/165 + borderT), - // X just right of the selectbox with a gap - int btn_x = sb_x + sb_w + gap; - - BtnLoad->setX(btn_x); - BtnAbort->setX(btn_x); - - WNDLoad->setDirty(); - break; - } - - case LOADMAP: - { - if(curFilename.empty()) - return; - PleaseWait(INITIALIZING_CALL); - - // we have to close the windows and initialize them again to prevent failures - EditorCursorMenu(MAP_QUIT); - EditorTextureMenu(MAP_QUIT); - EditorTreeMenu(MAP_QUIT); - EditorLandscapeMenu(MAP_QUIT); - MinimapMenu(MAP_QUIT); - EditorResourceMenu(MAP_QUIT); - EditorAnimalMenu(MAP_QUIT); - EditorPlayerMenu(MAP_QUIT); - - bfs::path filepath = global::userMapsPath / curFilename; - if(!filepath.has_extension()) - filepath.replace_extension("SWD"); - if(!bfs::exists(filepath)) - filepath.replace_extension("WLD"); - if(!bfs::exists(filepath)) - filepath.replace_extension("SWD"); - - global::s2->enterEditor(filepath); - - // we need to check which of these windows was active before - /* - EditorCursorMenu(INITIALIZING_CALL); - EditorTextureMenu(INITIALIZING_CALL); - EditorTreeMenu(INITIALIZING_CALL); - EditorLandscapeMenu(INITIALIZING_CALL); - MinimapMenu(INITIALIZING_CALL); - EditorResourceMenu(INITIALIZING_CALL); - EditorAnimalMenu(INITIALIZING_CALL); - EditorPlayerMenu(INITIALIZING_CALL); - */ - - PleaseWait(WINDOW_QUIT_MESSAGE); - EditorLoadMenu(WINDOWQUIT); - break; - } - - default: break; - } -} - -void callback::EditorSaveMenu(int Param) -{ - static CWindow* WNDSave = nullptr; - static CTextfield* TXTF_Filename = nullptr; - static CTextfield* TXTF_Mapname = nullptr; - static CTextfield* TXTF_Author = nullptr; - static CMap* MapObj = nullptr; - - enum - { - SAVEMAP, - WINDOWQUIT - }; - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDSave) - break; - { - WNDSave = global::s2->RegisterWindow( - std::make_unique(EditorSaveMenu, WINDOWQUIT, WindowPos::Center, Extent(280, 200), "Save", - WINDOW_GREEN1, WINDOW_CLOSE | WINDOW_MOVE)); - MapObj = global::s2->getMapObj(); - - WNDSave->addText("Filename", Position(100, 2), FontSize::Small); - TXTF_Filename = WNDSave->addTextfield(Position(10, 13), 21, 1); - const bfs::path filePath = MapObj->getFilepath().empty() ? "MyMap" : MapObj->getFilepath(); - TXTF_Filename->setText(filePath.filename().string()); - WNDSave->addText("Mapname", Position(100, 38), FontSize::Small); - TXTF_Mapname = WNDSave->addTextfield(Position(10, 50), 21, 1); - TXTF_Mapname->setText(MapObj->getMapname()); - WNDSave->addText("Author", Position(100, 75), FontSize::Small); - TXTF_Author = WNDSave->addTextfield(Position(10, 87), 21, 1); - TXTF_Author->setText(MapObj->getAuthor()); - WNDSave->addButton(EditorSaveMenu, SAVEMAP, Position(170, 120), Extent(90, 20), BUTTON_GREY, "Save"); - WNDSave->addButton(EditorSaveMenu, WINDOWQUIT, Position(170, 145), Extent(90, 20), BUTTON_RED1, - "Abort"); - break; - } - case WINDOWQUIT: - case MAP_QUIT: - if(WNDSave) - { - WNDSave->setWaste(); - WNDSave = nullptr; - } - TXTF_Filename = nullptr; - TXTF_Mapname = nullptr; - TXTF_Author = nullptr; - break; - - case SAVEMAP: - { - PleaseWait(INITIALIZING_CALL); - - MapObj->setMapname(TXTF_Mapname->getText()); - MapObj->setAuthor(TXTF_Author->getText()); - bfs::path filepath = global::userMapsPath / TXTF_Filename->getText(); - if(!filepath.has_extension()) - filepath.replace_extension("SWD"); - MapObj->setFilepath(filepath); - bool result = CFile::save_file(filepath, WLD, MapObj->getMap()); - - ShowStatus(INITIALIZING_CALL); - ShowStatus(result ? 1 : 2); - - PleaseWait(WINDOW_QUIT_MESSAGE); - EditorSaveMenu(WINDOWQUIT); - break; - } - - default: break; - } -} - -void callback::EditorQuitMenu(int Param) -{ - static CWindow* WNDBackToMainMenu = nullptr; - - enum - { - BACKTOMAIN = 1, - NOTBACKTOMAIN, - WINDOWQUIT - }; - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDBackToMainMenu) - break; - WNDBackToMainMenu = global::s2->RegisterWindow( - std::make_unique(EditorQuitMenu, WINDOWQUIT, WindowPos::Center, Extent(212, 110), "Exit?")); - WNDBackToMainMenu->addButton(EditorQuitMenu, BACKTOMAIN, Position(0, 0), Extent(100, 80), BUTTON_GREEN2, - nullptr, PICTURE_SMALL_TICK); - WNDBackToMainMenu->addButton(EditorQuitMenu, NOTBACKTOMAIN, Position(100, 0), Extent(100, 80), BUTTON_RED1, - nullptr, PICTURE_SMALL_CROSS); - break; - - case BACKTOMAIN: - if(global::s2->getMapObj()) - global::s2->delMapObj(); - WNDBackToMainMenu->setWaste(); - WNDBackToMainMenu = nullptr; - // now call all EditorMenu callbacks (from the menubar) with MAP_QUIT - EditorHelpMenu(MAP_QUIT); - EditorMainMenu(MAP_QUIT); - EditorLoadMenu(MAP_QUIT); - EditorSaveMenu(MAP_QUIT); - EditorTextureMenu(MAP_QUIT); - EditorTreeMenu(MAP_QUIT); - EditorLandscapeMenu(MAP_QUIT); - MinimapMenu(MAP_QUIT); - EditorCursorMenu(MAP_QUIT); - EditorResourceMenu(MAP_QUIT); - EditorAnimalMenu(MAP_QUIT); - EditorPlayerMenu(MAP_QUIT); - EditorCreateMenu(MAP_QUIT); - // go to main menu - WINDOWMANAGER.Switch(std::make_unique()); - break; - - case NOTBACKTOMAIN: - if(WNDBackToMainMenu) - { - WNDBackToMainMenu->setWaste(); - WNDBackToMainMenu = nullptr; - } - break; - - default: break; - } -} - -void callback::EditorTextureMenu(int Param) -{ - static CWindow* WNDTexture = nullptr; - static CMap* MapObj = nullptr; - static bobMAP* map = nullptr; - static int textureIndex = 0; - static int lastContent = 0x00; - static Position Pos{0, 0}; - - enum - { - WINDOWQUIT, - PICSNOW, - PICSTEPPE, - PICSWAMP, - PICFLOWER, - PICMINING1, - PICMINING2, - PICMINING3, - PICMINING4, - PICSTEPPE_MEADOW1, - PICMEADOW1, - PICMEADOW2, - PICMEADOW3, - PICSTEPPE_MEADOW2, - PICMINING_MEADOW, - PICWATER, - PICLAVA, - PICMEADOW_MIXED - }; - - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - { - assert(MapObj); - assert(map); - } - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDTexture) - break; - WNDTexture = global::s2->RegisterWindow( - std::make_unique(EditorTextureMenu, WINDOWQUIT, Pos, Extent(220, 133), "Terrain", WINDOW_GREEN1, - WINDOW_CLOSE | WINDOW_MINIMIZE | WINDOW_MOVE)); - MapObj = global::s2->getMapObj(); - map = MapObj->getMap(); - switch(map->type) - { - case MAP_GREENLAND: textureIndex = PICTURE_GREENLAND_TEXTURE_SNOW; break; - case MAP_WASTELAND: textureIndex = PICTURE_WASTELAND_TEXTURE_SNOW; break; - case MAP_WINTERLAND: textureIndex = PICTURE_WINTERLAND_TEXTURE_SNOW; break; - default: textureIndex = PICTURE_GREENLAND_TEXTURE_SNOW; break; - } - MapObj->setMode(EDITOR_MODE_TEXTURE); - MapObj->setModeContent(TRIANGLE_TEXTURE_SNOW); - - WNDTexture->addPicture(EditorTextureMenu, PICSNOW, Position(2, 2), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICSTEPPE, Position(36, 2), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICSWAMP, Position(70, 2), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICFLOWER, Position(104, 2), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMINING1, Position(138, 2), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMINING2, Position(172, 2), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMINING3, Position(2, 36), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMINING4, Position(36, 36), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICSTEPPE_MEADOW1, Position(70, 36), ArchiveID::EDITIO, - textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMEADOW1, Position(104, 36), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMEADOW2, Position(138, 36), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMEADOW3, Position(172, 36), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICSTEPPE_MEADOW2, Position(2, 70), ArchiveID::EDITIO, - textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICMINING_MEADOW, Position(36, 70), ArchiveID::EDITIO, - textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICWATER, Position(70, 70), ArchiveID::EDITIO, textureIndex++); - WNDTexture->addPicture(EditorTextureMenu, PICLAVA, Position(104, 70), ArchiveID::EDITIO, textureIndex++); - if(map->type != MAP_WASTELAND) - WNDTexture->addPicture(EditorTextureMenu, PICMEADOW_MIXED, Position(138, 70), ArchiveID::EDITIO, - textureIndex); - break; - - case PICSNOW: MapObj->setModeContent(TRIANGLE_TEXTURE_SNOW); break; - case PICSTEPPE: MapObj->setModeContent(TRIANGLE_TEXTURE_STEPPE); break; - case PICSWAMP: MapObj->setModeContent(TRIANGLE_TEXTURE_SWAMP); break; - case PICFLOWER: MapObj->setModeContent(TRIANGLE_TEXTURE_FLOWER); break; - case PICMINING1: MapObj->setModeContent(TRIANGLE_TEXTURE_MINING1); break; - case PICMINING2: MapObj->setModeContent(TRIANGLE_TEXTURE_MINING2); break; - case PICMINING3: MapObj->setModeContent(TRIANGLE_TEXTURE_MINING3); break; - case PICMINING4: MapObj->setModeContent(TRIANGLE_TEXTURE_MINING4); break; - case PICSTEPPE_MEADOW1: MapObj->setModeContent(TRIANGLE_TEXTURE_STEPPE_MEADOW1); break; - case PICMEADOW1: MapObj->setModeContent(TRIANGLE_TEXTURE_MEADOW1); break; - case PICMEADOW2: MapObj->setModeContent(TRIANGLE_TEXTURE_MEADOW2); break; - case PICMEADOW3: MapObj->setModeContent(TRIANGLE_TEXTURE_MEADOW3); break; - case PICSTEPPE_MEADOW2: MapObj->setModeContent(TRIANGLE_TEXTURE_STEPPE_MEADOW2); break; - case PICMINING_MEADOW: MapObj->setModeContent(TRIANGLE_TEXTURE_MINING_MEADOW); break; - case PICWATER: MapObj->setModeContent(TRIANGLE_TEXTURE_WATER); break; - case PICLAVA: MapObj->setModeContent(TRIANGLE_TEXTURE_LAVA); break; - case PICMEADOW_MIXED: MapObj->setModeContent(TRIANGLE_TEXTURE_MEADOW_MIXED); break; - - case WINDOW_CLICKED_CALL: - if(MapObj) - { - MapObj->setMode(EDITOR_MODE_TEXTURE); - MapObj->setModeContent(lastContent); - } - break; - - case WINDOWQUIT: - if(WNDTexture) - { - Pos = WNDTexture->getPos(); - WNDTexture->setWaste(); - WNDTexture = nullptr; - } - MapObj->setMode(EDITOR_MODE_HEIGHT_RAISE); - MapObj->setModeContent(0x00); - lastContent = 0x00; - MapObj = nullptr; - map = nullptr; - textureIndex = 0; - break; - - case MAP_QUIT: - // we do the same like in case WINDOWQUIT, but we won't setMode(EDITOR_MODE_HEIGHT_RAISE), cause map is dead - if(WNDTexture) - { - Pos = WNDTexture->getPos(); - WNDTexture->setWaste(); - WNDTexture = nullptr; - } - lastContent = 0x00; - MapObj = nullptr; - map = nullptr; - textureIndex = 0; - break; - - default: break; - } - if(MapObj) - lastContent = MapObj->getModeContent(); -} - -void callback::EditorTreeMenu(int Param) -{ - static CWindow* WNDTree = nullptr; - static CMap* MapObj = nullptr; - static bobMAP* map = nullptr; - static int lastContent = 0x00; - static int lastContent2 = 0x00; - static Position Pos{230, 0}; - - enum - { - WINDOWQUIT, - PICPINE, - PICBIRCH, - PICOAK, - PICPALM1, - PICPALM2, - PICPINEAPPLE, - PICCYPRESS, - PICCHERRY, - PICFIR, - PICSPIDER, - PICFLAPHAT, - PICWOOD_MIXED, - PICPALM_MIXED - }; - - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - assert(WNDTree && MapObj && map); - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDTree) - break; - WNDTree = global::s2->RegisterWindow( - std::make_unique(EditorTreeMenu, WINDOWQUIT, Pos, Extent(148, 140), "Trees", WINDOW_GREEN1, - WINDOW_CLOSE | WINDOW_MINIMIZE | WINDOW_MOVE)); - MapObj = global::s2->getMapObj(); - map = MapObj->getMap(); - switch(map->type) - { - case MAP_GREENLAND: - WNDTree->addPicture(EditorTreeMenu, PICPINE, Position(2, 2), ArchiveID::EDITIO, PICTURE_TREE_PINE); - WNDTree->addPicture(EditorTreeMenu, PICBIRCH, Position(36, 2), ArchiveID::EDITIO, - PICTURE_TREE_BIRCH); - WNDTree->addPicture(EditorTreeMenu, PICOAK, Position(70, 2), ArchiveID::EDITIO, PICTURE_TREE_OAK); - WNDTree->addPicture(EditorTreeMenu, PICPALM1, Position(104, 2), ArchiveID::EDITIO, - PICTURE_TREE_PALM1); - WNDTree->addPicture(EditorTreeMenu, PICPALM2, Position(2, 36), ArchiveID::EDITIO, - PICTURE_TREE_PALM2); - WNDTree->addPicture(EditorTreeMenu, PICPINEAPPLE, Position(36, 36), ArchiveID::EDITIO, - PICTURE_TREE_PINEAPPLE); - WNDTree->addPicture(EditorTreeMenu, PICCYPRESS, Position(70, 36), ArchiveID::EDITIO, - PICTURE_TREE_CYPRESS); - WNDTree->addPicture(EditorTreeMenu, PICCHERRY, Position(104, 36), ArchiveID::EDITIO, - PICTURE_TREE_CHERRY); - WNDTree->addPicture(EditorTreeMenu, PICFIR, Position(2, 72), ArchiveID::EDITIO, PICTURE_TREE_FIR); - WNDTree->addPicture(EditorTreeMenu, PICWOOD_MIXED, Position(36, 70), ArchiveID::EDITIO, - PICTURE_TREE_WOOD_MIXED); - WNDTree->addPicture(EditorTreeMenu, PICPALM_MIXED, Position(70, 70), ArchiveID::EDITIO, - PICTURE_TREE_PALM_MIXED); - break; - case MAP_WASTELAND: - WNDTree->addPicture(EditorTreeMenu, PICFLAPHAT, Position(2, 2), ArchiveID::EDITIO, - PICTURE_TREE_FLAPHAT); - WNDTree->addPicture(EditorTreeMenu, PICSPIDER, Position(36, 2), ArchiveID::EDITIO, - PICTURE_TREE_SPIDER); - WNDTree->addPicture(EditorTreeMenu, PICPINEAPPLE, Position(70, 2), ArchiveID::EDITIO, - PICTURE_TREE_PINEAPPLE); - WNDTree->addPicture(EditorTreeMenu, PICCHERRY, Position(104, 2), ArchiveID::EDITIO, - PICTURE_TREE_CHERRY); - break; - case MAP_WINTERLAND: - WNDTree->addPicture(EditorTreeMenu, PICPINE, Position(2, 2), ArchiveID::EDITIO, PICTURE_TREE_PINE); - WNDTree->addPicture(EditorTreeMenu, PICBIRCH, Position(36, 2), ArchiveID::EDITIO, - PICTURE_TREE_BIRCH); - WNDTree->addPicture(EditorTreeMenu, PICCYPRESS, Position(70, 2), ArchiveID::EDITIO, - PICTURE_TREE_CYPRESS); - WNDTree->addPicture(EditorTreeMenu, PICFIR, Position(104, 2), ArchiveID::EDITIO, PICTURE_TREE_FIR); - WNDTree->addPicture(EditorTreeMenu, PICWOOD_MIXED, Position(2, 36), ArchiveID::EDITIO, - PICTURE_TREE_WOOD_MIXED); - break; - default: // should not happen - break; - } - MapObj->setMode(EDITOR_MODE_TREE); - MapObj->setModeContent(0x30); - MapObj->setModeContent2(0xC4); - lastContent = 0x30; - lastContent2 = 0xC4; - break; - - case PICPINE: - MapObj->setModeContent(0x30); - MapObj->setModeContent2(0xC4); - lastContent = 0x30; - lastContent2 = 0xC4; - break; - case PICBIRCH: - MapObj->setModeContent(0x70); - MapObj->setModeContent2(0xC4); - lastContent = 0x70; - lastContent2 = 0xC4; - break; - case PICOAK: - MapObj->setModeContent(0xB0); - MapObj->setModeContent2(0xC4); - lastContent = 0xB0; - lastContent2 = 0xC4; - break; - case PICPALM1: - MapObj->setModeContent(0xF0); - MapObj->setModeContent2(0xC4); - lastContent = 0xF0; - lastContent2 = 0xC4; - break; - case PICPALM2: - MapObj->setModeContent(0x30); - MapObj->setModeContent2(0xC5); - lastContent = 0x30; - lastContent2 = 0xC5; - break; - case PICPINEAPPLE: - MapObj->setModeContent(0x70); - MapObj->setModeContent2(0xC5); - lastContent = 0x70; - lastContent2 = 0xC5; - break; - case PICCYPRESS: - MapObj->setModeContent(0xB0); - MapObj->setModeContent2(0xC5); - lastContent = 0xB0; - lastContent2 = 0xC5; - break; - case PICCHERRY: - MapObj->setModeContent(0xF0); - MapObj->setModeContent2(0xC5); - lastContent = 0xF0; - lastContent2 = 0xC5; - break; - case PICFIR: - MapObj->setModeContent(0x30); - MapObj->setModeContent2(0xC6); - lastContent = 0x30; - lastContent2 = 0xC6; - break; - case PICFLAPHAT: - MapObj->setModeContent(0x70); - MapObj->setModeContent2(0xC4); - lastContent = 0x70; - lastContent2 = 0xC4; - break; - case PICSPIDER: - MapObj->setModeContent(0x30); - MapObj->setModeContent2(0xC4); - lastContent = 0x30; - lastContent2 = 0xC4; - break; - case PICWOOD_MIXED: - MapObj->setModeContent(0xFF); - MapObj->setModeContent2(0xC4); - lastContent = 0xFF; - lastContent2 = 0xC4; - break; - case PICPALM_MIXED: - MapObj->setModeContent(0xFF); - MapObj->setModeContent2(0xC5); - lastContent = 0xFF; - lastContent2 = 0xC5; - break; - - case WINDOW_CLICKED_CALL: - if(MapObj) - { - MapObj->setMode(EDITOR_MODE_TREE); - MapObj->setModeContent(lastContent); - MapObj->setModeContent2(lastContent2); - } - break; - - case WINDOWQUIT: - if(WNDTree) - { - Pos = WNDTree->getPos(); - WNDTree->setWaste(); - WNDTree = nullptr; - } - MapObj->setMode(EDITOR_MODE_HEIGHT_RAISE); - MapObj->setModeContent(0x00); - MapObj->setModeContent2(0x00); - lastContent = 0x00; - lastContent2 = 0x00; - MapObj = nullptr; - map = nullptr; - break; - - case MAP_QUIT: - // we do the same like in case WINDOWQUIT, but we won't setMode(EDITOR_MODE_HEIGHT_RAISE), cause map is dead - if(WNDTree) - { - Pos = WNDTree->getPos(); - WNDTree->setWaste(); - WNDTree = nullptr; - } - lastContent = 0x00; - lastContent2 = 0x00; - MapObj = nullptr; - map = nullptr; - break; - - default: break; - } -} - -void callback::EditorResourceMenu(int Param) -{ - static CWindow* WNDResource = nullptr; - static CMap* MapObj = nullptr; - static int lastContent = 0x00; - static Position Pos{0, 140}; - - enum - { - WINDOWQUIT, - PICGOLD, - PICORE, - PICCOAL, - PICGRANITE - }; - - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - assert(WNDResource && MapObj); - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDResource) - break; - WNDResource = global::s2->RegisterWindow( - std::make_unique(EditorResourceMenu, WINDOWQUIT, Pos, Extent(148, 55), "Resources", - WINDOW_GREEN1, WINDOW_CLOSE | WINDOW_MINIMIZE | WINDOW_MOVE)); - MapObj = global::s2->getMapObj(); - - WNDResource->addPicture(EditorResourceMenu, PICGOLD, Position(2, 2), ArchiveID::EDITIO, - PICTURE_RESOURCE_GOLD); - WNDResource->addPicture(EditorResourceMenu, PICORE, Position(36, 2), ArchiveID::EDITIO, - PICTURE_RESOURCE_ORE); - WNDResource->addPicture(EditorResourceMenu, PICCOAL, Position(70, 2), ArchiveID::EDITIO, - PICTURE_RESOURCE_COAL); - WNDResource->addPicture(EditorResourceMenu, PICGRANITE, Position(104, 2), ArchiveID::EDITIO, - PICTURE_RESOURCE_GRANITE); - - MapObj->setMode(EDITOR_MODE_RESOURCE_RAISE); - MapObj->setModeContent(0x51); - lastContent = 0x51; - break; - - case PICGOLD: - MapObj->setModeContent(0x51); - lastContent = 0x51; - break; - case PICORE: - MapObj->setModeContent(0x49); - lastContent = 0x49; - break; - case PICCOAL: - MapObj->setModeContent(0x41); - lastContent = 0x41; - break; - case PICGRANITE: - MapObj->setModeContent(0x59); - lastContent = 0x59; - break; - - case WINDOW_CLICKED_CALL: - if(MapObj) - { - MapObj->setMode(EDITOR_MODE_RESOURCE_RAISE); - MapObj->setModeContent(lastContent); - } - break; - - case WINDOWQUIT: - if(WNDResource) - { - Pos = WNDResource->getPos(); - WNDResource->setWaste(); - WNDResource = nullptr; - } - MapObj->setMode(EDITOR_MODE_HEIGHT_RAISE); - MapObj->setModeContent(0x00); - lastContent = 0x00; - MapObj = nullptr; - break; - - case MAP_QUIT: - // we do the same like in case WINDOWQUIT, but we won't setMode(EDITOR_MODE_HEIGHT_RAISE), cause map is dead - if(WNDResource) - { - Pos = WNDResource->getPos(); - WNDResource->setWaste(); - WNDResource = nullptr; - } - lastContent = 0x00; - MapObj = nullptr; - break; - - default: break; - } -} - -void callback::EditorLandscapeMenu(int Param) -{ - static CWindow* WNDLandscape = nullptr; - static CMap* MapObj = nullptr; - static bobMAP* map = nullptr; - static int lastContent = 0x00; - static int lastContent2 = 0x00; - static Position Pos{390, 0}; - - enum - { - WINDOWQUIT, - PICGRANITE, - PICTREEDEAD, - PICSTONE, - PICCACTUS, - PICPEBBLE, - PICBUSH, - PICSHRUB, - PICBONE, - PICMUSHROOM, - PICSTALAGMITE, - PICFLOWERS - }; - - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - assert(WNDLandscape && MapObj && map); - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDLandscape) - break; - WNDLandscape = global::s2->RegisterWindow( - std::make_unique(EditorLandscapeMenu, WINDOWQUIT, Pos, Extent(112, 174), "Landscape", - WINDOW_GREEN1, WINDOW_CLOSE | WINDOW_MINIMIZE | WINDOW_MOVE)); - MapObj = global::s2->getMapObj(); - map = MapObj->getMap(); - switch(map->type) - { - case MAP_GREENLAND: - WNDLandscape->addPicture(EditorLandscapeMenu, PICGRANITE, Position(2, 2), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_GRANITE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICTREEDEAD, Position(36, 2), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_TREE_DEAD); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSTONE, Position(70, 2), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_STONE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICCACTUS, Position(2, 36), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_CACTUS); - WNDLandscape->addPicture(EditorLandscapeMenu, PICPEBBLE, Position(36, 36), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_PEBBLE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICBUSH, Position(70, 36), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_BUSH); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSHRUB, Position(2, 70), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_SHRUB); - WNDLandscape->addPicture(EditorLandscapeMenu, PICBONE, Position(36, 70), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_BONE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICMUSHROOM, Position(70, 70), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_MUSHROOM); - WNDLandscape->addPicture(EditorLandscapeMenu, PICFLOWERS, Position(5, 107), ArchiveID::MAP00, - MAPPIC_FLOWERS); - break; - case MAP_WASTELAND: - WNDLandscape->addPicture(EditorLandscapeMenu, PICGRANITE, Position(2, 2), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_GRANITE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICTREEDEAD, Position(36, 2), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_TREE_DEAD); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSTONE, Position(70, 2), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_STONE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSTALAGMITE, Position(2, 36), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_STALAGMITE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICPEBBLE, Position(36, 36), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_PEBBLE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICBUSH, Position(70, 36), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_BUSH); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSHRUB, Position(2, 70), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_SHRUB); - WNDLandscape->addPicture(EditorLandscapeMenu, PICBONE, Position(36, 70), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_BONE); - WNDLandscape->addPicture(EditorLandscapeMenu, PICMUSHROOM, Position(70, 70), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_MUSHROOM); - WNDLandscape->addPicture(EditorLandscapeMenu, PICFLOWERS, Position(5, 107), ArchiveID::MAP00, - MAPPIC_FLOWERS); - break; - case MAP_WINTERLAND: - WNDLandscape->addPicture(EditorLandscapeMenu, PICGRANITE, Position(2, 2), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_GRANITE_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICTREEDEAD, Position(36, 2), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_TREE_DEAD_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICSTONE, Position(70, 2), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_STONE_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICPEBBLE, Position(2, 36), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_PEBBLE_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICBONE, Position(36, 36), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_BONE_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICMUSHROOM, Position(70, 36), ArchiveID::EDITIO, - PICTURE_LANDSCAPE_MUSHROOM_WINTER); - WNDLandscape->addPicture(EditorLandscapeMenu, PICFLOWERS, Position(73, 73), ArchiveID::MAP00, - MAPPIC_FLOWERS); - break; - default: // should not happen - break; - } - MapObj->setMode(EDITOR_MODE_LANDSCAPE); - MapObj->setModeContent(0x01); - MapObj->setModeContent2(0xCC); - lastContent = 0x01; - lastContent2 = 0xCC; - break; - - case PICGRANITE: - MapObj->setModeContent(0x01); - MapObj->setModeContent2(0xCC); - lastContent = 0x01; - lastContent2 = 0xCC; - break; - case PICTREEDEAD: - MapObj->setModeContent(0x05); - MapObj->setModeContent2(0xC8); - lastContent = 0x05; - lastContent2 = 0xC8; - break; - case PICSTONE: - MapObj->setModeContent(0x02); - MapObj->setModeContent2(0xC8); - lastContent = 0x02; - lastContent2 = 0xC8; - break; - case PICCACTUS: - MapObj->setModeContent(0x0C); - MapObj->setModeContent2(0xC8); - lastContent = 0x0C; - lastContent2 = 0xC8; - break; - case PICPEBBLE: - MapObj->setModeContent(0x25); - MapObj->setModeContent2(0xC8); - lastContent = 0x25; - lastContent2 = 0xC8; - break; - case PICBUSH: - MapObj->setModeContent(0x10); - MapObj->setModeContent2(0xC8); - lastContent = 0x10; - lastContent2 = 0xC8; - break; - case PICSHRUB: - MapObj->setModeContent(0x0E); - MapObj->setModeContent2(0xC8); - lastContent = 0x0E; - lastContent2 = 0xC8; - break; - case PICBONE: - MapObj->setModeContent(0x07); - MapObj->setModeContent2(0xC8); - lastContent = 0x07; - lastContent2 = 0xC8; - break; - case PICMUSHROOM: - MapObj->setModeContent(0x00); - MapObj->setModeContent2(0xC8); - lastContent = 0x00; - lastContent2 = 0xC8; - break; - case PICSTALAGMITE: - MapObj->setModeContent(0x18); - MapObj->setModeContent2(0xC8); - lastContent = 0x18; - lastContent2 = 0xC8; - break; - case PICFLOWERS: - MapObj->setModeContent(0x09); - MapObj->setModeContent2(0xC8); - lastContent = 0x09; - lastContent2 = 0xC8; - break; - - case WINDOW_CLICKED_CALL: - if(MapObj) - { - MapObj->setMode(EDITOR_MODE_LANDSCAPE); - MapObj->setModeContent(lastContent); - MapObj->setModeContent2(lastContent2); - } - break; - - case WINDOWQUIT: - if(WNDLandscape) - { - Pos = WNDLandscape->getPos(); - WNDLandscape->setWaste(); - WNDLandscape = nullptr; - } - MapObj->setMode(EDITOR_MODE_HEIGHT_RAISE); - MapObj->setModeContent(0x00); - MapObj->setModeContent2(0x00); - lastContent = 0x00; - lastContent2 = 0x00; - MapObj = nullptr; - map = nullptr; - break; - - case MAP_QUIT: - // we do the same like in case WINDOWQUIT, but we won't setMode(EDITOR_MODE_HEIGHT_RAISE), cause map is dead - if(WNDLandscape) - { - Pos = WNDLandscape->getPos(); - WNDLandscape->setWaste(); - WNDLandscape = nullptr; - } - lastContent = 0x00; - lastContent2 = 0x00; - MapObj = nullptr; - map = nullptr; - break; - - default: break; - } -} - -void callback::EditorAnimalMenu(int Param) -{ - static CWindow* WNDAnimal = nullptr; - static CMap* MapObj = nullptr; - static int lastContent = 0x00; - static Position Pos{510, 0}; - - enum - { - WINDOWQUIT, - PICRABBIT, - PICFOX, - PICSTAG, - PICROE, - PICDUCK, - PICSHEEP - }; - - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - assert(WNDAnimal && MapObj); - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDAnimal) - break; - WNDAnimal = global::s2->RegisterWindow( - std::make_unique(EditorAnimalMenu, WINDOWQUIT, Pos, Extent(116, 106), "Animals", WINDOW_GREEN1, - WINDOW_CLOSE | WINDOW_MINIMIZE | WINDOW_MOVE)); - WNDAnimal->addPicture(EditorAnimalMenu, PICRABBIT, Position(2, 2), ArchiveID::EDITIO, - PICTURE_ANIMAL_RABBIT); - WNDAnimal->addPicture(EditorAnimalMenu, PICFOX, Position(36, 2), ArchiveID::EDITIO, PICTURE_ANIMAL_FOX); - WNDAnimal->addPicture(EditorAnimalMenu, PICSTAG, Position(70, 2), ArchiveID::EDITIO, PICTURE_ANIMAL_STAG); - WNDAnimal->addPicture(EditorAnimalMenu, PICROE, Position(2, 36), ArchiveID::EDITIO, PICTURE_ANIMAL_ROE); - WNDAnimal->addPicture(EditorAnimalMenu, PICDUCK, Position(36, 36), ArchiveID::EDITIO, PICTURE_ANIMAL_DUCK); - WNDAnimal->addPicture(EditorAnimalMenu, PICSHEEP, Position(70, 36), ArchiveID::EDITIO, - PICTURE_ANIMAL_SHEEP); - - MapObj = global::s2->getMapObj(); - MapObj->setMode(EDITOR_MODE_ANIMAL); - MapObj->setModeContent(0x01); - lastContent = 0x01; - break; - - case PICRABBIT: - MapObj->setModeContent(0x01); - lastContent = 0x01; - break; - case PICFOX: - MapObj->setModeContent(0x02); - lastContent = 0x02; - break; - case PICSTAG: - MapObj->setModeContent(0x03); - lastContent = 0x03; - break; - case PICROE: - MapObj->setModeContent(0x04); - lastContent = 0x04; - break; - case PICDUCK: - MapObj->setModeContent(0x05); - lastContent = 0x05; - break; - case PICSHEEP: - MapObj->setModeContent(0x06); - lastContent = 0x06; - break; - - case WINDOW_CLICKED_CALL: - if(MapObj) - { - MapObj->setMode(EDITOR_MODE_ANIMAL); - MapObj->setModeContent(lastContent); - } - break; - - case WINDOWQUIT: - if(WNDAnimal) - { - Pos = WNDAnimal->getPos(); - WNDAnimal->setWaste(); - WNDAnimal = nullptr; - } - MapObj->setMode(EDITOR_MODE_HEIGHT_RAISE); - MapObj->setModeContent(0x00); - lastContent = 0x00; - MapObj = nullptr; - break; - - case MAP_QUIT: - // we do the same like in case WINDOWQUIT, but we won't setMode(EDITOR_MODE_HEIGHT_RAISE), cause map is dead - if(WNDAnimal) - { - Pos = WNDAnimal->getPos(); - WNDAnimal->setWaste(); - WNDAnimal = nullptr; - } - lastContent = 0x00; - MapObj = nullptr; - break; - - default: break; - } -} - -void callback::EditorPlayerMenu(int Param) -{ - static CWindow* WNDPlayer = nullptr; - static CMap* MapObj = nullptr; - static int PlayerIdx = 0x00; - static CFont* PlayerNumberText = nullptr; - static DisplayRectangle tempRect; - static Uint16* PlayerHQx = nullptr; - static Uint16* PlayerHQy = nullptr; - static Position Pos{0, 200}; - - enum - { - PLAYER_REDUCE = 0, - PLAYER_RAISE, - GOTO_PLAYER, - WINDOWQUIT - }; - - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - assert(WNDPlayer && MapObj); - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDPlayer) - break; - WNDPlayer = global::s2->RegisterWindow( - std::make_unique(EditorPlayerMenu, WINDOWQUIT, Pos, Extent(100, 80), "Players", WINDOW_GREEN1, - WINDOW_CLOSE | WINDOW_MINIMIZE | WINDOW_MOVE)); - MapObj = global::s2->getMapObj(); - tempRect = MapObj->getDisplayRect(); - PlayerHQx = MapObj->getPlayerHQx().data(); - PlayerHQy = MapObj->getPlayerHQy().data(); - - MapObj->setMode(EDITOR_MODE_FLAG); - MapObj->setModeContent(PlayerIdx); - - WNDPlayer->addButton(EditorPlayerMenu, PLAYER_REDUCE, Position(0, 0), Extent(20, 20), BUTTON_GREY, "-"); - PlayerNumberText = - WNDPlayer->addText(std::to_string(PlayerIdx + 1), Position(26, 4), FontSize::Large, FontColor::Orange); - WNDPlayer->addButton(EditorPlayerMenu, PLAYER_RAISE, Position(40, 0), Extent(20, 20), BUTTON_GREY, "+"); - WNDPlayer->addButton(EditorPlayerMenu, GOTO_PLAYER, Position(0, 20), Extent(60, 20), BUTTON_GREY, "Go to"); - break; - - case PLAYER_REDUCE: - if(PlayerIdx > 0) - { - PlayerIdx--; - MapObj->setModeContent(PlayerIdx); - WNDPlayer->delText(PlayerNumberText); - PlayerNumberText = WNDPlayer->addText(std::to_string(PlayerIdx + 1), Position(26, 4), FontSize::Large, - FontColor::Orange); - } - break; - - case PLAYER_RAISE: - if(PlayerIdx < MAXPLAYERS - 1) - { - PlayerIdx++; - MapObj->setModeContent(PlayerIdx); - WNDPlayer->delText(PlayerNumberText); - PlayerNumberText = WNDPlayer->addText(std::to_string(PlayerIdx + 1), Position(26, 4), FontSize::Large, - FontColor::Orange); - } - break; - - case GOTO_PLAYER: // test if player exists on map - if(PlayerHQx[PlayerIdx] != 0xFFFF && PlayerHQy[PlayerIdx] != 0xFFFF) - { - tempRect = MapObj->getDisplayRect(); - tempRect.setOrigin(Position(PlayerHQx[PlayerIdx], PlayerHQy[PlayerIdx]) - * Position(TR_W, TR_H) - - tempRect.getSize() / 2); - MapObj->setDisplayRect(tempRect); - } - break; - - case WINDOW_CLICKED_CALL: - if(MapObj) - { - MapObj->setMode(EDITOR_MODE_FLAG); - MapObj->setModeContent(PlayerIdx); - } - break; - - case WINDOWQUIT: - if(WNDPlayer) - { - Pos = WNDPlayer->getPos(); - WNDPlayer->setWaste(); - WNDPlayer = nullptr; - } - MapObj->setMode(EDITOR_MODE_HEIGHT_RAISE); - MapObj->setModeContent(0x00); - MapObj->setModeContent2(0x00); - MapObj = nullptr; - PlayerIdx = 0x01; - PlayerNumberText = nullptr; - PlayerHQx = nullptr; - PlayerHQy = nullptr; - break; - - case MAP_QUIT: - // we do the same like in case WINDOWQUIT, but we won't setMode(EDITOR_MODE_HEIGHT_RAISE), cause map is dead - if(WNDPlayer) - { - Pos = WNDPlayer->getPos(); - WNDPlayer->setWaste(); - WNDPlayer = nullptr; - } - MapObj = nullptr; - PlayerIdx = 0x01; - PlayerNumberText = nullptr; - PlayerHQx = nullptr; - PlayerHQy = nullptr; - break; - - default: break; - } -} - -void callback::EditorCursorMenu(int Param) -{ - static CWindow* WNDCursor = nullptr; - static CMap* MapObj = nullptr; - static int trianglePictureArrowUp = -1; - static int trianglePictureArrowDown = -1; - static int trianglePictureRandom = -1; - static CButton* CursorModeButton = nullptr; - static CButton* CursorRandomButton = nullptr; - static Position Pos{0, 0}; - - enum - { - WINDOWQUIT, - TRIANGLE, - CURSORMODE, - CURSORRANDOM - }; - - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - assert(WNDCursor && MapObj); - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDCursor) - break; - WNDCursor = global::s2->RegisterWindow( - std::make_unique(EditorCursorMenu, WINDOWQUIT, Pos, Extent(210, 130), "Cursor", WINDOW_GREEN1, - WINDOW_CLOSE | WINDOW_MINIMIZE | WINDOW_MOVE)); - MapObj = global::s2->getMapObj(); - - CursorModeButton = WNDCursor->addButton(EditorCursorMenu, CURSORMODE, Position(2, 2), Extent(96, 32), - BUTTON_GREY, "Hexagon"); - CursorRandomButton = WNDCursor->addButton(EditorCursorMenu, CURSORRANDOM, Position(2, 34), Extent(196, 32), - BUTTON_GREY, "Cursor-Activity: static"); - WNDCursor->addButton(EditorCursorMenu, TRIANGLE, Position(2, 66), Extent(32, 32), BUTTON_GREY, nullptr); - trianglePictureArrowUp = - WNDCursor->addStaticPicture(Position(8, 74), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP); - trianglePictureArrowDown = - WNDCursor->addStaticPicture(Position(17, 77), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN); - if(MapObj) - { - MapObj->setVertexFillRSU(true); - MapObj->setVertexFillUSD(true); - MapObj->setVertexFillRandom(false); - MapObj->setHexagonMode(true); - MapObj->setVertexActivityRandom(false); - } - break; - - case TRIANGLE: - if(trianglePictureArrowUp != -1 && trianglePictureArrowDown != -1) - { - // both arrows are shown, so set to random - // delete arrow up - WNDCursor->delStaticPicture(trianglePictureArrowUp); - trianglePictureArrowUp = -1; - // delete arrow down - WNDCursor->delStaticPicture(trianglePictureArrowDown); - trianglePictureArrowDown = -1; - // add random if necessary - if(trianglePictureRandom == -1) - trianglePictureRandom = WNDCursor->addStaticPicture( - Position(14, 76), ArchiveID::EDITIO, FONT14_SPACE + 31 * 7 + 5); // Interrogation point - MapObj->setVertexFillRSU(false); - MapObj->setVertexFillUSD(false); - MapObj->setVertexFillRandom(true); - } else if(trianglePictureArrowUp == -1 && trianglePictureRandom == -1) - { - // only arrow down is shown, so upgrade to both arrows - // add arrow up - trianglePictureArrowUp = - WNDCursor->addStaticPicture(Position(8, 74), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP); - // add arrow down if necessary - if(trianglePictureArrowDown == -1) - trianglePictureArrowDown = - WNDCursor->addStaticPicture(Position(17, 77), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN); - MapObj->setVertexFillRSU(true); - MapObj->setVertexFillUSD(true); - MapObj->setVertexFillRandom(false); - } else if(trianglePictureArrowDown == -1 && trianglePictureRandom == -1) - { - // only arrow up is shown, so delete arrow up and add arrow down - // delete arrow up if necessary - if(trianglePictureArrowUp != -1) - { - WNDCursor->delStaticPicture(trianglePictureArrowUp); - trianglePictureArrowUp = -1; - } - trianglePictureArrowDown = - WNDCursor->addStaticPicture(Position(17, 77), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN); - MapObj->setVertexFillRSU(false); - MapObj->setVertexFillUSD(true); - MapObj->setVertexFillRandom(false); - } else - { - // the interrogation point is shown, so set to arrow up - WNDCursor->delStaticPicture(trianglePictureRandom); - trianglePictureRandom = -1; - // add arrow up if necessary - if(trianglePictureArrowUp == -1) - trianglePictureArrowUp = - WNDCursor->addStaticPicture(Position(8, 74), ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP); - // delete arrow down if necessary - if(trianglePictureArrowDown != -1) - { - WNDCursor->delStaticPicture(trianglePictureArrowDown); - trianglePictureArrowDown = -1; - } - MapObj->setVertexFillRSU(true); - MapObj->setVertexFillUSD(false); - MapObj->setVertexFillRandom(false); - } - break; - - case CURSORMODE: - if(CursorModeButton) - { - WNDCursor->delButton(CursorModeButton); - CursorModeButton = nullptr; - } - if(MapObj->getHexagonMode()) - { - CursorModeButton = WNDCursor->addButton(EditorCursorMenu, CURSORMODE, Position(2, 2), Extent(96, 32), - BUTTON_GREY, "Square"); - MapObj->setHexagonMode(false); - } else - { - CursorModeButton = WNDCursor->addButton(EditorCursorMenu, CURSORMODE, Position(2, 2), Extent(96, 32), - BUTTON_GREY, "Hexagon"); - MapObj->setHexagonMode(true); - } - break; - case CURSORRANDOM: - if(CursorRandomButton) - { - WNDCursor->delButton(CursorRandomButton); - CursorRandomButton = nullptr; - } - if(MapObj->getVertexActivityRandom()) - { - CursorRandomButton = WNDCursor->addButton(EditorCursorMenu, CURSORRANDOM, Position(2, 34), - Extent(196, 32), BUTTON_GREY, "Cursor-Activity: static"); - MapObj->setVertexActivityRandom(false); - } else - { - CursorRandomButton = WNDCursor->addButton(EditorCursorMenu, CURSORRANDOM, Position(2, 34), - Extent(196, 32), BUTTON_GREY, "Cursor-Activity: random"); - MapObj->setVertexActivityRandom(true); - } - break; - - case WINDOW_CLICKED_CALL: break; - - case WINDOWQUIT: - case MAP_QUIT: - // we do the same like in case WINDOWQUIT - if(WNDCursor) - { - Pos = WNDCursor->getPos(); - WNDCursor->setWaste(); - WNDCursor = nullptr; - } - MapObj = nullptr; - trianglePictureArrowUp = -1; - trianglePictureArrowDown = -1; - trianglePictureRandom = -1; - CursorModeButton = nullptr; - CursorRandomButton = nullptr; - break; - - default: break; - } -} - -//"create world" menu -void callback::EditorCreateMenu(int Param) -{ - static CWindow* WNDCreate = nullptr; - static CMap* MapObj = nullptr; - static CFont* TextWidth = nullptr; - static int width = 32; - static CFont* TextHeight = nullptr; - static int height = 32; - static CButton* ButtonLandscape = nullptr; - static int LandscapeType = 0; // 0 = Greenland, 1 = Wasteland, 2 = Winterland - static int PicTextureIndex = -1; - static int PicTextureIndexGlobal = PICTURE_GREENLAND_TEXTURE_SNOW; - static int texture = TRIANGLE_TEXTURE_SNOW; - static int PicBorderTextureIndex = -1; - static int PicBorderTextureIndexGlobal = PICTURE_GREENLAND_TEXTURE_SNOW; - static CFont* TextBorder = nullptr; - static int border = 0; - static int border_texture = TRIANGLE_TEXTURE_SNOW; - static Position Pos(global::s2->GameResolution.x / 2 - 125, global::s2->GameResolution.y / 2 - 175); - - enum - { - REDUCE_WIDTH_128, - REDUCE_WIDTH_16, - REDUCE_WIDTH_2, - RAISE_WIDTH_2, - RAISE_WIDTH_16, - RAISE_WIDTH_128, - REDUCE_HEIGHT_128, - REDUCE_HEIGHT_16, - REDUCE_HEIGHT_2, - RAISE_HEIGHT_2, - RAISE_HEIGHT_16, - RAISE_HEIGHT_128, - CHANGE_LANDSCAPE, - TEXTURE_PREVIOUS, - TEXTURE_NEXT, - BORDER_TEXTURE_PREVIOUS, - BORDER_TEXTURE_NEXT, - REDUCE_BORDER, - RAISE_BORDER, - CREATE_WORLD, - WINDOWQUIT - }; - - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - { - assert(WNDCreate); - assert(MapObj); - } - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDCreate) - break; - WNDCreate = global::s2->RegisterWindow( - std::make_unique(EditorCreateMenu, WINDOWQUIT, Pos, Extent(250, 350), "Create world", - WINDOW_GREEN1, WINDOW_CLOSE | WINDOW_MOVE | WINDOW_MINIMIZE)); - MapObj = global::s2->getMapObj(); - - WNDCreate->addText("Width", Position(95, 4), FontSize::Small, FontColor::Yellow); - WNDCreate->addButton(EditorCreateMenu, REDUCE_WIDTH_128, Position(0, 15), Extent(35, 20), BUTTON_GREY, - "128<-"); - WNDCreate->addButton(EditorCreateMenu, REDUCE_WIDTH_16, Position(35, 15), Extent(35, 20), BUTTON_GREY, - "16<-"); - WNDCreate->addButton(EditorCreateMenu, REDUCE_WIDTH_2, Position(70, 15), Extent(25, 20), BUTTON_GREY, - "2<-"); - TextWidth = - WNDCreate->addText(std::to_string(width), Position(105, 17), FontSize::Large, FontColor::Yellow); - WNDCreate->addButton(EditorCreateMenu, RAISE_WIDTH_2, Position(143, 15), Extent(25, 20), BUTTON_GREY, - "->2"); - WNDCreate->addButton(EditorCreateMenu, RAISE_WIDTH_16, Position(168, 15), Extent(35, 20), BUTTON_GREY, - "->16"); - WNDCreate->addButton(EditorCreateMenu, RAISE_WIDTH_128, Position(203, 15), Extent(35, 20), BUTTON_GREY, - "->128"); - - WNDCreate->addText("Height", Position(100, 40), FontSize::Small, FontColor::Yellow); - WNDCreate->addButton(EditorCreateMenu, REDUCE_HEIGHT_128, Position(0, 49), Extent(35, 20), BUTTON_GREY, - "128<-"); - WNDCreate->addButton(EditorCreateMenu, REDUCE_HEIGHT_16, Position(35, 49), Extent(35, 20), BUTTON_GREY, - "16<-"); - WNDCreate->addButton(EditorCreateMenu, REDUCE_HEIGHT_2, Position(70, 49), Extent(25, 20), BUTTON_GREY, - "2<-"); - TextHeight = - WNDCreate->addText(std::to_string(height), Position(105, 51), FontSize::Large, FontColor::Yellow); - WNDCreate->addButton(EditorCreateMenu, RAISE_HEIGHT_2, Position(143, 49), Extent(25, 20), BUTTON_GREY, - "->2"); - WNDCreate->addButton(EditorCreateMenu, RAISE_HEIGHT_16, Position(168, 49), Extent(35, 20), BUTTON_GREY, - "->16"); - WNDCreate->addButton(EditorCreateMenu, RAISE_HEIGHT_128, Position(203, 49), Extent(35, 20), BUTTON_GREY, - "->128"); - - WNDCreate->addText("Landscape", Position(85, 80), FontSize::Small, FontColor::Yellow); - ButtonLandscape = WNDCreate->addButton( - EditorCreateMenu, CHANGE_LANDSCAPE, Position(64, 93), Extent(110, 20), BUTTON_GREY, - (LandscapeType == 0 ? "Greenland" : (LandscapeType == 1 ? "Wasteland" : "Winterworld"))); - - WNDCreate->addText("Main area", Position(82, 120), FontSize::Small, FontColor::Yellow); - WNDCreate->addButton(EditorCreateMenu, TEXTURE_PREVIOUS, Position(45, 139), Extent(35, 20), BUTTON_GREY, - "-"); - PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), ArchiveID::EDITIO, PicTextureIndexGlobal); - WNDCreate->addButton(EditorCreateMenu, TEXTURE_NEXT, Position(158, 139), Extent(35, 20), BUTTON_GREY, "+"); - - WNDCreate->addText("Border size", Position(103, 175), FontSize::Small, FontColor::Yellow); - WNDCreate->addButton(EditorCreateMenu, REDUCE_BORDER, Position(45, 186), Extent(35, 20), BUTTON_GREY, "-"); - TextBorder = - WNDCreate->addText(std::to_string(border), Position(112, 188), FontSize::Large, FontColor::Yellow); - WNDCreate->addButton(EditorCreateMenu, RAISE_BORDER, Position(158, 186), Extent(35, 20), BUTTON_GREY, "+"); - - WNDCreate->addText("Border area", Position(65, 215), FontSize::Small, FontColor::Yellow); - WNDCreate->addButton(EditorCreateMenu, BORDER_TEXTURE_PREVIOUS, Position(45, 234), Extent(35, 20), - BUTTON_GREY, "-"); - PicBorderTextureIndex = - WNDCreate->addStaticPicture(Position(102, 228), ArchiveID::EDITIO, PicBorderTextureIndexGlobal); - WNDCreate->addButton(EditorCreateMenu, BORDER_TEXTURE_NEXT, Position(158, 234), Extent(35, 20), BUTTON_GREY, - "+"); - - WNDCreate->addButton(EditorCreateMenu, CREATE_WORLD, Position(44, 275), Extent(150, 40), BUTTON_GREY, - "Create world"); - break; - - case CALL_FROM_GAMELOOP: break; - - case REDUCE_WIDTH_128: - if(width - 128 >= 32) - width -= 128; - else - width = 32; - WNDCreate->delText(TextWidth); - TextWidth = - WNDCreate->addText(std::to_string(width), Position(105, 17), FontSize::Large, FontColor::Yellow); - break; - case REDUCE_WIDTH_16: - if(width - 16 >= 32) - width -= 16; - else - width = 32; - WNDCreate->delText(TextWidth); - TextWidth = - WNDCreate->addText(std::to_string(width), Position(105, 17), FontSize::Large, FontColor::Yellow); - break; - case REDUCE_WIDTH_2: - if(width - 2 >= 32) - width -= 2; - else - width = 32; - WNDCreate->delText(TextWidth); - TextWidth = - WNDCreate->addText(std::to_string(width), Position(105, 17), FontSize::Large, FontColor::Yellow); - break; - case RAISE_WIDTH_2: - if(width + 2 <= MAXMAPWIDTH) - width += 2; - else - width = MAXMAPWIDTH; - WNDCreate->delText(TextWidth); - TextWidth = - WNDCreate->addText(std::to_string(width), Position(105, 17), FontSize::Large, FontColor::Yellow); - break; - case RAISE_WIDTH_16: - if(width + 16 <= MAXMAPWIDTH) - width += 16; - else - width = MAXMAPWIDTH; - WNDCreate->delText(TextWidth); - TextWidth = - WNDCreate->addText(std::to_string(width), Position(105, 17), FontSize::Large, FontColor::Yellow); - break; - case RAISE_WIDTH_128: - if(width + 128 <= MAXMAPWIDTH) - width += 128; - else - width = MAXMAPWIDTH; - WNDCreate->delText(TextWidth); - TextWidth = - WNDCreate->addText(std::to_string(width), Position(105, 17), FontSize::Large, FontColor::Yellow); - break; - case REDUCE_HEIGHT_128: - if(height - 128 >= 32) - height -= 128; - else - height = 32; - WNDCreate->delText(TextHeight); - TextHeight = - WNDCreate->addText(std::to_string(height), Position(105, 51), FontSize::Large, FontColor::Yellow); - break; - case REDUCE_HEIGHT_16: - if(height - 16 >= 32) - height -= 16; - else - height = 32; - WNDCreate->delText(TextHeight); - TextHeight = - WNDCreate->addText(std::to_string(height), Position(105, 51), FontSize::Large, FontColor::Yellow); - break; - case REDUCE_HEIGHT_2: - if(height - 2 >= 32) - height -= 2; - else - height = 32; - WNDCreate->delText(TextHeight); - TextHeight = - WNDCreate->addText(std::to_string(height), Position(105, 51), FontSize::Large, FontColor::Yellow); - break; - case RAISE_HEIGHT_2: - if(height + 2 <= MAXMAPHEIGHT) - height += 2; - else - height = MAXMAPHEIGHT; - WNDCreate->delText(TextHeight); - TextHeight = - WNDCreate->addText(std::to_string(height), Position(105, 51), FontSize::Large, FontColor::Yellow); - break; - case RAISE_HEIGHT_16: - if(height + 16 <= MAXMAPHEIGHT) - height += 16; - else - height = MAXMAPHEIGHT; - WNDCreate->delText(TextHeight); - TextHeight = - WNDCreate->addText(std::to_string(height), Position(105, 51), FontSize::Large, FontColor::Yellow); - break; - case RAISE_HEIGHT_128: - if(height + 128 <= MAXMAPHEIGHT) - height += 128; - else - height = MAXMAPHEIGHT; - WNDCreate->delText(TextHeight); - TextHeight = - WNDCreate->addText(std::to_string(height), Position(105, 51), FontSize::Large, FontColor::Yellow); - break; - - case CHANGE_LANDSCAPE: - LandscapeType++; - if(LandscapeType > 2) - LandscapeType = 0; - WNDCreate->delButton(ButtonLandscape); - ButtonLandscape = WNDCreate->addButton( - EditorCreateMenu, CHANGE_LANDSCAPE, Position(64, 93), Extent(110, 20), BUTTON_GREY, - (LandscapeType == 0 ? "Greenland" : (LandscapeType == 1 ? "Wasteland" : "Winterworld"))); - switch(LandscapeType) - { - case 0: - PicTextureIndexGlobal = PICTURE_GREENLAND_TEXTURE_SNOW; - PicBorderTextureIndexGlobal = PICTURE_GREENLAND_TEXTURE_SNOW; - break; - case 1: - PicTextureIndexGlobal = PICTURE_WASTELAND_TEXTURE_SNOW; - PicBorderTextureIndexGlobal = PICTURE_WASTELAND_TEXTURE_SNOW; - break; - case 2: - PicTextureIndexGlobal = PICTURE_WINTERLAND_TEXTURE_SNOW; - PicBorderTextureIndexGlobal = PICTURE_WINTERLAND_TEXTURE_SNOW; - break; - default: break; - } - WNDCreate->delStaticPicture(PicTextureIndex); - WNDCreate->delStaticPicture(PicBorderTextureIndex); - PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), ArchiveID::EDITIO, PicTextureIndexGlobal); - PicBorderTextureIndex = - WNDCreate->addStaticPicture(Position(102, 228), ArchiveID::EDITIO, PicBorderTextureIndexGlobal); - break; - - case TEXTURE_PREVIOUS: - PicTextureIndexGlobal--; - switch(LandscapeType) - { - case 0: - if(PicTextureIndexGlobal < PICTURE_GREENLAND_TEXTURE_SNOW) - PicTextureIndexGlobal = PICTURE_GREENLAND_TEXTURE_SNOW; - break; - case 1: - if(PicTextureIndexGlobal < PICTURE_WASTELAND_TEXTURE_SNOW) - PicTextureIndexGlobal = PICTURE_WASTELAND_TEXTURE_SNOW; - break; - case 2: - if(PicTextureIndexGlobal < PICTURE_WINTERLAND_TEXTURE_SNOW) - PicTextureIndexGlobal = PICTURE_WINTERLAND_TEXTURE_SNOW; - break; - default: break; - } - if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_SNOW - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_SNOW - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_SNOW) - { - texture = TRIANGLE_TEXTURE_SNOW; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE) - { - texture = TRIANGLE_TEXTURE_STEPPE; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_SWAMP - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_SWAMP - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_SWAMP) - { - texture = TRIANGLE_TEXTURE_SWAMP; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_FLOWER - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_FLOWER - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_FLOWER) - { - texture = TRIANGLE_TEXTURE_FLOWER; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING1 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING1 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING1) - { - texture = TRIANGLE_TEXTURE_MINING1; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING2 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING2 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING2) - { - texture = TRIANGLE_TEXTURE_MINING2; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING3 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING3 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING3) - { - texture = TRIANGLE_TEXTURE_MINING3; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING4 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING4 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING4) - { - texture = TRIANGLE_TEXTURE_MINING4; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW1 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW1 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW1) - { - texture = TRIANGLE_TEXTURE_STEPPE_MEADOW1; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW1 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW1 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW1) - { - texture = TRIANGLE_TEXTURE_MEADOW1; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW2 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW2 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW2) - { - texture = TRIANGLE_TEXTURE_MEADOW2; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW3 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW3 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW3) - { - texture = TRIANGLE_TEXTURE_MEADOW3; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW2 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW2 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW2) - { - texture = TRIANGLE_TEXTURE_STEPPE_MEADOW2; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING_MEADOW - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING_MEADOW - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING_MEADOW) - { - texture = TRIANGLE_TEXTURE_MINING_MEADOW; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_WATER - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_WATER - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_WATER) - { - texture = TRIANGLE_TEXTURE_WATER; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_LAVA - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_LAVA - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_LAVA) - { - texture = TRIANGLE_TEXTURE_LAVA; - } - WNDCreate->delStaticPicture(PicTextureIndex); - PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), ArchiveID::EDITIO, PicTextureIndexGlobal); - break; - case TEXTURE_NEXT: - PicTextureIndexGlobal++; - switch(LandscapeType) - { - case 0: - if(PicTextureIndexGlobal > PICTURE_GREENLAND_TEXTURE_LAVA) - PicTextureIndexGlobal = PICTURE_GREENLAND_TEXTURE_LAVA; - break; - case 1: - if(PicTextureIndexGlobal > PICTURE_WASTELAND_TEXTURE_LAVA) - PicTextureIndexGlobal = PICTURE_WASTELAND_TEXTURE_LAVA; - break; - case 2: - if(PicTextureIndexGlobal > PICTURE_WINTERLAND_TEXTURE_LAVA) - PicTextureIndexGlobal = PICTURE_WINTERLAND_TEXTURE_LAVA; - break; - default: break; - } - if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_SNOW - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_SNOW - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_SNOW) - { - texture = TRIANGLE_TEXTURE_SNOW; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE) - { - texture = TRIANGLE_TEXTURE_STEPPE; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_SWAMP - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_SWAMP - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_SWAMP) - { - texture = TRIANGLE_TEXTURE_SWAMP; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_FLOWER - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_FLOWER - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_FLOWER) - { - texture = TRIANGLE_TEXTURE_FLOWER; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING1 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING1 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING1) - { - texture = TRIANGLE_TEXTURE_MINING1; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING2 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING2 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING2) - { - texture = TRIANGLE_TEXTURE_MINING2; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING3 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING3 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING3) - { - texture = TRIANGLE_TEXTURE_MINING3; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING4 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING4 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING4) - { - texture = TRIANGLE_TEXTURE_MINING4; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW1 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW1 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW1) - { - texture = TRIANGLE_TEXTURE_STEPPE_MEADOW1; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW1 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW1 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW1) - { - texture = TRIANGLE_TEXTURE_MEADOW1; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW2 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW2 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW2) - { - texture = TRIANGLE_TEXTURE_MEADOW2; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW3 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW3 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW3) - { - texture = TRIANGLE_TEXTURE_MEADOW3; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW2 - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW2 - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW2) - { - texture = TRIANGLE_TEXTURE_STEPPE_MEADOW2; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING_MEADOW - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING_MEADOW - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING_MEADOW) - { - texture = TRIANGLE_TEXTURE_MINING_MEADOW; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_WATER - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_WATER - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_WATER) - { - texture = TRIANGLE_TEXTURE_WATER; - } else if(PicTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_LAVA - || PicTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_LAVA - || PicTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_LAVA) - { - texture = TRIANGLE_TEXTURE_LAVA; - } - WNDCreate->delStaticPicture(PicTextureIndex); - PicTextureIndex = WNDCreate->addStaticPicture(Position(102, 133), ArchiveID::EDITIO, PicTextureIndexGlobal); - break; - - case REDUCE_BORDER: - border = std::max(0, border - 1); - WNDCreate->delText(TextBorder); - TextBorder = - WNDCreate->addText(std::to_string(border), Position(112, 188), FontSize::Large, FontColor::Yellow); - break; - case RAISE_BORDER: - border = std::min(12, border + 1); - WNDCreate->delText(TextBorder); - TextBorder = - WNDCreate->addText(std::to_string(border), Position(112, 188), FontSize::Large, FontColor::Yellow); - break; - - case BORDER_TEXTURE_PREVIOUS: - PicBorderTextureIndexGlobal--; - switch(LandscapeType) - { - case 0: - if(PicBorderTextureIndexGlobal < PICTURE_GREENLAND_TEXTURE_SNOW) - PicBorderTextureIndexGlobal = PICTURE_GREENLAND_TEXTURE_SNOW; - break; - case 1: - if(PicBorderTextureIndexGlobal < PICTURE_WASTELAND_TEXTURE_SNOW) - PicBorderTextureIndexGlobal = PICTURE_WASTELAND_TEXTURE_SNOW; - break; - case 2: - if(PicBorderTextureIndexGlobal < PICTURE_WINTERLAND_TEXTURE_SNOW) - PicBorderTextureIndexGlobal = PICTURE_WINTERLAND_TEXTURE_SNOW; - break; - default: break; - } - if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_SNOW - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_SNOW - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_SNOW) - { - border_texture = TRIANGLE_TEXTURE_SNOW; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE) - { - border_texture = TRIANGLE_TEXTURE_STEPPE; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_SWAMP - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_SWAMP - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_SWAMP) - { - border_texture = TRIANGLE_TEXTURE_SWAMP; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_FLOWER - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_FLOWER - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_FLOWER) - { - border_texture = TRIANGLE_TEXTURE_FLOWER; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING1 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING1 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING1) - { - border_texture = TRIANGLE_TEXTURE_MINING1; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING2 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING2 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING2) - { - border_texture = TRIANGLE_TEXTURE_MINING2; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING3 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING3 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING3) - { - border_texture = TRIANGLE_TEXTURE_MINING3; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING4 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING4 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING4) - { - border_texture = TRIANGLE_TEXTURE_MINING4; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW1 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW1 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW1) - { - border_texture = TRIANGLE_TEXTURE_STEPPE_MEADOW1; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW1 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW1 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW1) - { - border_texture = TRIANGLE_TEXTURE_MEADOW1; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW2 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW2 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW2) - { - border_texture = TRIANGLE_TEXTURE_MEADOW2; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW3 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW3 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW3) - { - border_texture = TRIANGLE_TEXTURE_MEADOW3; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW2 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW2 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW2) - { - border_texture = TRIANGLE_TEXTURE_STEPPE_MEADOW2; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING_MEADOW - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING_MEADOW - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING_MEADOW) - { - border_texture = TRIANGLE_TEXTURE_MINING_MEADOW; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_WATER - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_WATER - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_WATER) - { - border_texture = TRIANGLE_TEXTURE_WATER; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_LAVA - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_LAVA - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_LAVA) - { - border_texture = TRIANGLE_TEXTURE_LAVA; - } - WNDCreate->delStaticPicture(PicBorderTextureIndex); - PicBorderTextureIndex = - WNDCreate->addStaticPicture(Position(102, 228), ArchiveID::EDITIO, PicBorderTextureIndexGlobal); - break; - case BORDER_TEXTURE_NEXT: - PicBorderTextureIndexGlobal++; - switch(LandscapeType) - { - case 0: - if(PicBorderTextureIndexGlobal > PICTURE_GREENLAND_TEXTURE_LAVA) - PicBorderTextureIndexGlobal = PICTURE_GREENLAND_TEXTURE_LAVA; - break; - case 1: - if(PicBorderTextureIndexGlobal > PICTURE_WASTELAND_TEXTURE_LAVA) - PicBorderTextureIndexGlobal = PICTURE_WASTELAND_TEXTURE_LAVA; - break; - case 2: - if(PicBorderTextureIndexGlobal > PICTURE_WINTERLAND_TEXTURE_LAVA) - PicBorderTextureIndexGlobal = PICTURE_WINTERLAND_TEXTURE_LAVA; - break; - default: break; - } - if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_SNOW - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_SNOW - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_SNOW) - { - border_texture = TRIANGLE_TEXTURE_SNOW; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE) - { - border_texture = TRIANGLE_TEXTURE_STEPPE; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_SWAMP - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_SWAMP - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_SWAMP) - { - border_texture = TRIANGLE_TEXTURE_SWAMP; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_FLOWER - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_FLOWER - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_FLOWER) - { - border_texture = TRIANGLE_TEXTURE_FLOWER; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING1 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING1 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING1) - { - border_texture = TRIANGLE_TEXTURE_MINING1; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING2 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING2 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING2) - { - border_texture = TRIANGLE_TEXTURE_MINING2; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING3 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING3 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING3) - { - border_texture = TRIANGLE_TEXTURE_MINING3; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING4 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING4 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING4) - { - border_texture = TRIANGLE_TEXTURE_MINING4; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW1 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW1 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW1) - { - border_texture = TRIANGLE_TEXTURE_STEPPE_MEADOW1; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW1 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW1 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW1) - { - border_texture = TRIANGLE_TEXTURE_MEADOW1; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW2 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW2 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW2) - { - border_texture = TRIANGLE_TEXTURE_MEADOW2; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MEADOW3 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MEADOW3 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MEADOW3) - { - border_texture = TRIANGLE_TEXTURE_MEADOW3; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW2 - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_STEPPE_MEADOW2 - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_STEPPE_MEADOW2) - { - border_texture = TRIANGLE_TEXTURE_STEPPE_MEADOW2; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_MINING_MEADOW - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_MINING_MEADOW - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_MINING_MEADOW) - { - border_texture = TRIANGLE_TEXTURE_MINING_MEADOW; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_WATER - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_WATER - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_WATER) - { - border_texture = TRIANGLE_TEXTURE_WATER; - } else if(PicBorderTextureIndexGlobal == PICTURE_GREENLAND_TEXTURE_LAVA - || PicBorderTextureIndexGlobal == PICTURE_WASTELAND_TEXTURE_LAVA - || PicBorderTextureIndexGlobal == PICTURE_WINTERLAND_TEXTURE_LAVA) - { - border_texture = TRIANGLE_TEXTURE_LAVA; - } - WNDCreate->delStaticPicture(PicBorderTextureIndex); - PicBorderTextureIndex = - WNDCreate->addStaticPicture(Position(102, 228), ArchiveID::EDITIO, PicBorderTextureIndexGlobal); - break; - - case CREATE_WORLD: - PleaseWait(INITIALIZING_CALL); - - // we have to close the windows and initialize them again to prevent failures - EditorCursorMenu(MAP_QUIT); - EditorTextureMenu(MAP_QUIT); - EditorTreeMenu(MAP_QUIT); - EditorLandscapeMenu(MAP_QUIT); - MinimapMenu(MAP_QUIT); - EditorResourceMenu(MAP_QUIT); - EditorAnimalMenu(MAP_QUIT); - EditorPlayerMenu(MAP_QUIT); - - MapObj->destructMap(); - MapObj->constructMap("", width, height, MapType(LandscapeType), TriangleTerrainType(texture), border, - border_texture); - - // we need to check which of these windows was active before - /* - EditorCursorMenu(INITIALIZING_CALL); - EditorTextureMenu(INITIALIZING_CALL); - EditorTreeMenu(INITIALIZING_CALL); - EditorLandscapeMenu(INITIALIZING_CALL); - MinimapMenu(INITIALIZING_CALL); - EditorResourceMenu(INITIALIZING_CALL); - EditorAnimalMenu(INITIALIZING_CALL); - EditorPlayerMenu(INITIALIZING_CALL); - */ - - PleaseWait(WINDOW_QUIT_MESSAGE); - break; - - case MAP_QUIT: - case WINDOWQUIT: - if(WNDCreate) - { - Pos = WNDCreate->getPos(); - WNDCreate->setWaste(); - WNDCreate = nullptr; - } - MapObj = nullptr; - TextWidth = nullptr; - width = 32; - TextHeight = nullptr; - height = 32; - ButtonLandscape = nullptr; - LandscapeType = 0; - PicTextureIndex = -1; - PicTextureIndexGlobal = PICTURE_GREENLAND_TEXTURE_SNOW; - texture = TRIANGLE_TEXTURE_SNOW; - PicBorderTextureIndex = -1; - PicBorderTextureIndexGlobal = PICTURE_GREENLAND_TEXTURE_SNOW; - TextBorder = nullptr; - border = 0; - border_texture = TRIANGLE_TEXTURE_SNOW; - break; - - default: break; - } -} - -void callback::MinimapMenu(int Param) -{ - static CWindow* WNDMinimap = nullptr; - static CMap* MapObj = nullptr; - static int scaleNum = 1; - // only in case INITIALIZING_CALL needed to create the window - int width; - int height; - - enum - { - WINDOWQUIT - }; - - if(Param != INITIALIZING_CALL && Param != MAP_QUIT) - assert(WNDMinimap && MapObj); - - switch(Param) - { - case INITIALIZING_CALL: - if(WNDMinimap) - break; - { - // this variables are needed to reduce the size of minimap-windows of big maps - MapObj = global::s2->getMapObj(); - bobMAP* map = MapObj->getMap(); - scaleNum = std::max(std::max(map->width / 256, map->height / 256), 1); - - width = map->width / scaleNum; - height = map->height / scaleNum; - //--> 12px is width of left and right window frame and 30px is height of the upper and lower window - // frame - if((static_cast(global::s2->getRes().x) - 12 < width) - || (static_cast(global::s2->getRes().y) - 30 < height)) - break; - WNDMinimap = global::s2->RegisterWindow(std::make_unique( - MinimapMenu, WINDOWQUIT, WindowPos::Center, Extent(width + 12, height + 30), "Overview", - WINDOW_NOTHING, WINDOW_CLOSE | WINDOW_MOVE)); - global::s2->RegisterCallback(MinimapMenu); - } - break; - - case WINDOW_CLICKED_CALL: - if(MapObj) - { - Position mouse; - if(SDL_GetMouseState(&mouse.x, &mouse.y) & SDL_BUTTON(1)) - { - if(IsPointInRect( - mouse, Rect(WNDMinimap->getPos() + Position(6, 20), WNDMinimap->getSize() - Extent(12, 30)))) - { - DisplayRectangle displayRect = MapObj->getDisplayRect(); - displayRect.setOrigin( - (mouse - WNDMinimap->getRect().getOrigin() - Position(6, 20) - - Texture::getTexture(ArchiveID::MAP00, MAPPIC_ARROWCROSS_ORANGE).anchor()) - * Position(TR_W, TR_H) * scaleNum); - MapObj->setDisplayRect(displayRect); - } - } - } - break; - - case WINDOWQUIT: - case MAP_QUIT: - if(WNDMinimap) - { - WNDMinimap->setWaste(); - WNDMinimap = nullptr; - } - MapObj = nullptr; - global::s2->UnregisterCallback(MinimapMenu); - break; - - default: break; - } -} - -#ifdef _ADMINMODE -// the debugger is an object and a friend class of all other classes -// debugger-function only will construct a new debugger and if debugger-function gets a window-quit-message -// then the debugger-function will destruct the object -void callback::debugger(int Param) -{ - static CDebug* Debugger = nullptr; - - switch(Param) - { - case INITIALIZING_CALL: - if(Debugger) - break; - Debugger = new CDebug(debugger, DEBUGGER_QUIT); - break; - - case DEBUGGER_QUIT: - delete Debugger; - Debugger = nullptr; - break; - - default: - if(Debugger) - Debugger->sendParam(Param); - break; - } -} - -// this is a submenu for testing (removed) -void callback::submenu1(int Param) -{ -} -#endif diff --git a/callbacks.h b/callbacks.h deleted file mode 100644 index 3413f93..0000000 --- a/callbacks.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -// NOTE: negative callbackParams are reserved: -1 = callback is called first time, -2 = used by gameloop for registered -// callbacks (callbacks that will additionally execute WITHIN the gameloop) - -// NOTE: don't forget that if the map quits (Param: MAP_QUIT), there are many windows that have to be closed. -// This happens for example if a new Map will be loaded or user goes to main menu. So if you add a new window, don't -// forget to add it to this "close lists" if it's necessary (also in the file CMap.cpp, function setMouseData(Button)). - -#pragma once - -namespace callback { -// PleaseWait creates a small window (not moveable, not resizeable, not minimizable, not closeable) with the String -// "Please wait..." -void PleaseWait(int Param); -void ShowStatus(int Param); - -void MinimapMenu(int Param); -void EditorHelpMenu(int Param); -void EditorMainMenu(int Param); -void EditorLoadMenu(int Param); -void EditorSaveMenu(int Param); -void EditorQuitMenu(int Param); -void EditorTextureMenu(int Param); -void EditorTreeMenu(int Param); -void EditorResourceMenu(int Param); -void EditorLandscapeMenu(int Param); -void EditorAnimalMenu(int Param); -void EditorPlayerMenu(int Param); -void EditorCreateMenu(int Param); -void EditorCursorMenu(int Param); - -#ifdef _ADMINMODE -void debugger(int Param); - -#endif -} // namespace callback From 79a19df1b2d57a346888e26c6487c3bd2d51e350 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 14:56:05 +0200 Subject: [PATCH 10/16] tools --- CGame.cpp | 1 + EditorWorldLoader.cpp | 36 ++++++++++++++++++- EditorWorldLoader.h | 10 ++++++ GameWorldEditor.cpp | 58 +++++++++++++++++++++++++++++++ dskEditorInterface.cpp | 70 +++++++++++++++++++++++++++++++++++-- dskEditorInterface.h | 3 ++ iwEditorTexture.cpp | 78 ++++++++++++++++++++++++++++-------------- iwEditorTexture.h | 10 +++++- iwEditorTree.cpp | 52 +++++++++++++++++----------- iwEditorTree.h | 10 +++++- 10 files changed, 278 insertions(+), 50 deletions(-) diff --git a/CGame.cpp b/CGame.cpp index adfc87f..866191b 100644 --- a/CGame.cpp +++ b/CGame.cpp @@ -6,6 +6,7 @@ #include "CGame.h" #include "CMap.h" #include "RttrConfig.h" +#include "defines.h" #include "files.h" #include "globals.h" #include "s25util/file_handle.h" diff --git a/EditorWorldLoader.cpp b/EditorWorldLoader.cpp index b015ac5..123154f 100644 --- a/EditorWorldLoader.cpp +++ b/EditorWorldLoader.cpp @@ -1,12 +1,28 @@ #include "EditorWorldLoader.h" #include "Loader.h" +#include "globals.h" #include "libsiedler2/Archiv.h" +#include "libsiedler2/ArchivItem.h" #include "libsiedler2/ArchivItem_Bitmap.h" #include "libsiedler2/libsiedler2.h" #include "ogl/glArchivItem_Bitmap.h" #include "ogl/glAllocator.h" -#include "resources/ResourceId.h" #include +#include + +/// Maps "clean" bitmap index (as used by MAPPIC_TREE_*) to actual archive index. +/// Built once after MAP00 is loaded. +static std::vector s_mapCleanIdxToArchive; + +/// Given a "clean" bitmap index (where only bitmaps are counted), return the +/// corresponding archive index (where nulls/shadows are skipped). +/// Returns -1 if not found. +int editorMapCleanToArchiveIdx(int cleanIdx) +{ + if(cleanIdx >= 0 && static_cast(cleanIdx) < s_mapCleanIdxToArchive.size()) + return static_cast(s_mapCleanIdxToArchive[cleanIdx]); + return -1; +} void loadTexturesForEditorWorld(const std::string& gameDataPath) { @@ -22,4 +38,22 @@ void loadTexturesForEditorWorld(const std::string& gameDataPath) if(boost::filesystem::exists(path)) LOADER.Load(path, nullptr); } + + // Load MAP00.LST into the Loader (key "map00") + const auto map00Path = boost::filesystem::path(gameDataPath) / "DATA/MAP00.LST"; + if(!boost::filesystem::exists(map00Path)) + return; + LOADER.Load(map00Path, global::currentPalette); + + // Build the clean-index → archive-index lookup + auto& arch = LOADER.GetArchive("map00"); + for(unsigned i = 0; i < arch.size(); i++) + { + auto* item = arch.get(i); + if(!item) continue; + auto bt = item->getBobType(); + if(bt == libsiedler2::BobType::Bitmap || bt == libsiedler2::BobType::BitmapRLE + || bt == libsiedler2::BobType::Raw || bt == libsiedler2::BobType::BitmapPlayer) + s_mapCleanIdxToArchive.push_back(i); + } } diff --git a/EditorWorldLoader.h b/EditorWorldLoader.h index 19b78e6..f02671a 100644 --- a/EditorWorldLoader.h +++ b/EditorWorldLoader.h @@ -1,3 +1,13 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + #pragma once #include + void loadTexturesForEditorWorld(const std::string& gameDataPath); + +/// Given a clean bitmap index (only bitmaps counted, as expected by MAPPIC_TREE_*), +/// return the actual archive index in the LOADER's MAP00 archive. +/// Returns -1 if not found. +int editorMapCleanToArchiveIdx(int cleanIdx); diff --git a/GameWorldEditor.cpp b/GameWorldEditor.cpp index 6730d5b..b98164c 100644 --- a/GameWorldEditor.cpp +++ b/GameWorldEditor.cpp @@ -3,10 +3,19 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "GameWorldEditor.h" +#include "EditorWorldLoader.h" +#include "Loader.h" +#include "defines.h" #include "world/GameWorldViewer.h" #include "world/GameWorld.h" +#include "TerrainRenderer.h" #include "gameData/MapConsts.h" +#include "nodeObjs/noBase.h" +#include "nodeObjs/noTree.h" +#include "libsiedler2/Archiv.h" +#include "ogl/glArchivItem_Bitmap.h" #include +#include void GameWorldEditor::MoveBy(const DrawPoint& delta) { @@ -46,6 +55,8 @@ void GameWorldEditor::Draw(const Extent& screenSize) Position firstPt(firstX, firstY); Position lastPt(lastX, lastY); + const auto mapSize = world_.GetSize(); + glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); @@ -57,8 +68,55 @@ void GameWorldEditor::Draw(const Extent& screenSize) // Translate modelview to scroll position — same as GameWorldView glTranslatef(static_cast(-offset_.x), static_cast(-offset_.y), 0.0f); + // Draw terrain viewer_.GetTerrainRenderer().Draw(firstPt, lastPt, viewer_, nullptr); + // Draw objects (trees, animals, buildings, etc.) on top of terrain + // Same visible range iteration as TerrainRenderer + const auto& tr = viewer_.GetTerrainRenderer(); + for(int y = firstY; y <= lastY; y++) + { + for(int x = firstX; x <= lastX; x++) + { + Position rawPt(x, y); + // Convert to map point with wrapping, get pixel offset for wrap + Position wrapOffset; + MapPoint pt = tr.ConvertCoords(rawPt, &wrapOffset); + if(pt.x >= mapSize.x || pt.y >= mapSize.y) + continue; + + noBase* obj = world_.GetNO(pt); + if(!obj) + continue; + + // World-space pixel position of this node + Position nodePos = world_.GetNodePos(pt); + // Apply wrap offset so wrapped copies draw at the correct screen position + nodePos += wrapOffset; + + // Draw objects using LOADER's MAP00 archive with clean-index lookup + if(auto* tree = dynamic_cast(obj)) + { + static Uint32 lastTick = 0; + static unsigned frame = 0; + Uint32 now = SDL_GetTicks(); + if(now - lastTick > 80) { frame = (frame + 1) % 8; lastTick = now; } + int cleanIdx = MAPPIC_TREE_PINE + tree->getTreeType() * 15 + frame; + int archIdx = editorMapCleanToArchiveIdx(cleanIdx); + if(archIdx >= 0) + { + auto& arch = LOADER.GetArchive("map00"); + auto* bmp = dynamic_cast(arch.get(static_cast(archIdx))); + if(bmp) + bmp->DrawFull(DrawPoint(nodePos.x, nodePos.y)); + } + } else + { + obj->Draw(DrawPoint(nodePos.x, nodePos.y)); + } + } + } + glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); diff --git a/dskEditorInterface.cpp b/dskEditorInterface.cpp index ba73694..a95aef5 100644 --- a/dskEditorInterface.cpp +++ b/dskEditorInterface.cpp @@ -24,7 +24,12 @@ #include "defines.h" #include "world/MapGeometry.h" #include "world/MapBase.h" +#include "world/World.h" +#include "TerrainRenderer.h" #include "ogl/glArchivItem_Bitmap.h" +#include "gameData/WorldDescription.h" +#include "gameData/TerrainDesc.h" +#include "nodeObjs/noTree.h" #include dskEditorInterface::dskEditorInterface(std::unique_ptr world) @@ -389,6 +394,56 @@ void dskEditorInterface::applyTool() } break; } + case EditorToolMode::Texture: + { + // Map legacy s2Id (TRIANGLE_TEXTURE_* value) to DescIdx + auto terrainByS2Id = [&](int s2Id) -> DescIdx { + for(DescIdx i(0); i.value < global::worldDesc.terrain.size(); i.value++) + if(global::worldDesc.terrain.get(i).s2Id == s2Id) + return i; + return DescIdx(); + }; + auto getTerrainOrMix = [&](int s2Id) -> DescIdx { + // MEADOW_MIXED is a sentinel: pick randomly from MEADOW1/2/3 + if(s2Id == TRIANGLE_TEXTURE_MEADOW_MIXED) + { + int ids[] = {TRIANGLE_TEXTURE_MEADOW1, TRIANGLE_TEXTURE_MEADOW2, TRIANGLE_TEXTURE_MEADOW3}; + return terrainByS2Id(ids[rand() % 3]); + } + return terrainByS2Id(s2Id); + }; + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + auto& node = world.GetNodeWriteable(cv.pt); + auto terrain = getTerrainOrMix(modeContent_); + if(!terrain) continue; + node.t1 = terrain; + node.t2 = terrain; + } + pendingTerrainRefresh_ = true; + break; + } + case EditorToolMode::Tree: + { + auto& w = world; + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + // Skip if there's already an object + if(w.GetNO(cv.pt)) + continue; + int treeType = modeContent2_; + if(treeType == -1) // mixed wood + treeType = rand() % 3; // pine, birch, oak + else if(treeType == -2) // mixed palm + treeType = 3 + rand() % 5; // palm1, palm2, pineapple, cypress, cherry + else if(treeType < 0 || treeType > 8) + treeType = 0; + w.SetNO(cv.pt, new noTree(cv.pt, static_cast(treeType), 3), true); + } + break; + } default: break; } @@ -407,6 +462,13 @@ void dskEditorInterface::Msg_PaintBefore() const int w = static_cast(screenSize.x); const int h = static_cast(screenSize.y); + // ── Refresh terrain renderer if world data was modified (e.g. texture painting) ── + if(pendingTerrainRefresh_) + { + pendingTerrainRefresh_ = false; + world_->getViewer().GetTerrainRenderer().GenerateOpenGL(world_->getViewer()); + } + // ── Terrain via GameWorldEditor ── if(gwEditor_) gwEditor_->Draw(screenSize); @@ -522,11 +584,15 @@ void dskEditorInterface::Msg_ButtonClick(unsigned ctrl_id) break; case ID_btToolTexture: mode_ = EditorToolMode::Texture; - WINDOWMANAGER.Show(std::make_unique()); + WINDOWMANAGER.Show(std::make_unique([this](int s2Id) noexcept { + modeContent_ = s2Id; + })); break; case ID_btToolTree: mode_ = EditorToolMode::Tree; - WINDOWMANAGER.Show(std::make_unique()); + WINDOWMANAGER.Show(std::make_unique([this](int treeType) noexcept { + modeContent2_ = treeType; + })); break; case ID_btToolResource: mode_ = EditorToolMode::Resource; diff --git a/dskEditorInterface.h b/dskEditorInterface.h index ad3ffeb..3e4e495 100644 --- a/dskEditorInterface.h +++ b/dskEditorInterface.h @@ -74,6 +74,9 @@ class dskEditorInterface : public Desktop int brushSize_ = 1; // 0..MAX_BRUSH MapPoint cursorPos_{0, 0}; bool isModifying_ = false; + int modeContent_ = 8; // selected terrain s2Id (default TRIANGLE_TEXTURE_MEADOW1) + int modeContent2_ = 0; // secondary: tree type (0-8) or -1/-2 for mixed + bool pendingTerrainRefresh_ = false; // Cursor vertex field static constexpr int MAX_BRUSH = 10; diff --git a/iwEditorTexture.cpp b/iwEditorTexture.cpp index 5c55bd1..6ef57cb 100644 --- a/iwEditorTexture.cpp +++ b/iwEditorTexture.cpp @@ -7,42 +7,70 @@ #include "controls/ctrlButton.h" #include "defines.h" -iwEditorTexture::iwEditorTexture() +iwEditorTexture::iwEditorTexture(CbFunc onSelect) : IngameWindow(101, IngameWindow::posLastOrCenter, Extent(220, 133), "Terrain", - LOADER.GetImageN("resource", 41)) + LOADER.GetImageN("resource", 41)), onSelect_(std::move(onSelect)) { const int x0 = contentOffset.x; const int y0 = contentOffset.y; const int step = 34; const int picSize = 32; - static constexpr int texIds[] = { - PICTURE_GREENLAND_TEXTURE_SNOW, - PICTURE_GREENLAND_TEXTURE_STEPPE, - PICTURE_GREENLAND_TEXTURE_SWAMP, - PICTURE_GREENLAND_TEXTURE_FLOWER, - PICTURE_GREENLAND_TEXTURE_MINING1, - PICTURE_GREENLAND_TEXTURE_MINING2, - PICTURE_GREENLAND_TEXTURE_MINING3, - PICTURE_GREENLAND_TEXTURE_MINING4, - PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW1, - PICTURE_GREENLAND_TEXTURE_MEADOW1, - PICTURE_GREENLAND_TEXTURE_MEADOW2, - PICTURE_GREENLAND_TEXTURE_MEADOW3, - PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW2, - PICTURE_GREENLAND_TEXTURE_MINING_MEADOW, - PICTURE_GREENLAND_TEXTURE_WATER, - PICTURE_GREENLAND_TEXTURE_LAVA, - PICTURE_GREENLAND_TEXTURE_MEADOW_MIXED, + // Map button ID (1..17) to TRIANGLE_TEXTURE_* value (the legacy s2Id) + static constexpr struct { unsigned id; int texIdx; int s2Id; } entries[] = { + {1, PICTURE_GREENLAND_TEXTURE_SNOW, TRIANGLE_TEXTURE_SNOW}, + {2, PICTURE_GREENLAND_TEXTURE_STEPPE, TRIANGLE_TEXTURE_STEPPE}, + {3, PICTURE_GREENLAND_TEXTURE_SWAMP, TRIANGLE_TEXTURE_SWAMP}, + {4, PICTURE_GREENLAND_TEXTURE_FLOWER, TRIANGLE_TEXTURE_FLOWER}, + {5, PICTURE_GREENLAND_TEXTURE_MINING1, TRIANGLE_TEXTURE_MINING1}, + {6, PICTURE_GREENLAND_TEXTURE_MINING2, TRIANGLE_TEXTURE_MINING2}, + {7, PICTURE_GREENLAND_TEXTURE_MINING3, TRIANGLE_TEXTURE_MINING3}, + {8, PICTURE_GREENLAND_TEXTURE_MINING4, TRIANGLE_TEXTURE_MINING4}, + {9, PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW1, TRIANGLE_TEXTURE_STEPPE_MEADOW1}, + {10, PICTURE_GREENLAND_TEXTURE_MEADOW1, TRIANGLE_TEXTURE_MEADOW1}, + {11, PICTURE_GREENLAND_TEXTURE_MEADOW2, TRIANGLE_TEXTURE_MEADOW2}, + {12, PICTURE_GREENLAND_TEXTURE_MEADOW3, TRIANGLE_TEXTURE_MEADOW3}, + {13, PICTURE_GREENLAND_TEXTURE_STEPPE_MEADOW2, TRIANGLE_TEXTURE_STEPPE_MEADOW2}, + {14, PICTURE_GREENLAND_TEXTURE_MINING_MEADOW, TRIANGLE_TEXTURE_MINING_MEADOW}, + {15, PICTURE_GREENLAND_TEXTURE_WATER, TRIANGLE_TEXTURE_WATER}, + {16, PICTURE_GREENLAND_TEXTURE_LAVA, TRIANGLE_TEXTURE_LAVA}, + {17, PICTURE_GREENLAND_TEXTURE_MEADOW_MIXED, TRIANGLE_TEXTURE_MEADOW_MIXED}, }; - for(unsigned i = 0; i < sizeof(texIds) / sizeof(texIds[0]); i++) + for(const auto& e : entries) { - auto* img = LOADER.GetImageN("editio", texIds[i]); + auto* img = LOADER.GetImageN("editio", e.texIdx); if(!img) continue; - int col = i % 6; - int row = i / 6; - AddImageButton(i + 1, DrawPoint(x0 + col * step, y0 + row * step), Extent(picSize, picSize), + int col = (e.id - 1) % 6; + int row = (e.id - 1) / 6; + AddImageButton(e.id, DrawPoint(x0 + col * step, y0 + row * step), Extent(picSize, picSize), TextureColor::Invisible, img, "")->SetBorder(false); } } + +void iwEditorTexture::Msg_ButtonClick(unsigned ctrl_id) +{ + static constexpr int s2IdForId[] = { + 0, // unused index 0 + TRIANGLE_TEXTURE_SNOW, + TRIANGLE_TEXTURE_STEPPE, + TRIANGLE_TEXTURE_SWAMP, + TRIANGLE_TEXTURE_FLOWER, + TRIANGLE_TEXTURE_MINING1, + TRIANGLE_TEXTURE_MINING2, + TRIANGLE_TEXTURE_MINING3, + TRIANGLE_TEXTURE_MINING4, + TRIANGLE_TEXTURE_STEPPE_MEADOW1, + TRIANGLE_TEXTURE_MEADOW1, + TRIANGLE_TEXTURE_MEADOW2, + TRIANGLE_TEXTURE_MEADOW3, + TRIANGLE_TEXTURE_STEPPE_MEADOW2, + TRIANGLE_TEXTURE_MINING_MEADOW, + TRIANGLE_TEXTURE_WATER, + TRIANGLE_TEXTURE_LAVA, + TRIANGLE_TEXTURE_MEADOW_MIXED, + }; + if(ctrl_id < sizeof(s2IdForId) / sizeof(s2IdForId[0]) && onSelect_) + onSelect_(s2IdForId[ctrl_id]); + Close(); +} diff --git a/iwEditorTexture.h b/iwEditorTexture.h index d70bcb9..21f9305 100644 --- a/iwEditorTexture.h +++ b/iwEditorTexture.h @@ -5,9 +5,17 @@ #pragma once #include "ingameWindows/IngameWindow.h" +#include class iwEditorTexture : public IngameWindow { public: - iwEditorTexture(); + /// Callback receives the selected terrain s2Id (TRIANGLE_TEXTURE_* value & ~0x40) + using CbFunc = std::function; + iwEditorTexture(CbFunc onSelect); + + void Msg_ButtonClick(unsigned ctrl_id) override; + +private: + CbFunc onSelect_; }; diff --git a/iwEditorTree.cpp b/iwEditorTree.cpp index b103234..59d69b2 100644 --- a/iwEditorTree.cpp +++ b/iwEditorTree.cpp @@ -7,37 +7,49 @@ #include "controls/ctrlButton.h" #include "defines.h" -iwEditorTree::iwEditorTree() +iwEditorTree::iwEditorTree(CbFunc onSelect) : IngameWindow(102, IngameWindow::posLastOrCenter, Extent(148, 140), "Trees", - LOADER.GetImageN("resource", 41)) + LOADER.GetImageN("resource", 41)), onSelect_(std::move(onSelect)) { const int x0 = contentOffset.x; const int y0 = contentOffset.y; const int step = 34; const int picSize = 32; - // Greenland trees (most complete set) - static constexpr int treeIds[] = { - PICTURE_TREE_PINE, - PICTURE_TREE_BIRCH, - PICTURE_TREE_OAK, - PICTURE_TREE_PALM1, - PICTURE_TREE_PALM2, - PICTURE_TREE_PINEAPPLE, - PICTURE_TREE_CYPRESS, - PICTURE_TREE_CHERRY, - PICTURE_TREE_FIR, - PICTURE_TREE_WOOD_MIXED, - PICTURE_TREE_PALM_MIXED, + // Map button ID to noTree type (0-8) or sentinel for mixed + static constexpr struct { unsigned id; int texIdx; int treeType; } entries[] = { + {1, PICTURE_TREE_PINE, 0}, + {2, PICTURE_TREE_BIRCH, 1}, + {3, PICTURE_TREE_OAK, 2}, + {4, PICTURE_TREE_PALM1, 3}, + {5, PICTURE_TREE_PALM2, 4}, + {6, PICTURE_TREE_PINEAPPLE, 5}, + {7, PICTURE_TREE_CYPRESS, 6}, + {8, PICTURE_TREE_CHERRY, 7}, + {9, PICTURE_TREE_FIR, 8}, + {10, PICTURE_TREE_WOOD_MIXED, -1}, // mixed wood: random pine/birch/oak + {11, PICTURE_TREE_PALM_MIXED, -2}, // mixed palm: random palm1/palm2/pineapple/cypress/cherry }; - for(unsigned i = 0; i < sizeof(treeIds) / sizeof(treeIds[0]); i++) + for(const auto& e : entries) { - auto* img = LOADER.GetImageN("editio", treeIds[i]); + auto* img = LOADER.GetImageN("editio", e.texIdx); if(!img) continue; - int col = i % 4; - int row = i / 4; - AddImageButton(i + 1, DrawPoint(x0 + col * step, y0 + row * step), Extent(picSize, picSize), + int col = (e.id - 1) % 4; + int row = (e.id - 1) / 4; + AddImageButton(e.id, DrawPoint(x0 + col * step, y0 + row * step), Extent(picSize, picSize), TextureColor::Invisible, img, "")->SetBorder(false); } } + +void iwEditorTree::Msg_ButtonClick(unsigned ctrl_id) +{ + // treeTypeForId[ctrl_id] = noTree type (0-8), -1 for mixed wood, -2 for mixed palm, 0 for invalid + static constexpr int treeTypeForId[] = { + 0, // unused index 0 + 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -2 + }; + if(ctrl_id < sizeof(treeTypeForId) / sizeof(treeTypeForId[0]) && onSelect_) + onSelect_(treeTypeForId[ctrl_id]); + Close(); +} diff --git a/iwEditorTree.h b/iwEditorTree.h index 69ccc41..0078809 100644 --- a/iwEditorTree.h +++ b/iwEditorTree.h @@ -5,9 +5,17 @@ #pragma once #include "ingameWindows/IngameWindow.h" +#include class iwEditorTree : public IngameWindow { public: - iwEditorTree(); + /// Callback receives the noTree type (0-8) or -1 for mixed wood, -2 for mixed palm + using CbFunc = std::function; + iwEditorTree(CbFunc onSelect); + + void Msg_ButtonClick(unsigned ctrl_id) override; + +private: + CbFunc onSelect_; }; From ab4f9a21d6fe865cdc6646993560ed8b6168d85b Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 15:17:27 +0200 Subject: [PATCH 11/16] Delete Texture --- CGame.cpp | 3 - CGame.h | 10 +- CGame_Init.cpp | 55 ++++----- CGame_Render.cpp | 5 +- CMap.cpp | 1 - CSurface.cpp | 1 - Texture.cpp | 288 ----------------------------------------------- Texture.h | 91 --------------- dskMainMenu.cpp | 8 +- dskOptions.cpp | 8 +- globals.h | 1 - 11 files changed, 39 insertions(+), 432 deletions(-) delete mode 100644 Texture.cpp delete mode 100644 Texture.h diff --git a/CGame.cpp b/CGame.cpp index 866191b..8865f59 100644 --- a/CGame.cpp +++ b/CGame.cpp @@ -71,9 +71,6 @@ int CGame::Execute() void CGame::RenderPresent() { - const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; - cursorImg.draw(Cursor.pos); - VIDEODRIVER.SwapBuffers(); } diff --git a/CGame.h b/CGame.h index 97b2202..1b7bfc4 100644 --- a/CGame.h +++ b/CGame.h @@ -6,8 +6,9 @@ #pragma once #include "SdlSurface.h" -#include "Texture.h" #include "driver/VideoDriverLoaderInterface.h" + +class glArchivItem_Bitmap; #include #include #include @@ -34,11 +35,8 @@ class CGame : public VideoDriverLoaderInterface Extent appliedResolution_ = Extent{0, 0}; ///< Last resolution we applied to the window/display bool appliedFullscreen_ = false; ///< Last fullscreen state we applied - // Textures for splash screen and cursor - Texture splashBg_; - Texture cursor_; - Texture cursorClicked_; - Texture cross_; + // Loading screen bitmap (loaded via LOADER at startup) + glArchivItem_Bitmap* splashBg_ = nullptr; // structure for mouse cursor struct diff --git a/CGame_Init.cpp b/CGame_Init.cpp index 286bbce..f10abc8 100644 --- a/CGame_Init.cpp +++ b/CGame_Init.cpp @@ -11,6 +11,7 @@ #include "Loader.h" #include "lua/GameDataLoader.h" #include "ogl/glAllocator.h" +#include "ogl/glArchivItem_Bitmap.h" #include #include #include @@ -18,6 +19,7 @@ #include #include "drivers/VideoDriverWrapper.h" #include +#include #include #include @@ -166,35 +168,31 @@ bool CGame::Init() * otherwise all images will be black (in exception of the LBM-Files, they have their own palette). */ - // load some pictures (after all the splash-screens) - // at first GFX/PICS/SETUP997.LBM, cause this is the S2-loading picture - std::cout << "\nLoading file: GFX/PICS/SETUP997.LBM..."; - if(!global::loadArchive(ArchiveID::SETUP997, global::gameDataFilePath / "GFX/PICS/SETUP997.LBM", nullptr)) + // Initialize basic LOADER infrastructure early (before LoadFilesAtStart) + libsiedler2::setAllocator(new GlAllocator()); + LOADER.initResourceFolders(); + + // Load the loading screen splash before the heavier LoadFilesAtStart { - std::cout << "failure"; - // if SETUP997.LBM doesn't exist, it's probably settlers2+mission cd and there we have SETUP998.LBM instead - std::cout << "\nTry to load file: GFX/PICS/SETUP998.LBM instead..."; - if(!global::loadArchive(ArchiveID::SETUP997, global::gameDataFilePath / "GFX/PICS/SETUP998.LBM", nullptr)) + auto setup997Path = global::gameDataFilePath / "GFX/PICS/SETUP997.LBM"; + if(!boost::filesystem::exists(setup997Path)) + setup997Path = global::gameDataFilePath / "GFX/PICS/SETUP998.LBM"; + if(boost::filesystem::exists(setup997Path)) { - std::cout << "failure"; - return false; + LOADER.Load(setup997Path, nullptr); + splashBg_ = LOADER.GetImageN(ResourceId::make(setup997Path), 0); } } - // Create texture for splash background - { - auto& archiv = global::typedArchives[ArchiveID::SETUP997]; - auto* bmp = dynamic_cast(archiv.get(0)); - if(bmp) - splashBg_.load(*bmp); - } - - // std::cout << "\nShow loading screen..."; showLoadScreen = true; glClear(GL_COLOR_BUFFER_BIT); - splashBg_.draw(Rect(0, 0, GameResolution.x, GameResolution.y)); + if(splashBg_) + splashBg_->DrawFull(Rect(0, 0, GameResolution.x, GameResolution.y)); SDL_GL_SwapWindow(window_.get()); + // Now load the full set of LOADER files + LOADER.LoadFilesAtStart(); + GameDataLoader gdLoader(global::worldDesc); if(!gdLoader.Load()) { @@ -373,31 +371,26 @@ bool CGame::Init() } } - // Initialize the s25main Loader with the same files the game itself uses. + // Load editor resources into the LOADER (already initialized at top) { - libsiedler2::setAllocator(new GlAllocator()); - LOADER.initResourceFolders(); - LOADER.LoadFilesAtStart(); + // Main menu background (not in LoadFilesAtStart) + const auto setup010Path = global::gameDataFilePath / "GFX/PICS/SETUP010.LBM"; + if(boost::filesystem::exists(setup010Path)) + LOADER.Load(setup010Path, nullptr); - // Also load the editor's EDITIO.IDX into a separate archive (keyed as "editio") - // so the editor toolbar can use its tool icons (MENUBAR_TREE=113, etc.) - // without overwriting the game's IO.IDX (needed for s25main button borders etc.). + // Editor EDITIO keyed as "editio" (separate from game's IO.IDX) const auto editioPath = global::gameDataFilePath / "DATA/IO/EDITIO.IDX"; LOADER.Load(editioPath, global::currentPalette); - // Load editor resource archives into the Loader const auto editresPath = global::gameDataFilePath / "DATA/EDITRES.IDX"; LOADER.Load(editresPath, global::currentPalette); const auto editbobPath = global::gameDataFilePath / "DATA/EDITBOB.LST"; LOADER.Load(editbobPath, global::currentPalette); - // Use editor cursor everywhere instead of the game's default hand auto* cursorNorm = LOADER.GetImageN("editres", CURSOR); auto* cursorPressed = LOADER.GetImageN("editres", CURSOR_CLICKED); if(cursorNorm) WINDOWMANAGER.SetCursorImage(Cursor::Hand, cursorNorm, cursorPressed); - - } // Show the new Desktop-based main menu via WindowManager diff --git a/CGame_Render.cpp b/CGame_Render.cpp index 9f81a05..c932abc 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -6,10 +6,10 @@ #include "CGame.h" #include "CMap.h" #include "CSurface.h" -#include "Texture.h" #include "WindowManager.h" #include "globals.h" #include "drivers/VideoDriverWrapper.h" +#include "ogl/glArchivItem_Bitmap.h" #include #ifdef _WIN32 # include "s25editResource.h" @@ -48,7 +48,8 @@ void CGame::Render() // if the S2 loading screen is shown, render only this until user clicks a mouse button if(showLoadScreen) { - splashBg_.draw(Rect(0, 0, GameResolution.x, GameResolution.y)); + if(splashBg_) + splashBg_->DrawFull(Rect(0, 0, GameResolution.x, GameResolution.y)); VIDEODRIVER.SwapBuffers(); return; } diff --git a/CMap.cpp b/CMap.cpp index fb1b8bc..d5afbc9 100644 --- a/CMap.cpp +++ b/CMap.cpp @@ -7,7 +7,6 @@ #include "CGame.h" #include "CIO/CFile.h" #include "CSurface.h" -#include "Texture.h" #include "globals.h" #include "gameData/LandscapeDesc.h" #include "gameData/TerrainDesc.h" diff --git a/CSurface.cpp b/CSurface.cpp index c555764..9ae6864 100644 --- a/CSurface.cpp +++ b/CSurface.cpp @@ -7,7 +7,6 @@ #include "CGame.h" #include "CMap.h" #include "Rect.h" -#include "Texture.h" #include "globals.h" #include "gameData/EdgeDesc.h" #include "gameData/TerrainDesc.h" diff --git a/Texture.cpp b/Texture.cpp deleted file mode 100644 index 4117408..0000000 --- a/Texture.cpp +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (C) 2026 - 2026 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "Texture.h" -#include "defines.h" -#include "globals.h" -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -Texture::~Texture() -{ - if(texture_) - glDeleteTextures(1, &texture_); -} - -Texture::Texture(Texture&& other) noexcept - : texture_(std::exchange(other.texture_, 0)), size_(std::exchange(other.size_, {0, 0})) -{} - -Texture& Texture::operator=(Texture&& other) noexcept -{ - if(this != &other) - { - if(texture_) - glDeleteTextures(1, &texture_); - texture_ = std::exchange(other.texture_, 0); - size_ = std::exchange(other.size_, {0, 0}); - } - return *this; -} - -void Texture::load(const uint8_t* bgraPixels, Extent size) -{ - if(texture_) - glDeleteTextures(1, &texture_); - texture_ = 0; - size_ = {0, 0}; - - glGenTextures(1, &texture_); - glBindTexture(GL_TEXTURE_2D, texture_); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0, GL_BGRA, GL_UNSIGNED_BYTE, bgraPixels); - size_ = size; -} - -void Texture::createEmpty(Extent size) -{ - load(nullptr, size); -} - -void Texture::upload(const void* bgraPixels) -{ - if(!texture_) - return; - glBindTexture(GL_TEXTURE_2D, texture_); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size_.x, size_.y, GL_BGRA, GL_UNSIGNED_BYTE, bgraPixels); -} - -bool Texture::load(const libsiedler2::baseArchivItem_Bitmap& bitmap) -{ - const auto w = bitmap.getWidth(); - const auto h = bitmap.getHeight(); - if(w == 0 || h == 0) - return false; - - // Render the bitmap to a BGRA buffer via libsiedler2's print method. - // This handles both paletted and BGRA source formats. - std::vector bgra(static_cast(w) * h * 4); - if(bitmap.print(bgra.data(), w, h, libsiedler2::TextureFormat::BGRA) != 0) - { - // If print fails (e.g. paletted bitmap without a palette), try manual conversion - if(bitmap.getFormat() == libsiedler2::TextureFormat::Paletted) - { - const auto* pal = bitmap.getPalette(); - if(!pal) - return false; - const auto& src = bitmap.getPixelData(); - if(src.size() < static_cast(w) * h) - return false; - for(unsigned y = 0; y < h; y++) - { - for(unsigned x = 0; x < w; x++) - { - uint8_t idx = src[y * w + x]; - auto c = pal->get(idx); - uint32_t& dst = reinterpret_cast(bgra.data())[y * w + x]; - dst = (0xFFu << 24) | (uint32_t(c.r) << 16) | (uint32_t(c.g) << 8) | uint32_t(c.b); - } - } - } else - return false; - } - - load(bgra.data(), Extent(w, h)); - return true; -} - -void Texture::draw(const Rect& destRect) const -{ - if(!texture_) - return; - - glColor4f(1, 1, 1, 1); - glBindTexture(GL_TEXTURE_2D, texture_); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); - glVertex2i(destRect.left, destRect.top); - glTexCoord2f(1, 0); - glVertex2i(destRect.right, destRect.top); - glTexCoord2f(1, 1); - glVertex2i(destRect.right, destRect.bottom); - glTexCoord2f(0, 1); - glVertex2i(destRect.left, destRect.bottom); - glEnd(); -} - -void Texture::draw(Position pos) const -{ - if(!texture_) - return; - - glColor4f(1, 1, 1, 1); - glBindTexture(GL_TEXTURE_2D, texture_); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); - glVertex2i(pos.x, pos.y); - glTexCoord2f(1, 0); - glVertex2i(pos.x + size_.x, pos.y); - glTexCoord2f(1, 1); - glVertex2i(pos.x + size_.x, pos.y + size_.y); - glTexCoord2f(0, 1); - glVertex2i(pos.x, pos.y + size_.y); - glEnd(); -} - -void Texture::drawTiled(const Rect& destRect) const -{ - if(!texture_) - return; - - const Extent tileSize = getSize(); - if(tileSize.x == 0 || tileSize.y == 0) - return; - - glBindTexture(GL_TEXTURE_2D, texture_); - glBegin(GL_QUADS); - for(int y = destRect.top; y < destRect.bottom; y += static_cast(tileSize.y)) - { - const int rowH = std::min(static_cast(tileSize.y), destRect.bottom - y); - const float v1 = float(rowH) / float(tileSize.y); - for(int x = destRect.left; x < destRect.right; x += static_cast(tileSize.x)) - { - const int colW = std::min(static_cast(tileSize.x), destRect.right - x); - const float u1 = float(colW) / float(tileSize.x); - - glTexCoord2f(0, 0); - glVertex2i(x, y); - glTexCoord2f(u1, 0); - glVertex2i(x + colW, y); - glTexCoord2f(u1, v1); - glVertex2i(x + colW, y + rowH); - glTexCoord2f(0, v1); - glVertex2i(x, y + rowH); - } - } - glEnd(); -} - -void Texture::draw(const Rect& destRect, const Rect& srcRect) const -{ - if(!texture_) - return; - - // Clamp source rect to texture bounds - int srcL = std::max(0, srcRect.left); - int srcT = std::max(0, srcRect.top); - int srcR = std::min(static_cast(size_.x), srcRect.right); - int srcB = std::min(static_cast(size_.y), srcRect.bottom); - if(srcL >= srcR || srcT >= srcB) - return; - - const float u0 = float(srcL) / float(size_.x); - const float v0 = float(srcT) / float(size_.y); - const float u1 = float(srcR) / float(size_.x); - const float v1 = float(srcB) / float(size_.y); - - glColor4f(1, 1, 1, 1); - glBindTexture(GL_TEXTURE_2D, texture_); - glBegin(GL_QUADS); - glTexCoord2f(u0, v0); - glVertex2i(destRect.left, destRect.top); - glTexCoord2f(u1, v0); - glVertex2i(destRect.right, destRect.top); - glTexCoord2f(u1, v1); - glVertex2i(destRect.right, destRect.bottom); - glTexCoord2f(u0, v1); - glVertex2i(destRect.left, destRect.bottom); - glEnd(); -} - -void drawRect(const Rect& rect, unsigned color) -{ - glDisable(GL_TEXTURE_2D); - glColor4ub((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF); - glBegin(GL_QUADS); - glVertex2i(rect.left, rect.top); - glVertex2i(rect.right, rect.top); - glVertex2i(rect.right, rect.bottom); - glVertex2i(rect.left, rect.bottom); - glEnd(); - glEnable(GL_TEXTURE_2D); - glColor4f(1, 1, 1, 1); -} - -Texture& getTexture(ArchiveID archive, int index) -{ - return Texture::getTexture(archive, index); -} - -void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned faceTex) -{ - getTexture(ArchiveID::EDITIO, baseTex).drawTiled(area); - - const auto sz = area.getSize(); - - // 2px black frame: left+top if pressed, right+bottom otherwise - if(pressed) - { - drawRect(Rect(area.getOrigin(), 2, sz.y), 0xFF000000); - drawRect(Rect(area.getOrigin(), sz.x, 2), 0xFF000000); - } else - { - drawRect(Rect(area.right - 2, area.top, 2, sz.y), 0xFF000000); - drawRect(Rect(area.left, area.bottom - 2, sz.x, 2), 0xFF000000); - } - - // Foreground inset by 2px - const Extent fgSz(sz.x - 4u, sz.y - 4u); - const Rect fgRect(area.getOrigin() + Position(2, 2), fgSz); - getTexture(ArchiveID::EDITIO, faceTex).drawTiled(fgRect); -} - -// Bitmap-texture cache (static members) -// Cache for typed-archive textures: (archive, index) → Texture -static std::map, std::unique_ptr> s_typedTexCache; - -Texture& Texture::getTexture(ArchiveID archive, int index) -{ - auto& archiv = global::typedArchives[archive]; - if(index < 0 || static_cast(index) >= archiv.size()) - { - static Texture dummy; - return dummy; - } - const auto key = std::make_pair(archive, index); - auto it = s_typedTexCache.find(key); - if(it == s_typedTexCache.end() || !it->second->isValid()) - { - auto tex = std::make_unique(); - const auto* bmp = dynamic_cast(archiv.get(index)); - if(bmp) - { - tex->load(*bmp); - tex->anchor_ = {bmp->getNx(), bmp->getNy()}; - } - it = s_typedTexCache.emplace(key, std::move(tex)).first; - } - return *it->second; -} - -void Texture::drawSprite(Position pos) const -{ - if(!isValid()) - return; - draw(pos - anchor_); -} diff --git a/Texture.h b/Texture.h deleted file mode 100644 index dbe9501..0000000 --- a/Texture.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (C) 2026 - 2026 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "ArchiveID.h" -#include "Rect.h" -#include -#include -#include -#include -#include - -namespace libsiedler2 { -class baseArchivItem_Bitmap; -} // namespace libsiedler2 - -/// Wraps a texture with RAII and provides draw methods. -class Texture -{ -public: - Texture() = default; - ~Texture(); - - Texture(Texture&&) noexcept; - Texture& operator=(Texture&&) noexcept; - - // No copy - Texture(const Texture&) = delete; - Texture& operator=(const Texture&) = delete; - - /// Load from a libsiedler2 bitmap (paletted or BGRA). - bool load(const libsiedler2::baseArchivItem_Bitmap& bitmap); - - /// Load raw BGRA pixel data directly. - void load(const uint8_t* bgraPixels, Extent size); - - /// Create an empty texture of the given size (for use as a render-target). - void createEmpty(Extent size); - - /// Upload new pixel data to an existing texture (glTexSubImage2D). - void upload(const void* bgraPixels); - - /// Draw the texture stretched to fill the given rect. - void draw(const Rect& destRect) const; - - /// Draw the texture at native size at the given position. - void draw(Position pos) const; - - /// Tile the texture to fill the given rectangle. - void drawTiled(const Rect& destRect) const; - - /// Size in pixels. - Extent getSize() const { return size_; } - - /// Draw a sub-rect of the texture stretched to fill the given dest rect. - void draw(const Rect& destRect, const Rect& srcRect) const; - - /// Returns true if the texture has been created. - bool isValid() const { return texture_ != 0; } - - /// Draw at native size at the given position adjusted by the sprite anchor. - void drawSprite(Position pos) const; - - /// Sprite anchor offset (set by getTexture). - Position anchor() const { return anchor_; } - - /// Direct handle access for manual GL ops. - GLuint getHandle() const { return texture_; } - - // Static bitmap-texture cache - - /// Return (or create on first use) a cached GL texture from a typed archive. - static Texture& getTexture(ArchiveID archive, int index); - -private: - GLuint texture_ = 0; - Extent size_; - Position anchor_ = {0, 0}; // sprite anchor offset, set by getTexture -}; - -/// Draw a filled rectangle with a 32-bit ARGB colour. -void drawRect(const Rect& rect, unsigned color); - -/// Draw a 3D-style button box: tiled background, 2px black frame (sunken if pressed, raised otherwise), -/// and tiled foreground inset by 2px. All button textures from EDITIO.IDX. -void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned faceTex); - -/// Get or create the cached OpenGL texture from a typed archive. -Texture& getTexture(ArchiveID archive, int index); diff --git a/dskMainMenu.cpp b/dskMainMenu.cpp index bab1658..cbad870 100644 --- a/dskMainMenu.cpp +++ b/dskMainMenu.cpp @@ -5,13 +5,14 @@ #include "dskMainMenu.h" #include "CGame.h" #include "EditorWorld.h" -#include "Texture.h" +#include "Loader.h" #include "WindowManager.h" #include "controls/ctrlButton.h" #include "defines.h" #include "dskEditorInterface.h" #include "dskOptions.h" #include "globals.h" +#include "ogl/glArchivItem_Bitmap.h" #include "iwLoadMap.h" dskMainMenu::dskMainMenu() @@ -26,9 +27,8 @@ dskMainMenu::dskMainMenu() void dskMainMenu::Draw_() { - auto& bg = Texture::getTexture(ArchiveID::SETUP010, SPLASHSCREEN_MAINMENU); - if(bg.isValid()) - bg.draw(GetDrawRect()); + if(auto* bg = LOADER.GetImageN("setup010", 0)) + bg->DrawFull(GetDrawRect()); Desktop::Draw_(); } diff --git a/dskOptions.cpp b/dskOptions.cpp index f4abd5f..d5d79c5 100644 --- a/dskOptions.cpp +++ b/dskOptions.cpp @@ -4,7 +4,7 @@ #include "dskOptions.h" #include "CGame.h" -#include "Texture.h" +#include "Loader.h" #include "WindowManager.h" #include "controls/ctrlButton.h" #include "controls/ctrlList.h" @@ -14,6 +14,7 @@ #include "globals.h" #include "helpers/format.hpp" #include "ogl/FontStyle.h" +#include "ogl/glArchivItem_Bitmap.h" static constexpr std::pair resolutions[] = { {800, 600}, {832, 624}, {960, 540}, {964, 544}, {960, 640}, {960, 720}, {1024, 576}, {1024, 600}, @@ -51,9 +52,8 @@ dskOptions::dskOptions() void dskOptions::Draw_() { - auto& bg = Texture::getTexture(ArchiveID::SETUP013, SPLASHSCREEN_SUBMENU3); - if(bg.isValid()) - bg.draw(GetDrawRect()); + if(auto* bg = LOADER.GetImageN("setup013", 0)) + bg->DrawFull(GetDrawRect()); Desktop::Draw_(); } diff --git a/globals.h b/globals.h index 5f464d8..f087bc6 100644 --- a/globals.h +++ b/globals.h @@ -6,7 +6,6 @@ #pragma once #include "ArchiveID.h" -#include "Texture.h" #include "gameData/WorldDescription.h" #include #include From a1ef7341f8ebad6352b408929b4027fbeef9c693 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 15:21:32 +0200 Subject: [PATCH 12/16] delete CFile --- CIO/CFile.cpp | 467 -------------------------------------------------- CIO/CFile.h | 26 --- iwSaveMap.cpp | 32 +--- 3 files changed, 4 insertions(+), 521 deletions(-) delete mode 100644 CIO/CFile.cpp delete mode 100644 CIO/CFile.h diff --git a/CIO/CFile.cpp b/CIO/CFile.cpp deleted file mode 100644 index eee26c6..0000000 --- a/CIO/CFile.cpp +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2024 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CFile.h" -#include "../globals.h" -#include "libendian/libendian.h" -#include "s25util/file_handle.h" -#include -#include -#include -#include -#include -#include - -#define CHECK_READ(readCmd) \ - if(!(readCmd)) \ - throw std::runtime_error("Read failed") - -void* CFile::open_file(const boost::filesystem::path& filepath, char filetype) -{ - if(filepath.empty()) - return nullptr; - s25util::file_handle fh(boost::nowide::fopen(filepath.string().c_str(), "rb")); - if(!fh) - return nullptr; - try - { - switch(filetype) - { - case WLD: return read_wld(*fh); - case SWD: return read_swd(*fh); - default: break; - } - } catch(const std::exception& e) - { - std::cerr << "Error reading " << filepath << ": " << e.what() << std::endl; - } - return nullptr; -} - -bool CFile::save_file(const boost::filesystem::path& filepath, char filetype, void* data) -{ - if(filepath.empty() || !data) - return false; - s25util::file_handle fh(boost::nowide::fopen(filepath.string().c_str(), "wb")); - if(!fh) - return false; - try - { - switch(filetype) - { - case WLD: - if(save_wld(*fh, data)) - return true; - break; - case SWD: - if(save_swd(*fh, data)) - return true; - break; - default: break; - } - } catch(const std::exception& e) - { - std::cerr << "Error saving " << filepath << ": " << e.what() << std::endl; - } - return false; -} - -bobMAP* CFile::read_wld(FILE* fp) -{ - auto myMap = std::make_unique(); - std::array tmpNameAuthor; - - fseek(fp, 10, SEEK_SET); - tmpNameAuthor.fill('\0'); - CHECK_READ(libendian::read(tmpNameAuthor, fp)); - myMap->setName(tmpNameAuthor.data()); - CHECK_READ(libendian::le_read_us(&myMap->width_old, fp)); - CHECK_READ(libendian::le_read_us(&myMap->height_old, fp)); - uint8_t mapType; - CHECK_READ(libendian::read(&mapType, 1, fp)); - myMap->type = MapType(mapType); - CHECK_READ(libendian::read(&myMap->player, 1, fp)); - tmpNameAuthor.fill('\0'); - CHECK_READ(libendian::read(tmpNameAuthor, fp)); - myMap->setAuthor(tmpNameAuthor.data()); - for(unsigned short& i : myMap->HQx) - CHECK_READ(libendian::le_read_us(&i, fp)); - for(unsigned short& i : myMap->HQy) - CHECK_READ(libendian::le_read_us(&i, fp)); - - // go to big map header and read it - fseek(fp, 92, SEEK_SET); - for(auto& i : myMap->header) - { - CHECK_READ(libendian::read(&i.type, 1, fp)); - CHECK_READ(libendian::le_read_us(&i.x, fp)); - CHECK_READ(libendian::le_read_us(&i.y, fp)); - CHECK_READ(libendian::le_read_ui(&i.area, fp)); - } - - // go to real map height and width - fseek(fp, 2348, SEEK_SET); - CHECK_READ(libendian::le_read_us(&myMap->width, fp)); - CHECK_READ(libendian::le_read_us(&myMap->height, fp)); - - myMap->vertex.resize(myMap->width * myMap->height); - - // go to altitude information (we skip the 16 bytes long map data header that each block has) - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - { - Uint8 heightFactor; - CHECK_READ(libendian::read(&heightFactor, 1, fp)); - myMap->getVertex(i, j).h = heightFactor; //-V807 - } - } - myMap->initVertexCoords(); - - // go to texture information for RightSideUp-Triangles - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).rsuTexture, 1, fp)); - } - - // go to texture information for UpSideDown-Triangles - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).usdTexture, 1, fp)); - } - - // go to road data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).road, 1, fp)); - } - - // go to object type data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).objectType, 1, fp)); - } - - // go to object info data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).objectInfo, 1, fp)); - } - - // go to animal data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).animal, 1, fp)); - } - - // go to unknown1 data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).unknown1, 1, fp)); - } - - // go to build data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).build, 1, fp)); - } - - // go to unknown2 data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).unknown2, 1, fp)); - } - - // go to unknown3 data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).unknown3, 1, fp)); - } - - // go to resource data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).resource, 1, fp)); - } - - // go to shading data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).shading, 1, fp)); - } - - // go to unknown5 data - fseek(fp, 16, SEEK_CUR); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).unknown5, 1, fp)); - } - - return myMap.release(); -} - -bobMAP* CFile::read_swd(FILE* fp) -{ - return read_wld(fp); -} - -bool CFile::save_wld(FILE* fp, void* data) -{ - char zero = 0; // to fill bytes - char temp = 0; // to fill bytes - auto* myMap = (bobMAP*)data; - char map_version[11] = "WORLD_V1.0"; - std::array map_data_header; - - // prepare map data header - map_data_header[0] = 0x10; - map_data_header[1] = 0x27; - map_data_header[2] = 0x00; - map_data_header[3] = 0x00; - map_data_header[4] = 0x00; - map_data_header[5] = 0x00; - *((Uint16*)(&map_data_header[6])) = boost::endian::native_to_little(myMap->width); - *((Uint16*)(&map_data_header[8])) = boost::endian::native_to_little(myMap->height); - map_data_header[10] = 0x01; - map_data_header[11] = 0x00; - *((Uint32*)(&map_data_header[12])) = boost::endian::native_to_little(myMap->width * myMap->height); - - // begin writing data to file - // first of all the map header - // WORLD_V1.0 - libendian::write(map_version, 10, fp); - auto makeNameArray = [](const std::string& name) { - std::array ar; - auto size = std::min(name.size(), ar.size()); - ar.fill(0); - std::copy_n(name.begin(), size, ar.begin()); - return ar; - }; - - // name - libendian::write(makeNameArray(myMap->getName()), fp); - // old width - libendian::le_write_us(myMap->width_old, fp); - // old height - libendian::le_write_us(myMap->height_old, fp); - // type - auto mapType = uint8_t(myMap->type); - libendian::write(&mapType, 1, fp); - // players - libendian::write(&myMap->player, 1, fp); - // author - libendian::write(makeNameArray(myMap->getAuthor()), fp); - // headquarters x - for(unsigned short i : myMap->HQx) - libendian::le_write_us(i, fp); - // headquarters y - for(unsigned short i : myMap->HQy) - libendian::le_write_us(i, fp); - // unknown data (8 Bytes) - for(int i = 0; i < 8; i++) - libendian::write(&zero, 1, fp); - // big map header with area information - for(auto& i : myMap->header) - { - libendian::write(&i.type, 1, fp); - libendian::le_write_us(i.x, fp); - libendian::le_write_us(i.y, fp); - libendian::le_write_ui(i.area, fp); - } - // 0x11 0x27 - temp = 0x11; - libendian::write(&temp, 1, fp); - temp = 0x27; - libendian::write(&temp, 1, fp); - // unknown data (always null, 4 Bytes) - for(int i = 0; i < 4; i++) - libendian::write(&zero, 1, fp); - // width - libendian::le_write_us(myMap->width, fp); - // height - libendian::le_write_us(myMap->height, fp); - - // now begin writing the real map data - - // altitude information - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - { - temp = myMap->getVertex(i, j).z / 5 + 0x0A; //-V807 - libendian::write(&temp, 1, fp); - } - } - - // texture information for RightSideUp-Triangles - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).rsuTexture, 1, fp); - } - - // go to texture information for UpSideDown-Triangles - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).usdTexture, 1, fp); - } - - // go to road data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).road, 1, fp); - } - - // go to object type data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).objectType, 1, fp); - } - - // go to object info data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).objectInfo, 1, fp); - } - - // go to animal data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).animal, 1, fp); - } - - // go to unknown1 data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).unknown1, 1, fp); - } - - // go to build data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).build, 1, fp); - } - - // go to unknown2 data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).unknown2, 1, fp); - } - - // go to unknown3 data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).unknown3, 1, fp); - } - - // go to resource data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).resource, 1, fp); - } - - // go to shading data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).shading, 1, fp); - } - - // go to unknown5 data - libendian::write(map_data_header, fp); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).unknown5, 1, fp); - } - - // at least write the map footer (ends in 0xFF) - temp = char(0xFF); - libendian::write(&temp, 1, fp); - - return true; -} - -bool CFile::save_swd(FILE* fp, void* data) -{ - return save_wld(fp, data); -} diff --git a/CIO/CFile.h b/CIO/CFile.h deleted file mode 100644 index 54fe30e..0000000 --- a/CIO/CFile.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2024 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "defines.h" -#include -#include -#include - -struct bobMAP; - -class CFile -{ -private: - static bobMAP* read_wld(FILE* fp); - static bobMAP* read_swd(FILE* fp); - static bool save_wld(FILE* fp, void* data); - static bool save_swd(FILE* fp, void* data); - -public: - static void* open_file(const boost::filesystem::path& filepath, char filetype); - static bool save_file(const boost::filesystem::path& filepath, char filetype, void* data); -}; diff --git a/iwSaveMap.cpp b/iwSaveMap.cpp index 7b5f281..69701f0 100644 --- a/iwSaveMap.cpp +++ b/iwSaveMap.cpp @@ -3,9 +3,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "iwSaveMap.h" -#include "CGame.h" -#include "CIO/CFile.h" -#include "CMap.h" #include namespace bfs = boost::filesystem; #include "WindowManager.h" @@ -25,17 +22,13 @@ iwSaveMap::iwSaveMap() AddText(ID_lblFilename, DrawPoint(labelX, off.y + 2), "Filename", COLOR_YELLOW, FontStyle::CENTER, SmallFont); auto* editFile = AddEdit(ID_edtFilename, off + DrawPoint(10, 13), Extent(210, 22), TextureColor::Grey, NormalFont); - auto* mapObj = global::s2->getMapObj(); - bfs::path defaultPath = mapObj ? mapObj->getFilepath() : ""; - editFile->SetText(defaultPath.empty() ? "MyMap" : defaultPath.filename().string()); + editFile->SetText("MyMap"); AddText(ID_lblMapname, DrawPoint(labelX, off.y + 38), "Mapname", COLOR_YELLOW, FontStyle::CENTER, SmallFont); - auto* editName = AddEdit(ID_edtMapname, off + DrawPoint(10, 50), Extent(210, 22), TextureColor::Grey, NormalFont); - editName->SetText(mapObj ? mapObj->getMapname() : ""); + AddEdit(ID_edtMapname, off + DrawPoint(10, 50), Extent(210, 22), TextureColor::Grey, NormalFont); AddText(ID_lblAuthor, DrawPoint(labelX, off.y + 75), "Author", COLOR_YELLOW, FontStyle::CENTER, SmallFont); - auto* editAuthor = AddEdit(ID_edtAuthor, off + DrawPoint(10, 87), Extent(210, 22), TextureColor::Grey, NormalFont); - editAuthor->SetText(mapObj ? mapObj->getAuthor() : ""); + AddEdit(ID_edtAuthor, off + DrawPoint(10, 87), Extent(210, 22), TextureColor::Grey, NormalFont); off += DrawPoint(0, 20); AddTextButton(ID_btSave, off + DrawPoint(10, 115), Extent(100, 22), TextureColor::Green2, "Save", NormalFont); @@ -48,24 +41,7 @@ void iwSaveMap::Msg_ButtonClick(unsigned ctrl_id) { case ID_btSave: { - auto* mapObj = global::s2->getMapObj(); - if(!mapObj) - break; - auto* editFile = GetCtrl(ID_edtFilename); - auto* editName = GetCtrl(ID_edtMapname); - auto* editAuthor = GetCtrl(ID_edtAuthor); - if(!editFile || !editName || !editAuthor) - break; - - mapObj->setMapname(editName->GetText()); - mapObj->setAuthor(editAuthor->GetText()); - - bfs::path filepath = global::userMapsPath / editFile->GetText(); - if(!filepath.has_extension()) - filepath.replace_extension("SWD"); - mapObj->setFilepath(filepath); - CFile::save_file(filepath, WLD, mapObj->getMap()); // ignore return for now - + // TODO: wire up to EditorWorld/GameWorld for saving Close(); break; } From c463ee58ae2228bfd0c860b1e0dec1b9f0d4b3f7 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 15:36:13 +0200 Subject: [PATCH 13/16] delete delete --- CGame.cpp | 21 - CGame.h | 8 - CGame_Event.cpp | 1 - CGame_Init.cpp | 184 +-- CGame_Render.cpp | 45 +- CMap.cpp | 2705 ----------------------------------------- CMap.h | 221 ---- CSurface.cpp | 1427 ---------------------- CSurface.h | 43 - EditorWorldLoader.cpp | 3 +- globals.cpp | 138 --- globals.h | 51 - include/ArchiveID.h | 66 - iwLoadMap.cpp | 4 +- 14 files changed, 20 insertions(+), 4897 deletions(-) delete mode 100644 CMap.cpp delete mode 100644 CMap.h delete mode 100644 CSurface.cpp delete mode 100644 CSurface.h delete mode 100644 include/ArchiveID.h diff --git a/CGame.cpp b/CGame.cpp index 8865f59..d5f68e9 100644 --- a/CGame.cpp +++ b/CGame.cpp @@ -4,7 +4,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CGame.h" -#include "CMap.h" #include "RttrConfig.h" #include "defines.h" #include "files.h" @@ -89,26 +88,6 @@ bool CGame::UnregisterCallback(void (*callback)(int)) return true; } -void CGame::setMapObj(std::unique_ptr MapObj) -{ - this->MapObj = std::move(MapObj); -} - -CMap* CGame::getMapObj() -{ - return MapObj.get(); -} - -void CGame::delMapObj() -{ - MapObj.reset(); -} - -void CGame::enterEditor(const boost::filesystem::path& filepath) -{ - setMapObj(std::make_unique(filepath)); -} - void CGame::LoadSettings() { const bfs::path settingsPath = RTTRCONFIG.ExpandPath("/s25edit.ini"); diff --git a/CGame.h b/CGame.h index 1b7bfc4..5cd1bc8 100644 --- a/CGame.h +++ b/CGame.h @@ -14,8 +14,6 @@ class glArchivItem_Bitmap; #include #include -class CMap; - class CGame : public VideoDriverLoaderInterface { @@ -52,8 +50,6 @@ class CGame : public VideoDriverLoaderInterface // Object for Callbacks std::vector Callbacks; - // Object for the Map - std::unique_ptr MapObj; void SetAppIcon(); void setGLViewport(); @@ -97,8 +93,4 @@ class CGame : public VideoDriverLoaderInterface void RegisterCallback(void (*callback)(int)); bool UnregisterCallback(void (*callback)(int)); - void setMapObj(std::unique_ptr MapObj); - CMap* getMapObj(); - void delMapObj(); - void enterEditor(const boost::filesystem::path& filepath); }; diff --git a/CGame_Event.cpp b/CGame_Event.cpp index 05b12a5..b28bd79 100644 --- a/CGame_Event.cpp +++ b/CGame_Event.cpp @@ -4,7 +4,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CGame.h" -#include "CMap.h" #include "WindowManager.h" #include "drivers/VideoDriverWrapper.h" #include "enum_cast.hpp" diff --git a/CGame_Init.cpp b/CGame_Init.cpp index f10abc8..2b9066c 100644 --- a/CGame_Init.cpp +++ b/CGame_Init.cpp @@ -4,9 +4,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CGame.h" -#include "CMap.h" #include "WindowManager.h" #include "dskMainMenu.h" +#include "defines.h" #include "globals.h" #include "Loader.h" #include "lua/GameDataLoader.h" @@ -200,192 +200,24 @@ bool CGame::Init() return false; } - // continue loading pictures - const struct - { - ArchiveID id; - const char* path; - } setupFiles[] = { - {ArchiveID::SETUP000, "GFX/PICS/SETUP000.LBM"}, {ArchiveID::SETUP010, "GFX/PICS/SETUP010.LBM"}, - {ArchiveID::SETUP011, "GFX/PICS/SETUP011.LBM"}, {ArchiveID::SETUP012, "GFX/PICS/SETUP012.LBM"}, - {ArchiveID::SETUP013, "GFX/PICS/SETUP013.LBM"}, {ArchiveID::SETUP014, "GFX/PICS/SETUP014.LBM"}, - {ArchiveID::SETUP015, "GFX/PICS/SETUP015.LBM"}, - }; - for(const auto& sf : setupFiles) - { - std::cout << "\nLoading file: " << sf.path << "..."; - if(!global::loadArchive(sf.id, global::gameDataFilePath / sf.path, nullptr)) - { - std::cout << "failure"; - // if it doesn't exist, it's probably settlers2+missioncd and we simply load SETUP010.LBM instead - std::cout << "\nLoading file: GFX/PICS/SETUP010.LBM instead..."; - if(!global::loadArchive(ArchiveID::SETUP010, global::gameDataFilePath / "GFX/PICS/SETUP010.LBM", nullptr)) - { - std::cout << "failure"; - return false; - } - } - } - - { // batch 2: SETUP666-896 - const struct - { - ArchiveID id; - const char* path; - } files[] = { - {ArchiveID::SETUP666, "GFX/PICS/SETUP666.LBM"}, {ArchiveID::SETUP667, "GFX/PICS/SETUP667.LBM"}, - {ArchiveID::SETUP801, "GFX/PICS/SETUP801.LBM"}, {ArchiveID::SETUP802, "GFX/PICS/SETUP802.LBM"}, - {ArchiveID::SETUP803, "GFX/PICS/SETUP803.LBM"}, {ArchiveID::SETUP804, "GFX/PICS/SETUP804.LBM"}, - {ArchiveID::SETUP805, "GFX/PICS/SETUP805.LBM"}, {ArchiveID::SETUP806, "GFX/PICS/SETUP806.LBM"}, - {ArchiveID::SETUP810, "GFX/PICS/SETUP810.LBM"}, {ArchiveID::SETUP811, "GFX/PICS/SETUP811.LBM"}, - {ArchiveID::SETUP895, "GFX/PICS/SETUP895.LBM"}, {ArchiveID::SETUP896, "GFX/PICS/SETUP896.LBM"}, - }; - for(const auto& f : files) - { - std::cout << "\nLoading file: " << f.path << "..."; - if(!global::loadArchive(f.id, global::gameDataFilePath / f.path, nullptr)) - { - std::cout << "failure"; - return false; - } - } - } - - { // batch 3: SETUP897-898 with fallback to SETUP896 - const struct - { - ArchiveID id; - const char* path; - } files[] = { - {ArchiveID::SETUP897, "GFX/PICS/SETUP897.LBM"}, - {ArchiveID::SETUP898, "GFX/PICS/SETUP898.LBM"}, - }; - for(const auto& f : files) - { - std::cout << "\nLoading file: " << f.path << "..."; - if(!global::loadArchive(f.id, global::gameDataFilePath / f.path, nullptr)) - { - std::cout << "failure"; - std::cout << "\nLoading file: GFX/PICS/SETUP896.LBM instead..."; - if(!global::loadArchive(f.id, global::gameDataFilePath / "GFX/PICS/SETUP896.LBM", nullptr)) - { - std::cout << "failure"; - return false; - } - } - } - } - - { // batch 4: remaining loading screens - const struct - { - ArchiveID id; - const char* path; - } files[] = { - {ArchiveID::SETUP899, "GFX/PICS/SETUP899.LBM"}, - {ArchiveID::SETUP990, "GFX/PICS/SETUP990.LBM"}, - {ArchiveID::WORLD_LBM, "GFX/PICS/WORLD.LBM"}, - {ArchiveID::WORLDMSK_LBM, "GFX/PICS/WORLDMSK.LBM"}, - }; - for(const auto& f : files) - { - std::cout << "\nLoading file: " << f.path << "..."; - if(!global::loadArchive(f.id, global::gameDataFilePath / f.path, nullptr)) - { - std::cout << "failure"; - return false; - } - } - } - - // Load the default palette first so all subsequent loads have it available + // Load EDITRES for fonts, and palette std::cout << "\nLoading default palette from file: GFX/PALETTE/PAL5.BBM..."; - if(!global::loadPalette(global::gameDataFilePath / "GFX/PALETTE/PAL5.BBM")) - { - std::cout << "failure"; - return false; - } - - // Load EDITRES.IDX as a complete bundle in typedArchives - { - libsiedler2::Archiv editres; - int ec = libsiedler2::Load(global::gameDataFilePath / "DATA/EDITRES.IDX", editres, global::currentPalette); - if(ec) - { - std::cout << "\nError loading EDITRES.IDX: " << libsiedler2::getErrorString(ec) << std::endl; - return false; - } - // The palette in EDITRES (item 1) may override the default - auto* pal = dynamic_cast(editres.get(1)); - if(pal) - global::currentPalette = pal; - // Store the complete Archiv in typedArchives - // Indices match file positions: 0=Font, 1=Palette, 2=Font, 3=Font, 4-56=Bitmaps - global::typedArchives[ArchiveID::EDITRES] = std::move(editres); - } - - std::cout << "\nLoading file: DATA/IO/EDITIO.IDX..."; - if(!global::loadArchive(ArchiveID::EDITIO, global::gameDataFilePath / "DATA/IO/EDITIO.IDX", global::currentPalette)) - { - std::cout << "failure"; - return false; - } - std::cout << "done"; - - std::cout << "\nLoading file: DATA/EDITBOB.LST..."; - if(!global::loadArchive(ArchiveID::EDITBOB, global::gameDataFilePath / "DATA/EDITBOB.LST", global::currentPalette)) - { - std::cout << "failure"; - return false; - } - std::cout << "done"; - - // texture tilesets - const ArchiveID texArchives[3] = {ArchiveID::TEX5, ArchiveID::TEX6, ArchiveID::TEX7}; - const std::string texFiles[3] = {"GFX/TEXTURES/TEX5.LBM", "GFX/TEXTURES/TEX6.LBM", "GFX/TEXTURES/TEX7.LBM"}; - for(unsigned ti = 0; ti < 3; ti++) - { - std::cout << "\nLoading file: " << texFiles[ti] << "..."; - if(!global::loadTileset(texArchives[ti], ti, global::gameDataFilePath / texFiles[ti])) - { - std::cout << "failure"; - return false; - } - std::cout << "done"; - } - - - - // EVERY MISSION-FILE SHOULD BE LOADED SEPARATLY IF THE SPECIFIED MISSION GOES ON -- SO THIS IS TEMPORARY - const ArchiveID misArchives[] = {ArchiveID::MIS0BOBS, ArchiveID::MIS1BOBS, ArchiveID::MIS2BOBS, - ArchiveID::MIS3BOBS, ArchiveID::MIS4BOBS, ArchiveID::MIS5BOBS}; - const std::string misFiles[] = {"DATA/MIS0BOBS.LST", "DATA/MIS1BOBS.LST", "DATA/MIS2BOBS.LST", - "DATA/MIS3BOBS.LST", "DATA/MIS4BOBS.LST", "DATA/MIS5BOBS.LST"}; - for(unsigned mi = 0; mi < 6; mi++) - { - std::cout << "\nLoading file: " << misFiles[mi] << "..."; - if(!global::loadArchive(misArchives[mi], global::gameDataFilePath / misFiles[mi], global::currentPalette)) - { - std::cout << "failure"; - return false; - } - } - // Load editor resources into the LOADER (already initialized at top) { + const auto* pal5 = LOADER.GetPaletteN("pal5", 0); + // Main menu background (not in LoadFilesAtStart) const auto setup010Path = global::gameDataFilePath / "GFX/PICS/SETUP010.LBM"; if(boost::filesystem::exists(setup010Path)) LOADER.Load(setup010Path, nullptr); - // Editor EDITIO keyed as "editio" (separate from game's IO.IDX) + // Editor archives keyed separately from game's IO.IDX etc. const auto editioPath = global::gameDataFilePath / "DATA/IO/EDITIO.IDX"; - LOADER.Load(editioPath, global::currentPalette); - + LOADER.Load(editioPath, pal5); const auto editresPath = global::gameDataFilePath / "DATA/EDITRES.IDX"; - LOADER.Load(editresPath, global::currentPalette); + LOADER.Load(editresPath, pal5); const auto editbobPath = global::gameDataFilePath / "DATA/EDITBOB.LST"; - LOADER.Load(editbobPath, global::currentPalette); + LOADER.Load(editbobPath, pal5); auto* cursorNorm = LOADER.GetImageN("editres", CURSOR); auto* cursorPressed = LOADER.GetImageN("editres", CURSOR_CLICKED); diff --git a/CGame_Render.cpp b/CGame_Render.cpp index c932abc..9acd220 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -4,8 +4,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CGame.h" -#include "CMap.h" -#include "CSurface.h" #include "WindowManager.h" #include "globals.h" #include "drivers/VideoDriverWrapper.h" @@ -54,42 +52,15 @@ void CGame::Render() return; } - // If no map is active, let the WindowManager render the Desktop (and any IngameWindows) - if(!MapObj || !MapObj->isActive()) - { - // Reset projection to screen-space before WindowManager draws - const auto rs = VIDEODRIVER.GetRenderSize(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, rs.x, rs.y, 0, -1, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - WINDOWMANAGER.Draw(); - } + // Reset projection to screen-space before WindowManager draws + const auto rs = VIDEODRIVER.GetRenderSize(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, rs.x, rs.y, 0, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); - // render the map if active - if(MapObj && MapObj->isActive()) - { - // Set up map-space projection: (displayRect.left, top) maps to (0,0) screen - auto viewRect = MapObj->getDisplayRect(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(static_cast(viewRect.left), static_cast(viewRect.left + GameResolution.x), - static_cast(viewRect.top + GameResolution.y), static_cast(viewRect.top), -1, 1); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - MapObj->render(); - - // Restore screen-space projection - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } + WINDOWMANAGER.Draw(); VIDEODRIVER.SwapBuffers(); diff --git a/CMap.cpp b/CMap.cpp deleted file mode 100644 index d5afbc9..0000000 --- a/CMap.cpp +++ /dev/null @@ -1,2705 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CMap.h" -#include "CGame.h" -#include "CIO/CFile.h" -#include "CSurface.h" -#include "globals.h" -#include "gameData/LandscapeDesc.h" -#include "gameData/TerrainDesc.h" -#include -#include -#include -#include -#include - -void bobMAP::setName(const std::string& newName) -{ - name = newName; - if(name.size() > 20) - name.resize(20u); -} -void bobMAP::setAuthor(const std::string& newAuthor) -{ - author = newAuthor; - if(author.size() > 20) - author.resize(20); -} - -void bobMAP::initVertexCoords() -{ - for(unsigned j = 0; j < height; j++) - { - for(unsigned i = 0; i < width; i++) - { - EditorMapNode& curVertex = getVertex(i, j); - curVertex.VertexX = i; - curVertex.VertexY = j; - } - } - updateVertexCoords(); -} - -void bobMAP::updateVertexCoords() -{ - width_pixel = width * TR_W; - height_pixel = height * TR_H; - - Sint32 b = 0; - for(unsigned j = 0; j < height; j++) - { - Sint32 a; - if(j % 2u == 0u) - a = TR_W / 2u; - else - a = TR_W; - - for(unsigned i = 0; i < width; i++) - { - EditorMapNode& curVertex = getVertex(i, j); - curVertex.x = a; - curVertex.y = b - HEIGHT_FACTOR * (curVertex.h - 0x0A); - curVertex.z = HEIGHT_FACTOR * (curVertex.h - 0x0A); - a += TR_W; - } - b += TR_H; - } -} - -CMap::CMap(const boost::filesystem::path& filepath) -{ - constructMap(filepath); -} - -CMap::~CMap() -{ - destructMap(); -} - -void CMap::constructMap(const boost::filesystem::path& filepath, int width, int height, MapType type, - TriangleTerrainType texture, int border, int border_texture) -{ - map = nullptr; - displayRect.left = 0; - displayRect.top = 0; - displayRect.setSize(global::s2->GameResolution); - - if(!filepath.empty()) - { - map.reset((bobMAP*)CFile::open_file(filepath, WLD)); - if(map) - filepath_ = filepath; - } - - if(!map) - { - filepath_.clear(); - map = generateMap(width, height, type, texture, border, border_texture); - } - - // load the right MAP0x.LST for all pictures - loadMapPics(); - - // Populate s2IdToTerrain mapping before building calculation (needed by getTerrainDesc) - { - DescIdx lt(0); - for(DescIdx i(0); i.value < global::worldDesc.landscapes.size(); i.value++) - { - if(global::worldDesc.get(i).s2Id == map->type) - { - lt = i; - break; - } - } - for(DescIdx i(0); i.value < global::worldDesc.terrain.size(); i.value++) - { - const TerrainDesc& t = global::worldDesc.get(i); - if(t.landscape == lt) - { - if(map->s2IdToTerrain.size() <= t.s2Id) - map->s2IdToTerrain.resize(t.s2Id + 1); - map->s2IdToTerrain[t.s2Id] = i; - } - } - } - - CSurface::get_nodeVectors(*map); - - // for safety recalculate build and shadow data and test if fishes and water is correct - for(int i = 0; i < map->height; i++) - { - for(int j = 0; j < map->width; j++) - { - modifyBuild(Position(j, i)); - modifyShading(Position(j, i)); - modifyResource(Position(j, i)); - } - } - - active = true; - Vertex_ = {10, 10}; - RenderBuildHelp = false; - RenderBorders = true; - MouseBlit = correctMouseBlit(Vertex_); - ChangeSection_ = 1; - lastChangeSection = ChangeSection_; - ChangeSectionHexagonMode = true; - VertexFillRSU = true; - VertexFillUSD = true; - VertexFillRandom = false; - VertexActivityRandom = false; - // calculate the maximum number of vertices for cursor - VertexCounter = 0; - for(int i = -MAX_CHANGE_SECTION; i <= MAX_CHANGE_SECTION; i++) - { - if(abs(i) % 2 == 0) - for(int j = -MAX_CHANGE_SECTION; j <= MAX_CHANGE_SECTION; j++) - VertexCounter++; - else - for(int j = -MAX_CHANGE_SECTION; j <= MAX_CHANGE_SECTION - 1; j++) - VertexCounter++; - } - Vertices.resize(VertexCounter); - calculateVertices(); - setupVerticesActivity(); - mode = EDITOR_MODE_HEIGHT_RAISE; - lastMode = EDITOR_MODE_HEIGHT_RAISE; - modeContent = 0x00; - modeContent2 = 0x00; - modify = false; - MaxRaiseHeight = 0x3C; - MinReduceHeight = 0x00; - saveCurrentVertices = false; - undoBuffer.clear(); - redoBuffer.clear(); - - // we count the players, cause the original editor writes number of players to header no matter if they are set or - // not - int CountPlayers = 0; - // now for internal reasons save all players to a new array, also players with number greater than 7 - // initalize the internal array - for(int i = 0; i < MAXPLAYERS; i++) - { - PlayerHQx[i] = 0xFFFF; - PlayerHQy[i] = 0xFFFF; - } - // find out player positions - for(int y = 0; y < map->height; y++) - { - for(int x = 0; x < map->width; x++) - { - EditorMapNode& curVertex = map->getVertex(x, y); - if(curVertex.objectInfo == 0x80) - { - CountPlayers++; - // objectType is the number of the player - if(curVertex.objectType < MAXPLAYERS) - { - PlayerHQx[curVertex.objectType] = x; - PlayerHQy[curVertex.objectType] = y; - - // for compatibility with original settlers 2 save the first 7 player positions to the map header - // NOTE: this is already done by map loading, but to prevent inconsistence we do it again this way - if(curVertex.objectType < 0x07) - { - map->HQx[curVertex.objectType] = x; - map->HQy[curVertex.objectType] = y; - } - } - } - } - } - map->player = CountPlayers; - - HorizontalMovementLocked = false; - VerticalMovementLocked = false; - - // Init EditorWorld for TerrainRenderer rendering - terrainWorld_ = std::make_unique(MapExtent(map->width, map->height), 7u); - { - auto& gameWorld = terrainWorld_->getWorld(); - const auto& terrains = gameWorld.GetDescription().terrain; - std::array, 256> texIdToDesc; - for(unsigned i = 0; i < terrains.size(); i++) - { - auto idx = DescIdx(i); - texIdToDesc[terrains.get(idx).s2Id] = idx; - } - for(unsigned y = 0; y < map->height; y++) - { - for(unsigned x = 0; x < map->width; x++) - { - const auto& src = map->getVertex(x, y); - auto& dst = gameWorld.GetNodeWriteable(MapPoint(x, y)); - dst.altitude = src.h; - dst.t1 = texIdToDesc[src.rsuTexture]; - dst.t2 = texIdToDesc[src.usdTexture]; - dst.shadow = src.shading; - } - } - } -} -void CMap::destructMap() -{ - undoBuffer.clear(); - redoBuffer.clear(); - // free vertex array - Vertices.clear(); - // free map structure memory - map.reset(); - terrainWorld_.reset(); - filepath_.clear(); -} - -std::unique_ptr CMap::generateMap(int width, int height, MapType type, TriangleTerrainType texture, int border, - int border_texture) -{ - auto myMap = std::make_unique(); - - myMap->setName("Ohne Namen"); - myMap->width = width; - myMap->width_old = width; - myMap->height = height; - myMap->height_old = height; - myMap->type = type; - myMap->player = 0; - myMap->setAuthor("Niemand"); - for(int i = 0; i < 7; i++) - { - myMap->HQx[i] = 0xFFFF; - myMap->HQy[i] = 0xFFFF; - } - - myMap->vertex.resize(myMap->width * myMap->height); - - for(int j = 0; j < myMap->height; j++) - { - for(int i = 0; i < myMap->width; i++) - { - EditorMapNode& curVertex = myMap->getVertex(i, j); - curVertex.h = 0x0A; - - if((j < border || myMap->height - j <= border) || (i < border || myMap->width - i <= border)) - { - curVertex.rsuTexture = border_texture; - curVertex.usdTexture = border_texture; - } else - { - curVertex.rsuTexture = texture; - curVertex.usdTexture = texture; - } - - // initialize all other blocks -- outcommented blocks are recalculated at map load - curVertex.road = 0x00; - curVertex.objectType = 0x00; - curVertex.objectInfo = 0x00; - curVertex.animal = 0x00; - curVertex.unknown1 = 0x00; - // curVertex.build = 0x00; - curVertex.unknown2 = 0x07; - curVertex.unknown3 = 0x00; - // curVertex.resource = 0x00; - // curVertex.shading = 0x00; - curVertex.unknown5 = 0x00; - } - } - myMap->initVertexCoords(); - - return myMap; -} - -void CMap::rotateMap() -{ - // we allocate memory for the new triangle field but with x equals the height and y equals the width - std::vector new_vertex(map->vertex.size()); - - undoBuffer.clear(); - redoBuffer.clear(); - - // copy old to new while permuting x and y - for(int y = 0; y < map->height; y++) - { - for(int x = 0; x < map->width; x++) - { - new_vertex[x * map->height + (map->height - 1 - y)] = map->getVertex(x, y); - } - } - - // release old map and point to new - std::swap(map->vertex, new_vertex); - - // permute width and height - Uint16 tmp_height = map->height; - Uint16 tmp_height_old = map->height_old; - Uint16 tmp_height_pixel = map->height_pixel; - Uint16 tmp_width = map->width; - Uint16 tmp_width_old = map->width_old; - Uint16 tmp_width_pixel = map->width_pixel; - - map->height = tmp_width; - map->height_old = tmp_width_old; - map->height_pixel = tmp_width_pixel; - map->width = tmp_height; - map->width_old = tmp_height_old; - map->width_pixel = tmp_height_pixel; - - // permute player positions - // at first the internal array - swap(PlayerHQx, PlayerHQy); - // and now the map array - swap(map->HQx, map->HQy); - - // recalculate some values - map->initVertexCoords(); - for(int y = 0; y < map->height; y++) - { - for(int x = 0; x < map->width; x++) - { - modifyBuild(Position(x, y)); - modifyShading(Position(x, y)); - modifyResource(Position(x, y)); - CSurface::update_shading(*map, Position(x, y)); - } - } - - // reset mouse and view position to prevent failures - Vertex_ = {12, 12}; - MouseBlit = correctMouseBlit(Vertex_); - calculateVertices(); - displayRect.left = 0; - displayRect.top = 0; -} - -void CMap::MirrorMapOnXAxis() -{ - for(int y = 1; y < map->height / 2; y++) - { - for(int x = 0; x < map->width; x++) - { - map->getVertex(x, map->height - y) = map->getVertex(x, y); - } - } - - // recalculate some values - map->initVertexCoords(); - for(int y = 0; y < map->height; y++) - { - for(int x = 0; x < map->width; x++) - { - modifyBuild(Position(x, y)); - modifyShading(Position(x, y)); - modifyResource(Position(x, y)); - CSurface::update_shading(*map, Position(x, y)); - } - } -} - -void CMap::MirrorMapOnYAxis() -{ - for(int y = 0; y < map->height; y++) - { - for(int x = 0; x < map->width / 2; x++) - { - if(y % 2 != 0) - { - if(x != map->width / 2 - 1) - map->getVertex(map->width - 2 - x, y) = map->getVertex(x, y); - } else - map->getVertex(map->width - 1 - x, y) = map->getVertex(x, y); - } - } - - // recalculate some values - map->initVertexCoords(); - for(int y = 0; y < map->height; y++) - { - for(int x = 0; x < map->width; x++) - { - modifyBuild(Position(x, y)); - modifyShading(Position(x, y)); - modifyResource(Position(x, y)); - CSurface::update_shading(*map, Position(x, y)); - } - } -} - -void CMap::loadMapPics() -{ - std::string picFile, palFile; - switch(map->type) - { - case 0: - picFile = "DATA/MAP00.LST"; - palFile = "GFX/PALETTE/PAL5.BBM"; - break; - case 1: - picFile = "DATA/MAP01.LST"; - palFile = "GFX/PALETTE/PAL6.BBM"; - break; - case 2: - picFile = "DATA/MAP02.LST"; - palFile = "GFX/PALETTE/PAL7.BBM"; - break; - default: - picFile = "DATA/MAP00.LST"; - palFile = "GFX/PALETTE/PAL5.BBM"; - break; - } - // Load the palette file first so the LST load has it available - std::cout << "\nLoading palette from file: " << palFile << "..."; - global::loadPalette(global::gameDataFilePath / palFile); - // Load map graphics into typed archive (bitmap items only) - std::cout << "\nLoading file: " << picFile << "..."; - if(!global::loadBitmapArchive(ArchiveID::MAP00, global::gameDataFilePath / picFile, global::currentPalette)) - { - std::cout << "failure"; - } -} - -void CMap::unloadMapPics() -{ - auto it = global::typedArchives.find(ArchiveID::MAP00); - if(it != global::typedArchives.end()) - global::typedArchives.erase(it); -} - -void CMap::moveMap(Position offset) -{ - displayRect.setOrigin(displayRect.getOrigin() + offset); - // reset coords of displayRects when end of map is reached - if(displayRect.left >= map->width_pixel) - displayRect.move(Position(-map->width_pixel, 0)); - else if(displayRect.left <= -static_cast(displayRect.getSize().x)) - displayRect.setOrigin(Position(map->width_pixel - displayRect.getSize().x, displayRect.top)); - - if(displayRect.top >= map->height_pixel) - displayRect.move(Position(0, -map->height_pixel)); - else if(displayRect.top <= -static_cast(displayRect.getSize().y)) - displayRect.setOrigin(Position(displayRect.left, map->height_pixel - displayRect.getSize().y)); -} - -void CMap::setMouseData(const SDL_MouseMotionEvent& motion) -{ - // following code important for blitting the right field of the map - // Are we scrolling? - if(startScrollPos) - { - assert(motion.state & SDL_BUTTON(3)); - Position offset = Position(motion.x, motion.y) - *startScrollPos; - if(HorizontalMovementLocked) - offset.x = 0; - if(VerticalMovementLocked) - offset.y = 0; - moveMap(offset); - - // this whole "warping-thing" is to prevent cursor-moving WITHIN the window while user moves over the map - SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); - SDL_WarpMouseInWindow(nullptr, startScrollPos->x, startScrollPos->y); - SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE); - } - - storeVerticesFromMouse(Position(motion.x, motion.y), motion.state); -} - -void CMap::onLeftMouseDown(const Point32& pos) -{ // find out if user clicked on one of the game menu pictures - // we start with lower menubar - const Point32 displaySize(displayRect.getSize()); - if(pos.x >= (displaySize.x / 2 - 236) && pos.x <= (displaySize.x / 2 - 199) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the height-mode picture was clicked - mode = EDITOR_MODE_HEIGHT_RAISE; - } else if(pos.x >= (displaySize.x / 2 - 199) && pos.x <= (displaySize.x / 2 - 162) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the texture-mode picture was clicked - mode = EDITOR_MODE_TEXTURE; - // callback::EditorTextureMenu() — removed, old menu system deleted - } else if(pos.x >= (displaySize.x / 2 - 162) && pos.x <= (displaySize.x / 2 - 125) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the tree-mode picture was clicked - mode = EDITOR_MODE_TREE; - // callback::EditorTreeMenu() — removed, old menu system deleted - } else if(pos.x >= (displaySize.x / 2 - 125) && pos.x <= (displaySize.x / 2 - 88) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the resource-mode picture was clicked - mode = EDITOR_MODE_RESOURCE_RAISE; - // callback::EditorResourceMenu() — removed, old menu system deleted - } else if(pos.x >= (displaySize.x / 2 - 88) && pos.x <= (displaySize.x / 2 - 51) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the landscape-mode picture was clicked - mode = EDITOR_MODE_LANDSCAPE; - // callback::EditorLandscapeMenu() — removed, old menu system deleted - } else if(pos.x >= (displaySize.x / 2 - 51) && pos.x <= (displaySize.x / 2 - 14) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the animal-mode picture was clicked - mode = EDITOR_MODE_ANIMAL; - // callback::EditorAnimalMenu() — removed, old menu system deleted - } else if(pos.x >= (displaySize.x / 2 - 14) && pos.x <= (displaySize.x / 2 + 23) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the player-mode picture was clicked - mode = EDITOR_MODE_FLAG; - ChangeSection_ = 0; - setupVerticesActivity(); - // callback::EditorPlayerMenu() — removed, old menu system deleted - } else if(pos.x >= (displaySize.x / 2 + 96) && pos.x <= (displaySize.x / 2 + 133) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the build-help picture was clicked - RenderBuildHelp = !RenderBuildHelp; - } else if(pos.x >= (displaySize.x / 2 + 131) && pos.x <= (displaySize.x / 2 + 168) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the minimap picture was clicked - // callback::MinimapMenu() — removed, old menu system deleted - } else if(pos.x >= (displaySize.x / 2 + 166) && pos.x <= (displaySize.x / 2 + 203) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the create-world picture was clicked - // callback::EditorCreateMenu() — removed, old menu system deleted - } else if(pos.x >= (displaySize.x / 2 + 203) && pos.x <= (displaySize.x / 2 + 240) && pos.y >= (displaySize.y - 35) - && pos.y <= (displaySize.y - 3)) - { - // the editor-main-menu picture was clicked - // callback::EditorMainMenu() — removed, old menu system deleted - } - // now we check the right menubar - else if(pos.x >= (displaySize.x - 37) && pos.x <= (displaySize.x) && pos.y >= (displaySize.y / 2 + 162) - && pos.y <= (displaySize.y / 2 + 199)) - { - // the bugkill picture was clicked for quickload - // callback::PleaseWait() — removed, old menu system deleted - // we have to close the windows and initialize them again to prevent failures - // callback::EditorCursorMenu() — removed, old menu system deleted - // callback::EditorTextureMenu() — removed, old menu system deleted - // callback::EditorTreeMenu() — removed, old menu system deleted - // callback::EditorLandscapeMenu() — removed, old menu system deleted - // callback::MinimapMenu() — removed, old menu system deleted - // callback::EditorResourceMenu() — removed, old menu system deleted - // callback::EditorAnimalMenu() — removed, old menu system deleted - // callback::EditorPlayerMenu() — removed, old menu system deleted - - destructMap(); - constructMap(global::userMapsPath / "quicksave.swd"); - // callback::PleaseWait() — removed, old menu system deleted - } else if(pos.x >= (displaySize.x - 37) && pos.x <= (displaySize.x) && pos.y >= (displaySize.y / 2 + 200) - && pos.y <= (displaySize.y / 2 + 237)) - { - // the bugkill picture was clicked for quicksave - // callback::PleaseWait() — removed, old menu system deleted - if(!CFile::save_file(global::userMapsPath / "quicksave.swd", SWD, getMap())) - { - // callback::ShowStatus() — removed, old menu system deleted - // callback::ShowStatus() — removed, old menu system deleted - } - // callback::PleaseWait() — removed, old menu system deleted - } else if(pos.x >= (displaySize.x - 37) && pos.x <= (displaySize.x) && pos.y >= (displaySize.y / 2 - 239) - && pos.y <= (displaySize.y / 2 - 202)) - { - // the cursor picture was clicked - // callback::EditorCursorMenu() — removed, old menu system deleted - } else - { - // no picture was clicked - // touch vertex data - modify = true; - saveCurrentVertices = true; - } -} - -void CMap::setMouseData(const SDL_MouseButtonEvent& button) -{ - if(button.state == SDL_PRESSED) - { - if(button.button == SDL_BUTTON_LEFT) - onLeftMouseDown({button.x, button.y}); - else if(button.button == SDL_BUTTON_RIGHT) - startScrollPos = Position(button.x, button.y); - } else if(button.state == SDL_RELEASED) - { - // stop touching vertex data - if(button.button == SDL_BUTTON_LEFT) - modify = false; - else if(button.button == SDL_BUTTON_RIGHT) - startScrollPos = std::nullopt; - } -} - -namespace { -SavedVertex saveVertex(Position pt, const bobMAP& map) -{ - SavedVertex res; - res.pos = pt; - for(int i = pt.x - SavedVertex::NODES_PER_DIR, k = 0; i <= pt.x + SavedVertex::NODES_PER_DIR; i++, k++) - { - for(int j = pt.y - SavedVertex::NODES_PER_DIR, l = 0; j <= pt.y + SavedVertex::NODES_PER_DIR; j++, l++) - { - // Correct i and j to take wrap around map borders into account - int m = i; - if(m < 0) - m += map.width; - else if(m >= map.width) - m -= map.width; - int n = j; - if(n < 0) - n += map.height; - else if(n >= map.height) - n -= map.height; - res.PointsArroundVertex[l][k] = map.getVertex(m, n); - } - } - return res; -} - -void restoreVertex(const SavedVertex& vertex, bobMAP& map) -{ - for(int i = vertex.pos.x - SavedVertex::NODES_PER_DIR, k = 0; i <= vertex.pos.x + SavedVertex::NODES_PER_DIR; - i++, k++) - { - for(int j = vertex.pos.y - SavedVertex::NODES_PER_DIR, l = 0; j <= vertex.pos.y + SavedVertex::NODES_PER_DIR; - j++, l++) - { - int m = i; - if(m < 0) - m += map.width; - else if(m >= map.width) - m -= map.width; - int n = j; - if(n < 0) - n += map.height; - else if(n >= map.height) - n -= map.height; - map.getVertex(m, n) = vertex.PointsArroundVertex[l][k]; - } - } -} -} // namespace - -void CMap::setKeyboardData(const SDL_KeyboardEvent& key) -{ - if(key.type == SDL_KEYDOWN) - { - switch(key.keysym.sym) - { - case SDLK_LSHIFT: - if(mode == EDITOR_MODE_HEIGHT_RAISE) - mode = EDITOR_MODE_HEIGHT_REDUCE; - else if(mode == EDITOR_MODE_RESOURCE_RAISE) - mode = EDITOR_MODE_RESOURCE_REDUCE; - else if(mode == EDITOR_MODE_FLAG) - mode = EDITOR_MODE_FLAG_DELETE; - break; - case SDLK_LALT: - if(mode == EDITOR_MODE_HEIGHT_RAISE) - mode = EDITOR_MODE_HEIGHT_PLANE; - break; - case SDLK_INSERT: - if(mode == EDITOR_MODE_HEIGHT_RAISE || mode == EDITOR_MODE_HEIGHT_REDUCE) - { - if(MaxRaiseHeight > 0x00) - MaxRaiseHeight--; - } - break; - case SDLK_HOME: - if(mode == EDITOR_MODE_HEIGHT_RAISE || mode == EDITOR_MODE_HEIGHT_REDUCE) - { - MaxRaiseHeight = 0x3C; - } - break; - case SDLK_PAGEUP: - if(mode == EDITOR_MODE_HEIGHT_RAISE || mode == EDITOR_MODE_HEIGHT_REDUCE) - { - if(MaxRaiseHeight < 0x3C) - MaxRaiseHeight++; - } - break; - case SDLK_DELETE: - if(mode == EDITOR_MODE_HEIGHT_RAISE || mode == EDITOR_MODE_HEIGHT_REDUCE) - { - if(MinReduceHeight > 0x00) - MinReduceHeight--; - } - break; - case SDLK_END: - if(mode == EDITOR_MODE_HEIGHT_RAISE || mode == EDITOR_MODE_HEIGHT_REDUCE) - { - MinReduceHeight = 0x00; - } - break; - case SDLK_PAGEDOWN: - if(mode == EDITOR_MODE_HEIGHT_RAISE || mode == EDITOR_MODE_HEIGHT_REDUCE) - { - if(MinReduceHeight < 0x3C) - MinReduceHeight++; - } - break; - case SDLK_LCTRL: - lastMode = mode; - mode = EDITOR_MODE_CUT; - break; - case SDLK_b: - if(mode != EDITOR_MODE_HEIGHT_MAKE_BIG_HOUSE && mode != EDITOR_MODE_TEXTURE_MAKE_HARBOUR) - { - lastMode = mode; - lastChangeSection = ChangeSection_; - ChangeSection_ = 0; - setupVerticesActivity(); - mode = EDITOR_MODE_HEIGHT_MAKE_BIG_HOUSE; - } - break; - case SDLK_h: - if(mode != EDITOR_MODE_HEIGHT_MAKE_BIG_HOUSE && mode != EDITOR_MODE_TEXTURE_MAKE_HARBOUR) - { - lastMode = mode; - lastChangeSection = ChangeSection_; - ChangeSection_ = 0; - setupVerticesActivity(); - mode = EDITOR_MODE_TEXTURE_MAKE_HARBOUR; - } - break; - case SDLK_r: - // callback::PleaseWait() — removed, old menu system deleted - rotateMap(); - rotateMap(); - // callback::PleaseWait() — removed, old menu system deleted - break; - case SDLK_x: - // callback::PleaseWait() — removed, old menu system deleted - MirrorMapOnXAxis(); - // callback::PleaseWait() — removed, old menu system deleted - break; - case SDLK_y: - // callback::PleaseWait() — removed, old menu system deleted - MirrorMapOnYAxis(); - // callback::PleaseWait() — removed, old menu system deleted - break; - case SDLK_KP_PLUS: - if(ChangeSection_ < MAX_CHANGE_SECTION) - { - ChangeSection_++; - setupVerticesActivity(); - } - break; - case SDLK_KP_MINUS: - if(ChangeSection_ > 0) - { - ChangeSection_--; - setupVerticesActivity(); - } - break; - case SDLK_1: - case SDLK_KP_1: - ChangeSection_ = 0; - setupVerticesActivity(); - break; - case SDLK_2: - case SDLK_KP_2: - ChangeSection_ = 1; - setupVerticesActivity(); - break; - case SDLK_3: - case SDLK_KP_3: - ChangeSection_ = 2; - setupVerticesActivity(); - break; - case SDLK_4: - case SDLK_KP_4: - ChangeSection_ = 3; - setupVerticesActivity(); - break; - case SDLK_5: - case SDLK_KP_5: - ChangeSection_ = 4; - setupVerticesActivity(); - break; - case SDLK_6: - case SDLK_KP_6: - ChangeSection_ = 5; - setupVerticesActivity(); - break; - case SDLK_7: - case SDLK_KP_7: - ChangeSection_ = 6; - setupVerticesActivity(); - break; - case SDLK_8: - case SDLK_KP_8: - ChangeSection_ = 7; - setupVerticesActivity(); - break; - case SDLK_9: - case SDLK_KP_9: - ChangeSection_ = 8; - setupVerticesActivity(); - break; - case SDLK_SPACE: RenderBuildHelp = !RenderBuildHelp; break; - case SDLK_F11: RenderBorders = !RenderBorders; break; - case SDLK_q: - if(!saveCurrentVertices) - { - if(SDL_GetModState() & (KMOD_LSHIFT | KMOD_RSHIFT)) - { - if(!redoBuffer.empty()) - { - undoBuffer.push_back(saveVertex(redoBuffer.back().pos, *map)); - restoreVertex(redoBuffer.back(), *map); - redoBuffer.pop_back(); - } - } else if(!undoBuffer.empty()) - { - redoBuffer.push_back(saveVertex(undoBuffer.back().pos, *map)); - restoreVertex(undoBuffer.back(), *map); - undoBuffer.pop_back(); - } - } - break; - case SDLK_UP: - case SDLK_DOWN: - case SDLK_LEFT: - case SDLK_RIGHT: - { - Position offset{key.keysym.sym == SDLK_LEFT ? -100 : (key.keysym.sym == SDLK_RIGHT ? 100 : 0), - key.keysym.sym == SDLK_UP ? -100 : (key.keysym.sym == SDLK_DOWN ? 100 : 0)}; - moveMap(offset); - } - break; - case SDLK_F1: // help menu - // callback::EditorHelpMenu() — removed, old menu system deleted - break; - case SDLK_g: // convert map to greenland - // callback::PleaseWait() — removed, old menu system deleted - - // we have to close the windows and initialize them again to prevent failures - // callback::EditorCursorMenu() — removed, old menu system deleted - // callback::EditorTextureMenu() — removed, old menu system deleted - // callback::EditorTreeMenu() — removed, old menu system deleted - // callback::EditorLandscapeMenu() — removed, old menu system deleted - // callback::MinimapMenu() — removed, old menu system deleted - // callback::EditorResourceMenu() — removed, old menu system deleted - // callback::EditorAnimalMenu() — removed, old menu system deleted - // callback::EditorPlayerMenu() — removed, old menu system deleted - - map->type = MAP_GREENLAND; - unloadMapPics(); - loadMapPics(); - - // callback::PleaseWait() — removed, old menu system deleted - break; - case SDLK_o: // convert map to wasteland - // callback::PleaseWait() — removed, old menu system deleted - - // we have to close the windows and initialize them again to prevent failures - // callback::EditorCursorMenu() — removed, old menu system deleted - // callback::EditorTextureMenu() — removed, old menu system deleted - // callback::EditorTreeMenu() — removed, old menu system deleted - // callback::EditorLandscapeMenu() — removed, old menu system deleted - // callback::MinimapMenu() — removed, old menu system deleted - // callback::EditorResourceMenu() — removed, old menu system deleted - // callback::EditorAnimalMenu() — removed, old menu system deleted - // callback::EditorPlayerMenu() — removed, old menu system deleted - - map->type = MAP_WASTELAND; - unloadMapPics(); - loadMapPics(); - - // callback::PleaseWait() — removed, old menu system deleted - break; - case SDLK_w: // convert map to winterland - // callback::PleaseWait() — removed, old menu system deleted - - // we have to close the windows and initialize them again to prevent failures - // callback::EditorCursorMenu() — removed, old menu system deleted - // callback::EditorTextureMenu() — removed, old menu system deleted - // callback::EditorTreeMenu() — removed, old menu system deleted - // callback::EditorLandscapeMenu() — removed, old menu system deleted - // callback::MinimapMenu() — removed, old menu system deleted - // callback::EditorResourceMenu() — removed, old menu system deleted - // callback::EditorAnimalMenu() — removed, old menu system deleted - // callback::EditorPlayerMenu() — removed, old menu system deleted - - map->type = MAP_WINTERLAND; - unloadMapPics(); - loadMapPics(); - - // callback::PleaseWait() — removed, old menu system deleted - break; - - case SDLK_F9: // lock horizontal movement - HorizontalMovementLocked = !HorizontalMovementLocked; - - break; - case SDLK_F10: // lock vertical movement - // VerticalMovementLocked = !VerticalMovementLocked; - default: break; - } - } else if(key.type == SDL_KEYUP) - { - switch(key.keysym.sym) - { - case SDLK_LSHIFT: // user probably released EDITOR_MODE_HEIGHT_REDUCE - if(mode == EDITOR_MODE_HEIGHT_REDUCE) - mode = EDITOR_MODE_HEIGHT_RAISE; - else if(mode == EDITOR_MODE_RESOURCE_REDUCE) - mode = EDITOR_MODE_RESOURCE_RAISE; - else if(mode == EDITOR_MODE_FLAG_DELETE) - mode = EDITOR_MODE_FLAG; - break; - case SDLK_LALT: // user probably released EDITOR_MODE_HEIGHT_PLANE - if(mode == EDITOR_MODE_HEIGHT_PLANE) - mode = EDITOR_MODE_HEIGHT_RAISE; - break; - case SDLK_LCTRL: // user probably released EDITOR_MODE_CUT - mode = lastMode; - break; - case SDLK_b: // user probably released EDITOR_MODE_HEIGHT_MAKE_BIG_HOUSE - case SDLK_h: // user probably released EDITOR_MODE_TEXTURE_MAKE_HARBOUR - mode = lastMode; - ChangeSection_ = lastChangeSection; - setupVerticesActivity(); - break; - default: break; - } - } -} - -void CMap::storeVerticesFromMouse(Position mousePos, Uint8 /*MouseState*/) -{ - // if user raises or reduces the height of a vertex, don't let the cursor jump to another vertex - // if ( (MouseState == SDL_PRESSED) && (mode == EDITOR_MODE_HEIGHT_RAISE || mode == EDITOR_MODE_HEIGHT_REDUCE) ) - // return; - - int X = 0, Xeven = 0, Xodd = 0; - int Y = 0, MousePosY = 0; - - // get X - // following out commented lines are the correct ones, but for tolerance (to prevent to early jumps of the cursor) - // we subtract "TR_W/2" Xeven = (MouseX + displayRect.left) / TR_W; - Xeven = (mousePos.x + displayRect.left - TR_W / 2) / TR_W; - if(Xeven < 0) - Xeven += (map->width); - else if(Xeven > map->width - 1) - Xeven -= (map->width - 1); - // Add rows are already shifted by TR_W / 2 - Xodd = (mousePos.x + displayRect.left) / TR_W; - // Xodd = (mousePos.x + displayRect.left) / TR_W; - if(Xodd < 0) - Xodd += (map->width - 1); - else if(Xodd > map->width - 1) - Xodd -= (map->width); - - MousePosY = mousePos.y + displayRect.top; - // correct mouse position Y if displayRect is outside map edges - if(MousePosY < 0) - MousePosY += map->height_pixel; - else if(MousePosY > map->height_pixel) - MousePosY = mousePos.y - (map->height_pixel - displayRect.top); - - // get Y - for(int j = 0; j < map->height; j++) - { - if(j % 2 == 0) - { - // subtract "TR_H/2" is for tolerance, we did the same for X - if((MousePosY - TR_H / 2) > map->getVertex(Xeven, j).y) - Y++; - else - { - X = Xodd; - break; - } - } else - { - if((MousePosY - TR_H / 2) > map->getVertex(Xodd, j).y) - Y++; - else - { - X = Xeven; - break; - } - } - } - if(Y >= map->height) - { - Y -= map->height; - X = Y % 2 == 0 ? Xeven : Xodd; - } - - Vertex_ = {X, Y}; - - MouseBlit = correctMouseBlit(Vertex_); - - calculateVertices(); -} - -Position CMap::correctMouseBlit(Position vertexPos) const -{ - const auto& vertex = map->getVertex(vertexPos); - Position newBlit(vertex.x, vertex.y); - if(newBlit.x < displayRect.left) - newBlit.x += map->width_pixel; - else if(newBlit.x > displayRect.right) - newBlit.x -= map->width_pixel; - if(newBlit.y < displayRect.top) - newBlit.y += map->height_pixel; - else if(newBlit.y > displayRect.bottom) - newBlit.y -= map->height_pixel; - newBlit -= displayRect.getOrigin(); - - return newBlit; -} - -void CMap::render() -{ - // check if game resolution has been changed - if(displayRect.getSize() != global::s2->GameResolution) - { - displayRect.setSize(global::s2->GameResolution); - } - - // touch vertex data if user modifies it - if(modify) - { - modifyVertex(); - } - - // 1. Draw terrain - if(terrainWorld_ && !map->vertex.empty()) - { - Position firstPt(std::max(0, displayRect.left / TR_W - 1), - std::max(0, displayRect.top / TR_H - 1)); - Position lastPt(std::min(map->width - 1, displayRect.right / TR_W + 1), - std::min(map->height - 1, displayRect.bottom / TR_H + 1)); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(static_cast(displayRect.left), - static_cast(displayRect.right), - static_cast(displayRect.bottom), - static_cast(displayRect.top), -100, 100); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - terrainWorld_->draw(firstPt, lastPt); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - - // 2. Draw editor UI chrome on top (screen-space) - // Switch to screen-space projection for UI chrome - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0, static_cast(displayRect.getSize().x), static_cast(displayRect.getSize().y), 0, -1, - 1); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_SCISSOR_TEST); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - // draw pictures to cursor position - int symbol_index, symbol_index2 = -1; - switch(mode) - { - case EDITOR_MODE_CUT: symbol_index = CURSOR_SYMBOL_SCISSORS; break; - case EDITOR_MODE_TREE: symbol_index = CURSOR_SYMBOL_TREE; break; - case EDITOR_MODE_HEIGHT_RAISE: symbol_index = CURSOR_SYMBOL_ARROW_UP; break; - case EDITOR_MODE_HEIGHT_REDUCE: symbol_index = CURSOR_SYMBOL_ARROW_DOWN; break; - case EDITOR_MODE_HEIGHT_PLANE: - symbol_index = CURSOR_SYMBOL_ARROW_UP; - symbol_index2 = CURSOR_SYMBOL_ARROW_DOWN; - break; - case EDITOR_MODE_HEIGHT_MAKE_BIG_HOUSE: symbol_index = MAPPIC_ARROWCROSS_RED_HOUSE_BIG; break; - case EDITOR_MODE_TEXTURE: symbol_index = CURSOR_SYMBOL_TEXTURE; break; - case EDITOR_MODE_TEXTURE_MAKE_HARBOUR: symbol_index = MAPPIC_ARROWCROSS_RED_HOUSE_HARBOUR; break; - case EDITOR_MODE_LANDSCAPE: symbol_index = CURSOR_SYMBOL_LANDSCAPE; break; - case EDITOR_MODE_FLAG: - case EDITOR_MODE_FLAG_DELETE: symbol_index = CURSOR_SYMBOL_FLAG; break; - case EDITOR_MODE_RESOURCE_REDUCE: symbol_index = CURSOR_SYMBOL_PICKAXE_MINUS; break; - case EDITOR_MODE_RESOURCE_RAISE: symbol_index = CURSOR_SYMBOL_PICKAXE_PLUS; break; - case EDITOR_MODE_ANIMAL: symbol_index = CURSOR_SYMBOL_ANIMAL; break; - default: symbol_index = CURSOR_SYMBOL_ARROW_UP; break; - } - for(int i = 0; i < VertexCounter; i++) - { - if(!Vertices[i].active) - continue; - const bool isMapPicSymbol = - (mode == EDITOR_MODE_HEIGHT_MAKE_BIG_HOUSE || mode == EDITOR_MODE_TEXTURE_MAKE_HARBOUR); - if(isMapPicSymbol) - { - // MAPPIC textures - Texture::getTexture(ArchiveID::MAP00, symbol_index) - .draw(Position(Vertices[i].blit.x - 10, Vertices[i].blit.y - 10)); - } else - { - // Cursor symbols from EDITBOB.LST - Texture::getTexture(ArchiveID::EDITBOB, symbol_index) - .draw(Position(Vertices[i].blit.x - 10, Vertices[i].blit.y - 10)); - if(symbol_index2 >= 0) - Texture::getTexture(ArchiveID::EDITBOB, symbol_index2) - .draw(Position(Vertices[i].blit.x, Vertices[i].blit.y - 7)); - } - } - - // draw the frame - if(displayRect.getSize() == Extent(640, 480)) - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480).draw(Position(0, 0)); - else if(displayRect.getSize() == Extent(800, 600)) - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_800_600).draw(Position(0, 0)); - else if(displayRect.getSize() == Extent(1024, 768)) - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_1024_768).draw(Position(0, 0)); - else if(displayRect.getSize() == Extent(1280, 1024)) - { - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_LEFT_1280_1024).draw(Position(0, 0)); - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_RIGHT_1280_1024).draw(Position(640, 0)); - } else - { - // draw the corners - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480).draw(Rect(0, 0, 150, 150), Rect(0, 0, 150, 150)); - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) - .draw(Rect(0, static_cast(displayRect.getSize().y) - 150, 150, 150), Rect(0, 480 - 150, 150, 150)); - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) - .draw(Rect(static_cast(displayRect.getSize().x) - 150, 0, 150, 150), Rect(640 - 150, 0, 150, 150)); - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) - .draw(Rect(static_cast(displayRect.getSize().x) - 150, static_cast(displayRect.getSize().y) - 150, - 150, 150), - Rect(640 - 150, 480 - 150, 150, 150)); - // draw the edges - unsigned x = 150, y = 150; - while(x + 150 < displayRect.getSize().x) - { - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) - .draw(Rect(static_cast(x), 0, 150, 12), Rect(150, 0, 150, 12)); - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) - .draw(Rect(static_cast(x), static_cast(displayRect.getSize().y) - 12, 150, 12), - Rect(150, 0, 150, 12)); - x += 150; - } - while(y + 150 < displayRect.getSize().y) - { - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) - .draw(Rect(0, static_cast(y), 12, 150), Rect(0, 150, 12, 150)); - Texture::getTexture(ArchiveID::EDITRES, MAINFRAME_640_480) - .draw(Rect(static_cast(displayRect.getSize().x) - 12, static_cast(y), 12, 150), - Rect(0, 150, 12, 150)); - y += 150; - } - } - - // draw the statues at the frame - Texture::getTexture(ArchiveID::EDITRES, STATUE_UP_LEFT).draw(Position(12, 12)); - Texture::getTexture(ArchiveID::EDITRES, STATUE_UP_RIGHT) - .draw(Position(static_cast(displayRect.getSize().x) - - static_cast(global::getBitmapSize(ArchiveID::EDITRES, STATUE_UP_RIGHT).x) - 12, - 12)); - Texture::getTexture(ArchiveID::EDITRES, STATUE_DOWN_LEFT) - .draw(Position(12, static_cast(displayRect.getSize().y) - - static_cast(global::getBitmapSize(ArchiveID::EDITRES, STATUE_DOWN_LEFT).y) - 12)); - Texture::getTexture(ArchiveID::EDITRES, STATUE_DOWN_RIGHT) - .draw(Position(static_cast(displayRect.getSize().x) - - static_cast(global::getBitmapSize(ArchiveID::EDITRES, STATUE_DOWN_RIGHT).x) - 12, - static_cast(displayRect.getSize().y) - - static_cast(global::getBitmapSize(ArchiveID::EDITRES, STATUE_DOWN_RIGHT).y) - 12)); - - // lower menubar - const Position menubarPos = - Position(static_cast(displayRect.getSize().x) / 2, static_cast(displayRect.getSize().y)); - // draw lower menubar - Texture::getTexture(ArchiveID::EDITRES, MENUBAR) - .draw(Position(menubarPos.x - static_cast(global::getBitmapSize(ArchiveID::EDITRES, MENUBAR).x) / 2, - menubarPos.y - static_cast(global::getBitmapSize(ArchiveID::EDITRES, MENUBAR).y))); - - // draw pictures to lower menubar - // backgrounds (use button background texture for each slot) - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x - 236, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x - 199, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x - 162, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x - 125, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x - 88, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x - 51, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x - 14, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x + 92, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x + 129, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x + 166, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(menubarPos.x + 203, menubarPos.y - 36, 37, 32), Rect(0, 0, 37, 32)); - - // pictures - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_HEIGHT).draw(Position(menubarPos.x - 232, menubarPos.y - 35)); - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_TEXTURE).draw(Position(menubarPos.x - 195, menubarPos.y - 35)); - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_TREE).draw(Position(menubarPos.x - 158, menubarPos.y - 37)); - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_RESOURCE).draw(Position(menubarPos.x - 121, menubarPos.y - 32)); - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_LANDSCAPE).draw(Position(menubarPos.x - 84, menubarPos.y - 37)); - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_ANIMAL).draw(Position(menubarPos.x - 48, menubarPos.y - 36)); - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_PLAYER).draw(Position(menubarPos.x - 10, menubarPos.y - 34)); - - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_BUILDHELP).draw(Position(menubarPos.x + 96, menubarPos.y - 35)); - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_MINIMAP).draw(Position(menubarPos.x + 131, menubarPos.y - 37)); - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_NEWWORLD).draw(Position(menubarPos.x + 166, menubarPos.y - 37)); - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_COMPUTER).draw(Position(menubarPos.x + 207, menubarPos.y - 35)); - - // right menubar: draw the MENUBAR sprite rotated 270 degrees via OpenGL - { - auto& tex = Texture::getTexture(ArchiveID::EDITRES, MENUBAR); - const auto sz = tex.getSize(); - const Position rmPos = - Position(static_cast(displayRect.getSize().x), static_cast(displayRect.getSize().y) / 2); - - if(tex.isValid()) - { - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - // Shift right menubar 1px right, 2px down to align button backgrounds - glTranslatef(static_cast(rmPos.x - static_cast(sz.y) / 2 + 1), static_cast(rmPos.y + 2), - 0.f); - glRotatef(270.f, 0.f, 0.f, 1.f); - tex.draw(Rect(-static_cast(sz.x) / 2, -static_cast(sz.y) / 2, sz.x, sz.y)); - glPopMatrix(); - } - } - - // draw pictures to right menubar - const Position rightMenubarPos = - Position(static_cast(displayRect.getSize().x), static_cast(displayRect.getSize().y) / 2); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 239, 32, 37), Rect(0, 0, 32, 37)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 202, 32, 37), Rect(0, 0, 32, 37)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 165, 32, 37), Rect(0, 0, 32, 37)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 128, 32, 37), Rect(0, 0, 32, 37)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y - 22, 32, 37), Rect(0, 0, 32, 37)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 15, 32, 37), Rect(0, 0, 32, 37)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 52, 32, 37), Rect(0, 0, 32, 37)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 89, 32, 37), Rect(0, 0, 32, 37)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 126, 32, 37), Rect(0, 0, 32, 37)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 163, 32, 37), Rect(0, 0, 32, 37)); - Texture::getTexture(ArchiveID::EDITIO, BUTTON_GREEN1_DARK) - .draw(Rect(rightMenubarPos.x - 36, rightMenubarPos.y + 200, 32, 37), Rect(0, 0, 32, 37)); - - // pictures - Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP) - .draw(Position(rightMenubarPos.x - 33, rightMenubarPos.y - 237)); - Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN) - .draw(Position(rightMenubarPos.x - 20, rightMenubarPos.y - 235)); - Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_DOWN) - .draw(Position(rightMenubarPos.x - 33, rightMenubarPos.y - 220)); - Texture::getTexture(ArchiveID::EDITBOB, CURSOR_SYMBOL_ARROW_UP) - .draw(Position(rightMenubarPos.x - 20, rightMenubarPos.y - 220)); - // bugkill picture for quickload - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_BUGKILL) - .draw(Position(rightMenubarPos.x - 37, rightMenubarPos.y + 162)); - // bugkill picture for quicksave - Texture::getTexture(ArchiveID::EDITIO, MENUBAR_BUGKILL) - .draw(Position(rightMenubarPos.x - 37, rightMenubarPos.y + 200)); - - // Restore matrices - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -} - -static const TerrainDesc* getTerrainDesc(const bobMAP& map, Uint8 rawTextureId) -{ - const Uint8 s2Id = rawTextureId & ~0x40; - if(s2Id < map.s2IdToTerrain.size()) - { - const auto idx = map.s2IdToTerrain[s2Id]; - if(idx) - return &global::worldDesc.get(idx); - } - return nullptr; -} - -static bool nodeHasTerrainFlag(const bobMAP& map, const EditorMapNode& node, ETerrain flag, bool checkBoth = true) -{ - const auto* rsu = getTerrainDesc(map, node.rsuTexture); - const auto* usd = getTerrainDesc(map, node.usdTexture); - if(checkBoth) - return rsu && usd && rsu->Is(flag) && usd->Is(flag); - return (rsu && rsu->Is(flag)) || (usd && usd->Is(flag)); -} - -static void getTriangleColor(const bobMAP& map, Uint8 rawTextureId, Sint16& r, Sint16& g, Sint16& b) -{ - const auto* desc = getTerrainDesc(map, rawTextureId); - if(desc) - { - r = (desc->minimapColor >> 16) & 0xFF; - g = (desc->minimapColor >> 8) & 0xFF; - b = desc->minimapColor & 0xFF; - return; - } - // Fallback: grey for unknown terrain (e.g. MEADOW_MIXED sentinel) - r = 128; - g = 128; - b = 128; -} - -void CMap::drawMinimap(std::vector& pixels, int w, int h, int& scale) -{ - // Scale factor to keep minimap within a reasonable size - int sx = (map->width > 256 ? map->width / 256 : 1); - int sy = (map->height > 256 ? map->height / 256 : 1); - - // Keep aspect ratio uniform - scale = (sx > sy ? sx : sy); - - // Ensure pixel buffer is the right size - pixels.assign(static_cast(w) * h, 0); - - for(int y = 0; y < map->height; y++) - { - if(y % scale != 0) - continue; - - for(int x = 0; x < map->width; x++) - { - if(x % scale != 0) - continue; - - Sint16 r, g, b; - getTriangleColor(*map, map->getVertex(x, y).rsuTexture, r, g, b); - - const int py = y / scale; - const int px = x / scale; - if(py >= h || px >= w) - continue; - - auto& pixel = pixels[static_cast(py) * w + px]; - - Sint32 vertexLighting = map->getVertex(x, y).i; - r = ((r * vertexLighting) >> 16); - g = ((g * vertexLighting) >> 16); - b = ((b * vertexLighting) >> 16); - const auto r8 = (Uint8)(r > 255 ? 255 : (r < 0 ? 0 : r)); - const auto g8 = (Uint8)(g > 255 ? 255 : (g < 0 ? 0 : g)); - const auto b8 = (Uint8)(b > 255 ? 255 : (b < 0 ? 0 : b)); - pixel = (0xFFu << 24) | (r8 << 16) | (g8 << 8) | b8; - } - } -} - -void CMap::modifyVertex() -{ - static Uint32 TimeOfLastModification = SDL_GetTicks(); - - if((SDL_GetTicks() - TimeOfLastModification) < 5) - return; - else - TimeOfLastModification = SDL_GetTicks(); - - // save vertices for "undo" - if(saveCurrentVertices) - { - // Cannot redo anymore - redoBuffer.clear(); - undoBuffer.push_back(saveVertex(Vertex_, *map)); - saveCurrentVertices = false; - } - - if(mode == EDITOR_MODE_HEIGHT_RAISE) - { - for(int i = 0; i < VertexCounter; i++) - if(Vertices[i].active) - modifyHeightRaise(Vertices[i]); - } else if(mode == EDITOR_MODE_HEIGHT_REDUCE) - { - for(int i = 0; i < VertexCounter; i++) - if(Vertices[i].active) - modifyHeightReduce(Vertices[i]); - } else if(mode == EDITOR_MODE_HEIGHT_PLANE) - { - // calculate height average over all vertices - int h_sum = 0; - int h_count = 0; - Uint8 h_avg = 0x00; - - for(int i = 0; i < VertexCounter; i++) - { - if(Vertices[i].active) - { - h_sum += map->getVertex(Vertices[i]).h; - h_count++; - } - } - - if(h_count > 0) - { - h_avg = h_sum / h_count; - - for(int i = 0; i < VertexCounter; i++) - if(Vertices[i].active) - modifyHeightPlane(Vertices[i], h_avg); - } - } else if(mode == EDITOR_MODE_HEIGHT_MAKE_BIG_HOUSE) - { - modifyHeightMakeBigHouse(Vertex_); - } else if(mode == EDITOR_MODE_TEXTURE_MAKE_HARBOUR) - { - modifyHeightMakeBigHouse(Vertex_); - modifyTextureMakeHarbour(Vertex_); - } - // at this time we need a modeContent to set - else if(mode == EDITOR_MODE_CUT) - { - for(int i = 0; i < VertexCounter; i++) - { - if(Vertices[i].active) - { - modifyObject(Vertices[i]); - modifyAnimal(Vertices[i]); - } - } - } else if(mode == EDITOR_MODE_TEXTURE) - { - for(int i = 0; i < VertexCounter; i++) - if(Vertices[i].active) - modifyTexture(Vertices[i], Vertices[i].fill_rsu, Vertices[i].fill_usd); - } else if(mode == EDITOR_MODE_TREE) - { - for(int i = 0; i < VertexCounter; i++) - if(Vertices[i].active) - modifyObject(Vertices[i]); - } else if(mode == EDITOR_MODE_LANDSCAPE) - { - for(int i = 0; i < VertexCounter; i++) - if(Vertices[i].active) - modifyObject(Vertices[i]); - } else if(mode == EDITOR_MODE_RESOURCE_RAISE || mode == EDITOR_MODE_RESOURCE_REDUCE) - { - for(int i = 0; i < VertexCounter; i++) - if(Vertices[i].active) - modifyResource(Vertices[i]); - } else if(mode == EDITOR_MODE_ANIMAL) - { - for(int i = 0; i < VertexCounter; i++) - if(Vertices[i].active) - modifyAnimal(Vertices[i]); - } else if(mode == EDITOR_MODE_FLAG || mode == EDITOR_MODE_FLAG_DELETE) - { - modifyPlayer(Vertex_); - } -} - -void CMap::modifyHeightRaise(Position pos) -{ - // vertex count for the points - int X, Y; - EditorMapNode* tempP = &map->getVertex(pos.x, pos.y); - // this is to setup the building depending on the vertices around - std::array tempVertices; - calculateVerticesAround(tempVertices, pos); - - bool even = false; - if(pos.y % 2 == 0) - even = true; - - // DO IT - if(tempP->z >= HEIGHT_FACTOR * (MaxRaiseHeight - 0x0A)) // user specified maximum reached - return; - - if(tempP->z >= HEIGHT_FACTOR * (0x3C - 0x0A)) // maximum reached (0x3C is max) - return; - - tempP->y -= HEIGHT_FACTOR; - tempP->z += HEIGHT_FACTOR; - tempP->h += 0x01; - CSurface::update_shading(*map, pos); - - // after (5*HEIGHT_FACTOR) pixel all vertices around will be raised too - // update first vertex left upside - X = pos.x - (even ? 1 : 0); - if(X < 0) - X += map->width; - Y = pos.y - 1; - if(Y < 0) - Y += map->height; - // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few - // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) //-V807 - modifyHeightRaise(Position(X, Y)); - // update second vertex right upside - X = pos.x + (even ? 0 : 1); - if(X >= map->width) - X -= map->width; - Y = pos.y - 1; - if(Y < 0) - Y += map->height; - // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few - // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) - modifyHeightRaise(Position(X, Y)); - // update third point bottom left - X = pos.x - 1; - if(X < 0) - X += map->width; - Y = pos.y; - // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few - // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) - modifyHeightRaise(Position(X, Y)); - // update fourth point bottom right - X = pos.x + 1; - if(X >= map->width) - X -= map->width; - Y = pos.y; - // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few - // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) - modifyHeightRaise(Position(X, Y)); - // update fifth point down left - X = pos.x - (even ? 1 : 0); - if(X < 0) - X += map->width; - Y = pos.y + 1; - if(Y >= map->height) - Y -= map->height; - // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few - // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) - modifyHeightRaise(Position(X, Y)); - // update sixth point down right - X = pos.x + (even ? 0 : 1); - if(X >= map->width) - X -= map->width; - Y = pos.y + 1; - if(Y >= map->height) - Y -= map->height; - // only modify if the other point is lower than the middle point of the hexagon (-5 cause point was raised a few - // lines before) - if(map->getVertex(X, Y).z < tempP->z - (5 * HEIGHT_FACTOR)) - modifyHeightRaise(Position(X, Y)); - - // at least setup the possible building and shading at the vertex and 2 sections around - for(int i = 0; i < 19; i++) - { - modifyBuild(tempVertices[i]); - modifyShading(tempVertices[i]); - } -} - -void CMap::modifyHeightReduce(Position pos) -{ - // vertex count for the points - int X, Y; - EditorMapNode* tempP = &map->getVertex(pos.x, pos.y); - // this is to setup the building depending on the vertices around - std::array tempVertices; - calculateVerticesAround(tempVertices, pos); - - bool even = false; - if(pos.y % 2 == 0) - even = true; - - // DO IT - if(tempP->z <= HEIGHT_FACTOR * (MinReduceHeight - 0x0A)) // user specified minimum reached - return; - - if(tempP->z <= HEIGHT_FACTOR * (0x00 - 0x0A)) // minimum reached (0x00 is min) - return; - - tempP->y += HEIGHT_FACTOR; - tempP->z -= HEIGHT_FACTOR; - tempP->h -= 0x01; - CSurface::update_shading(*map, pos); - // after (5*HEIGHT_FACTOR) pixel all vertices around will be reduced too - // update first vertex left upside - X = pos.x - (even ? 1 : 0); - if(X < 0) - X += map->width; - Y = pos.y - 1; - if(Y < 0) - Y += map->height; - // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few - // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) //-V807 - modifyHeightReduce(Position(X, Y)); - // update second vertex right upside - X = pos.x + (even ? 0 : 1); - if(X >= map->width) - X -= map->width; - Y = pos.y - 1; - if(Y < 0) - Y += map->height; - // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few - // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) - modifyHeightReduce(Position(X, Y)); - // update third point bottom left - X = pos.x - 1; - if(X < 0) - X += map->width; - Y = pos.y; - // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few - // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) - modifyHeightReduce(Position(X, Y)); - // update fourth point bottom right - X = pos.x + 1; - if(X >= map->width) - X -= map->width; - Y = pos.y; - // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few - // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) - modifyHeightReduce(Position(X, Y)); - // update fifth point down left - X = pos.x - (even ? 1 : 0); - if(X < 0) - X += map->width; - Y = pos.y + 1; - if(Y >= map->height) - Y -= map->height; - // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few - // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) - modifyHeightReduce(Position(X, Y)); - // update sixth point down right - X = pos.x + (even ? 0 : 1); - if(X >= map->width) - X -= map->width; - Y = pos.y + 1; - if(Y >= map->height) - Y -= map->height; - // only modify if the other point is higher than the middle point of the hexagon (+5 cause point was reduced a few - // lines before) - if(map->getVertex(X, Y).z > tempP->z + (5 * HEIGHT_FACTOR)) - modifyHeightReduce(Position(X, Y)); - - // at least setup the possible building and shading at the vertex and 2 sections around - for(int i = 0; i < 19; i++) - { - modifyBuild(tempVertices[i]); - modifyShading(tempVertices[i]); - } -} - -void CMap::modifyHeightPlane(Position pos, Uint8 h) -{ - // we could do "while" but "if" looks better during planing (optical effect) - if(map->getVertex(pos.x, pos.y).h < h) - modifyHeightRaise(pos); - // we could do "while" but "if" looks better during planing (optical effect) - if(map->getVertex(pos.x, pos.y).h > h) - modifyHeightReduce(pos); -} - -void CMap::modifyHeightMakeBigHouse(Position pos) -{ - // at first save all vertices we need to calculate the new building - std::array tempVertices; - calculateVerticesAround(tempVertices, pos); - - EditorMapNode& middleVertex = map->getVertex(pos.x, pos.y); - Uint8 height = middleVertex.h; - - // calculate the building using the height of the vertices - - // test the whole section - for(int i = 0; i < 6; i++) - { - EditorMapNode& vertex = map->getVertex(tempVertices[i]); - for(int j = height - vertex.h; j >= 0x04; --j) - modifyHeightRaise(tempVertices[i]); - - for(int j = vertex.h - height; j >= 0x04; --j) - modifyHeightReduce(tempVertices[i]); - } - - // test vertex lower right - EditorMapNode& vertex = map->getVertex(tempVertices[6]); - for(int j = height - vertex.h; j >= 0x04; --j) - modifyHeightRaise(tempVertices[6]); - - for(int j = vertex.h - height; j >= 0x02; --j) - modifyHeightReduce(tempVertices[6]); - - // now test the second section around the vertex - - // test the whole section - for(int i = 7; i < 19; i++) - { - EditorMapNode& vertex = map->getVertex(tempVertices[i]); - for(int j = height - vertex.h; j >= 0x03; --j) - modifyHeightRaise(tempVertices[i]); - - for(int j = vertex.h - height; j >= 0x03; --j) - modifyHeightReduce(tempVertices[i]); - } - - // remove harbour if there is one - if(middleVertex.rsuTexture & 0x40) - { - middleVertex.rsuTexture &= ~0x40; - } -} - -void CMap::modifyShading(Position pos) -{ - // temporary to keep the lines short - int X, Y; - // this is to setup the shading depending on the vertices around (2 sections from the cursor) - std::array tempVertices; - calculateVerticesAround(tempVertices, pos); - EditorMapNode& middleVertex = map->getVertex(pos.x, pos.y); - - // shading stakes - int A, B, C, D, Result; - - // shading stake of point right upside (first section) - X = tempVertices[2].x; - Y = tempVertices[2].y; - A = 9 * (map->getVertex(X, Y).h - middleVertex.h); //-V807 - // shading stake of point left (first section) - X = tempVertices[3].x; - Y = tempVertices[3].y; - B = -6 * (map->getVertex(X, Y).h - middleVertex.h); - // shading stake of point left (second section) - X = tempVertices[12].x; - Y = tempVertices[12].y; - C = -3 * (map->getVertex(X, Y).h - middleVertex.h); - // shading stake of point bottom/middle left (second section) - X = tempVertices[14].x; - Y = tempVertices[14].y; - D = -9 * (map->getVertex(X, Y).h - middleVertex.h); - - Result = 0x40 + A + B + C + D; - if(Result > 0x80) - Result = 0x80; - else if(Result < 0x00) - Result = 0x00; - - middleVertex.shading = Result; -} - -void CMap::modifyTexture(Position pos, bool rsu, bool usd) -{ - if(modeContent == TRIANGLE_TEXTURE_MEADOW_MIXED || modeContent == TRIANGLE_TEXTURE_MEADOW_MIXED_HARBOUR) - { - int newContent = rand() % 3; - if(newContent == 0) - { - if(modeContent == TRIANGLE_TEXTURE_MEADOW_MIXED) - newContent = TRIANGLE_TEXTURE_MEADOW1; - else - newContent = TRIANGLE_TEXTURE_MEADOW1_HARBOUR; - } else if(newContent == 1) - { - if(modeContent == TRIANGLE_TEXTURE_MEADOW_MIXED) - newContent = TRIANGLE_TEXTURE_MEADOW2; - else - newContent = TRIANGLE_TEXTURE_MEADOW2_HARBOUR; - } else - { - if(modeContent == TRIANGLE_TEXTURE_MEADOW_MIXED) - newContent = TRIANGLE_TEXTURE_MEADOW3; - else - newContent = TRIANGLE_TEXTURE_MEADOW3_HARBOUR; - } - if(rsu) - map->getVertex(pos.x, pos.y).rsuTexture = newContent; - if(usd) - map->getVertex(pos.x, pos.y).usdTexture = newContent; - } else - { - if(rsu) - map->getVertex(pos.x, pos.y).rsuTexture = modeContent; - if(usd) - map->getVertex(pos.x, pos.y).usdTexture = modeContent; - } - - // at least setup the possible building and the resources at the vertex and 1 section/2 sections around - std::array tempVertices; - calculateVerticesAround(tempVertices, pos); - for(int i = 0; i < 19; i++) - { - if(i < 7) - modifyBuild(tempVertices[i]); - modifyResource(tempVertices[i]); - } -} - -void CMap::modifyTextureMakeHarbour(Position pos) -{ - EditorMapNode& vertex = map->getVertex(pos.x, pos.y); - const auto* desc = getTerrainDesc(*map, vertex.rsuTexture); - if(desc && desc->kind == TerrainKind::Land && desc->Is(ETerrain::Buildable)) - { - vertex.rsuTexture |= 0x40; - } -} - -void CMap::modifyObject(Position pos) -{ - EditorMapNode& curVertex = map->getVertex(pos.x, pos.y); - if(mode == EDITOR_MODE_CUT) - { - // prevent cutting a player position - if(curVertex.objectInfo != 0x80) - { - curVertex.objectType = 0x00; - curVertex.objectInfo = 0x00; - } - } else if(mode == EDITOR_MODE_TREE) - { - // if there is another object at the vertex, return - if(curVertex.objectInfo != 0x00) - return; - if(modeContent == 0xFF) - { - // mixed wood - if(modeContent2 == 0xC4) - { - int newContent = rand() % 3; - if(newContent == 0) - newContent = 0x30; - else if(newContent == 1) - newContent = 0x70; - else - newContent = 0xB0; - // we set different start pictures for the tree, cause the trees should move different, so we add a - // random value that walks from 0 to 7 - curVertex.objectType = newContent + rand() % 8; - curVertex.objectInfo = modeContent2; - } - // mixed palm - else // if (modeContent2 == 0xC5) - { - int newContent = rand() % 2; - int newContent2; - if(newContent == 0) - { - newContent = 0x30; - newContent2 = 0xC5; - } else - { - newContent = 0xF0; - newContent2 = 0xC4; - } - // we set different start pictures for the tree, cause the trees should move different, so we add a - // random value that walks from 0 to 7 - curVertex.objectType = newContent + rand() % 8; - curVertex.objectInfo = newContent2; - } - } else - { - // we set different start pictures for the tree, cause the trees should move different, so we add a random - // value that walks from 0 to 7 - curVertex.objectType = modeContent + rand() % 8; - curVertex.objectInfo = modeContent2; - } - } else if(mode == EDITOR_MODE_LANDSCAPE) - { - // if there is another object at the vertex, return - if(curVertex.objectInfo != 0x00) - return; - - if(modeContent == 0x01) - { - int newContent = modeContent + rand() % 6; - int newContent2 = 0xCC + rand() % 2; - - curVertex.objectType = newContent; - curVertex.objectInfo = newContent2; - - // now set up the buildings around the granite - modifyBuild(pos); - } else if(modeContent == 0x05) - { - int newContent = modeContent + rand() % 2; - - curVertex.objectType = newContent; - curVertex.objectInfo = modeContent2; - } else if(modeContent == 0x02) - { - int newContent = modeContent + rand() % 3; - - curVertex.objectType = newContent; - curVertex.objectInfo = modeContent2; - } else if(modeContent == 0x0C) - { - int newContent = modeContent + rand() % 2; - - curVertex.objectType = newContent; - curVertex.objectInfo = modeContent2; - } else if(modeContent == 0x25) - { - int newContent = modeContent + rand() % 3; - - curVertex.objectType = newContent; - curVertex.objectInfo = modeContent2; - } else if(modeContent == 0x10) - { - int newContent = rand() % 4; - if(newContent == 0) - newContent = 0x10; - else if(newContent == 1) - newContent = 0x11; - else if(newContent == 2) - newContent = 0x12; - else - newContent = 0x0A; - - curVertex.objectType = newContent; - curVertex.objectInfo = modeContent2; - } else if(modeContent == 0x0E) - { - int newContent = rand() % 4; - if(newContent == 0) - newContent = 0x0E; - else if(newContent == 1) - newContent = 0x0F; - else if(newContent == 2) - newContent = 0x13; - else - newContent = 0x14; - - curVertex.objectType = newContent; - curVertex.objectInfo = modeContent2; - } else if(modeContent == 0x07) - { - int newContent = modeContent + rand() % 2; - - curVertex.objectType = newContent; - curVertex.objectInfo = modeContent2; - } else if(modeContent == 0x00) - { - int newContent = rand() % 3; - if(newContent == 0) - newContent = 0x00; - else if(newContent == 1) - newContent = 0x01; - else - newContent = 0x22; - - curVertex.objectType = newContent; - curVertex.objectInfo = modeContent2; - } else if(modeContent == 0x18) - { - int newContent = modeContent + rand() % 7; - - curVertex.objectType = newContent; - curVertex.objectInfo = modeContent2; - } else if(modeContent == 0x09) - { - curVertex.objectType = modeContent; - curVertex.objectInfo = modeContent2; - } - } - // at least setup the possible building at the vertex and 1 section around - std::array tempVertices; - calculateVerticesAround(tempVertices, pos); - for(int i = 0; i < 7; i++) - modifyBuild(tempVertices[i]); -} - -void CMap::modifyAnimal(Position pos) -{ - if(mode == EDITOR_MODE_CUT) - { - map->getVertex(pos.x, pos.y).animal = 0x00; - } else if(mode == EDITOR_MODE_ANIMAL) - { - // if there is another object at the vertex, return - if(map->getVertex(pos.x, pos.y).animal != 0x00) - return; - - if(modeContent > 0x00 && modeContent <= 0x06) - map->getVertex(pos.x, pos.y).animal = modeContent; - } -} - -void CMap::modifyBuild(Position pos) -{ - // at first save all vertices we need to calculate the new building - std::array tempVertices; - calculateVerticesAround(tempVertices, pos); - - /// evtl. keine festen werte sondern addition und subtraktion wegen originalkompatibilitaet (bei baeumen bspw. keine - /// 0x00 sondern 0x68) - - Uint8 building; - EditorMapNode& curVertex = map->getVertex(pos.x, pos.y); - const Uint8 height = curVertex.h; - std::array mapVertices; - for(unsigned i = 0; i < mapVertices.size(); i++) - mapVertices[i] = &map->getVertex(tempVertices[i]); - - // Determine building quality from terrain following s25client's BQCalculator: - // Check the 6 terrain triangles around the point (same layout as World::GetTerrainsAround): - // {nwNode.t1, nwNode.t2, neNode.t1, curNode.t2, curNode.t1, wNode.t2} - // where t1 = rsuTexture, t2 = usdTexture - int buildingHits = 0, mineHits = 0, flagHits = 0; - bool danger = false; - - auto checkTerrainBQ = [&](const TerrainDesc* desc) { - if(!desc) - return; - switch(desc->GetBQ()) - { - case TerrainBQ::Castle: ++buildingHits; break; - case TerrainBQ::Mine: ++mineHits; break; - case TerrainBQ::Flag: ++flagHits; break; - case TerrainBQ::Danger: danger = true; break; - default: break; // Nothing - } - }; - - checkTerrainBQ(getTerrainDesc(*map, mapVertices[1]->rsuTexture)); // nwNode.t1 - checkTerrainBQ(getTerrainDesc(*map, mapVertices[1]->usdTexture)); // nwNode.t2 - checkTerrainBQ(getTerrainDesc(*map, mapVertices[2]->rsuTexture)); // neNode.t1 - checkTerrainBQ(getTerrainDesc(*map, mapVertices[0]->usdTexture)); // curNode.t2 - checkTerrainBQ(getTerrainDesc(*map, mapVertices[0]->rsuTexture)); // curNode.t1 - checkTerrainBQ(getTerrainDesc(*map, mapVertices[3]->usdTexture)); // wNode.t2 - - if(danger) - building = 0x00; - else if(mineHits == 6) - building = 0x05; - else if(buildingHits == 6) - building = 0x04; - else if(buildingHits || mineHits || flagHits) - building = 0x01; - else - building = 0x00; - - // Now reduce BQ based on altitude (matching s25client altitude checks) - if(building == 0x04) // Castle - { - // flag point (SE neighbour) more than 1 higher? -> Flag - if(mapVertices[6]->h > height + 1) - building = 0x01; - else - { - // Direct neighbours: Flag for altitude difference > 3 - for(int i = 1; i < 7; i++) - { - const auto tmpHeight = mapVertices[i]->h; - if(height > tmpHeight + 3 || tmpHeight > height + 3) - { - building = 0x01; - break; - } - } - - if(building == 0x04) - { - // Radius-2 neighbours: Hut (small house) for altitude difference > 2 - for(int i = 7; i < 19; i++) - { - const auto tmpHeight = map->getVertex(tempVertices[i]).h; - if(height > tmpHeight + 2 || tmpHeight > height + 2) - { - building = 0x02; - break; - } - } - } - } - } else if(building == 0x05) // Mine - { - // Mines only possible till altitude diff of 3 to SE neighbour - if(mapVertices[6]->h > height + 3) - building = 0x01; - } - - // test if there is an object AROUND the vertex (trees or granite) - if(building > 0x01) - { - for(int i = 1; i < 7; i++) - { - const EditorMapNode& vertexI = *mapVertices[i]; - if(vertexI.objectInfo == 0xC4 // tree - || vertexI.objectInfo == 0xC5 // tree - || vertexI.objectInfo == 0xC6 // tree - ) - { - // if lower right - if(i == 6) - { - building = 0x01; - break; - } else - building = 0x02; - } else if(vertexI.objectInfo == 0xCC // granite - || vertexI.objectInfo == 0xCD // granite - ) - { - building = 0x01; - break; - } - } - } - - // test if there is an object AT the vertex (trees or granite) - if(building > 0x00) - { - if(curVertex.objectInfo == 0xC4 // tree - || curVertex.objectInfo == 0xC5 // tree - || curVertex.objectInfo == 0xC6 // tree - || curVertex.objectInfo == 0xCC // granite - || curVertex.objectInfo == 0xCD // granite - ) - { - building = 0x00; - } - } - - // test for headquarters around the point - // NOTE: In EDITORMODE don't test AT the point, cause in Original game we need a big house AT the point, otherwise - // the game wouldn't set a player there - if(building > 0x00) - { - for(int i = 1; i < 7; i++) - { - if(map->getVertex(tempVertices[i]).objectInfo == 0x80) - building = 0x00; - } - } - - // test for headquarters around (second section) - if(building > 0x01) - { - for(int i = 7; i < 19; i++) - { - if(map->getVertex(tempVertices[i]).objectInfo == 0x80) - { - if(i == 15 || i == 17 || i == 18) - building = 0x01; - else - { - // make middle house, but only if it's not a mine - if(building > 0x03 && building < 0x05) - building = 0x03; - } - } - } - } - - // Some additional information for "ingame"-building-calculation: - // There is no difference between small, middle and big houses. If you set a small house on a vertex, the - // buildings around will change like this where a middle or a big house. - // Only a flag has another algorithm. - //--Flagge einfuegen!!! - - curVertex.build = building; -} - -void CMap::modifyResource(Position pos) -{ - // at first save all vertices we need to check - std::array tempVertices; - calculateVerticesAround(tempVertices, pos); - EditorMapNode& curVertex = map->getVertex(pos.x, pos.y); - std::array mapVertices; - for(unsigned i = 0; i < mapVertices.size(); i++) - mapVertices[i] = &map->getVertex(tempVertices[i]); - - // SPECIAL CASE: test if we should set water only - // test if vertex is surrounded by meadow and meadow-like textures - // Original logic: both triangles for v0/v1, only rsu for v2, only usd for v3 - if(getTerrainDesc(*map, mapVertices[0]->rsuTexture)->Is(ETerrain::Buildable) - && getTerrainDesc(*map, mapVertices[0]->usdTexture)->Is(ETerrain::Buildable) - && getTerrainDesc(*map, mapVertices[1]->rsuTexture)->Is(ETerrain::Buildable) - && getTerrainDesc(*map, mapVertices[1]->usdTexture)->Is(ETerrain::Buildable) - && getTerrainDesc(*map, mapVertices[2]->rsuTexture)->Is(ETerrain::Buildable) - && getTerrainDesc(*map, mapVertices[3]->usdTexture)->Is(ETerrain::Buildable)) - { - curVertex.resource = 0x21; - } - // SPECIAL CASE: test if we should set fishes only - // test if vertex is surrounded by water (first section) and at least one non-water texture in the second section - // Original logic: both triangles for v0/v1, only rsu for v2, only usd for v3 - else if(nodeHasTerrainFlag(*map, *mapVertices[0], ETerrain::Shippable, true) - && nodeHasTerrainFlag(*map, *mapVertices[1], ETerrain::Shippable, true) - && getTerrainDesc(*map, mapVertices[2]->rsuTexture)->Is(ETerrain::Shippable) - && getTerrainDesc(*map, mapVertices[3]->usdTexture)->Is(ETerrain::Shippable) - && (!nodeHasTerrainFlag(*map, *mapVertices[2], ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, *mapVertices[3], ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, *mapVertices[4], ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, *mapVertices[5], ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, *mapVertices[6], ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, map->getVertex(tempVertices[7]), ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, map->getVertex(tempVertices[8]), ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, map->getVertex(tempVertices[9]), ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, map->getVertex(tempVertices[10]), ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, map->getVertex(tempVertices[11]), ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, map->getVertex(tempVertices[12]), ETerrain::Shippable, false) - || !nodeHasTerrainFlag(*map, map->getVertex(tempVertices[14]), ETerrain::Shippable, false))) - { - curVertex.resource = 0x87; - } - // test if vertex is surrounded by mining textures - // Original logic: both triangles for v0/v1, only rsu for v2, only usd for v3 - else if(getTerrainDesc(*map, mapVertices[0]->rsuTexture)->Is(ETerrain::Mineable) - && getTerrainDesc(*map, mapVertices[0]->usdTexture)->Is(ETerrain::Mineable) - && getTerrainDesc(*map, mapVertices[1]->rsuTexture)->Is(ETerrain::Mineable) - && getTerrainDesc(*map, mapVertices[1]->usdTexture)->Is(ETerrain::Mineable) - && getTerrainDesc(*map, mapVertices[2]->rsuTexture)->Is(ETerrain::Mineable) - && getTerrainDesc(*map, mapVertices[3]->usdTexture)->Is(ETerrain::Mineable)) - { - // check which resource to set - if(mode == EDITOR_MODE_RESOURCE_RAISE) - { - // if there is no or another resource at the moment - if(curVertex.resource == 0x40 || curVertex.resource < modeContent || curVertex.resource > modeContent + 6) - { - curVertex.resource = modeContent; - } else if(curVertex.resource >= modeContent && curVertex.resource <= modeContent + 6) - { - // maximum not reached? - if(curVertex.resource != modeContent + 6) - curVertex.resource++; - } - } else if(mode == EDITOR_MODE_RESOURCE_REDUCE) - { - // minimum not reached? - if(curVertex.resource != 0x40) - { - curVertex.resource--; - // minimum now reached? if so, set it to 0x40 - if(curVertex.resource == 0x48 || curVertex.resource == 0x50 || curVertex.resource == 0x58 - // in case of coal we already have a 0x40, so don't check this - ) - curVertex.resource = 0x40; - } - } else if(curVertex.resource == 0x00) - curVertex.resource = 0x40; - } else - curVertex.resource = 0x00; -} - -void CMap::modifyPlayer(Position pos) -{ - // if we have repositioned a player, we need the old position to recalculate the buildings there - bool PlayerRePositioned = false; - int oldPositionX = 0; - int oldPositionY = 0; - EditorMapNode& vertex = map->getVertex(pos.x, pos.y); - - // set player position - if(mode == EDITOR_MODE_FLAG) - { - // only allowed on big houses (0x04) --> but in cheat mode within the game also small houses (0x02) are allowed - if(vertex.build % 8 == 0x04 && vertex.objectInfo != 0x80) - { - vertex.objectType = modeContent; - vertex.objectInfo = 0x80; - - // for compatibility with original settlers 2 we write the headquarters positions to the map header (for the - // first 7 players) - if(modeContent >= 0 && modeContent < 7) - { - map->HQx[modeContent] = pos.x; - map->HQy[modeContent] = pos.y; - } - - // save old position if exists - if(PlayerHQx[modeContent] != 0xFFFF && PlayerHQy[modeContent] != 0xFFFF) - { - oldPositionX = PlayerHQx[modeContent]; - oldPositionY = PlayerHQy[modeContent]; - map->getVertex(oldPositionX, oldPositionY).objectType = 0x00; - map->getVertex(oldPositionX, oldPositionY).objectInfo = 0x00; - PlayerRePositioned = true; - } - PlayerHQx[modeContent] = pos.x; - PlayerHQy[modeContent] = pos.y; - - // setup number of players in map header - if(!PlayerRePositioned) - map->player++; - } - } - // delete player position - else if(mode == EDITOR_MODE_FLAG_DELETE) - { - if(vertex.objectInfo == 0x80) - { - // at first delete the player position using the number of the player as saved in objectType - if(vertex.objectType < MAXPLAYERS) - { - PlayerHQx[vertex.objectType] = 0xFFFF; - PlayerHQy[vertex.objectType] = 0xFFFF; - - // for compatibility with original settlers 2 we write the headquarters positions to the map header (for - // the first 7 players) - if(vertex.objectType < 7) - { - map->HQx[vertex.objectType] = 0xFFFF; - map->HQy[vertex.objectType] = 0xFFFF; - } - } - - vertex.objectType = 0x00; - vertex.objectInfo = 0x00; - - // setup number of players in map header - map->player--; - } - } - - // at least setup the possible building at the vertex and 2 sections around - std::array tempVertices; - calculateVerticesAround(tempVertices, pos); - for(int i = 0; i < 19; i++) - modifyBuild(tempVertices[i]); - - if(PlayerRePositioned) - { - calculateVerticesAround(tempVertices, Position(oldPositionX, oldPositionY)); - for(int i = 0; i < 19; i++) - modifyBuild(tempVertices[i]); - } -} - -void CMap::calculateVertices() -{ - const bool even = Vertex_.y % 2 == 0; - - int index = 0; - for(int i = -MAX_CHANGE_SECTION; i <= MAX_CHANGE_SECTION; i++) - { - if(abs(i) % 2 == 0) - { - for(int j = -MAX_CHANGE_SECTION; j <= MAX_CHANGE_SECTION; j++, index++) - { - static_cast(Vertices[index]) = Vertex_ + Position(j, i); - if(Vertices[index].x < 0) - Vertices[index].x += map->width; - else if(Vertices[index].x >= map->width) - Vertices[index].x -= map->width; - if(Vertices[index].y < 0) - Vertices[index].y += map->height; - else if(Vertices[index].y >= map->height) - Vertices[index].y -= map->height; - Vertices[index].blit = correctMouseBlit(Vertices[index]); - } - } else - { - for(int j = -MAX_CHANGE_SECTION; j <= MAX_CHANGE_SECTION - 1; j++, index++) - { - static_cast(Vertices[index]) = Vertex_ + Position(even ? j : j + 1, i); - if(Vertices[index].x < 0) - Vertices[index].x += map->width; - else if(Vertices[index].x >= map->width) - Vertices[index].x -= map->width; - if(Vertices[index].y < 0) - Vertices[index].y += map->height; - else if(Vertices[index].y >= map->height) - Vertices[index].y -= map->height; - Vertices[index].blit = correctMouseBlit(Vertices[index]); - } - } - } - // check if cursor vertices should change randomly - if(VertexActivityRandom || VertexFillRandom) - setupVerticesActivity(); -} - -template -void CMap::calculateVerticesAround(std::array& newVertices, Position pos) -{ - int x = pos.x, y = pos.y; - static_assert(T_size == 1u || T_size == 7u || T_size == 19u, "Only 1, 7 or 19 are allowed"); - bool even = false; - if(y % 2 == 0) - even = true; - - newVertices[0].x = x; - newVertices[0].y = y; - - if(T_size >= 7u) - { - newVertices[1].x = x - (even ? 1 : 0); - if(newVertices[1].x < 0) - newVertices[1].x += map->width; - newVertices[1].y = y - 1; - if(newVertices[1].y < 0) - newVertices[1].y += map->height; - newVertices[2].x = x + (even ? 0 : 1); - if(newVertices[2].x >= map->width) - newVertices[2].x -= map->width; - newVertices[2].y = y - 1; - if(newVertices[2].y < 0) - newVertices[2].y += map->height; - newVertices[3].x = x - 1; - if(newVertices[3].x < 0) - newVertices[3].x += map->width; - newVertices[3].y = y; - newVertices[4].x = x + 1; - if(newVertices[4].x >= map->width) - newVertices[4].x -= map->width; - newVertices[4].y = y; - newVertices[5].x = x - (even ? 1 : 0); - if(newVertices[5].x < 0) - newVertices[5].x += map->width; - newVertices[5].y = y + 1; - if(newVertices[5].y >= map->height) - newVertices[5].y -= map->height; - newVertices[6].x = x + (even ? 0 : 1); - if(newVertices[6].x >= map->width) - newVertices[6].x -= map->width; - newVertices[6].y = y + 1; - if(newVertices[6].y >= map->height) - newVertices[6].y -= map->height; - } - if(T_size >= 19) - { - newVertices[7].x = x - 1; - if(newVertices[7].x < 0) - newVertices[7].x += map->width; - newVertices[7].y = y - 2; - if(newVertices[7].y < 0) - newVertices[7].y += map->height; - newVertices[8].x = x; - newVertices[8].y = y - 2; - if(newVertices[8].y < 0) - newVertices[8].y += map->height; - newVertices[9].x = x + 1; - if(newVertices[9].x >= map->width) - newVertices[9].x -= map->width; - newVertices[9].y = y - 2; - if(newVertices[9].y < 0) - newVertices[9].y += map->height; - newVertices[10].x = x - (even ? 2 : 1); - if(newVertices[10].x < 0) - newVertices[10].x += map->width; - newVertices[10].y = y - 1; - if(newVertices[10].y < 0) - newVertices[10].y += map->height; - newVertices[11].x = x + (even ? 1 : 2); - if(newVertices[11].x >= map->width) - newVertices[11].x -= map->width; - newVertices[11].y = y - 1; - if(newVertices[11].y < 0) - newVertices[11].y += map->height; - newVertices[12].x = x - 2; - if(newVertices[12].x < 0) - newVertices[12].x += map->width; - newVertices[12].y = y; - newVertices[13].x = x + 2; - if(newVertices[13].x >= map->width) - newVertices[13].x -= map->width; - newVertices[13].y = y; - newVertices[14].x = x - (even ? 2 : 1); - if(newVertices[14].x < 0) - newVertices[14].x += map->width; - newVertices[14].y = y + 1; - if(newVertices[14].y >= map->height) - newVertices[14].y -= map->height; - newVertices[15].x = x + (even ? 1 : 2); - if(newVertices[15].x >= map->width) - newVertices[15].x -= map->width; - newVertices[15].y = y + 1; - if(newVertices[15].y >= map->height) - newVertices[15].y -= map->height; - newVertices[16].x = x - 1; - if(newVertices[16].x < 0) - newVertices[16].x += map->width; - newVertices[16].y = y + 2; - if(newVertices[16].y >= map->height) - newVertices[16].y -= map->height; - newVertices[17].x = x; - newVertices[17].y = y + 2; - if(newVertices[17].y >= map->height) - newVertices[17].y -= map->height; - newVertices[18].x = x + 1; - if(newVertices[18].x >= map->width) - newVertices[18].x -= map->width; - newVertices[18].y = y + 2; - if(newVertices[18].y >= map->height) - newVertices[18].y -= map->height; - } -} - -void CMap::setupVerticesActivity() -{ - int index = 0; - for(int i = -MAX_CHANGE_SECTION; i <= MAX_CHANGE_SECTION; i++) - { - if(abs(i) % 2 == 0) - { - for(int j = -MAX_CHANGE_SECTION; j <= MAX_CHANGE_SECTION; j++, index++) - { - if(abs(i) <= ChangeSection_ && abs(j) <= ChangeSection_ - (ChangeSectionHexagonMode ? abs(i / 2) : 0)) - { - // check if cursor vertices should change randomly - if(VertexActivityRandom) - Vertices[index].active = (rand() % 2 == 1); - else - Vertices[index].active = true; - - // decide which triangle-textures will be filled at this vertex (necessary for border) - Vertices[index].fill_rsu = VertexFillRSU || (VertexFillRandom && (rand() % 2 == 1)); - Vertices[index].fill_usd = VertexFillUSD || (VertexFillRandom && (rand() % 2 == 1)); - - // if we have a ChangeSection greater than zero - if(ChangeSection_) - { - // if we are in hexagon mode - if(ChangeSectionHexagonMode) - { - // if we walk through the upper rows of the cursor field - if(i < 0) - { - // right vertex of the row - if(j == ChangeSection_ - abs(i / 2)) - Vertices[index].fill_usd = false; - } - // if we are at the last lower row - else if(i == ChangeSection_) - { - Vertices[index].fill_rsu = false; - Vertices[index].fill_usd = false; - } - // if we walk through the lower rows of the cursor field - else // if (i >= 0 && i != ChangeSection) - { - // left vertex of the row - if(j == -ChangeSection_ + abs(i / 2)) - Vertices[index].fill_rsu = false; - // right vertex of the row - else if(j == ChangeSection_ - abs(i / 2)) - { - Vertices[index].fill_rsu = false; - Vertices[index].fill_usd = false; - } - } - } - // we are in square mode - else - { - // if we are at the last lower row or right vertex of the row - if(i == ChangeSection_ || j == ChangeSection_) - { - Vertices[index].fill_rsu = false; - Vertices[index].fill_usd = false; - } - // left vertex of the row - else if(j == -ChangeSection_) - Vertices[index].fill_rsu = false; - } - } - } else - { - Vertices[index].active = false; - Vertices[index].fill_rsu = false; - Vertices[index].fill_usd = false; - } - } - } else - { - for(int j = -MAX_CHANGE_SECTION; j <= MAX_CHANGE_SECTION - 1; j++, index++) - { - if(abs(i) <= ChangeSection_ - && (j < 0 ? abs(j) <= ChangeSection_ - (ChangeSectionHexagonMode ? abs(i / 2) : 0) : - j <= ChangeSection_ - 1 - (ChangeSectionHexagonMode ? abs(i / 2) : 0))) - { - // check if cursor vertices should change randomly - if(VertexActivityRandom) - Vertices[index].active = (rand() % 2 == 1); - else - Vertices[index].active = true; - - // decide which triangle-textures will be filled at this vertex (necessary for border) - Vertices[index].fill_rsu = VertexFillRSU || (VertexFillRandom && (rand() % 2 == 1)); - Vertices[index].fill_usd = VertexFillUSD || (VertexFillRandom && (rand() % 2 == 1)); - - // if we have a ChangeSection greater than zero - if(ChangeSection_) - { - // if we are in hexagon mode - if(ChangeSectionHexagonMode) - { - // if we walk through the upper rows of the cursor field - if(i < 0) - { - // right vertex of the row - if(j == ChangeSection_ - 1 - abs(i / 2)) - Vertices[index].fill_usd = false; - } - // if we are at the last lower row - else if(i == ChangeSection_) - { - Vertices[index].fill_rsu = false; - Vertices[index].fill_usd = false; - } - // if we walk through the lower rows of the cursor field - else // if (i >= 0 && i != ChangeSection) - { - // left vertex of the row - if(j == -ChangeSection_ + abs(i / 2)) - Vertices[index].fill_rsu = false; - // right vertex of the row - else if(j == ChangeSection_ - 1 - abs(i / 2)) - { - Vertices[index].fill_rsu = false; - Vertices[index].fill_usd = false; - } - } - } - // we are in square mode - else - { - // if we are at the last lower row - if(i == ChangeSection_) - { - Vertices[index].fill_rsu = false; - Vertices[index].fill_usd = false; - } - // right vertex of the row - else if(j == ChangeSection_ - 1) - Vertices[index].fill_usd = false; - } - } - } else - { - Vertices[index].active = false; - Vertices[index].fill_rsu = false; - Vertices[index].fill_usd = false; - } - } - } - } - // NOTE: to understand this '-(ChangeSectionHexagonMode ? abs(i/2) : 0)' - // if we don't change the cursor size in square-mode, but in hexagon mode, - // at each row there have to be missing as much vertices as the row number is - // i = row number --> so at the left side of the row there are missing i/2 - // and at the right side there are missing i/2. That makes it look like an hexagon. -} diff --git a/CMap.h b/CMap.h deleted file mode 100644 index 3fb4fa8..0000000 --- a/CMap.h +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "CSurface.h" -#include "EditorWorld.h" -#include "defines.h" -#include -#include -#include -#include -#include -#include -#include -#include - -struct SavedVertex -{ - template - struct ArrayPtr - { - std::unique_ptr array_; - auto& operator[](size_t index) { return (*array_)[index]; } - const auto& operator[](size_t index) const { return (*array_)[index]; } - ArrayPtr() : array_(std::make_unique()) {} - }; - Position pos; - // NUM_NODES = number of vertices in one row or col - //+ 10 because if we raise a vertex then the other vertices will be raised too after 5 times - // this ranges up to 10 vertices - //+ 2 because modifications on a vertex will touch building and shading around - // Using int due to signed arithmetic used later - static constexpr int NODES_PER_DIR = MAX_CHANGE_SECTION + 10 + 2; - static constexpr size_t NUM_NODES = NODES_PER_DIR * 2 + 1; - using PointArray = std::array, NUM_NODES>; - // Use a unique pointer to not create huge stack arrays - ArrayPtr PointsArroundVertex; -}; - -class CMap -{ - friend class CSurface; - -private: - boost::filesystem::path filepath_; - std::unique_ptr map; - std::unique_ptr terrainWorld_; - DisplayRectangle displayRect; - bool active; - Position Vertex_; - bool RenderBuildHelp; - bool RenderBorders; - // editor mode variables - int mode; - // necessary for release the EDITOR_MODE_CUT (set back to last used mode) - int lastMode; - // these variables are used by the callback functions to define what new data should go into the vertex - int modeContent; - int modeContent2; - // is the user currently modifying? - bool modify; - // necessary for "undo"- and "do"-function - bool saveCurrentVertices; - std::list undoBuffer; - std::list redoBuffer; - // get the number of the triangle nearest to cursor and save it to VertexX and VertexY - void storeVerticesFromMouse(Position mousePos, Uint8 MouseState); - // blitting coords for the mouse cursor - Position MouseBlit; - // counts the distance from the cursor vertex to the farest vertex that can be involved in changes (0 - only cursor - // vertex, 1 - six vertices around the cursor vertex ....) (editor mode) - int ChangeSection_; - // in some cases we change the ChangeSection manually but want to reset it (this is user friendly) - int lastChangeSection; - // decides what to do if user presses '+' or '-', if true, then cursor will increase like an hexagon, otherwise like - // a square - bool ChangeSectionHexagonMode; - // user can decide that only RSU-Triangles will be filled (within the cursor field) - bool VertexFillRSU; - // user can decide that only USD-Triangles will be filled (within the cursor field) - bool VertexFillUSD; - // user can decide that all triangles will be filled randomly (within the cursor field) - bool VertexFillRandom; - // user can set activity to random, so all active cursor vertices (within the ChangeSection) will change each - // gameloop - bool VertexActivityRandom; - // counts how many vertices we have around the cursor (and including the cursor) - int VertexCounter; - // array to store all vertices (editor mode) --> after constructing class CMap this will have 'VertexCounter' - // elements - std::vector Vertices; - // these are the new (internal) values for player positions (otherwise we had to walk through the objectXXXX-Blocks - // step by step) - std::array PlayerHQx; - std::array PlayerHQy; - // maximum value of height (user can modify this) - Uint8 MaxRaiseHeight; - Uint8 MinReduceHeight; - // lock vertical or horizontal movement - bool HorizontalMovementLocked; - bool VerticalMovementLocked; - std::optional startScrollPos; - -public: - CMap(const boost::filesystem::path& filepath); - ~CMap(); - void constructMap(const boost::filesystem::path& filepath, int width = 32, int height = 32, - MapType type = MAP_GREENLAND, TriangleTerrainType texture = TRIANGLE_TEXTURE_MEADOW1, - int border = 4, int border_texture = TRIANGLE_TEXTURE_WATER); - static std::unique_ptr generateMap(int width, int height, MapType type, TriangleTerrainType texture, - int border, int border_texture); - void destructMap(); - void loadMapPics(); - static void unloadMapPics(); - - void moveMap(Position offset); - void setMouseData(const SDL_MouseMotionEvent& motion); - void setMouseData(const SDL_MouseButtonEvent& button); - void setKeyboardData(const SDL_KeyboardEvent& key); - void setActive() { active = true; } - void setInactive() { active = false; } - bool isActive() const { return active; } - int getVertexX() const { return Vertex_.x; } - int getVertexY() const { return Vertex_.y; } - auto getMaxRaiseHeight() const { return MaxRaiseHeight; } - auto getMinReduceHeight() const { return MinReduceHeight; } - bool isHorizontalMovementLocked() const { return HorizontalMovementLocked; } - bool isVerticalMovementLocked() const { return VerticalMovementLocked; } - bool getRenderBuildHelp() const { return RenderBuildHelp; } - bool getRenderBorders() const { return RenderBorders; } - void setMode(int mode) { this->mode = mode; } - int getMode() const { return mode; } - void setModeContent(int modeContent) { this->modeContent = modeContent; } - void setModeContent2(int modeContent2) { this->modeContent2 = modeContent2; } - int getModeContent() const { return modeContent; } - int getModeContent2() const { return modeContent2; } - bobMAP* getMap() { return map.get(); } - EditorWorld* getTerrainWorld() { return terrainWorld_.get(); } - /// Render terrain directly with OpenGL, then draw editor UI chrome. - /// Should be called from the main render loop with the correct GL projection set. - void render(); - DisplayRectangle getDisplayRect() { return displayRect; } - void setDisplayRect(const DisplayRectangle& displayRect) { this->displayRect = displayRect; } - auto& getPlayerHQx() { return PlayerHQx; } - auto& getPlayerHQy() { return PlayerHQy; } - const boost::filesystem::path& getFilepath() const { return filepath_; } - void setFilepath(boost::filesystem::path filepath) { filepath_ = std::move(filepath); } - std::string getMapname() const { return map->getName(); } - void setMapname(const std::string& name) { map->setName(name); } - std::string getAuthor() const { return map->getAuthor(); } - void setAuthor(const std::string& author) { map->setAuthor(author); } - - void drawMinimap(std::vector& pixels, int w, int h, int& scale); - // get and set some variables necessary for cursor behavior - void setHexagonMode(bool HexagonMode) - { - ChangeSectionHexagonMode = HexagonMode; - setupVerticesActivity(); - } - bool getHexagonMode() const { return ChangeSectionHexagonMode; } - void setVertexFillRSU(bool fillRSU) - { - VertexFillRSU = fillRSU; - setupVerticesActivity(); - } - bool getVertexFillRSU() const { return VertexFillRSU; } - void setVertexFillUSD(bool fillUSD) - { - VertexFillUSD = fillUSD; - setupVerticesActivity(); - } - bool getVertexFillUSD() const { return VertexFillUSD; } - void setVertexFillRandom(bool fillRandom) - { - VertexFillRandom = fillRandom; - setupVerticesActivity(); - } - bool getVertexFillRandom() const { return VertexFillRandom; } - void setVertexActivityRandom(bool activityRandom) - { - VertexActivityRandom = activityRandom; - setupVerticesActivity(); - } - bool getVertexActivityRandom() const { return VertexActivityRandom; } - -private: - // this will calculate ALL vertices for the whole square - void calculateVertices(); - // this will calculate the vertices two sections around one vertex (like a great hexagon) --> necessary to calculate - // the possible building for a vertex view this pic to understand the indices - // X=7 X=8 X=9 - // X=10 X=1 X=2 X=11 - // X=12 X=3 X=0 X=4 X=13 - // X=14 X=5 X=6 X=15 - // X=16 X=17 X=18 - template - void calculateVerticesAround(std::array& newVertices, Position pos); - // this will setup the 'active' variable of each vertices depending on 'ChangeSection' - void setupVerticesActivity(); - Position correctMouseBlit(Position vertexPos) const; - void modifyVertex(); - void modifyHeightRaise(Position pos); - void modifyHeightReduce(Position pos); - void modifyHeightPlane(Position pos, Uint8 h); - void modifyHeightMakeBigHouse(Position pos); - void modifyShading(Position pos); - void modifyTexture(Position pos, bool rsu, bool usd); - void modifyTextureMakeHarbour(Position pos); - void modifyObject(Position pos); - void modifyAnimal(Position pos); - void modifyBuild(Position pos); - void modifyResource(Position pos); - void modifyPlayer(Position pos); - void rotateMap(); - void MirrorMapOnXAxis(); - void MirrorMapOnYAxis(); - void onLeftMouseDown(const Point32& pos); -}; diff --git a/CSurface.cpp b/CSurface.cpp deleted file mode 100644 index 9ae6864..0000000 --- a/CSurface.cpp +++ /dev/null @@ -1,1427 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "CSurface.h" -#include "CGame.h" -#include "CMap.h" -#include "Rect.h" -#include "globals.h" -#include "gameData/EdgeDesc.h" -#include "gameData/TerrainDesc.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -static uint8_t intensityToColor(Sint32 val) -{ - if(val <= 0) - return 0; - constexpr Sint32 maxVal = 2 * 65536; - if(val >= maxVal) - return 255; - return static_cast((val * 255 + maxVal / 2) / maxVal); -} - -// For border rendering we use GL_MODULATE (no RGB_SCALE), so -// [0, 65536] maps linearly to [0, 255]. -static uint8_t intensityToModulate(Sint32 val) -{ - if(val <= 0) - return 0; - constexpr Sint32 maxVal = 65536; - if(val >= maxVal) - return 255; - return static_cast((val * 255 + maxVal / 2) / maxVal); -} - -namespace { -const TerrainDesc* getTerrainDesc(const bobMAP& map, Uint8 rawTextureId) -{ - const Uint8 s2Id = rawTextureId & ~0x40; - if(s2Id < map.s2IdToTerrain.size()) - { - const auto idx = map.s2IdToTerrain[s2Id]; - if(idx) - return &global::worldDesc.get(idx); - } - return nullptr; -} - -static void DrawFadedTexturedTrigon(const Point16& p1, const Point16& p2, const Point16& p3, const Rect& rect, - Sint32 I1, Sint32 I2, float texW, float texH) -{ - uint8_t c1 = intensityToModulate(I1); - uint8_t c2 = intensityToModulate(I2); - uint8_t ct = c2; - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBegin(GL_TRIANGLES); - glTexCoord2f(float(rect.left) / texW, float(rect.top) / texH); - glColor4ub(c1, c1, c1, 255); - glVertex2f(float(p1.x), float(p1.y)); - glTexCoord2f(float(rect.right) / texW, float(rect.top) / texH); - glColor4ub(c2, c2, c2, 255); - glVertex2f(float(p2.x), float(p2.y)); - glTexCoord2f(float((rect.left + rect.right) / 2) / texW, float(rect.bottom) / texH); - glColor4ub(ct, ct, ct, 255); - glVertex2f(float(p3.x), float(p3.y)); - glEnd(); -} - -} // namespace - -bool CSurface::drawTextures = false; - -void CSurface::DrawTriangleField(const DisplayRectangle& displayRect, const bobMAP& myMap) -{ - Uint16 width = myMap.width; - Uint16 height = myMap.height; - auto type = myMap.type; - EditorMapNode tempP1, tempP2, tempP3; - - // min size to avoid underflows - if(width < 8 || height < 8) - return; - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - - // draw triangle field - // NOTE: WE DO THIS TWICE, AT FIRST ONLY TRIANGLE-TEXTURES, AT SECOND THE TEXTURE-BORDERS AND OBJECTS - for(int i = 0; i < 2; i++) - { - drawTextures = (i == 0); - - for(int k = 0; k < 4; k++) - { - // IMPORTANT: integer values like +8 or -1 are for tolerance to beware of high triangles are not shown - - int row_start = std::max(0, displayRect.top / TR_H - 1); - int row_end = std::min(height, displayRect.bottom / TR_H + 2); - int col_start = std::max(0, displayRect.left / TR_W - 1); - int col_end = std::min(width, displayRect.right / TR_W + 2); - bool view_outside_edges; - - if(k > 0) - { - // now call DrawTriangle for all triangles outside the map edges - view_outside_edges = false; - - if(k == 1 || k == 3) - { - // at first call DrawTriangle for all triangles up or down outside - if(displayRect.top < 0) - { - row_start = std::max(0, height - 1 - (-displayRect.top / TR_H) - 1); - row_end = height - 1; - view_outside_edges = true; - } else if(displayRect.bottom > myMap.height_pixel) - { - row_start = 0; - row_end = (displayRect.bottom - myMap.height_pixel) / TR_H + 8; - view_outside_edges = true; - } else if(displayRect.top <= 2 * TR_H) - { - // this is for draw triangles that are reduced under the lower map edge (have bigger y-coords as - // myMap.height_pixel) - row_start = height - 3; - row_end = height - 1; - view_outside_edges = true; - } else if(displayRect.bottom >= (myMap.height_pixel - 8 * TR_H)) - { - // this is for draw triangles that are raised over the upper map edge (have negative y-coords) - row_start = 0; - row_end = 8; - view_outside_edges = true; - } - } - - if(k == 2 || k == 3) - { - // now call DrawTriangle for all triangles left or right outside - if(displayRect.left <= 0) - { - col_start = std::max(0, width - 1 - (-displayRect.left / TR_W) - 1); - col_end = width - 1; - view_outside_edges = true; - } else if(displayRect.left < TR_W) - { - col_start = width - 2; - col_end = width - 1; - view_outside_edges = true; - } else if(displayRect.right > myMap.width_pixel) - { - col_start = 0; - col_end = (displayRect.right - myMap.width_pixel) / TR_W + 1; - view_outside_edges = true; - } - } - - // if displayRect is not outside the map edges, there is nothing to do - if(!view_outside_edges) - continue; - } - - assert(col_start >= 0); - assert(row_start >= 0); - assert(col_start <= col_end); - assert(row_start <= row_end); - - for(unsigned y = row_start; y < height - 1u && y <= static_cast(row_end); y++) - { - if(y % 2 == 0) - { - // first RightSideUp - tempP2 = myMap.getVertex(width - 1, y + 1); - tempP2.x = 0; - DrawTriangle(displayRect, myMap, type, myMap.getVertex(0, y), tempP2, myMap.getVertex(0, y + 1)); - for(unsigned x = std::max(col_start, 1); x < width && x <= static_cast(col_end); x++) - { - // RightSideUp - DrawTriangle(displayRect, myMap, type, myMap.getVertex(x, y), myMap.getVertex(x - 1, y + 1), - myMap.getVertex(x, y + 1)); - // UpSideDown - DrawTriangle(displayRect, myMap, type, myMap.getVertex(x - 1, y + 1), myMap.getVertex(x - 1, y), - myMap.getVertex(x, y)); - } - // last UpSideDown - tempP3 = myMap.getVertex(0, y); - tempP3.x = myMap.getVertex(width - 1, y).x + TR_W; - DrawTriangle(displayRect, myMap, type, myMap.getVertex(width - 1, y + 1), - myMap.getVertex(width - 1, y), tempP3); - } else - { - for(unsigned x = col_start; x < width - 1u && x <= static_cast(col_end); x++) - { - // RightSideUp - DrawTriangle(displayRect, myMap, type, myMap.getVertex(x, y), myMap.getVertex(x, y + 1), - myMap.getVertex(x + 1, y + 1)); - // UpSideDown - DrawTriangle(displayRect, myMap, type, myMap.getVertex(x + 1, y + 1), myMap.getVertex(x, y), - myMap.getVertex(x + 1, y)); - } - // last RightSideUp - tempP3 = myMap.getVertex(0, y + 1); - tempP3.x = myMap.getVertex(width - 1, y + 1).x + TR_W; - DrawTriangle(displayRect, myMap, type, myMap.getVertex(width - 1, y), - myMap.getVertex(width - 1, y + 1), tempP3); - // last UpSideDown - tempP1 = myMap.getVertex(0, y + 1); - tempP1.x = myMap.getVertex(width - 1, y + 1).x + TR_W; - tempP3 = myMap.getVertex(0, y); - tempP3.x = myMap.getVertex(width - 1, y).x + TR_W; - DrawTriangle(displayRect, myMap, type, tempP1, myMap.getVertex(width - 1, y), tempP3); - } - } - - // draw last line - for(unsigned x = col_start; x < width - 1u && x <= static_cast(col_end); x++) - { - // RightSideUp - tempP2 = myMap.getVertex(x, 0); - tempP2.y = height * TR_H + myMap.getVertex(x, 0).y; - tempP3 = myMap.getVertex(x + 1, 0); - tempP3.y = height * TR_H + myMap.getVertex(x + 1, 0).y; - DrawTriangle(displayRect, myMap, type, myMap.getVertex(x, height - 1), tempP2, tempP3); - // UpSideDown - tempP1 = myMap.getVertex(x + 1, 0); - tempP1.y = height * TR_H + myMap.getVertex(x + 1, 0).y; - DrawTriangle(displayRect, myMap, type, tempP1, myMap.getVertex(x, height - 1), - myMap.getVertex(x + 1, height - 1)); - } - } - - // last RightSideUp - tempP2 = myMap.getVertex(width - 1, 0); - tempP2.y += height * TR_H; - tempP3 = myMap.getVertex(0, 0); - tempP3.x = myMap.getVertex(width - 1, 0).x + TR_W; - tempP3.y += height * TR_H; - DrawTriangle(displayRect, myMap, type, myMap.getVertex(width - 1, height - 1), tempP2, tempP3); - // last UpSideDown - tempP1 = myMap.getVertex(0, 0); - tempP1.x = myMap.getVertex(width - 1, 0).x + TR_W; - tempP1.y += height * TR_H; - tempP3 = myMap.getVertex(0, height - 1); - tempP3.x = myMap.getVertex(width - 1, height - 1).x + TR_W; - DrawTriangle(displayRect, myMap, type, tempP1, myMap.getVertex(width - 1, height - 1), tempP3); - } -} - -namespace { -enum class BorderPreference -{ - None, - LeftTop, - RightBottom -}; -BorderPreference CalcBorders(const bobMAP& map, Uint8 s2Id1, Uint8 s2Id2, Rect& borderRect) -{ - // we have to decide which border to blit, "left or right" or "top or bottom" - s2Id1 &= ~(0x40 | 0x80); - s2Id2 &= ~(0x40 | 0x80); - - assert(s2Id1 < map.s2IdToTerrain.size()); - assert(s2Id2 < map.s2IdToTerrain.size()); - - DescIdx idxTop = map.s2IdToTerrain[s2Id1]; - DescIdx idxBottom = map.s2IdToTerrain[s2Id2]; - if(idxTop == idxBottom) - return BorderPreference::None; - const TerrainDesc& t1 = global::worldDesc.get(idxTop); - const TerrainDesc& t2 = global::worldDesc.get(idxBottom); - if(t1.edgePriority > t2.edgePriority) - { - if(!t1.edgeType) - return BorderPreference::None; - borderRect = global::worldDesc.get(t1.edgeType).posInTexture; - return BorderPreference::LeftTop; - } else if(t1.edgePriority < t2.edgePriority) - { - if(!t2.edgeType) - return BorderPreference::None; - borderRect = global::worldDesc.get(t2.edgeType).posInTexture; - return BorderPreference::RightBottom; - } - return BorderPreference::None; -} - -template -constexpr bool isInRange(T val, T min, T max) -{ - return val >= min && val <= max; -} - -/// Return true if triangle is drawn -bool GetAdjustedPoints(const DisplayRectangle& displayRect, const bobMAP& myMap, Point32& p1, Point32& p2, Point32& p3) -{ - if((!isInRange(p1.x, displayRect.left, displayRect.right) && !isInRange(p2.x, displayRect.left, displayRect.right) - && !isInRange(p3.x, displayRect.left, displayRect.right)) - || (!isInRange(p1.y, displayRect.top, displayRect.bottom) - && !isInRange(p2.y, displayRect.top, displayRect.bottom) - && !isInRange(p3.y, displayRect.top, displayRect.bottom))) - { - bool triangle_shown = false; - - if(displayRect.left <= 0) - { - int outside_left = displayRect.left; - int outside_right = 0; - if(isInRange(p1.x - myMap.width_pixel, outside_left, outside_right) - || isInRange(p2.x - myMap.width_pixel, outside_left, outside_right) - || isInRange(p3.x - myMap.width_pixel, outside_left, outside_right)) - { - p1.x -= myMap.width_pixel; - p2.x -= myMap.width_pixel; - p3.x -= myMap.width_pixel; - triangle_shown = true; - } - } else if(displayRect.left < TR_W) - { - int outside_left = displayRect.left; - int outside_right = displayRect.left + TR_W; - if(isInRange(p1.x - myMap.width_pixel, outside_left, outside_right) - || isInRange(p2.x - myMap.width_pixel, outside_left, outside_right) - || isInRange(p3.x - myMap.width_pixel, outside_left, outside_right)) - { - p1.x -= myMap.width_pixel; - p2.x -= myMap.width_pixel; - p3.x -= myMap.width_pixel; - triangle_shown = true; - } - } else if(displayRect.right > myMap.width_pixel) - { - int outside_left = myMap.width_pixel; - int outside_right = displayRect.right; - if(isInRange(p1.x + myMap.width_pixel, outside_left, outside_right) - || isInRange(p2.x + myMap.width_pixel, outside_left, outside_right) - || isInRange(p3.x + myMap.width_pixel, outside_left, outside_right)) - { - p1.x += myMap.width_pixel; - p2.x += myMap.width_pixel; - p3.x += myMap.width_pixel; - triangle_shown = true; - } - } - - if(displayRect.top < 0) - { - int outside_top = displayRect.top; - int outside_bottom = 0; - if(isInRange(p1.y - myMap.height_pixel, outside_top, outside_bottom) - || isInRange(p2.y - myMap.height_pixel, outside_top, outside_bottom) - || isInRange(p3.y - myMap.height_pixel, outside_top, outside_bottom)) - { - p1.y -= myMap.height_pixel; - p2.y -= myMap.height_pixel; - p3.y -= myMap.height_pixel; - triangle_shown = true; - } - } else if(displayRect.bottom > myMap.height_pixel) - { - int outside_top = myMap.height_pixel; - int outside_bottom = displayRect.bottom; - if(isInRange(p1.y + myMap.height_pixel, outside_top, outside_bottom) - || isInRange(p2.y + myMap.height_pixel, outside_top, outside_bottom) - || isInRange(p3.y + myMap.height_pixel, outside_top, outside_bottom)) - { - p1.y += myMap.height_pixel; - p2.y += myMap.height_pixel; - p3.y += myMap.height_pixel; - triangle_shown = true; - } - } - - // now test if triangle has negative y-coords cause it's raised over the upper map edge - if(p1.y < 0 || p2.y < 0 || p3.y < 0) - { - if(isInRange(p1.y + myMap.height_pixel, displayRect.top, displayRect.bottom) - || isInRange(p2.y + myMap.height_pixel, displayRect.top, displayRect.bottom) - || isInRange(p3.y + myMap.height_pixel, displayRect.top, displayRect.bottom)) - { - p1.y += myMap.height_pixel; - p2.y += myMap.height_pixel; - p3.y += myMap.height_pixel; - triangle_shown = true; - } - } - - // now test if triangle has bigger y-coords as myMap.height_pixel cause it's reduced under the lower map edge - if(p1.y > myMap.height_pixel || p2.y > myMap.height_pixel || p3.y > myMap.height_pixel) - { - if(isInRange(p1.y - myMap.height_pixel, displayRect.top, displayRect.bottom) - || isInRange(p2.y - myMap.height_pixel, displayRect.top, displayRect.bottom) - || isInRange(p3.y - myMap.height_pixel, displayRect.top, displayRect.bottom)) - { - p1.y -= myMap.height_pixel; - p2.y -= myMap.height_pixel; - p3.y -= myMap.height_pixel; - triangle_shown = true; - } - } - - if(!triangle_shown) - return false; - } - return true; -} -} // namespace - -// palette animation helpers - -/// Holds pre-rendered frames for one palette-animated terrain. -struct AnimFrames -{ - std::vector frames; -}; - -static std::map, AnimFrames> s_animFrameCache; - -static const AnimFrames* getAnimFrames(const TerrainDesc& td, MapType mapType) -{ - // Determine tileset index from map type - auto& ta = global::tilesetAnims[static_cast(mapType)]; - if(ta.anims.empty()) - return nullptr; - // palAnimIdx is the index in the tileset Archiv (0 = bitmap, 1+ = animations) - // ta.anims[0] = Archiv[1], ta.anims[1] = Archiv[2], etc. - if(td.palAnimIdx < 1) - return nullptr; - size_t animIdx = static_cast(td.palAnimIdx) - 1; - if(animIdx >= ta.anims.size()) - return nullptr; - const auto* anim = ta.anims[animIdx]; - if(!anim || !anim->isActive) - return nullptr; - - unsigned numFrames = anim->lastClr - anim->firstClr + 1; - if(numFrames < 2) - return nullptr; - if(numFrames > 32) - numFrames = 32; - - auto key = std::make_pair(&td, static_cast(mapType)); - auto it = s_animFrameCache.find(key); - if(it != s_animFrameCache.end()) - return &it->second; - - // Get the tileset bitmap from the typed archive - const libsiedler2::baseArchivItem_Bitmap* tsBmp = - dynamic_cast(global::typedArchives[ta.archive].get(ta.bmpIdx)); - if(!tsBmp) - return nullptr; - const auto* srcPal = tsBmp->getPalette(); - if(!srcPal) - return nullptr; - - // Extract the terrain sub-rect from the tileset - auto r = td.posInTexture; - Extent texSize = r.getSize(); - if(texSize.x == 0 || texSize.y == 0) - return nullptr; - - // Create paletted pixel buffer with the sub-rect - libsiedler2::PixelBufferPaletted buffer(texSize.x, texSize.y); - if(tsBmp->print(buffer, nullptr, 0, 0, r.left, r.top, texSize.x, texSize.y)) - return nullptr; - - // Build the per-frame animation object (direction hardcoded to false, - // matching s25client's ExtractAnimatedTexture which ignores the CRNG flags) - libsiedler2::ArchivItem_PaletteAnimation frameStep; - frameStep.isActive = true; - frameStep.moveUp = false; - frameStep.firstClr = anim->firstClr; - frameStep.lastClr = anim->lastClr; - - auto& result = s_animFrameCache[key]; - result.frames.reserve(numFrames); - - std::unique_ptr curPal; - for(unsigned fi = 0; fi < numFrames; fi++) - { - auto pal = (fi == 0) ? std::make_unique(*srcPal) : frameStep.apply(*curPal); - if(!pal) - continue; - - // Render frame to BGRA - libsiedler2::PixelBufferBGRA bgraBuf(texSize.x, texSize.y); - for(unsigned y = 0; y < texSize.y; y++) - { - for(unsigned x = 0; x < texSize.x; x++) - { - auto idx = buffer.get(x, y); - auto c = pal->get(idx); - uint32_t* dst = reinterpret_cast(bgraBuf.getPixelPtr()) + y * texSize.x + x; - *dst = (0xFFu << 24) | (uint32_t(c.r) << 16) | (uint32_t(c.g) << 8) | uint32_t(c.b); - } - } - - Texture tex; - libsiedler2::ArchivItem_Bitmap_Raw tmpBmp; - tmpBmp.create(texSize.x, texSize.y, bgraBuf.getPixelPtr(), texSize.x, texSize.y, - libsiedler2::TextureFormat::BGRA, nullptr); - tex.load(tmpBmp); - result.frames.push_back(std::move(tex)); - - curPal = std::move(pal); - } - - return result.frames.empty() ? nullptr : &result; -} - -/// Choose the current animation frame based on elapsed wall-clock time. -/// Matches s25client: each frame is shown for 630*5/16 = ~197 ms. -static unsigned getAnimFrameIdx(const AnimFrames& af) -{ - unsigned numFrames = af.frames.size(); - if(numFrames <= 1) - return 0; - // Match s25client's GetGlobalAnimation(numFrames, 5*numFrames, 16, 0): - // unit = 630ms * 5 * numFrames / 16 → 197ms per frame - constexpr unsigned unitPerFrame = 630 * 5 / 16; // ≈ 197 ms - uint32_t now = SDL_GetTicks(); - return (now / unitPerFrame) % numFrames; -} - -void CSurface::GetTerrainTextureCoords(MapType mapType, TriangleTerrainType texture, bool isRSU, Point16& upper, - Point16& left, Point16& right, Point16& upper2, Point16& left2, Point16& right2) -{ - switch(texture) - { - // in case of USD-Triangle "upper.x" and "upper.y" means "lowerX" and "lowerY" - case TRIANGLE_TEXTURE_STEPPE_MEADOW1: - upper = Point16(17, 96); - left = Point16(0, 126); - right = Point16(35, 126); - break; - case TRIANGLE_TEXTURE_MINING1: - upper = Point16(17, 48); - left = Point16(0, 78); - right = Point16(35, 78); - break; - case TRIANGLE_TEXTURE_SNOW: - if(isRSU) - { - upper = Point16(17, 0); - left = Point16(0, 30); - right = Point16(35, 30); - } else - { - upper = Point16(17, 28); - left = Point16(0, 0); - right = Point16(37, 0); - } - if(mapType == MAP_WINTERLAND) - { - if(isRSU) - { - upper2 = Point16(231, 61); - left2 = Point16(207, 62); - right2 = Point16(223, 78); - } else - { - upper2 = Point16(224, 79); - left2 = Point16(232, 62); - right2 = Point16(245, 76); - } - } - break; - case TRIANGLE_TEXTURE_SWAMP: - upper = Point16(113, 0); - left = Point16(96, 30); - right = Point16(131, 30); - if(mapType == MAP_WINTERLAND) - { - if(isRSU) - { - upper2 = Point16(231, 61); - left2 = Point16(207, 62); - right2 = Point16(223, 78); - } else - { - upper2 = Point16(224, 79); - left2 = Point16(232, 62); - right2 = Point16(245, 76); - } - } - break; - case TRIANGLE_TEXTURE_STEPPE: - case TRIANGLE_TEXTURE_STEPPE_: - case TRIANGLE_TEXTURE_STEPPE__: - case TRIANGLE_TEXTURE_STEPPE___: - upper = Point16(65, 0); - left = Point16(48, 30); - right = Point16(83, 30); - break; - case TRIANGLE_TEXTURE_WATER: - case TRIANGLE_TEXTURE_WATER_: - case TRIANGLE_TEXTURE_WATER__: - if(isRSU) - { - upper = Point16(231, 61); - left = Point16(207, 62); - right = Point16(223, 78); - } else - { - upper = Point16(224, 79); - left = Point16(232, 62); - right = Point16(245, 76); - } - break; - case TRIANGLE_TEXTURE_MEADOW1: - upper = Point16(65, 96); - left = Point16(48, 126); - right = Point16(83, 126); - break; - case TRIANGLE_TEXTURE_MEADOW2: - upper = Point16(113, 96); - left = Point16(96, 126); - right = Point16(131, 126); - break; - case TRIANGLE_TEXTURE_MEADOW3: - upper = Point16(161, 96); - left = Point16(144, 126); - right = Point16(179, 126); - break; - case TRIANGLE_TEXTURE_MINING2: - upper = Point16(65, 48); - left = Point16(48, 78); - right = Point16(83, 78); - break; - case TRIANGLE_TEXTURE_MINING3: - upper = Point16(113, 48); - left = Point16(96, 78); - right = Point16(131, 78); - break; - case TRIANGLE_TEXTURE_MINING4: - upper = Point16(161, 48); - left = Point16(144, 78); - right = Point16(179, 78); - break; - case TRIANGLE_TEXTURE_STEPPE_MEADOW2: - upper = Point16(17, 144); - left = Point16(0, 174); - right = Point16(35, 174); - break; - case TRIANGLE_TEXTURE_FLOWER: - upper = Point16(161, 0); - left = Point16(144, 30); - right = Point16(179, 30); - break; - case TRIANGLE_TEXTURE_LAVA: - if(isRSU) - { - upper = Point16(231, 117); - left = Point16(207, 118); - right = Point16(223, 134); - } else - { - upper = Point16(224, 135); - left = Point16(232, 118); - right = Point16(245, 132); - } - break; - case TRIANGLE_TEXTURE_MINING_MEADOW: - upper = Point16(65, 144); - left = Point16(48, 174); - right = Point16(83, 174); - break; - default: // TRIANGLE_TEXTURE_FLOWER - upper = Point16(161, 0); - left = Point16(144, 30); - right = Point16(179, 30); - break; - } -} - -void CSurface::DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& myMap, MapType type, const EditorMapNode& P1, - const EditorMapNode& P2, const EditorMapNode& P3) -{ - Point32 p1(P1.x, P1.y); - Point32 p2(P2.x, P2.y); - Point32 p3(P3.x, P3.y); - - // prevent drawing triangles that are not shown - if(!GetAdjustedPoints(displayRect, myMap, p1, p2, p3)) - return; - - static int roundCount = 0; - static Uint32 roundTimeObjects = SDL_GetTicks(); - if(SDL_GetTicks() - roundTimeObjects > 30) - { - roundTimeObjects = SDL_GetTicks(); - if(roundCount >= 7) - roundCount = 0; - else - roundCount++; - } - - // Determine tileset texture - ArchiveID tsArchive; - switch(type) - { - case MAP_GREENLAND: - default: tsArchive = ArchiveID::TEX5; break; - case MAP_WASTELAND: tsArchive = ArchiveID::TEX6; break; - case MAP_WINTERLAND: tsArchive = ArchiveID::TEX7; break; - } - bool const isRSU = p1.y < p2.y; - auto& tilesetTex = Texture::getTexture(tsArchive, 0); - if(!tilesetTex.isValid()) - return; - glBindTexture(GL_TEXTURE_2D, tilesetTex.getHandle()); - - const auto* tsBmp = - dynamic_cast(global::typedArchives[tsArchive].get(0)); - const float texW = tsBmp ? static_cast(tsBmp->getWidth()) : 0.0f; - const float texH = tsBmp ? static_cast(tsBmp->getHeight()) : 0.0f; - if(drawTextures) - { - Point16 upper, left, right, upper2, left2, right2; - auto const texture = - TriangleTerrainType((isRSU ? P1.rsuTexture : P2.usdTexture) & ~0x40); // Mask out harbor bit - GetTerrainTextureCoords(type, texture, isRSU, upper, left, right, upper2, left2, right2); - - const float uvs[3][2] = {{static_cast(upper.x) / texW, static_cast(upper.y) / texH}, - {static_cast(left.x) / texW, static_cast(left.y) / texH}, - {static_cast(right.x) / texW, static_cast(right.y) / texH}}; - - const float vertCoord[3][2] = { - {float(p1.x), float(p1.y)}, {float(p2.x), float(p2.y)}, {float(p3.x), float(p3.y)}}; - const EditorMapNode* verts[3] = {&P1, &P2, &P3}; - - // --- palette animation: any terrain with palAnimIdx >= 0 --- - if(const auto* terrainDesc = getTerrainDesc(myMap, texture); terrainDesc && terrainDesc->palAnimIdx >= 0) - { - const auto* af = getAnimFrames(*terrainDesc, type); - if(af && !af->frames.empty()) - { - unsigned frameIdx = getAnimFrameIdx(*af); - glBindTexture(GL_TEXTURE_2D, af->frames[frameIdx].getHandle()); - - // Use the GDL triangle UVs (the animated texture covers only the terrain sub-rect) - auto tri = isRSU ? terrainDesc->GetRSUTriangle() : terrainDesc->GetUSDTriangle(); - auto r = terrainDesc->posInTexture; - float ox = static_cast(r.left); - float oy = static_cast(r.top); - float sx = static_cast(r.getSize().x); - float sy = static_cast(r.getSize().y); - float nu[3][2] = {{(tri.tip.x - ox) / sx, (tri.tip.y - oy) / sy}, - {(tri.left.x - ox) / sx, (tri.left.y - oy) / sy}, - {(tri.right.x - ox) / sx, (tri.right.y - oy) / sy}}; - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); - glBegin(GL_TRIANGLES); - for(int k = 0; k < 3; k++) - { - glTexCoord2f(nu[k][0], nu[k][1]); - glColor4ub(intensityToColor(verts[k]->i), intensityToColor(verts[k]->i), - intensityToColor(verts[k]->i), 255); - glVertex2f(vertCoord[k][0], vertCoord[k][1]); - } - glEnd(); - return; - } - } - - // Most terrains: draw from the tileset with standard shading - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); - glBegin(GL_TRIANGLES); - for(int k = 0; k < 3; k++) - { - glTexCoord2f(uvs[k][0], uvs[k][1]); - glColor4ub(intensityToColor(verts[k]->i), intensityToColor(verts[k]->i), intensityToColor(verts[k]->i), - 255); - glVertex2f(vertCoord[k][0], vertCoord[k][1]); - } - glEnd(); - return; - } - - // blit borders - /// PRIORITY FROM HIGH TO LOW: SNOW, MINING_MEADOW, STEPPE, STEPPE_MEADOW2, MINING, MEADOW, FLOWER, STEPPE_MEADOW1, - /// SWAMP, WATER, LAVA - if(global::s2->getMapObj()->getRenderBorders()) - { - // RSU-Triangle - if(isRSU) - { - // left upper / right lower edge - therefore get the usd-texture from left to compare - Uint16 col = (P1.VertexX - 1 < 0 ? myMap.width - 1 : P1.VertexX - 1); - EditorMapNode tempP = myMap.getVertex(col, P1.VertexY); - - Rect BorderRect; - auto borderSide = CalcBorders(myMap, tempP.usdTexture, P1.rsuTexture, BorderRect); - if(borderSide != BorderPreference::None) - { - Point16 tmpP1{p1}, tmpP2{p2}; - Point32 thirdPt; - if(borderSide == BorderPreference::LeftTop) - thirdPt = p3; - else - { - tmpP1 += Point16(1, 0); - tmpP2 += Point16(1, 0); - thirdPt = Point32(tempP.x, tempP.y); - // Shift it close to p1 - auto diff = thirdPt - p1; - if(diff.x < -myMap.width_pixel / 2) - thirdPt.x += myMap.width_pixel; - else if(diff.x > myMap.width_pixel / 2) - thirdPt.x -= myMap.width_pixel; - if(diff.y < -myMap.height_pixel / 2) - thirdPt.y += myMap.height_pixel; - else if(diff.y > myMap.height_pixel / 2) - thirdPt.y -= myMap.height_pixel; - } - Point16 tipPt{(p1 + p2 + thirdPt) / 3}; - - DrawFadedTexturedTrigon(tmpP1, tmpP2, tipPt, BorderRect, P1.i, P2.i, texW, texH); - } - } - // USD-Triangle - else - { - Rect BorderRect; - // left lower / right upper - auto borderSide = CalcBorders(myMap, P2.rsuTexture, P2.usdTexture, BorderRect); - - if(borderSide != BorderPreference::None) - { - Uint16 col = (P1.VertexX - 1 < 0 ? myMap.width - 1 : P1.VertexX - 1); - EditorMapNode tempP = myMap.getVertex(col, P1.VertexY); - - Point16 tmpP1{p1}, tmpP2{p2}; - Point32 thirdPt; - if(borderSide == BorderPreference::LeftTop) - { - thirdPt = p3; - tmpP1 -= Point16(1, 0); - tmpP2 -= Point16(1, 0); - } else - { - thirdPt = Point32(tempP.x, tempP.y); - // Shift it close to p1 - auto diff = thirdPt - p1; - if(diff.x < -myMap.width_pixel / 2) - thirdPt.x += myMap.width_pixel; - else if(diff.x > myMap.width_pixel / 2) - thirdPt.x -= myMap.width_pixel; - if(diff.y < -myMap.height_pixel / 2) - thirdPt.y += myMap.height_pixel; - else if(diff.y > myMap.height_pixel / 2) - thirdPt.y -= myMap.height_pixel; - } - - Point16 tipPt{(p1 + p2 + thirdPt) / 3}; - - DrawFadedTexturedTrigon(tmpP1, tmpP2, tipPt, BorderRect, P1.i, P2.i, texW, texH); - } - - // top / bottom - therefore get the rsu-texture one line above to compare - Uint16 row = (P2.VertexY - 1 < 0 ? myMap.height - 1 : P2.VertexY - 1); - Uint16 col = (P2.VertexY % 2 == 0 ? P2.VertexX : (P2.VertexX + 1 > myMap.width - 1 ? 0 : P2.VertexX + 1)); - EditorMapNode tempP = myMap.getVertex(col, row); - - borderSide = CalcBorders(myMap, tempP.rsuTexture, P2.usdTexture, BorderRect); - if(borderSide != BorderPreference::None) - { - Point32 thirdPt; - if(borderSide == BorderPreference::LeftTop) - thirdPt = p1; - else - { - thirdPt = Point32(tempP.x, tempP.y); - // Shift it close to p2 - auto diff = thirdPt - p2; - if(diff.x < -myMap.width_pixel / 2) - thirdPt.x += myMap.width_pixel; - else if(diff.x > myMap.width_pixel / 2) - thirdPt.x -= myMap.width_pixel; - if(diff.y < -myMap.height_pixel / 2) - thirdPt.y += myMap.height_pixel; - else if(diff.y > myMap.height_pixel / 2) - thirdPt.y -= myMap.height_pixel; - } - Point16 tipPt{(p2 + p3 + thirdPt) / 3}; - - DrawFadedTexturedTrigon(Point16(p2), Point16(p3), tipPt, BorderRect, P2.i, P3.i, texW, texH); - } - } - } - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - // blit picture to vertex (trees, animals, buildings and so on) --> BUT ONLY AT node1 ON RIGHTSIDEUP-TRIANGLES - - // blit objects - if(!isRSU) - { - int objIdx = 0; - switch(P2.objectInfo) - { - // tree - case 0xC4: - if(P2.objectType >= 0x30 && P2.objectType <= 0x37) - { - if(P2.objectType + roundCount > 0x37) - objIdx = MAPPIC_TREE_PINE + (P2.objectType - 0x30) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_PINE + (P2.objectType - 0x30) + roundCount; - - } else if(P2.objectType >= 0x70 && P2.objectType <= 0x77) - { - if(P2.objectType + roundCount > 0x77) - objIdx = MAPPIC_TREE_BIRCH + (P2.objectType - 0x70) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_BIRCH + (P2.objectType - 0x70) + roundCount; - } else if(P2.objectType >= 0xB0 && P2.objectType <= 0xB7) - { - if(P2.objectType + roundCount > 0xB7) - objIdx = MAPPIC_TREE_OAK + (P2.objectType - 0xB0) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_OAK + (P2.objectType - 0xB0) + roundCount; - } else if(P2.objectType >= 0xF0 && P2.objectType <= 0xF7) - { - if(P2.objectType + roundCount > 0xF7) - objIdx = MAPPIC_TREE_PALM1 + (P2.objectType - 0xF0) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_PALM1 + (P2.objectType - 0xF0) + roundCount; - } - break; - // tree - case 0xC5: - if(P2.objectType >= 0x30 && P2.objectType <= 0x37) - { - if(P2.objectType + roundCount > 0x37) - objIdx = MAPPIC_TREE_PALM2 + (P2.objectType - 0x30) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_PALM2 + (P2.objectType - 0x30) + roundCount; - - } else if(P2.objectType >= 0x70 && P2.objectType <= 0x77) - { - if(P2.objectType + roundCount > 0x77) - objIdx = MAPPIC_TREE_PINEAPPLE + (P2.objectType - 0x70) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_PINEAPPLE + (P2.objectType - 0x70) + roundCount; - } else if(P2.objectType >= 0xB0 && P2.objectType <= 0xB7) - { - if(P2.objectType + roundCount > 0xB7) - objIdx = MAPPIC_TREE_CYPRESS + (P2.objectType - 0xB0) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_CYPRESS + (P2.objectType - 0xB0) + roundCount; - } else if(P2.objectType >= 0xF0 && P2.objectType <= 0xF7) - { - if(P2.objectType + roundCount > 0xF7) - objIdx = MAPPIC_TREE_CHERRY + (P2.objectType - 0xF0) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_CHERRY + (P2.objectType - 0xF0) + roundCount; - } - break; - // tree - case 0xC6: - if(P2.objectType >= 0x30 && P2.objectType <= 0x37) - { - if(P2.objectType + roundCount > 0x37) - objIdx = MAPPIC_TREE_FIR + (P2.objectType - 0x30) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_FIR + (P2.objectType - 0x30) + roundCount; - } - break; - // landscape - case 0xC8: - switch(P2.objectType) - { - case 0x00: objIdx = MAPPIC_MUSHROOM1; break; - case 0x01: objIdx = MAPPIC_MUSHROOM2; break; - case 0x02: objIdx = MAPPIC_STONE1; break; - case 0x03: objIdx = MAPPIC_STONE2; break; - case 0x04: objIdx = MAPPIC_STONE3; break; - case 0x05: objIdx = MAPPIC_TREE_TRUNK_DEAD; break; - case 0x06: objIdx = MAPPIC_TREE_DEAD; break; - case 0x07: objIdx = MAPPIC_BONE1; break; - case 0x08: objIdx = MAPPIC_BONE2; break; - case 0x09: objIdx = MAPPIC_FLOWERS; break; - case 0x10: objIdx = MAPPIC_BUSH2; break; - case 0x11: objIdx = MAPPIC_BUSH3; break; - case 0x12: objIdx = MAPPIC_BUSH4; break; - - case 0x0A: objIdx = MAPPIC_BUSH1; break; - - case 0x0C: objIdx = MAPPIC_CACTUS1; break; - case 0x0D: objIdx = MAPPIC_CACTUS2; break; - case 0x0E: objIdx = MAPPIC_SHRUB1; break; - case 0x0F: objIdx = MAPPIC_SHRUB2; break; - - case 0x13: objIdx = MAPPIC_SHRUB3; break; - case 0x14: objIdx = MAPPIC_SHRUB4; break; - - case 0x16: objIdx = MAPPIC_DOOR; break; - - case 0x18: - Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE1).drawSprite(p2); - objIdx = 0; - break; - case 0x19: - Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE2).drawSprite(p2); - objIdx = 0; - break; - case 0x1A: - Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE3).drawSprite(p2); - objIdx = 0; - break; - case 0x1B: - Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE4).drawSprite(p2); - objIdx = 0; - break; - case 0x1C: - Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE5).drawSprite(p2); - objIdx = 0; - break; - case 0x1D: - Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE6).drawSprite(p2); - objIdx = 0; - break; - case 0x1E: - Texture::getTexture(ArchiveID::MIS1BOBS, MIS1BOBS_STONE7).drawSprite(p2); - objIdx = 0; - break; - - case 0x22: objIdx = MAPPIC_MUSHROOM3; break; - - case 0x25: objIdx = MAPPIC_PEBBLE1; break; - case 0x26: objIdx = MAPPIC_PEBBLE2; break; - case 0x27: objIdx = MAPPIC_PEBBLE3; break; - default: break; - } - break; - // stone - case 0xCC: objIdx = MAPPIC_GRANITE_1_1 + (P2.objectType - 0x01); break; - // stone - case 0xCD: objIdx = MAPPIC_GRANITE_2_1 + (P2.objectType - 0x01); break; - // headquarter - case 0x80: // node2.objectType is the number of the player beginning with 0x00 - //%7 cause in the original game there are only 7 players and 7 different flags - Texture::getTexture(ArchiveID::EDITBOB, FLAG_BLUE_DARK + P2.objectType % 7).drawSprite(p2); - break; // don't set objIdx — drawn directly from typed archive - default: break; - } - if(objIdx != 0) - Texture::getTexture(ArchiveID::MAP00, objIdx).drawSprite(p2); - } - - // blit resources - if(!isRSU) - { - if(P2.resource >= 0x41 && P2.resource <= 0x47) - { - for(char i = 0x41; i <= P2.resource; i++) - Texture::getTexture(ArchiveID::EDITIO, PICTURE_RESOURCE_COAL) - .drawSprite(Position(p2.x, p2.y - 4 * (i - 0x40))); - } else if(P2.resource >= 0x49 && P2.resource <= 0x4F) - { - for(char i = 0x49; i <= P2.resource; i++) - Texture::getTexture(ArchiveID::EDITIO, PICTURE_RESOURCE_ORE) - .drawSprite(Position(p2.x, p2.y - 4 * (i - 0x48))); - } - if(P2.resource >= 0x51 && P2.resource <= 0x57) - { - for(char i = 0x51; i <= P2.resource; i++) - Texture::getTexture(ArchiveID::EDITIO, PICTURE_RESOURCE_GOLD) - .drawSprite(Position(p2.x, p2.y - 4 * (i - 0x50))); - } - if(P2.resource >= 0x59 && P2.resource <= 0x5F) - { - for(char i = 0x59; i <= P2.resource; i++) - Texture::getTexture(ArchiveID::EDITIO, PICTURE_RESOURCE_GRANITE) - .drawSprite(Position(p2.x, p2.y - 4 * (i - 0x58))); - } - // blit animals - if(P2.animal > 0x00 && P2.animal <= 0x06) - Texture::getTexture(ArchiveID::EDITBOB, PICTURE_SMALL_BEAR + P2.animal).drawSprite(p2); - } - - // blit buildings - if(global::s2->getMapObj()->getRenderBuildHelp()) - { - if(!isRSU) - { - switch(P2.build % 8) - { - case 0x01: Texture::getTexture(ArchiveID::MAP00, MAPPIC_FLAG).drawSprite(p2); break; - case 0x02: Texture::getTexture(ArchiveID::MAP00, MAPPIC_HOUSE_SMALL).drawSprite(p2); break; - case 0x03: Texture::getTexture(ArchiveID::MAP00, MAPPIC_HOUSE_MIDDLE).drawSprite(p2); break; - case 0x04: - if(P2.rsuTexture & 0x40) - Texture::getTexture(ArchiveID::MAP00, MAPPIC_HOUSE_HARBOUR).drawSprite(p2); - else - Texture::getTexture(ArchiveID::MAP00, MAPPIC_HOUSE_BIG).drawSprite(p2); - break; - case 0x05: Texture::getTexture(ArchiveID::MAP00, MAPPIC_MINE).drawSprite(p2); break; - default: break; - } - } - } -} - -void CSurface::get_nodeVectors(bobMAP& myMap) -{ - // prepare triangle field - int height = myMap.height; - int width = myMap.width; - IntVector tempP2, tempP3; - - // get flat vectors - for(int j = 0; j < height - 1; j++) - { - if(j % 2 == 0) - { - // vector of first triangle - tempP2.x = 0; - tempP2.y = myMap.getVertex(width - 1, j + 1).y; - tempP2.z = myMap.getVertex(width - 1, j + 1).z; - myMap.getVertex(0, j).flatVector = get_flatVector(myMap.getVertex(0, j), tempP2, myMap.getVertex(0, j + 1)); - - for(int i = 1; i < width; i++) - myMap.getVertex(i, j).flatVector = - get_flatVector(myMap.getVertex(i, j), myMap.getVertex(i - 1, j + 1), myMap.getVertex(i, j + 1)); - } else - { - for(int i = 0; i < width - 1; i++) - myMap.getVertex(i, j).flatVector = - get_flatVector(myMap.getVertex(i, j), myMap.getVertex(i, j + 1), myMap.getVertex(i + 1, j + 1)); - - // vector of last triangle - tempP3.x = myMap.getVertex(width - 1, j + 1).x + TR_W; - tempP3.y = myMap.getVertex(0, j + 1).y; - tempP3.z = myMap.getVertex(0, j + 1).z; - myMap.getVertex(width - 1, j).flatVector = - get_flatVector(myMap.getVertex(width - 1, j), myMap.getVertex(width - 1, j + 1), tempP3); - } - } - // flat vectors of last line - for(int i = 0; i < width - 1; i++) - { - tempP2 = myMap.getVertex(i, 0); - tempP2.y += height * TR_H; - tempP3 = myMap.getVertex(i + 1, 0); - tempP3.y += height * TR_H; - myMap.getVertex(i, height - 1).flatVector = get_flatVector(myMap.getVertex(i, height - 1), tempP2, tempP3); - } - // vector of last Triangle - tempP2 = myMap.getVertex(width - 1, 0); - tempP2.y += height * TR_H; - tempP3.x = myMap.getVertex(width - 1, 0).x + TR_W; - tempP3.y = height * TR_H + myMap.getVertex(0, 0).y; - tempP3.z = myMap.getVertex(0, 0).z; - myMap.getVertex(width - 1, height - 1).flatVector = - get_flatVector(myMap.getVertex(width - 1, height - 1), tempP2, tempP3); - - // now get the vector at each node and save it to myMap.getVertex(j*width+i, 0).normVector - for(int j = 0; j < height; j++) - { - if(j % 2 == 0) - { - for(int i = 0; i < width; i++) - { - EditorMapNode& curVertex = myMap.getVertex(i, j); - int iM1 = (i == 0 ? width - 1 : i - 1); - if(j == 0) // first line - curVertex.normVector = - get_nodeVector(myMap.getVertex(iM1, height - 1).flatVector, - myMap.getVertex(i, height - 1).flatVector, curVertex.flatVector); - else - curVertex.normVector = get_nodeVector(myMap.getVertex(iM1, j - 1).flatVector, - myMap.getVertex(i, j - 1).flatVector, curVertex.flatVector); - curVertex.i = get_LightIntensity(curVertex.normVector); - } - } else - { - for(int i = 0; i < width; i++) - { - EditorMapNode& curVertex = myMap.getVertex(i, j); - int iP1 = (i + 1 == width ? 0 : i + 1); - - curVertex.normVector = get_nodeVector(myMap.getVertex(i, j - 1).flatVector, - myMap.getVertex(iP1, j - 1).flatVector, curVertex.flatVector); - curVertex.i = get_LightIntensity(curVertex.normVector); - } - } - } -} - -Sint32 CSurface::get_LightIntensity(const vector& node) -{ - // we calculate the light intensity right now - float I, Ip = 1.1f, kd = 1, light_const = 1.0f; - vector L = {-10, 5, 0.5f}; - L = get_normVector(L); - I = Ip * kd * (node.x * L.x + node.y * L.y + node.z * L.z) + light_const; - return (Sint32)(I * pow(2, 16)); -} - -vector CSurface::get_nodeVector(const vector& v1, const vector& v2, const vector& v3) -{ - vector node; - // dividing through 3 is not necessary cause normal vector would be the same - node.x = v1.x + v2.x + v3.x; - node.y = v1.y + v2.y + v3.y; - node.z = v1.z + v2.z + v3.z; - node = get_normVector(node); - return node; -} - -vector CSurface::get_normVector(const vector& v) -{ - vector normal; - auto length = static_cast(sqrt(pow(v.x, 2) + pow(v.y, 2) + pow(v.z, 2))); - // in case vector length equals 0 (should not happen) - if(std::abs(length) < 1e-20f) - { - normal.x = 0; - normal.y = 0; - normal.z = 1; - } else - { - normal = v; - normal.x /= length; - normal.y /= length; - normal.z /= length; - } - - return normal; -} - -vector CSurface::get_flatVector(const IntVector& P1, const IntVector& P2, const IntVector& P3) -{ - // vector components - float vax, vay, vaz, vbx, vby, vbz; - // cross product - vector cross; - - vax = static_cast(P1.x - P2.x); - vay = static_cast(P1.y - P2.y); - vaz = static_cast(P1.z - P2.z); - vbx = static_cast(P3.x - P2.x); - vby = static_cast(P3.y - P2.y); - vbz = static_cast(P3.z - P2.z); - - cross.x = (vay * vbz - vaz * vby); - cross.y = (vaz * vbx - vax * vbz); - cross.z = (vax * vby - vay * vbx); - // normalize - cross = get_normVector(cross); - - return cross; -} - -void CSurface::update_shading(bobMAP& myMap, Position pos) -{ - // vertex count for the points - int X, Y; - - bool even = false; - if(pos.y % 2 == 0) - even = true; - - update_flatVectors(myMap, pos); - update_nodeVector(myMap, pos); - - // now update all nodeVectors around pos - // update first vertex left upside - X = pos.x - (even ? 1 : 0); - if(X < 0) - X += myMap.width; - Y = pos.y - 1; - if(Y < 0) - Y += myMap.height; - update_nodeVector(myMap, Position(X, Y)); - // update second vertex right upside - X = pos.x + (even ? 0 : 1); - if(X >= myMap.width) - X -= myMap.width; - Y = pos.y - 1; - if(Y < 0) - Y += myMap.height; - update_nodeVector(myMap, Position(X, Y)); - // update third point bottom left - X = pos.x - 1; - if(X < 0) - X += myMap.width; - Y = pos.y; - update_nodeVector(myMap, Position(X, Y)); - // update fourth point bottom right - X = pos.x + 1; - if(X >= myMap.width) - X -= myMap.width; - Y = pos.y; - update_nodeVector(myMap, Position(X, Y)); - // update fifth point down left - X = pos.x - (even ? 1 : 0); - if(X < 0) - X += myMap.width; - Y = pos.y + 1; - if(Y >= myMap.height) - Y -= myMap.height; - update_nodeVector(myMap, Position(X, Y)); - // update sixth point down right - X = pos.x + (even ? 0 : 1); - if(X >= myMap.width) - X -= myMap.width; - Y = pos.y + 1; - if(Y >= myMap.height) - Y -= myMap.height; - update_nodeVector(myMap, Position(X, Y)); -} - -void CSurface::update_flatVectors(bobMAP& myMap, Position pos) -{ - // point structures for the triangles, Pmiddle is the point in the middle of the hexagon we will update - EditorMapNode *P1, *P2, *P3, *Pmiddle; - // vertex count for the points - int P1x, P1y, P2x, P2y, P3x, P3y; - - bool even = false; - if(pos.y % 2 == 0) - even = true; - - Pmiddle = &myMap.getVertex(pos.x, pos.y); - - // update first triangle left upside - P1x = pos.x - (even ? 1 : 0); - if(P1x < 0) - P1x += myMap.width; - P1y = pos.y - 1; - if(P1y < 0) - P1y += myMap.height; - P1 = &myMap.getVertex(P1x, P1y); - P2x = pos.x - 1; - if(P2x < 0) - P2x += myMap.width; - P2y = pos.y; - P2 = &myMap.getVertex(P2x, P2y); - P3 = Pmiddle; - P1->flatVector = get_flatVector(*P1, *P2, *P3); - - // update second triangle right upside - P1x = pos.x + (even ? 0 : 1); - if(P1x >= myMap.width) - P1x -= myMap.width; - P1y = pos.y - 1; - if(P1y < 0) - P1y += myMap.height; - P1 = &myMap.getVertex(P1x, P1y); - P2 = Pmiddle; - P3x = pos.x + 1; - if(P3x >= myMap.width) - P3x -= myMap.width; - P3y = pos.y; - P3 = &myMap.getVertex(P3x, P3y); - P1->flatVector = get_flatVector(*P1, *P2, *P3); - - // update third triangle down middle - P1 = Pmiddle; - P2x = pos.x - (even ? 1 : 0); - if(P2x < 0) - P2x += myMap.width; - P2y = pos.y + 1; - if(P2y >= myMap.height) - P2y -= myMap.height; - P2 = &myMap.getVertex(P2x, P2y); - P3x = pos.x + (even ? 0 : 1); - if(P3x >= myMap.width) - P3x -= myMap.width; - P3y = pos.y + 1; - if(P3y >= myMap.height) - P3y -= myMap.height; - P3 = &myMap.getVertex(P3x, P3y); - P1->flatVector = get_flatVector(*P1, *P2, *P3); -} - -void CSurface::update_nodeVector(bobMAP& myMap, Position pos) -{ - int j = pos.y; - int i = pos.x; - int width = myMap.width; - int height = myMap.height; - - if(j % 2 == 0) - { - EditorMapNode& curVertex = myMap.getVertex(i, j); - int iM1 = (i == 0 ? width - 1 : i - 1); - if(j == 0) // first line - curVertex.normVector = get_nodeVector(myMap.getVertex(iM1, height - 1).flatVector, - myMap.getVertex(i, height - 1).flatVector, curVertex.flatVector); - else - curVertex.normVector = get_nodeVector(myMap.getVertex(iM1, j - 1).flatVector, - myMap.getVertex(i, j - 1).flatVector, curVertex.flatVector); - curVertex.i = get_LightIntensity(curVertex.normVector); - } else - { - EditorMapNode& curVertex = myMap.getVertex(i, j); - int iP1 = (i + 1 == width ? 0 : i + 1); - - curVertex.normVector = get_nodeVector(myMap.getVertex(i, j - 1).flatVector, - myMap.getVertex(iP1, j - 1).flatVector, curVertex.flatVector); - curVertex.i = get_LightIntensity(curVertex.normVector); - } -} - -float CSurface::absf(float a) -{ - if(a >= 0) - return a; - else - return a * (-1); -} diff --git a/CSurface.h b/CSurface.h deleted file mode 100644 index 3c5b911..0000000 --- a/CSurface.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2009 - 2021 Marc Vester (XaserLE) -// Copyright (C) 2009 - 2021 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "defines.h" - -struct vector; - -class CSurface -{ -public: - /// Render terrain into the current GL framebuffer. - /// displayRect specifies the visible area in map-pixel coordinates. - static void DrawTriangleField(const DisplayRectangle& displayRect, const bobMAP& myMap); - - /// Draw a single triangle given its three vertices. - static void DrawTriangle(const DisplayRectangle& displayRect, const bobMAP& myMap, MapType type, const EditorMapNode& P1, - const EditorMapNode& P2, const EditorMapNode& P3); - - static void get_nodeVectors(bobMAP& myMap); - static void update_shading(bobMAP& myMap, Position pos); - -private: - // to decide what to draw, triangle-textures or objects and texture-borders - static bool drawTextures; - - static vector get_nodeVector(const vector& v1, const vector& v2, const vector& v3); - static vector get_normVector(const vector& v); - static vector get_flatVector(const IntVector& P1, const IntVector& P2, const IntVector& P3); - static Sint32 get_LightIntensity(const vector& node); - static float absf(float a); - // update flatVectors around a vertex - static void update_flatVectors(bobMAP& myMap, Position pos); - // update nodeVector based on new flatVectors around it - static void update_nodeVector(bobMAP& myMap, Position pos); - - static void GetTerrainTextureCoords(MapType mapType, TriangleTerrainType texture, bool isRSU, Point16& upper, - Point16& left, Point16& right, Point16& upper2, Point16& left2, - Point16& right2); -}; diff --git a/EditorWorldLoader.cpp b/EditorWorldLoader.cpp index 123154f..72840a2 100644 --- a/EditorWorldLoader.cpp +++ b/EditorWorldLoader.cpp @@ -1,6 +1,5 @@ #include "EditorWorldLoader.h" #include "Loader.h" -#include "globals.h" #include "libsiedler2/Archiv.h" #include "libsiedler2/ArchivItem.h" #include "libsiedler2/ArchivItem_Bitmap.h" @@ -43,7 +42,7 @@ void loadTexturesForEditorWorld(const std::string& gameDataPath) const auto map00Path = boost::filesystem::path(gameDataPath) / "DATA/MAP00.LST"; if(!boost::filesystem::exists(map00Path)) return; - LOADER.Load(map00Path, global::currentPalette); + LOADER.Load(map00Path, LOADER.GetPaletteN("pal5", 0)); // Build the clean-index → archive-index lookup auto& arch = LOADER.GetArchive("map00"); diff --git a/globals.cpp b/globals.cpp index c6d9112..8984413 100644 --- a/globals.cpp +++ b/globals.cpp @@ -4,148 +4,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "globals.h" -#include -#include -#include -#include -#include -#include -#include -// single archive for all loaded assets -// typed archive storage -std::map global::typedArchives; - -// currently active palette -const libsiedler2::ArchivItem_Palette* global::currentPalette = nullptr; - -bool global::loadArchive(ArchiveID archive, const boost::filesystem::path& filepath, - const libsiedler2::ArchivItem_Palette* palette) -{ - libsiedler2::Archiv tmp; - int ec = libsiedler2::Load(filepath, tmp, palette); - if(ec) - { - std::cerr << "loadArchive(" << static_cast(archive) << ") error for " << filepath << ": " - << libsiedler2::getErrorString(ec) << std::endl; - return false; - } - typedArchives[archive] = std::move(tmp); - return true; -} - -bool global::loadBitmapArchive(ArchiveID archive, const boost::filesystem::path& filepath, - const libsiedler2::ArchivItem_Palette* palette) -{ - libsiedler2::Archiv tmp; - int ec = libsiedler2::Load(filepath, tmp, palette); - if(ec) - { - std::cerr << "loadBitmapArchive(" << static_cast(archive) << ") error for " << filepath << ": " - << libsiedler2::getErrorString(ec) << std::endl; - return false; - } - - // Keep only bitmap-type items (skip nulls, shadows, palettes, fonts) - libsiedler2::Archiv filtered; - for(unsigned i = 0; i < tmp.size(); i++) - { - auto* item = tmp.get(i); - if(!item) - continue; - auto bt = item->getBobType(); - if(bt == libsiedler2::BobType::Bitmap || bt == libsiedler2::BobType::BitmapRLE - || bt == libsiedler2::BobType::Raw || bt == libsiedler2::BobType::BitmapPlayer) - { - filtered.push(std::unique_ptr(tmp.release(i).release())); - } - } - - typedArchives[archive] = std::move(filtered); - return true; -} - -bool global::loadPalette(const boost::filesystem::path& filepath) -{ - libsiedler2::Archiv tmp; - int ec = libsiedler2::Load(filepath, tmp, nullptr); - if(ec) - { - auto datPath = filepath; - datPath.replace_extension(".DAT"); - ec = libsiedler2::Load(datPath, tmp, nullptr); - } - if(ec || tmp.empty()) - { - std::cerr << "loadPalette error for " << filepath << ": " << (ec ? libsiedler2::getErrorString(ec) : "empty") - << std::endl; - return false; - } - currentPalette = dynamic_cast(tmp.get(0)); - if(!currentPalette) - { - std::cerr << "loadPalette: first item is not a palette in " << filepath << std::endl; - return false; - } - static libsiedler2::Archiv s_paletteStorage; - s_paletteStorage = std::move(tmp); - return true; -} - -Extent global::getBitmapSize(ArchiveID archive, unsigned index) -{ - auto& archiv = typedArchives[archive]; - if(index >= archiv.size()) - return {0u, 0u}; - auto* bmp = dynamic_cast(archiv.get(index)); - if(!bmp) - return {0u, 0u}; - return {bmp->getWidth(), bmp->getHeight()}; -} - -bool global::loadTileset(ArchiveID archive, int tsIdx, const boost::filesystem::path& filepath) -{ - // LBM files contain their own palette, so no external palette needed - libsiedler2::Archiv tmp; - int ec = libsiedler2::Load(filepath, tmp, nullptr); - if(ec || tmp.empty()) - { - std::cerr << "loadTileset(" << static_cast(archive) << ") error for " << filepath << ": " - << (ec ? libsiedler2::getErrorString(ec) : "empty") << std::endl; - return false; - } - - // Store in typed archive (index 0 = main bitmap, 1+ = palette animations) - auto& dest = typedArchives[archive]; - dest = std::move(tmp); - - // Extract palette animations into tilesetAnims[tsIdx] - auto& ta = tilesetAnims[tsIdx]; - ta.archive = archive; - ta.bmpIdx = 0; // index 0 within this archive = main bitmap - ta.anims.clear(); - ta.storage.clear(); - for(unsigned ai = 1; ai < dest.size(); ai++) - { - auto* anim = dynamic_cast(dest.get(ai)); - if(!anim) - continue; - // We need mutable pointers for the animation system; clone them - auto clone = std::unique_ptr(dest.release(ai).release()); - ta.anims.push_back(static_cast(clone.get())); - ta.storage.push_back(std::move(clone)); - } - - return true; -} - -// font archives loaded at startup -std::array global::tilesetAnims; // the game object CGame* global::s2; boost::filesystem::path global::gameDataFilePath("."); boost::filesystem::path global::userMapsPath; WorldDescription global::worldDesc; - - diff --git a/globals.h b/globals.h index f087bc6..8ba2286 100644 --- a/globals.h +++ b/globals.h @@ -5,65 +5,14 @@ #pragma once -#include "ArchiveID.h" #include "gameData/WorldDescription.h" -#include #include -#include #include -#include -#include class CGame; -namespace libsiedler2 { -class ArchivItem_Palette; -class ArchivItem_PaletteAnimation; -class baseArchivItem_Bitmap; -struct ColorBGRA; -} // namespace libsiedler2 - namespace global { -// ── Typed archive storage ───────────────────────────────────────────── -/// Per-ArchiveID archives, loaded and kept intact. -extern std::map typedArchives; - -/// Load a file into typedArchives[archive] using libsiedler2::Load directly. -/// Returns true on success. -bool loadArchive(ArchiveID archive, const boost::filesystem::path& filepath, - const libsiedler2::ArchivItem_Palette* palette = nullptr); - -/// Get the size of a bitmap from a typed archive. -Extent getBitmapSize(ArchiveID archive, unsigned index); - -/// Load a palette BBM file into currentPalette. Returns true on success. -bool loadPalette(const boost::filesystem::path& filepath); - -/// Load a file into typedArchives[archive], keeping only bitmap-type items -/// (Bitmap, BitmapRLE, Raw, BitmapPlayer), skipping nulls and other types. -/// Used for archives like MAP00.LST that contain non-bitmap items. -bool loadBitmapArchive(ArchiveID archive, const boost::filesystem::path& filepath, - const libsiedler2::ArchivItem_Palette* palette = nullptr); - -/// Load a terrain tileset (TEX5/6/7.LBM) into typedArchives and extract -/// palette animations into tilesetAnims[tsIdx]. The old flat-archive -/// path is NOT used — call this instead of CFile::open_file. -bool loadTileset(ArchiveID archive, int tsIdx, const boost::filesystem::path& filepath); - -// Palette animations per tileset (greenland=0, wasteland=1, winterland=2). -struct TilesetAnim -{ - ArchiveID archive = ArchiveID::EDITRES; // which archive contains the bitmap - unsigned bmpIdx = 0; // index of the tileset bitmap within the archive - std::vector anims; - std::vector> storage; // keeps animations alive -}; -extern std::array tilesetAnims; - -/// Currently active palette (loaded from PAL*.BBM). -extern const libsiedler2::ArchivItem_Palette* currentPalette; - // the game object extern CGame* s2; // Path to game data (must not be empty!) diff --git a/include/ArchiveID.h b/include/ArchiveID.h deleted file mode 100644 index 496f6e1..0000000 --- a/include/ArchiveID.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (C) 2026 - 2026 Settlers Freaks -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include - -/// Identifies a loaded resource archive. -/// Each value corresponds to one file (or group of related files) that is loaded -/// and kept as a separate libsiedler2::Archiv, keyed by this type. -enum class ArchiveID : uint8_t -{ - // ── Editor / UI archives ────────────────────────────────────────── - EDITBOB = 0, // DATA/EDITBOB.LST - EDITIO, // DATA/IO/EDITIO.IDX - EDITRES, // DATA/EDITRES.IDX (or RESOURCE.IDX/DAT) - - // ── Loading screens ─────────────────────────────────────────────── - SETUP997, - SETUP998, - SETUP000, - SETUP010, - SETUP011, - SETUP012, - SETUP013, - SETUP014, - SETUP015, - SETUP666, - SETUP667, - SETUP801, - SETUP802, - SETUP803, - SETUP804, - SETUP805, - SETUP806, - SETUP810, - SETUP811, - SETUP895, - SETUP896, - SETUP897, - SETUP898, - SETUP899, - SETUP990, - WORLD_LBM, - WORLDMSK_LBM, - - // ── Mission BOBs ────────────────────────────────────────────────── - MIS0BOBS, - MIS1BOBS, - MIS2BOBS, - MIS3BOBS, - MIS4BOBS, - MIS5BOBS, - - // ── Terrain tilesets (landscape-specific, one per landscape) ───── - TEX5, // GFX/TEXTURES/TEX5.LBM (greenland) - TEX6, // GFX/TEXTURES/TEX6.LBM (wasteland) - TEX7, // GFX/TEXTURES/TEX7.LBM (winterland) - - // ── Map object sprites (MAP00.LST) ─────────────────────────────── - MAP00, // DATA/MAP00.LST - - // ── Palettes (keyed separately) ─────────────────────────────────── - // (not in this enum — palettes have their own storage) -}; diff --git a/iwLoadMap.cpp b/iwLoadMap.cpp index 0d107b5..bfc4e1e 100644 --- a/iwLoadMap.cpp +++ b/iwLoadMap.cpp @@ -64,7 +64,9 @@ void iwLoadMap::Msg_ButtonClick(unsigned ctrl_id) path.replace_extension(".wld"); } if(bfs::exists(path)) - global::s2->enterEditor(path); + { + // TODO: Load map into EditorWorld and switch to dskEditorInterface + } } Close(); break; From b747fda002f920ba650e289665980203dd2a8632 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 16:22:58 +0200 Subject: [PATCH 14/16] draw game objects --- EditorWorldLoader.cpp | 5 +++ GameWorldEditor.cpp | 90 ++++++++++++++++++++++++++++++++++++++---- dskEditorInterface.cpp | 88 ++++++++++++++++++++++++++++++++++++++--- iwEditorAnimal.cpp | 27 ++++++++++--- iwEditorAnimal.h | 12 +++++- iwEditorLandscape.cpp | 32 ++++++++++++--- iwEditorLandscape.h | 11 +++++- 7 files changed, 241 insertions(+), 24 deletions(-) diff --git a/EditorWorldLoader.cpp b/EditorWorldLoader.cpp index 72840a2..b53ad61 100644 --- a/EditorWorldLoader.cpp +++ b/EditorWorldLoader.cpp @@ -44,6 +44,11 @@ void loadTexturesForEditorWorld(const std::string& gameDataPath) return; LOADER.Load(map00Path, LOADER.GetPaletteN("pal5", 0)); + // Load MAP_0_Z.LST (greenland full sprites) for animals and other game objects + const auto map0zPath = boost::filesystem::path(gameDataPath) / "DATA/MAP_0_Z.LST"; + if(boost::filesystem::exists(map0zPath)) + LOADER.Load(map0zPath, LOADER.GetPaletteN("pal5", 0)); + // Build the clean-index → archive-index lookup auto& arch = LOADER.GetArchive("map00"); for(unsigned i = 0; i < arch.size(); i++) diff --git a/GameWorldEditor.cpp b/GameWorldEditor.cpp index b98164c..5f3e9fa 100644 --- a/GameWorldEditor.cpp +++ b/GameWorldEditor.cpp @@ -12,8 +12,14 @@ #include "gameData/MapConsts.h" #include "nodeObjs/noBase.h" #include "nodeObjs/noTree.h" +#include "nodeObjs/noGranite.h" +#include "nodeObjs/noEnvObject.h" +#include "nodeObjs/noStaticObject.h" +#include "nodeObjs/noAnimal.h" +#include "gameData/AnimalConsts.h" #include "libsiedler2/Archiv.h" #include "ogl/glArchivItem_Bitmap.h" +#include "enum_cast.hpp" #include #include @@ -95,13 +101,49 @@ void GameWorldEditor::Draw(const Extent& screenSize) nodePos += wrapOffset; // Draw objects using LOADER's MAP00 archive with clean-index lookup + // Tree types 0-8, where pineapple (type 5) has only 8 frames. + static const int treeStart[9] = { + MAPPIC_TREE_PINE, // 0 pine + MAPPIC_TREE_BIRCH, // 1 birch + MAPPIC_TREE_OAK, // 2 oak + MAPPIC_TREE_PALM1, // 3 palm1 + MAPPIC_TREE_PALM2, // 4 palm2 + MAPPIC_TREE_PINEAPPLE,// 5 pineapple (8 frames) + MAPPIC_TREE_CYPRESS, // 6 cypress + MAPPIC_TREE_CHERRY, // 7 cherry + MAPPIC_TREE_FIR // 8 fir + }; + static constexpr int TREE_FRAMES = 8; // animate 8 frames (standing animation) if(auto* tree = dynamic_cast(obj)) { - static Uint32 lastTick = 0; - static unsigned frame = 0; - Uint32 now = SDL_GetTicks(); - if(now - lastTick > 80) { frame = (frame + 1) % 8; lastTick = now; } - int cleanIdx = MAPPIC_TREE_PINE + tree->getTreeType() * 15 + frame; + unsigned type = tree->getTreeType(); + if(type < 9) + { + static Uint32 lastTick = 0; + static unsigned frame = 0; + Uint32 now = SDL_GetTicks(); + if(now - lastTick > 80) { frame = (frame + 1) % TREE_FRAMES; lastTick = now; } + int cleanIdx = treeStart[type] + static_cast(frame); + if(cleanIdx >= 0) + { + int archIdx = editorMapCleanToArchiveIdx(cleanIdx); + if(archIdx >= 0) + { + auto& arch = LOADER.GetArchive("map00"); + auto* bmp = dynamic_cast(arch.get(static_cast(archIdx))); + if(bmp) + { + bmp->DrawFull(DrawPoint(nodePos.x, nodePos.y)); + // Draw shadow (image + 100 in map_?_z convention, but MAP00 has shadow at offset 7) + // The first 8 frames have shadows at +100 in map_?_z. + // For MAP00 we just draw the image without shadow for simplicity. + } + } + } + } + } else if(auto* granite = dynamic_cast(obj)) + { + int cleanIdx = MAPPIC_GRANITE_1_1 + rttr::enum_cast(granite->GetType()) * 6 + granite->GetSize(); int archIdx = editorMapCleanToArchiveIdx(cleanIdx); if(archIdx >= 0) { @@ -110,9 +152,43 @@ void GameWorldEditor::Draw(const Extent& screenSize) if(bmp) bmp->DrawFull(DrawPoint(nodePos.x, nodePos.y)); } - } else + } else if(auto* env = dynamic_cast(obj)) + { + // Map objects (file == 0xFFFF) use MAPPIC indices directly + if(env->GetItemFile() == 0xFFFF) + { + int cleanIdx = env->GetItemID(); + int archIdx = editorMapCleanToArchiveIdx(cleanIdx); + if(archIdx >= 0) + { + auto& arch = LOADER.GetArchive("map00"); + auto* bmp = dynamic_cast(arch.get(static_cast(archIdx))); + if(bmp) + bmp->DrawFull(DrawPoint(nodePos.x, nodePos.y)); + } + } else + { + // Non-map objects (mis*bobs) — skip for now + } + } + // Draw animals (figures) at this node — just one static frame for now + for(auto& fig : world_.GetFigures(pt)) { - obj->Draw(DrawPoint(nodePos.x, nodePos.y)); + if(fig.GetGOT() != GO_Type::Animal) + continue; + auto& animal = static_cast(fig); + Species sp = animal.GetSpecies(); + int walkingId = ANIMALCONSTS[sp].walking_id; + int steps = ANIMALCONSTS[sp].animation_steps; + // Use East direction (maps to offset 0) and first animation step + int rawIdx = walkingId + steps * 0 + 0; + auto& archZ = LOADER.GetArchive("map_0_z"); + if(rawIdx >= 0 && static_cast(rawIdx) < archZ.size()) + { + auto* bmp = dynamic_cast(archZ.get(static_cast(rawIdx))); + if(bmp) + bmp->DrawFull(DrawPoint(nodePos.x, nodePos.y)); + } } } } diff --git a/dskEditorInterface.cpp b/dskEditorInterface.cpp index a95aef5..4dc7fd8 100644 --- a/dskEditorInterface.cpp +++ b/dskEditorInterface.cpp @@ -18,6 +18,13 @@ #include "iwEditorAnimal.h" #include "iwEditorPlayer.h" #include "iwMinimap.h" +#include "nodeObjs/noEnvObject.h" +#include "nodeObjs/noGranite.h" +#include "nodeObjs/noTree.h" +#include "nodeObjs/noAnimal.h" +#include "gameTypes/AnimalTypes.h" +#include "gameData/AnimalConsts.h" +#include "enum_cast.hpp" #include "iwEditorCreateWorld.h" #include "iwEditorCursor.h" #include "controls/ctrlButton.h" @@ -426,12 +433,11 @@ void dskEditorInterface::applyTool() } case EditorToolMode::Tree: { - auto& w = world; for(const auto& cv : cursorVerts_) { if(!cv.active) continue; // Skip if there's already an object - if(w.GetNO(cv.pt)) + if(world.GetNode(cv.pt).obj != nullptr) continue; int treeType = modeContent2_; if(treeType == -1) // mixed wood @@ -440,10 +446,78 @@ void dskEditorInterface::applyTool() treeType = 3 + rand() % 5; // palm1, palm2, pineapple, cypress, cherry else if(treeType < 0 || treeType > 8) treeType = 0; - w.SetNO(cv.pt, new noTree(cv.pt, static_cast(treeType), 3), true); + world.SetNO(cv.pt, new noTree(cv.pt, static_cast(treeType), 3), true); } break; } + case EditorToolMode::Landscape: + { + int mapPicId = modeContent2_; + if(mapPicId <= 0) + break; + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + if(world.GetNode(cv.pt).obj != nullptr) + continue; + // Granite range in MAPPIC: 170-181 + if(mapPicId >= MAPPIC_GRANITE_1_1 && mapPicId <= MAPPIC_GRANITE_2_6) + { + int graniteType = (mapPicId - MAPPIC_GRANITE_1_1) / 6; + int graniteSize = (mapPicId - MAPPIC_GRANITE_1_1) % 6; + world.SetNO(cv.pt, new noGranite(static_cast(graniteType), + static_cast(graniteSize)), true); + } else + { + world.SetNO(cv.pt, new noEnvObject(cv.pt, static_cast(mapPicId), 0xFFFF), true); + } + } + break; + } + case EditorToolMode::Cut: + { + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + auto& node = world.GetNodeWriteable(cv.pt); + // Destroy node object (trees, granite, landscape objects) + if(node.obj != nullptr) + world.DestroyNO(cv.pt, false); + // Remove figures (animals) + if(!node.figures.empty()) + { + // Destroy each figure manually + for(auto it = node.figures.begin(); it != node.figures.end();) + { + auto* fig = it->release(); + it = node.figures.erase(it); + fig->Destroy(); + delete fig; + } + } + } + break; + } + case EditorToolMode::Animal: + { + int species = modeContent2_; + if(species < 0 || species > rttr::enum_cast(Species::Sheep)) + break; + for(const auto& cv : cursorVerts_) + { + if(!cv.active) continue; + // Animals are figures, not node objects. AddFigure adds to the figures list. + // But only if there isn't already an animal there (skip occupied nodes) + auto& node = world.GetNodeWriteable(cv.pt); + if(!node.figures.empty()) + continue; + world.AddFigure(cv.pt, + std::make_unique(static_cast(species), cv.pt)); + } + break; + } + case EditorToolMode::Flag: + case EditorToolMode::Resource: default: break; } @@ -600,11 +674,15 @@ void dskEditorInterface::Msg_ButtonClick(unsigned ctrl_id) break; case ID_btToolLandscape: mode_ = EditorToolMode::Landscape; - WINDOWMANAGER.Show(std::make_unique()); + WINDOWMANAGER.Show(std::make_unique([this](int mapPicId) noexcept { + modeContent2_ = mapPicId; + })); break; case ID_btToolAnimal: mode_ = EditorToolMode::Animal; - WINDOWMANAGER.Show(std::make_unique()); + WINDOWMANAGER.Show(std::make_unique([this](int species) noexcept { + modeContent2_ = species; + })); break; case ID_btToolPlayer: mode_ = EditorToolMode::Flag; diff --git a/iwEditorAnimal.cpp b/iwEditorAnimal.cpp index f123287..c1f5b21 100644 --- a/iwEditorAnimal.cpp +++ b/iwEditorAnimal.cpp @@ -7,16 +7,26 @@ #include "controls/ctrlButton.h" #include "defines.h" -iwEditorAnimal::iwEditorAnimal() +/// Map from button index (0-based) to Species enum value (as int). +static constexpr int buttonToSpecies[] = { + 1, // 0: rabbit → Species::RabbitWhite + 3, // 1: fox → Species::Fox + 4, // 2: stag → Species::Stag + 5, // 3: roe (deer) → Species::Deer + 6, // 4: duck → Species::Duck + 7, // 5: sheep → Species::Sheep +}; + +iwEditorAnimal::iwEditorAnimal(CbFunc onSelect) : IngameWindow(105, IngameWindow::posLastOrCenter, Extent(116, 106), "Animals", - LOADER.GetImageN("resource", 41)) + LOADER.GetImageN("resource", 41)), onSelect_(std::move(onSelect)) { const int x0 = contentOffset.x; const int y0 = contentOffset.y; const int step = 34; const int picSize = 32; - static constexpr int animalIds[] = { + static constexpr int animalIcons[] = { PICTURE_ANIMAL_RABBIT, PICTURE_ANIMAL_FOX, PICTURE_ANIMAL_STAG, @@ -25,9 +35,9 @@ iwEditorAnimal::iwEditorAnimal() PICTURE_ANIMAL_SHEEP, }; - for(unsigned i = 0; i < sizeof(animalIds) / sizeof(animalIds[0]); i++) + for(unsigned i = 0; i < sizeof(animalIcons) / sizeof(animalIcons[0]); i++) { - auto* img = LOADER.GetImageN("editio", animalIds[i]); + auto* img = LOADER.GetImageN("editio", animalIcons[i]); if(!img) continue; int col = i % 3; int row = i / 3; @@ -35,3 +45,10 @@ iwEditorAnimal::iwEditorAnimal() TextureColor::Invisible, img, "")->SetBorder(false); } } + +void iwEditorAnimal::Msg_ButtonClick(unsigned ctrl_id) +{ + if(ctrl_id >= 1 && ctrl_id <= sizeof(buttonToSpecies) / sizeof(buttonToSpecies[0]) && onSelect_) + onSelect_(buttonToSpecies[ctrl_id - 1]); + Close(); +} diff --git a/iwEditorAnimal.h b/iwEditorAnimal.h index 24373b6..620db1b 100644 --- a/iwEditorAnimal.h +++ b/iwEditorAnimal.h @@ -5,9 +5,19 @@ #pragma once #include "ingameWindows/IngameWindow.h" +#include "gameTypes/AnimalTypes.h" +#include +/// Window for selecting animals to place on the map. +/// onSelect receives the Species enum value cast to int. class iwEditorAnimal : public IngameWindow { public: - iwEditorAnimal(); + using CbFunc = std::function; + iwEditorAnimal(CbFunc onSelect); + + void Msg_ButtonClick(unsigned ctrl_id) override; + +private: + CbFunc onSelect_; }; diff --git a/iwEditorLandscape.cpp b/iwEditorLandscape.cpp index 08edd2e..4bd5366 100644 --- a/iwEditorLandscape.cpp +++ b/iwEditorLandscape.cpp @@ -7,9 +7,22 @@ #include "controls/ctrlButton.h" #include "defines.h" -iwEditorLandscape::iwEditorLandscape() +/// Map from button index (0-based) to MAPPIC clean index for the corresponding landscape object. +static constexpr int buttonToMapPic[] = { + MAPPIC_GRANITE_1_6, // 0: granite (largest size) + MAPPIC_TREE_DEAD, // 1: dead tree + MAPPIC_STONE1, // 2: stone + MAPPIC_CACTUS1, // 3: cactus + MAPPIC_PEBBLE1, // 4: pebble + MAPPIC_BUSH1, // 5: bush + MAPPIC_SHRUB1, // 6: shrub + MAPPIC_BONE1, // 7: bone + MAPPIC_MUSHROOM1, // 8: mushroom +}; + +iwEditorLandscape::iwEditorLandscape(CbFunc onSelect) : IngameWindow(104, IngameWindow::posLastOrCenter, Extent(112, 174), "Landscape", - LOADER.GetImageN("resource", 41)) + LOADER.GetImageN("resource", 41)), onSelect_(std::move(onSelect)) { const int x0 = contentOffset.x; const int y0 = contentOffset.y; @@ -17,7 +30,7 @@ iwEditorLandscape::iwEditorLandscape() const int picSize = 32; // Greenland landscape objects - static constexpr int landscapeIds[] = { + static constexpr int landscapeIcons[] = { PICTURE_LANDSCAPE_GRANITE, PICTURE_LANDSCAPE_TREE_DEAD, PICTURE_LANDSCAPE_STONE, @@ -29,9 +42,9 @@ iwEditorLandscape::iwEditorLandscape() PICTURE_LANDSCAPE_MUSHROOM, }; - for(unsigned i = 0; i < sizeof(landscapeIds) / sizeof(landscapeIds[0]); i++) + for(unsigned i = 0; i < sizeof(landscapeIcons) / sizeof(landscapeIcons[0]); i++) { - auto* img = LOADER.GetImageN("editio", landscapeIds[i]); + auto* img = LOADER.GetImageN("editio", landscapeIcons[i]); if(!img) continue; int col = i % 3; int row = i / 3; @@ -39,3 +52,12 @@ iwEditorLandscape::iwEditorLandscape() TextureColor::Invisible, img, "")->SetBorder(false); } } + +void iwEditorLandscape::Msg_ButtonClick(unsigned ctrl_id) +{ + if(ctrl_id >= 1 && ctrl_id <= sizeof(buttonToMapPic) / sizeof(buttonToMapPic[0]) && onSelect_) + { + onSelect_(buttonToMapPic[ctrl_id - 1]); + } + Close(); +} diff --git a/iwEditorLandscape.h b/iwEditorLandscape.h index 4a31ec1..d95838f 100644 --- a/iwEditorLandscape.h +++ b/iwEditorLandscape.h @@ -5,9 +5,18 @@ #pragma once #include "ingameWindows/IngameWindow.h" +#include +/// Window for selecting landscape objects (rocks, cactuses, bushes, etc.). +/// onSelect receives the MAPPIC clean index of the chosen object. class iwEditorLandscape : public IngameWindow { public: - iwEditorLandscape(); + using CbFunc = std::function; + iwEditorLandscape(CbFunc onSelect); + + void Msg_ButtonClick(unsigned ctrl_id) override; + +private: + CbFunc onSelect_; }; From b241281e2018502c7b2e5e90213dcb6fda1c4c31 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 16:53:56 +0200 Subject: [PATCH 15/16] loading and saving --- EditorWorld.cpp | 340 +++++++++++++++++++++++++++++++++++++++++ EditorWorld.h | 6 + dskEditorInterface.cpp | 12 +- iwEditorMenu.cpp | 7 +- iwEditorMenu.h | 5 +- iwLoadMap.cpp | 36 +++-- iwSaveMap.cpp | 312 +++++++++++++++++++++++++++++++++++-- iwSaveMap.h | 6 +- 8 files changed, 692 insertions(+), 32 deletions(-) create mode 100644 EditorWorld.cpp diff --git a/EditorWorld.cpp b/EditorWorld.cpp new file mode 100644 index 0000000..82224a0 --- /dev/null +++ b/EditorWorld.cpp @@ -0,0 +1,340 @@ +// Copyright (C) 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "EditorWorld.h" +#include "EditorWorldLoader.h" +#include "Loader.h" +#include "RttrForeachPt.h" +#include "defines.h" +#include "globals.h" +#include "nodeObjs/noAnimal.h" +#include "nodeObjs/noEnvObject.h" +#include "nodeObjs/noGranite.h" +#include "nodeObjs/noStaticObject.h" +#include "nodeObjs/noTree.h" +#include "libsiedler2/Archiv.h" +#include "libsiedler2/ArchivItem_Map_Header.h" +#include "libsiedler2/libsiedler2.h" +#include "libsiedler2/prototypen.h" +#include "gameTypes/AnimalTypes.h" +#include "gameTypes/FlagType.h" +#include "gameData/TerrainDesc.h" +#include +#include + +namespace bfs = boost::filesystem; + +/// Inlined shadow recalculation — mirrors World::RecalcShadow (protected) +static void recalcShadowAt(GameWorld& world, MapPoint pt) +{ + int altitude = world.GetNode(pt).altitude; + int A = world.GetNode(world.GetNeighbour(pt, Direction::NorthEast)).altitude - altitude; + int B = world.GetNode(world.GetNeighbour2(pt, 0)).altitude - altitude; + int C = world.GetNode(world.GetNeighbour(pt, Direction::West)).altitude - altitude; + int D = world.GetNode(world.GetNeighbour2(pt, 11)).altitude - altitude; + + int shadingS2 = 64 + 9 * A - 3 * B - 6 * C - 9 * D; + if(shadingS2 > 128) + shadingS2 = 128; + else if(shadingS2 < 0) + shadingS2 = 0; + world.GetNodeWriteable(pt).shadow = static_cast(shadingS2); +} + +std::unique_ptr EditorWorld::loadFromSwd(const bfs::path& filepath) +{ + // ── 1. Load the SWD/WLD file ── + libsiedler2::Archiv mapArchiv; + if(int ec = libsiedler2::loader::LoadMAP(filepath, mapArchiv)) + { + std::cerr << "Failed to load map: " << filepath << " (error " << ec << ")\n"; + return nullptr; + } + + const auto& map = *static_cast(mapArchiv[0]); + const auto& hdr = map.getHeader(); + + const uint16_t w = hdr.getWidth(); + const uint16_t h = hdr.getHeight(); + const uint8_t gfxSet = hdr.getGfxSet(); + const uint8_t numPlayers = std::max(hdr.getNumPlayers(), 1); + + // ── 2. Find the landscape description matching gfxSet ── + DescIdx landscape; + for(DescIdx i(0); i.value < global::worldDesc.landscapes.size(); i.value++) + { + if(global::worldDesc.landscapes.get(i).s2Id == gfxSet) + { + landscape = i; + break; + } + } + if(!landscape) + { + std::cerr << "No landscape found for gfxSet " << int(gfxSet) << " in map " << filepath << "\n"; + return nullptr; + } + + // ── 3. Create base EditorWorld ── + auto ew = std::make_unique(MapExtent(w, h), numPlayers); + + // ── 4. Override metadata ── + ew->mapName_ = hdr.getName(); + ew->author_ = hdr.getAuthor(); + ew->filepath_ = filepath; + + // ── 5. Set the correct landscape type ── + ew->world_.SetLandscapeType(landscape); + + // ── 6. Helper: look up a terrain DescIdx by s2Id + current landscape ── + auto& desc = ew->world_.GetDescriptionWriteable(); + auto getTerrainFromS2 = [&](uint8_t s2Id) -> DescIdx { + for(DescIdx i(0); i.value < desc.terrain.size(); i.value++) + { + const auto& t = desc.terrain.get(i); + if(t.s2Id == s2Id && t.landscape == landscape) + return i; + } + return DescIdx(); + }; + + // ── 7. Populate all nodes ── + RTTR_FOREACH_PT(MapPoint, MapExtent(w, h)) + { + auto& node = ew->world_.GetNodeWriteable(pt); + + // Clear roads + std::fill(node.roads.begin(), node.roads.end(), PointRoad::None); + + // Altitude + node.altitude = map.getMapDataAt(libsiedler2::MapLayer::Altitude, pt.x, pt.y); + + // Terrain (lower 6 bits; bit 6 = harbour, stored separately) + uint8_t rawT1 = map.getMapDataAt(libsiedler2::MapLayer::Terrain1, pt.x, pt.y); + uint8_t rawT2 = map.getMapDataAt(libsiedler2::MapLayer::Terrain2, pt.x, pt.y); + + node.t1 = getTerrainFromS2(rawT1 & 0x3F); + node.t2 = getTerrainFromS2(rawT2 & 0x3F); + + // Resources + uint8_t res = map.getMapDataAt(libsiedler2::MapLayer::Resources, pt.x, pt.y); + if(res == 0x20 || res == 0x21) + node.resources = Resource(ResourceType::Water, 7); + else if(res > 0x40 && res < 0x48) + node.resources = Resource(ResourceType::Coal, res - 0x40); + else if(res > 0x48 && res < 0x50) + node.resources = Resource(ResourceType::Iron, res - 0x48); + else if(res > 0x50 && res < 0x58) + node.resources = Resource(ResourceType::Gold, res - 0x50); + else if(res > 0x58 && res < 0x60) + node.resources = Resource(ResourceType::Granite, res - 0x58); + else if(res > 0x80 && res < 0x90) + node.resources = Resource(ResourceType::Fish, 4); + else + node.resources = Resource(ResourceType::Nothing, 0); + + // Roads (block 4) + uint8_t roadData = map.getMapDataAt(libsiedler2::MapLayer::RoadsOld, pt.x, pt.y); + // lower left: (roadData / 16) % 4 → SouthWest + // lower right: (roadData % 16) / 4 → SouthEast + // right: (roadData % 4) → East + node.roads[RoadDir::SouthWest] = static_cast((roadData / 16) % 4); + node.roads[RoadDir::SouthEast] = static_cast((roadData % 16) / 4); + node.roads[RoadDir::East] = static_cast(roadData % 4); + + // Harbour marker (bit 6 of terrain1) — stored in node.harborId for save reconstruction + if((rawT1 & libsiedler2::HARBOR_MASK) != 0) + node.harborId = HarborId(1); + else + node.harborId.reset(); + + // FOW: all visible for the editor + for(auto& fow : node.fow) + { + fow = FoWNode(); + fow.visibility = Visibility::Visible; + } + + // Clear dynamic fields + node.owner = 0; + node.reserved = false; + std::fill(node.boundary_stones.begin(), node.boundary_stones.end(), 0); + node.seaId.reset(); + node.obj = nullptr; + node.figures.clear(); + // Keep harbour marker if the terrain had the harbour flag + // (set below after checking rawT1) + } + + // ── 8. Place objects (trees, granite, decorations, HQ markers) ── + { + std::vector hqPositions; // indexed by player number + RTTR_FOREACH_PT(MapPoint, MapExtent(w, h)) + { + using libsiedler2::MapLayer; + uint8_t lc = map.getMapDataAt(MapLayer::ObjectIndex, pt.x, pt.y); + uint8_t type = map.getMapDataAt(MapLayer::ObjectType, pt.x, pt.y); + noBase* obj = nullptr; + + switch(type) + { + // ── Player HQ ── + case 0x80: + { + if(lc < MAX_PLAYERS) + { + while(hqPositions.size() <= lc) + hqPositions.push_back(MapPoint::Invalid()); + hqPositions[lc] = pt; + } + break; + } + + // ── Trees (types 1-4) ── + case 0xC4: + { + if(lc >= 0x30 && lc <= 0x3D) obj = new noTree(pt, 0, 3); + else if(lc >= 0x70 && lc <= 0x7D) obj = new noTree(pt, 1, 3); + else if(lc >= 0xB0 && lc <= 0xBD) obj = new noTree(pt, 2, 3); + else if(lc >= 0xF0 && lc <= 0xFD) obj = new noTree(pt, 3, 3); + break; + } + + // ── Trees (types 5-8) ── + case 0xC5: + { + if(lc >= 0x30 && lc <= 0x3D) obj = new noTree(pt, 4, 3); + else if(lc >= 0x70 && lc <= 0x7D) obj = new noTree(pt, 5, 3); + else if(lc >= 0xB0 && lc <= 0xBD) obj = new noTree(pt, 6, 3); + else if(lc >= 0xF0 && lc <= 0xFD) obj = new noTree(pt, 7, 3); + break; + } + + // ── Tree type 9 ── + case 0xC6: + { + if(lc >= 0x30 && lc <= 0x3D) + obj = new noTree(pt, 8, 3); + break; + } + + // ── Landscape objects ── + case 0xC8: + case 0xC9: + { + if(lc == 0x0B) + obj = new noStaticObject(pt, 500 + lc); + else if(lc <= 0x0F) + obj = new noEnvObject(pt, 500 + lc); + else if(lc <= 0x14) + obj = new noEnvObject(pt, 542 + lc - 0x10); + else if(lc == 0x15) + obj = new noStaticObject(pt, 0, 0); + else if(lc == 0x16) + obj = new noStaticObject(pt, 560); + else if(lc == 0x17) + obj = new noStaticObject(pt, 561); + else if(lc <= 0x1E) + obj = new noStaticObject(pt, (lc - 0x18) * 2, 1); + else if(lc <= 0x20) + obj = new noStaticObject(pt, 20 + (lc - 0x1F) * 2, 1); + else if(lc == 0x21) + obj = new noStaticObject(pt, 30, 1); + else if(lc <= 0x2B) + obj = new noEnvObject(pt, 550 + lc - 0x22); + else if(lc <= 0x2E || lc == 0x30) + obj = new noStaticObject(pt, (lc - 0x2C) * 2, 2); + else if(lc == 0x2F) + obj = new noStaticObject(pt, (lc - 0x2C) * 2, 2, 2); + else if(lc == 0x31) + obj = new noStaticObject(pt, 0, 3); + else if(lc == 0x32) + obj = new noStaticObject(pt, 0, 4); + else if(lc == 0x33) + obj = new noStaticObject(pt, 0, 5); + else if(lc == 0x34) + obj = new noStaticObject(pt, 2, 5); + else if(lc == 0x35) + obj = new noStaticObject(pt, 4, 5); + break; + } + + // ── Granite type 1 ── + case 0xCC: + { + if(lc >= 0x01 && lc <= 0x06) + obj = new noGranite(GraniteType::One, lc - 1); + break; + } + + // ── Granite type 2 ── + case 0xCD: + { + if(lc >= 0x01 && lc <= 0x06) + obj = new noGranite(GraniteType::Two, lc - 1); + break; + } + // default: nothing + } + + if(obj) + ew->world_.SetNO(pt, obj); + } + } + + // ── 9. Place animals ── + RTTR_FOREACH_PT(MapPoint, MapExtent(w, h)) + { + using libsiedler2::MapLayer; + uint8_t a = map.getMapDataAt(MapLayer::Animals, pt.x, pt.y); + Species species; + switch(a) + { + case 1: species = Species::RabbitGrey; break; // random rabbit + case 2: species = Species::Fox; break; + case 3: species = Species::Stag; break; + case 4: species = Species::Deer; break; + case 5: species = Species::Duck; break; + case 6: species = Species::Sheep; break; + case 0: + case 0xFF: continue; + default: continue; + } + ew->world_.AddFigure(pt, std::make_unique(species, pt)); + } + + // ── 10. Extra animal info (from map's extraInfo list) ── + // Note: extraInfo animals are positioned at explicit (x,y) coords that may + // be outside the regular layer. We place them as additional figures. + for(const auto& extra : map.extraInfo) + { + if(extra.x >= w || extra.y >= h) + continue; + MapPoint pt(extra.x, extra.y); + Species species; + switch(extra.id) + { + case 1: species = Species::RabbitGrey; break; + case 2: species = Species::Fox; break; + case 3: species = Species::Stag; break; + case 4: species = Species::Deer; break; + case 5: species = Species::Duck; break; + case 6: species = Species::Sheep; break; + default: continue; + } + ew->world_.AddFigure(pt, std::make_unique(species, pt)); + } + + // ── 11. Shadows — recalculate from altitudes ── + RTTR_FOREACH_PT(MapPoint, MapExtent(w, h)) + recalcShadowAt(ew->world_, pt); + + // ── 12. BQ recalculation ── + ew->world_.InitAfterLoad(); + + // ── 13. Regenerate the terrain renderer with the new data ── + ew->viewer_->InitTerrainRenderer(); + + return ew; +} diff --git a/EditorWorld.h b/EditorWorld.h index a62d78d..a3dea7f 100644 --- a/EditorWorld.h +++ b/EditorWorld.h @@ -15,6 +15,9 @@ #include "world/GameWorld.h" #include "world/GameWorldViewer.h" #include "gameData/MapConsts.h" +#include "libsiedler2/ArchivItem_Map.h" +#include +#include class EditorWorld { @@ -27,6 +30,9 @@ class EditorWorld boost::filesystem::path filepath_; public: + /// Load an SWD/WLD map file into a new EditorWorld + static std::unique_ptr loadFromSwd(const boost::filesystem::path& filepath); + EditorWorld(const MapExtent& size, unsigned numPlayers) : em_(0), world_(std::vector(numPlayers), ggs_, em_), mapName_("Ohne Namen"), author_("Niemand") diff --git a/dskEditorInterface.cpp b/dskEditorInterface.cpp index 4dc7fd8..fda2d58 100644 --- a/dskEditorInterface.cpp +++ b/dskEditorInterface.cpp @@ -27,6 +27,8 @@ #include "enum_cast.hpp" #include "iwEditorCreateWorld.h" #include "iwEditorCursor.h" +#include "iwLoadMap.h" +#include "iwSaveMap.h" #include "controls/ctrlButton.h" #include "defines.h" #include "world/MapGeometry.h" @@ -697,7 +699,15 @@ void dskEditorInterface::Msg_ButtonClick(unsigned ctrl_id) WINDOWMANAGER.Show(std::make_unique()); break; case ID_btEditorMenu: - WINDOWMANAGER.Show(std::make_unique()); + if(world_) + WINDOWMANAGER.Show(std::make_unique(*world_)); + break; + case ID_btRLoad: + WINDOWMANAGER.Show(std::make_unique()); + break; + case ID_btRSave: + if(world_) + WINDOWMANAGER.Show(std::make_unique(*world_)); break; } } diff --git a/iwEditorMenu.cpp b/iwEditorMenu.cpp index b1c08ca..44da391 100644 --- a/iwEditorMenu.cpp +++ b/iwEditorMenu.cpp @@ -13,9 +13,10 @@ #include "globals.h" #include "Loader.h" -iwEditorMenu::iwEditorMenu() +iwEditorMenu::iwEditorMenu(EditorWorld& world) : IngameWindow(100, IngameWindow::posLastOrCenter, Extent(220, 320), "Main menu", - LOADER.GetImageN("resource", 41)) + LOADER.GetImageN("resource", 41)), + world_(world) { auto off = DrawPoint(contentOffset.x, contentOffset.y); int cx = (GetSize().x - contentOffset.x - contentOffsetEnd.x) / 2 + contentOffset.x; @@ -34,7 +35,7 @@ void iwEditorMenu::Msg_ButtonClick(unsigned ctrl_id) break; case ID_btSave: Close(); - WINDOWMANAGER.Show(std::make_unique()); + WINDOWMANAGER.Show(std::make_unique(world_)); break; case ID_btQuit: Close(); diff --git a/iwEditorMenu.h b/iwEditorMenu.h index 8eb8cfc..d5b5e9e 100644 --- a/iwEditorMenu.h +++ b/iwEditorMenu.h @@ -6,10 +6,12 @@ #include "ingameWindows/IngameWindow.h" +class EditorWorld; + class iwEditorMenu : public IngameWindow { public: - iwEditorMenu(); + explicit iwEditorMenu(EditorWorld& world); void Msg_ButtonClick(unsigned ctrl_id) override; @@ -20,4 +22,5 @@ class iwEditorMenu : public IngameWindow ID_btSave, ID_btQuit }; + EditorWorld& world_; }; diff --git a/iwLoadMap.cpp b/iwLoadMap.cpp index bfc4e1e..a23711c 100644 --- a/iwLoadMap.cpp +++ b/iwLoadMap.cpp @@ -3,16 +3,18 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "iwLoadMap.h" -#include "CGame.h" +#include "EditorWorld.h" #include "WindowManager.h" #include "controls/ctrlButton.h" #include "controls/ctrlList.h" #include "defines.h" #include "globals.h" +#include "dskEditorInterface.h" #include "helpers/format.hpp" #include "s25util/strAlgos.h" #include "Loader.h" #include +#include namespace bfs = boost::filesystem; @@ -54,25 +56,37 @@ void iwLoadMap::Msg_ButtonClick(unsigned ctrl_id) switch(ctrl_id) { case ID_btLoad: - if(!selectedFile_.empty()) + { + if(selectedFile_.empty()) + { + Close(); + break; + } + bfs::path path = global::userMapsPath / selectedFile_; + if(!bfs::exists(path)) + { + // Try both extensions + auto tryPath = global::userMapsPath / (selectedFile_ + ".swd"); + if(!bfs::exists(tryPath)) + tryPath = global::userMapsPath / (selectedFile_ + ".wld"); + path = tryPath; + } + if(bfs::exists(path)) { - auto path = global::userMapsPath / selectedFile_; - if(!bfs::exists(path)) + auto world = EditorWorld::loadFromSwd(path); + if(world) { - path.replace_extension(".swd"); - if(!bfs::exists(path)) - path.replace_extension(".wld"); - } - if(bfs::exists(path)) + WINDOWMANAGER.Switch(std::make_unique(std::move(world))); + } else { - // TODO: Load map into EditorWorld and switch to dskEditorInterface + std::cerr << "Failed to load map from " << path << "\n"; } } Close(); break; + } case ID_btAbort: Close(); break; } } - diff --git a/iwSaveMap.cpp b/iwSaveMap.cpp index 69701f0..9f0c1f5 100644 --- a/iwSaveMap.cpp +++ b/iwSaveMap.cpp @@ -3,36 +3,64 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "iwSaveMap.h" -#include -namespace bfs = boost::filesystem; -#include "WindowManager.h" +#include "EditorWorld.h" +#include "RttrForeachPt.h" +#include "defines.h" +#include "globals.h" +#include "libsiedler2/Archiv.h" +#include "libsiedler2/ArchivItem_Map.h" +#include "libsiedler2/ArchivItem_Map_Header.h" +#include "libsiedler2/libsiedler2.h" +#include "libsiedler2/prototypen.h" +#include "gameData/TerrainDesc.h" +#include "gameTypes/MapNode.h" +#include "gameTypes/BuildingQuality.h" +#include "gameTypes/GO_Type.h" +#include "gameTypes/Resource.h" +#include "nodeObjs/noAnimal.h" +#include "nodeObjs/noEnvObject.h" +#include "nodeObjs/noGranite.h" +#include "nodeObjs/noStaticObject.h" +#include "nodeObjs/noTree.h" #include "controls/ctrlButton.h" #include "controls/ctrlEdit.h" #include "controls/ctrlText.h" -#include "defines.h" -#include "globals.h" +#include "WindowManager.h" #include "Loader.h" +#include +#include + +namespace bfs = boost::filesystem; -iwSaveMap::iwSaveMap() - : IngameWindow(102, IngameWindow::posLastOrCenter, Extent(280, 200), "Save map", - LOADER.GetImageN("resource", 41)) +iwSaveMap::iwSaveMap(EditorWorld& world) + : IngameWindow(102, IngameWindow::posLastOrCenter, Extent(280, 230), "Save map", + LOADER.GetImageN("resource", 41)), + world_(world) { auto off = DrawPoint(contentOffset.x, contentOffset.y); int labelX = off.x + (GetSize().x - contentOffset.x - contentOffsetEnd.x) / 2 + contentOffset.x - 30; AddText(ID_lblFilename, DrawPoint(labelX, off.y + 2), "Filename", COLOR_YELLOW, FontStyle::CENTER, SmallFont); auto* editFile = AddEdit(ID_edtFilename, off + DrawPoint(10, 13), Extent(210, 22), TextureColor::Grey, NormalFont); - editFile->SetText("MyMap"); + { + // Use the original filename stem if available, else fall back to map name + auto fp = world_.getFilepath(); + if(!fp.empty()) + editFile->SetText(fp.stem().string()); + else + editFile->SetText(world_.getMapName()); + } AddText(ID_lblMapname, DrawPoint(labelX, off.y + 38), "Mapname", COLOR_YELLOW, FontStyle::CENTER, SmallFont); - AddEdit(ID_edtMapname, off + DrawPoint(10, 50), Extent(210, 22), TextureColor::Grey, NormalFont); + auto* editMapname = AddEdit(ID_edtMapname, off + DrawPoint(10, 50), Extent(210, 22), TextureColor::Grey, NormalFont); + editMapname->SetText(world_.getMapName()); AddText(ID_lblAuthor, DrawPoint(labelX, off.y + 75), "Author", COLOR_YELLOW, FontStyle::CENTER, SmallFont); - AddEdit(ID_edtAuthor, off + DrawPoint(10, 87), Extent(210, 22), TextureColor::Grey, NormalFont); + auto* editAuthor = AddEdit(ID_edtAuthor, off + DrawPoint(10, 87), Extent(210, 22), TextureColor::Grey, NormalFont); + editAuthor->SetText(world_.getAuthor()); - off += DrawPoint(0, 20); - AddTextButton(ID_btSave, off + DrawPoint(10, 115), Extent(100, 22), TextureColor::Green2, "Save", NormalFont); - AddTextButton(ID_btAbort, off + DrawPoint(120, 115), Extent(100, 22), TextureColor::Red1, "Abort", NormalFont); + AddTextButton(ID_btSave, off + DrawPoint(10, 125), Extent(100, 22), TextureColor::Green2, "Save", NormalFont); + AddTextButton(ID_btAbort, off + DrawPoint(120, 125), Extent(100, 22), TextureColor::Red1, "Abort", NormalFont); } void iwSaveMap::Msg_ButtonClick(unsigned ctrl_id) @@ -41,7 +69,261 @@ void iwSaveMap::Msg_ButtonClick(unsigned ctrl_id) { case ID_btSave: { - // TODO: wire up to EditorWorld/GameWorld for saving + auto& gameWorld = world_.getWorld(); + const auto mapSize = gameWorld.GetSize(); + + // ── Get user input ── + auto* edFilename = GetCtrl(ID_edtFilename); + auto* edMapname = GetCtrl(ID_edtMapname); + auto* edAuthor = GetCtrl(ID_edtAuthor); + if(!edFilename || !edMapname || !edAuthor) + break; + + std::string filename = edFilename->GetText(); + if(filename.empty()) + filename = "MyMap"; + + std::string mapName = edMapname->GetText(); + if(mapName.empty()) + mapName = filename; + + std::string author = edAuthor->GetText(); + if(author.empty()) + author = world_.getAuthor(); + + bfs::path outPath = global::userMapsPath / (filename + ".SWD"); + + // ── Build header ── + auto header = std::make_unique(); + header->setWidth(mapSize.x); + header->setHeight(mapSize.y); + auto landscape = gameWorld.GetLandscapeType(); + uint8_t gfxSet = 0; + if(landscape) + gfxSet = global::worldDesc.landscapes.get(landscape).s2Id; + header->setGfxSet(gfxSet); + header->setNumPlayers(static_cast(gameWorld.GetNumPlayers())); + header->setName(mapName); + header->setAuthor(author); + + // ── Build ArchivItem_Map ── + auto mapItem = std::make_unique(); + mapItem->init(std::move(header)); + + // Helper: find s2Id for a terrain descriptor + auto& desc = gameWorld.GetDescription(); + auto s2IdOfTerrain = [&](DescIdx t) -> uint8_t { + if(!t) return 0; + return desc.terrain.get(t).s2Id; + }; + + // Helper: check if a point is a harbor point + auto isHarbor = [&](MapPoint pt) -> bool { + return gameWorld.GetNode(pt).harborId.isValid(); + }; + + // ── Fill each layer ── + using libsiedler2::MapLayer; + + for(unsigned layerIdx = 0; layerIdx < libsiedler2::ArchivItem_Map::NUM_SWD_LAYERS; ++layerIdx) + { + auto layer = static_cast(layerIdx); + auto& layerData = mapItem->getLayer(layer); + + RTTR_FOREACH_PT(MapPoint, mapSize) + { + unsigned i = pt.y * mapSize.x + pt.x; + const auto& node = gameWorld.GetNode(pt); + + switch(layer) + { + case MapLayer::Altitude: + layerData[i] = node.altitude; + break; + + case MapLayer::Terrain1: + { + uint8_t t = s2IdOfTerrain(node.t1) & 0x3F; + if(isHarbor(pt)) + t |= libsiedler2::HARBOR_MASK; + layerData[i] = t; + break; + } + + case MapLayer::Terrain2: + layerData[i] = s2IdOfTerrain(node.t2) & 0x3F; + break; + + case MapLayer::RoadsOld: + { + uint8_t r = 0; + r |= static_cast(node.roads[RoadDir::SouthWest]) * 16; + r |= static_cast(node.roads[RoadDir::SouthEast]) * 4; + r |= static_cast(node.roads[RoadDir::East]); + layerData[i] = r; + break; + } + + case MapLayer::ObjectIndex: + { + noBase* obj = gameWorld.GetNO(pt); + uint8_t val = 0; + if(obj) + { + if(auto* tree = dynamic_cast(obj)) + { + unsigned t = tree->getTreeType(); + static const uint8_t baseIdx[9] = {0x30,0x70,0xB0,0xF0, + 0x30,0x70,0xB0,0xF0, + 0x30}; + val = (t < 9) ? baseIdx[t] : 0; + } else if(auto* granite = dynamic_cast(obj)) + { + val = granite->GetSize() + 1; + } else if(auto* stat = dynamic_cast(obj)) + { + val = static_cast(stat->GetItemID() & 0xFF); + } + } + layerData[i] = val; + break; + } + + case MapLayer::ObjectType: + { + noBase* obj = gameWorld.GetNO(pt); + uint8_t val = 0; + if(obj) + { + if(auto* tree = dynamic_cast(obj)) + { + unsigned t = tree->getTreeType(); + if(t <= 3) + val = 0xC4; + else if(t <= 7) + val = 0xC5; + else + val = 0xC6; + } else if(dynamic_cast(obj)) + { + val = 0xCC; + } else if(dynamic_cast(obj)) + { + val = 0xC8; + } + } + layerData[i] = val; + break; + } + + case MapLayer::Animals: + { + uint8_t val = 0; + for(const auto& fig : gameWorld.GetFigures(pt)) + { + if(fig.GetGOT() != GO_Type::Animal) + continue; + auto& animal = static_cast(fig); + switch(animal.GetSpecies()) + { + case Species::RabbitGrey: + case Species::RabbitWhite: val = 1; break; + case Species::Fox: val = 2; break; + case Species::Stag: val = 3; break; + case Species::Deer: val = 4; break; + case Species::Duck: val = 5; break; + case Species::Sheep: val = 6; break; + default: val = 0; break; + } + break; + } + layerData[i] = val; + break; + } + + case MapLayer::Unknown7: + layerData[i] = 0; + break; + + case MapLayer::BuildingQuality: + { + uint8_t bq = 0; + switch(node.bq) + { + case BuildingQuality::Nothing: bq = 0; break; + case BuildingQuality::Flag: bq = 1; break; + case BuildingQuality::Hut: bq = 2; break; + case BuildingQuality::House: bq = 3; break; + case BuildingQuality::Castle: bq = 4; break; + case BuildingQuality::Mine: bq = 5; break; + case BuildingQuality::Harbor: bq = 6; break; + } + layerData[i] = bq; + break; + } + + case MapLayer::Unknown9: + layerData[i] = 0x07; + break; + + case MapLayer::Unknown10: + layerData[i] = 0; + break; + + case MapLayer::Resources: + { + uint8_t val = 0; + auto res = node.resources; + switch(res.getType()) + { + case ResourceType::Nothing: val = 0; break; + case ResourceType::Water: + val = 0x20 | (res.getAmount() ? 1 : 0); + break; + case ResourceType::Coal: val = 0x40 | res.getAmount(); break; + case ResourceType::Iron: val = 0x48 | res.getAmount(); break; + case ResourceType::Gold: val = 0x50 | res.getAmount(); break; + case ResourceType::Granite: val = 0x58 | res.getAmount(); break; + case ResourceType::Fish: + val = 0x80 | (res.getAmount() > 0 ? 4 : 0); + break; + default: val = 0; break; + } + layerData[i] = val; + break; + } + + case MapLayer::Shadows: + layerData[i] = node.shadow; + break; + + case MapLayer::Lakes: + layerData[i] = 0; + break; + + default: + layerData[i] = 0; + break; + } + } + } + + // ── Extra animal info ── + mapItem->extraInfo.clear(); + + // ── Write file (wrap in Archiv, same pattern as LoadMAP produces) ── + libsiedler2::Archiv outArchiv; + outArchiv.push(std::move(mapItem)); + int ec = libsiedler2::loader::WriteMAP(outPath, outArchiv); + if(ec == 0) + { + std::cout << "Map saved to " << outPath << "\n"; + world_.setFilepath(outPath); + } else + { + std::cerr << "Failed to save map to " << outPath << " (error " << ec << ")\n"; + } + Close(); break; } diff --git a/iwSaveMap.h b/iwSaveMap.h index ac52c3d..11631f5 100644 --- a/iwSaveMap.h +++ b/iwSaveMap.h @@ -6,10 +6,12 @@ #include "ingameWindows/IngameWindow.h" +class EditorWorld; + class iwSaveMap : public IngameWindow { public: - iwSaveMap(); + explicit iwSaveMap(EditorWorld& world); void Msg_ButtonClick(unsigned ctrl_id) override; @@ -25,4 +27,6 @@ class iwSaveMap : public IngameWindow ID_btSave, ID_btAbort }; + + EditorWorld& world_; }; From 798fbb7eda1bd4fbe150d7e669a1903fb7f6304b Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 10 Jul 2026 17:20:46 +0200 Subject: [PATCH 16/16] HQ --- EditorWorld.cpp | 20 ++++++++++------- EditorWorld.h | 12 ++++++++++ GameWorldEditor.cpp | 21 ++++++++++++++++- GameWorldEditor.h | 11 ++++++--- dskEditorInterface.cpp | 30 ++++++++++++++++++++++--- dskEditorInterface.h | 1 + iwEditorPlayer.cpp | 51 +++++++++++++++++++++++++++++++++++++----- iwEditorPlayer.h | 19 +++++++++++++++- iwSaveMap.cpp | 44 ++++++++++++++++++++++++++++++++++++ 9 files changed, 188 insertions(+), 21 deletions(-) diff --git a/EditorWorld.cpp b/EditorWorld.cpp index 82224a0..449783d 100644 --- a/EditorWorld.cpp +++ b/EditorWorld.cpp @@ -84,7 +84,16 @@ std::unique_ptr EditorWorld::loadFromSwd(const bfs::path& filepath) ew->author_ = hdr.getAuthor(); ew->filepath_ = filepath; - // ── 5. Set the correct landscape type ── + // ── 5. Store HQ positions from the map header (max 7 players) ── + for(unsigned p = 0; p < MAX_PLAYERS && p < 7u; p++) + { + uint16_t hx, hy; + hdr.getPlayerHQ(p, hx, hy); + if(hx != 0xFFFF && hy != 0xFFFF) + ew->hqPositions_[p] = MapPoint(hx, hy); + } + + // ── 6. Set the correct landscape type ── ew->world_.SetLandscapeType(landscape); // ── 6. Helper: look up a terrain DescIdx by s2Id + current landscape ── @@ -169,7 +178,6 @@ std::unique_ptr EditorWorld::loadFromSwd(const bfs::path& filepath) // ── 8. Place objects (trees, granite, decorations, HQ markers) ── { - std::vector hqPositions; // indexed by player number RTTR_FOREACH_PT(MapPoint, MapExtent(w, h)) { using libsiedler2::MapLayer; @@ -179,15 +187,11 @@ std::unique_ptr EditorWorld::loadFromSwd(const bfs::path& filepath) switch(type) { - // ── Player HQ ── + // ── Player HQ (override header position from layer data) ── case 0x80: { if(lc < MAX_PLAYERS) - { - while(hqPositions.size() <= lc) - hqPositions.push_back(MapPoint::Invalid()); - hqPositions[lc] = pt; - } + ew->hqPositions_[lc] = pt; break; } diff --git a/EditorWorld.h b/EditorWorld.h index a3dea7f..186b509 100644 --- a/EditorWorld.h +++ b/EditorWorld.h @@ -77,6 +77,18 @@ class EditorWorld const boost::filesystem::path& getFilepath() const { return filepath_; } void setFilepath(const boost::filesystem::path& fp) { filepath_ = fp; } + /// HQ position per player (MapPoint::Invalid() = unused) + using HQArray = std::array; + const HQArray& getHQPositions() const { return hqPositions_; } + void setHQPosition(unsigned player, MapPoint pt) { if(player < MAX_PLAYERS) hqPositions_[player] = pt; } + void clearHQPosition(unsigned player) { if(player < MAX_PLAYERS) hqPositions_[player] = MapPoint::Invalid(); } + + /// Get index into editbob FLAG_* icons for a player (0-6 -> 11-17) + static int getHQIconForPlayer(unsigned player) { return 11 + player; } + +private: + HQArray hqPositions_{}; + void notifyChanged(MapPoint pt) { world_.GetNotifications().publish(NodeNote(NodeNote::Altitude, pt)); diff --git a/GameWorldEditor.cpp b/GameWorldEditor.cpp index 5f3e9fa..ec589fb 100644 --- a/GameWorldEditor.cpp +++ b/GameWorldEditor.cpp @@ -50,7 +50,7 @@ void GameWorldEditor::WrapOffset() } } -void GameWorldEditor::Draw(const Extent& screenSize) +void GameWorldEditor::Draw(const Extent& screenSize, const HQArray& hqPositions) { // Same tile range calculation as GameWorldView::CalcFxLx() int firstX = offset_.x / TR_W - 1; @@ -193,6 +193,25 @@ void GameWorldEditor::Draw(const Extent& screenSize) } } + // ── Draw HQ markers (colored flags from editbob) ── + { + for(unsigned player = 0; player < MAX_PLAYERS; player++) + { + const MapPoint& hqPt = hqPositions[player]; + if(!hqPt.isValid()) + continue; + // Draw at the node's world position — OpenGL already has the -offset_ translation + Position nodePos = world_.GetNodePos(hqPt); + + int flagIdx = 11 + static_cast(player); // FLAG_BLUE_DARK..FLAG_ORANGE + if(auto* flagImg = LOADER.GetImageN("editbob", flagIdx)) + { + // DrawFull compensates for origin offset (nx/ny); offset slightly above the node + flagImg->DrawFull(DrawPoint(nodePos.x - 10, nodePos.y - 20)); + } + } + } + glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); diff --git a/GameWorldEditor.h b/GameWorldEditor.h index adf6f93..34cfa06 100644 --- a/GameWorldEditor.h +++ b/GameWorldEditor.h @@ -6,9 +6,9 @@ #include "DrawPoint.h" #include "Point.h" +#include "gameTypes/MapCoordinates.h" #include - -#include "Point.h" +#include class GameWorld; class GameWorldViewer; @@ -17,6 +17,10 @@ class GameWorldViewer; class GameWorldEditor { public: + /// Maximum players in Settlers 2 + static constexpr unsigned MAX_PLAYERS = 8; + using HQArray = std::array; + GameWorldEditor(GameWorldViewer& viewer, GameWorld& world, const DrawPoint& offset = DrawPoint(0, 0)) : viewer_(viewer), world_(world), offset_(offset) {} @@ -24,7 +28,8 @@ class GameWorldEditor void SetOffset(const DrawPoint& offset); DrawPoint GetOffset() const { return offset_; } - void Draw(const Extent& screenSize); + /// Draw the editor view. hqPositions are the per-player HQ locations (Invalid = unused). + void Draw(const Extent& screenSize, const HQArray& hqPositions = {}); private: void WrapOffset(); diff --git a/dskEditorInterface.cpp b/dskEditorInterface.cpp index fda2d58..d34de35 100644 --- a/dskEditorInterface.cpp +++ b/dskEditorInterface.cpp @@ -519,6 +519,28 @@ void dskEditorInterface::applyTool() break; } case EditorToolMode::Flag: + { + // Place HQ for current player at cursor, or remove if already there + if(world_ && cursorPos_.isValid()) + { + const auto& hqPos = world_->getHQPositions(); + // Check if there's already an HQ at this position + bool alreadyHQ = false; + for(unsigned p = 0; p < MAX_PLAYERS; p++) + { + if(hqPos[p] == cursorPos_) + { + // Remove it + world_->clearHQPosition(p); + alreadyHQ = true; + break; + } + } + if(!alreadyHQ) + world_->setHQPosition(static_cast(currentPlayer_), cursorPos_); + } + break; + } case EditorToolMode::Resource: default: break; @@ -546,8 +568,8 @@ void dskEditorInterface::Msg_PaintBefore() } // ── Terrain via GameWorldEditor ── - if(gwEditor_) - gwEditor_->Draw(screenSize); + if(gwEditor_ && world_) + gwEditor_->Draw(screenSize, world_->getHQPositions()); // ── Cursor sprites (under UI chrome) ── drawCursor(); @@ -688,7 +710,9 @@ void dskEditorInterface::Msg_ButtonClick(unsigned ctrl_id) break; case ID_btToolPlayer: mode_ = EditorToolMode::Flag; - WINDOWMANAGER.Show(std::make_unique()); + WINDOWMANAGER.Show(std::make_unique( + currentPlayer_, + [this](int player) noexcept { currentPlayer_ = player; })); break; case ID_btToolBuildHelp: break; diff --git a/dskEditorInterface.h b/dskEditorInterface.h index 3e4e495..80b0cd4 100644 --- a/dskEditorInterface.h +++ b/dskEditorInterface.h @@ -76,6 +76,7 @@ class dskEditorInterface : public Desktop bool isModifying_ = false; int modeContent_ = 8; // selected terrain s2Id (default TRIANGLE_TEXTURE_MEADOW1) int modeContent2_ = 0; // secondary: tree type (0-8) or -1/-2 for mixed + int currentPlayer_ = 0; // active player for HQ/flag placement (0-6) bool pendingTerrainRefresh_ = false; // Cursor vertex field diff --git a/iwEditorPlayer.cpp b/iwEditorPlayer.cpp index 6afb2fd..fc2fa8e 100644 --- a/iwEditorPlayer.cpp +++ b/iwEditorPlayer.cpp @@ -5,15 +5,56 @@ #include "iwEditorPlayer.h" #include "Loader.h" #include "controls/ctrlButton.h" +#include "controls/ctrlText.h" +#include "defines.h" +#include "s25util/colors.h" +#include -iwEditorPlayer::iwEditorPlayer() +iwEditorPlayer::iwEditorPlayer(int currentPlayer, CbFunc onPlayerChanged) : IngameWindow(106, IngameWindow::posLastOrCenter, Extent(100, 80), "Players", - LOADER.GetImageN("resource", 41)) + LOADER.GetImageN("resource", 41)), + currentPlayer_(currentPlayer), onPlayerChanged_(std::move(onPlayerChanged)) { const int x0 = contentOffset.x; const int y0 = contentOffset.y; - AddTextButton(1, DrawPoint(x0, y0), Extent(20, 20), TextureColor::Grey, "-", NormalFont); - AddTextButton(2, DrawPoint(x0 + 40, y0), Extent(20, 20), TextureColor::Grey, "+", NormalFont); - AddTextButton(3, DrawPoint(x0, y0 + 20), Extent(60, 20), TextureColor::Grey, "Go to", NormalFont); + AddTextButton(ID_btPrev, DrawPoint(x0, y0), Extent(20, 20), TextureColor::Grey, "-", NormalFont); + AddText(ID_txtPlayer, DrawPoint(x0 + 26, y0 + 4), std::to_string(currentPlayer_ + 1), + COLOR_ORANGE, FontStyle::CENTER, LargeFont); + AddTextButton(ID_btNext, DrawPoint(x0 + 60, y0), Extent(20, 20), TextureColor::Grey, "+", NormalFont); + AddTextButton(ID_btGoTo, DrawPoint(x0, y0 + 20), Extent(60, 20), TextureColor::Grey, "Go to", NormalFont); +} + +void iwEditorPlayer::updateDisplay() +{ + auto* txt = GetCtrl(ID_txtPlayer); + if(txt) + txt->SetText(std::to_string(currentPlayer_ + 1)); +} + +void iwEditorPlayer::Msg_ButtonClick(unsigned ctrl_id) +{ + switch(ctrl_id) + { + case ID_btPrev: + if(currentPlayer_ > 0) + { + currentPlayer_--; + updateDisplay(); + if(onPlayerChanged_) + onPlayerChanged_(currentPlayer_); + } + break; + case ID_btNext: + if(currentPlayer_ < 6) + { + currentPlayer_++; + updateDisplay(); + if(onPlayerChanged_) + onPlayerChanged_(currentPlayer_); + } + break; + case ID_btGoTo: + break; + } } diff --git a/iwEditorPlayer.h b/iwEditorPlayer.h index 3e62e5f..7feb5ad 100644 --- a/iwEditorPlayer.h +++ b/iwEditorPlayer.h @@ -5,9 +5,26 @@ #pragma once #include "ingameWindows/IngameWindow.h" +#include class iwEditorPlayer : public IngameWindow { public: - iwEditorPlayer(); + using CbFunc = std::function; + iwEditorPlayer(int currentPlayer, CbFunc onPlayerChanged); + + void Msg_ButtonClick(unsigned ctrl_id) override; + +private: + enum + { + ID_btPrev, + ID_txtPlayer, + ID_btNext, + ID_btGoTo + }; + void updateDisplay(); + + int currentPlayer_; + CbFunc onPlayerChanged_; }; diff --git a/iwSaveMap.cpp b/iwSaveMap.cpp index 9f0c1f5..2d32a13 100644 --- a/iwSaveMap.cpp +++ b/iwSaveMap.cpp @@ -106,6 +106,16 @@ void iwSaveMap::Msg_ButtonClick(unsigned ctrl_id) header->setName(mapName); header->setAuthor(author); + // ── Store HQ positions in header (max 7 players) ── + { + const auto& hqPos = world_.getHQPositions(); + for(unsigned p = 0; p < MAX_PLAYERS && p < 7u; p++) + { + if(hqPos[p].isValid()) + header->setPlayerHQ(p, hqPos[p].x, hqPos[p].y); + } + } + // ── Build ArchivItem_Map ── auto mapItem = std::make_unique(); mapItem->init(std::move(header)); @@ -166,6 +176,23 @@ void iwSaveMap::Msg_ButtonClick(unsigned ctrl_id) case MapLayer::ObjectIndex: { + // Check for HQ marker first + const auto& hqPos = world_.getHQPositions(); + unsigned hqPlayer = MAX_PLAYERS; + for(unsigned p = 0; p < MAX_PLAYERS; p++) + { + if(hqPos[p] == pt) + { + hqPlayer = p; + break; + } + } + if(hqPlayer < MAX_PLAYERS) + { + layerData[i] = static_cast(hqPlayer); + break; + } + noBase* obj = gameWorld.GetNO(pt); uint8_t val = 0; if(obj) @@ -191,6 +218,23 @@ void iwSaveMap::Msg_ButtonClick(unsigned ctrl_id) case MapLayer::ObjectType: { + // Check for HQ marker first + const auto& hqPos = world_.getHQPositions(); + bool isHQ = false; + for(unsigned p = 0; p < MAX_PLAYERS; p++) + { + if(hqPos[p] == pt) + { + isHQ = true; + break; + } + } + if(isHQ) + { + layerData[i] = 0x80; + break; + } + noBase* obj = gameWorld.GetNO(pt); uint8_t val = 0; if(obj)