Merge branch 'main' into sse

This commit is contained in:
Ondřej Novák 2025-05-09 08:04:02 +02:00
commit 5931c6eab4
37 changed files with 739 additions and 147 deletions

View file

@ -95,9 +95,10 @@ elseif(APPLE)
target_sources(skeldal PRIVATE
linux/app_start.cpp
)
target_compile_definitions(mylib PRIVATE PLATFORM_MACOS)
set(STEAMLIB ${STEAMWORKS_SDK_DIR}/redistributable_bin/osx/libsteam_api.dylib)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
if(STEAM_ENABLED)
set(STEAMLIB ${STEAMWORKS_SDK_DIR}/redistributable_bin/osx/libsteam_api.dylib)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
message(STATUS "Building for macOS")
target_link_libraries(skeldal ${all_libs} ${STEAMLIB})
else()

View file

@ -4,6 +4,7 @@
#include <cstdarg>
#include <cstdint>
#include <iostream>
#include <sstream>
#include "error.h"
#include "platform.h"
@ -38,3 +39,18 @@ void send_log_impl(const char *format, ...) {
void throw_exception(const char *text) {
throw std::runtime_error(std::string("Invoked crash:") + text);
}
std::string exception_to_string(const std::exception& e) {
std::ostringstream oss;
oss << e.what();
try {
std::rethrow_if_nested(e);
} catch (const std::exception& nested) {
oss << "\n\n Reason: " << exception_to_string(nested);
} catch (...) {
oss << "\n\n Reason: unknown exception of crash";
}
return std::move(oss).str();
}

View file

@ -2,6 +2,11 @@
#ifdef __cplusplus
#include <string>
#include <exception>
std::string exception_to_string(const std::exception& e);
extern "C" {
#endif
@ -10,7 +15,8 @@ void send_log_impl(const char *format, ...);
void display_error(const char *format, ...);
void throw_exception(const char *text);
#ifdef __cplusplus
}
#endif

View file

@ -7,23 +7,37 @@
#include "../libs/logfile.h"
std::filesystem::path break_and_compose_path(const std::string_view &pathname, char sep) {
std::filesystem::path break_and_compose_path(std::string_view pathname, char sep) {
auto utf8_to_path = [](std::string_view sv) -> std::filesystem::path {
return std::filesystem::path(std::u8string(reinterpret_cast<const char8_t*>(sv.data()), sv.size()));
};
auto p = pathname.rfind(sep);
if (p == pathname.npos) {
if (pathname == "." || pathname == "..") {
return std::filesystem::canonical(".");
} else if (pathname.empty()) {
return std::filesystem::current_path().root_path();
} else if (pathname == std::filesystem::current_path().root_name()) {
return std::filesystem::current_path().root_path();
} else {
return std::filesystem::current_path()/pathname;
}
}
return break_and_compose_path(pathname.substr(0,p), sep) / pathname.substr(p+1);
}
// Detekce Windows drive letter jako "C:"
if (pathname.size() == 2 && std::isalpha(static_cast<unsigned char>(pathname[0])) && pathname[1] == ':') {
return utf8_to_path(std::string(pathname) + "\\"); // vždy konstruujeme s \ pro root disku
}
// Kontrola na root (např. "/") musíme převést pro porovnání
if (utf8_to_path(pathname) == std::filesystem::current_path().root_path()) {
return std::filesystem::current_path().root_path();
}
// Vše ostatní relativně vůči current_path
return std::filesystem::current_path() / utf8_to_path(pathname);
} else if (p == 0) {
return std::filesystem::current_path().root_path() / utf8_to_path(pathname);
}
return break_and_compose_path(pathname.substr(0, p), sep) / utf8_to_path(pathname.substr(p + 1));
}
std::filesystem::path convert_pathname_to_path(const std::string_view &pathname) {
auto p = pathname.find('\\');
@ -81,7 +95,12 @@ const char *file_icase_find(const char *pathname) {
FILE *fopen_icase(const char *pathname, const char *mode) {
std::filesystem::path path = try_to_find_file(convert_pathname_to_path(pathname));
#ifdef _WIN32
std::wstring wmode(mode, mode + std::strlen(mode)); // bezpečnější převod
return _wfopen(path.wstring().c_str(), wmode.c_str());
#else
return fopen(path.string().c_str(), mode);
#endif
}
static thread_local std::string build_pathname_buffer;

View file

@ -1,6 +1,7 @@
#include "../../game/skeldal.h"
#include "../getopt.h"
#include "../platform.h"
#include "../error.h"
#include <iostream>
#include <string>
@ -67,7 +68,7 @@ int main(int argc, char **argv) {
}
} catch (const std::exception &e) {
std::cerr << "ERROR: " << e.what() << std::endl;
std::cerr << "ERROR: " << exception_to_string(e) << std::endl;
return 1;
}

View file

@ -1,9 +1,7 @@
extern "C" {
#include "map_file.h"
#include "../error.h"
}
#include <stdio.h>
#include <stdlib.h>

View file

@ -1,4 +1,13 @@
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void *map_file_to_memory(const char *name, size_t *sz);
void unmap_file(void *ptr, size_t sz);
#ifdef __cplusplus
}
#endif

