This commit is contained in:
wcjbr
2026-08-16 13:32:51 +08:00
parent 9b5d76a6ac
commit d36fd6d2ee
25 changed files with 2836 additions and 4 deletions
+323
View File
@@ -0,0 +1,323 @@
#include <config.hpp>
#include <json/json.h>
#include <algorithm>
#include <cctype>
#include <fstream>
#include <string>
#include <vector>
namespace openceg {
namespace {
std::string lowercase(std::string value) {
std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {
return static_cast<char>(std::tolower(ch));
});
return value;
}
int parse_key_name(const std::string& name) {
const std::string key = lowercase(name);
if (key == "space") return 32;
if (key == "apostrophe" || key == "'") return 39;
if (key == "comma" || key == ",") return 44;
if (key == "minus" || key == "-") return 45;
if (key == "period" || key == ".") return 46;
if (key == "slash" || key == "/") return 47;
if (key.size() == 1 && key[0] >= '0' && key[0] <= '9') return key[0];
if (key.size() == 1 && key[0] >= 'a' && key[0] <= 'z') return key[0] - 'a' + 'A';
if (key == "semicolon" || key == ";") return 59;
if (key == "equal" || key == "=") return 61;
if (key == "leftbracket" || key == "[") return 91;
if (key == "backslash" || key == "\\") return 92;
if (key == "rightbracket" || key == "]") return 93;
if (key == "graveaccent" || key == "`") return 96;
if (key == "escape" || key == "esc") return 256;
if (key == "enter" || key == "return") return 257;
if (key == "tab") return 258;
if (key == "backspace") return 259;
if (key == "insert") return 260;
if (key == "delete" || key == "del") return 261;
if (key == "right") return 262;
if (key == "left") return 263;
if (key == "down") return 264;
if (key == "up") return 265;
if (key == "pageup" || key == "pgup") return 266;
if (key == "pagedown" || key == "pgdown" || key == "pgdn") return 267;
if (key == "home") return 268;
if (key == "end") return 269;
if (key == "capslock" || key == "caps") return 280;
if (key == "scrolllock") return 281;
if (key == "numlock") return 282;
if (key == "printscreen" || key == "prtscr") return 283;
if (key == "pause") return 284;
if (key.size() > 1 && key[0] == 'f') {
try {
int number = std::stoi(key.substr(1));
if (number >= 1 && number <= 25) return 290 + number - 1;
} catch (...) {
}
}
if (key == "kp0" || key == "keypad0") return 320;
if (key == "kp1" || key == "keypad1") return 321;
if (key == "kp2" || key == "keypad2") return 322;
if (key == "kp3" || key == "keypad3") return 323;
if (key == "kp4" || key == "keypad4") return 324;
if (key == "kp5" || key == "keypad5") return 325;
if (key == "kp6" || key == "keypad6") return 326;
if (key == "kp7" || key == "keypad7") return 327;
if (key == "kp8" || key == "keypad8") return 328;
if (key == "kp9" || key == "keypad9") return 329;
if (key == "leftshift" || key == "lshift") return 340;
if (key == "rightshift" || key == "rshift") return 344;
if (key == "leftcontrol" || key == "leftctrl" || key == "lctrl") return 341;
if (key == "rightcontrol" || key == "rightctrl" || key == "rctrl") return 345;
if (key == "leftalt" || key == "lalt") return 342;
if (key == "rightalt" || key == "ralt") return 346;
if (key == "leftsuper" || key == "lsuper") return 343;
if (key == "rightsuper" || key == "rsuper") return 347;
try {
return std::stoi(name);
} catch (...) {
return -1;
}
}
int parse_mouse_button(const std::string& name) {
const std::string button = lowercase(name);
if (button == "left") return 0;
if (button == "right") return 1;
if (button == "middle") return 2;
try {
return std::stoi(name);
} catch (...) {
return -1;
}
}
int json_int(const Json::Value& value, int fallback) {
if (value.isNumeric()) {
return value.asInt();
}
if (value.isString()) {
try {
return std::stoi(value.asString());
} catch (...) {
}
}
return fallback;
}
float json_float(const Json::Value& value, float fallback) {
if (value.isNumeric()) {
return value.asFloat();
}
if (value.isString()) {
try {
return std::stof(value.asString());
} catch (...) {
}
}
return fallback;
}
std::string json_string(const Json::Value& value, const std::string& fallback) {
if (value.isString()) {
return value.asString();
}
if (value.isNumeric()) {
return std::to_string(value.asInt());
}
return fallback;
}
void add_binding_code(const Json::Value& value, int type, std::vector<int>& output) {
if (value.isArray()) {
for (Json::ArrayIndex i = 0; i < value.size(); ++i) {
add_binding_code(value[i], type, output);
}
return;
}
int code = -1;
if (value.isNumeric()) {
code = value.asInt();
} else if (value.isString()) {
code = type == 0 ? parse_key_name(value.asString())
: parse_mouse_button(value.asString());
}
if (code >= 0) {
output.push_back(code);
}
}
void parse_window(const Json::Value& root, WindowConfig& window) {
if (!root.isMember("window") || !root["window"].isObject()) {
return;
}
const Json::Value& value = root["window"];
if (value.isMember("width")) {
window.width = json_int(value["width"], window.width);
}
if (value.isMember("height")) {
window.height = json_int(value["height"], window.height);
}
if (value.isMember("title")) {
window.title = json_string(value["title"], window.title);
}
}
void parse_input(const Json::Value& root, std::vector<InputBindingConfig>& bindings) {
if (!root.isMember("input") || !root["input"].isArray()) {
return;
}
for (const Json::Value& item : root["input"]) {
if (!item.isObject()) {
continue;
}
InputBindingConfig binding;
binding.action = item.isMember("action")
? json_string(item["action"], "")
: json_string(item["name"], "");
if (item.isMember("key")) {
add_binding_code(item["key"], 0, binding.keys);
}
if (item.isMember("keys")) {
add_binding_code(item["keys"], 0, binding.keys);
}
if (item.isMember("mouse")) {
add_binding_code(item["mouse"], 1, binding.mouse_buttons);
}
if (item.isMember("mouse_buttons")) {
add_binding_code(item["mouse_buttons"], 1, binding.mouse_buttons);
}
if (!binding.action.empty()) {
bindings.push_back(std::move(binding));
}
}
}
void parse_color(const Json::Value& mesh, MeshConfig& mesh_config) {
if (!mesh.isObject() || !mesh.isMember("color")) {
return;
}
const Json::Value& color = mesh["color"];
if (color.isObject()) {
if (color.isMember("r")) mesh_config.color[0] = json_float(color["r"], mesh_config.color[0]);
if (color.isMember("g")) mesh_config.color[1] = json_float(color["g"], mesh_config.color[1]);
if (color.isMember("b")) mesh_config.color[2] = json_float(color["b"], mesh_config.color[2]);
if (color.isMember("a")) mesh_config.color[3] = json_float(color["a"], mesh_config.color[3]);
} else if (color.isArray()) {
for (Json::ArrayIndex i = 0; i < color.size() && i < 4; ++i) {
mesh_config.color[i] = json_float(color[i], mesh_config.color[i]);
}
}
}
ActorConfig parse_actor(const Json::Value& value) {
ActorConfig actor;
if (value.isMember("name")) {
actor.name = json_string(value["name"], "");
}
if (value.isMember("init")) {
actor.init_function = json_string(value["init"], "");
}
if (value.isMember("tick")) {
actor.tick_function = json_string(value["tick"], "");
}
if (value.isMember("position") && value["position"].isObject()) {
const Json::Value& position = value["position"];
actor.position[0] = json_float(position["x"], actor.position[0]);
actor.position[1] = json_float(position["y"], actor.position[1]);
}
if (value.isMember("facing") && value["facing"].isObject()) {
const Json::Value& facing = value["facing"];
actor.facing[0] = json_float(facing["x"], actor.facing[0]);
actor.facing[1] = json_float(facing["y"], actor.facing[1]);
}
if (value.isMember("mesh") && value["mesh"].isObject()) {
const Json::Value& mesh = value["mesh"];
if (mesh.isMember("shape")) {
actor.mesh.shape = json_string(mesh["shape"], actor.mesh.shape);
}
parse_color(mesh, actor.mesh);
}
return actor;
}
void parse_actors(const Json::Value& root, std::vector<ActorConfig>& actors) {
const Json::Value* list = nullptr;
if (root.isMember("actors") && root["actors"].isArray()) {
list = &root["actors"];
} else if (root.isMember("scene")) {
const Json::Value& scene = root["scene"];
if (scene.isArray()) {
list = &scene;
} else if (scene.isObject() && scene.isMember("actors") && scene["actors"].isArray()) {
list = &scene["actors"];
}
}
if (list == nullptr) {
return;
}
for (const Json::Value& item : *list) {
if (!item.isObject()) {
continue;
}
ActorConfig actor = parse_actor(item);
if (!actor.name.empty()) {
actors.push_back(std::move(actor));
}
}
}
} // namespace
bool ConfigLoader::load(const std::string& path) {
Json::Value root;
Json::CharReaderBuilder builder;
std::ifstream file(path);
std::string errors;
if (!Json::parseFromStream(builder, file, &root, &errors)) {
last_error_ = "无法解析 JSON 配置文件: " + path + " - " + errors;
return false;
}
if (!root.isObject()) {
last_error_ = "JSON 根节点必须是对象: " + path;
return false;
}
config_ = GameConfig{};
parse_window(root, config_.window);
parse_input(root, config_.input_bindings);
parse_actors(root, config_.actors);
return true;
}
const GameConfig& ConfigLoader::config() const {
return config_;
}
const std::string& ConfigLoader::last_error() const {
return last_error_;
}
} // namespace openceg
+117
View File
@@ -0,0 +1,117 @@
#include <engine.hpp>
#include <chrono>
#include <cstdio>
#include <memory>
#include <string>
#include <thread>
#include <vector>
#include <openceg.hpp>
namespace openceg {
int run_engine(int argc, char** argv, const char* default_config_path) {
std::string config_path = default_config_path != nullptr ? default_config_path : "config.ceg";
if (argc > 1) {
config_path = argv[1];
}
ConfigLoader loader;
if (!loader.load(config_path)) {
std::fprintf(stderr, "%s\n", loader.last_error().c_str());
return 1;
}
const GameConfig& config = loader.config();
Game& game = Game::getInstance();
BehaviorRegistry& behaviors = BehaviorRegistry::getInstance();
std::vector<std::shared_ptr<Actor>> actor_storage;
std::vector<Actor*> actors;
for (const ActorConfig& actor_config : config.actors) {
auto mesh = std::make_shared<Mesh>();
if (actor_config.mesh.shape == "quad") {
*mesh = Mesh::quad();
} else {
// 当前渲染器只提供 quad;未知形状先按 quad 创建,便于后续扩展。
*mesh = Mesh::quad();
}
mesh->set_color(actor_config.mesh.color);
auto actor = std::make_shared<Actor>(actor_config.name, game, mesh);
actor->set_position(actor_config.position);
actor->set_facing(actor_config.facing);
if (!actor_config.init_function.empty()) {
auto handler = behaviors.init(actor_config.init_function);
if (handler) {
actor->set_init_handler(std::move(handler));
} else {
std::fprintf(stderr, "未找到 init 处理函数: %s\n",
actor_config.init_function.c_str());
}
}
if (!actor_config.tick_function.empty()) {
auto handler = behaviors.tick(actor_config.tick_function);
if (handler) {
actor->set_tick_handler(std::move(handler));
} else {
std::fprintf(stderr, "未找到 tick 处理函数: %s\n",
actor_config.tick_function.c_str());
}
}
actors.push_back(actor.get());
actor_storage.push_back(std::move(actor));
}
for (auto& actor : actor_storage) {
actor->initialize();
}
render::RenderLoop render_loop;
for (const InputBindingConfig& binding : config.input_bindings) {
render_loop.input().add_action(binding.action);
for (int key : binding.keys) {
render_loop.input().bind_key(binding.action, key);
}
for (int button : binding.mouse_buttons) {
render_loop.input().bind_mouse_button(binding.action, button);
}
}
// 引擎级默认退出动作,不包含具体游戏逻辑。
render_loop.input().add_action("quit");
render_loop.input().bind_key("quit", 256);
render_loop.set_actors(std::move(actors));
render_loop.start(config.window.width, config.window.height,
config.window.title.c_str());
auto last = std::chrono::steady_clock::now();
while (!render_loop.should_close()) {
render_loop.poll_events();
if (render_loop.input().is_action_just_pressed("quit")) {
break;
}
const auto now = std::chrono::steady_clock::now();
const float dt = std::chrono::duration<float>(now - last).count();
last = now;
for (auto& actor : actor_storage) {
actor->process(dt, render_loop.input());
}
render_loop.input().end_frame();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
render_loop.stop();
return 0;
}
} // namespace openceg
+5
View File
@@ -0,0 +1,5 @@
#include <engine.hpp>
int main(int argc, char** argv) {
return openceg::run_engine(argc, argv);
}
+17
View File
@@ -0,0 +1,17 @@
#include <game.hpp>
namespace openceg {
Game::Game() { id_cnt = 0; }
Game::~Game() = default;
Game& Game::getInstance() {
static Game instance;
return instance;
}
void Game::launch() {}
size_t Game::new_id() { return id_cnt++; }
}
+415
View File
@@ -0,0 +1,415 @@
// Minimal GLFW-compatible Win32 backend for cross-compiling the example.
// It implements only the subset used by src/render.cpp.
#include <windows.h>
#include <windowsx.h>
#include <array>
#include <cstdint>
#include <vector>
#define GLFW_INCLUDE_VULKAN
#define VK_USE_PLATFORM_WIN32_KHR
#include <GLFW/glfw3.h>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_win32.h>
struct GLFWwindow {
HWND handle = nullptr;
void* user_pointer = nullptr;
bool should_close = false;
int width = 0;
int height = 0;
GLFWkeyfun key_callback = nullptr;
GLFWmousebuttonfun mouse_button_callback = nullptr;
GLFWcursorposfun cursor_pos_callback = nullptr;
GLFWscrollfun scroll_callback = nullptr;
std::array<unsigned char, 1024> key_state{};
std::array<unsigned char, 8> mouse_button_state{};
double cursor_x = 0.0;
double cursor_y = 0.0;
};
namespace {
constexpr wchar_t kWindowClassName[] = L"OpenCGE_GLFWStub";
HINSTANCE g_instance = nullptr;
bool g_initialized = false;
bool g_resizable = true;
int map_key(WPARAM vk) {
if (vk >= 'A' && vk <= 'Z') {
return GLFW_KEY_A + static_cast<int>(vk - 'A');
}
if (vk >= '0' && vk <= '9') {
return GLFW_KEY_0 + static_cast<int>(vk - '0');
}
switch (vk) {
case VK_ESCAPE:
return GLFW_KEY_ESCAPE;
case VK_LEFT:
return GLFW_KEY_LEFT;
case VK_RIGHT:
return GLFW_KEY_RIGHT;
case VK_UP:
return GLFW_KEY_UP;
case VK_DOWN:
return GLFW_KEY_DOWN;
case VK_SPACE:
return GLFW_KEY_SPACE;
case VK_RETURN:
return GLFW_KEY_ENTER;
case VK_TAB:
return GLFW_KEY_TAB;
case VK_BACK:
return GLFW_KEY_BACKSPACE;
case VK_DELETE:
return GLFW_KEY_DELETE;
case VK_LSHIFT:
return GLFW_KEY_LEFT_SHIFT;
case VK_RSHIFT:
return GLFW_KEY_RIGHT_SHIFT;
case VK_LCONTROL:
return GLFW_KEY_LEFT_CONTROL;
case VK_RCONTROL:
return GLFW_KEY_RIGHT_CONTROL;
case VK_LMENU:
return GLFW_KEY_LEFT_ALT;
case VK_RMENU:
return GLFW_KEY_RIGHT_ALT;
default:
break;
}
return GLFW_KEY_UNKNOWN;
}
int current_mods() {
int mods = 0;
if (GetKeyState(VK_SHIFT) & 0x8000) {
mods |= GLFW_MOD_SHIFT;
}
if (GetKeyState(VK_CONTROL) & 0x8000) {
mods |= GLFW_MOD_CONTROL;
}
if (GetKeyState(VK_MENU) & 0x8000) {
mods |= GLFW_MOD_ALT;
}
if ((GetKeyState(VK_LWIN) & 0x8000) || (GetKeyState(VK_RWIN) & 0x8000)) {
mods |= GLFW_MOD_SUPER;
}
return mods;
}
void handle_key(GLFWwindow* window, UINT message, WPARAM wparam, LPARAM lparam) {
if (window == nullptr || window->key_callback == nullptr) {
return;
}
const int key = map_key(wparam);
const int scancode = static_cast<int>((lparam >> 16) & 0x1ff);
const int action = message == WM_KEYDOWN || message == WM_SYSKEYDOWN
? (((lparam & (1U << 30)) != 0) ? GLFW_REPEAT : GLFW_PRESS)
: GLFW_RELEASE;
if (key >= 0 && key < static_cast<int>(window->key_state.size())) {
window->key_state[key] = action == GLFW_RELEASE ? GLFW_RELEASE : GLFW_PRESS;
}
window->key_callback(window, key, scancode, action, current_mods());
}
int map_mouse_button(UINT message, WPARAM wparam) {
switch (message) {
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
return GLFW_MOUSE_BUTTON_LEFT;
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
return GLFW_MOUSE_BUTTON_RIGHT;
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
return GLFW_MOUSE_BUTTON_MIDDLE;
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
return GET_XBUTTON_WPARAM(wparam) == XBUTTON1 ? GLFW_MOUSE_BUTTON_4
: GLFW_MOUSE_BUTTON_5;
default:
return -1;
}
}
void handle_mouse_button(GLFWwindow* window, UINT message, WPARAM wparam) {
if (window == nullptr || window->mouse_button_callback == nullptr) {
return;
}
const int button = map_mouse_button(message, wparam);
if (button < 0) {
return;
}
const bool is_down = message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN ||
message == WM_MBUTTONDOWN || message == WM_XBUTTONDOWN;
window->mouse_button_state[button] = is_down ? GLFW_PRESS : GLFW_RELEASE;
window->mouse_button_callback(window, button, is_down ? GLFW_PRESS : GLFW_RELEASE,
current_mods());
}
LRESULT CALLBACK window_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
auto* window = reinterpret_cast<GLFWwindow*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
switch (message) {
case WM_CLOSE:
if (window != nullptr) {
window->should_close = true;
}
return 0;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
handle_key(window, message, wparam, lparam);
return 0;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
handle_mouse_button(window, message, wparam);
return 0;
case WM_MOUSEMOVE:
if (window != nullptr) {
window->cursor_x = static_cast<double>(GET_X_LPARAM(lparam));
window->cursor_y = static_cast<double>(GET_Y_LPARAM(lparam));
if (window->cursor_pos_callback != nullptr) {
window->cursor_pos_callback(window, window->cursor_x, window->cursor_y);
}
}
return 0;
case WM_MOUSEWHEEL:
if (window != nullptr && window->scroll_callback != nullptr) {
const double delta = static_cast<double>(GET_WHEEL_DELTA_WPARAM(wparam)) /
static_cast<double>(WHEEL_DELTA);
window->scroll_callback(window, 0.0, delta);
}
return 0;
default:
break;
}
return DefWindowProcW(hwnd, message, wparam, lparam);
}
} // namespace
extern "C" {
int glfwInit(void) {
if (g_initialized) {
return GLFW_TRUE;
}
g_instance = GetModuleHandleW(nullptr);
WNDCLASSEXW wc{};
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = window_proc;
wc.hInstance = g_instance;
wc.hCursor = LoadCursorW(nullptr, MAKEINTRESOURCEW(32512));
wc.lpszClassName = kWindowClassName;
if (RegisterClassExW(&wc) == 0) {
return GLFW_FALSE;
}
g_initialized = true;
return GLFW_TRUE;
}
void glfwTerminate(void) {
g_initialized = false;
}
void glfwWindowHint(int hint, int value) {
if (hint == GLFW_RESIZABLE) {
g_resizable = value != GLFW_FALSE;
}
}
GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor*, GLFWwindow*) {
if (!g_initialized) {
return nullptr;
}
const int wide_length = MultiByteToWideChar(CP_UTF8, 0, title, -1, nullptr, 0);
std::vector<wchar_t> wide_title(wide_length);
MultiByteToWideChar(CP_UTF8, 0, title, -1, wide_title.data(), wide_length);
DWORD style = WS_OVERLAPPEDWINDOW;
if (!g_resizable) {
style &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
}
RECT rect{0, 0, width, height};
AdjustWindowRectEx(&rect, style, FALSE, 0);
HWND hwnd = CreateWindowExW(
0, kWindowClassName, wide_title.data(), style, CW_USEDEFAULT, CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top, nullptr, nullptr, g_instance, nullptr);
if (hwnd == nullptr) {
return nullptr;
}
auto* window = new GLFWwindow();
window->handle = hwnd;
window->width = width;
window->height = height;
SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(window));
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
return window;
}
void glfwDestroyWindow(GLFWwindow* window) {
if (window == nullptr) {
return;
}
if (window->handle != nullptr) {
DestroyWindow(window->handle);
}
delete window;
}
void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer) {
if (window != nullptr) {
window->user_pointer = pointer;
}
}
void* glfwGetWindowUserPointer(GLFWwindow* window) {
return window != nullptr ? window->user_pointer : nullptr;
}
GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun callback) {
if (window == nullptr) {
return nullptr;
}
GLFWkeyfun previous = window->key_callback;
window->key_callback = callback;
return previous;
}
GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun callback) {
if (window == nullptr) {
return nullptr;
}
GLFWmousebuttonfun previous = window->mouse_button_callback;
window->mouse_button_callback = callback;
return previous;
}
GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun callback) {
if (window == nullptr) {
return nullptr;
}
GLFWcursorposfun previous = window->cursor_pos_callback;
window->cursor_pos_callback = callback;
return previous;
}
GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback) {
if (window == nullptr) {
return nullptr;
}
GLFWscrollfun previous = window->scroll_callback;
window->scroll_callback = callback;
return previous;
}
void glfwPollEvents(void) {
MSG msg{};
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
int glfwWindowShouldClose(GLFWwindow* window) {
return window != nullptr && window->should_close ? GLFW_TRUE : GLFW_FALSE;
}
int glfwGetKey(GLFWwindow* window, int key) {
if (window == nullptr || key < 0 || key >= static_cast<int>(window->key_state.size())) {
return GLFW_RELEASE;
}
return window->key_state[key] != 0 ? GLFW_PRESS : GLFW_RELEASE;
}
int glfwGetMouseButton(GLFWwindow* window, int button) {
if (window == nullptr || button < 0 ||
button >= static_cast<int>(window->mouse_button_state.size())) {
return GLFW_RELEASE;
}
return window->mouse_button_state[button] != 0 ? GLFW_PRESS : GLFW_RELEASE;
}
void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos) {
if (xpos != nullptr) {
*xpos = window != nullptr ? window->cursor_x : 0.0;
}
if (ypos != nullptr) {
*ypos = window != nullptr ? window->cursor_y : 0.0;
}
}
void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height) {
if (window == nullptr || window->handle == nullptr) {
return;
}
RECT client{};
GetClientRect(window->handle, &client);
if (width != nullptr) {
*width = client.right - client.left;
}
if (height != nullptr) {
*height = client.bottom - client.top;
}
}
const char** glfwGetRequiredInstanceExtensions(uint32_t* count) {
static const char* extensions[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
};
if (count != nullptr) {
*count = static_cast<uint32_t>(sizeof(extensions) / sizeof(extensions[0]));
}
return extensions;
}
VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface) {
if (instance == VK_NULL_HANDLE || window == nullptr || surface == nullptr) {
return VK_ERROR_INITIALIZATION_FAILED;
}
auto create_surface = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(
vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"));
if (create_surface == nullptr) {
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
VkWin32SurfaceCreateInfoKHR info{};
info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
info.hinstance = g_instance;
info.hwnd = window->handle;
return create_surface(instance, &info, allocator, surface);
}
} // extern "C"
+1
View File
@@ -0,0 +1 @@
#include <openceg.hpp>
+1340
View File
File diff suppressed because it is too large Load Diff