mirror of
https://github.com/isledecomp/isle-portable.git
synced 2025-08-03 15:47:34 -04:00
Add extensions, TextureLoader
(#570)
* Add extensions, `TextureLoader` * Fix wording * Add to default ini * Add folder to flatpak * Use different enable strategy
This commit is contained in:
parent
4e8ac86415
commit
68c967ebdf
@ -48,6 +48,7 @@ option(ISLE_WERROR "Treat warnings as errors" OFF)
|
||||
option(ISLE_DEBUG "Enable imgui debug" ON)
|
||||
cmake_dependent_option(ISLE_USE_DX5 "Build with internal DirectX 5 SDK" "${NOT_MINGW}" "WIN32;CMAKE_SIZEOF_VOID_P EQUAL 4" OFF)
|
||||
cmake_dependent_option(ISLE_MINIWIN "Use miniwin" ON "NOT ISLE_USE_DX5" OFF)
|
||||
cmake_dependent_option(ISLE_EXTENSIONS "Use extensions" ON "NOT ISLE_USE_DX5" OFF)
|
||||
cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN;NOT NINTENDO_3DS;NOT WINDOWS_STORE" OFF)
|
||||
cmake_dependent_option(ISLE_COMPILE_SHADERS "Compile shaders" ON "SDL_SHADERCROSS_BIN;TARGET Python3::Interpreter" OFF)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Build with -fPIC" ON)
|
||||
@ -61,6 +62,7 @@ message(STATUS "Isle app: ${ISLE_BUILD_APP}")
|
||||
message(STATUS "Config app: ${ISLE_BUILD_CONFIG}")
|
||||
message(STATUS "Internal DirectX5 SDK: ${ISLE_USE_DX5}")
|
||||
message(STATUS "Internal miniwin: ${ISLE_MINIWIN}")
|
||||
message(STATUS "Isle extensions: ${ISLE_EXTENSIONS}")
|
||||
message(STATUS "Isle debugging: ${ISLE_DEBUG}")
|
||||
message(STATUS "Compile shaders: ${ISLE_COMPILE_SHADERS}")
|
||||
|
||||
@ -170,6 +172,7 @@ add_library(lego1
|
||||
target_precompile_headers(lego1 PRIVATE "LEGO1/lego1_pch.h")
|
||||
set_property(TARGET lego1 PROPERTY DEFINE_SYMBOL "LEGO1_DLL")
|
||||
target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/util>")
|
||||
target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/extensions/include>")
|
||||
target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/LEGO1>")
|
||||
target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/LEGO1/omni/include>")
|
||||
target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/LEGO1/lego/sources>")
|
||||
@ -487,6 +490,14 @@ if (NOT ISLE_MINIWIN)
|
||||
target_compile_definitions(lego1 PRIVATE DIRECTINPUT_VERSION=0x0500)
|
||||
endif()
|
||||
|
||||
if (ISLE_EXTENSIONS)
|
||||
target_compile_definitions(lego1 PUBLIC EXTENSIONS)
|
||||
target_sources(lego1 PRIVATE
|
||||
extensions/src/extensions.cpp
|
||||
extensions/src/textureloader.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ISLE_BUILD_APP)
|
||||
add_executable(isle WIN32
|
||||
ISLE/res/isle.rc
|
||||
|
@ -6,12 +6,7 @@ If you feel fit to contribute, feel free to create a pull request! Someone will
|
||||
|
||||
Please keep your pull requests small and understandable; you may be able to shoot ahead and make a lot of progress in a short amount of time, but this is a collaborative project, so you must allow others to catch up and follow along. Large pull requests become significantly more unwieldy to review, and as such make it exponentially more likely for a mistake or error to go undetected. They also make it harder to merge other pull requests because the more files you modify, the more likely it is for a merge conflict to occur. A general guideline is to keep submissions limited to one class at a time. Sometimes two or more classes may be too interlinked for this to be feasible, so this is not a hard rule, however if your PR is starting to modify more than 10 or so files, it's probably getting too big.
|
||||
|
||||
This repository has a single goal: achieving platform independence. Consequently, contributions that do not support this goal cannot be accepted. Examples of out-of-scope contributions include:
|
||||
|
||||
* Improving code efficiency or performance without addressing platform compatibility
|
||||
* Replacing `MxString` with `std::string`
|
||||
* Fixing gameplay bugs
|
||||
* Enhancing audio or video quality
|
||||
This repository has achieving platform independence as its primary goal, with limited support for light modding (using [`extensions`](/extensions)). Any changes that modify code in `LEGO1` are unlikely to be accepted, unless they directly serve to increase platform compatibility.
|
||||
|
||||
If in doubt, please contact us in the [Matrix chatroom](https://matrix.to/#/#isledecomp:matrix.org).
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "tgl/d3drm/impl.h"
|
||||
#include "viewmanager/viewmanager.h"
|
||||
|
||||
#include <extensions/extensions.h>
|
||||
#include <miniwin/miniwindevice.h>
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS
|
||||
@ -1013,6 +1014,13 @@ bool IsleApp::LoadConfig()
|
||||
iniparser_set(dict, "isle:Max Allowed Extras", SDL_itoa(m_maxAllowedExtras, buf, 10));
|
||||
iniparser_set(dict, "isle:Transition Type", SDL_itoa(m_transitionType, buf, 10));
|
||||
|
||||
#ifdef EXTENSIONS
|
||||
iniparser_set(dict, "extensions", NULL);
|
||||
for (const char* key : Extensions::availableExtensions) {
|
||||
iniparser_set(dict, key, "false");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __3DS__
|
||||
N3DS_SetupDefaultConfigOverrides(dict);
|
||||
#endif
|
||||
@ -1089,6 +1097,18 @@ bool IsleApp::LoadConfig()
|
||||
m_savePath = new char[strlen(savePath) + 1];
|
||||
strcpy(m_savePath, savePath);
|
||||
|
||||
#ifdef EXTENSIONS
|
||||
std::vector<const char*> keys;
|
||||
keys.resize(iniparser_getsecnkeys(dict, "extensions"));
|
||||
iniparser_getseckeys(dict, "extensions", keys.data());
|
||||
|
||||
for (const char* key : keys) {
|
||||
if (iniparser_getboolean(dict, key, 0)) {
|
||||
Extensions::Enable(key);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
iniparser_freedict(dict);
|
||||
delete[] iniConfig;
|
||||
#ifndef IOS
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "legotextureinfo.h"
|
||||
|
||||
#include "extensions/textureloader.h"
|
||||
#include "legovideomanager.h"
|
||||
#include "misc.h"
|
||||
#include "misc/legoimage.h"
|
||||
@ -9,6 +10,8 @@
|
||||
|
||||
DECOMP_SIZE_ASSERT(LegoTextureInfo, 0x10)
|
||||
|
||||
using namespace Extensions;
|
||||
|
||||
// FUNCTION: LEGO1 0x10065bf0
|
||||
LegoTextureInfo::LegoTextureInfo()
|
||||
{
|
||||
@ -56,6 +59,10 @@ LegoTextureInfo* LegoTextureInfo::Create(const char* p_name, LegoTexture* p_text
|
||||
strcpy(textureInfo->m_name, p_name);
|
||||
}
|
||||
|
||||
if (Extension<TextureLoader>::Call(PatchTexture, textureInfo).value_or(false)) {
|
||||
return textureInfo;
|
||||
}
|
||||
|
||||
LPDIRECTDRAW pDirectDraw = VideoManager()->GetDirect3D()->DirectDraw();
|
||||
LegoImage* image = p_texture->GetImage();
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
This initiative is a portable version of LEGO Island (Version 1.1, English) based on the [decompilation project](https://github.com/isledecomp/isle). Our primary goal is to transform the codebase to achieve platform independence, thereby enhancing compatibility across various systems while preserving the original game's experience as faithfully as possible.
|
||||
|
||||
Please note: this project is dedicated to achieving platform independence without altering the core gameplay, adding new features, enhancing visual quality, or rewriting code for improvement's sake. While those are worthwhile objectives, they are not within the scope of this project.
|
||||
Please note: this project is primarily dedicated to achieving platform independence without altering the core gameplay or rewriting code for improvement's sake. While those are worthwhile objectives, they are not within the scope of this project. `isle-portable` offers support for light modding using [`extensions`](/extensions).
|
||||
|
||||
## Status
|
||||
|
||||
|
28
extensions/include/extensions/extensions.h
Normal file
28
extensions/include/extensions/extensions.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "lego1_export.h"
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace Extensions
|
||||
{
|
||||
constexpr const char* availableExtensions[] = {"extensions:texture loader"};
|
||||
|
||||
LEGO1_EXPORT void Enable(const char* p_key);
|
||||
|
||||
template <typename T>
|
||||
struct Extension {
|
||||
template <typename Function, typename... Args>
|
||||
static auto Call(Function&& function, Args&&... args) -> std::optional<std::invoke_result_t<Function, Args...>>
|
||||
{
|
||||
#ifdef EXTENSIONS
|
||||
if (T::enabled) {
|
||||
return std::invoke(std::forward<Function>(function), std::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
}; // namespace Extensions
|
24
extensions/include/extensions/textureloader.h
Normal file
24
extensions/include/extensions/textureloader.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "extensions/extensions.h"
|
||||
#include "legotextureinfo.h"
|
||||
|
||||
namespace Extensions
|
||||
{
|
||||
class TextureLoader {
|
||||
public:
|
||||
static bool PatchTexture(LegoTextureInfo* p_textureInfo);
|
||||
static bool enabled;
|
||||
|
||||
private:
|
||||
static constexpr const char* texturePath = "/textures/";
|
||||
|
||||
static SDL_Surface* FindTexture(const char* p_name);
|
||||
};
|
||||
|
||||
#ifdef EXTENSIONS
|
||||
constexpr auto PatchTexture = &TextureLoader::PatchTexture;
|
||||
#else
|
||||
constexpr decltype(&TextureLoader::PatchTexture) PatchTexture = nullptr;
|
||||
#endif
|
||||
}; // namespace Extensions
|
19
extensions/src/extensions.cpp
Normal file
19
extensions/src/extensions.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include "extensions/extensions.h"
|
||||
|
||||
#include "extensions/textureloader.h"
|
||||
|
||||
#include <SDL3/SDL_log.h>
|
||||
|
||||
void Extensions::Enable(const char* p_key)
|
||||
{
|
||||
for (const char* key : availableExtensions) {
|
||||
if (!SDL_strcasecmp(p_key, key)) {
|
||||
if (!SDL_strcasecmp(p_key, "extensions:texture loader")) {
|
||||
TextureLoader::enabled = true;
|
||||
}
|
||||
|
||||
SDL_Log("Enabled extension: %s", p_key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
98
extensions/src/textureloader.cpp
Normal file
98
extensions/src/textureloader.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include "extensions/textureloader.h"
|
||||
|
||||
using namespace Extensions;
|
||||
|
||||
bool TextureLoader::enabled = false;
|
||||
|
||||
bool TextureLoader::PatchTexture(LegoTextureInfo* p_textureInfo)
|
||||
{
|
||||
SDL_Surface* surface = FindTexture(p_textureInfo->m_name);
|
||||
if (!surface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(surface->format);
|
||||
|
||||
DDSURFACEDESC desc;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
|
||||
desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
|
||||
desc.dwWidth = surface->w;
|
||||
desc.dwHeight = surface->h;
|
||||
desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
|
||||
desc.ddpfPixelFormat.dwRGBBitCount = details->bits_per_pixel == 8 ? 24 : details->bits_per_pixel;
|
||||
desc.ddpfPixelFormat.dwRBitMask = details->Rmask;
|
||||
desc.ddpfPixelFormat.dwGBitMask = details->Gmask;
|
||||
desc.ddpfPixelFormat.dwBBitMask = details->Bmask;
|
||||
desc.ddpfPixelFormat.dwRGBAlphaBitMask = details->Amask;
|
||||
|
||||
if (VideoManager()->GetDirect3D()->DirectDraw()->CreateSurface(&desc, &p_textureInfo->m_surface, NULL) != DD_OK) {
|
||||
SDL_DestroySurface(surface);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.dwSize = sizeof(desc);
|
||||
|
||||
if (p_textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) != DD_OK) {
|
||||
SDL_DestroySurface(surface);
|
||||
return false;
|
||||
}
|
||||
|
||||
MxU8* dst = (MxU8*) desc.lpSurface;
|
||||
Uint8* srcPixels = (Uint8*) surface->pixels;
|
||||
|
||||
if (details->bits_per_pixel == 8) {
|
||||
SDL_Palette* palette = SDL_GetSurfacePalette(surface);
|
||||
if (palette) {
|
||||
for (int y = 0; y < surface->h; ++y) {
|
||||
Uint8* srcRow = srcPixels + y * surface->pitch;
|
||||
Uint8* dstRow = dst + y * desc.lPitch;
|
||||
for (int x = 0; x < surface->w; ++x) {
|
||||
SDL_Color color = palette->colors[srcRow[x]];
|
||||
dstRow[x * 3 + 0] = color.r;
|
||||
dstRow[x * 3 + 1] = color.g;
|
||||
dstRow[x * 3 + 2] = color.b;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
p_textureInfo->m_surface->Unlock(desc.lpSurface);
|
||||
SDL_DestroySurface(surface);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
memcpy(dst, srcPixels, surface->pitch * surface->h);
|
||||
}
|
||||
|
||||
p_textureInfo->m_surface->Unlock(desc.lpSurface);
|
||||
p_textureInfo->m_palette = NULL;
|
||||
|
||||
if (((TglImpl::RendererImpl*) VideoManager()->GetRenderer())
|
||||
->CreateTextureFromSurface(p_textureInfo->m_surface, &p_textureInfo->m_texture) != D3DRM_OK) {
|
||||
SDL_DestroySurface(surface);
|
||||
return false;
|
||||
}
|
||||
|
||||
p_textureInfo->m_texture->SetAppData((LPD3DRM_APPDATA) p_textureInfo);
|
||||
SDL_DestroySurface(surface);
|
||||
return true;
|
||||
}
|
||||
|
||||
SDL_Surface* TextureLoader::FindTexture(const char* p_name)
|
||||
{
|
||||
SDL_Surface* surface;
|
||||
MxString path = MxString(MxOmni::GetHD()) + texturePath + p_name + ".bmp";
|
||||
|
||||
path.MapPathToFilesystem();
|
||||
if (!(surface = SDL_LoadBMP(path.GetData()))) {
|
||||
path = MxString(MxOmni::GetCD()) + texturePath + p_name + ".bmp";
|
||||
path.MapPathToFilesystem();
|
||||
surface = SDL_LoadBMP(path.GetData());
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
@ -55,6 +55,11 @@
|
||||
"path": "../../../miniwin",
|
||||
"dest": "miniwin/"
|
||||
},
|
||||
{
|
||||
"type": "dir",
|
||||
"path": "../../../extensions",
|
||||
"dest": "extensions/"
|
||||
},
|
||||
{
|
||||
"type": "dir",
|
||||
"path": "../../../packaging",
|
||||
|
Loading…
x
Reference in New Issue
Block a user