View file

@ -2,6 +2,7 @@
temp_file=$(mktemp /tmp/skeldal.XXXXXX.log)
CURDIR=`dirname "$0"`
chmod +x "$CURDIR/skeldal_bin"
LD_LIBRARY_PATH=$CURDIR:$LD_LIBRARY_PATH "$CURDIR/skeldal_bin" $* > "$temp_file" 2>&1
exit_code=$?
@ -25,4 +26,3 @@ fi
rm $temp_file
exit $exit_code

View file

@ -1,2 +1,6 @@
#include <string.h>
#include <malloc.h>
#if defined(__linux__)
#include <malloc.h>
#elif defined(__APPLE__)
#include <stdlib.h>
#endif

View file

@ -0,0 +1,184 @@
#pragma once
#include <SDL_surface.h>
template<Uint32 format>
struct FormatMapping {
static_assert(false, "Unsupported pixel format");
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ARGB2101010> {
static constexpr int RShift = 20;
static constexpr int GShift = 10;
static constexpr int BShift = 0;
static constexpr int AShift = 30;
static constexpr int RBits = 10;
static constexpr int GBits = 10;
static constexpr int BBits = 10;
static constexpr int ABits = 2;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ABGR8888> {
static constexpr int RShift = 0;
static constexpr int GShift = 8;
static constexpr int BShift = 16;
static constexpr int AShift = 24;
static constexpr int RBits = 8;
static constexpr int GBits = 8;
static constexpr int BBits = 8;
static constexpr int ABits = 8;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ARGB8888> {
static constexpr int RShift = 16;
static constexpr int GShift = 8;
static constexpr int BShift = 0;
static constexpr int AShift = 24;
static constexpr int RBits = 8;
static constexpr int GBits = 8;
static constexpr int BBits = 8;
static constexpr int ABits = 8;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_RGBA8888> {
static constexpr int RShift = 24;
static constexpr int GShift = 16;
static constexpr int BShift = 8;
static constexpr int AShift = 0;
static constexpr int RBits = 8;
static constexpr int GBits = 8;
static constexpr int BBits = 8;
static constexpr int ABits = 8;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_BGRA8888> {
static constexpr int RShift = 8;
static constexpr int GShift = 16;
static constexpr int BShift = 24;
static constexpr int AShift = 0;
static constexpr int RBits = 8;
static constexpr int GBits = 8;
static constexpr int BBits = 8;
static constexpr int ABits = 8;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ABGR4444> {
static constexpr int RShift = 0;
static constexpr int GShift = 4;
static constexpr int BShift = 8;
static constexpr int AShift = 12;
static constexpr int RBits = 4;
static constexpr int GBits = 4;
static constexpr int BBits = 4;
static constexpr int ABits = 4;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ARGB4444> {
static constexpr int RShift = 8;
static constexpr int GShift = 4;
static constexpr int BShift = 0;
static constexpr int AShift = 12;
static constexpr int RBits = 4;
static constexpr int GBits = 4;
static constexpr int BBits = 4;
static constexpr int ABits = 4;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_RGBA4444> {
static constexpr int RShift = 12;
static constexpr int GShift = 8;
static constexpr int BShift = 4;
static constexpr int AShift = 0;
static constexpr int RBits = 4;
static constexpr int GBits = 4;
static constexpr int BBits = 4;
static constexpr int ABits = 4;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_BGRA4444> {
static constexpr int RShift = 4;
static constexpr int GShift = 8;
static constexpr int BShift = 12;
static constexpr int AShift = 0;
static constexpr int RBits = 4;
static constexpr int GBits = 4;
static constexpr int BBits = 4;
static constexpr int ABits = 4;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ABGR1555> {
static constexpr int RShift = 0;
static constexpr int GShift = 5;
static constexpr int BShift = 10;
static constexpr int AShift = 15;
static constexpr int RBits = 5;
static constexpr int GBits = 5;
static constexpr int BBits = 5;
static constexpr int ABits = 1;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ARGB1555> {
static constexpr int RShift = 10;
static constexpr int GShift = 5;
static constexpr int BShift = 0;
static constexpr int AShift = 15;
static constexpr int RBits = 5;
static constexpr int GBits = 5;
static constexpr int BBits = 5;
static constexpr int ABits = 1;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_RGBA5551> {
static constexpr int RShift = 11;
static constexpr int GShift = 6;
static constexpr int BShift = 1;
static constexpr int AShift = 0;
static constexpr int RBits = 5;
static constexpr int GBits = 5;
static constexpr int BBits = 5;
static constexpr int ABits = 1;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_BGRA5551> {
static constexpr int RShift = 1;
static constexpr int GShift = 6;
static constexpr int BShift = 11;
static constexpr int AShift = 0;
static constexpr int RBits = 5;
static constexpr int GBits = 5;
static constexpr int BBits = 5;
static constexpr int ABits = 1;
};

View file

@ -1,9 +1,11 @@
#include "sdl_context.h"
#include "keyboard_map.h"
#include "format_mapping.h"
#include <atomic>
#include <cassert>
#include "../platform.h"
#include "../error.h"
#include <cmath>
#include <iostream>
@ -34,6 +36,9 @@ void SDLContext::SDL_Deleter::operator ()(SDL_Surface* surface) {
void SDLContext::SDL_Deleter::operator ()(SDL_Texture* texture) {
SDL_DestroyTexture(texture);
}
void SDLContext::SDL_Deleter::operator ()(SDL_PixelFormat* f) {
SDL_FreeFormat(f);
}
void SDLContext::SDL_Audio_Deleter::operator()(SDL_AudioDeviceID x) {
SDL_CloseAudioDevice(x);
@ -74,10 +79,24 @@ SDLContext::SDLContext() {
void handle_sdl_error(const char *msg) {
char buff[512];
snprintf(buff, sizeof(buff), "SDL critical error (check video driver): %s %s",msg, SDL_GetError());
snprintf(buff, sizeof(buff), "SDL critical error: %s %s",msg, SDL_GetError());
throw std::runtime_error(buff);
}
bool isFormatSupported(SDL_Renderer *renderer, Uint32 pixel_format) {
SDL_RendererInfo info;
if (SDL_GetRendererInfo(renderer, &info) != 0) {
handle_sdl_error("Failed to get renderer info");
return false;
}
for (Uint32 i = 0; i < info.num_texture_formats; ++i) {
if (info.texture_formats[i] == pixel_format) {
return true;
}
}
return false;
}
void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** texture, int width, int height, CrtFilterType type) {
@ -95,6 +114,8 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur
default: break;
}
if (type == CrtFilterType::scanlines || type == CrtFilterType::scanlines_2) {
width = 32;
} else {
@ -105,8 +126,11 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur
unsigned int mult_of_base = std::max<unsigned int>((height+240)/480,interfer);
height = height * interfer / mult_of_base;
}
// Vytvoř novou texturu ve správné velikosti
*texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height);
*texture = SDL_CreateTexture(renderer, _texture_render_format, SDL_TEXTUREACCESS_STREAMING, width, height);
if (!*texture) {
type = CrtFilterType::none;
return; //crt filter failed to create, do not use filter
@ -126,10 +150,12 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur
Uint32* pixelArray = (Uint32*)pixels;
if (type == CrtFilterType::scanlines) {
Uint32 darkPixel = 0xA0A0A0FF;
Uint32 transparentPixel = 0xFFFFFFC0;
Uint32 darkPixel = SDL_MapRGBA(_main_pixel_format.get(), 0xA0, 0xA0, 0xA0, 0xFF);
Uint32 transparentPixel = SDL_MapRGBA(_main_pixel_format.get(), 0xFF, 0xFF, 0xFF, 0xC0);
for (int y = 0; y < height; y++) {
Uint32 color = ((y & 1)== 0) ? darkPixel : transparentPixel;
@ -141,8 +167,8 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur
else if (type == CrtFilterType::scanlines_2) {
Uint32 darkPixel = 0x808080FF;
Uint32 transparentPixel = 0xFFFFFFE0;
Uint32 darkPixel = SDL_MapRGBA(_main_pixel_format.get(), 0x80, 0x80, 0x80, 0xFF);
Uint32 transparentPixel = SDL_MapRGBA(_main_pixel_format.get(), 0xFF, 0xFF, 0xFF, 0xE0);
for (int y = 0; y < height; y++) {
Uint32 color = (y % 3== 2) ? darkPixel : transparentPixel;
@ -152,10 +178,10 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur
}
} else {
static Uint32 red_pixel = 0xFF8080A0;
static Uint32 green_pixel = 0x80FF80A0;
static Uint32 blue_pixel = 0x8080FFA0;
static Uint32 dark_pixel = 0x000000C0;
static Uint32 red_pixel = SDL_MapRGBA(_main_pixel_format.get(), 0xFF, 0x80, 0x80, 0xA0);
static Uint32 green_pixel = SDL_MapRGBA(_main_pixel_format.get(), 0x80, 0xFF, 0x80, 0xA0);
static Uint32 blue_pixel = SDL_MapRGBA(_main_pixel_format.get(), 0x80, 0x80, 0xFF, 0xA0);
static Uint32 dark_pixel = SDL_MapRGBA(_main_pixel_format.get(), 0x0, 0x0, 0x00, 0xA0);
for (int y = 2; y < height; y++) {
if (type == CrtFilterType::rgb_matrix_2) {
for (int x = 2; x < width; x+=3) {
@ -199,6 +225,48 @@ static void crash_sdl_exception() {
abort();
}
// Seznam akceptovatelných formátů odpovídajících RGBA8888 (v různém pořadí)
constexpr Uint32 acceptable_formats[] = {
SDL_PIXELFORMAT_RGBA8888,
SDL_PIXELFORMAT_ARGB8888,
SDL_PIXELFORMAT_BGRA8888,
SDL_PIXELFORMAT_ABGR8888,
SDL_PIXELFORMAT_RGBA4444,
SDL_PIXELFORMAT_ARGB4444,
SDL_PIXELFORMAT_BGRA4444,
SDL_PIXELFORMAT_ABGR4444,
SDL_PIXELFORMAT_ARGB2101010,
};
constexpr bool is_acceptable_format(Uint32 format) {
for (size_t i = 0; i < sizeof(acceptable_formats)/sizeof(acceptable_formats[0]); ++i) {
if (format == acceptable_formats[i]) {
return true;
}
}
return false;
}
static Uint32 find_best_rgba_like_format(SDL_Renderer* renderer) {
SDL_RendererInfo info;
if (SDL_GetRendererInfo(renderer, &info) != 0) {
return 0;
}
if ((info.max_texture_width != 0 && info.max_texture_width < 640) ||
(info.max_texture_height!= 0 && info.max_texture_height < 480)) return 0;
for (Uint32 i = 0; i < info.num_texture_formats; ++i) {
Uint32 fmt = info.texture_formats[i];
if (is_acceptable_format(fmt)) {
return fmt;
}
}
return 0;
}
void SDLContext::init_video(const VideoConfig &config, const char *title) {
static Uint32 update_request_event = SDL_RegisterEvents(1);
@ -219,15 +287,17 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) {
_enable_crt = false;
}
_fullscreen_mode = config.fullscreen;
_mouse_size = config.cursor_size;
std::atomic<bool> done = false;
std::exception_ptr e;
std::string_view stage;
std::string rname;
_render_thread = std::jthread([&](std::stop_token stp){
bool err = false;
try {
stage = "window";
SDL_Window *window = SDL_CreateWindow(title,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
width, height, SDL_WINDOW_RESIZABLE|(_fullscreen_mode?SDL_WINDOW_FULLSCREEN_DESKTOP:0));
@ -237,13 +307,49 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) {
}
_window.reset(window);
SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, config.composer);
if (!renderer) {
handle_sdl_error("Failed to create composer");
auto composer = config.composer;
stage = "renderer";
while (true) {
SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, composer);
if (!renderer) {
if (config.composer & SDL_RENDERER_SOFTWARE) {
handle_sdl_error("Failed to create composer");
} else {
composer |= SDL_RENDERER_SOFTWARE;
continue;
}
}
_texture_render_format = find_best_rgba_like_format(renderer);
if (_texture_render_format == 0) {
if (composer & SDL_RENDERER_SOFTWARE) {
throw std::runtime_error("Failed to create composer, failed software fallback");
} else {
SDL_DestroyRenderer(renderer);
composer |= SDL_RENDERER_SOFTWARE;
continue;
}
}
_renderer.reset(renderer);
break;
}
SDL_RendererInfo rinfo;
SDL_GetRendererInfo(renderer, &rinfo);
SDL_GetRendererInfo(_renderer.get(), &rinfo);
rname = rinfo.name;
stage = "pixel format";
_main_pixel_format.reset(SDL_AllocFormat(_texture_render_format));
if (!_main_pixel_format) {
handle_sdl_error("Failed to create texture format");
}
if (istrcmp(config.scale_quality, "auto") == 0) {
if (rinfo.flags & SDL_RENDERER_ACCELERATED) {
@ -253,20 +359,30 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) {
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, config.scale_quality);
}
_renderer.reset(renderer);
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB1555, SDL_TEXTUREACCESS_STREAMING, 640, 480);
stage = "main render target";
SDL_Texture *texture = SDL_CreateTexture(_renderer.get(), _texture_render_format, SDL_TEXTUREACCESS_STREAMING, 640, 480);
if (!texture) {
handle_sdl_error("Failed to create render target");
}
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
_texture.reset(texture);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB1555, SDL_TEXTUREACCESS_STREAMING, 640, 480);
stage = "secondary render target";
texture = SDL_CreateTexture(_renderer.get(), _texture_render_format, SDL_TEXTUREACCESS_STREAMING, 640, 480);
if (!texture) {
handle_sdl_error("Failed to create second render target");
}
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
_texture2.reset(texture);
stage = "all done";
_visible_texture = _texture.get();
_hidden_texture = _texture2.get();
} catch (...) {
@ -294,7 +410,17 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) {
done.wait(false);
if (e) {
_render_thread.join();
std::rethrow_exception(e);
try {
std::rethrow_exception(e);
} catch (...) {
std::throw_with_nested(
std::runtime_error(std::string("Oops! The application couldn't start properly (problem during SDL initialization). Stage: [")
.append(stage).append("]\n\n"
"Renderer: ").append(rname).append("\n\n"
"This may be caused by outdated or missing graphics or audio drivers."
"To fix this, please try the following:\n- Restart your computer and try again\n- "
"Make sure your graphics and sound drivers are up to date.")));
}
}
@ -335,6 +461,102 @@ int SDLContext::adjust_deadzone(int v, short deadzone) {
return 0;
}
template<int shift>
constexpr Uint32 shift_bits_5(Uint32 val) {
if constexpr(shift > 0) {
return val << shift | shift_bits_5<shift-5>(val);
} else if constexpr(shift < 0) {
return val >> (-shift);
} else {
return val;
}
}
template<Uint32 pixel_format>
void SDLContext::convert_bitmap(const void *pixels, SDL_Rect rect, int pitch) {
constexpr auto RShift = FormatMapping<pixel_format>::RShift;
constexpr auto GShift = FormatMapping<pixel_format>::GShift;
constexpr auto BShift = FormatMapping<pixel_format>::BShift;
constexpr auto AShift = FormatMapping<pixel_format>::AShift;
constexpr auto RBits = FormatMapping<pixel_format>::RBits;
constexpr auto GBits = FormatMapping<pixel_format>::GBits;
constexpr auto BBits = FormatMapping<pixel_format>::BBits;
constexpr auto ABits = FormatMapping<pixel_format>::ABits;
const Uint16 *src = static_cast<const Uint16*>(pixels);
auto trg = converted_pixels.data();
for (int y = 0; y < rect.h; ++y) {
for (int x = 0; x < rect.w; ++x) {
Uint16 pixel = src[x];
Uint32 a = (pixel & 0x8000) ? 0 : 0x1F;
Uint32 r = ((pixel >> 10) & 0x1F);
Uint32 g = ((pixel >> 5) & 0x1F);
Uint32 b = (pixel & 0x1F);
r = shift_bits_5<RBits-5>(r);
g = shift_bits_5<GBits-5>(g);
b = shift_bits_5<BBits-5>(b);
a = shift_bits_5<ABits-5>(a);
trg[x] = (r << RShift) | (g << GShift) | (b << BShift) | (a << AShift);
}
trg += rect.w;
src = src + pitch / 2;
}
}
void SDLContext::update_texture_with_conversion(SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
{
SDL_Rect r;
if (rect) {
r = *rect;
} else {
SDL_QueryTexture(texture, nullptr, nullptr, &r.w, &r.h);
r.x = 0;
r.y = 0;
}
converted_pixels.clear();
converted_pixels.resize(r.w * r.h);
switch (_texture_render_format) {
case SDL_PIXELFORMAT_ABGR8888:
convert_bitmap<SDL_PIXELFORMAT_ABGR8888>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ARGB8888:
convert_bitmap<SDL_PIXELFORMAT_ARGB8888>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ARGB2101010:
convert_bitmap<SDL_PIXELFORMAT_ARGB2101010>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_RGBA8888:
convert_bitmap<SDL_PIXELFORMAT_RGBA8888>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_BGRA8888:
convert_bitmap<SDL_PIXELFORMAT_BGRA8888>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ABGR4444:
convert_bitmap<SDL_PIXELFORMAT_ABGR4444>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ARGB4444:
convert_bitmap<SDL_PIXELFORMAT_ARGB4444>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_BGRA4444:
convert_bitmap<SDL_PIXELFORMAT_BGRA4444>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_RGBA4444:
convert_bitmap<SDL_PIXELFORMAT_RGBA4444>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ABGR1555:
convert_bitmap<SDL_PIXELFORMAT_ABGR1555>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ARGB1555:
convert_bitmap<SDL_PIXELFORMAT_ARGB1555>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_RGBA5551:
convert_bitmap<SDL_PIXELFORMAT_RGBA5551>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_BGRA5551:
convert_bitmap<SDL_PIXELFORMAT_BGRA5551>(pixels, r, pitch);break;
default:
return;
}
if (SDL_UpdateTexture(texture, &r, converted_pixels.data(), r.w * 4) < 0) {
handle_sdl_error("Failed to update texture");
}
}
static int axis_dynamic(int c) {
double f = std::floor(std::pow(std::abs(c)*0.001,2)*0.025);
@ -698,19 +920,19 @@ void SDLContext::update_screen(bool force_refresh) {
SDL_Rect r;
pop_item(iter, r);
std::string_view data = pop_data(iter, r.w*r.h*2);
if (SDL_UpdateTexture(_texture.get(), &r, data.data(), r.w*2)<0) handle_sdl_error("Update of render target failed");
update_texture_with_conversion(_texture.get(), &r, data.data(), r.w*2);
}
break;
case DisplayRequest::show_mouse_cursor: {
SDL_Rect r;
pop_item(iter, r);
std::string_view data = pop_data(iter, r.w*r.h*2);
_mouse.reset(SDL_CreateTexture(_renderer.get(), SDL_PIXELFORMAT_ARGB1555,SDL_TEXTUREACCESS_STATIC, r.w, r.h));
_mouse.reset(SDL_CreateTexture(_renderer.get(), _texture_render_format,SDL_TEXTUREACCESS_STATIC, r.w, r.h));
if (!_mouse) handle_sdl_error("Failed to create surface for mouse cursor");
SDL_SetTextureBlendMode(_mouse.get(), SDL_BLENDMODE_BLEND);
_mouse_rect.w = r.w;
_mouse_rect.h = r.h;
if (SDL_UpdateTexture(_mouse.get(), NULL, data.data(), r.w*2)<0) handle_sdl_error("Update of mouse cursor failed");
update_texture_with_conversion(_mouse.get(), NULL, data.data(), r.w*2);
}
break;
case DisplayRequest::hide_mouse_cursor: {
@ -747,10 +969,10 @@ void SDLContext::update_screen(bool force_refresh) {
if (iter == _sprites.end()) {
iter = _sprites.insert(iter,{id});
}
iter->_txtr.reset(SDL_CreateTexture(_renderer.get(), SDL_PIXELFORMAT_ARGB1555, SDL_TEXTUREACCESS_STATIC,r.w, r.h));
iter->_txtr.reset(SDL_CreateTexture(_renderer.get(), _texture_render_format, SDL_TEXTUREACCESS_STATIC,r.w, r.h));
if (!iter->_txtr) handle_sdl_error("Failed to create compositor sprite");
SDL_SetTextureBlendMode(iter->_txtr.get(), SDL_BLENDMODE_BLEND);
if (SDL_UpdateTexture(iter->_txtr.get(), NULL, data.data(), r.w*2)<0) handle_sdl_error("Update of sprite failed");
update_texture_with_conversion(iter->_txtr.get(), NULL, data.data(), r.w*2);
iter->_rect = r;
update_zindex();
} break;
@ -851,10 +1073,8 @@ void SDLContext::push_update_msg(const SDL_Rect &rc, const uint16_t *data, int p
_display_update_queue.resize(sz+rc.w*rc.h*2);
short *trg = reinterpret_cast<short *>(_display_update_queue.data()+sz);
for (int yp = 0; yp < rc.h; ++yp) {
for (int xp = 0; xp < rc.w; ++xp) {
*trg = data[xp] ^ 0x8000;
++trg;
}
std::copy(data, data+rc.w, trg);
trg += rc.w;
data += pitch;
}
}
@ -1009,7 +1229,7 @@ void put_picture_ex(unsigned short x,unsigned short y,const void *p, unsigned sh
}
void SDLContext::push_hi_image(const unsigned short *image) {
SDL_Rect rc;
SDL_Rect rc = {};
rc.w= image[0];
rc.h =image[1];
push_item(rc);
@ -1019,7 +1239,6 @@ void SDLContext::push_hi_image(const unsigned short *image) {
unsigned short *trg = reinterpret_cast<unsigned short *>(_display_update_queue.data()+sz);
std::fill(trg, trg+imgsz, 0x8000);
put_picture_ex(0, 0, image, trg, rc.w);
std::transform(trg, trg+imgsz, trg, [](unsigned short &x)->unsigned short {return x ^ 0x8000;});
}
void SDLContext::show_mouse_cursor(const unsigned short *ms_hi_format, SDL_Point finger) {

View file

@ -170,6 +170,7 @@ protected:
void operator()(SDL_Renderer *);
void operator()(SDL_Surface *);
void operator()(SDL_Texture *);
void operator()(SDL_PixelFormat* f);
};
struct BlendTransitionReq {
@ -237,13 +238,16 @@ protected:
std::unique_ptr<SDL_Texture, SDL_Deleter> _texture2;
std::unique_ptr<SDL_Texture, SDL_Deleter> _crt_effect;
std::unique_ptr<SDL_Texture, SDL_Deleter> _mouse;
std::unique_ptr<SDL_PixelFormat, SDL_Deleter> _main_pixel_format;
unique_value<SDL_AudioDeviceID, SDL_Audio_Deleter> _audio;
SDL_Texture *_visible_texture;
SDL_Texture *_hidden_texture;
SDL_Texture *_visible_texture = nullptr;
SDL_Texture *_hidden_texture = nullptr;
uint32_t _texture_render_format = SDL_PIXELFORMAT_ARGB1555;
bool _fullscreen_mode = false;
bool _present = false;
bool _convert_format = false;
std::atomic<bool> _key_control = false;
std::atomic<bool> _key_shift = false;
std::atomic<bool> _key_capslock = false;
@ -252,11 +256,12 @@ protected:
std::vector<char> _display_update_queue;
std::vector<uint32_t> converted_pixels;
using QueueIter = const char *;
std::queue<uint16_t> _keyboard_queue;
SDL_Rect _mouse_rect;
SDL_Point _mouse_finger;
float _mouse_size;
float _mouse_size = 1;
SpriteList _sprites;
@ -307,4 +312,11 @@ protected:
void generate_j_event(int button, char up);
static int adjust_deadzone(int v, short deadzone);
void update_texture_with_conversion(SDL_Texture * texture,
const SDL_Rect * rect,
const void *pixels, int pitch);
template<Uint32 pixel_format>
void convert_bitmap(const void *pixels, SDL_Rect r, int pitch);
};

View file

@ -299,7 +299,8 @@ static void update_music_volume(){
float v = music_volume * master_volume;
for (int i = 0; i <2; i++)
sound_mixer.visit_track(music_track_id_base+i,[&](WaveMixer<2> &m){
m.set_channel_volume(v, v);
m.set_channel_volume(0, v);
m.set_channel_volume(1, v);
});
}

View file

@ -91,8 +91,8 @@ public:
} else {
(*iter) += value.left * vol[0];
++iter;
(*iter) += value.right * vol[0];
++iter;
(*iter) += value.right * vol[1];
std::advance(iter, channels-1);
}
}

View file

@ -1,6 +1,7 @@
#include "../../game/skeldal.h"
#include "../getopt.h"
#include "../platform.h"
#include "../error.h"
#include <iostream>
#include <string>
#include <sstream>
@ -86,7 +87,7 @@ int main(int argc, char **argv) {
}
} catch (const std::exception &e) {
cfg.show_error(e.what());
cfg.show_error(exception_to_string(e).c_str());
return 1;
}
catch (...) {

View file

@ -15,13 +15,17 @@ std::string getSavedGamesDirectory() {
PWSTR path = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_SavedGames, 0, NULL, &path))) {
fs::path savedGamesPath(path);
CoTaskMemFree(path);
return (savedGamesPath / SAVEGAME_FOLDERNAME).string();
CoTaskMemFree(path);
// Převod na UTF-8 std::string
std::u8string utf8 = (savedGamesPath / SAVEGAME_FOLDERNAME).u8string();
return std::string(reinterpret_cast<const char*>(utf8.data()), utf8.size());
} else {
display_error("Failed to retrieve FOLDEROD_SavedGames");
display_error("Failed to retrieve FOLDERID_SavedGames");
abort();
}
}
const char *get_default_savegame_directory() {
static std::string dir = getSavedGamesDirectory();