diff --git a/OP2-Landlord/Graphics.cpp b/OP2-Landlord/Graphics.cpp index e02da2e..37fc3e1 100644 --- a/OP2-Landlord/Graphics.cpp +++ b/OP2-Landlord/Graphics.cpp @@ -3,7 +3,39 @@ #include +#include #include +#include + + +namespace +{ + + struct SurfaceDeleter + { + void operator()(SDL_Surface* srf) + { + SDL_FreeSurface(srf); + } + }; + + using SdlSurface = std::unique_ptr ; + + SdlSurface createSurfaceFromBuffer(const void* buffer, const size_t buffersize) + { + auto rwops = SDL_RWFromConstMem(buffer, static_cast(buffersize)); + SDL_Surface* surface = IMG_LoadBMP_RW(rwops); + SDL_RWclose(rwops); + + if (!surface) + { + const std::string msg{ "createSurfaceFromBuffer(): Unable to load from memory buffer: " + std::string(SDL_GetError()) }; + throw std::runtime_error(msg); + } + + return SdlSurface{ surface }; + } +}; Graphics::Graphics(ImVec2 windowSize) : @@ -41,7 +73,7 @@ void Graphics::present() } -Graphics::Texture Graphics::loadTexture(const std::string& filename) +Graphics::Texture Graphics::loadTexture(const std::string& filename) const { SDL_Surface* temp = IMG_Load(filename.c_str()); if (!temp) @@ -66,6 +98,64 @@ Graphics::Texture Graphics::loadTexture(const std::string& filename) } +Graphics::Texture Graphics::loadTexture(const void* buffer, const size_t buffersize) const +{ + auto out = SDL_CreateTextureFromSurface(mRenderer, createSurfaceFromBuffer(buffer, buffersize).get()); + + if (!out) + { + const std::string msg{ std::string("loadTexture(): Unable to load from memory buffer: ") + SDL_GetError() }; + throw std::runtime_error(msg); + } + + int width = 0, height = 0; + SDL_QueryTexture(out, nullptr, nullptr, &width, &height); + + return Texture{ out, SDL_Rect{ 0, 0, width, height }, { static_cast(width), static_cast(height) } }; +} + + +Graphics::Texture Graphics::loadTexturePacked(const void* buffer, const size_t buffersize) const +{ + SdlSurface src{ SDL_ConvertSurfaceFormat(createSurfaceFromBuffer(buffer, buffersize).get(), SDL_PIXELFORMAT_RGB888, 0) }; + + SdlSurface destinationSurface(SDL_CreateRGBSurface( + src.get()->flags, + 1024, 1024, + src->format->BitsPerPixel, + src->format->Rmask, + src->format->Gmask, + src->format->Bmask, + src->format->Amask)); + + if (!destinationSurface.get()) + { + throw std::runtime_error("loadTexturePacked(): Unable to create new surface: " + std::string(SDL_GetError())); + } + + SDL_Rect sourceRect{ 0, 0, 32, 32 }; + SDL_Rect destRect{ 0, 0, 32, 32 }; + for (size_t i = 0; i < src->h / 32; ++i) + { + destRect = { (static_cast(i) % 32) * 32, (static_cast(i) / 32) * 32, 32, 32 }; + SDL_BlitSurface(src.get(), &sourceRect, destinationSurface.get(), &destRect); + sourceRect.y += 32; + } + + auto out = SDL_CreateTextureFromSurface(mRenderer, destinationSurface.get()); + if (!out) + { + const std::string msg{ std::string("loadTexturePacked(): Unable to load from memory buffer: ") + SDL_GetError() }; + throw std::runtime_error(msg); + } + + int width = 0, height = 0; + SDL_QueryTexture(out, nullptr, nullptr, &width, &height); + + return Texture{ out, SDL_Rect{ 0, 0, width, height }, { static_cast(width), static_cast(height) } }; +} + + void Graphics::init() { if (SDL_Init(SDL_INIT_VIDEO)) diff --git a/OP2-Landlord/Graphics.h b/OP2-Landlord/Graphics.h index 1550a90..d314a16 100644 --- a/OP2-Landlord/Graphics.h +++ b/OP2-Landlord/Graphics.h @@ -28,7 +28,9 @@ class Graphics void clear(); void present(); - Texture loadTexture(const std::string& filename); + Texture loadTexture(const std::string& filename) const; + Texture loadTexture(const void* buffer, const size_t bufferSize) const; + Texture loadTexturePacked(const void* buffer, const size_t buffersize) const; SDL_Window* window() { return mWindow; } SDL_Renderer* renderer() { return mRenderer; } diff --git a/OP2-Landlord/OP2-Landlord.vcxproj b/OP2-Landlord/OP2-Landlord.vcxproj index 157f62b..7f47375 100644 --- a/OP2-Landlord/OP2-Landlord.vcxproj +++ b/OP2-Landlord/OP2-Landlord.vcxproj @@ -71,11 +71,11 @@ - ../nas2d-core/;../OP2Utility/header/;../json/include;$(IncludePath) + ../nas2d-core/;../OP2Utility/include/;../json/include;$(IncludePath) $(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath) - ../nas2d-core/;../OP2Utility/header/;../json/include;$(IncludePath) + ../nas2d-core/;../OP2Utility/include/;../json/include;$(IncludePath) $(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath) diff --git a/OP2-Landlord/main.cpp b/OP2-Landlord/main.cpp index d7866f2..868e9c9 100644 --- a/OP2-Landlord/main.cpp +++ b/OP2-Landlord/main.cpp @@ -8,6 +8,7 @@ #include #if defined(_WIN32) +#define NOMINMAX #include #endif @@ -23,6 +24,11 @@ #include "StringTable.h" #include "Utility.h" +#include "OP2Utility.h" + + +using namespace OP2Utility; + namespace { @@ -33,12 +39,14 @@ namespace using StateGuiFunction = std::function; std::map StateFunctionTable; - using StateTransitionFunction = std::function; + using StateTransitionFunction = std::function; std::map StateTransitionFunctionTable; + + std::vector TileSets; }; -void mainLoop(Graphics& graphics, Gui& gui) +void mainLoop(EditorConfig& config, Graphics& graphics, Gui& gui) { std::string pathToOutpost2{}; @@ -56,7 +64,7 @@ void mainLoop(Graphics& graphics, Gui& gui) { try { - StateTransitionFunctionTable.at(ApplicationState)(gui); + StateTransitionFunctionTable.at(ApplicationState)(config, graphics, gui); } catch (std::out_of_range) { @@ -64,6 +72,24 @@ void mainLoop(Graphics& graphics, Gui& gui) } } + if (!TileSets.empty()) + { + const auto& tset = TileSets.back(); + + int offset = 250; + for (const auto& tset : TileSets) + { + const SDL_Rect destRect{ + offset, 100, + static_cast(tset.dimensions.x), + static_cast(tset.dimensions.y) + }; + + SDL_RenderCopy(graphics.renderer(), tset.texture, nullptr, &destRect); + offset += 40; + } + } + gui.endFrame(); graphics.present(); } @@ -76,8 +102,52 @@ void checkConfig(EditorConfig& config) } -void loadOrCreateTransition(Gui& gui) +Graphics::Texture bmpToTexture(Graphics& graphics, EditorConfig& config, BitmapFile& bmp) { + std::size_t pixelOffset = sizeof(BmpHeader) + sizeof(ImageHeader) + bmp.palette.size() * sizeof(Color); + std::size_t bufferSize = pixelOffset + ImageHeader::CalculatePitch(bmp.imageHeader.bitCount, bmp.imageHeader.width) * std::abs(bmp.imageHeader.height); + + auto buffer = new uint8_t[bufferSize]; + memset(buffer, 0, bufferSize); + + Stream::MemoryWriter writer(buffer, bufferSize); + + bmp.WriteIndexed(writer); + + return graphics.loadTexturePacked(buffer, bufferSize); +} + + +void loadOrCreateTransition(EditorConfig& config, Graphics& graphics, Gui& gui) +{ + Archive::VolFile artVol(config["Op2FilePath"] + "/" + "art.vol"); + const auto indexCount = artVol.GetCount(); + + std::vector tilesetIndicies; + for (size_t i = 0; i < indexCount; ++i) + { + const auto artName{ StringUtility::ConvertToUpper(artVol.GetName(i)) }; + + if (artName.find("WELL") != std::string::npos) + { + tilesetIndicies.push_back(i); + } + } + + for (size_t i = 0; i < tilesetIndicies.size(); ++i) + { + const auto tsetIndex = tilesetIndicies[i]; + + try + { + auto bitmap = Tileset::ReadTileset(*artVol.OpenStream(tsetIndex)); + TileSets.push_back(bmpToTexture(graphics, config, bitmap)); + } + catch(std::runtime_error e) + { + std::cout << "[Warning] Unable to load tilset '" << artVol.GetName(tsetIndex) << "' : " << e.what() << std::endl; + } + } } @@ -107,10 +177,10 @@ int main(int argc, char* argv[]) if (ApplicationState != Gui::AppState::InitialSetup) { - loadOrCreateTransition(gui); + loadOrCreateTransition(config, graphics, gui); } - mainLoop(graphics, gui); + mainLoop(config, graphics, gui); SDL_Quit(); }