isle-portable/extensions/src/textureloader.cpp
Christian Semmler 3d7bbdf0ae
Add third person camera extension
Introduces a third person camera system with orbit camera, input handling
(mouse/keyboard/touch/gamepad), display actor cloning, and camera-relative
movement. Includes shared character utilities (animator, cloner, customizer)
and an IExtraAnimHandler interface for optional animation extensions.
Also includes generic base game fixes and extension system improvements.
2026-03-29 08:20:57 -07:00

129 lines
3.8 KiB
C++

#include "extensions/textureloader.h"
#include "extensions/common/pathutils.h"
#include "legovideomanager.h"
#include "misc.h"
#include "mxdirectx/mxdirect3d.h"
#include "mxmain.h"
#include "tgl/d3drm/impl.h"
using namespace Extensions;
std::map<std::string, std::string> TextureLoaderExt::options;
std::vector<std::string> TextureLoaderExt::excludedFiles;
bool TextureLoaderExt::enabled = false;
void TextureLoaderExt::Initialize()
{
for (const auto& option : defaults) {
if (!options.count(option.first.data())) {
options[option.first.data()] = option.second;
}
}
}
void TextureLoaderExt::AddExcludedFile(const std::string& p_file)
{
excludedFiles.emplace_back(p_file);
}
bool TextureLoaderExt::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;
desc.ddpfPixelFormat.dwRBitMask = details->Rmask;
desc.ddpfPixelFormat.dwGBitMask = details->Gmask;
desc.ddpfPixelFormat.dwBBitMask = details->Bmask;
desc.ddpfPixelFormat.dwRGBAlphaBitMask = details->Amask;
LPDIRECTDRAW pDirectDraw = VideoManager()->GetDirect3D()->DirectDraw();
if (pDirectDraw->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* sdlPalette = SDL_GetSurfacePalette(surface);
if (!sdlPalette) {
p_textureInfo->m_surface->Unlock(desc.lpSurface);
SDL_DestroySurface(surface);
return false;
}
PALETTEENTRY entries[256];
for (int i = 0; i < sdlPalette->ncolors; ++i) {
entries[i].peRed = sdlPalette->colors[i].r;
entries[i].peGreen = sdlPalette->colors[i].g;
entries[i].peBlue = sdlPalette->colors[i].b;
entries[i].peFlags = PC_NONE;
}
LPDIRECTDRAWPALETTE ddPalette = nullptr;
if (pDirectDraw->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, entries, &ddPalette, NULL) != DD_OK) {
p_textureInfo->m_surface->Unlock(desc.lpSurface);
SDL_DestroySurface(surface);
return false;
}
p_textureInfo->m_surface->SetPalette(ddPalette);
ddPalette->Release();
}
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* TextureLoaderExt::FindTexture(const char* p_name)
{
if (std::find(excludedFiles.begin(), excludedFiles.end(), p_name) != excludedFiles.end()) {
return nullptr;
}
const char* texturePath = options["texture loader:texture path"].c_str();
MxString relativePath = MxString(texturePath) + "/" + p_name + ".bmp";
MxString path;
if (!Common::ResolveGamePath(relativePath.GetData(), path)) {
return nullptr;
}
return SDL_LoadBMP(path.GetData());
}