From eeda003c1f47acfd32f415fa16bb409f9ee11703 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Wed, 8 Jul 2026 20:14:09 +0200 Subject: [PATCH 1/3] 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 2/3] 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 3/3] 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);