Files
2026-09-03 17:14:24 +08:00

804 lines
18 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "dl_system.h"
#include <cstdio>
#include <cstdlib>
#include <iostream>
#ifndef DL_DISABLE_RENDER
#if DL_PLATFORM == DL_PLATFORM_WIN32
#include <Windows.h>
#include <iptypes.h>
#include <iphlpapi.h>
#pragma comment(lib, "Winmm.lib")
#pragma comment(lib, "IPHLPAPI.lib")
// glfw必须包含在windows.h后面
#include <GLFW/glfw3.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h>
#elif DL_PLATFORM == DL_PLATFORM_LINUX
#include <GLFW/glfw3.h>
#define GLFW_EXPOSE_NATIVE_X11
#include <GLFW/glfw3native.h>
#undef Bool
#elif DL_PLATFORM == DL_PLATFORM_ANDROID
#include "system/dl_android.h"
#elif DL_PLATFORM == DL_PLATFORM_APPLE
#include <GLFW/glfw3.h>
#include <unistd.h>
#include <pwd.h>
#endif
#include "io/dl_log.h"
#include "dl_time.h"
#include "vk/dl_vk.h"
#include "io/dl_json.h"
#include "render/dl_factory.h"
#include "io/dl_input.h"
#include "math/dl_physics.h"
#include "render/dl_action.h"
#include "ui/dl_ui_manager.h"
#include "system/dl_audio.h"
#include "ui/dl_ui_scene.h"
#include "script/dl_lua.h"
#include "memory/dl_crypto.h"
#include "system/dl_infoware.h"
namespace dl
{
System* g_system;
class SystemImp
{
public:
SystemImp() :
_window{ nullptr },
_monitor{ nullptr },
_bClearCursorDt{ false }
{}
GLFWwindow* _window;
GLFWmonitor* _monitor;// 主显示器
// 是否清空光标差值(切换光标模式时使用,移动平台始终为false)
bool _bClearCursorDt;
};
//大小变化回调函数(创建窗口不会调用)
static void CallbackFrameBufferResize(GLFWwindow* window, int width, int height)
{
g_system->_resize();
}
static void CallbackKey(GLFWwindow* window, int key, int scancode, int action, int mods)
{
#if DL_PLATFORM != DL_PLATFORM_ANDROID
//action GLFW_PRESS
//mods GLFW_MOD_SHIFT
/*if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);*/
if (key < 0)
{
log_msg0("未知按键消息");
return;
}
g_input->_set_key(key, action);
if (action == GLFW_REPEAT
|| action == GLFW_PRESS)
{
g_ui->_on_key(key,
mods & GLFW_MOD_CONTROL);
}
/*mods& GLFW_MOD_CONTROL,
mods& GLFW_MOD_SHIFT,
mods& GLFW_MOD_ALT,
mods& GLFW_MOD_SUPER,
mods& GLFW_MOD_CAPS_LOCK,
mods& GLFW_MOD_NUM_LOCK*/
#endif
}
static void CallbackChar(GLFWwindow* window, unsigned int codepoint)
{
g_ui->_on_char((char32_t)codepoint);
//string str = CodeCvt::cvt_wc_u8(std::wstring_view((wchar_t*)&codepoint, 1));
//debug_test(format("打字:{}", str));
}
static void CallbackCursorPos(GLFWwindow* window, double xpos, double ypos)
{
bool& clear = g_system->GetImp()->_bClearCursorDt;
#if 0
float scale_x;
float scale_y;
glfwGetWindowContentScale(window, &scale_x, &scale_y);
g_input->_set_cursor((int)(xpos * scale_x), (int)(ypos * scale_y), clear);
clear = false;
#else
g_input->_set_cursor((int)xpos, (int)ypos, clear);
clear = false;
#endif
//debug_test(format("光标移动:{}, {}", xpos, ypos));
}
static void CallbackMouseButton(GLFWwindow* window, int button, int action, int mods)
{
/*if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
popup_menu();*/
g_input->_set_key_mouse(button, action);
}
static void CallbackScroll(GLFWwindow* window, double dx, double dy)
{
g_input->_set_scroll(dx, -dy);
//log_test("滚动操作:{}, {}", dx, -dy);
}
void CallbackDrop(GLFWwindow* window, int count, const char** paths)
{
for (int i = 0; i < count; ++i)
g_system->_add_drop_file(String::CvtPathSeparator(paths[i]));
}
System::System() :
_funcInit{ nullptr },
_funcRun{ nullptr },
_fullScreenMode{ FullScreenMode::WINDOW },
_step{ SystemStep::START },
_dir{ WindowDirection::UP }
{
_imp = new SystemImp;
}
System::~System()
{
delete _imp;
}
void System::Start(const ParamWindow& param)
{
if (!_start_init(param))
return;
//
while (!glfwWindowShouldClose(_imp->_window))
{
_step = SystemStep::UPDATE;
g_time->_update_pre();//计时
g_input->_update();// 覆盖旧状态
glfwPollEvents();
g_input->_update_late();
g_physics->Update();// 计算物理
g_ui->_update_pre();
g_ui->_update();
g_action->_update();
g_scene->_update_pre();
g_scene->_update();
if (_funcRun)
_funcRun();//帧函数
g_factory->_render_rt();
if (_lua._funcRun)
g_lua->CallFunction(_lua._funcRun);
_step = SystemStep::RENDER;
g_factory->_clear_pickup(); // 统一在Render处理OrderPickup
g_ui->_render();
g_scene->_render();
g_factory->_render_pickup();
g_factory->_auto_render();
//-----------------vk------------------
// 在 Update之前 禁止写入GPU可见内容
g_vk->Update();
g_factory->_clear_render();
g_vk->Render(_imp->_window);
g_vk->RenderEnd();
//
g_time->_sleep();// 延时
g_time->_update();//计时
}
_step = SystemStep::RELEASE;
#if (DL_PLATFORM == DL_PLATFORM_WIN32)
timeEndPeriod(1);
#endif
}
void System::Start(std::string_view json_window, std::string_view json_path)
{
auto fn_load_path = [&](){
if (json_path.empty())
return;
json j = Json::ParseFile(json_path);
if (j.is_null())
return;
g_factory->SetPath(
j["image"].get<std::string_view>(),
j["model"].get<std::string_view>(),
j["binary"].get<std::string_view>(),
j["temp"].get<std::string_view>());
//删除输出目录
bool delete_binary = false;
bool delete_2d = false;
bool delete_3d = false;
Json::Get(j, "delete_binary", delete_binary);
Json::Get(j, "delete_2d", delete_2d);
Json::Get(j, "delete_3d", delete_3d);
g_factory->DeleteBinary(delete_binary, delete_2d, delete_3d);
g_audio->SetPath(j["audio"].get<std::string_view>());
};
ParamWindow param_window;
auto fn_load_window = [&]() {
if (json_window.empty())
return;
json j = Json::ParseFile(json_window);
if (j.is_null())
return;
Json::Get(j, "title", param_window._strTitle);
Json::Get(j, "size", param_window._size);
};
fn_load_path();
fn_load_window();
return Start(param_window);
}
void System::Exit()
{
glfwSetWindowShouldClose(_imp->_window, 1);
}
void System::_convert_glfw_to_system(Point& xy)
{
switch (_dir)
{
case dl::WindowDirection::UP:
break;
case dl::WindowDirection::RIGHT:
{
int width, height;
_get_window_size(width, height);
int x = xy[1];
int y = width - xy[0];
xy[0] = x;
xy[1] = y;
}
break;
case dl::WindowDirection::DOWN:
break;
case dl::WindowDirection::LEFT:
break;
default:
break;
}
}
void System::_convert_system_to_glfw(Point& xy)
{
switch (_dir)
{
case dl::WindowDirection::UP:
break;
case dl::WindowDirection::RIGHT:
{
int width, height;
_get_window_size(width, height);
int x = xy[1];
int y = width - xy[0];
xy[0] = x;
xy[1] = y;
}
break;
case dl::WindowDirection::DOWN:
break;
case dl::WindowDirection::LEFT:
break;
default:
break;
}
}
void System::_get_window_size(int& w, int& h)
{
glfwGetFramebufferSize(_imp->_window, &w, &h);
}
void System::SetCursorPosition(Point xy)
{
_convert_system_to_glfw(xy);
glfwSetCursorPos(_imp->_window, xy[0], xy[1]);
}
Size System::GetWindowSize()
{
int width, height;
_get_window_size(width, height);
if (_dir == WindowDirection::RIGHT || _dir == WindowDirection::LEFT)
std::swap(width, height);
return toSizeNeg2Zero(Point{ width, height });
}
Size System::GetWorkArea()
{
int x, y, w, h;
glfwGetMonitorWorkarea(_imp->_monitor, &x, &y, &w, &h);
return { (unsigned)w, (unsigned)h };
}
void System::SetWindowPoint(const Point& xy)
{
glfwSetWindowPos(_imp->_window, xy[0], xy[1]);
}
void System::SetWindowCenter()
{
Size s = GetWorkArea();
Size size_window = GetWindowSize();
Point xy = (toPoint(s) - toPoint(size_window)) / 2;
SetWindowPoint(xy);
}
void System::SetWindowTitle(std::string_view str)
{
#if DL_PLATFORM != DL_PLATFORM_ANDROID
glfwSetWindowTitle(_imp->_window, str.data());
#endif
}
bool System::IsWindowExist()
{
#if DL_PLATFORM != DL_PLATFORM_ANDROID
return _imp->_window;
#else
return g_android->_surfaceState == 2;
#endif
}
void System::SetCursorMode(CursorMode mode)
{
#if (DL_PLATFORM == DL_PLATFORM_ANDROID)
#else
if (_cursorMode == mode)
return;
_imp->_bClearCursorDt = true;
_cursorMode = mode;
switch (mode)
{
case CursorMode::NORMAL:
glfwSetInputMode(_imp->_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
break;
case CursorMode::HIDE:
glfwSetInputMode(_imp->_window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
break;
case CursorMode::DISABLE:
glfwSetInputMode(_imp->_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
break;
default:
assert(0);
break;
}
#endif
}
void System::SetClipboardString(std::string_view str)
{
glfwSetClipboardString(nullptr, str.data());
}
std::string System::GetClipboardString()
{
const char* str = glfwGetClipboardString(nullptr);
if (!str)
return {};
return str;
}
void System::ShowMessageBox(std::string_view title, std::string_view text)
{
#if DL_PLATFORM == DL_PLATFORM_WIN32
::MessageBoxW((HWND)_nativeWindow, CodeCvt::Utf8ToWideChar(text).c_str(), CodeCvt::Utf8ToWideChar(title).c_str(), MB_OK);
#else
assert(0);
#endif
}
void System::SetFullScreen(FullScreenMode mode, const Size& size /*= {}*/)
{
#if DL_PLATFORM != DL_PLATFORM_ANDROID
int w = (int)size[0];
int h = (int)size[1];
if (_dir == WindowDirection::RIGHT || _dir == WindowDirection::LEFT)
std::swap(w, h);
switch (_fullScreenMode)
{
case dl::FullScreenMode::WINDOW:
if (mode == FullScreenMode::WINDOW)
{
glfwSetWindowSize(_imp->_window, w, h);
SetWindowCenter();
}
else if (mode == FullScreenMode::FULL)
{
glfwSetWindowMonitor(_imp->_window, glfwGetPrimaryMonitor(),
0, 0, w, h,
GLFW_DONT_CARE);
}
else if (mode == FullScreenMode::FULL_WINDOW)
{
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
glfwSetWindowMonitor(_imp->_window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
}
break;
case dl::FullScreenMode::FULL:
if (mode == FullScreenMode::WINDOW)
{
// 使用旧大小
int w, h;
_get_window_size(w, h);
if (_dir == WindowDirection::RIGHT || _dir == WindowDirection::LEFT)
std::swap(w, h);
glfwSetWindowMonitor(_imp->_window, nullptr,
0, 0, w, h, GLFW_DONT_CARE);
SetWindowCenter();
}
else if (mode == FullScreenMode::FULL)
{
glfwSetWindowSize(_imp->_window, (int)size[0], (int)size[1]);
}
else if (mode == FullScreenMode::FULL_WINDOW)
{
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
// 使用显示器原始大小
glfwSetWindowMonitor(_imp->_window, monitor, 0, 0, (int)_desktopSize[0], (int)_desktopSize[1],
mode->refreshRate);
}
break;
case dl::FullScreenMode::FULL_WINDOW:
if (mode == FullScreenMode::WINDOW)
{
glfwSetWindowMonitor(_imp->_window, nullptr,
0, 0, w, h, GLFW_DONT_CARE);
SetWindowCenter();
}
else if (mode == FullScreenMode::FULL)
{
glfwSetWindowMonitor(_imp->_window, glfwGetPrimaryMonitor(),
0, 0, w, h, GLFW_DONT_CARE);
}
else if (mode == FullScreenMode::FULL_WINDOW)
{
}
break;
default:
assert(0);
break;
}
_fullScreenMode = mode;
#endif
}
void System::SetWindowSize(const Size& size)
{
SetFullScreen(_fullScreenMode, size);
}
#if DL_PLATFORM == DL_PLATFORM_WIN32
bool GetMacByGetAdaptersInfo(std::string& macOUT)
{
bool ret = false;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL)
return false;
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
{
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO*)malloc(ulOutBufLen);
if (pAdapterInfo == NULL)
return false;
}
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == NO_ERROR)
{
for (PIP_ADAPTER_INFO pAdapter = pAdapterInfo; pAdapter != NULL; pAdapter = pAdapter->Next)
{
// 确保是以太网
if (pAdapter->Type != MIB_IF_TYPE_ETHERNET)
continue;
// 确保MAC地址的长度为 00-00-00-00-00-00
if (pAdapter->AddressLength != 6)
continue;
char acMAC[32];
sprintf(acMAC, "%02X-%02X-%02X-%02X-%02X-%02X",
int(pAdapter->Address[0]),
int(pAdapter->Address[1]),
int(pAdapter->Address[2]),
int(pAdapter->Address[3]),
int(pAdapter->Address[4]),
int(pAdapter->Address[5]));
macOUT = acMAC;
ret = true;
break;
}
}
free(pAdapterInfo);
return ret;
}
#endif
std::string System::GetHardwareId()
{
std::string str;
#if DL_PLATFORM == DL_PLATFORM_WIN32
str += Infoware::GetCpuId();
std::string str_mac;
GetMacByGetAdaptersInfo(str_mac);
str += str_mac;
return to_string_hex(Crypto::HashMd5(CreateBufferView(str)));
#else
str = "dl engine";
#endif
return to_string_hex(Crypto::HashMd5(CreateBufferView(str)));
}
std::string System::GetUsername()
{
//#if DL_PLATFORM == DL_PLATFORM_APPLE
// // 1. 获取当前进程的用户ID(UID)
// uid_t uid = getuid();
//
// // 2. 通过UID查询用户信息
// struct passwd* pw = getpwuid(uid);
//
// if (pw == nullptr)
// return {};
// return pw->pw_name;
//#endif
return {};
}
void System::_init_glfw()
{
#if DL_PLATFORM != DL_PLATFORM_ANDROID
//------------------创建窗口------------------------
// if (glfwPlatformSupported(GLFW_PLATFORM_WAYLAND))
// glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND);
// else
// wayland 暂不支持,先使用 x11
if (glfwPlatformSupported(GLFW_PLATFORM_X11))
glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11);
// vscode 需要启用wayland才能在vscode里正常显示标题栏
//code --ozone-platform=wayland
if (!glfwInit())
{
log_err("glfw 初始化失败!");
return;
}
int platform = glfwGetPlatform();
switch(platform)
{
case GLFW_ANY_PLATFORM:
log_msg0("当前glfw平台:any");
break;
case GLFW_PLATFORM_WIN32:
log_msg0("当前glfw平台:win32");
break;
case GLFW_PLATFORM_COCOA:
log_msg0("当前glfw平台:cocoa");
break;
case GLFW_PLATFORM_WAYLAND:
log_msg0("当前glfw平台:wayland");
break;
case GLFW_PLATFORM_X11:
log_msg0("当前glfw平台:x11");
break;
default:
log_msg0("当前glfw平台:error");
}
//glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // 自动调整窗口大小
//glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE); // 自动调整帧缓冲区大小
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);//设置不使用OpenGL
//glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);//设置窗口禁止修改大小
_imp->_monitor = glfwGetPrimaryMonitor();
log_msg("当前显示器:{}", glfwGetMonitorName(_imp->_monitor));
#endif
}
void System::_delete_glfw()
{
glfwDestroyWindow(_imp->_window);
glfwTerminate();
}
void System::_resize()
{
if (g_vk)
g_vk->SetFrameBufferResize();
g_ui->_resize();
g_factory->_resize();
}
void System::lua_SetFuncInit(luabridge::LuaRef func)
{
_lua._funcInit = func;
}
void System::lua_SetFuncRun(luabridge::LuaRef func)
{
_lua._funcRun = func;
}
const RenderInfo2D& System::GetRenderInfo2D()
{
return g_vk->GetRenderInfo2D();
}
const RenderInfo3D& System::GetRenderInfo3D()
{
return g_vk->GetRenderInfo3D();
}
void System::ScreenShot(std::string_view path_name)
{
g_vk->ScreenShot(path_name);
}
bool System::_start_init(const ParamWindow& param)
{
#if (DL_PLATFORM != DL_PLATFORM_ANDROID)
//------------------创建窗口------------------------
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
if (param._bHideTitle)
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
_fullScreenMode = param._fullScreenMode;
_desktopSize = toSize(mode->width, mode->width);
switch (_fullScreenMode)
{
case dl::FullScreenMode::WINDOW:
_imp->_window = glfwCreateWindow((int)param._size[0], (int)param._size[1],
param._strTitle.c_str(), nullptr, nullptr);
break;
case dl::FullScreenMode::FULL:
_imp->_window = glfwCreateWindow((int)param._size[0], (int)param._size[1],
param._strTitle.c_str(), glfwGetPrimaryMonitor(), nullptr);
break;
case dl::FullScreenMode::FULL_WINDOW:
{
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
glfwWindowHint(GLFW_RED_BITS, mode->redBits);
glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);
_imp->_window = glfwCreateWindow(mode->width, mode->height,
param._strTitle.c_str(), monitor, nullptr);
}
break;
default:
assert(0);
break;
}
if (!_imp->_window)
{
log_err("窗口创建失败!");
return false;
}
//SetWindowCenter();
// 设置大小变化回调
glfwSetFramebufferSizeCallback(_imp->_window, CallbackFrameBufferResize);
// 设置按键回调
glfwSetKeyCallback(_imp->_window, CallbackKey);
// 设置输入回调
glfwSetCharCallback(_imp->_window, CallbackChar);
// 设置光标位置回调
glfwSetCursorPosCallback(_imp->_window, CallbackCursorPos);
// 设置鼠标按键回调
glfwSetMouseButtonCallback(_imp->_window, CallbackMouseButton);
// 设置滚动回调
glfwSetScrollCallback(_imp->_window, CallbackScroll);
// 拖入文件回调
glfwSetDropCallback(_imp->_window, CallbackDrop);
#elif DL_PLATFORM == DL_PLATFORM_ANDROID
// 此时安卓窗口和surface已经创建完毕
_fullScreenMode = FullScreenMode::FULL;
_desktopSize = toSize(g_android->_sizeWindow);
#endif
//------------------创建VK------------------------
g_vk = new VK(_imp->_window);
g_factory->_init_path();
g_factory->_init_defualt_res();
g_audio->_load();
//g_ui->_resize(); // 不应该调用(默认值就应该正确)
if (_funcInit)
_funcInit(); // 初始化函数(此时设置ui标准大小)
if(_lua._funcInit)
g_lua->CallFunction(_lua._funcInit);
g_factory->_save_cache();
//-----------------游戏循环-----------------------
#if (DL_PLATFORM == DL_PLATFORM_WIN32)
timeBeginPeriod(1);
#endif
// 获取窗口句柄
#if DL_PLATFORM == DL_PLATFORM_WIN32
_nativeWindow = glfwGetWin32Window(_imp->_window);
#elif DL_PLATFORM == DL_PLATFORM_LINUX
//_nativeWindow = glfwGetX11Window(_imp->_window);
#elif DL_PLATFORM == DL_PLATFORM_ANDROID
#endif
//glfwGetCocoaWindow macos
return true;
}
//! 暂停程序,等待用户输入后继续(Windows:按任意键;其他平台:回车)
void System::Pause()
{
#if DL_PLATFORM == DL_PLATFORM_WIN32
system("pause");
#else
printf("输入任意字符并按回车继续:");
char b;
std::cin >> b;
#endif
}
}
#endif