diff --git a/mlcc b/mlcc index 2fa83f71..a8dd521d 160000 --- a/mlcc +++ b/mlcc @@ -1 +1 @@ -Subproject commit 2fa83f7186879933b8348d4d888a1ac29b3c1a4d +Subproject commit a8dd521da1858413a115caae76ef9a174b7746f6 diff --git a/src/BattleSceneSekiro.cpp b/src/BattleSceneSekiro.cpp index 4cc646a6..e2453c57 100644 --- a/src/BattleSceneSekiro.cpp +++ b/src/BattleSceneSekiro.cpp @@ -1159,16 +1159,16 @@ void BattleSceneSekiro::backRun1() void BattleSceneSekiro::Action(Role* r) { - if (r->CoolDown == 0) + if (r->HaveAction) { - auto r1 = findNearestEnemy(r->Team, r->Pos); - if (r1) + if (r && !r->Dead && r->CoolDown == 0) { - r->RealTowards = r1->Pos - r->Pos; + auto r1 = findNearestEnemy(r->Team, r->Pos); + if (r1) + { + r->RealTowards = r1->Pos - r->Pos; + } } - } - if (r->HaveAction) - { //音效和动画 if (r->OperationType >= 0 //&& r->ActFrame == r->FightFrame[r->ActType] - 3 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2d65a632..879b5239 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,6 @@ file(GLOB SRC_LIST ../mlcc/strfunc.cpp ../mlcc/filefunc.cpp ../mlcc/PotConv.cpp - ../mlcc/Engine.cpp ../others/Hanz2Piny.cpp ) diff --git a/src/Engine.cpp b/src/Engine.cpp new file mode 100644 index 00000000..6243262b --- /dev/null +++ b/src/Engine.cpp @@ -0,0 +1,784 @@ +#include "Engine.h" +#ifdef _MSC_VER +#define NOMINMAX +#include +#pragma comment(lib, "user32.lib") +#endif + +#if defined(_WIN32) && defined(WITH_SMALLPOT) +#include "PotDll.h" +#endif + +Engine::Engine() +{ +} + +Engine::~Engine() +{ + destroy(); +} + +int Engine::init(void* handle /*= nullptr*/, int handle_type /*= 0*/, int maximized) +{ + if (inited_) + { + return 0; + } + inited_ = true; +#ifndef _WINDLL + if (SDL_Init(SDL_INIT_EVENTS | SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC)) + { + return -1; + } +#endif + window_mode_ = handle_type; + if (handle) + { + if (handle_type == 0) + { + window_ = SDL_CreateWindowFrom(handle); + } + else + { + window_ = (BP_Window*)handle; + } + } + else + { + uint32_t flags = SDL_WINDOW_RESIZABLE; + if (maximized) + { + flags |= SDL_WINDOW_MAXIMIZED; + } + window_ = SDL_CreateWindow(title_.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, start_w_, start_h_, flags); + } + //SDL_CreateWindowFrom() +#ifndef _WINDLL + SDL_ShowWindow(window_); + SDL_RaiseWindow(window_); +#endif + renderer_ = SDL_GetRenderer(window_); + fmt1::print("{}\n", SDL_GetError()); + if (renderer_ == nullptr) + { + renderer_ = SDL_CreateRenderer(window_, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE /*| SDL_RENDERER_PRESENTVSYNC*/); + renderer_self_ = true; + } + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); + SDL_EventState(SDL_DROPFILE, SDL_ENABLE); + + //屏蔽触摸板 + SDL_EventState(SDL_FINGERUP, SDL_DISABLE); + SDL_EventState(SDL_FINGERDOWN, SDL_DISABLE); + SDL_EventState(SDL_FINGERMOTION, SDL_DISABLE); + + //手柄 + if (SDL_NumJoysticks() < 1) + { + fmt1::print("Warning: No joysticks connected!\n"); + } + else + { + //按照游戏控制器打开 + game_controller_ = SDL_GameControllerOpen(0); + if (game_controller_) + { + fmt1::print("Found {} game controller(s)\n", SDL_NumJoysticks()); + std::string name = SDL_GameControllerName(game_controller_); + fmt1::print("{}\n", name); + if (name.find("Switch") != std::string::npos) { switch_ = 1; } + } + else + { + fmt1::print("Warning: Unable to open game controller! SDL Error: {}\n", SDL_GetError()); + } + } + + rect_ = { 0, 0, start_w_, start_h_ }; + logo_ = loadImage("logo.png"); + showLogo(); + renderPresent(); + TTF_Init(); + +#ifdef _MSC_VER + RECT r; + SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&r, 0); + int w = GetSystemMetrics(SM_CXEDGE); + int h = GetSystemMetrics(SM_CYEDGE); + min_x_ = r.left + w; + min_y_ = r.top + h + GetSystemMetrics(SM_CYCAPTION); + max_x_ = r.right - w; + max_y_ = r.bottom - h; +#else + BP_Rect r; + SDL_GetDisplayBounds(0, &r); + min_x_ = r.x; + min_y_ = r.y; + max_x_ = r.w + r.x; + max_y_ = r.h + r.y; +#endif + + square_ = createRectTexture(100, 100, 0); + + fmt1::print("maximum width and height are: {}, {}\n", max_x_, max_y_); +#if defined(_WIN32) && defined(WITH_SMALLPOT) && !defined(_DEBUG) + tinypot_ = PotCreateFromWindow(window_); +#endif + createMainTexture(start_w_, start_h_); + return 0; +} + +void Engine::destroy() +{ + destroyTexture(tex_); + destroyAssistTexture(); + if (renderer_self_) + { + SDL_DestroyRenderer(renderer_); + } + if (window_mode_ == 0) + { + SDL_DestroyWindow(window_); + } + +#ifndef _WINDLL + SDL_Quit(); +#endif +#if defined(_WIN32) && defined(WITH_SMALLPOT) && !defined(_DEBUG) + PotDestory(tinypot_); +#endif +} + +BP_Texture* Engine::createTexture(int pix_fmt, int w, int h) +{ + if (pix_fmt == SDL_PIXELFORMAT_UNKNOWN) + { + pix_fmt = SDL_PIXELFORMAT_RGB24; + } + return SDL_CreateTexture(renderer_, pix_fmt, SDL_TEXTUREACCESS_STREAMING, w, h); +} + +BP_Texture* Engine::createYUVTexture(int w, int h) +{ + return SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, w, h); +} + +void Engine::updateYUVTexture(BP_Texture* t, uint8_t* data0, int size0, uint8_t* data1, int size1, uint8_t* data2, int size2) +{ + SDL_UpdateYUVTexture(t, nullptr, data0, size0, data1, size1, data2, size2); +} + +BP_Texture* Engine::createARGBTexture(int w, int h) +{ + return SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h); +} + +BP_Texture* Engine::createARGBRenderedTexture(int w, int h) +{ + return SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, w, h); +} + +void Engine::updateARGBTexture(BP_Texture* t, uint8_t* buffer, int pitch) +{ + SDL_UpdateTexture(t, nullptr, buffer, pitch); +} + +int Engine::lockTexture(BP_Texture* t, BP_Rect* r, void** pixel, int* pitch) +{ + return SDL_LockTexture(t, r, pixel, pitch); +} + +void Engine::unlockTexture(BP_Texture* t) +{ + SDL_UnlockTexture(t); +} + +void Engine::renderCopy(BP_Texture* t, int x, int y, int w, int h, double angle, int inPresent) +{ + if (inPresent == 1) + { + x += rect_.x; + y += rect_.y; + } + BP_Rect r = { x, y, w, h }; + renderCopy(t, nullptr, &r, angle); +} + +void Engine::renderCopy(BP_Texture* t /*= nullptr*/, double angle) +{ + SDL_RenderCopyEx(renderer_, t, nullptr, &rect_, angle, nullptr, SDL_FLIP_NONE); + render_times_++; +} + +void Engine::renderPresent() +{ + renderMainTextureToWindow(); + SDL_RenderPresent(renderer_); + SDL_RenderClear(renderer_); + setRenderMainTexture(); +} + +void Engine::renderCopy(BP_Texture* t, BP_Rect* rect0, BP_Rect* rect1, double angle, int inPresent /*= 0*/) +{ + SDL_RenderCopyEx(renderer_, t, rect0, rect1, angle, nullptr, SDL_FLIP_NONE); + render_times_++; +} + +void Engine::getMouseState(int& x, int& y) +{ + SDL_GetMouseState(&x, &y); + int w, h; + getWindowSize(w, h); + x = x * start_w_ / w; + y = y * start_h_ / h; +} + +void Engine::setMouseState(int x, int y) +{ + SDL_WarpMouseInWindow(window_, x, y); +} + +int Engine::pollEvent(BP_Event& e) +{ + int r = SDL_PollEvent(&e); + if (switch_) + { + if (e.type == BP_CONTROLLERBUTTONDOWN || e.type == BP_CONTROLLERBUTTONUP) + { + auto& key = e.cbutton.button; + if (key == BP_CONTROLLER_BUTTON_A) { key = BP_CONTROLLER_BUTTON_B; } + else if (key == BP_CONTROLLER_BUTTON_B) { key = BP_CONTROLLER_BUTTON_A; } + else if (key == BP_CONTROLLER_BUTTON_X) { key = BP_CONTROLLER_BUTTON_Y; } + else if (key == BP_CONTROLLER_BUTTON_Y) { key = BP_CONTROLLER_BUTTON_X; } + } + } + return r; +} + +bool Engine::checkKeyPress(BP_Keycode key) +{ + return SDL_GetKeyboardState(NULL)[SDL_GetScancodeFromKey(key)]; +} + +bool Engine::gameControllerGetButton(int key) +{ + if (game_controller_) + { + if (switch_) + { + if (key == BP_CONTROLLER_BUTTON_A) { key = BP_CONTROLLER_BUTTON_B; } + else if (key == BP_CONTROLLER_BUTTON_B) { key = BP_CONTROLLER_BUTTON_A; } + else if (key == BP_CONTROLLER_BUTTON_X) { key = BP_CONTROLLER_BUTTON_Y; } + else if (key == BP_CONTROLLER_BUTTON_Y) { key = BP_CONTROLLER_BUTTON_X; } + } + return SDL_GameControllerGetButton(game_controller_, SDL_GameControllerButton(key)); + } + return false; +} + +int16_t Engine::gameControllerGetAxis(int axis) +{ + if (game_controller_) + { + return SDL_GameControllerGetAxis(game_controller_, SDL_GameControllerAxis(axis)); + } + return 0; +} + +void Engine::gameControllerRumble(int l, int h, uint32_t time) +{ + if (game_controller_) + { + auto s = SDL_GameControllerRumble(game_controller_, l * 65535 / 100, h * 65535 / 100, time); + } +} + +BP_Texture* Engine::createRectTexture(int w, int h, int style) +{ + auto square_s = SDL_CreateRGBSurface(0, w, h, 32, RMASK, GMASK, BMASK, AMASK); + + //SDL_FillRect(square_s, nullptr, 0xffffffff); + BP_Rect r = { 0, 0, 1, 1 }; + auto& x = r.x; + auto& y = r.y; + uint8_t a = 0; + for (x = 0; x < w; x++) + { + for (y = 0; y < h; y++) + { + int c; + if (style == 0) + { + a = 100 + 150 * cos(M_PI * (1.0 * y / w - 0.5)); + c = 0x00ffffff | (a << 24); + } + else if (style == 1) + { + c = 0xffffffff; + } + SDL_FillRect(square_s, &r, c); + /*if ((x - d / 2)*(x - d / 2) + (y - d / 2)*(y - d / 2) < (d / 2) * (d / 2)) + { + SDL_FillRect(square_s, &r, 0x00ffffff | (a<<24)); + }*/ + } + } + auto square = SDL_CreateTextureFromSurface(renderer_, square_s); + setTextureBlendMode(square); + //setTextureAlphaMod(square, 128); + SDL_FreeSurface(square_s); + return square; +} + +BP_Texture* Engine::createTextTexture(const std::string& fontname, const std::string& text, int size, BP_Color c) +{ + auto font = TTF_OpenFont(fontname.c_str(), size); + if (!font) + { + return nullptr; + } + //SDL_Color c = { 255, 255, 255, 128 }; + auto text_s = TTF_RenderUTF8_Blended(font, text.c_str(), c); + auto text_t = SDL_CreateTextureFromSurface(renderer_, text_s); + SDL_FreeSurface(text_s); + TTF_CloseFont(font); + return text_t; +} + +int Engine::getWindowWidth() +{ + int w, h; + getWindowSize(w, h); + return w; +} + +int Engine::getWindowHeight() +{ + int w, h; + getWindowSize(w, h); + return h; +} + +bool Engine::isFullScreen() +{ + Uint32 state = SDL_GetWindowFlags(window_); + full_screen_ = (state & SDL_WINDOW_FULLSCREEN) || (state & SDL_WINDOW_FULLSCREEN_DESKTOP); + return full_screen_; +} + +void Engine::toggleFullscreen() +{ + full_screen_ = !full_screen_; + if (full_screen_) + { + SDL_SetWindowFullscreen(window_, SDL_WINDOW_FULLSCREEN_DESKTOP); + } + else + { + SDL_SetWindowFullscreen(window_, 0); + } + renderClear(); +} + +BP_Texture* Engine::loadImage(const std::string& filename, int as_white) +{ + //fmt1::print("%s", filename.c_str()); + auto sur = IMG_Load(filename.c_str()); + if (as_white) { toWhite(sur); } + auto tex = SDL_CreateTextureFromSurface(renderer_, sur); + SDL_FreeSurface(sur); + return tex; +} + +BP_Texture* Engine::loadImageFromMemory(const std::string& content, int as_white) +{ + auto rw = SDL_RWFromConstMem(content.data(), content.size()); + auto sur = IMG_LoadTyped_RW(rw, 1, "png"); + if (as_white) { toWhite(sur); } + auto tex = SDL_CreateTextureFromSurface(renderer_, sur); + SDL_FreeSurface(sur); + return tex; +} + +void Engine::toWhite(BP_Surface* sur) +{ + for (int i = 0; i < sur->w * sur->h; i++) + { + auto p = (uint32_t*)sur->pixels + i; + uint8_t r, g, b, a; + SDL_GetRGBA(*p, sur->format, &r, &g, &b, &a); + if (a == 0) + { + *p = SDL_MapRGBA(sur->format, 255, 255, 255, 0); + } + else + { + *p = SDL_MapRGBA(sur->format, 255, 255, 255, 255); + } + } +} + +bool Engine::setKeepRatio(bool b) +{ + return keep_ratio_ = b; +} + +void Engine::createMainTexture(int w, int h) +{ + if (tex_) + { + SDL_DestroyTexture(tex_); + } + tex_ = createARGBRenderedTexture(w, h); + setPresentPosition(tex_); +} + +void Engine::resizeMainTexture(int w, int h) +{ + int w0, h0; + uint32_t pix_fmt; + if (!SDL_QueryTexture(tex_, &pix_fmt, nullptr, &w0, &h0)) + { + if (w0 != w || h0 != h) + { + //createMainTexture(pix_fmt, w, h); + } + } +} + +//创建一个专用于画场景的,后期放大 +void Engine::createAssistTexture(int w, int h) +{ + //tex_ = createYUVTexture(w, h); + tex2_ = createARGBRenderedTexture(w, h); + //tex_ = createARGBRenderedTexture(768, 480); + //SDL_SetTextureBlendMode(tex2_, SDL_BLENDMODE_BLEND); +} + +void Engine::setPresentPosition(BP_Texture* tex) +{ + if (!tex) + { + return; + } + int w_dst = 0, h_dst = 0; + int w_src = 0, h_src = 0; + getWindowSize(w_dst, h_dst); + SDL_QueryTexture(tex, nullptr, nullptr, &w_src, &h_src); + w_src *= ratio_x_; + h_src *= ratio_y_; + if (keep_ratio_) + { + if (w_src == 0 || h_src == 0) + { + return; + } + double ratio = std::min(1.0 * w_dst / w_src, 1.0 * h_dst / h_src); + if (rotation_ == 90 || rotation_ == 270) + { + ratio = std::min(1.0 * w_dst / h_src, 1.0 * h_dst / w_src); + } + rect_.x = (w_dst - w_src * ratio) / 2; + rect_.y = (h_dst - h_src * ratio) / 2; + rect_.w = w_src * ratio; + rect_.h = h_src * ratio; + } + else + { + //unfinshed + rect_.x = 0; + rect_.y = 0; + rect_.w = w_dst; + rect_.h = h_dst; + if (rotation_ == 90 || rotation_ == 270) + { + rect_.x = (h_dst - w_dst) / 2; + rect_.y = (w_dst - h_dst) / 2; + rect_.w = h_dst; + rect_.h = w_dst; + } + } +} + +BP_Texture* Engine::transBitmapToTexture(const uint8_t* src, uint32_t color, int w, int h, int stride) +{ + auto s = SDL_CreateRGBSurface(0, w, h, 32, 0xff000000, 0xff0000, 0xff00, 0xff); + SDL_FillRect(s, nullptr, color); + auto p = (uint8_t*)s->pixels; + for (int x = 0; x < w; x++) + { + for (int y = 0; y < h; y++) + { + p[4 * (y * w + x)] = src[y * stride + x]; + } + } + auto t = SDL_CreateTextureFromSurface(renderer_, s); + SDL_FreeSurface(s); + setTextureBlendMode(t); + setTextureAlphaMod(t, 192); + return t; +} + +int Engine::showMessage(const std::string& content) +{ + const SDL_MessageBoxButtonData buttons[] = { + { /* .flags, .buttonid, .text */ 0, 0, "no" }, + { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "yes" }, + { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 2, "cancel" }, + }; + const SDL_MessageBoxColorScheme colorScheme = { + { /* .colors (.r, .g, .b) */ + /* [SDL_MESSAGEBOX_COLOR_BACKGROUND] */ + { 255, 0, 0 }, + /* [SDL_MESSAGEBOX_COLOR_TEXT] */ + { 0, 255, 0 }, + /* [SDL_MESSAGEBOX_COLOR_BUTTON_BORDER] */ + { 255, 255, 0 }, + /* [SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND] */ + { 0, 0, 255 }, + /* [SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED] */ + { 255, 0, 255 } } + }; + const SDL_MessageBoxData messageboxdata = { + SDL_MESSAGEBOX_INFORMATION, /* .flags */ + NULL, /* .window */ + title_.c_str(), /* .title */ + content.c_str(), /* .message */ + SDL_arraysize(buttons), /* .numbuttons */ + buttons, /* .buttons */ + &colorScheme /* .colorScheme */ + }; + int buttonid; + SDL_ShowMessageBox(&messageboxdata, &buttonid); + return buttonid; +} + +void Engine::setWindowIsMaximized(bool b) +{ + if (b) + { + SDL_MaximizeWindow(window_); + } + else + { + SDL_RestoreWindow(window_); + } +} + +void Engine::setWindowSize(int w, int h) +{ + if (getWindowIsMaximized()) + { + return; + } + if (rotation_ == 90 || rotation_ == 270) + { + std::swap(w, h); + } + if (w <= 0 || h <= 0) + { + return; + } + //w = 1920; + //h = 1080; + win_w_ = std::min(max_x_ - min_x_, w); + win_h_ = std::min(max_y_ - min_y_, h); + double ratio; + ratio = std::min(1.0 * win_w_ / w, 1.0 * win_h_ / h); + win_w_ = w * ratio; + win_h_ = h * ratio; + //fmt1::print("{}, {}, {}, {}, {}\n", win_w_, win_h_, w, h, ratio); + if (!window_) + { + return; + } + + SDL_SetWindowSize(window_, win_w_, win_h_); + setPresentPosition(tex_); + + SDL_ShowWindow(window_); + SDL_RaiseWindow(window_); + SDL_GetWindowSize(window_, &win_w_, &win_h_); + //fmt1::print("{}, {}, {}, {}, {}\n", win_w_, win_h_, w, h, ratio); + //resetWindowsPosition(); + //renderPresent(); +} + +void Engine::resetWindowPosition() +{ + int x, y, w, h, x0, y0; + getWindowSize(w, h); + SDL_GetWindowPosition(window_, &x0, &y0); + x = std::max(min_x_, x0); + y = std::max(min_y_, y0); + if (x + w > max_x_) + { + x = std::min(x, max_x_ - w); + } + if (y + h > max_y_) + { + y = std::min(y, max_y_ - h); + } + if (x != x0 || y != y0) + { + setWindowPosition(x, y); + } +} + +void Engine::setColor(BP_Texture* tex, BP_Color c) +{ + SDL_SetTextureColorMod(tex, c.r, c.g, c.b); + setTextureAlphaMod(tex, c.a); + setTextureBlendMode(tex); +} + +void Engine::fillColor(BP_Color color, int x, int y, int w, int h) +{ + if (w < 0 || h < 0) + { + getWindowSize(w, h); + } + BP_Rect r{ x, y, w, h }; + SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, color.a); + SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); + SDL_RenderFillRect(renderer_, &r); +} + +void Engine::renderMainTextureToWindow() +{ + resetRenderTarget(); + renderCopy(tex_, nullptr, nullptr); +} + +void Engine::renderAssistTextureToWindow() +{ + setRenderTarget(tex_); + renderCopy(tex2_, nullptr, nullptr); +} + +void Engine::renderSquareTexture(BP_Rect* rect, BP_Color color, uint8_t alpha) +{ + color.a = alpha; + setColor(square_, color); + renderCopy(square_, nullptr, rect); +} + +void Engine::mixAudio(Uint8* dst, const Uint8* src, Uint32 len, int volume) +{ + SDL_MixAudioFormat(dst, src, audio_format_, len, volume); +} + +int Engine::openAudio(int& freq, int& channels, int& size, int minsize, AudioCallback f) +{ + SDL_AudioSpec want; + SDL_zero(want); + + fmt1::print("\naudio freq/channels: stream {}/{}, ", freq, channels); + if (channels <= 2) + { + channels = 2; + } + want.freq = freq; + want.format = AUDIO_S16; + want.channels = channels; + want.samples = size; + want.callback = mixAudioCallback; + //want.userdata = this; + want.silence = 0; + + audio_callback_ = f; + //if (useMap()) + { + want.samples = std::max(size, minsize); + } + + audio_device_ = 0; + int i = 10; + while (audio_device_ == 0 && i > 0) + { + audio_device_ = SDL_OpenAudioDevice(NULL, 0, &want, &audio_spec_, SDL_AUDIO_ALLOW_FORMAT_CHANGE); + want.channels--; + i--; + } + fmt1::print("device {}/{}\n", audio_spec_.freq, audio_spec_.channels); + + audio_format_ = audio_spec_.format; + + if (audio_device_) + { + SDL_PauseAudioDevice(audio_device_, 0); + } + else + { + fmt1::print("failed to open audio: {}\n", SDL_GetError()); + } + + freq = audio_spec_.freq; + channels = audio_spec_.channels; + + return 0; +} + +void Engine::mixAudioCallback(void* userdata, Uint8* stream, int len) +{ + SDL_memset(stream, 0, len); + if (getInstance()->audio_callback_) + { + getInstance()->audio_callback_(stream, len); + } +} +int Engine::playVideo(std::string filename) +{ + if (filename == "") + { + return 0; + } +#if defined(_WIN32) && defined(WITH_SMALLPOT) && !defined(_DEBUG) + return PotInputVideo(tinypot_, (char*)filename.c_str()); +#endif + return 0; +} + +int Engine::saveScreen(const char* filename) +{ + BP_Rect rect; + rect.x = 0; + rect.y = 0; + getWindowSize(rect.w, rect.h); + BP_Surface* sur = SDL_CreateRGBSurface(0, rect.w, rect.h, 32, RMASK, GMASK, BMASK, AMASK); + SDL_RenderReadPixels(renderer_, &rect, SDL_PIXELFORMAT_ARGB8888, sur->pixels, rect.w * 4); + SDL_SaveBMP(sur, filename); + SDL_FreeSurface(sur); + return 0; +} + +int Engine::saveTexture(BP_Texture* tex, const char* filename) +{ + BP_Rect rect; + rect.x = 0; + rect.y = 0; + queryTexture(tex, &rect.w, &rect.h); + setRenderTarget(tex); + BP_Surface* sur = SDL_CreateRGBSurface(0, rect.w, rect.h, 32, RMASK, GMASK, BMASK, AMASK); + SDL_RenderReadPixels(renderer_, &rect, SDL_PIXELFORMAT_ARGB8888, sur->pixels, rect.w * 4); + SDL_SaveBMP(sur, filename); + SDL_FreeSurface(sur); + resetRenderTarget(); + return 0; +} + +void Engine::setWindowPosition(int x, int y) +{ + int w, h; + getWindowSize(w, h); + if (x == BP_WINDOWPOS_CENTERED) + { + x = min_x_ + (max_x_ - min_x_ - w) / 2; + } + if (y == BP_WINDOWPOS_CENTERED) + { + y = min_y_ + (max_y_ - min_y_ - h) / 2; + } + SDL_SetWindowPosition(window_, x, y); +} diff --git a/src/Engine.h b/src/Engine.h new file mode 100644 index 00000000..7e6cdcf3 --- /dev/null +++ b/src/Engine.h @@ -0,0 +1,458 @@ +#pragma once + +#include "SDL2/SDL.h" +#include "SDL2/SDL_image.h" +#include "SDL2/SDL_ttf.h" + +#include +#include +#include +#include +#include +#include +#include + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX + +#include "fmt1.h" + +#ifndef M_PI +#define M_PI 3.1415926535897 +#endif + +//这里是底层部分,将SDL的函数均封装了一次 +//如需更换底层,则要重新实现下面的全部功能,并重新定义全部常数和类型 +#define BP_AUDIO_MIX_MAXVOLUME SDL_MIX_MAXVOLUME + +//每个SDL的函数和结构通常仅出现一次,其余的均用已封的功能完成 + +using AudioCallback = std::function; +using BP_Renderer = SDL_Renderer; +using BP_Window = SDL_Window; +using BP_Texture = SDL_Texture; +using BP_Rect = SDL_Rect; +using BP_Color = SDL_Color; +using BP_Keycode = SDL_Keycode; +using BP_Surface = SDL_Surface; +using BP_GameController = SDL_GameController; +using BP_Haptic = SDL_Haptic; + +enum BP_Align +{ + BP_ALIGN_LEFT, + BP_ALIGN_MIDDLE, + BP_ALIGN_RIGHT +}; + +#define BP_WINDOWPOS_CENTERED SDL_WINDOWPOS_CENTERED + +#define RMASK (0xff0000) +#define GMASK (0xff00) +#define BMASK (0xff) +#define AMASK (0xff000000) + +//声音类型在其他文件中未使用 +using BP_AudioSpec = SDL_AudioSpec; +//这里直接使用SDL的事件结构,如果更换底层需重新实现一套相同的 +using BP_Event = SDL_Event; + +class Engine +{ +private: + Engine(); + virtual ~Engine(); + +public: + static Engine* getInstance() + { + static Engine e; + return &e; + } + //图形相关 +private: + bool inited_ = false; + BP_Window* window_ = nullptr; + BP_Renderer* renderer_ = nullptr; + BP_Texture* tex_ = nullptr; + BP_Texture* tex2_ = nullptr; + BP_Texture* logo_ = nullptr; + BP_Rect rect_; + bool full_screen_ = false; + bool keep_ratio_ = true; + + int start_w_ = 1024, start_h_ = 640; + int win_w_, win_h_, min_x_, min_y_, max_x_, max_y_; + double rotation_ = 0; + double ratio_x_ = 1, ratio_y_ = 1; + + int render_times_ = 0; + + BP_GameController* game_controller_ = nullptr; + BP_Haptic* haptic_ = nullptr; + + int switch_ = 0; + + int window_mode_ = 0; //0-窗口和渲染器自行创建,1-窗口和渲染器由外部创建 + bool renderer_self_ = false; + +public: + int init(void* handle = nullptr, int handle_type = 0, int maximized = 0); + + void getWindowSize(int& w, int& h) { SDL_GetWindowSize(window_, &w, &h); } + void getWindowMaxSize(int& w, int& h) { SDL_GetWindowMaximumSize(window_, &w, &h); } + int getWindowWidth(); + int getWindowHeight(); + int getStartWindowWidth() { return start_w_; } + int getStartWindowHeight() { return start_h_; } + int getMaxWindowWidth() { return max_x_ - min_x_; } + int getMaxWindowHeight() { return max_y_ - min_y_; } + void getWindowPosition(int& x, int& y) { SDL_GetWindowPosition(window_, &x, &y); } + bool getWindowIsMaximized() { return SDL_GetWindowFlags(window_) & SDL_WINDOW_MAXIMIZED; } + void setWindowIsMaximized(bool b); + void setWindowSize(int w, int h); + void setStartWindowSize(int w, int h) + { + start_w_ = w; + start_h_ = h; + } + void getStartWindowSize(int& w, int& h) + { + w = start_w_; + h = start_h_; + } + void setWindowPosition(int x, int y); + void setWindowTitle(const std::string& str) { SDL_SetWindowTitle(window_, str.c_str()); } + BP_Renderer* getRenderer() { return renderer_; } + + void createMainTexture(int w, int h); + void resizeMainTexture(int w, int h); + void createAssistTexture(int w, int h); + void setPresentPosition(BP_Texture* tex); //设置贴图的位置 + //void getPresentSize(int& w, int& h) { w = rect_.w; h = rect_.h; } + int getPresentWidth() { return rect_.w; } + int getPresentHeight() { return rect_.h; } + BP_Texture* getMainTexture() { return tex_; } + void getMainTextureSize(int& w, int& h) { queryTexture(tex2_, &w, &h); } + void destroyAssistTexture() + { + if (tex2_) + { + destroyTexture(tex2_); + } + } + BP_Texture* createTexture(int pix_fmt, int w, int h); + static void destroyTexture(BP_Texture* t) { SDL_DestroyTexture(t); } + BP_Texture* createYUVTexture(int w, int h); + void updateYUVTexture(BP_Texture* t, uint8_t* data0, int size0, uint8_t* data1, int size1, uint8_t* data2, int size2); + BP_Texture* createARGBTexture(int w, int h); + BP_Texture* createARGBRenderedTexture(int w, int h); + static void updateARGBTexture(BP_Texture* t, uint8_t* buffer, int pitch); + static int lockTexture(BP_Texture* t, BP_Rect* r, void** pixel, int* pitch); + static void unlockTexture(BP_Texture* t); + void renderCopy(BP_Texture* t = nullptr, double angle = 0); + void showLogo() { renderCopy(logo_, nullptr, nullptr); } + void renderPresent(); + void renderClear() { SDL_RenderClear(renderer_); } + void setTextureAlphaMod(BP_Texture* t, uint8_t alpha) { SDL_SetTextureAlphaMod(t, alpha); } + void queryTexture(BP_Texture* t, int* w, int* h) { SDL_QueryTexture(t, nullptr, nullptr, w, h); } + void setRenderTarget(BP_Texture* t) { SDL_SetRenderTarget(renderer_, t); } + BP_Texture* getRenderTarget() { return SDL_GetRenderTarget(renderer_); } + void resetRenderTarget() { setRenderTarget(nullptr); } + void createWindow() {} + void createRenderer() {} + void renderCopy(BP_Texture* t, int x, int y, int w = 0, int h = 0, double angle = 0, int inPresent = 0); + void renderCopy(BP_Texture* t, BP_Rect* rect0, BP_Rect* rect1, double angle = 0, int inPresent = 0); + void destroy(); + bool isFullScreen(); + void toggleFullscreen(); + BP_Texture* loadImage(const std::string& filename, int as_white = 0); + BP_Texture* loadImageFromMemory(const std::string& content, int as_white = 0); + void toWhite(BP_Surface* sur); + bool setKeepRatio(bool b); + BP_Texture* transBitmapToTexture(const uint8_t* src, uint32_t color, int w, int h, int stride); + double setRotation(double r) { return rotation_ = r; } + void resetWindowPosition(); + void setRatio(double x, double y) + { + ratio_x_ = x; + ratio_y_ = y; + } + void setColor(BP_Texture* tex, BP_Color c); + void fillColor(BP_Color color, int x, int y, int w, int h); + void setRenderMainTexture() { setRenderTarget(tex_); } + void renderMainTextureToWindow(); + void setRenderAssistTexture() { setRenderTarget(tex2_); } + void renderAssistTextureToWindow(); + int setTextureBlendMode(BP_Texture* t) { return SDL_SetTextureBlendMode(t, SDL_BLENDMODE_BLEND); } + + void resetRenderTimes(int t = 0) { render_times_ = t; } + int getRenderTimes() { return render_times_; } + + BP_Texture* getRenderAssistTexture() { return tex2_; } + + //声音相关 +private: + SDL_AudioDeviceID audio_device_; + AudioCallback audio_callback_ = nullptr; + SDL_AudioFormat audio_format_ = AUDIO_S16; + BP_AudioSpec audio_spec_; + +public: + void pauseAudio(int pause) { SDL_PauseAudioDevice(audio_device_, pause); } + void closeAudio() { SDL_CloseAudioDevice(audio_device_); }; + static int getMaxVolume() { return BP_AUDIO_MIX_MAXVOLUME; }; + void mixAudio(Uint8* dst, const Uint8* src, Uint32 len, int volume); + SDL_AudioFormat getAudioFormat() { return audio_format_; } + int openAudio(int& freq, int& channels, int& size, int minsize, AudioCallback f); + static void mixAudioCallback(void* userdata, Uint8* stream, int len); + void setAudioCallback(AudioCallback cb = nullptr) { audio_callback_ = cb; } + + //事件相关 +private: + uint64_t time_; + +public: + static void delay(double t) { std::this_thread::sleep_for(std::chrono::nanoseconds(int64_t(t * 1e6))); } + static double getTicks() { return 1e-6 * std::chrono::time_point_cast(std::chrono::steady_clock::now()).time_since_epoch().count(); } + uint64_t tic() { return time_ = getTicks(); } + void toc() + { + if (getTicks() != time_) + { + fmt1::print("{}\n", getTicks() - time_); + } + } + void getMouseState(int& x, int& y); + void setMouseState(int x, int y); + int pollEvent(BP_Event& e); + static int pollEvent() { return SDL_PollEvent(nullptr); } + static int pushEvent(BP_Event& e) { return SDL_PushEvent(&e); } + static void flushEvent() { SDL_FlushEvent(0); } + static void free(void* mem) { SDL_free(mem); } + static bool checkKeyPress(BP_Keycode key); + bool gameControllerGetButton(int key); + int16_t gameControllerGetAxis(int axis); + + void gameControllerRumble(int l, int h, uint32_t time); + + //UI相关 +private: + BP_Texture* square_; + +public: + BP_Texture* createRectTexture(int w, int h, int style); + BP_Texture* createTextTexture(const std::string& fontname, const std::string& text, int size, BP_Color c); + int showMessage(const std::string& content); + void renderSquareTexture(BP_Rect* rect, BP_Color color, uint8_t alpha); + +public: + //标题; + std::string title_ = "All Heroes in Kam Yung Stories"; + +private: + void* tinypot_ = nullptr; + +public: + int playVideo(std::string filename); + int saveScreen(const char* filename); + int saveTexture(BP_Texture* tex, const char* filename); + + //输入相关 + void startTextInput() { SDL_StartTextInput(); } + void stopTextInput() { SDL_StopTextInput(); } + void setTextInputRect(int x, int y, int w = 0, int h = 0) + { + BP_Rect r = { x, y, w, h }; + SDL_SetTextInputRect(&r); + } +}; + +//这里直接照搬SDL +//更换底层需自己定义一套 +//好像是瞎折腾 +enum BP_EventType +{ + BP_FIRSTEVENT = SDL_FIRSTEVENT, + //按关闭按钮 + BP_QUIT = SDL_QUIT, + //window + BP_WINDOWEVENT = SDL_WINDOWEVENT, + BP_SYSWMEVENT = SDL_SYSWMEVENT, + //键盘 + BP_KEYDOWN = SDL_KEYDOWN, + BP_KEYUP = SDL_KEYUP, + BP_TEXTEDITING = SDL_TEXTEDITING, + BP_TEXTINPUT = SDL_TEXTINPUT, + //鼠标 + BP_MOUSEMOTION = SDL_MOUSEMOTION, + BP_MOUSEBUTTONDOWN = SDL_MOUSEBUTTONDOWN, + BP_MOUSEBUTTONUP = SDL_MOUSEBUTTONUP, + BP_MOUSEWHEEL = SDL_MOUSEWHEEL, + //手柄 + BP_JOYAXISMOTION = SDL_JOYAXISMOTION, + BP_JOYBALLMOTION = SDL_JOYBALLMOTION, + BP_JOYHATMOTION = SDL_JOYHATMOTION, + BP_JOYBUTTONDOWN = SDL_JOYBUTTONDOWN, + BP_JOYBUTTONUP = SDL_JOYBUTTONUP, + BP_JOYDEVICEADDED = SDL_JOYDEVICEADDED, + BP_JOYDEVICEREMOVED = SDL_JOYDEVICEREMOVED, + //游戏控制器 + BP_CONTROLLERAXISMOTION = SDL_CONTROLLERAXISMOTION, + BP_CONTROLLERBUTTONDOWN = SDL_CONTROLLERBUTTONDOWN, + BP_CONTROLLERBUTTONUP = SDL_CONTROLLERBUTTONUP, + BP_CONTROLLERDEVICEADDED = SDL_CONTROLLERDEVICEADDED, + BP_CONTROLLERDEVICEREMOVED = SDL_CONTROLLERDEVICEREMOVED, + BP_CONTROLLERDEVICEREMAPPED = SDL_CONTROLLERDEVICEREMAPPED, + + //剪贴板 + BP_CLIPBOARDUPDATE = SDL_CLIPBOARDUPDATE, + //拖放文件 + BP_DROPFILE = SDL_DROPFILE, + //渲染改变 + BP_RENDER_TARGETS_RESET = SDL_RENDER_TARGETS_RESET, + + BP_LASTEVENT = SDL_LASTEVENT +}; + +enum BP_WindowEventID +{ + BP_WINDOWEVENT_NONE = SDL_WINDOWEVENT_NONE, /**< Never used */ + BP_WINDOWEVENT_SHOWN = SDL_WINDOWEVENT_SHOWN, + BP_WINDOWEVENT_HIDDEN = SDL_WINDOWEVENT_HIDDEN, + BP_WINDOWEVENT_EXPOSED = SDL_WINDOWEVENT_EXPOSED, + + BP_WINDOWEVENT_MOVED = SDL_WINDOWEVENT_MOVED, + + BP_WINDOWEVENT_RESIZED = SDL_WINDOWEVENT_RESIZED, + BP_WINDOWEVENT_SIZE_CHANGED = SDL_WINDOWEVENT_SIZE_CHANGED, + BP_WINDOWEVENT_MINIMIZED = SDL_WINDOWEVENT_MINIMIZED, + BP_WINDOWEVENT_MAXIMIZED = SDL_WINDOWEVENT_MAXIMIZED, + BP_WINDOWEVENT_RESTORED = SDL_WINDOWEVENT_RESTORED, + + BP_WINDOWEVENT_ENTER = SDL_WINDOWEVENT_ENTER, + BP_WINDOWEVENT_LEAVE = SDL_WINDOWEVENT_LEAVE, + BP_WINDOWEVENT_FOCUS_GAINED = SDL_WINDOWEVENT_FOCUS_GAINED, + BP_WINDOWEVENT_FOCUS_LOST = SDL_WINDOWEVENT_FOCUS_LOST, + BP_WINDOWEVENT_CLOSE = SDL_WINDOWEVENT_CLOSE +}; + +enum BP_KeyBoard +{ + BPK_LEFT = SDLK_LEFT, + BPK_RIGHT = SDLK_RIGHT, + BPK_UP = SDLK_UP, + BPK_DOWN = SDLK_DOWN, + BPK_SPACE = SDLK_SPACE, + BPK_ESCAPE = SDLK_ESCAPE, + BPK_RETURN = SDLK_RETURN, + BPK_DELETE = SDLK_DELETE, + BPK_BACKSPACE = SDLK_BACKSPACE, + BPK_TAB = SDLK_TAB, + BPK_0 = SDLK_0, + BPK_1 = SDLK_1, + BPK_2 = SDLK_2, + BPK_3 = SDLK_3, + BPK_4 = SDLK_4, + BPK_PLUS = SDLK_PLUS, + BPK_COMMA = SDLK_COMMA, + BPK_MINUS = SDLK_MINUS, + BPK_PERIOD = SDLK_PERIOD, + BPK_EQUALS = SDLK_EQUALS, + BPK_a = SDLK_a, + BPK_b = SDLK_b, + BPK_c = SDLK_c, + BPK_d = SDLK_d, + BPK_e = SDLK_e, + BPK_f = SDLK_f, + BPK_g = SDLK_g, + BPK_h = SDLK_h, + BPK_i = SDLK_i, + BPK_j = SDLK_j, + BPK_k = SDLK_k, + BPK_l = SDLK_l, + BPK_m = SDLK_m, + BPK_n = SDLK_n, + BPK_o = SDLK_o, + BPK_p = SDLK_p, + BPK_q = SDLK_q, + BPK_r = SDLK_r, + BPK_s = SDLK_s, + BPK_t = SDLK_t, + BPK_u = SDLK_u, + BPK_v = SDLK_v, + BPK_w = SDLK_w, + BPK_x = SDLK_x, + BPK_y = SDLK_y, + BPK_z = SDLK_z, + BPK_PAGEUP = SDLK_PAGEUP, + BPK_PAGEDOWN = SDLK_PAGEDOWN, +}; + +enum BP_Button +{ + BP_BUTTON_LEFT = SDL_BUTTON_LEFT, + BP_BUTTON_MIDDLE = SDL_BUTTON_MIDDLE, + BP_BUTTON_RIGHT = SDL_BUTTON_RIGHT +}; + +enum BP_State +{ + BP_PRESSED = SDL_PRESSED, + BP_RELEASED = SDL_RELEASED, +}; + +enum BP_GameControllerButton +{ + //xbox + BP_CONTROLLER_BUTTON_INVALID = SDL_CONTROLLER_BUTTON_INVALID, + BP_CONTROLLER_BUTTON_A = SDL_CONTROLLER_BUTTON_A, + BP_CONTROLLER_BUTTON_B = SDL_CONTROLLER_BUTTON_B, + BP_CONTROLLER_BUTTON_X = SDL_CONTROLLER_BUTTON_X, + BP_CONTROLLER_BUTTON_Y = SDL_CONTROLLER_BUTTON_Y, + BP_CONTROLLER_BUTTON_BACK = SDL_CONTROLLER_BUTTON_BACK, + BP_CONTROLLER_BUTTON_GUIDE = SDL_CONTROLLER_BUTTON_GUIDE, + BP_CONTROLLER_BUTTON_START = SDL_CONTROLLER_BUTTON_START, + BP_CONTROLLER_BUTTON_LEFTSTICK = SDL_CONTROLLER_BUTTON_LEFTSTICK, + BP_CONTROLLER_BUTTON_RIGHTSTICK = SDL_CONTROLLER_BUTTON_RIGHTSTICK, + BP_CONTROLLER_BUTTON_LEFTSHOULDER = SDL_CONTROLLER_BUTTON_LEFTSHOULDER, + BP_CONTROLLER_BUTTON_RIGHTSHOULDER = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, + BP_CONTROLLER_BUTTON_DPAD_UP = SDL_CONTROLLER_BUTTON_DPAD_UP, + BP_CONTROLLER_BUTTON_DPAD_DOWN = SDL_CONTROLLER_BUTTON_DPAD_DOWN, + BP_CONTROLLER_BUTTON_DPAD_LEFT = SDL_CONTROLLER_BUTTON_DPAD_LEFT, + BP_CONTROLLER_BUTTON_DPAD_RIGHT = SDL_CONTROLLER_BUTTON_DPAD_RIGHT, + BP_CONTROLLER_BUTTON_MISC1 = SDL_CONTROLLER_BUTTON_MISC1, + BP_CONTROLLER_BUTTON_PADDLE1 = SDL_CONTROLLER_BUTTON_PADDLE1, + BP_CONTROLLER_BUTTON_PADDLE2 = SDL_CONTROLLER_BUTTON_PADDLE2, + BP_CONTROLLER_BUTTON_PADDLE3 = SDL_CONTROLLER_BUTTON_PADDLE3, + BP_CONTROLLER_BUTTON_PADDLE4 = SDL_CONTROLLER_BUTTON_PADDLE4, + BP_CONTROLLER_BUTTON_TOUCHPAD = SDL_CONTROLLER_BUTTON_TOUCHPAD, + BP_CONTROLLER_BUTTON_MAX = SDL_CONTROLLER_BUTTON_MAX, +}; + +enum BP_GameControllerAxis +{ + BP_CONTROLLER_AXIS_INVALID = SDL_CONTROLLER_AXIS_INVALID, + BP_CONTROLLER_AXIS_LEFTX = SDL_CONTROLLER_AXIS_LEFTX, + BP_CONTROLLER_AXIS_LEFTY = SDL_CONTROLLER_AXIS_LEFTY, + BP_CONTROLLER_AXIS_RIGHTX = SDL_CONTROLLER_AXIS_RIGHTX, + BP_CONTROLLER_AXIS_RIGHTY = SDL_CONTROLLER_AXIS_RIGHTY, + BP_CONTROLLER_AXIS_TRIGGERLEFT = SDL_CONTROLLER_AXIS_TRIGGERLEFT, + BP_CONTROLLER_AXIS_TRIGGERRIGHT = SDL_CONTROLLER_AXIS_TRIGGERRIGHT, + BP_CONTROLLER_AXIS_MAX = SDL_CONTROLLER_AXIS_MAX, +}; + +//mingw无std::mutex +#ifdef __MINGW32__ +class mutex +{ +private: + SDL_mutex* _mutex; + +public: + mutex() { _mutex = SDL_CreateMutex(); } + ~mutex() { SDL_DestroyMutex(_mutex); } + int lock() { return SDL_LockMutex(_mutex); } + int unlock() { return SDL_UnlockMutex(_mutex); } +}; +#endif diff --git a/src/Head.cpp b/src/Head.cpp index 93cbb3a6..cdbeb70f 100644 --- a/src/Head.cpp +++ b/src/Head.cpp @@ -160,7 +160,7 @@ void Head::draw() { font->draw(m->Name, 15, x_ + Font::getTextDrawSize(role_->Name) * 10 + 30, y_ + 5, white); } - font->draw(fmt1::format("{}/{}", role_->HP, role_->MaxHP), 12, x_ + 10, y_ + 25, white); + font->draw(fmt1::format("{}/{}", role_->HP, role_->MaxHP), 12, x_ + width_ + 10, y_ + 25, white); int length = std::max(0.0, role_->Posture * 5); int w_tex = TextureManager::getInstance()->getTexture("title", 203)->w; int h_tex = TextureManager::getInstance()->getTexture("title", 203)->h; diff --git a/src/kys.vcxproj b/src/kys.vcxproj index 2c620921..f3c27a05 100644 --- a/src/kys.vcxproj +++ b/src/kys.vcxproj @@ -100,7 +100,7 @@ - + @@ -162,7 +162,7 @@ - + diff --git a/src/kys.vcxproj.filters b/src/kys.vcxproj.filters index 1610b47e..cd57e515 100644 --- a/src/kys.vcxproj.filters +++ b/src/kys.vcxproj.filters @@ -178,8 +178,8 @@ battle - - mlcc + + engine @@ -360,9 +360,6 @@ battle - - mlcc - mlcc @@ -375,6 +372,9 @@ mlcc + + engine + @@ -430,6 +430,9 @@ {52c8cf7c-440e-4bd0-ad8e-5f6f1a23576a} + + {28899186-132a-450b-923e-6b29745a6d18} +