From ae00ff02ad14088c88e0a50338a01e842b39a7fe Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Wed, 17 Jun 2026 00:06:57 +0200 Subject: [PATCH] OpenGL --- CGame.cpp | 37 +- CGame.h | 16 +- CGame_Event.cpp | 4 + CGame_Init.cpp | 49 +- CGame_Render.cpp | 101 +- CIO/CFile.cpp | 14 + CIO/CFont.cpp | 70 +- CIO/CMenu.cpp | 14 +- CMakeLists.txt | 29 +- CMap.cpp | 344 +++-- CMap.h | 49 +- CSurface.cpp | 1143 ++------------ CSurface.h | 12 +- CSurfaceGL.cpp | 211 +++ CSurfaceGL.h | 82 + GEOMETRY.md | 110 ++ GameWorldView.cpp | 282 ++++ GameWorldView.h | 21 + 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 --------- TerrainRenderer.cpp | 832 ++++++++++ include/SdlSurface.h | 15 - include/TerrainRenderer.h | 102 ++ 44 files changed, 2239 insertions(+), 10426 deletions(-) create mode 100644 CSurfaceGL.cpp create mode 100644 CSurfaceGL.h create mode 100644 GEOMETRY.md create mode 100644 GameWorldView.cpp create mode 100644 GameWorldView.h 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 create mode 100644 TerrainRenderer.cpp create mode 100644 include/TerrainRenderer.h diff --git a/CGame.cpp b/CGame.cpp index 2b28fd3..35f3444 100644 --- a/CGame.cpp +++ b/CGame.cpp @@ -8,9 +8,11 @@ #include "CIO/CWindow.h" #include "CMap.h" #include "RttrConfig.h" +#include "TerrainRenderer.h" #include "files.h" #include "globals.h" #include "s25util/file_handle.h" +#include #include #include #include @@ -41,6 +43,11 @@ CGame::CGame(Extent GameResolution_, bool fullscreen_) CGame::~CGame() { + if(glContext_) + { + SDL_GL_DeleteContext(static_cast(glContext_)); + glContext_ = nullptr; + } global::s2 = nullptr; } @@ -67,12 +74,21 @@ int CGame::Execute() return 0; } -void CGame::RenderPresent() const +void CGame::RenderPresent() +{ + // Upload Surf_Display to GL and draw (used by loading screen and callbacks) + if(uiOverlayTex_.valid()) + uiOverlayTex_.updateFromSurface(Surf_Display.get()); + else + uiOverlayTex_.createFromSurface(Surf_Display.get()); + if(uiOverlayTex_.valid()) + uiOverlayTex_.draw(0, 0); + SDL_GL_SwapWindow(window_.get()); +} + +void CGame::FlushSurfaceToGL() { - SDL_UpdateTexture(displayTexture_.get(), nullptr, Surf_Display->pixels, Surf_Display->w * sizeof(Uint32)); - SDL_RenderClear(renderer_.get()); - SDL_RenderCopy(renderer_.get(), displayTexture_.get(), nullptr, nullptr); - SDL_RenderPresent(renderer_.get()); + RenderPresent(); } CMenu* CGame::RegisterMenu(std::unique_ptr Menu) @@ -82,6 +98,7 @@ CMenu* CGame::RegisterMenu(std::unique_ptr Menu) Menu->setActive(); Menus.emplace_back(std::move(Menu)); + uiDirty_ = true; return Menus.back().get(); } @@ -94,6 +111,7 @@ bool CGame::UnregisterMenu(CMenu* Menu) if(it != Menus.begin()) it[-1]->setActive(); Menus.erase(it); + uiDirty_ = true; return true; } @@ -111,6 +129,7 @@ CWindow* CGame::RegisterWindow(std::unique_ptr Window) Window->setActive(); Window->setPriority(highestPriority + 1); Windows.emplace_back(std::move(Window)); + uiDirty_ = true; return Windows.back().get(); } @@ -123,6 +142,7 @@ bool CGame::UnregisterWindow(CWindow* Window) if(it != Windows.begin()) it[-1]->setActive(); Windows.erase(it); + uiDirty_ = true; return true; } @@ -141,9 +161,12 @@ bool CGame::UnregisterCallback(void (*callback)(int)) return true; } -void CGame::setMapObj(std::unique_ptr MapObj) +void CGame::setMapObj(std::unique_ptr map) { - this->MapObj = std::move(MapObj); + this->MapObj = std::move(map); + // Force terrain regeneration on new map. CMap::Draw will call + // GenerateOpenGL on the next frame when it sees the terrain is invalid. + TerrainRenderer::invalidateTerrain(); } CMap* CGame::getMapObj() diff --git a/CGame.h b/CGame.h index f1e74eb..5f68a4c 100644 --- a/CGame.h +++ b/CGame.h @@ -6,6 +6,7 @@ #pragma once #include "CIO/CFont.h" +#include "CSurfaceGL.h" #include "SdlSurface.h" #include #include @@ -26,9 +27,12 @@ class CGame bool Running; bool showLoadScreen; SdlSurface Surf_Display; - SdlTexture displayTexture_; - SdlRenderer renderer_; SdlWindow window_; + void* glContext_; + /// Persistent OpenGL texture for uploading the software overlay surface + EditorGLTexture displayGLTex_; + /// Persistent OpenGL texture for the final UI overlay (used by RenderPresent) + EditorGLTexture uiOverlayTex_; private: #ifdef _ADMINMODE @@ -42,6 +46,8 @@ class CGame CFont lastFps; Uint32 lastFrameTime = 0; + /// Does the composited UI surface (Surf_Display) need re-uploading? + bool uiDirty_ = true; // structure for mouse cursor struct @@ -81,7 +87,10 @@ class CGame void Render(); - void RenderPresent() const; + void RenderPresent(); + /// Upload Surf_Display content to OpenGL and present it. + /// Used by callbacks that render to Surf_Display directly (e.g. "Please wait"). + void FlushSurfaceToGL(); CMenu* RegisterMenu(std::unique_ptr Menu); bool UnregisterMenu(CMenu* Menu); @@ -94,4 +103,5 @@ class CGame void delMapObj(); SDL_Surface* getDisplaySurface() const { return Surf_Display.get(); }; auto getRes() const { return GameResolution; } + auto getCursorPos() const { return Cursor.pos; } }; diff --git a/CGame_Event.cpp b/CGame_Event.cpp index 8799fcd..a64bcfa 100644 --- a/CGame_Event.cpp +++ b/CGame_Event.cpp @@ -8,6 +8,7 @@ #include "CIO/CWindow.h" #include "CMap.h" #include "CSurface.h" +#include "TerrainRenderer.h" #include "callbacks.h" #include "globals.h" @@ -146,6 +147,7 @@ void CGame::EventHandling(SDL_Event* Event) { Cursor.pos = Position(Event->motion.x, Event->motion.y); } + uiDirty_ = true; /* //NOTE: we will now deliver the data to menus, windows, map etc., sometimes we have to break the switch and stop @@ -238,6 +240,7 @@ void CGame::EventHandling(SDL_Event* Event) Cursor.button.left = true; else if(Event->button.button == SDL_BUTTON_RIGHT) Cursor.button.right = true; + uiDirty_ = true; // clicking a mouse button will close the S2 loading screen if it is shown if(showLoadScreen) @@ -309,6 +312,7 @@ void CGame::EventHandling(SDL_Event* Event) { // setup mouse cursor data Cursor.clicked = false; + uiDirty_ = true; // NOTE: we will now deliver the data to menus, windows, map etc., sometimes we have to break the switch and // stop diff --git a/CGame_Init.cpp b/CGame_Init.cpp index 8c86271..37d81f7 100644 --- a/CGame_Init.cpp +++ b/CGame_Init.cpp @@ -7,32 +7,52 @@ #include "CIO/CFile.h" #include "CMap.h" #include "CSurface.h" -#include "SGE/sge_blib.h" -#include "SGE/sge_surface.h" +#include "CSurfaceGL.h" +#include "TerrainRenderer.h" #include "callbacks.h" #include "globals.h" #include "lua/GameDataLoader.h" +#include #include #include bool CGame::ReCreateWindow() { - displayTexture_.reset(); - renderer_.reset(); + displayGLTex_ = EditorGLTexture(); + uiOverlayTex_ = EditorGLTexture(); window_.reset(); + + unsigned windowFlags = fullscreen ? SDL_WINDOW_FULLSCREEN : 0; + + // Create window with OpenGL support (hard requirement, like s25client) window_.reset(SDL_CreateWindow("Return to the Roots Map editor [BETA]", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, GameResolution.x, GameResolution.y, - fullscreen ? SDL_WINDOW_FULLSCREEN : 0)); + windowFlags | SDL_WINDOW_OPENGL)); if(!window_) return false; - renderer_.reset(SDL_CreateRenderer(window_.get(), -1, 0)); - if(!renderer_) + + glContext_ = SDL_GL_CreateContext(window_.get()); + if(!glContext_ || !gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) + { + std::cerr << "Failed to create OpenGL context!\n"; return false; - displayTexture_ = makeSdlTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, GameResolution.x, - GameResolution.y); + } + + std::cout << "OpenGL " << GLVersion.major << "." << GLVersion.minor << " initialized\n"; + CSurfaceGL::init(GameResolution.x, GameResolution.y); // GL state setup (once) + TerrainRenderer::Init(GameResolution); // renderer init (once) + glClear(GL_COLOR_BUFFER_BIT); + SDL_GL_SwapWindow(window_.get()); + + // Software surface for legacy rendering (text overlay, callbacks). + // RGBA so the UI overlay can be composited on top of the map. Surf_Display = makeRGBSurface(GameResolution.x, GameResolution.y, true); - if(!displayTexture_ || !Surf_Display) + if(!Surf_Display) return false; + uiDirty_ = true; + + if(MapObj) + MapObj->setOverlayDirty(); SetAppIcon(); return true; @@ -50,7 +70,6 @@ bool CGame::Init() std::cout << "failure"; return false; } - sge_Lock_OFF(); CFile::init(); /*NOTE: its important to load a palette at first, @@ -80,12 +99,8 @@ bool CGame::Init() // std::cout << "\nShow loading screen..."; showLoadScreen = true; - // CSurface::Draw(Surf_Display, global::bmpArray[SPLASHSCREEN_LOADING_S2SCREEN].surface, 0, 0); - auto& surfSplash = global::bmpArray[SPLASHSCREEN_LOADING_S2SCREEN].surface; - sge_TexturedRect(Surf_Display.get(), 0, 0, Surf_Display->w - 1, 0, 0, Surf_Display->h - 1, Surf_Display->w - 1, - Surf_Display->h - 1, surfSplash.get(), 0, 0, surfSplash->w - 1, 0, 0, surfSplash->h - 1, - surfSplash->w - 1, surfSplash->h - 1); - RenderPresent(); + // Render the loading screen once so the user sees something during loading + Render(); GameDataLoader gdLoader(global::worldDesc); if(!gdLoader.Load()) diff --git a/CGame_Render.cpp b/CGame_Render.cpp index d4c0bfd..a15d508 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -9,7 +9,7 @@ #include "CIO/CWindow.h" #include "CMap.h" #include "CSurface.h" -#include "SGE/sge_blib.h" +#include "TerrainRenderer.h" #include "globals.h" #ifdef _WIN32 # include "s25editResource.h" @@ -28,7 +28,6 @@ void CGame::SetAppIcon() SendMessage(GetConsoleWindow(), WM_SETICON, ICON_SMALL, icon); SDL_SysWMinfo info; - // get window handle from SDL SDL_VERSION(&info.version); if(SDL_GetWindowWMInfo(window_.get(), &info) != 1) return; @@ -48,29 +47,68 @@ void CGame::Render() // if the S2 loading screen is shown, render only this until user clicks a mouse button if(showLoadScreen) { - // CSurface::Draw(Surf_Display, global::bmpArray[SPLASHSCREEN_LOADING_S2SCREEN].surface, 0, 0); auto& surfLoadScreen = global::bmpArray[SPLASHSCREEN_LOADING_S2SCREEN].surface; - sge_TexturedRect(Surf_Display.get(), 0, 0, Surf_Display->w - 1, 0, 0, Surf_Display->h - 1, Surf_Display->w - 1, - Surf_Display->h - 1, surfLoadScreen.get(), 0, 0, surfLoadScreen->w - 1, 0, 0, - surfLoadScreen->h - 1, surfLoadScreen->w - 1, surfLoadScreen->h - 1); + // Convert 8-bit paletted splash to match Surf_Display format (32-bit no alpha) + // Use same pixel format as Surf_Display so alpha from palette doesn't cause transparency + SDL_Surface* splash32 = SDL_ConvertSurface(surfLoadScreen.get(), Surf_Display->format, 0); + if(splash32) + { + // Remove any colorkey so full image renders + Uint32 key; + if(SDL_GetColorKey(splash32, &key) == 0) + SDL_SetColorKey(splash32, SDL_FALSE, 0); + SDL_BlitScaled(splash32, nullptr, Surf_Display.get(), nullptr); + SDL_FreeSurface(splash32); + } RenderPresent(); return; } + // Render terrain via OpenGL, then composite UI on top + glClear(GL_COLOR_BUFFER_BIT); + + // Clear UI overlay surface so old pixels don't persist + SDL_FillRect(Surf_Display.get(), nullptr, SDL_MapRGBA(Surf_Display->format, 0, 0, 0, 0)); + // render the map if active if(MapObj && MapObj->isActive()) { - CSurface::Draw(Surf_Display, MapObj->getSurface(), 0, 0); + RectBase viewRect = MapObj->getDisplayRect(); + + // Set camera projection for map-space rendering + TerrainRenderer::setCamera(viewRect.left, viewRect.top, GameResolution.x, GameResolution.y); + + // Only re-render and re-upload the map UI overlay when something changed. + // When idle (no mouse/keyboard input), the overlay content is identical + // to the previous frame and we can skip the expensive texture upload. + if(MapObj->isOverlayDirty() || !displayGLTex_.valid()) + { + if(displayGLTex_.valid()) + displayGLTex_.updateFromSurface(MapObj->getSurface()); + else + displayGLTex_.createFromSurface(MapObj->getSurface()); + MapObj->markOverlayClean(); + } + + // Draw terrain (+ pre-computed borders) from VBOs + TerrainRenderer::Draw(viewRect); + + // Switch to screen projection for all UI overlay drawing + TerrainRenderer::setScreenProjection(GameResolution.x, GameResolution.y); + + // Draw map overlay (frame, menubar, objects) in screen-space. + if(displayGLTex_.valid()) + displayGLTex_.draw(0, 0); + + // HUD text (coordinates, height info, lock status) — drawn to Surf_Display + // in screen-space. 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::writeText(Surf_Display, textBuffer.data(), 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::writeText(Surf_Display, textBuffer.data(), 100, 20); - // text for MovementLocked if(MapObj->isHorizontalMovementLocked() && MapObj->isVerticalMovementLocked()) CFont::writeText(Surf_Display, "Movement locked (F9 or F10 to unlock)", 20, 40, FontSize::Large, FontColor::Orange); @@ -107,22 +145,12 @@ void CGame::Render() } } - // render mouse cursor - if(Cursor.clicked) - { - if(Cursor.button.right) - CSurface::Draw(Surf_Display, global::bmpArray[CROSS].surface, Cursor.pos); - else - CSurface::Draw(Surf_Display, global::bmpArray[CURSOR_CLICKED].surface, Cursor.pos); - } else - CSurface::Draw(Surf_Display, global::bmpArray[CURSOR].surface, Cursor.pos); - #ifdef _ADMINMODE FrameCounter++; #endif + // FPS counter. ++framesPassedSinceLastFps; - const auto curTicks = SDL_GetTicks(); const auto diffTicks = curTicks - lastFpsTick; if(diffTicks > 1000) @@ -130,10 +158,39 @@ void CGame::Render() lastFps.setText(std::to_string((framesPassedSinceLastFps * 1000) / diffTicks) + " FPS"); framesPassedSinceLastFps = 0; lastFpsTick = curTicks; + uiDirty_ = true; } CSurface::Draw(Surf_Display, lastFps.getSurface(), 0, 0); - RenderPresent(); + // Upload final Surf_Display content to GL and draw it. + // Skip re-upload when nothing changed (idle state). + if(uiDirty_ || !uiOverlayTex_.valid()) + { + if(uiOverlayTex_.valid()) + uiOverlayTex_.updateFromSurface(Surf_Display.get()); + else + uiOverlayTex_.createFromSurface(Surf_Display.get()); + uiDirty_ = false; + } + if(uiOverlayTex_.valid()) + uiOverlayTex_.draw(0, 0); + + // render mouse cursor + EditorGLTexture cursorTex; + SDL_Surface* cursorSurf = nullptr; + if(Cursor.clicked) + { + if(Cursor.button.right) + cursorSurf = global::bmpArray[CROSS].surface.get(); + else + cursorSurf = global::bmpArray[CURSOR_CLICKED].surface.get(); + } else + cursorSurf = global::bmpArray[CURSOR].surface.get(); + if(cursorSurf && cursorTex.createFromSurface(cursorSurf)) + cursorTex.draw(Cursor.pos.x, Cursor.pos.y); + + glFlush(); + SDL_GL_SwapWindow(window_.get()); if(msWait) SDL_Delay(msWait); diff --git a/CIO/CFile.cpp b/CIO/CFile.cpp index 5f32718..59aa16b 100644 --- a/CIO/CFile.cpp +++ b/CIO/CFile.cpp @@ -482,6 +482,11 @@ bool CFile::read_lbm(FILE* fp, const boost::filesystem::path& filepath) CSurface::Draw(bmpArray->surface, (bmpArray - 1)->surface); } else bmpArray--; + } else + { + // Convert non-texture sprites to RGBA so we can use the alpha channel + // instead of a black sentinel for transparency. + bmpArray->surface = CSurface::ConvertToRgba(bmpArray->surface.get()); } // we are finished, the surface is filled @@ -1069,6 +1074,9 @@ bool CFile::read_bob02(FILE* fp) return false; } + // Convert to RGBA so transparency is encoded in the alpha channel. + bmpArray->surface = CSurface::ConvertToRgba(bmpArray->surface.get()); + // increment bmpArray for the next picture bmpArray++; @@ -1232,6 +1240,9 @@ bool CFile::read_bob04(FILE* fp, int player_color) // return false; } + // Convert to RGBA so transparency is encoded in the alpha channel. + bmpArray->surface = CSurface::ConvertToRgba(bmpArray->surface.get()); + // increment bmpArray for the next picture bmpArray++; @@ -1445,6 +1456,9 @@ bool CFile::read_bob14(FILE* fp) // 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); + // Convert to RGBA so transparency is encoded in the alpha channel. + bmpArray->surface = CSurface::ConvertToRgba(bmpArray->surface.get()); + // increment bmpArray for the next picture bmpArray++; diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp index 334486c..00a7943 100644 --- a/CIO/CFont.cpp +++ b/CIO/CFont.cpp @@ -293,12 +293,6 @@ void CFont::writeText() 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; - if(!Surf_Dest || string.empty()) return false; @@ -306,58 +300,20 @@ bool CFont::writeText(SDL_Surface* Surf_Dest, const std::string& string, unsigne if(Surf_Dest->h < static_cast(y + static_cast(fontsize))) return false; - // in case of right or middle alignment we must count the pixels first - auto pixel_count_loop = (align == FontAlign::Middle) || (align == FontAlign::Right); - - // 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) - { - 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) - { - pos_x = 0; - chiffre = string.begin(); - pixel_count_loop = false; - continue; - } - - ++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(); - - if(align == FontAlign::Middle) - pos_x = x - pixel_ctr_w / 2; - else if(align == FontAlign::Right) - pos_x = Surf_Dest->w - pixel_ctr_w; - - pixel_count_loop = false; - } - continue; - } - - // if right end of surface is reached, stop drawing chiffres - if(Surf_Dest->w < static_cast(pos_x + charW)) - break; - - // draw the chiffre to the destination - CSurface::Draw(Surf_Dest, global::bmpArray[getIndexForChar(*chiffre, fontsize, color)].surface, pos_x, pos_y); - - // set position for next chiffre - pos_x += charW; + // Render to a temporary surface first. + CFont font(string, 0, 0, fontsize, color); + font.writeText(); + SDL_Surface* fontSurf = font.getSurface(); + if(!fontSurf) + return false; - // go to next chiffre - ++chiffre; - } + // Calculate horizontal position based on alignment. + int pos_x = x; + if(align == FontAlign::Middle) + pos_x = x - fontSurf->w / 2; + else if(align == FontAlign::Right) + pos_x = Surf_Dest->w - fontSurf->w; + CSurface::Draw(Surf_Dest, fontSurf, pos_x, y); return true; } diff --git a/CIO/CMenu.cpp b/CIO/CMenu.cpp index 95b362c..e632d6b 100644 --- a/CIO/CMenu.cpp +++ b/CIO/CMenu.cpp @@ -6,7 +6,6 @@ #include "CMenu.h" #include "../CGame.h" #include "../globals.h" -#include CMenu::CMenu(int pic_background) : CControlContainer(pic_background) {} @@ -27,10 +26,17 @@ bool CMenu::render() return false; } - // CSurface::Draw(surface, global::bmpArray[pic_background].surface, 0, 0); auto& surfBG = global::bmpArray[getBackground()].surface; - sge_TexturedRect(surface.get(), 0, 0, surface->w - 1, 0, 0, surface->h - 1, surface->w - 1, surface->h - 1, - surfBG.get(), 0, 0, surfBG->w - 1, 0, 0, surfBG->h - 1, surfBG->w - 1, surfBG->h - 1); + // Convert to match destination format (drops palette alpha/colorkey), then stretch + SDL_Surface* bgConv = SDL_ConvertSurface(surfBG.get(), surface->format, 0); + if(bgConv) + { + Uint32 key; + if(SDL_GetColorKey(bgConv, &key) == 0) + SDL_SetColorKey(bgConv, SDL_FALSE, 0); + SDL_BlitScaled(bgConv, nullptr, surface.get(), nullptr); + SDL_FreeSurface(bgConv); + } renderElements(); return true; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cce50a..543867a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,25 @@ cmake_minimum_required(VERSION 3.16..3.20) project(s25edit) find_package(Boost 1.64 REQUIRED) +find_package(SDL2 REQUIRED) -add_subdirectory(SGE) +# glad: OpenGL loader +if(NOT TARGET glad) + set(RTTR_OGL_MAJOR 2) + set(RTTR_OGL_MINOR 0) + set(RTTR_OGL_ES 0) + set(RTTR_OGL_COMPAT 1) + set(RTTR_OGL_GL4ES 0) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../glad/openglCfg.hpp.cmake ${CMAKE_CURRENT_BINARY_DIR}/include/openglCfg.hpp @ONLY) + + set(GLAD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../glad/OpenGL2.0Compat/src/glad.c) + set(GLAD_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/../glad/OpenGL2.0Compat/include) + add_library(glad STATIC ${GLAD_SRC}) + target_include_directories(glad PUBLIC ${GLAD_INCLUDE} ${CMAKE_CURRENT_BINARY_DIR}/include) + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_link_libraries(glad PUBLIC ${CMAKE_DL_LIBS}) + endif() +endif() 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,8 +55,14 @@ ELSE() ENDIF() add_executable(s25edit ${MAIN_SOURCES} ${CIO_SOURCES} ${icon_RC}) -target_link_libraries(s25edit PRIVATE SGE rttrConfig s25Common gamedata endian::static Boost::nowide PUBLIC Boost::disable_autolinking Boost::program_options) -target_include_directories(s25edit PRIVATE include) +target_link_libraries(s25edit PRIVATE rttrConfig s25Common gamedata endian::static glad SDL2::SDL2 Boost::nowide PUBLIC Boost::disable_autolinking Boost::program_options) +target_include_directories(s25edit PRIVATE include + ${CMAKE_CURRENT_SOURCE_DIR}/CIO + ${CMAKE_CURRENT_SOURCE_DIR}/../libsiedler2/include + ${CMAKE_CURRENT_SOURCE_DIR}/../../libs/s25main + ${CMAKE_CURRENT_SOURCE_DIR}/../../libs/common/include + ${CMAKE_CURRENT_SOURCE_DIR}/../../libs/driver/include +) target_compile_features(s25edit PRIVATE cxx_std_17) if(MINGW) diff --git a/CMap.cpp b/CMap.cpp index 3318beb..93ec319 100644 --- a/CMap.cpp +++ b/CMap.cpp @@ -8,14 +8,40 @@ #include "CIO/CFile.h" #include "CIO/CFont.h" #include "CSurface.h" +#include "GameWorldView.h" +#include "TerrainRenderer.h" #include "callbacks.h" #include "globals.h" #include "gameData/LandscapeDesc.h" #include "gameData/TerrainDesc.h" +#include #include +#include #include #include +namespace { +// Fill the button rectangle with opaque black and then tile the background +// sprite on top. This guarantees the button is fully opaque even if the +// background sprite has transparent areas. +void drawButtonBackground(SdlSurface& dest, int x, int y, int w, int h, int bgPic) +{ + SDL_Rect r{x, y, w, h}; + SDL_FillRect(dest.get(), &r, SDL_MapRGBA(dest->format, 0, 0, 0, 255)); + + auto& bg = global::bmpArray[bgPic]; + for(int posX = 0; posX < w; posX += bg.w) + { + int drawW = std::min(bg.w, w - posX); + for(int posY = 0; posY < h; posY += bg.h) + { + int drawH = std::min(bg.h, h - posY); + CSurface::Draw(dest, bg.surface, x + posX, y + posY, 0, 0, drawW, drawH); + } + } +} +} // namespace + void bobMAP::setName(const std::string& newName) { name = newName; @@ -83,11 +109,12 @@ 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(); + Surf_UI.reset(); + overlayDirty_ = true; displayRect.left = 0; displayRect.top = 0; displayRect.setSize(global::s2->GameResolution); + cursorWorldPos_ = displayRect.getOrigin() + Position(displayRect.getSize().x / 2, displayRect.getSize().y / 2); if(!filepath.empty()) { @@ -118,7 +145,7 @@ void CMap::constructMap(const boost::filesystem::path& filepath, int width, int } } - Surf_Map.reset(); + Surf_UI.reset(); active = true; Vertex_ = {10, 10}; RenderBuildHelp = false; @@ -217,6 +244,8 @@ void CMap::constructMap(const boost::filesystem::path& filepath, int width, int map->s2IdToTerrain[t.s2Id] = i; } } + + TerrainRenderer::invalidateTerrain(); } void CMap::destructMap() { @@ -224,8 +253,8 @@ void CMap::destructMap() unloadMapPics(); undoBuffer.clear(); redoBuffer.clear(); - Surf_Map.reset(); - Surf_RightMenubar.reset(); + Surf_UI.reset(); + overlayDirty_ = true; // free vertex array Vertices.clear(); // free map structure memory @@ -475,6 +504,7 @@ void CMap::unloadMapPics() void CMap::moveMap(Position offset) { displayRect.setOrigin(displayRect.getOrigin() + offset); + overlayDirty_ = true; // reset coords of displayRects when end of map is reached if(displayRect.left >= map->width_pixel) displayRect.move(Position(-map->width_pixel, 0)); @@ -489,6 +519,7 @@ void CMap::moveMap(Position offset) void CMap::setMouseData(const SDL_MouseMotionEvent& motion) { + overlayDirty_ = true; // following code important for blitting the right field of the map // Are we scrolling? if(startScrollPos) @@ -505,9 +536,17 @@ void CMap::setMouseData(const SDL_MouseMotionEvent& motion) SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); SDL_WarpMouseInWindow(nullptr, startScrollPos->x, startScrollPos->y); SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE); - } - storeVerticesFromMouse(motion.x, motion.y, motion.state); + // After warping the cursor the logical vertex under the cursor must be + // recomputed from the *warped* screen position and the updated display + // rectangle. Using the pre-warp motion coordinates would place the + // brush at the old cursor location, making it drift away from the + // actual cursor while panning. + storeVerticesFromMouse(startScrollPos->x, startScrollPos->y, motion.state); + } else + { + storeVerticesFromMouse(motion.x, motion.y, motion.state); + } } void CMap::onLeftMouseDown(const Point32& pos) @@ -624,6 +663,7 @@ void CMap::onLeftMouseDown(const Point32& pos) void CMap::setMouseData(const SDL_MouseButtonEvent& button) { + overlayDirty_ = true; if(button.state == SDL_PRESSED) { if(button.button == SDL_BUTTON_LEFT) @@ -692,6 +732,7 @@ void restoreVertex(const SavedVertex& vertex, bobMAP& map) void CMap::setKeyboardData(const SDL_KeyboardEvent& key) { + overlayDirty_ = true; if(key.type == SDL_KEYDOWN) { switch(key.keysym.sym) @@ -987,6 +1028,10 @@ void CMap::storeVerticesFromMouse(Uint16 MouseX, Uint16 MouseY, Uint8 /*MouseSta // if ( (MouseState == SDL_PRESSED) && (mode == EDITOR_MODE_HEIGHT_RAISE || mode == EDITOR_MODE_HEIGHT_REDUCE) ) // return; + // Remember the unwrapped world coordinate of the cursor so the brush can be + // drawn on the wrapped copy of the map that is actually under the mouse. + cursorWorldPos_ = Position(MouseX + displayRect.left, MouseY + displayRect.top); + int X = 0, Xeven = 0, Xodd = 0; int Y = 0, MousePosY = 0; @@ -1054,16 +1099,25 @@ Position CMap::correctMouseBlit(Position vertexPos) const { const auto& vertex = map->getVertex(vertexPos); Position newBlit(vertex.x, vertex.y); - if(newBlit.x < displayRect.left) - newBlit.x += map->width_pixel; - else if(newBlit.x > displayRect.right) - newBlit.x -= map->width_pixel; - if(newBlit.y < displayRect.top) - newBlit.y += map->height_pixel; - else if(newBlit.y > displayRect.bottom) - newBlit.y -= map->height_pixel; - newBlit -= displayRect.getOrigin(); + // Pick the wrapped copy of the vertex that is closest to the unwrapped + // cursor world position. This keeps the brush on the same visible copy of + // the map as the mouse even when the view crosses a wrap seam or the map + // is zoomed out so far that it repeats many times. + if(map->width_pixel > 0) + { + int kx = + static_cast(std::floor((cursorWorldPos_.x - vertex.x) / static_cast(map->width_pixel) + 0.5)); + newBlit.x += kx * map->width_pixel; + } + if(map->height_pixel > 0) + { + int ky = + static_cast(std::floor((cursorWorldPos_.y - vertex.y) / static_cast(map->height_pixel) + 0.5)); + newBlit.y += ky * map->height_pixel; + } + + newBlit -= displayRect.getOrigin(); return newBlit; } @@ -1073,28 +1127,91 @@ void CMap::render() if(displayRect.getSize() != global::s2->GameResolution) { displayRect.setSize(global::s2->GameResolution); - Surf_Map.reset(); + Surf_UI.reset(); + overlayDirty_ = true; } // if we need a new surface - if(!Surf_Map) + if(!Surf_UI) { - 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); + Surf_UI = makeRGBSurface(displayRect.getSize().x, displayRect.getSize().y, true); + overlayDirty_ = true; + } + + // Skip re-rendering if nothing changed since last frame. + // The dirty flag is set by any method that modifies overlay state + // (mouse/keyboard events, mode changes, scrolling, etc.). + if(!overlayDirty_) + { + // Still need to process vertex modifications when user is actively editing + if(modify) + modifyVertex(); + return; + } + + // Make sure the cursor world position is current. When the mouse itself + // moved we also recompute the logical vertex under the cursor. We only do + // the latter on actual cursor movement so that random cursor fill does not + // get re-rolled every frame while scrolling. + { + Position cursorScreen = global::s2->getCursorPos(); + if(cursorScreen != lastCursorScreenPos_) + { + storeVerticesFromMouse(cursorScreen.x, cursorScreen.y, 0); + lastCursorScreenPos_ = cursorScreen; + } else + { + // The view may have scrolled; keep the unwrapped cursor position in + // sync with the current display rectangle and recompute the brush + // blit positions so the cursor highlight stays on the right wrapped + // copy. We do not recompute the logical vertex here so random fill + // does not flicker every frame while panning. + cursorWorldPos_ = cursorScreen + displayRect.getOrigin(); + for(auto& v : Vertices) + v.blit = correctMouseBlit(v); + } } - // 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) ); + + // Clear to fully transparent (0,0,0,0). Transparent sprite pixels leave + // the overlay see-through in GL. + SDL_FillRect(Surf_UI.get(), nullptr, SDL_MapRGBA(Surf_UI->format, 0, 0, 0, 0)); // touch vertex data if user modifies it if(modify) modifyVertex(); + // Terrain and coastline borders are rendered by TerrainRenderer::Draw. + // Editor overlay sprites (trees, resources, buildings, animals) are drawn + // by EditorWorldView, aligned with s25client::GameWorldView. if(!map->vertex.empty()) - CSurface::DrawTriangleField(Surf_Map.get(), displayRect, *map); + { + if(!TerrainRenderer::isTerrainValid()) + { + SDL_Surface* tilesetSurface = nullptr; + switch(map->type) + { + case MAP_GREENLAND: + default: + tilesetSurface = + global::bmpArray[BitsPerPixel == 8 ? TILESET_GREENLAND_8BPP : TILESET_GREENLAND_32BPP] + .surface.get(); + break; + case MAP_WASTELAND: + tilesetSurface = + global::bmpArray[BitsPerPixel == 8 ? TILESET_WASTELAND_8BPP : TILESET_WASTELAND_32BPP] + .surface.get(); + break; + case MAP_WINTERLAND: + tilesetSurface = + global::bmpArray[BitsPerPixel == 8 ? TILESET_WINTERLAND_8BPP : TILESET_WINTERLAND_32BPP] + .surface.get(); + break; + } + if(tilesetSurface) + TerrainRenderer::GenerateOpenGL(*map, tilesetSurface); + } + EditorWorldView::Draw(Surf_UI.get(), displayRect, *map); + } // draw pictures to cursor position int symbol_index, symbol_index2 = -1; @@ -1123,58 +1240,58 @@ void CMap::render() { if(Vertices[i].active) { - CSurface::Draw(Surf_Map, global::bmpArray[symbol_index].surface, Vertices[i].blit - Position::all(10)); + CSurface::Draw(Surf_UI, global::bmpArray[symbol_index].surface, Vertices[i].blit - Position::all(10)); if(symbol_index2 >= 0) - CSurface::Draw(Surf_Map, global::bmpArray[symbol_index2].surface, Vertices[i].blit - Position(0, 7)); + CSurface::Draw(Surf_UI, global::bmpArray[symbol_index2].surface, Vertices[i].blit - Position(0, 7)); } } // draw the frame if(displayRect.getSize() == Extent(640, 480)) - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_640_480].surface); + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_640_480].surface); else if(displayRect.getSize() == Extent(800, 600)) - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_800_600].surface); + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_800_600].surface); else if(displayRect.getSize() == Extent(1024, 768)) - CSurface::Draw(Surf_Map, global::bmpArray[MAINFRAME_1024_768].surface); + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_1024_768].surface); 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)); + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_LEFT_1280_1024].surface); + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_RIGHT_1280_1024].surface, 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, + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_640_480].surface, 0, 0, 0, 0, 150, 150); + CSurface::Draw(Surf_UI, 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, + CSurface::Draw(Surf_UI, 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, + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_640_480].surface, displayRect.getSize().x - 150, displayRect.getSize().y - 150, 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, + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_640_480].surface, x, 0, 150, 0, 150, 12); + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_640_480].surface, x, displayRect.getSize().y - 12, 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, + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_640_480].surface, 0, y, 0, 150, 12, 150); + CSurface::Draw(Surf_UI, global::bmpArray[MAINFRAME_640_480].surface, displayRect.getSize().x - 12, y, 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, + CSurface::Draw(Surf_UI, global::bmpArray[STATUE_UP_LEFT].surface, Position(12, 12)); + CSurface::Draw(Surf_UI, 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, + CSurface::Draw(Surf_UI, 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, + CSurface::Draw(Surf_UI, global::bmpArray[STATUE_DOWN_RIGHT].surface, displayRect.getSize() - Position(global::bmpArray[STATUE_DOWN_RIGHT].w, global::bmpArray[STATUE_DOWN_RIGHT].h) - Position::all(12)); @@ -1182,101 +1299,68 @@ void CMap::render() // lower menubar const Position menubarPos = Position(displayRect.getSize().x / 2, displayRect.getSize().y); // draw lower menubar - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR].surface, + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR].surface, menubarPos - Extent(global::bmpArray[MENUBAR].w / 2, 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); + // The button face sprite has transparent areas; blitting it onto the RGBA + // Surf_UI leaves those pixels see-through. Draw an opaque background + // first so every button is square and opaque, then blit the face on top. + const int lowerBtnW = 37, lowerBtnH = 32; + const int lowerBtnX[] = {-236, -199, -162, -125, -88, -51, -14, 92, 129, 166, 203}; + for(int offsetX : lowerBtnX) + { + int x = menubarPos.x + offsetX; + int y = menubarPos.y - 36; + drawButtonBackground(Surf_UI, x, y, lowerBtnW, lowerBtnH, BUTTON_GREEN1_BACKGROUND); + CSurface::Draw(Surf_UI, global::bmpArray[BUTTON_GREEN1_DARK].surface, x, y, 0, 0, lowerBtnW, lowerBtnH); + } // 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)); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_HEIGHT].surface, menubarPos - Extent(232, 35)); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_TEXTURE].surface, menubarPos - Extent(195, 35)); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_TREE].surface, menubarPos - Extent(158, 37)); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_RESOURCE].surface, menubarPos - Extent(121, 32)); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_LANDSCAPE].surface, menubarPos - Extent(84, 37)); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_ANIMAL].surface, menubarPos - Extent(48, 36)); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_PLAYER].surface, menubarPos - Extent(10, 34)); + + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_BUILDHELP].surface, menubarPos + Position(96, -35)); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_MINIMAP].surface, menubarPos + Position(131, -37)); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_NEWWORLD].surface, menubarPos + Position(166, -37)); + CSurface::Draw(Surf_UI, 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) - { - 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); - } - } - // 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 the menubar rotated 90 degrees directly into the overlay + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR].surface, rightMenubarPos.x - global::bmpArray[MENUBAR].h, + rightMenubarPos.y - global::bmpArray[MENUBAR].w / 2, 270); // 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); + // Draw an opaque background first so the button faces are square and + // opaque over the terrain. + const int rightBtnW = 32, rightBtnH = 37; + const int rightBtnY[] = {-239, -202, -165, -128, -22, 15, 52, 89, 126, 163, 200}; + for(int offsetY : rightBtnY) + { + int x = rightMenubarPos.x - 36; + int y = rightMenubarPos.y + offsetY; + drawButtonBackground(Surf_UI, x, y, rightBtnW, rightBtnH, BUTTON_GREEN1_BACKGROUND); + CSurface::Draw(Surf_UI, global::bmpArray[BUTTON_GREEN1_DARK].surface, x, y, 0, 0, rightBtnW, rightBtnH); + } // 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)); + CSurface::Draw(Surf_UI, global::bmpArray[CURSOR_SYMBOL_ARROW_UP].surface, rightMenubarPos - Extent(33, 237)); + CSurface::Draw(Surf_UI, global::bmpArray[CURSOR_SYMBOL_ARROW_DOWN].surface, rightMenubarPos - Extent(20, 235)); + CSurface::Draw(Surf_UI, global::bmpArray[CURSOR_SYMBOL_ARROW_DOWN].surface, rightMenubarPos - Extent(33, 220)); + CSurface::Draw(Surf_UI, global::bmpArray[CURSOR_SYMBOL_ARROW_UP].surface, rightMenubarPos - Extent(20, 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", rightMenubarPos.x - 35, rightMenubarPos.y + 193); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_BUGKILL].surface, rightMenubarPos + Position(-37, 162)); + CFont::writeText(Surf_UI, "Load", rightMenubarPos.x - 35, rightMenubarPos.y + 193); // bugkill picture for quicksave with text - CSurface::Draw(Surf_Map, global::bmpArray[MENUBAR_BUGKILL].surface, rightMenubarPos + Position(-37, 200)); - CFont::writeText(Surf_Map, "Save", rightMenubarPos.x - 35, rightMenubarPos.y + 231); + CSurface::Draw(Surf_UI, global::bmpArray[MENUBAR_BUGKILL].surface, rightMenubarPos + Position(-37, 200)); + CFont::writeText(Surf_UI, "Save", rightMenubarPos.x - 35, rightMenubarPos.y + 231); + + overlayDirty_ = false; } static void getTriangleColor(TriangleTerrainType terrainType, MapType mapType, Sint16& r, Sint16& g, Sint16& b) @@ -1536,6 +1620,10 @@ void CMap::modifyVertex() { modifyPlayer(Vertex_.x, Vertex_.y); } + + // Height/texture/shading edits changed the underlying map data, so the + // GL terrain cache must be rebuilt on the next frame. + TerrainRenderer::invalidateTerrain(); } void CMap::modifyHeightRaise(int VertexX, int VertexY) diff --git a/CMap.h b/CMap.h index 427d682..4d3431c 100644 --- a/CMap.h +++ b/CMap.h @@ -45,8 +45,7 @@ class CMap private: boost::filesystem::path filepath_; - SdlSurface Surf_Map; - SdlSurface Surf_RightMenubar; + SdlSurface Surf_UI; std::unique_ptr map; DisplayRectangle displayRect; bool active; @@ -63,6 +62,8 @@ class CMap int modeContent2; // is the user currently modifying? bool modify; + // does the UI overlay surface need re-rendering and re-uploading? + bool overlayDirty_ = true; // necessary for "undo"- and "do"-function bool saveCurrentVertices; std::list undoBuffer; @@ -104,6 +105,10 @@ class CMap bool HorizontalMovementLocked; bool VerticalMovementLocked; std::optional startScrollPos; + // Unwrapped world position of the mouse cursor, used to place the brush on + // the correct wrapped copy of the map. + Position cursorWorldPos_; + Position lastCursorScreenPos_ = Position::Invalid(); public: CMap(const boost::filesystem::path& filepath); @@ -136,22 +141,43 @@ class CMap void setBitsPerPixel(int bbp) { BitsPerPixel = bbp; - Surf_Map.reset(); + Surf_UI.reset(); + overlayDirty_ = true; + } + void setMode(int mode) + { + this->mode = mode; + overlayDirty_ = true; } - void setMode(int mode) { this->mode = mode; } int getMode() const { return mode; } - void setModeContent(int modeContent) { this->modeContent = modeContent; } - void setModeContent2(int modeContent2) { this->modeContent2 = modeContent2; } + void setModeContent(int modeContent) + { + this->modeContent = modeContent; + overlayDirty_ = true; + } + void setModeContent2(int modeContent2) + { + this->modeContent2 = modeContent2; + overlayDirty_ = true; + } int getModeContent() const { return modeContent; } int getModeContent2() const { return modeContent2; } bobMAP* getMap() { return map.get(); } SDL_Surface* getSurface() { - render(); - return Surf_Map.get(); + if(overlayDirty_) + render(); + return Surf_UI.get(); } + bool isOverlayDirty() const { return overlayDirty_; } + void markOverlayClean() { overlayDirty_ = false; } + void setOverlayDirty() { overlayDirty_ = true; } DisplayRectangle getDisplayRect() { return displayRect; } - void setDisplayRect(const DisplayRectangle& displayRect) { this->displayRect = displayRect; } + void setDisplayRect(const DisplayRectangle& displayRect) + { + this->displayRect = displayRect; + overlayDirty_ = true; + } auto& getPlayerHQx() { return PlayerHQx; } auto& getPlayerHQy() { return PlayerHQy; } const boost::filesystem::path& getFilepath() const { return filepath_; } @@ -168,30 +194,35 @@ class CMap { ChangeSectionHexagonMode = HexagonMode; setupVerticesActivity(); + overlayDirty_ = true; } bool getHexagonMode() const { return ChangeSectionHexagonMode; } void setVertexFillRSU(bool fillRSU) { VertexFillRSU = fillRSU; setupVerticesActivity(); + overlayDirty_ = true; } bool getVertexFillRSU() const { return VertexFillRSU; } void setVertexFillUSD(bool fillUSD) { VertexFillUSD = fillUSD; setupVerticesActivity(); + overlayDirty_ = true; } bool getVertexFillUSD() const { return VertexFillUSD; } void setVertexFillRandom(bool fillRandom) { VertexFillRandom = fillRandom; setupVerticesActivity(); + overlayDirty_ = true; } bool getVertexFillRandom() const { return VertexFillRandom; } void setVertexActivityRandom(bool activityRandom) { VertexActivityRandom = activityRandom; setupVerticesActivity(); + overlayDirty_ = true; } bool getVertexActivityRandom() const { return VertexActivityRandom; } diff --git a/CSurface.cpp b/CSurface.cpp index 6494ffb..fb543fc 100644 --- a/CSurface.cpp +++ b/CSurface.cpp @@ -4,58 +4,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CSurface.h" -#include "CGame.h" -#include "CMap.h" #include "Rect.h" -#include "SGE/sge_blib.h" -#include "SGE/sge_rotation.h" #include "globals.h" -#include "gameData/EdgeDesc.h" -#include "gameData/TerrainDesc.h" #include -#include #include -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]) -{ - 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); -} - -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; +// drawTextures removed — terrain is pre-computed in GL bool CSurface::Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y) { @@ -67,8 +21,27 @@ bool CSurface::Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y) DestR.x = X; DestR.y = Y; + // Ensure source pixels get alpha=255 when blitting to an RGBA surface, + // so only colorkey-skipped pixels remain transparent. + bool destHasAlpha = (Surf_Dest->format->Amask != 0); + SDL_BlendMode oldBlend = SDL_BLENDMODE_NONE; + Uint8 oldMod = 255; + if(destHasAlpha) + { + SDL_GetSurfaceBlendMode(Surf_Src, &oldBlend); + SDL_GetSurfaceAlphaMod(Surf_Src, &oldMod); + SDL_SetSurfaceBlendMode(Surf_Src, SDL_BLENDMODE_BLEND); + SDL_SetSurfaceAlphaMod(Surf_Src, 255); + } + SDL_BlitSurface(Surf_Src, nullptr, Surf_Dest, &DestR); + if(destHasAlpha) + { + SDL_SetSurfaceBlendMode(Surf_Src, oldBlend); + SDL_SetSurfaceAlphaMod(Surf_Src, oldMod); + } + return true; } @@ -87,31 +60,96 @@ bool CSurface::Draw(SdlSurface& Surf_Dest, SDL_Surface* Surf_Src, int X, int Y) return Draw(Surf_Dest.get(), Surf_Src, X, Y); } +SdlSurface CSurface::ConvertToRgba(SDL_Surface* src) +{ + if(!src) + return nullptr; + if(src->format->BitsPerPixel == 32) + return SdlSurface(SDL_ConvertSurface(src, src->format, 0)); + if(src->format->BitsPerPixel != 8 || !src->format->palette) + return nullptr; + + SDL_Surface* dst = SDL_CreateRGBSurface(0, src->w, src->h, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000); + if(!dst) + return nullptr; + + Uint32 ck; + const bool hasCK = (SDL_GetColorKey(src, &ck) == 0); + const Uint8 ckIdx = (hasCK ? static_cast(ck & 0xFF) : 0xFF); + + SDL_LockSurface(src); + SDL_LockSurface(dst); + for(int y = 0; y < src->h; y++) + { + const Uint8* srcRow = (const Uint8*)src->pixels + y * src->pitch; + Uint32* dstRow = (Uint32*)((Uint8*)dst->pixels + y * dst->pitch); + for(int x = 0; x < src->w; x++) + { + const Uint8 idx = srcRow[x]; + const SDL_Color& c = src->format->palette->colors[idx]; + const Uint8 a = (hasCK && idx == ckIdx) ? 0 : 0xFF; + dstRow[x] = (Uint32(a) << 24) | (Uint32(c.r) << 16) | (Uint32(c.g) << 8) | Uint32(c.b); + } + } + SDL_UnlockSurface(dst); + SDL_UnlockSurface(src); + + return SdlSurface(dst); +} + bool CSurface::Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y, int angle) { if(!Surf_Dest || !Surf_Src) return false; - Uint16 px, py; + if(angle != 90 && angle != 180 && angle != 270) + return false; - switch(angle) + // Simple software rotation for 90/180/270 degrees + SDL_Surface* rotated = + SDL_CreateRGBSurface(0, Surf_Src->h, Surf_Src->w, 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++) { - case 90: - px = 0; - py = Surf_Src->h - 1; - break; - case 180: - px = Surf_Src->w - 1; - py = Surf_Src->h - 1; - break; - case 270: - px = Surf_Src->w - 1; - py = 0; - break; - default: return false; + 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); + } } - - sge_transform(Surf_Src, Surf_Dest, (float)angle, 1.0, 1.0, px, py, X, Y, SGE_TSAFE); + 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; } @@ -138,8 +176,25 @@ bool CSurface::Draw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y, SrcR.w = W; SrcR.h = H; + bool destHasAlpha = (Surf_Dest->format->Amask != 0); + SDL_BlendMode oldBlend = SDL_BLENDMODE_NONE; + Uint8 oldMod = 255; + if(destHasAlpha) + { + SDL_GetSurfaceBlendMode(Surf_Src, &oldBlend); + SDL_GetSurfaceAlphaMod(Surf_Src, &oldMod); + SDL_SetSurfaceBlendMode(Surf_Src, SDL_BLENDMODE_BLEND); + SDL_SetSurfaceAlphaMod(Surf_Src, 255); + } + SDL_BlitSurface(Surf_Src, &SrcR, Surf_Dest, &DestR); + if(destHasAlpha) + { + SDL_SetSurfaceBlendMode(Surf_Src, oldBlend); + SDL_SetSurfaceAlphaMod(Surf_Src, oldMod); + } + return true; } @@ -219,966 +274,6 @@ Uint32 CSurface::GetPixel(SDL_Surface* surface, int x, int y) } } -void CSurface::DrawTriangleField(SDL_Surface* display, const DisplayRectangle& displayRect, const bobMAP& myMap) -{ - Uint16 width = myMap.width; - Uint16 height = myMap.height; - auto type = myMap.type; - MapNode tempP1, tempP2, tempP3; - - // min size to avoid underflows - 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; - - // draw triangle field - // NOTE: WE DO THIS TWICE, AT FIRST ONLY TRIANGLE-TEXTURES, AT SECOND THE TEXTURE-BORDERS AND OBJECTS - for(int i = 0; i < 2; i++) - { - drawTextures = (i == 0); - - for(int k = 0; k < 4; k++) - { - // 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; - bool view_outside_edges; - - if(k > 0) - { - // now call DrawTriangle for all triangles outside the map edges - view_outside_edges = false; - - if(k == 1 || k == 3) - { - // at first call DrawTriangle for all triangles up or down outside - if(displayRect.top < 0) - { - row_start = std::max(0, height - 1 - (-displayRect.top / triangleHeight) - 1); - row_end = height - 1; - view_outside_edges = true; - } else if(displayRect.bottom > myMap.height_pixel) - { - row_start = 0; - row_end = (displayRect.bottom - myMap.height_pixel) / triangleHeight + 8; - view_outside_edges = true; - } else if(displayRect.top <= 2 * triangleHeight) - { - // this is for draw triangles that are reduced under the lower map edge (have bigger y-coords as - // myMap.height_pixel) - row_start = height - 3; - row_end = height - 1; - view_outside_edges = true; - } else if(displayRect.bottom >= (myMap.height_pixel - 8 * triangleHeight)) - { - // this is for draw triangles that are raised over the upper map edge (have negative y-coords) - row_start = 0; - row_end = 8; - view_outside_edges = true; - } - } - - if(k == 2 || k == 3) - { - // now call DrawTriangle for all triangles left or right outside - if(displayRect.left <= 0) - { - col_start = std::max(0, width - 1 - (-displayRect.left / triangleWidth) - 1); - col_end = width - 1; - view_outside_edges = true; - } else if(displayRect.left < triangleWidth) - { - col_start = width - 2; - col_end = width - 1; - view_outside_edges = true; - } else if(displayRect.right > myMap.width_pixel) - { - col_start = 0; - col_end = (displayRect.right - myMap.width_pixel) / triangleWidth + 1; - view_outside_edges = true; - } - } - - // if displayRect is not outside the map edges, there is nothing to do - if(!view_outside_edges) - continue; - } - - assert(col_start >= 0); - assert(row_start >= 0); - assert(col_start <= col_end); - assert(row_start <= row_end); - - for(unsigned y = row_start; y < height - 1u && y <= static_cast(row_end); y++) - { - if(y % 2 == 0) - { - // first RightSideUp - tempP2 = myMap.getVertex(width - 1, y + 1); - tempP2.x = 0; - DrawTriangle(display, 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)); - // UpSideDown - DrawTriangle(display, 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), - 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)); - // UpSideDown - DrawTriangle(display, 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), - 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); - } - } - - // draw last line - for(unsigned x = col_start; x < width - 1u && x <= static_cast(col_end); x++) - { - // RightSideUp - tempP2 = myMap.getVertex(x, 0); - tempP2.y = height * 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); - // 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), - myMap.getVertex(x + 1, height - 1)); - } - } - - // last RightSideUp - tempP2 = myMap.getVertex(width - 1, 0); - tempP2.y += height * triangleHeight; - 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); - // 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); - } -} - -namespace { -enum class BorderPreference -{ - None, - LeftTop, - RightBottom -}; -BorderPreference CalcBorders(const bobMAP& map, Uint8 s2Id1, Uint8 s2Id2, SDL_Rect& borderRect) -{ - // we have to decide which border to blit, "left or right" or "top or bottom" - s2Id1 &= ~(0x40 | 0x80); - s2Id2 &= ~(0x40 | 0x80); - - assert(s2Id1 < map.s2IdToTerrain.size()); - assert(s2Id2 < map.s2IdToTerrain.size()); - - DescIdx idxTop = map.s2IdToTerrain[s2Id1]; - DescIdx idxBottom = map.s2IdToTerrain[s2Id2]; - if(idxTop == idxBottom) - return BorderPreference::None; - const TerrainDesc& t1 = global::worldDesc.get(idxTop); - const TerrainDesc& t2 = global::worldDesc.get(idxBottom); - if(t1.edgePriority > t2.edgePriority) - { - if(!t1.edgeType) - return BorderPreference::None; - borderRect = rect2SDL_Rect(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); - return BorderPreference::RightBottom; - } - return BorderPreference::None; -} - -template -constexpr bool isInRange(T val, T min, T max) -{ - return val >= min && val <= max; -} - -/// Return true if triangle is drawn -bool GetAdjustedPoints(const DisplayRectangle& displayRect, const bobMAP& myMap, Point32& p1, Point32& p2, Point32& p3) -{ - if((!isInRange(p1.x, displayRect.left, displayRect.right) && !isInRange(p2.x, displayRect.left, displayRect.right) - && !isInRange(p3.x, displayRect.left, displayRect.right)) - || (!isInRange(p1.y, displayRect.top, displayRect.bottom) - && !isInRange(p2.y, displayRect.top, displayRect.bottom) - && !isInRange(p3.y, displayRect.top, displayRect.bottom))) - { - bool triangle_shown = false; - - if(displayRect.left <= 0) - { - int outside_left = displayRect.left; - int outside_right = 0; - if(isInRange(p1.x - myMap.width_pixel, outside_left, outside_right) - || isInRange(p2.x - myMap.width_pixel, outside_left, outside_right) - || isInRange(p3.x - myMap.width_pixel, outside_left, outside_right)) - { - p1.x -= myMap.width_pixel; - p2.x -= myMap.width_pixel; - p3.x -= myMap.width_pixel; - triangle_shown = true; - } - } else if(displayRect.left < triangleWidth) - { - int outside_left = displayRect.left; - int outside_right = displayRect.left + triangleWidth; - if(isInRange(p1.x - myMap.width_pixel, outside_left, outside_right) - || isInRange(p2.x - myMap.width_pixel, outside_left, outside_right) - || isInRange(p3.x - myMap.width_pixel, outside_left, outside_right)) - { - p1.x -= myMap.width_pixel; - p2.x -= myMap.width_pixel; - p3.x -= myMap.width_pixel; - triangle_shown = true; - } - } else if(displayRect.right > myMap.width_pixel) - { - int outside_left = myMap.width_pixel; - int outside_right = displayRect.right; - if(isInRange(p1.x + myMap.width_pixel, outside_left, outside_right) - || isInRange(p2.x + myMap.width_pixel, outside_left, outside_right) - || isInRange(p3.x + myMap.width_pixel, outside_left, outside_right)) - { - p1.x += myMap.width_pixel; - p2.x += myMap.width_pixel; - p3.x += myMap.width_pixel; - triangle_shown = true; - } - } - - if(displayRect.top < 0) - { - int outside_top = displayRect.top; - int outside_bottom = 0; - if(isInRange(p1.y - myMap.height_pixel, outside_top, outside_bottom) - || isInRange(p2.y - myMap.height_pixel, outside_top, outside_bottom) - || isInRange(p3.y - myMap.height_pixel, outside_top, outside_bottom)) - { - p1.y -= myMap.height_pixel; - p2.y -= myMap.height_pixel; - p3.y -= myMap.height_pixel; - triangle_shown = true; - } - } else if(displayRect.bottom > myMap.height_pixel) - { - int outside_top = myMap.height_pixel; - int outside_bottom = displayRect.bottom; - if(isInRange(p1.y + myMap.height_pixel, outside_top, outside_bottom) - || isInRange(p2.y + myMap.height_pixel, outside_top, outside_bottom) - || isInRange(p3.y + myMap.height_pixel, outside_top, outside_bottom)) - { - p1.y += myMap.height_pixel; - p2.y += myMap.height_pixel; - p3.y += myMap.height_pixel; - triangle_shown = true; - } - } - - // now test if triangle has negative y-coords cause it's raised over the upper map edge - if(p1.y < 0 || p2.y < 0 || p3.y < 0) - { - if(isInRange(p1.y + myMap.height_pixel, displayRect.top, displayRect.bottom) - || isInRange(p2.y + myMap.height_pixel, displayRect.top, displayRect.bottom) - || isInRange(p3.y + myMap.height_pixel, displayRect.top, displayRect.bottom)) - { - p1.y += myMap.height_pixel; - p2.y += myMap.height_pixel; - p3.y += myMap.height_pixel; - triangle_shown = true; - } - } - - // now test if triangle has bigger y-coords as myMap.height_pixel cause it's reduced under the lower map edge - if(p1.y > myMap.height_pixel || p2.y > myMap.height_pixel || p3.y > myMap.height_pixel) - { - if(isInRange(p1.y - myMap.height_pixel, displayRect.top, displayRect.bottom) - || isInRange(p2.y - myMap.height_pixel, displayRect.top, displayRect.bottom) - || isInRange(p3.y - myMap.height_pixel, displayRect.top, displayRect.bottom)) - { - p1.y -= myMap.height_pixel; - p2.y -= myMap.height_pixel; - p3.y -= myMap.height_pixel; - triangle_shown = true; - } - } - - if(!triangle_shown) - return false; - } - p1 -= displayRect.getOrigin(); - p2 -= displayRect.getOrigin(); - p3 -= displayRect.getOrigin(); - return true; -} -} // 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) -{ - const auto animOffset = Point16(-texture_move, texture_move); - switch(texture) - { - // in case of USD-Triangle "upper.x" and "upper.y" means "lowerX" and "lowerY" - case TRIANGLE_TEXTURE_STEPPE_MEADOW1: - upper = Point16(17, 96); - left = Point16(0, 126); - right = Point16(35, 126); - break; - case TRIANGLE_TEXTURE_MINING1: - upper = Point16(17, 48); - left = Point16(0, 78); - right = Point16(35, 78); - break; - case TRIANGLE_TEXTURE_SNOW: - if(isRSU) - { - upper = Point16(17, 0); - left = Point16(0, 30); - right = Point16(35, 30); - } else - { - upper = Point16(17, 28); - left = Point16(0, 0); - right = Point16(37, 0); - } - if(mapType == MAP_WINTERLAND) - { - if(isRSU) - { - upper2 = Point16(231, 61) + animOffset; - left2 = Point16(207, 62) + animOffset; - right2 = Point16(223, 78) + animOffset; - } else - { - upper2 = Point16(224, 79) + animOffset; - left2 = Point16(232, 62) + animOffset; - right2 = Point16(245, 76) + animOffset; - } - } - break; - case TRIANGLE_TEXTURE_SWAMP: - upper = Point16(113, 0); - left = Point16(96, 30); - right = Point16(131, 30); - if(mapType == MAP_WINTERLAND) - { - if(isRSU) - { - upper2 = Point16(231, 61) + animOffset; - left2 = Point16(207, 62) + animOffset; - right2 = Point16(223, 78) + animOffset; - } else - { - upper2 = Point16(224, 79) + animOffset; - left2 = Point16(232, 62) + animOffset; - right2 = Point16(245, 76) + animOffset; - } - } - break; - case TRIANGLE_TEXTURE_STEPPE: - case TRIANGLE_TEXTURE_STEPPE_: - case TRIANGLE_TEXTURE_STEPPE__: - case TRIANGLE_TEXTURE_STEPPE___: - upper = Point16(65, 0); - left = Point16(48, 30); - right = Point16(83, 30); - break; - case TRIANGLE_TEXTURE_WATER: - case TRIANGLE_TEXTURE_WATER_: - case TRIANGLE_TEXTURE_WATER__: - if(isRSU) - { - upper = Point16(231, 61) + animOffset; - left = Point16(207, 62) + animOffset; - right = Point16(223, 78) + animOffset; - } else - { - upper = Point16(224, 79) + animOffset; - left = Point16(232, 62) + animOffset; - right = Point16(245, 76) + animOffset; - } - break; - case TRIANGLE_TEXTURE_MEADOW1: - upper = Point16(65, 96); - left = Point16(48, 126); - right = Point16(83, 126); - break; - case TRIANGLE_TEXTURE_MEADOW2: - upper = Point16(113, 96); - left = Point16(96, 126); - right = Point16(131, 126); - break; - case TRIANGLE_TEXTURE_MEADOW3: - upper = Point16(161, 96); - left = Point16(144, 126); - right = Point16(179, 126); - break; - case TRIANGLE_TEXTURE_MINING2: - upper = Point16(65, 48); - left = Point16(48, 78); - right = Point16(83, 78); - break; - case TRIANGLE_TEXTURE_MINING3: - upper = Point16(113, 48); - left = Point16(96, 78); - right = Point16(131, 78); - break; - case TRIANGLE_TEXTURE_MINING4: - upper = Point16(161, 48); - left = Point16(144, 78); - right = Point16(179, 78); - break; - case TRIANGLE_TEXTURE_STEPPE_MEADOW2: - upper = Point16(17, 144); - left = Point16(0, 174); - right = Point16(35, 174); - break; - case TRIANGLE_TEXTURE_FLOWER: - upper = Point16(161, 0); - left = Point16(144, 30); - right = Point16(179, 30); - break; - case TRIANGLE_TEXTURE_LAVA: - if(isRSU) - { - upper = Point16(231, 117) + animOffset; - left = Point16(207, 118) + animOffset; - right = Point16(223, 134) + animOffset; - } else - { - upper = Point16(224, 135) + animOffset; - left = Point16(232, 118) + animOffset; - right = Point16(245, 132) + animOffset; - } - break; - case TRIANGLE_TEXTURE_MINING_MEADOW: - upper = Point16(65, 144); - left = Point16(48, 174); - right = Point16(83, 174); - break; - default: // TRIANGLE_TEXTURE_FLOWER - upper = Point16(161, 0); - left = Point16(144, 30); - right = Point16(179, 30); - break; - } -} - -void CSurface::DrawTriangle(SDL_Surface* display, 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; - - // 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 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}; - 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(); - if(roundCount >= 7) - roundCount = 0; - else - roundCount++; - } - if(SDL_GetTicks() - roundTimeTextures > 170) - { - roundTimeTextures = SDL_GetTicks(); - texture_move++; - if(texture_move > 14) - texture_move = 0; - } - - SDL_Surface* Surf_Tileset; - 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; - } - - bool const isRSU = p1.y < p2.y; - - 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); - - // draw the triangle - // do not shade water and lava - if(texture == TRIANGLE_TEXTURE_WATER || texture == TRIANGLE_TEXTURE_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 - { - // 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()); - } 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); - } - } - return; - } - - // blit borders - /// PRIORITY FROM HIGH TO LOW: SNOW, MINING_MEADOW, STEPPE, STEPPE_MEADOW2, MINING, MEADOW, FLOWER, STEPPE_MEADOW1, - /// SWAMP, WATER, LAVA - if(global::s2->getMapObj()->getRenderBorders()) - { - // RSU-Triangle - if(isRSU) - { - // left upper / right lower edge - therefore get the usd-texture from left to compare - Uint16 col = (P1.VertexX - 1 < 0 ? myMap.width - 1 : P1.VertexX - 1); - MapNode tempP = myMap.getVertex(col, P1.VertexY); - - SDL_Rect BorderRect; - auto borderSide = CalcBorders(myMap, tempP.usdTexture, P1.rsuTexture, BorderRect); - if(borderSide != BorderPreference::None) - { - Point16 tmpP1{p1}, tmpP2{p2}; - Point32 thirdPt; - if(borderSide == BorderPreference::LeftTop) - thirdPt = p3; - else - { - tmpP1 += Point16(1, 0); - tmpP2 += Point16(1, 0); - thirdPt = Point32(tempP.x, tempP.y) - displayRect.getOrigin(); - // Shift it close to p1 - auto diff = thirdPt - p1; - if(diff.x < -myMap.width_pixel / 2) - thirdPt.x += myMap.width_pixel; - else if(diff.x > myMap.width_pixel / 2) - thirdPt.x -= myMap.width_pixel; - if(diff.y < -myMap.height_pixel / 2) - thirdPt.y += myMap.height_pixel; - else if(diff.y > myMap.height_pixel / 2) - thirdPt.y -= myMap.height_pixel; - } - Point16 tipPt{(p1 + p2 + thirdPt) / 3}; - - 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); - } - } - // USD-Triangle - else - { - SDL_Rect BorderRect; - // left lower / right upper - auto borderSide = CalcBorders(myMap, P2.rsuTexture, P2.usdTexture, BorderRect); - - if(borderSide != BorderPreference::None) - { - Uint16 col = (P1.VertexX - 1 < 0 ? myMap.width - 1 : P1.VertexX - 1); - MapNode tempP = myMap.getVertex(col, P1.VertexY); - - Point16 tmpP1{p1}, tmpP2{p2}; - Point32 thirdPt; - if(borderSide == BorderPreference::LeftTop) - { - thirdPt = p3; - tmpP1 -= Point16(1, 0); - tmpP2 -= Point16(1, 0); - } else - { - thirdPt = Point32(tempP.x, tempP.y) - displayRect.getOrigin(); - // Shift it close to p1 - auto diff = thirdPt - p1; - if(diff.x < -myMap.width_pixel / 2) - thirdPt.x += myMap.width_pixel; - else if(diff.x > myMap.width_pixel / 2) - thirdPt.x -= myMap.width_pixel; - if(diff.y < -myMap.height_pixel / 2) - thirdPt.y += myMap.height_pixel; - else if(diff.y > myMap.height_pixel / 2) - thirdPt.y -= myMap.height_pixel; - } - - Point16 tipPt{(p1 + p2 + thirdPt) / 3}; - - 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); - } - - // top / bottom - therefore get the rsu-texture one line above to compare - Uint16 row = (P2.VertexY - 1 < 0 ? myMap.height - 1 : P2.VertexY - 1); - Uint16 col = (P2.VertexY % 2 == 0 ? P2.VertexX : (P2.VertexX + 1 > myMap.width - 1 ? 0 : P2.VertexX + 1)); - MapNode tempP = myMap.getVertex(col, row); - - borderSide = CalcBorders(myMap, tempP.rsuTexture, P2.usdTexture, BorderRect); - if(borderSide != BorderPreference::None) - { - Point32 thirdPt; - if(borderSide == BorderPreference::LeftTop) - thirdPt = p1; - else - { - thirdPt = Point32(tempP.x, tempP.y) - displayRect.getOrigin(); - // Shift it close to p2 - auto diff = thirdPt - p2; - if(diff.x < -myMap.width_pixel / 2) - thirdPt.x += myMap.width_pixel; - else if(diff.x > myMap.width_pixel / 2) - thirdPt.x -= myMap.width_pixel; - if(diff.y < -myMap.height_pixel / 2) - thirdPt.y += myMap.height_pixel; - else if(diff.y > myMap.height_pixel / 2) - thirdPt.y -= myMap.height_pixel; - } - Point16 tipPt{(p2 + p3 + thirdPt) / 3}; - - 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); - } - } - } - - // blit picture to vertex (trees, animals, buildings and so on) --> BUT ONLY AT node1 ON RIGHTSIDEUP-TRIANGLES - - // blit objects - if(!isRSU) - { - int objIdx = 0; - switch(P2.objectInfo) - { - // tree - case 0xC4: - if(P2.objectType >= 0x30 && P2.objectType <= 0x37) - { - if(P2.objectType + roundCount > 0x37) - objIdx = MAPPIC_TREE_PINE + (P2.objectType - 0x30) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_PINE + (P2.objectType - 0x30) + roundCount; - - } else if(P2.objectType >= 0x70 && P2.objectType <= 0x77) - { - if(P2.objectType + roundCount > 0x77) - objIdx = MAPPIC_TREE_BIRCH + (P2.objectType - 0x70) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_BIRCH + (P2.objectType - 0x70) + roundCount; - } else if(P2.objectType >= 0xB0 && P2.objectType <= 0xB7) - { - if(P2.objectType + roundCount > 0xB7) - objIdx = MAPPIC_TREE_OAK + (P2.objectType - 0xB0) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_OAK + (P2.objectType - 0xB0) + roundCount; - } else if(P2.objectType >= 0xF0 && P2.objectType <= 0xF7) - { - if(P2.objectType + roundCount > 0xF7) - objIdx = MAPPIC_TREE_PALM1 + (P2.objectType - 0xF0) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_PALM1 + (P2.objectType - 0xF0) + roundCount; - } - break; - // tree - case 0xC5: - if(P2.objectType >= 0x30 && P2.objectType <= 0x37) - { - if(P2.objectType + roundCount > 0x37) - objIdx = MAPPIC_TREE_PALM2 + (P2.objectType - 0x30) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_PALM2 + (P2.objectType - 0x30) + roundCount; - - } else if(P2.objectType >= 0x70 && P2.objectType <= 0x77) - { - if(P2.objectType + roundCount > 0x77) - objIdx = MAPPIC_TREE_PINEAPPLE + (P2.objectType - 0x70) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_PINEAPPLE + (P2.objectType - 0x70) + roundCount; - } else if(P2.objectType >= 0xB0 && P2.objectType <= 0xB7) - { - if(P2.objectType + roundCount > 0xB7) - objIdx = MAPPIC_TREE_CYPRESS + (P2.objectType - 0xB0) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_CYPRESS + (P2.objectType - 0xB0) + roundCount; - } else if(P2.objectType >= 0xF0 && P2.objectType <= 0xF7) - { - if(P2.objectType + roundCount > 0xF7) - objIdx = MAPPIC_TREE_CHERRY + (P2.objectType - 0xF0) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_CHERRY + (P2.objectType - 0xF0) + roundCount; - } - break; - // tree - case 0xC6: - if(P2.objectType >= 0x30 && P2.objectType <= 0x37) - { - if(P2.objectType + roundCount > 0x37) - objIdx = MAPPIC_TREE_FIR + (P2.objectType - 0x30) + (roundCount - 7); - else - objIdx = MAPPIC_TREE_FIR + (P2.objectType - 0x30) + roundCount; - } - break; - // landscape - case 0xC8: - switch(P2.objectType) - { - case 0x00: objIdx = MAPPIC_MUSHROOM1; break; - case 0x01: objIdx = MAPPIC_MUSHROOM2; break; - case 0x02: objIdx = MAPPIC_STONE1; break; - case 0x03: objIdx = MAPPIC_STONE2; break; - case 0x04: objIdx = MAPPIC_STONE3; break; - case 0x05: objIdx = MAPPIC_TREE_TRUNK_DEAD; break; - case 0x06: objIdx = MAPPIC_TREE_DEAD; break; - case 0x07: objIdx = MAPPIC_BONE1; break; - case 0x08: objIdx = MAPPIC_BONE2; break; - case 0x09: objIdx = MAPPIC_FLOWERS; break; - case 0x10: objIdx = MAPPIC_BUSH2; break; - case 0x11: objIdx = MAPPIC_BUSH3; break; - case 0x12: objIdx = MAPPIC_BUSH4; break; - - case 0x0A: objIdx = MAPPIC_BUSH1; break; - - case 0x0C: objIdx = MAPPIC_CACTUS1; break; - case 0x0D: objIdx = MAPPIC_CACTUS2; break; - case 0x0E: objIdx = MAPPIC_SHRUB1; break; - case 0x0F: objIdx = MAPPIC_SHRUB2; break; - - case 0x13: objIdx = MAPPIC_SHRUB3; break; - case 0x14: objIdx = MAPPIC_SHRUB4; break; - - case 0x16: objIdx = MAPPIC_DOOR; break; - - case 0x18: 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 0x22: objIdx = MAPPIC_MUSHROOM3; break; - - case 0x25: objIdx = MAPPIC_PEBBLE1; break; - case 0x26: objIdx = MAPPIC_PEBBLE2; break; - case 0x27: objIdx = MAPPIC_PEBBLE3; break; - default: break; - } - break; - // stone - case 0xCC: objIdx = MAPPIC_GRANITE_1_1 + (P2.objectType - 0x01); break; - // stone - case 0xCD: objIdx = MAPPIC_GRANITE_2_1 + (P2.objectType - 0x01); break; - // headquarter - case 0x80: // node2.objectType is the number of the player beginning with 0x00 - //%7 cause in the original game there are only 7 players and 7 different flags - 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)); - } - - // blit resources - if(!isRSU) - { - 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)))); - } 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)))); - } - 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)))); - } - 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)))); - } - // 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)); - } - } - - // blit buildings - if(global::s2->getMapObj()->getRenderBuildHelp()) - { - if(!isRSU) - { - 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 0x04: - if(P2.rsuTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1_HARBOUR - || P2.rsuTexture == TRIANGLE_TEXTURE_MEADOW1_HARBOUR - || P2.rsuTexture == TRIANGLE_TEXTURE_MEADOW2_HARBOUR - || P2.rsuTexture == TRIANGLE_TEXTURE_MEADOW3_HARBOUR - || P2.rsuTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW2_HARBOUR - || P2.rsuTexture == TRIANGLE_TEXTURE_FLOWER_HARBOUR - || P2.rsuTexture == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR) - 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)); - 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)); - break; - default: break; - } - } - } -} - void CSurface::get_nodeVectors(bobMAP& myMap) { // prepare triangle field diff --git a/CSurface.h b/CSurface.h index accdbbd..e8c3409 100644 --- a/CSurface.h +++ b/CSurface.h @@ -19,6 +19,9 @@ class CSurface // 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); + // Convert an 8-bit paletted surface to 32-bit RGBA, using the colorkey + // (if any) as alpha=0. Non-colorkey pixels become fully opaque. + static SdlSurface ConvertToRgba(SDL_Surface* src); 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) @@ -39,17 +42,11 @@ class CSurface } static void DrawPixel_RGBA(SDL_Surface* screen, int x, int y, Uint8 R, Uint8 G, Uint8 B, Uint8 A); static Uint32 GetPixel(SDL_Surface* surface, int x, int y); - 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); static void get_nodeVectors(bobMAP& myMap); static void update_shading(bobMAP& myMap, int VertexX, int VertexY); private: - // to decide what to draw, triangle-textures or objects and texture-borders - static bool drawTextures; - static vector get_nodeVector(const vector& v1, const vector& v2, const vector& v3); static vector get_normVector(const vector& v); static vector get_flatVector(const IntVector& P1, const IntVector& P2, const IntVector& P3); @@ -59,7 +56,4 @@ class CSurface static void update_flatVectors(bobMAP& myMap, int VertexX, int VertexY); // update nodeVector based on new flatVectors around it static void update_nodeVector(bobMAP& myMap, int VertexX, int VertexY); - 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/CSurfaceGL.cpp b/CSurfaceGL.cpp new file mode 100644 index 0000000..ced859f --- /dev/null +++ b/CSurfaceGL.cpp @@ -0,0 +1,211 @@ +// Copyright (C) 2025 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "CSurfaceGL.h" +#include "Rect.h" +#include "TerrainRenderer.h" +#include "ogl/VBO.h" +#include "ogl/constants.h" +#include +#include +#include +#include + +namespace { + +// --------------------------------------------------------------------------- +bool isArgb32Format(const SDL_PixelFormat* fmt) +{ + return fmt->BitsPerPixel == 32 && fmt->Rmask == 0xFF0000 && fmt->Gmask == 0xFF00 && fmt->Bmask == 0xFF + && fmt->BytesPerPixel == 4; +} + +// =========================================================================== +// Texture cache (SDL_Surface -> GL texture) +// =========================================================================== + +static std::unordered_map s_texCache; + +} // anonymous namespace + +// =========================================================================== +// EditorGLTexture +// =========================================================================== + +bool EditorGLTexture::convertSurface(SDL_Surface* surface) +{ + int w = surface->w, h = surface->h, needed = w * h; + if(int(pixelBuffer_.size()) != needed) + pixelBuffer_.assign(needed, 0); + Uint32 ck; + bool hasCK = (SDL_GetColorKey(surface, &ck) == 0); + + if(isArgb32Format(surface->format) && !hasCK) + { + auto* src = (const uint32_t*)surface->pixels; + auto* dst = pixelBuffer_.data(); + for(int i = 0; i < needed; i++) + { + uint32_t p = src[i]; + dst[i] = p ? (p | 0xFF000000) : 0; + } + return true; + } + + if(surface->format->BitsPerPixel == 8) + { + SDL_Palette* pal = surface->format->palette; + if(!pal) + return false; + for(int y = 0; y < h; y++) + { + auto* src = (const uint8_t*)((const uint8_t*)surface->pixels + y * surface->pitch); + for(int x = 0; x < w; x++) + { + uint8_t idx = src[x]; + if(hasCK && idx == (ck & 0xFF)) + { + pixelBuffer_[y * w + x] = 0; + continue; + } + SDL_Color c = pal->colors[idx]; + pixelBuffer_[y * w + x] = (0xFF << 24) | (c.r << 16) | (c.g << 8) | c.b; + } + } + } else + { + SDL_PixelFormat* fmt = surface->format; + for(int y = 0; y < h; y++) + { + auto* src = (const uint32_t*)((const uint8_t*)surface->pixels + y * surface->pitch); + for(int x = 0; x < w; x++) + { + uint32_t p = src[x]; + if(hasCK && p == ck) + { + pixelBuffer_[y * w + x] = 0; + continue; + } + Uint8 r, g, b, a; + SDL_GetRGBA(p, fmt, &r, &g, &b, &a); + pixelBuffer_[y * w + x] = (0xFF << 24) | (r << 16) | (g << 8) | b; + } + } + } + return true; +} + +bool EditorGLTexture::createFromSurface(SDL_Surface* s) +{ + destroy(); + if(!s) + return false; + width_ = s->w; + height_ = s->h; + if(!convertSurface(s)) + return false; + texWidth_ = width_; + texHeight_ = height_; + glGenTextures(1, &texture_); + if(!texture_) + return false; + glBindTexture(GL_TEXTURE_2D, texture_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth_, texHeight_, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixelBuffer_.data()); + return true; +} + +bool EditorGLTexture::updateFromSurface(SDL_Surface* s) +{ + if(!texture_ || !s || s->w != width_ || s->h != height_) + return false; + Uint32 ck; + bool hasCK = (SDL_GetColorKey(s, &ck) == 0); + + if(isArgb32Format(s->format) && !hasCK) + { + glBindTexture(GL_TEXTURE_2D, texture_); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, s->pixels); + return true; + } + if(!convertSurface(s)) + return false; + glBindTexture(GL_TEXTURE_2D, texture_); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, pixelBuffer_.data()); + return true; +} + +void EditorGLTexture::destroy() +{ + if(texture_) + { + glDeleteTextures(1, &texture_); + texture_ = 0; + } + pixelBuffer_.clear(); + pixelBuffer_.shrink_to_fit(); +} + +void EditorGLTexture::draw(int x, int y) const +{ + if(!texture_) + return; + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, texture_); + GLfloat v[8] = {GLfloat(x), GLfloat(y), GLfloat(x), GLfloat(y + height_), + GLfloat(x + width_), GLfloat(y + height_), GLfloat(x + width_), GLfloat(y)}; + float u2 = float(width_) / texWidth_, v2 = float(height_) / texHeight_; + GLfloat tc[8] = {0, 0, 0, v2, u2, v2, u2, 0}; + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, v); + glTexCoordPointer(2, GL_FLOAT, 0, tc); + glDrawArrays(GL_QUADS, 0, 4); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); +} + +// =========================================================================== +// CSurfaceGL namespace +// =========================================================================== + +namespace CSurfaceGL { + +void init(int screenWidth, int screenHeight) +{ + // Permanent GL state (s25client does this in VideoDriverWrapper.cpp). + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glClearColor(0, 0, 0, 1); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, screenWidth, screenHeight, 0, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +const EditorGLTexture& getOrCreateTexture(SDL_Surface* s) +{ + auto it = s_texCache.find(s); + if(it == s_texCache.end()) + { + EditorGLTexture t; + if(t.createFromSurface(s)) + it = s_texCache.emplace(s, std::move(t)).first; + else + { + static EditorGLTexture e; + return e; + } + } + return it->second; +} + +} // namespace CSurfaceGL diff --git a/CSurfaceGL.h b/CSurfaceGL.h new file mode 100644 index 0000000..e189c2a --- /dev/null +++ b/CSurfaceGL.h @@ -0,0 +1,82 @@ +// Copyright (C) 2025 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "Point.h" +#include "Rect.h" +#include "defines.h" +#include +#include +#include +#include +#include +#include + +class EditorGLTexture +{ +public: + EditorGLTexture() : texture_(0), width_(0), height_(0), texWidth_(0), texHeight_(0) {} + ~EditorGLTexture() { destroy(); } + + EditorGLTexture(const EditorGLTexture&) = delete; + EditorGLTexture& operator=(const EditorGLTexture&) = delete; + + EditorGLTexture(EditorGLTexture&& other) noexcept + : texture_(other.texture_), width_(other.width_), height_(other.height_), texWidth_(other.texWidth_), + texHeight_(other.texHeight_) + { + other.texture_ = 0; + } + + EditorGLTexture& operator=(EditorGLTexture&& other) noexcept + { + if(this != &other) + { + destroy(); + texture_ = other.texture_; + width_ = other.width_; + height_ = other.height_; + texWidth_ = other.texWidth_; + texHeight_ = other.texHeight_; + other.texture_ = 0; + } + return *this; + } + + bool createFromSurface(SDL_Surface* surface); + bool updateFromSurface(SDL_Surface* surface); + void destroy(); + + void draw(int dstX, int dstY) const; + + bool valid() const { return texture_ != 0; } + GLuint texture() const { return texture_; } + int width() const { return width_; } + int height() const { return height_; } + int texWidth() const { return texWidth_; } + int texHeight() const { return texHeight_; } + +private: + bool convertSurface(SDL_Surface* surface); + + GLuint texture_; + int width_; + int height_; + int texWidth_; + int texHeight_; + std::vector pixelBuffer_; +}; + +namespace CSurfaceGL { + +/// Initialise OpenGL state (viewport, blending, etc.) with the given +/// screen resolution for the default orthographic projection. +/// Call once after GL context creation. +void init(int screenWidth, int screenHeight); + +/// Get-or-create a cached GL texture for an SDL surface. +const EditorGLTexture& getOrCreateTexture(SDL_Surface* surface); + +} // namespace CSurfaceGL diff --git a/GEOMETRY.md b/GEOMETRY.md new file mode 100644 index 0000000..f0f3187 --- /dev/null +++ b/GEOMETRY.md @@ -0,0 +1,110 @@ + + +# Map geometry alignment with s25client + +The editor and `s25client` render the same staggered hexagonal grid, but the +indexing of **USD (up-side-down) triangles differs by one vertex in even rows**. +This document describes the mapping so that border / coastline generation can +be aligned with `libs/s25main/TerrainRenderer.cpp` while still using the +editor's `bobMAP` data. + +## Vertex neighbour rules + +For a vertex `pt = (x, y)` the neighbours used by `s25client` are: + +| direction | even row (`y % 2 == 0`) | odd row (`y % 2 != 0`) | +|-----------|------------------------|------------------------| +| East | `(x + 1, y)` | `(x + 1, y)` | +| SouthEast | `(x, y + 1)` | `(x + 1, y + 1)` | +| SouthWest | `(x - 1, y + 1)` | `(x, y + 1)` | + +These are exactly the definitions from `s25client::GetNeighbour`. + +## Triangle ownership + +*`s25client` naming:* + +- **RSU** at `(x, y)`: vertices `[pt, SW(pt), SE(pt)]` — points down. +- **USD** at `(x, y)`: vertices `[pt, SE(pt), E(pt)]` — points up. + +*Editor naming (`bobMAP` / `CSurface::DrawTriangle`):* + +- **RSU at `(x, y)`** uses the same three vertices as `s25client`, so the two + agree completely. +- **USD at `(x, y)`** is shifted: + - even `y`: editor USD `(x, y)` == `s25client` USD `(x - 1, y)` + - odd `y`: editor USD `(x, y)` == `s25client` USD `(x, y)` + +In compact form: + +```text +editor USD(x, y) = s25client USD(x - !(y & 1), y) +s25client USD(x, y) = editor USD(x + !(y & 1), y) +``` + +## Texture lookups + +Because of the USD shift, the texture attached to a rendered USD triangle is +fetched from a different `MapNode` index in the editor than in `s25client`: + +- editor cached USD at `(x, y)` uses `map.getVertex(x - !(y & 1), y).usdTexture` +- `s25client` USD at `(x, y)` uses `map.getVertex(x, y).usdTexture` + +For borders we therefore use `s25client`'s conceptual triangle grid but read +the editor's raw `MapNode` textures at the `s25client` vertex coordinates. +This keeps the coastline consistent with the terrain actually rendered by the +editor. + +## Border generation mapping + +`s25client::TerrainRenderer::GenerateOpenGL` decides per vertex `(x, y)` which +of six possible border triangles exist, using the four terrain samples: + +```text +t1 = RSU(x, y) +t2 = USD(x, y) +t3 = RSU(x + 1, y) +t4 = USD(SW(x, y)) = USD(x - !(y & 1), y + 1) +``` + +Mapped to the editor's `bobMAP`: + +```text +t1 = map.getVertex(x, y).rsuTexture +t2 = map.getVertex(x, y).usdTexture +t3 = map.getVertex(x + 1, y).rsuTexture +t4 = map.getVertex(x - !(y&1), y + 1).usdTexture +``` + +The six border triangles (vertex positions and winding) are exactly those +from `s25client::TerrainRenderer::UpdateBorderTrianglePos`: + +| border | condition | vertices | +|--------------------------------|----------------------------|--------------------------------------------| +| `left_right[0]` (USD over RSU) | `GetEdgeType(t2, t1)` | `[pt, SE(pt), centroid(RSU(x, y))]` | +| `left_right[1]` (RSU over USD) | `GetEdgeType(t1, t2)` | `[centroid(USD(x, y)), SE(pt), pt]` | +| `right_left[0]` (RSU(E) over USD) | `GetEdgeType(t3, t2)` | `[SE(pt), E(pt), centroid(USD(x, y))]` | +| `right_left[1]` (USD over RSU(E)) | `GetEdgeType(t2, t3)` | `[centroid(RSU(x+1, y)), E(pt), SE(pt)]` | +| `top_down[0]` (USD(SW) over RSU) | `GetEdgeType(t4, t1)` | `[SW(pt), SE(pt), centroid(RSU(x, y))]` | +| `top_down[1]` (RSU over USD(SW)) | `GetEdgeType(t1, t4)` | `[centroid(USD(SW)), SE(pt), SW(pt)]` | + +`centroid(RSU(x, y)) = (SW + pt + SE) / 3` +`centroid(USD(x, y)) = (E + pt + SE) / 3` + +Pixel positions are taken from `MapNode::x / y` and wrapped to stay adjacent to +the reference vertex, matching the wrap handling already used for terrain +vertices. + +## Water animation + +The editor animates water/lava by shifting texture coordinates in the +static/dynamic texcoord VBO, because the editor does not have the multiple +animated texture frames that `s25client` uses for palette-animated terrains. +The texcoord buffer is updated every animation frame, so it should be created +with `ogl::Usage::Dynamic` to match the old editor behaviour and avoid +implicit synchronisation stalls. diff --git a/GameWorldView.cpp b/GameWorldView.cpp new file mode 100644 index 0000000..2b18a0e --- /dev/null +++ b/GameWorldView.cpp @@ -0,0 +1,282 @@ +// Copyright (C) 2009 - 2025 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "GameWorldView.h" +#include "CGame.h" +#include "CMap.h" +#include "CSurface.h" +#include "TerrainRenderer.h" +#include "defines.h" +#include "globals.h" + +namespace EditorWorldView { + +static void drawVertexOverlay(SDL_Surface* target, int screenX, int screenY, const MapNode& node) +{ + int objIdx = 0; + switch(node.objectInfo) + { + // tree + case 0xC4: + if(node.objectType >= 0x30 && node.objectType <= 0x37) + { + if(node.objectType + TerrainRenderer::roundCount() > 0x37) + objIdx = MAPPIC_TREE_PINE + (node.objectType - 0x30) + (TerrainRenderer::roundCount() - 7); + else + objIdx = MAPPIC_TREE_PINE + (node.objectType - 0x30) + TerrainRenderer::roundCount(); + + } else if(node.objectType >= 0x70 && node.objectType <= 0x77) + { + if(node.objectType + TerrainRenderer::roundCount() > 0x77) + objIdx = MAPPIC_TREE_BIRCH + (node.objectType - 0x70) + (TerrainRenderer::roundCount() - 7); + else + objIdx = MAPPIC_TREE_BIRCH + (node.objectType - 0x70) + TerrainRenderer::roundCount(); + } else if(node.objectType >= 0xB0 && node.objectType <= 0xB7) + { + if(node.objectType + TerrainRenderer::roundCount() > 0xB7) + objIdx = MAPPIC_TREE_OAK + (node.objectType - 0xB0) + (TerrainRenderer::roundCount() - 7); + else + objIdx = MAPPIC_TREE_OAK + (node.objectType - 0xB0) + TerrainRenderer::roundCount(); + } else if(node.objectType >= 0xF0 && node.objectType <= 0xF7) + { + if(node.objectType + TerrainRenderer::roundCount() > 0xF7) + objIdx = MAPPIC_TREE_PALM1 + (node.objectType - 0xF0) + (TerrainRenderer::roundCount() - 7); + else + objIdx = MAPPIC_TREE_PALM1 + (node.objectType - 0xF0) + TerrainRenderer::roundCount(); + } + break; + // tree + case 0xC5: + if(node.objectType >= 0x30 && node.objectType <= 0x37) + { + if(node.objectType + TerrainRenderer::roundCount() > 0x37) + objIdx = MAPPIC_TREE_PALM2 + (node.objectType - 0x30) + (TerrainRenderer::roundCount() - 7); + else + objIdx = MAPPIC_TREE_PALM2 + (node.objectType - 0x30) + TerrainRenderer::roundCount(); + + } else if(node.objectType >= 0x70 && node.objectType <= 0x77) + { + if(node.objectType + TerrainRenderer::roundCount() > 0x77) + objIdx = MAPPIC_TREE_PINEAPPLE + (node.objectType - 0x70) + (TerrainRenderer::roundCount() - 7); + else + objIdx = MAPPIC_TREE_PINEAPPLE + (node.objectType - 0x70) + TerrainRenderer::roundCount(); + } else if(node.objectType >= 0xB0 && node.objectType <= 0xB7) + { + if(node.objectType + TerrainRenderer::roundCount() > 0xB7) + objIdx = MAPPIC_TREE_CYPRESS + (node.objectType - 0xB0) + (TerrainRenderer::roundCount() - 7); + else + objIdx = MAPPIC_TREE_CYPRESS + (node.objectType - 0xB0) + TerrainRenderer::roundCount(); + } else if(node.objectType >= 0xF0 && node.objectType <= 0xF7) + { + if(node.objectType + TerrainRenderer::roundCount() > 0xF7) + objIdx = MAPPIC_TREE_CHERRY + (node.objectType - 0xF0) + (TerrainRenderer::roundCount() - 7); + else + objIdx = MAPPIC_TREE_CHERRY + (node.objectType - 0xF0) + TerrainRenderer::roundCount(); + } + break; + // tree + case 0xC6: + if(node.objectType >= 0x30 && node.objectType <= 0x37) + { + if(node.objectType + TerrainRenderer::roundCount() > 0x37) + objIdx = MAPPIC_TREE_FIR + (node.objectType - 0x30) + (TerrainRenderer::roundCount() - 7); + else + objIdx = MAPPIC_TREE_FIR + (node.objectType - 0x30) + TerrainRenderer::roundCount(); + } + break; + // landscape + case 0xC8: + switch(node.objectType) + { + case 0x00: objIdx = MAPPIC_MUSHROOM1; break; + case 0x01: objIdx = MAPPIC_MUSHROOM2; break; + case 0x02: objIdx = MAPPIC_STONE1; break; + case 0x03: objIdx = MAPPIC_STONE2; break; + case 0x04: objIdx = MAPPIC_STONE3; break; + case 0x05: objIdx = MAPPIC_TREE_TRUNK_DEAD; break; + case 0x06: objIdx = MAPPIC_TREE_DEAD; break; + case 0x07: objIdx = MAPPIC_BONE1; break; + case 0x08: objIdx = MAPPIC_BONE2; break; + case 0x09: objIdx = MAPPIC_FLOWERS; break; + case 0x10: objIdx = MAPPIC_BUSH2; break; + case 0x11: objIdx = MAPPIC_BUSH3; break; + case 0x12: objIdx = MAPPIC_BUSH4; break; + + case 0x0A: objIdx = MAPPIC_BUSH1; break; + + case 0x0C: objIdx = MAPPIC_CACTUS1; break; + case 0x0D: objIdx = MAPPIC_CACTUS2; break; + case 0x0E: objIdx = MAPPIC_SHRUB1; break; + case 0x0F: objIdx = MAPPIC_SHRUB2; break; + + case 0x13: objIdx = MAPPIC_SHRUB3; break; + case 0x14: objIdx = MAPPIC_SHRUB4; break; + + case 0x16: objIdx = MAPPIC_DOOR; break; + + case 0x18: 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 0x22: objIdx = MAPPIC_MUSHROOM3; break; + + case 0x25: objIdx = MAPPIC_PEBBLE1; break; + case 0x26: objIdx = MAPPIC_PEBBLE2; break; + case 0x27: objIdx = MAPPIC_PEBBLE3; break; + default: break; + } + break; + // stone + case 0xCC: objIdx = MAPPIC_GRANITE_1_1 + (node.objectType - 0x01); break; + // stone + case 0xCD: objIdx = MAPPIC_GRANITE_2_1 + (node.objectType - 0x01); break; + // headquarter + case 0x80: // node.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 + node.objectType % 7; + break; + + default: break; + } + if(objIdx != 0) + CSurface::Draw(target, global::bmpArray[objIdx].surface, screenX - global::bmpArray[objIdx].nx, + screenY - global::bmpArray[objIdx].ny); + + // resources + if(node.resource >= 0x41 && node.resource <= 0x47) + { + for(char i = 0x41; i <= node.resource; i++) + CSurface::Draw(target, global::bmpArray[PICTURE_RESOURCE_COAL].surface, + screenX - global::bmpArray[PICTURE_RESOURCE_COAL].nx, + screenY - global::bmpArray[PICTURE_RESOURCE_COAL].ny - (4 * (i - 0x40))); + } else if(node.resource >= 0x49 && node.resource <= 0x4F) + { + for(char i = 0x49; i <= node.resource; i++) + CSurface::Draw(target, global::bmpArray[PICTURE_RESOURCE_ORE].surface, + screenX - global::bmpArray[PICTURE_RESOURCE_ORE].nx, + screenY - global::bmpArray[PICTURE_RESOURCE_ORE].ny - (4 * (i - 0x48))); + } + if(node.resource >= 0x51 && node.resource <= 0x57) + { + for(char i = 0x51; i <= node.resource; i++) + CSurface::Draw(target, global::bmpArray[PICTURE_RESOURCE_GOLD].surface, + screenX - global::bmpArray[PICTURE_RESOURCE_GOLD].nx, + screenY - global::bmpArray[PICTURE_RESOURCE_GOLD].ny - (4 * (i - 0x50))); + } + if(node.resource >= 0x59 && node.resource <= 0x5F) + { + for(char i = 0x59; i <= node.resource; i++) + CSurface::Draw(target, global::bmpArray[PICTURE_RESOURCE_GRANITE].surface, + screenX - global::bmpArray[PICTURE_RESOURCE_GRANITE].nx, + screenY - global::bmpArray[PICTURE_RESOURCE_GRANITE].ny - (4 * (i - 0x58))); + } + + // animals + if(node.animal > 0x00 && node.animal <= 0x06) + { + CSurface::Draw(target, global::bmpArray[PICTURE_SMALL_BEAR + node.animal].surface, + screenX - global::bmpArray[PICTURE_SMALL_BEAR + node.animal].nx, + screenY - global::bmpArray[PICTURE_SMALL_BEAR + node.animal].ny); + } + + // buildings (editor build-help preview) + if(global::s2 && global::s2->getMapObj() && global::s2->getMapObj()->getRenderBuildHelp()) + { + switch(node.build % 8) + { + case 0x01: + CSurface::Draw(target, global::bmpArray[MAPPIC_FLAG].surface, + screenX - global::bmpArray[MAPPIC_FLAG].nx, screenY - global::bmpArray[MAPPIC_FLAG].ny); + break; + case 0x02: + CSurface::Draw(target, global::bmpArray[MAPPIC_HOUSE_SMALL].surface, + screenX - global::bmpArray[MAPPIC_HOUSE_SMALL].nx, + screenY - global::bmpArray[MAPPIC_HOUSE_SMALL].ny); + break; + case 0x03: + CSurface::Draw(target, global::bmpArray[MAPPIC_HOUSE_MIDDLE].surface, + screenX - global::bmpArray[MAPPIC_HOUSE_MIDDLE].nx, + screenY - global::bmpArray[MAPPIC_HOUSE_MIDDLE].ny); + break; + case 0x04: + if(node.rsuTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1_HARBOUR + || node.rsuTexture == TRIANGLE_TEXTURE_MEADOW1_HARBOUR + || node.rsuTexture == TRIANGLE_TEXTURE_MEADOW2_HARBOUR + || node.rsuTexture == TRIANGLE_TEXTURE_MEADOW3_HARBOUR + || node.rsuTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW2_HARBOUR + || node.rsuTexture == TRIANGLE_TEXTURE_FLOWER_HARBOUR + || node.rsuTexture == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR) + CSurface::Draw(target, global::bmpArray[MAPPIC_HOUSE_HARBOUR].surface, + screenX - global::bmpArray[MAPPIC_HOUSE_HARBOUR].nx, + screenY - global::bmpArray[MAPPIC_HOUSE_HARBOUR].ny); + else + CSurface::Draw(target, global::bmpArray[MAPPIC_HOUSE_BIG].surface, + screenX - global::bmpArray[MAPPIC_HOUSE_BIG].nx, + screenY - global::bmpArray[MAPPIC_HOUSE_BIG].ny); + break; + case 0x05: + CSurface::Draw(target, global::bmpArray[MAPPIC_MINE].surface, + screenX - global::bmpArray[MAPPIC_MINE].nx, screenY - global::bmpArray[MAPPIC_MINE].ny); + break; + default: break; + } + } +} + +void Draw(SDL_Surface* target, const DisplayRectangle& viewRect, const bobMAP& map) +{ + const int width = map.width; + const int height = map.height; + const int width_pixel = map.width_pixel; + const int height_pixel = map.height_pixel; + + // Floor division for possibly negative view coordinates. + auto floorDiv = [](int a, int b) { return (a >= 0) ? a / b : (a - b + 1) / b; }; + + // Map-coordinate range that can possibly be visible, with the same margin + // the old triangle loop used. + const int firstX = floorDiv(viewRect.left, triangleWidth) - 1; + const int lastX = floorDiv(viewRect.right, triangleWidth) + 1; + const int firstY = floorDiv(viewRect.top, triangleHeight) - 2; + const int lastY = floorDiv(viewRect.bottom, triangleHeight) + 2; + + // Allow sprites that extend a bit outside the view rectangle. + const int marginX = triangleWidth * 4; + const int marginY = triangleHeight * 4; + const int surfW = viewRect.getSize().x; + const int surfH = viewRect.getSize().y; + + for(int y = firstY; y <= lastY; ++y) + { + for(int x = firstX; x <= lastX; ++x) + { + // Wrap to canonical map coordinates. + int wx = x % width; + if(wx < 0) + wx += width; + int wy = y % height; + if(wy < 0) + wy += height; + + // Pixel offset for this wrapped copy of the map. + const int offsetX = (x - wx) / width * width_pixel; + const int offsetY = (y - wy) / height * height_pixel; + + const MapNode& node = map.getVertex(wx, wy); + const int screenX = node.x + offsetX - viewRect.left; + const int screenY = node.y + offsetY - viewRect.top; + + if(screenX < -marginX || screenX > surfW + marginX || screenY < -marginY || screenY > surfH + marginY) + continue; + + drawVertexOverlay(target, screenX, screenY, node); + } + } +} + +} // namespace EditorWorldView diff --git a/GameWorldView.h b/GameWorldView.h new file mode 100644 index 0000000..1a3d052 --- /dev/null +++ b/GameWorldView.h @@ -0,0 +1,21 @@ +// Copyright (C) 2009 - 2025 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "defines.h" + +struct SDL_Surface; +struct bobMAP; + +namespace EditorWorldView { + +/// Draw editor overlay sprites (trees, resources, buildings, animals) to target. +/// +/// This is the editor equivalent of s25client::GameWorldView::Draw: terrain and +/// coastline borders are rendered separately by TerrainRenderer, and this pass +/// blits the per-vertex editor overlays to the UI overlay surface. +void Draw(SDL_Surface* target, const DisplayRectangle& viewRect, const bobMAP& map); + +} // namespace EditorWorldView 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/TerrainRenderer.cpp b/TerrainRenderer.cpp new file mode 100644 index 0000000..20a3a67 --- /dev/null +++ b/TerrainRenderer.cpp @@ -0,0 +1,832 @@ +// Copyright (C) 2025 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later +// +// Adapted from s25client: libs/s25main/TerrainRenderer.cpp +// Original copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org) + +#include "TerrainRenderer.h" +#include "CSurfaceGL.h" +#include "Rect.h" +#include "globals.h" +#include "ogl/VBO.h" +#include "ogl/constants.h" +#include "gameData/EdgeDesc.h" +#include "gameData/TerrainDesc.h" +#include +#include +#include +#include + +// =========================================================================== +// Types (s25client: Triangle / ColorTriangle) +// =========================================================================== + +using TriPos = std::array, 3>; +using TriTex = std::array, 3>; +struct VertColor +{ + uint8_t r, g, b, a; +}; +using TriCol = std::array; + +// =========================================================================== +// Texture LUT — hardcoded atlas pixel coords (original editor code) +// These have margin for UV shifting, unlike GetRSUTriangle which sits at +// the sub-rect edges. Copied from CSurface::GetTerrainTextureCoords. +// =========================================================================== + +struct TexBase +{ + int ux, uy, lx, ly, rx, ry; +}; +static TexBase s_texLUT[64][2]; + +static void initTexLUT() +{ + for(int t = 0; t < 64; t++) + { + for(int r = 0; r < 2; r++) + { + auto& e = s_texLUT[t][r]; + bool rsu = (r == 1); + switch(TriangleTerrainType(t)) + { + case TRIANGLE_TEXTURE_STEPPE_MEADOW1: e = {17, 96, 0, 126, 35, 126}; break; + case TRIANGLE_TEXTURE_MINING1: e = {17, 48, 0, 78, 35, 78}; break; + case TRIANGLE_TEXTURE_SNOW: + if(rsu) + e = {17, 0, 0, 30, 35, 30}; + else + e = {17, 28, 0, 0, 37, 0}; + break; + case TRIANGLE_TEXTURE_SWAMP: e = {113, 0, 96, 30, 131, 30}; break; + case TRIANGLE_TEXTURE_STEPPE: + case TRIANGLE_TEXTURE_STEPPE_: + case TRIANGLE_TEXTURE_STEPPE__: + case TRIANGLE_TEXTURE_STEPPE___: e = {65, 0, 48, 30, 83, 30}; break; + case TRIANGLE_TEXTURE_WATER: + case TRIANGLE_TEXTURE_WATER_: + case TRIANGLE_TEXTURE_WATER__: + if(rsu) + e = {231, 61, 207, 62, 223, 78}; + else + e = {224, 79, 232, 62, 245, 76}; + break; + case TRIANGLE_TEXTURE_MEADOW1: e = {65, 96, 48, 126, 83, 126}; break; + case TRIANGLE_TEXTURE_MEADOW2: e = {113, 96, 96, 126, 131, 126}; break; + case TRIANGLE_TEXTURE_MEADOW3: e = {161, 96, 144, 126, 179, 126}; break; + case TRIANGLE_TEXTURE_MINING2: e = {65, 48, 48, 78, 83, 78}; break; + case TRIANGLE_TEXTURE_MINING3: e = {113, 48, 96, 78, 131, 78}; break; + case TRIANGLE_TEXTURE_MINING4: e = {161, 48, 144, 78, 179, 78}; break; + case TRIANGLE_TEXTURE_STEPPE_MEADOW2: e = {17, 144, 0, 174, 35, 174}; break; + case TRIANGLE_TEXTURE_FLOWER: e = {161, 0, 144, 30, 179, 30}; break; + case TRIANGLE_TEXTURE_LAVA: + if(rsu) + e = {231, 117, 207, 118, 223, 134}; + else + e = {224, 135, 232, 118, 245, 132}; + break; + default: e = {161, 0, 144, 30, 179, 30}; break; + } + } + } +} + +// =========================================================================== +// Shading +// =========================================================================== + +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); +} + +static uint8_t borderIntensity(Sint32 v) +{ + if(v <= 0) + return 0; + if(v >= 65536) + return 255; + return static_cast((v * 255 + 32768) / 65536); +} + +// =========================================================================== +// Module-level state +// =========================================================================== + +static int s_W = 0, s_H = 0, s_Wpx = 0, s_Hpx = 0; +static float s_texW = 1, s_texH = 1; +static SDL_Surface* s_tileset = nullptr; + +// Per-triangle cached data (2 per vertex) +struct CachedTri +{ + float t0u, t0v, t1u, t1v, t2u, t2v; + uint8_t c0, c1, c2; + bool isWaterLava; +}; +static std::vector s_cached; + +// Water animation base UVs +static std::vector> s_waterUV; +static int s_lastWaterAnim = -1; + +// Combined VBO: terrain then borders +static ogl::VBO s_posVBO; +static ogl::VBO s_texVBO; +static ogl::VBO s_colVBO; +static size_t s_terrainTris = 0; +static size_t s_borderTris = 0; +static bool s_valid = false; + +// Animation +static int s_texMove = 0; +static int s_round = 0; +static Uint32 s_lastRound = 0, s_lastTex = 0; + +// =========================================================================== +// Helpers +// =========================================================================== + +static int wX(int x) +{ + return ((x % s_W) + s_W) % s_W; +} +static int wY(int y) +{ + return ((y % s_H) + s_H) % s_H; +} + +// Euclidean floor division for positive divisors (map pixel dimensions). +static int floorDiv(int a, int b) +{ + if(a >= 0) + return a / b; + return (a - b + 1) / b; +} + +static int vIdx(int x, int y) +{ + return wY(y) * s_W + wX(x); +} +static size_t tIdx(int x, int y, int sub) +{ + return size_t(vIdx(x, y)) * 2 + sub; +} + +static Point32 wrapNear2(const MapNode& n, const Point32& ref) +{ + Point32 p(n.x, n.y); + if(p.x - ref.x < -s_Wpx / 2) + p.x += s_Wpx; + else if(p.x - ref.x > s_Wpx / 2) + p.x -= s_Wpx; + if(p.y - ref.y < -s_Hpx / 2) + p.y += s_Hpx; + else if(p.y - ref.y > s_Hpx / 2) + p.y -= s_Hpx; + return p; +} + +static MapNode getMapNodeWrapped(const bobMAP& map, int x, int y) +{ + return map.getVertex(wX(x), wY(y)); +} + +static Point32 getPosWrapped(const bobMAP& map, int x, int y, const Point32& ref) +{ + return wrapNear2(getMapNodeWrapped(map, x, y), ref); +} + +static uint8_t getBorderColor(const bobMAP& map, int x, int y) +{ + return borderIntensity(getMapNodeWrapped(map, x, y).i); +} + +static Point32 rsuCentroid(const bobMAP& map, int x, int y, const Point32& ref) +{ + Point32 pt = getPosWrapped(map, x, y, ref); + Point32 sw = getPosWrapped(map, x - !(y & 1), y + 1, ref); + Point32 se = getPosWrapped(map, x + (y & 1), y + 1, ref); + return Point32((pt.x + sw.x + se.x) / 3, (pt.y + sw.y + se.y) / 3); +} + +static Point32 usdCentroid(const bobMAP& map, int x, int y, const Point32& ref) +{ + Point32 pt = getPosWrapped(map, x, y, ref); + Point32 se = getPosWrapped(map, x + (y & 1), y + 1, ref); + Point32 e = getPosWrapped(map, x + 1, y, ref); + return Point32((pt.x + se.x + e.x) / 3, (pt.y + se.y + e.y) / 3); +} + +static TriangleTerrainType normaliseTexture(uint8_t raw) +{ + raw &= ~0x40; + switch(raw) + { + case TRIANGLE_TEXTURE_WATER_: + case TRIANGLE_TEXTURE_WATER__: return TRIANGLE_TEXTURE_WATER; + case TRIANGLE_TEXTURE_STEPPE__: + case TRIANGLE_TEXTURE_STEPPE___: return TRIANGLE_TEXTURE_STEPPE; + default: return TriangleTerrainType(raw); + } +} + +// =========================================================================== +// Edge-type detection — s25client: GetEdgeType +// =========================================================================== + +static DescIdx GetEdgeType(const TerrainDesc& t1, const TerrainDesc& t2) +{ + if(!t1.edgeType || t1.edgePriority <= t2.edgePriority) + return {}; + return t1.edgeType; +} + +static const TerrainDesc& getTerrain(const bobMAP& map, uint8_t raw) +{ + raw &= ~(0x40 | 0x80); + return global::worldDesc.get(map.s2IdToTerrain[raw]); +} + +// =========================================================================== +// Per-triangle cache computation (working LUT-based approach) +// =========================================================================== + +static void computeCached(const bobMAP& m, int x, int y, int sub) +{ + size_t idx = tIdx(x, y, sub); + CachedTri& ct = s_cached[idx]; + bool rsu = (sub == 0); + + int texX = x, texY = y; + if(!rsu && y % 2 == 0) + texX = x - 1; + + const MapNode& n = m.getVertex(wX(texX), wY(texY)); + uint8_t raw = rsu ? n.rsuTexture : n.usdTexture; + int ti = int(normaliseTexture(raw)); + if(ti < 0 || ti >= 64) + ti = 0; + const TexBase& b = s_texLUT[ti][rsu ? 1 : 0]; + + ct.t0u = float(b.ux) / s_texW; + ct.t0v = float(b.uy) / s_texH; + ct.t1u = float(b.lx) / s_texW; + ct.t1v = float(b.ly) / s_texH; + ct.t2u = float(b.rx) / s_texW; + ct.t2v = float(b.ry) / s_texH; + ct.isWaterLava = (ti == TRIANGLE_TEXTURE_WATER || ti == TRIANGLE_TEXTURE_LAVA); + + if(ct.isWaterLava) + { + auto& w = s_waterUV[idx]; + w[0] = ct.t0u; + w[1] = ct.t0v; + w[2] = ct.t1u; + w[3] = ct.t1v; + w[4] = ct.t2u; + w[5] = ct.t2v; + } + + int vx[3], vy[3]; + if(rsu) + { + if(y % 2 == 0) + { + vx[0] = x; + vy[0] = y; + vx[1] = x - 1; + vy[1] = y + 1; + vx[2] = x; + vy[2] = y + 1; + } else + { + vx[0] = x; + vy[0] = y; + vx[1] = x; + vy[1] = y + 1; + vx[2] = x + 1; + vy[2] = y + 1; + } + } else + { + if(y % 2 == 0) + { + vx[0] = x - 1; + vy[0] = y + 1; + vx[1] = x - 1; + vy[1] = y; + vx[2] = x; + vy[2] = y; + } else + { + vx[0] = x + 1; + vy[0] = y + 1; + vx[1] = x; + vy[1] = y; + vx[2] = x + 1; + vy[2] = y; + } + } + + Sint32 i[3]; + if(ct.isWaterLava) + { + i[0] = i[1] = i[2] = 65536; + } else + { + for(int k = 0; k < 3; k++) + i[k] = m.getVertex(wX(vx[k]), wY(vy[k])).i; + } + + ct.c0 = intensityToColor(i[0]); + ct.c1 = intensityToColor(i[1]); + ct.c2 = intensityToColor(i[2]); +} + +// =========================================================================== +// Build terrain VBO arrays from cached data +// =========================================================================== + +static void buildTerrainVBOs(const bobMAP& m, std::vector& pos, std::vector& tex, + std::vector& col) +{ + pos.clear(); + tex.clear(); + col.clear(); + pos.reserve(size_t(s_W) * size_t(s_H) * 2); + tex.reserve(pos.capacity()); + col.reserve(pos.capacity()); + + for(int y = 0; y < s_H; y++) + { + for(int x = 0; x < s_W; x++) + { + const bool isXSeam = ((y % 2 == 0) && x == 0) || ((y % 2 != 0) && x == s_W - 1); + + for(int sub = 0; sub < 2; sub++) + { + const size_t idx = tIdx(x, y, sub); + const CachedTri& ct = s_cached[idx]; + const bool rsu = (sub == 0); + + int vx[3], vy[3]; + if(rsu) + { + if(y % 2 == 0) + { + vx[0] = x; + vy[0] = y; + vx[1] = x - 1; + vy[1] = y + 1; + vx[2] = x; + vy[2] = y + 1; + } else + { + vx[0] = x; + vy[0] = y; + vx[1] = x; + vy[1] = y + 1; + vx[2] = x + 1; + vy[2] = y + 1; + } + } else + { + if(y % 2 == 0) + { + vx[0] = x - 1; + vy[0] = y + 1; + vx[1] = x - 1; + vy[1] = y; + vx[2] = x; + vy[2] = y; + } else + { + vx[0] = x + 1; + vy[0] = y + 1; + vx[1] = x; + vy[1] = y; + vx[2] = x + 1; + vy[2] = y; + } + } + + auto getX = [&](int p) { + float xf = float(m.getVertex(wX(vx[p]), wY(vy[p])).x); + if(isXSeam) + { + if(y % 2 == 0) + { + if((rsu && p == 1) || (!rsu && (p == 0 || p == 1))) + if(xf > float(s_Wpx) / 2) + xf -= float(s_Wpx); + } else + { + if((rsu && p == 2) || (!rsu && (p == 0 || p == 2))) + if(xf < float(s_Wpx) / 2) + xf += float(s_Wpx); + } + } + return xf; + }; + auto getY = [&](int p) { + float yf = float(m.getVertex(wX(vx[p]), wY(vy[p])).y); + if(y == s_H - 1 && vy[p] == s_H) + yf += float(s_Hpx); + return yf; + }; + + TriPos tp; + tp[0] = {{getX(0), getY(0)}}; + tp[1] = {{getX(1), getY(1)}}; + tp[2] = {{getX(2), getY(2)}}; + pos.push_back(tp); + + tex.push_back({{{{ct.t0u, ct.t0v}}, {{ct.t1u, ct.t1v}}, {{ct.t2u, ct.t2v}}}}); + + TriCol tc; + tc[0] = {ct.c0, ct.c0, ct.c0, 255}; + tc[1] = {ct.c1, ct.c1, ct.c1, 255}; + tc[2] = {ct.c2, ct.c2, ct.c2, 255}; + col.push_back(tc); + } + } + } +} + +// =========================================================================== +// Border triangle computation +// =========================================================================== + +static void emitBorderTri(std::vector& pos, std::vector& tex, std::vector& col, + const Point32& v0, const Point32& v1, const Point32& v2, const SDL_Rect& src, uint8_t c0, + uint8_t c1, uint8_t c2, bool swapTip) +{ + float uLeft = float(src.x) / s_texW; + float vTop = float(src.y) / s_texH; + float uRight = float(src.x + src.w) / s_texW; + float uMid = float(src.x + src.w / 2) / s_texW; + float vBot = float(src.y + src.h) / s_texH; + + TriPos tp = {{{{float(v0.x), float(v0.y)}}, {{float(v1.x), float(v1.y)}}, {{float(v2.x), float(v2.y)}}}}; + pos.push_back(tp); + + // s25client: for i==1 the tip/centroid (v0) uses the bottom-centre texcoord. + if(swapTip) + tex.push_back({{{{uMid, vBot}}, {{uRight, vTop}}, {{uLeft, vTop}}}}); + else + tex.push_back({{{{uLeft, vTop}}, {{uRight, vTop}}, {{uMid, vBot}}}}); + + TriCol tc; + tc[0] = {c0, c0, c0, 255}; + tc[1] = {c1, c1, c1, 255}; + tc[2] = {c2, c2, c2, 255}; + col.push_back(tc); +} + +static SDL_Rect edgeRect(DescIdx idx) +{ + const EdgeDesc& ed = global::worldDesc.get(idx); + const Rect& r = ed.posInTexture; + return SDL_Rect{Sint16(r.getOrigin().x), Sint16(r.getOrigin().y), Uint16(r.getSize().x), Uint16(r.getSize().y)}; +} + +/// Generate border triangles aligned with s25client::TerrainRenderer. +/// See GEOMETRY.md for the mapping between editor and s25client geometry. +static void buildBorderVBOs(const bobMAP& map, std::vector& pos, std::vector& tex, + std::vector& col) +{ + for(int y = 0; y < s_H; y++) + { + for(int x = 0; x < s_W; x++) + { + // Reference vertex and its s25client neighbours. + const MapNode& ptNode = map.getVertex(x, y); + Point32 ptRef(ptNode.x, ptNode.y); + + int ex = x + 1, ey = y; + int sex = x + (y & 1), sey = y + 1; + int swx = x - !(y & 1), swy = y + 1; + + Point32 pt = getPosWrapped(map, x, y, ptRef); + Point32 e = getPosWrapped(map, ex, ey, ptRef); + Point32 se = getPosWrapped(map, sex, sey, ptRef); + Point32 sw = getPosWrapped(map, swx, swy, ptRef); + + // Terrain samples for edge-type decisions (s25client indexing). + // Note: vertices are wrapped because ex/x+1 and swy/y+1 can be one + // past the map edge. + const TerrainDesc& t1 = getTerrain(map, map.getVertex(x, y).rsuTexture); + const TerrainDesc& t2 = getTerrain(map, map.getVertex(x, y).usdTexture); + const TerrainDesc& t3 = getTerrain(map, getMapNodeWrapped(map, ex, ey).rsuTexture); + const TerrainDesc& t4 = getTerrain(map, getMapNodeWrapped(map, swx, swy).usdTexture); + + // Vertex colours and centroids used by s25client border triangles. + uint8_t c_pt = getBorderColor(map, x, y); + uint8_t c_e = getBorderColor(map, ex, ey); + uint8_t c_se = getBorderColor(map, sex, sey); + uint8_t c_sw = getBorderColor(map, swx, swy); + + Point32 c_rsu = rsuCentroid(map, x, y, ptRef); + Point32 c_usd = usdCentroid(map, x, y, ptRef); + Point32 c_rsuE = rsuCentroid(map, ex, ey, ptRef); + Point32 c_usdSW = usdCentroid(map, swx, swy, ptRef); + + uint8_t c_rsuCentroid = (c_sw + c_pt + c_se) / 3; + uint8_t c_usdCentroid = (c_e + c_pt + c_se) / 3; + + uint8_t c_e_sw = getBorderColor(map, ex - !(ey & 1), ey + 1); + uint8_t c_e_se = getBorderColor(map, ex + (ey & 1), ey + 1); + uint8_t c_rsuECentroid = (c_e + c_e_sw + c_e_se) / 3; + + uint8_t c_sw_e = getBorderColor(map, swx + 1, swy); + uint8_t c_sw_se = getBorderColor(map, swx + (swy & 1), swy + 1); + uint8_t c_usdSWCentroid = (c_sw + c_sw_se + c_sw_e) / 3; + + // left_right[0]: USD over RSU + if(DescIdx edge = GetEdgeType(t2, t1)) + emitBorderTri(pos, tex, col, pt, se, c_rsu, edgeRect(edge), c_pt, c_se, c_rsuCentroid, false); + + // left_right[1]: RSU over USD + if(DescIdx edge = GetEdgeType(t1, t2)) + emitBorderTri(pos, tex, col, c_usd, se, pt, edgeRect(edge), c_usdCentroid, c_se, c_pt, true); + + // right_left[0]: RSU(E) over USD + if(DescIdx edge = GetEdgeType(t3, t2)) + emitBorderTri(pos, tex, col, se, e, c_usd, edgeRect(edge), c_se, c_e, c_usdCentroid, false); + + // right_left[1]: USD over RSU(E) + if(DescIdx edge = GetEdgeType(t2, t3)) + emitBorderTri(pos, tex, col, c_rsuE, e, se, edgeRect(edge), c_rsuECentroid, c_e, c_se, true); + + // top_down[0]: USD(SW) over RSU + if(DescIdx edge = GetEdgeType(t4, t1)) + emitBorderTri(pos, tex, col, sw, se, c_rsu, edgeRect(edge), c_sw, c_se, c_rsuCentroid, false); + + // top_down[1]: RSU over USD(SW) + if(DescIdx edge = GetEdgeType(t1, t4)) + emitBorderTri(pos, tex, col, c_usdSW, se, sw, edgeRect(edge), c_usdSWCentroid, c_se, c_sw, true); + } + } +} + +// =========================================================================== +// TerrainRenderer namespace +// =========================================================================== + +namespace TerrainRenderer { + +void Init(const Extent& /*size*/) +{ + initTexLUT(); + s_valid = false; +} + +void setCamera(int x, int y, int w, int h) +{ + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(x, x + w, y + h, y, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +void setScreenProjection(int w, int h) +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, w, h, 0, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +// ----------------------------------------------------------------------- +// GenerateOpenGL — s25client: TerrainRenderer::GenerateOpenGL +// ----------------------------------------------------------------------- +void GenerateOpenGL(const bobMAP& map, SDL_Surface* tileset) +{ + s_W = map.width; + s_H = map.height; + s_Wpx = map.width_pixel; + s_Hpx = map.height_pixel; + const EditorGLTexture& tex = CSurfaceGL::getOrCreateTexture(tileset); + s_texW = float(tex.texWidth()); + s_texH = float(tex.texHeight()); + s_tileset = tileset; + + size_t nV = size_t(s_W) * size_t(s_H); + s_cached.assign(nV * 2, CachedTri{}); + s_waterUV.assign(nV * 2, std::array{}); + s_lastWaterAnim = -1; + + for(int y = 0; y < s_H; y++) + for(int x = 0; x < s_W; x++) + { + computeCached(map, x, y, 0); + computeCached(map, x, y, 1); + } + + std::vector pos; + std::vector txc; + std::vector col; + buildTerrainVBOs(map, pos, txc, col); + s_terrainTris = pos.size(); + + buildBorderVBOs(map, pos, txc, col); + s_borderTris = pos.size() - s_terrainTris; + + s_posVBO = ogl::VBO(ogl::Target::Array); + s_texVBO = ogl::VBO(ogl::Target::Array); + s_colVBO = ogl::VBO(ogl::Target::Array); + s_posVBO.fill(pos, ogl::Usage::Static); + // Texcoords are updated every animation frame for water/lava. + s_texVBO.fill(txc, ogl::Usage::Dynamic); + s_colVBO.fill(col, ogl::Usage::Static); + + s_cached.shrink_to_fit(); + s_waterUV.shrink_to_fit(); + + s_valid = true; +} + +void AltitudeChanged(int /*x*/, int /*y*/, const bobMAP& /*map*/) +{ + // Full regeneration is simpler in the editor; CMap::Draw will call + // GenerateOpenGL on the next frame when isTerrainValid() is false. + s_valid = false; +} + +// ----------------------------------------------------------------------- +// Draw — s25client: TerrainRenderer::Draw +// ----------------------------------------------------------------------- +void Draw(const DisplayRectangle& displayRect) +{ + if(!s_valid || !s_tileset) + return; + const EditorGLTexture& tex = CSurfaceGL::getOrCreateTexture(s_tileset); + if(!tex.valid()) + return; + + updateAnimation(); + + // Water/lava animation: shift texcoords (LUT values have margin for this) + if(s_texMove != s_lastWaterAnim) + { + s_lastWaterAnim = s_texMove; + float du = float(s_texMove) / s_texW, dv = float(s_texMove) / s_texH; + std::vector at(s_cached.size()); + for(size_t i = 0; i < s_cached.size(); i++) + { + if(s_cached[i].isWaterLava) + { + auto& w = s_waterUV[i]; + at[i][0] = {{w[0] - du, w[1] + dv}}; + at[i][1] = {{w[2] - du, w[3] + dv}}; + at[i][2] = {{w[4] - du, w[5] + dv}}; + } else + { + at[i][0] = {{s_cached[i].t0u, s_cached[i].t0v}}; + at[i][1] = {{s_cached[i].t1u, s_cached[i].t1v}}; + at[i][2] = {{s_cached[i].t2u, s_cached[i].t2v}}; + } + } + // Update only terrain portion of texcoord VBO (borders follow after) + if(!at.empty() && at.size() <= s_terrainTris) + s_texVBO.update(at, 0); + } + + glBindTexture(GL_TEXTURE_2D, tex.texture()); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + s_posVBO.bind(); + glVertexPointer(2, GL_FLOAT, sizeof(std::array), nullptr); + s_texVBO.bind(); + glTexCoordPointer(2, GL_FLOAT, sizeof(std::array), nullptr); + s_colVBO.bind(); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertColor), nullptr); + + // Wrap passes: render every copy of the map whose bounding box intersects + // the visible display rectangle. When the map is zoomed out (or on a 4K + // display) the view can cover many wraps, so generate the full Cartesian + // product of required offsets instead of a single neighbour pass. + struct Off + { + int dx, dy; + }; + std::vector passes; + + // The canonical VBO contains seam triangles that extend beyond the map's + // pixel bounds (up to one triangle width/height). Include neighbouring + // wrap copies when the visible area intersects those extended bounds, so + // triangles at the left/top edge are not clipped away when the seam sits + // just outside the screen. + const int minDx = floorDiv(displayRect.left - triangleWidth, s_Wpx); + const int maxDx = floorDiv(displayRect.right - 1 + triangleWidth, s_Wpx); + const int minDy = floorDiv(displayRect.top - triangleHeight, s_Hpx); + const int maxDy = floorDiv(displayRect.bottom - 1 + triangleHeight, s_Hpx); + + passes.reserve(static_cast(maxDx - minDx + 1) * static_cast(maxDy - minDy + 1)); + for(int dy = minDy; dy <= maxDy; ++dy) + for(int dx = minDx; dx <= maxDx; ++dx) + passes.push_back({dx * s_Wpx, dy * s_Hpx}); + + // --- Terrain --- + glDisable(GL_BLEND); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); + + glPushMatrix(); + for(auto& pass : passes) + { + glPushMatrix(); + glTranslatef(GLfloat(pass.dx), GLfloat(pass.dy), 0); + glDrawArrays(GL_TRIANGLES, 0, GLsizei(s_terrainTris * 3)); + glPopMatrix(); + } + glPopMatrix(); + + // --- Borders --- + if(s_borderTris > 0) + { + glEnable(GL_BLEND); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glPushMatrix(); + for(auto& pass : passes) + { + glPushMatrix(); + glTranslatef(GLfloat(pass.dx), GLfloat(pass.dy), 0); + glDrawArrays(GL_TRIANGLES, GLsizei(s_terrainTris * 3), GLsizei(s_borderTris * 3)); + glPopMatrix(); + } + glPopMatrix(); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); +} + +bool isTerrainValid() +{ + return s_valid; +} +void invalidateTerrain() +{ + s_valid = false; +} +float texWidth() +{ + return s_texW; +} +float texHeight() +{ + return s_texH; +} +int mapWidthPx() +{ + return s_Wpx; +} +int mapHeightPx() +{ + return s_Hpx; +} + +void updateAnimation() +{ + Uint32 now = SDL_GetTicks(); + if(now - s_lastRound > 30) + { + s_lastRound = now; + s_round = (s_round >= 7) ? 0 : s_round + 1; + } + if(now - s_lastTex > 170) + { + s_lastTex = now; + s_texMove++; + if(s_texMove > 14) + s_texMove = 0; + } +} + +int textureOffset() +{ + return s_texMove; +} +int roundCount() +{ + return s_round; +} + +} // namespace TerrainRenderer diff --git a/include/SdlSurface.h b/include/SdlSurface.h index 28a31be..ce404a1 100644 --- a/include/SdlSurface.h +++ b/include/SdlSurface.h @@ -13,23 +13,13 @@ 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(int width, int height, bool withAlpha = false) { @@ -42,8 +32,3 @@ inline SdlSurface makePalSurface(int width, int height, const std::arrayformat->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/TerrainRenderer.h b/include/TerrainRenderer.h new file mode 100644 index 0000000..a9ef454 --- /dev/null +++ b/include/TerrainRenderer.h @@ -0,0 +1,102 @@ +// Copyright (C) 2025 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "Point.h" +#include "Rect.h" +#include "defines.h" +#include + +struct bobMAP; +class EditorGLTexture; + +/// Screen/game resolution used by the editor (matches CGame::GameResolution). +using Extent = Point; + +/// OpenGL terrain rendering adapted from s25client::TerrainRenderer. +/// +/// s25client ref: libs/s25main/TerrainRenderer.cpp +/// +/// Design (matches s25client): +/// - `GenerateOpenGL()` pre-computes ALL triangle data into VBOs once. +/// - `Draw(viewport)` renders the visible region from VBOs each frame. +/// - `AltitudeChanged()` incrementally updates triangles after a map edit. +/// +/// Differences from s25client: +/// - Single tileset atlas texture vs individual terrain textures — no +/// texture-sort batching needed; one glDrawArrays call covers all terrain. +/// - No fog-of-war / visibility system. +/// - Water animation via texcoord shifting (matches original SGE code), not +/// palette animation. +/// - Map wrapping via glTranslate passes instead of sorted texture batches. +namespace TerrainRenderer { + +/// Initialize OpenGL state and pre-allocate renderer structures. +/// s25client: libs/s25main/TerrainRenderer.cpp TerrainRenderer::Init +void Init(const Extent& screenSize); + +/// Set the viewport and map-space ortho camera. +/// s25client: libs/s25main/GameWorldViewer.cpp Draw -> setViewport +void setCamera(int camX, int camY, int screenW, int screenH); + +/// Reset to screen-space projection (for UI overlay). +void setScreenProjection(int screenW, int screenH); + +// --------------------------------------------------------------------------- +// Pre-compute (call once on map load) +// --------------------------------------------------------------------------- + +/// Pre-compute ALL terrain triangles into VBOs. After this, Draw() can be +/// called repeatedly without regeneration. +/// s25client: libs/s25main/TerrainRenderer.cpp TerrainRenderer::GenerateOpenGL() +void GenerateOpenGL(const bobMAP& map, SDL_Surface* tileset); + +/// Incrementally update triangles around vertex (x,y) after a height/texture +/// edit. Rebuilds VBOs for the affected neighbourhood. +/// s25client: libs/s25main/TerrainRenderer.cpp TerrainRenderer::AltitudeChanged() +void AltitudeChanged(int x, int y, const bobMAP& map); + +// --------------------------------------------------------------------------- +// Per-frame drawing +// --------------------------------------------------------------------------- + +/// Render terrain for the given viewport. Uses pre-computed VBOs. +/// Handles map wrapping internally via glTranslate passes. +/// s25client: libs/s25main/TerrainRenderer.cpp TerrainRenderer::Draw() +void Draw(const DisplayRectangle& displayRect); + +// --------------------------------------------------------------------------- +// State queries +// --------------------------------------------------------------------------- + +/// Check if terrain has been generated. +bool isTerrainValid(); + +/// Mark terrain as needing regeneration (new map). +void invalidateTerrain(); + +/// Get tileset texture dimensions (needed by border drawing). +float texWidth(); +float texHeight(); + +/// Get map pixel dimensions (needed by border wrap passes). +int mapWidthPx(); +int mapHeightPx(); + +// --------------------------------------------------------------------------- +// Animation +// --------------------------------------------------------------------------- + +/// Advance water/lava animation timers. Call once per frame. +/// s25client: libs/s25main/TerrainRenderer.cpp Draw (water animation) +void updateAnimation(); + +/// Get current texture animation offset (pixels). +int textureOffset(); + +/// Get current tree-animation round count (0-7). +int roundCount(); + +} // namespace TerrainRenderer