Use a submodule for minifb-zig
This commit is contained in:
parent
b734196410
commit
d742a5f51c
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "lib/minifb"]
|
||||||
|
path = lib/minifb
|
||||||
|
url = git@git.codemonkeysoftware.net:b/minifb-zig.git
|
1
lib/minifb
Submodule
1
lib/minifb
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 2aabdbaee97ac946f01ea5828fffaa0d93cf4bd3
|
@ -1,72 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
|
|
||||||
// fn thisDir() []const u8 {
|
|
||||||
// return std.fs.path.dirname(@src().file) orelse ".";
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn build(b: *std.build.Builder) void {
|
|
||||||
// TODO Use mode to set debug flags in MiniFB
|
|
||||||
const mode = b.standardReleaseOptions();
|
|
||||||
const target = b.standardTargetOptions(.{});
|
|
||||||
|
|
||||||
var main_tests = b.addTest("src/minifb.zig");
|
|
||||||
main_tests.setBuildMode(mode);
|
|
||||||
main_tests.setTarget(target);
|
|
||||||
link(b, main_tests);
|
|
||||||
|
|
||||||
const test_step = b.step("test", "Run library tests");
|
|
||||||
test_step.dependOn(&main_tests.step);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn link(b: *std.build.Builder, step: *std.build.LibExeObjStep) void {
|
|
||||||
const lib = buildLibrary(b, step);
|
|
||||||
step.linkLibrary(lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fromHere(allocator: std.mem.Allocator, path: []const u8) []const u8 {
|
|
||||||
const here = std.fs.path.dirname(@src().file) orelse ".";
|
|
||||||
return std.fs.path.join(allocator, &.{here, path}) catch unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn buildLibrary(b: *std.build.Builder, step: *std.build.LibExeObjStep) *std.build.LibExeObjStep {
|
|
||||||
// var main_abs = std.fs.path.join(b.allocator, &.{thisDir(), "src/minifb.zig"}) catch unreachable;
|
|
||||||
const lib = b.addStaticLibrary("minifb", fromHere(b.allocator, "src/minifb.zig"));
|
|
||||||
lib.setBuildMode(step.build_mode);
|
|
||||||
|
|
||||||
var sources = std.ArrayList([]const u8) .init(b.allocator);
|
|
||||||
for ([_][]const u8{
|
|
||||||
"upstream/src/MiniFB_common.c",
|
|
||||||
"upstream/src/MiniFB_internal.c",
|
|
||||||
//"upstream/src/MiniFB_internal.h",
|
|
||||||
"upstream/src/MiniFB_timer.c",
|
|
||||||
//"upstream/src/WindowData.h",
|
|
||||||
//"upstream/src/windows/WindowData_Win.h",
|
|
||||||
"upstream/src/windows/WinMiniFB.c",
|
|
||||||
}) |path| {
|
|
||||||
// const abs_path = std.fs.path.join(b.allocator, &.{ thisDir(), path}) catch unreachable;
|
|
||||||
sources.append(fromHere(b.allocator, path)) catch unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO More than Windows
|
|
||||||
lib.addCSourceFiles(sources.items, &[_][]const u8{
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-pedantic",
|
|
||||||
"-Wno-switch",
|
|
||||||
"-Wno-unused-function",
|
|
||||||
"-Wno-implicit-fallthrough",
|
|
||||||
"-std=c11",
|
|
||||||
});
|
|
||||||
|
|
||||||
const include_abs = fromHere(b.allocator, "upstream/include");
|
|
||||||
const src_abs = fromHere(b.allocator, "upstream/src");
|
|
||||||
lib.addIncludeDir(include_abs);
|
|
||||||
lib.addIncludeDir(src_abs);
|
|
||||||
step.addIncludeDir(include_abs);
|
|
||||||
step.addIncludeDir(src_abs);
|
|
||||||
|
|
||||||
lib.linkSystemLibraryName("gdi32");
|
|
||||||
lib.linkLibC();
|
|
||||||
lib.install();
|
|
||||||
return lib;
|
|
||||||
}
|
|
@ -1,403 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const c = @cImport({
|
|
||||||
@cInclude("MiniFB.h");
|
|
||||||
@cInclude("MiniFB_enums.h");
|
|
||||||
});
|
|
||||||
const testing = std.testing;
|
|
||||||
|
|
||||||
pub const Rgb = packed struct {
|
|
||||||
b: u8,
|
|
||||||
g: u8,
|
|
||||||
r: u8,
|
|
||||||
_reserved: u8 = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Key = enum(c_int) {
|
|
||||||
unknown = c.KB_KEY_UNKNOWN,
|
|
||||||
|
|
||||||
space = c.KB_KEY_SPACE,
|
|
||||||
apostrophe = c.KB_KEY_APOSTROPHE,
|
|
||||||
comma = c.KB_KEY_COMMA,
|
|
||||||
minus = c.KB_KEY_MINUS,
|
|
||||||
period = c.KB_KEY_PERIOD,
|
|
||||||
slash = c.KB_KEY_SLASH,
|
|
||||||
@"0" = c.KB_KEY_0,
|
|
||||||
@"1" = c.KB_KEY_1,
|
|
||||||
@"2" = c.KB_KEY_2,
|
|
||||||
@"3" = c.KB_KEY_3,
|
|
||||||
@"4" = c.KB_KEY_4,
|
|
||||||
@"5" = c.KB_KEY_5,
|
|
||||||
@"6" = c.KB_KEY_6,
|
|
||||||
@"7" = c.KB_KEY_7,
|
|
||||||
@"8" = c.KB_KEY_8,
|
|
||||||
@"9" = c.KB_KEY_9,
|
|
||||||
semicolon = c.KB_KEY_SEMICOLON,
|
|
||||||
equal = c.KB_KEY_EQUAL,
|
|
||||||
a = c.KB_KEY_A,
|
|
||||||
b = c.KB_KEY_B,
|
|
||||||
c = c.KB_KEY_C,
|
|
||||||
d = c.KB_KEY_D,
|
|
||||||
e = c.KB_KEY_E,
|
|
||||||
f = c.KB_KEY_F,
|
|
||||||
g = c.KB_KEY_G,
|
|
||||||
h = c.KB_KEY_H,
|
|
||||||
i = c.KB_KEY_I,
|
|
||||||
j = c.KB_KEY_J,
|
|
||||||
k = c.KB_KEY_K,
|
|
||||||
l = c.KB_KEY_L,
|
|
||||||
m = c.KB_KEY_M,
|
|
||||||
n = c.KB_KEY_N,
|
|
||||||
o = c.KB_KEY_O,
|
|
||||||
p = c.KB_KEY_P,
|
|
||||||
q = c.KB_KEY_Q,
|
|
||||||
r = c.KB_KEY_R,
|
|
||||||
s = c.KB_KEY_S,
|
|
||||||
t = c.KB_KEY_T,
|
|
||||||
u = c.KB_KEY_U,
|
|
||||||
v = c.KB_KEY_V,
|
|
||||||
w = c.KB_KEY_W,
|
|
||||||
x = c.KB_KEY_X,
|
|
||||||
y = c.KB_KEY_Y,
|
|
||||||
z = c.KB_KEY_Z,
|
|
||||||
left_bracket = c.KB_KEY_LEFT_BRACKET,
|
|
||||||
backslash = c.KB_KEY_BACKSLASH,
|
|
||||||
right_bracket = c.KB_KEY_RIGHT_BRACKET,
|
|
||||||
grave_accent = c.KB_KEY_GRAVE_ACCENT,
|
|
||||||
world_1 = c.KB_KEY_WORLD_1,
|
|
||||||
world_2 = c.KB_KEY_WORLD_2,
|
|
||||||
|
|
||||||
escape = c.KB_KEY_ESCAPE,
|
|
||||||
enter = c.KB_KEY_ENTER,
|
|
||||||
tab = c.KB_KEY_TAB,
|
|
||||||
backspace = c.KB_KEY_BACKSPACE,
|
|
||||||
insert = c.KB_KEY_INSERT,
|
|
||||||
delete = c.KB_KEY_DELETE,
|
|
||||||
right = c.KB_KEY_RIGHT,
|
|
||||||
left = c.KB_KEY_LEFT,
|
|
||||||
down = c.KB_KEY_DOWN,
|
|
||||||
up = c.KB_KEY_UP,
|
|
||||||
page_up = c.KB_KEY_PAGE_UP,
|
|
||||||
page_down = c.KB_KEY_PAGE_DOWN,
|
|
||||||
home = c.KB_KEY_HOME,
|
|
||||||
end = c.KB_KEY_END,
|
|
||||||
caps_lock = c.KB_KEY_CAPS_LOCK,
|
|
||||||
scroll_lock = c.KB_KEY_SCROLL_LOCK,
|
|
||||||
num_lock = c.KB_KEY_NUM_LOCK,
|
|
||||||
print_screen = c.KB_KEY_PRINT_SCREEN,
|
|
||||||
pause = c.KB_KEY_PAUSE,
|
|
||||||
f1 = c.KB_KEY_F1,
|
|
||||||
f2 = c.KB_KEY_F2,
|
|
||||||
f3 = c.KB_KEY_F3,
|
|
||||||
f4 = c.KB_KEY_F4,
|
|
||||||
f5 = c.KB_KEY_F5,
|
|
||||||
f6 = c.KB_KEY_F6,
|
|
||||||
f7 = c.KB_KEY_F7,
|
|
||||||
f8 = c.KB_KEY_F8,
|
|
||||||
f9 = c.KB_KEY_F9,
|
|
||||||
f10 = c.KB_KEY_F10,
|
|
||||||
f11 = c.KB_KEY_F11,
|
|
||||||
f12 = c.KB_KEY_F12,
|
|
||||||
f13 = c.KB_KEY_F13,
|
|
||||||
f14 = c.KB_KEY_F14,
|
|
||||||
f15 = c.KB_KEY_F15,
|
|
||||||
f16 = c.KB_KEY_F16,
|
|
||||||
f17 = c.KB_KEY_F17,
|
|
||||||
f18 = c.KB_KEY_F18,
|
|
||||||
f19 = c.KB_KEY_F19,
|
|
||||||
f20 = c.KB_KEY_F20,
|
|
||||||
f21 = c.KB_KEY_F21,
|
|
||||||
f22 = c.KB_KEY_F22,
|
|
||||||
f23 = c.KB_KEY_F23,
|
|
||||||
f24 = c.KB_KEY_F24,
|
|
||||||
f25 = c.KB_KEY_F25,
|
|
||||||
kp_0 = c.KB_KEY_KP_0,
|
|
||||||
kp_1 = c.KB_KEY_KP_1,
|
|
||||||
kp_2 = c.KB_KEY_KP_2,
|
|
||||||
kp_3 = c.KB_KEY_KP_3,
|
|
||||||
kp_4 = c.KB_KEY_KP_4,
|
|
||||||
kp_5 = c.KB_KEY_KP_5,
|
|
||||||
kp_6 = c.KB_KEY_KP_6,
|
|
||||||
kp_7 = c.KB_KEY_KP_7,
|
|
||||||
kp_8 = c.KB_KEY_KP_8,
|
|
||||||
kp_9 = c.KB_KEY_KP_9,
|
|
||||||
kp_decimal = c.KB_KEY_KP_DECIMAL,
|
|
||||||
kp_divide = c.KB_KEY_KP_DIVIDE,
|
|
||||||
kp_multiply = c.KB_KEY_KP_MULTIPLY,
|
|
||||||
kp_subtract = c.KB_KEY_KP_SUBTRACT,
|
|
||||||
kp_add = c.KB_KEY_KP_ADD,
|
|
||||||
kp_enter = c.KB_KEY_KP_ENTER,
|
|
||||||
kp_equal = c.KB_KEY_KP_EQUAL,
|
|
||||||
left_shift = c.KB_KEY_LEFT_SHIFT,
|
|
||||||
left_control = c.KB_KEY_LEFT_CONTROL,
|
|
||||||
left_alt = c.KB_KEY_LEFT_ALT,
|
|
||||||
left_super = c.KB_KEY_LEFT_SUPER,
|
|
||||||
right_shift = c.KB_KEY_RIGHT_SHIFT,
|
|
||||||
right_control = c.KB_KEY_RIGHT_CONTROL,
|
|
||||||
right_alt = c.KB_KEY_RIGHT_ALT,
|
|
||||||
right_super = c.KB_KEY_RIGHT_SUPER,
|
|
||||||
menu = c.KB_KEY_MENU,
|
|
||||||
_,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const KeyMod = packed struct {
|
|
||||||
shift: bool = false,
|
|
||||||
control: bool = false,
|
|
||||||
alt: bool = false,
|
|
||||||
super: bool = false,
|
|
||||||
caps_lock: bool = false,
|
|
||||||
num_lock: bool = false,
|
|
||||||
_reserved: u26 = 0,
|
|
||||||
|
|
||||||
fn putName(present: bool, name: []const u8, names: *[6][]const u8, index: *usize) void {
|
|
||||||
if (present) {
|
|
||||||
names.*[index.*] = name;
|
|
||||||
index.* += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn format(self: KeyMod, comptime fmt: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
||||||
var names: [6][]const u8 = undefined;
|
|
||||||
var i: usize = 0;
|
|
||||||
|
|
||||||
if (fmt.len > 0) {
|
|
||||||
@compileError("Unknown format character: '" ++ fmt ++ "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
putName(self.shift, "Shift", &names, &i);
|
|
||||||
putName(self.control, "Control", &names, &i);
|
|
||||||
putName(self.alt, "Alt", &names, &i);
|
|
||||||
putName(self.super, "Super", &names, &i);
|
|
||||||
putName(self.caps_lock, "Caps_Lock", &names, &i);
|
|
||||||
putName(self.num_lock, "Num_Lock", &names, &i);
|
|
||||||
var first = true;
|
|
||||||
for (names[0..i]) |name| {
|
|
||||||
if (!first) {
|
|
||||||
_ = try writer.write("+");
|
|
||||||
}
|
|
||||||
_ = try writer.write(name);
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const MouseButton = enum(c_int) {
|
|
||||||
@"0" = c.MOUSE_BTN_0,
|
|
||||||
@"1" = c.MOUSE_BTN_1,
|
|
||||||
@"2" = c.MOUSE_BTN_2,
|
|
||||||
@"3" = c.MOUSE_BTN_3,
|
|
||||||
@"4" = c.MOUSE_BTN_4,
|
|
||||||
@"5" = c.MOUSE_BTN_5,
|
|
||||||
@"6" = c.MOUSE_BTN_6,
|
|
||||||
@"7" = c.MOUSE_BTN_7,
|
|
||||||
_,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn Window(comptime TUserData: type) type {
|
|
||||||
return extern struct {
|
|
||||||
cwin: *c.mfb_window,
|
|
||||||
|
|
||||||
pub const UpdateError = error{
|
|
||||||
InvalidWindow,
|
|
||||||
InvalidBuffer,
|
|
||||||
InternalError,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const UpdateState = enum {
|
|
||||||
ok,
|
|
||||||
exit,
|
|
||||||
|
|
||||||
pub fn from(state: c.mfb_update_state) UpdateError!UpdateState {
|
|
||||||
return switch (state) {
|
|
||||||
c.STATE_OK => UpdateState.ok,
|
|
||||||
c.STATE_EXIT => UpdateState.exit,
|
|
||||||
c.STATE_INVALID_WINDOW => UpdateError.InvalidWindow,
|
|
||||||
c.STATE_INVALID_BUFFER => UpdateError.InvalidBuffer,
|
|
||||||
else => UpdateError.InternalError,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const OpenFlags = packed struct {
|
|
||||||
resizable: bool = false,
|
|
||||||
fullscreen: bool = false,
|
|
||||||
fullscreen_desktop: bool = false,
|
|
||||||
borderless: bool = false,
|
|
||||||
always_on_top: bool = false,
|
|
||||||
reserved: u27 = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const OpenError = error{OpenFailed};
|
|
||||||
pub fn open(title: [*:0]const u8, width: u32, height: u32, flags: OpenFlags) OpenError!Window(TUserData) {
|
|
||||||
const cwin: ?*c.mfb_window = c.mfb_open_ex(title, width, height, @bitCast(u32, flags));
|
|
||||||
if (cwin) |value| {
|
|
||||||
const win = Window(TUserData){ .cwin = value };
|
|
||||||
assert(@bitCast(usize, win) == @ptrToInt(win.cwin));
|
|
||||||
return win;
|
|
||||||
} else {
|
|
||||||
return OpenError.OpenFailed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn close(self: Window(TUserData)) void {
|
|
||||||
c.mfb_close(self.cwin);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn waitSync(self: Window(TUserData)) bool {
|
|
||||||
return c.mfb_wait_sync(self.cwin);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(self: Window(TUserData), buffer: []Rgb) UpdateError!UpdateState {
|
|
||||||
return UpdateState.from(c.mfb_update(self.cwin, @ptrCast(*anyopaque, buffer.ptr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn updateEvents(self: Window(TUserData)) UpdateError!UpdateState {
|
|
||||||
return UpdateState.from(c.mfb_update_events(self.cwin));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn updateEx(self: Window(TUserData), buffer: []Rgb, width: u32, height: u32) UpdateError!UpdateState {
|
|
||||||
return UpdateState.from(c.mfb_update_ex(self.cwin), @ptrCast(*anyopaque, buffer), width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setUserData(self: Window(TUserData), data: *TUserData) void {
|
|
||||||
c.mfb_set_user_data(self.cwin, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getUserData(self: Window(TUserData)) ?*TUserData {
|
|
||||||
var cData = c.mfb_get_user_data(self.cwin);
|
|
||||||
return @ptrCast(?*TUserData, @alignCast(@alignOf(TUserData), cData));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const ActiveFunc = fn (win: Window(TUserData), isActive: bool) callconv(.C) void;
|
|
||||||
pub fn setActiveCallback(self: Window(TUserData), callback: ActiveFunc) void {
|
|
||||||
c.mfb_set_active_callback(self.cwin, @ptrCast(c.mfb_active_func, callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const ResizeFunc = fn (win: Window(TUserData), width: i32, height: i32) callconv(.C) void;
|
|
||||||
pub fn setResizeCallback(self: Window(TUserData), callback: ResizeFunc) void {
|
|
||||||
c.mfb_set_resize_callback(self.cwin, @ptrCast(c.mfb_resize_func, callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const MouseButtonFunc = fn (win: Window(TUserData), mouse_button: MouseButton, key_mod: KeyMod, is_pressed: bool) callconv(.C) void;
|
|
||||||
pub fn setMouseButtonCallback(self: Window(TUserData), callback: MouseButtonFunc) void {
|
|
||||||
c.mfb_set_mouse_button_callback(self.cwin, @ptrCast(c.mfb_mouse_button_func, callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const MouseMoveFunc = fn (win: Window(TUserData), x: i32, y: i32) callconv(.C) void;
|
|
||||||
pub fn setMouseMoveCallback(self: Window(TUserData), callback: MouseMoveFunc) void {
|
|
||||||
c.mfb_set_mouse_move_callback(self.cwin, @ptrCast(c.mfb_mouse_move_func, callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const MouseScrollFunc = fn (win: Window(TUserData), key_mod: KeyMod, delta_x: f32, delty_y: f32) callconv(.C) void;
|
|
||||||
pub fn setMouseScrollCallback(self: Window(TUserData), callback: MouseScrollFunc) void {
|
|
||||||
c.mfb_set_mouse_scroll_callback(self.cwin, @ptrCast(c.mfb_mouse_scroll_func, callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const KeyboardFunc = fn (win: Window(TUserData), key: Key, key_mod: KeyMod, is_pressed: bool) callconv(.C) void;
|
|
||||||
pub fn setKeyboardCallback(self: Window(TUserData), callback: KeyboardFunc) void {
|
|
||||||
c.mfb_set_keyboard_callback(self.cwin, @ptrCast(c.mfb_keyboard_func, callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const CharInputFunc = fn (win: Window(TUserData), code: u32) callconv(.C) void;
|
|
||||||
pub fn setCharInputCallback(self: Window(TUserData), callback: CharInputFunc) void {
|
|
||||||
c.mfb_set_char_input_callback(self.cwin, @ptrCast(c.mfb_char_input_func, callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setViewport(self: Window(TUserData), offset_x: u32, offset_y: u32, width: u32, height: u32) bool {
|
|
||||||
return c.mfb_set_viewport(self.cwin, offset_x, offset_y, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const MonitorScale = struct {
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
};
|
|
||||||
pub fn getMonitorScale(self: Window(TUserData)) MonitorScale {
|
|
||||||
var scale = MonitorScale{
|
|
||||||
.x = undefined,
|
|
||||||
.y = undefined,
|
|
||||||
};
|
|
||||||
c.mfb_get_monitor_scale(self.cwin, &scale.x, &scale.y);
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
test "user data is null if never set" {
|
|
||||||
const win = try Window(u64).open("abc", 100, 100, .{});
|
|
||||||
defer win.close();
|
|
||||||
const data = win.getUserData();
|
|
||||||
try testing.expectEqual(@as(?*u64, null), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "user data is not null if previously set" {
|
|
||||||
const win = try Window(u64).open("abc", 100, 100, .{});
|
|
||||||
defer win.close();
|
|
||||||
var data: u64 = 42;
|
|
||||||
win.setUserData(&data);
|
|
||||||
const expected: u64 = 42;
|
|
||||||
try testing.expectEqual(expected, win.getUserData().?.*);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "also works with smaller user data" {
|
|
||||||
const win = try Window(u8).open("abc", 100, 100, .{});
|
|
||||||
defer win.close();
|
|
||||||
var data: u8 = 42;
|
|
||||||
win.setUserData(&data);
|
|
||||||
const expected: u8 = 42;
|
|
||||||
try testing.expectEqual(expected, win.getUserData().?.*);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getTargetFPS() u32 {
|
|
||||||
return c.mfb_get_target_fps();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setTargetFPS(fps: u32) void {
|
|
||||||
c.mfb_set_target_fps(fps);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "set and get target FPS" {
|
|
||||||
const max = 40;
|
|
||||||
var fps: u32 = 30;
|
|
||||||
while (fps < max) {
|
|
||||||
setTargetFPS(fps);
|
|
||||||
try std.testing.expectEqual(fps, getTargetFPS());
|
|
||||||
fps += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const Timer = extern struct {
|
|
||||||
ctimer: *c.mfb_timer,
|
|
||||||
|
|
||||||
pub fn init() std.mem.Allocator.Error!Timer {
|
|
||||||
const ctimer: ?*c.mfb_timer = c.mfb_timer_create();
|
|
||||||
if (ctimer) |value| {
|
|
||||||
return Timer{ .ctimer = value };
|
|
||||||
} else {
|
|
||||||
return std.mem.Allocator.Error.OutOfMemory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: Timer) void {
|
|
||||||
c.mfb_timer_destroy(self.ctimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(self: Timer) void {
|
|
||||||
c.mfb_timer_reset(self.ctimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn now(self: Timer) f64 {
|
|
||||||
return c.mfb_timer_now(self.ctimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delta(self: Timer) f64 {
|
|
||||||
return c.mfb_timer_delta(self.ctimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getFrequency() f64 {
|
|
||||||
return c.mfb_timer_get_frequency();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getResolution() f64 {
|
|
||||||
return c.mfb_timer_get_resolution();
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,91 +0,0 @@
|
|||||||
#ifndef _MINIFB_H_
|
|
||||||
#define _MINIFB_H_
|
|
||||||
|
|
||||||
#include "MiniFB_enums.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#define MFB_RGB(r, g, b) (((uint32_t) r) << 16) | (((uint32_t) g) << 8) | ((uint32_t) b)
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Create a window that is used to display the buffer sent into the mfb_update function, returns 0 if fails
|
|
||||||
struct mfb_window * mfb_open(const char *title, unsigned width, unsigned height);
|
|
||||||
struct mfb_window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags);
|
|
||||||
|
|
||||||
// Update the display
|
|
||||||
// Input buffer is assumed to be a 32-bit buffer of the size given in the open call
|
|
||||||
// Will return a negative status if something went wrong or the user want to exit
|
|
||||||
// Also updates the window events
|
|
||||||
mfb_update_state mfb_update(struct mfb_window *window, void *buffer);
|
|
||||||
|
|
||||||
mfb_update_state mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned height);
|
|
||||||
|
|
||||||
// Only updates the window events
|
|
||||||
mfb_update_state mfb_update_events(struct mfb_window *window);
|
|
||||||
|
|
||||||
// Close the window
|
|
||||||
void mfb_close(struct mfb_window *window);
|
|
||||||
|
|
||||||
// Set user data
|
|
||||||
void mfb_set_user_data(struct mfb_window *window, void *user_data);
|
|
||||||
void * mfb_get_user_data(struct mfb_window *window);
|
|
||||||
|
|
||||||
// Set viewport (useful when resize)
|
|
||||||
bool mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height);
|
|
||||||
|
|
||||||
// DPI
|
|
||||||
// [Deprecated]: Probably a better name will be mfb_get_monitor_scale
|
|
||||||
void mfb_get_monitor_dpi(struct mfb_window *window, float *dpi_x, float *dpi_y);
|
|
||||||
// Use this instead
|
|
||||||
void mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y);
|
|
||||||
|
|
||||||
// Callbacks
|
|
||||||
void mfb_set_active_callback(struct mfb_window *window, mfb_active_func callback);
|
|
||||||
void mfb_set_resize_callback(struct mfb_window *window, mfb_resize_func callback);
|
|
||||||
void mfb_set_keyboard_callback(struct mfb_window *window, mfb_keyboard_func callback);
|
|
||||||
void mfb_set_char_input_callback(struct mfb_window *window, mfb_char_input_func callback);
|
|
||||||
void mfb_set_mouse_button_callback(struct mfb_window *window, mfb_mouse_button_func callback);
|
|
||||||
void mfb_set_mouse_move_callback(struct mfb_window *window, mfb_mouse_move_func callback);
|
|
||||||
void mfb_set_mouse_scroll_callback(struct mfb_window *window, mfb_mouse_scroll_func callback);
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
const char * mfb_get_key_name(mfb_key key);
|
|
||||||
|
|
||||||
bool mfb_is_window_active(struct mfb_window *window);
|
|
||||||
unsigned mfb_get_window_width(struct mfb_window *window);
|
|
||||||
unsigned mfb_get_window_height(struct mfb_window *window);
|
|
||||||
int mfb_get_mouse_x(struct mfb_window *window); // Last mouse pos X
|
|
||||||
int mfb_get_mouse_y(struct mfb_window *window); // Last mouse pos Y
|
|
||||||
float mfb_get_mouse_scroll_x(struct mfb_window *window); // Mouse wheel X as a sum. When you call this function it resets.
|
|
||||||
float mfb_get_mouse_scroll_y(struct mfb_window *window); // Mouse wheel Y as a sum. When you call this function it resets.
|
|
||||||
const uint8_t * mfb_get_mouse_button_buffer(struct mfb_window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons)
|
|
||||||
const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0.
|
|
||||||
|
|
||||||
// FPS
|
|
||||||
void mfb_set_target_fps(uint32_t fps);
|
|
||||||
unsigned mfb_get_target_fps();
|
|
||||||
bool mfb_wait_sync(struct mfb_window *window);
|
|
||||||
|
|
||||||
// Timer
|
|
||||||
struct mfb_timer * mfb_timer_create(void);
|
|
||||||
void mfb_timer_destroy(struct mfb_timer *tmr);
|
|
||||||
void mfb_timer_reset(struct mfb_timer *tmr);
|
|
||||||
double mfb_timer_now(struct mfb_timer *tmr);
|
|
||||||
double mfb_timer_delta(struct mfb_timer *tmr);
|
|
||||||
double mfb_timer_get_frequency(void);
|
|
||||||
double mfb_timer_get_resolution(void);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "MiniFB_cpp.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,136 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include "MiniFB.h"
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, bool));
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int));
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key, mfb_key_mod, bool));
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, unsigned int));
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool));
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int));
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key_mod, float, float));
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
// To avoid clumsy hands
|
|
||||||
//-------------------------------------
|
|
||||||
class mfb_stub {
|
|
||||||
mfb_stub() : m_window(0x0) {}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
friend void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, bool));
|
|
||||||
template <class T>
|
|
||||||
friend void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int));
|
|
||||||
template <class T>
|
|
||||||
friend void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool));
|
|
||||||
template <class T>
|
|
||||||
friend void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key, mfb_key_mod, bool));
|
|
||||||
template <class T>
|
|
||||||
friend void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, unsigned int));
|
|
||||||
template <class T>
|
|
||||||
friend void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool));
|
|
||||||
template <class T>
|
|
||||||
friend void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int));
|
|
||||||
template <class T>
|
|
||||||
friend void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key_mod, float, float));
|
|
||||||
|
|
||||||
static mfb_stub *GetInstance(struct mfb_window *window);
|
|
||||||
|
|
||||||
static void active_stub(struct mfb_window *window, bool isActive);
|
|
||||||
static void resize_stub(struct mfb_window *window, int width, int height);
|
|
||||||
static void keyboard_stub(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed);
|
|
||||||
static void char_input_stub(struct mfb_window *window, unsigned int);
|
|
||||||
static void mouse_btn_stub(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed);
|
|
||||||
static void mouse_move_stub(struct mfb_window *window, int x, int y);
|
|
||||||
static void scroll_stub(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY);
|
|
||||||
|
|
||||||
struct mfb_window *m_window;
|
|
||||||
std::function<void(struct mfb_window *window, bool)> m_active;
|
|
||||||
std::function<void(struct mfb_window *window, int, int)> m_resize;
|
|
||||||
std::function<void(struct mfb_window *window, mfb_key, mfb_key_mod, bool)> m_keyboard;
|
|
||||||
std::function<void(struct mfb_window *window, unsigned int)> m_char_input;
|
|
||||||
std::function<void(struct mfb_window *window, mfb_mouse_button, mfb_key_mod, bool)> m_mouse_btn;
|
|
||||||
std::function<void(struct mfb_window *window, int, int)> m_mouse_move;
|
|
||||||
std::function<void(struct mfb_window *window, mfb_key_mod, float, float)> m_scroll;
|
|
||||||
};
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
template <class T>
|
|
||||||
inline void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, bool)) {
|
|
||||||
using namespace std::placeholders;
|
|
||||||
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_active = std::bind(method, obj, _1, _2);
|
|
||||||
mfb_set_active_callback(window, mfb_stub::active_stub);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, int, int)) {
|
|
||||||
using namespace std::placeholders;
|
|
||||||
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_resize = std::bind(method, obj, _1, _2, _3);
|
|
||||||
mfb_set_resize_callback(window, mfb_stub::resize_stub);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, mfb_key, mfb_key_mod, bool)) {
|
|
||||||
using namespace std::placeholders;
|
|
||||||
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_keyboard = std::bind(method, obj, _1, _2, _3, _4);
|
|
||||||
mfb_set_keyboard_callback(window, mfb_stub::keyboard_stub);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, unsigned int)) {
|
|
||||||
using namespace std::placeholders;
|
|
||||||
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_char_input = std::bind(method, obj, _1, _2);
|
|
||||||
mfb_set_char_input_callback(window, mfb_stub::char_input_stub);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, mfb_mouse_button, mfb_key_mod, bool)) {
|
|
||||||
using namespace std::placeholders;
|
|
||||||
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_mouse_btn = std::bind(method, obj, _1, _2, _3, _4);
|
|
||||||
mfb_set_mouse_button_callback(window, mfb_stub::mouse_btn_stub);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, int, int)) {
|
|
||||||
using namespace std::placeholders;
|
|
||||||
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_mouse_move = std::bind(method, obj, _1, _2, _3);
|
|
||||||
mfb_set_mouse_move_callback(window, mfb_stub::mouse_move_stub);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, mfb_key_mod, float, float)) {
|
|
||||||
using namespace std::placeholders;
|
|
||||||
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_scroll = std::bind(method, obj, _1, _2, _3, _4);
|
|
||||||
mfb_set_mouse_scroll_callback(window, mfb_stub::scroll_stub);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,185 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
// Enums
|
|
||||||
typedef enum {
|
|
||||||
STATE_OK = 0,
|
|
||||||
STATE_EXIT = -1,
|
|
||||||
STATE_INVALID_WINDOW = -2,
|
|
||||||
STATE_INVALID_BUFFER = -3,
|
|
||||||
STATE_INTERNAL_ERROR = -4,
|
|
||||||
} mfb_update_state;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
MOUSE_BTN_0, // No mouse button
|
|
||||||
MOUSE_BTN_1,
|
|
||||||
MOUSE_BTN_2,
|
|
||||||
MOUSE_BTN_3,
|
|
||||||
MOUSE_BTN_4,
|
|
||||||
MOUSE_BTN_5,
|
|
||||||
MOUSE_BTN_6,
|
|
||||||
MOUSE_BTN_7,
|
|
||||||
} mfb_mouse_button;
|
|
||||||
#define MOUSE_LEFT MOUSE_BTN_1
|
|
||||||
#define MOUSE_RIGHT MOUSE_BTN_2
|
|
||||||
#define MOUSE_MIDDLE MOUSE_BTN_3
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
KB_KEY_UNKNOWN = -1,
|
|
||||||
|
|
||||||
KB_KEY_SPACE = 32,
|
|
||||||
KB_KEY_APOSTROPHE = 39,
|
|
||||||
KB_KEY_COMMA = 44,
|
|
||||||
KB_KEY_MINUS = 45,
|
|
||||||
KB_KEY_PERIOD = 46,
|
|
||||||
KB_KEY_SLASH = 47,
|
|
||||||
KB_KEY_0 = 48,
|
|
||||||
KB_KEY_1 = 49,
|
|
||||||
KB_KEY_2 = 50,
|
|
||||||
KB_KEY_3 = 51,
|
|
||||||
KB_KEY_4 = 52,
|
|
||||||
KB_KEY_5 = 53,
|
|
||||||
KB_KEY_6 = 54,
|
|
||||||
KB_KEY_7 = 55,
|
|
||||||
KB_KEY_8 = 56,
|
|
||||||
KB_KEY_9 = 57,
|
|
||||||
KB_KEY_SEMICOLON = 59,
|
|
||||||
KB_KEY_EQUAL = 61,
|
|
||||||
KB_KEY_A = 65,
|
|
||||||
KB_KEY_B = 66,
|
|
||||||
KB_KEY_C = 67,
|
|
||||||
KB_KEY_D = 68,
|
|
||||||
KB_KEY_E = 69,
|
|
||||||
KB_KEY_F = 70,
|
|
||||||
KB_KEY_G = 71,
|
|
||||||
KB_KEY_H = 72,
|
|
||||||
KB_KEY_I = 73,
|
|
||||||
KB_KEY_J = 74,
|
|
||||||
KB_KEY_K = 75,
|
|
||||||
KB_KEY_L = 76,
|
|
||||||
KB_KEY_M = 77,
|
|
||||||
KB_KEY_N = 78,
|
|
||||||
KB_KEY_O = 79,
|
|
||||||
KB_KEY_P = 80,
|
|
||||||
KB_KEY_Q = 81,
|
|
||||||
KB_KEY_R = 82,
|
|
||||||
KB_KEY_S = 83,
|
|
||||||
KB_KEY_T = 84,
|
|
||||||
KB_KEY_U = 85,
|
|
||||||
KB_KEY_V = 86,
|
|
||||||
KB_KEY_W = 87,
|
|
||||||
KB_KEY_X = 88,
|
|
||||||
KB_KEY_Y = 89,
|
|
||||||
KB_KEY_Z = 90,
|
|
||||||
KB_KEY_LEFT_BRACKET = 91,
|
|
||||||
KB_KEY_BACKSLASH = 92,
|
|
||||||
KB_KEY_RIGHT_BRACKET = 93,
|
|
||||||
KB_KEY_GRAVE_ACCENT = 96,
|
|
||||||
KB_KEY_WORLD_1 = 161,
|
|
||||||
KB_KEY_WORLD_2 = 162,
|
|
||||||
|
|
||||||
KB_KEY_ESCAPE = 256,
|
|
||||||
KB_KEY_ENTER = 257,
|
|
||||||
KB_KEY_TAB = 258,
|
|
||||||
KB_KEY_BACKSPACE = 259,
|
|
||||||
KB_KEY_INSERT = 260,
|
|
||||||
KB_KEY_DELETE = 261,
|
|
||||||
KB_KEY_RIGHT = 262,
|
|
||||||
KB_KEY_LEFT = 263,
|
|
||||||
KB_KEY_DOWN = 264,
|
|
||||||
KB_KEY_UP = 265,
|
|
||||||
KB_KEY_PAGE_UP = 266,
|
|
||||||
KB_KEY_PAGE_DOWN = 267,
|
|
||||||
KB_KEY_HOME = 268,
|
|
||||||
KB_KEY_END = 269,
|
|
||||||
KB_KEY_CAPS_LOCK = 280,
|
|
||||||
KB_KEY_SCROLL_LOCK = 281,
|
|
||||||
KB_KEY_NUM_LOCK = 282,
|
|
||||||
KB_KEY_PRINT_SCREEN = 283,
|
|
||||||
KB_KEY_PAUSE = 284,
|
|
||||||
KB_KEY_F1 = 290,
|
|
||||||
KB_KEY_F2 = 291,
|
|
||||||
KB_KEY_F3 = 292,
|
|
||||||
KB_KEY_F4 = 293,
|
|
||||||
KB_KEY_F5 = 294,
|
|
||||||
KB_KEY_F6 = 295,
|
|
||||||
KB_KEY_F7 = 296,
|
|
||||||
KB_KEY_F8 = 297,
|
|
||||||
KB_KEY_F9 = 298,
|
|
||||||
KB_KEY_F10 = 299,
|
|
||||||
KB_KEY_F11 = 300,
|
|
||||||
KB_KEY_F12 = 301,
|
|
||||||
KB_KEY_F13 = 302,
|
|
||||||
KB_KEY_F14 = 303,
|
|
||||||
KB_KEY_F15 = 304,
|
|
||||||
KB_KEY_F16 = 305,
|
|
||||||
KB_KEY_F17 = 306,
|
|
||||||
KB_KEY_F18 = 307,
|
|
||||||
KB_KEY_F19 = 308,
|
|
||||||
KB_KEY_F20 = 309,
|
|
||||||
KB_KEY_F21 = 310,
|
|
||||||
KB_KEY_F22 = 311,
|
|
||||||
KB_KEY_F23 = 312,
|
|
||||||
KB_KEY_F24 = 313,
|
|
||||||
KB_KEY_F25 = 314,
|
|
||||||
KB_KEY_KP_0 = 320,
|
|
||||||
KB_KEY_KP_1 = 321,
|
|
||||||
KB_KEY_KP_2 = 322,
|
|
||||||
KB_KEY_KP_3 = 323,
|
|
||||||
KB_KEY_KP_4 = 324,
|
|
||||||
KB_KEY_KP_5 = 325,
|
|
||||||
KB_KEY_KP_6 = 326,
|
|
||||||
KB_KEY_KP_7 = 327,
|
|
||||||
KB_KEY_KP_8 = 328,
|
|
||||||
KB_KEY_KP_9 = 329,
|
|
||||||
KB_KEY_KP_DECIMAL = 330,
|
|
||||||
KB_KEY_KP_DIVIDE = 331,
|
|
||||||
KB_KEY_KP_MULTIPLY = 332,
|
|
||||||
KB_KEY_KP_SUBTRACT = 333,
|
|
||||||
KB_KEY_KP_ADD = 334,
|
|
||||||
KB_KEY_KP_ENTER = 335,
|
|
||||||
KB_KEY_KP_EQUAL = 336,
|
|
||||||
KB_KEY_LEFT_SHIFT = 340,
|
|
||||||
KB_KEY_LEFT_CONTROL = 341,
|
|
||||||
KB_KEY_LEFT_ALT = 342,
|
|
||||||
KB_KEY_LEFT_SUPER = 343,
|
|
||||||
KB_KEY_RIGHT_SHIFT = 344,
|
|
||||||
KB_KEY_RIGHT_CONTROL = 345,
|
|
||||||
KB_KEY_RIGHT_ALT = 346,
|
|
||||||
KB_KEY_RIGHT_SUPER = 347,
|
|
||||||
KB_KEY_MENU = 348
|
|
||||||
} mfb_key;
|
|
||||||
#define KB_KEY_LAST KB_KEY_MENU
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
KB_MOD_SHIFT = 0x0001,
|
|
||||||
KB_MOD_CONTROL = 0x0002,
|
|
||||||
KB_MOD_ALT = 0x0004,
|
|
||||||
KB_MOD_SUPER = 0x0008,
|
|
||||||
KB_MOD_CAPS_LOCK = 0x0010,
|
|
||||||
KB_MOD_NUM_LOCK = 0x0020
|
|
||||||
} mfb_key_mod;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
WF_RESIZABLE = 0x01,
|
|
||||||
WF_FULLSCREEN = 0x02,
|
|
||||||
WF_FULLSCREEN_DESKTOP = 0x04,
|
|
||||||
WF_BORDERLESS = 0x08,
|
|
||||||
WF_ALWAYS_ON_TOP = 0x10,
|
|
||||||
} mfb_window_flags;
|
|
||||||
|
|
||||||
// Opaque pointer
|
|
||||||
struct mfb_window;
|
|
||||||
struct mfb_timer;
|
|
||||||
|
|
||||||
// Event callbacks
|
|
||||||
typedef void(*mfb_active_func)(struct mfb_window *window, bool isActive);
|
|
||||||
typedef void(*mfb_resize_func)(struct mfb_window *window, int width, int height);
|
|
||||||
typedef void(*mfb_keyboard_func)(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed);
|
|
||||||
typedef void(*mfb_char_input_func)(struct mfb_window *window, unsigned int code);
|
|
||||||
typedef void(*mfb_mouse_button_func)(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed);
|
|
||||||
typedef void(*mfb_mouse_move_func)(struct mfb_window *window, int x, int y);
|
|
||||||
typedef void(*mfb_mouse_scroll_func)(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY);
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "MiniFB_enums.h"
|
|
||||||
|
|
||||||
void user_implemented_init(struct mfb_window *window);
|
|
||||||
|
|
||||||
void user_implemented_update(struct mfb_window *window);
|
|
@ -1,598 +0,0 @@
|
|||||||
#include <MiniFB.h>
|
|
||||||
#include "WindowData.h"
|
|
||||||
#include "MiniFB_internal.h"
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
short int g_keycodes[512] = { 0 };
|
|
||||||
//-------------------------------------
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
struct mfb_window *
|
|
||||||
mfb_open(const char *title, unsigned width, unsigned height) {
|
|
||||||
return mfb_open_ex(title, width, height, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
mfb_update_state
|
|
||||||
mfb_update(struct mfb_window *window, void *buffer) {
|
|
||||||
if (window == 0x0) {
|
|
||||||
return STATE_INVALID_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
|
|
||||||
return mfb_update_ex(window, buffer, window_data->buffer_width, window_data->buffer_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_set_active_callback(struct mfb_window *window, mfb_active_func callback) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
window_data->active_func = callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_set_resize_callback(struct mfb_window *window, mfb_resize_func callback) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
window_data->resize_func = callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_set_keyboard_callback(struct mfb_window *window, mfb_keyboard_func callback) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
window_data->keyboard_func = callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_set_char_input_callback(struct mfb_window *window, mfb_char_input_func callback) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
window_data->char_input_func = callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_set_mouse_button_callback(struct mfb_window *window, mfb_mouse_button_func callback) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
window_data->mouse_btn_func = callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_set_mouse_move_callback(struct mfb_window *window, mfb_mouse_move_func callback) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
window_data->mouse_move_func = callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_set_mouse_scroll_callback(struct mfb_window *window, mfb_mouse_scroll_func callback) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
window_data->mouse_wheel_func = callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_set_user_data(struct mfb_window *window, void *user_data) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
window_data->user_data = user_data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void *
|
|
||||||
mfb_get_user_data(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
return window_data->user_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// [Deprecated]
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_get_monitor_dpi(struct mfb_window *window, float *dpi_x, float *dpi_y) {
|
|
||||||
mfb_get_monitor_scale(window, dpi_x, dpi_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_close(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
window_data->close = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
keyboard_default(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) {
|
|
||||||
kUnused(mod);
|
|
||||||
kUnused(isPressed);
|
|
||||||
if (key == KB_KEY_ESCAPE) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
window_data->close = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
bool
|
|
||||||
mfb_is_window_active(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
return window_data->is_active;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
unsigned
|
|
||||||
mfb_get_window_width(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
return window_data->window_width;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
unsigned
|
|
||||||
mfb_get_window_height(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
return window_data->window_height;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
int
|
|
||||||
mfb_get_mouse_x(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
return window_data->mouse_pos_x;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
int
|
|
||||||
mfb_get_mouse_y(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
return window_data->mouse_pos_y;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
float
|
|
||||||
mfb_get_mouse_scroll_x(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
return window_data->mouse_wheel_x;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
float
|
|
||||||
mfb_get_mouse_scroll_y(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
return window_data->mouse_wheel_y;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
const uint8_t *
|
|
||||||
mfb_get_mouse_button_buffer(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
return window_data->mouse_button_status;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
const uint8_t *
|
|
||||||
mfb_get_key_buffer(struct mfb_window *window) {
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
return window_data->key_status;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
const char *
|
|
||||||
mfb_get_key_name(mfb_key key) {
|
|
||||||
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case KB_KEY_SPACE:
|
|
||||||
return "Space";
|
|
||||||
|
|
||||||
case KB_KEY_APOSTROPHE:
|
|
||||||
return "Apostrophe";
|
|
||||||
|
|
||||||
case KB_KEY_COMMA:
|
|
||||||
return "Comma";
|
|
||||||
|
|
||||||
case KB_KEY_MINUS:
|
|
||||||
return "Minus";
|
|
||||||
|
|
||||||
case KB_KEY_PERIOD:
|
|
||||||
return "Period";
|
|
||||||
|
|
||||||
case KB_KEY_SLASH:
|
|
||||||
return "Slash";
|
|
||||||
|
|
||||||
case KB_KEY_0:
|
|
||||||
return "0";
|
|
||||||
|
|
||||||
case KB_KEY_1:
|
|
||||||
return "1";
|
|
||||||
|
|
||||||
case KB_KEY_2:
|
|
||||||
return "2";
|
|
||||||
|
|
||||||
case KB_KEY_3:
|
|
||||||
return "3";
|
|
||||||
|
|
||||||
case KB_KEY_4:
|
|
||||||
return "4";
|
|
||||||
|
|
||||||
case KB_KEY_5:
|
|
||||||
return "5";
|
|
||||||
|
|
||||||
case KB_KEY_6:
|
|
||||||
return "6";
|
|
||||||
|
|
||||||
case KB_KEY_7:
|
|
||||||
return "7";
|
|
||||||
|
|
||||||
case KB_KEY_8:
|
|
||||||
return "8";
|
|
||||||
|
|
||||||
case KB_KEY_9:
|
|
||||||
return "9";
|
|
||||||
|
|
||||||
case KB_KEY_SEMICOLON:
|
|
||||||
return "Semicolon";
|
|
||||||
|
|
||||||
case KB_KEY_EQUAL:
|
|
||||||
return "Equal";
|
|
||||||
|
|
||||||
case KB_KEY_A:
|
|
||||||
return "A";
|
|
||||||
|
|
||||||
case KB_KEY_B:
|
|
||||||
return "B";
|
|
||||||
|
|
||||||
case KB_KEY_C:
|
|
||||||
return "C";
|
|
||||||
|
|
||||||
case KB_KEY_D:
|
|
||||||
return "D";
|
|
||||||
|
|
||||||
case KB_KEY_E:
|
|
||||||
return "E";
|
|
||||||
|
|
||||||
case KB_KEY_F:
|
|
||||||
return "F";
|
|
||||||
|
|
||||||
case KB_KEY_G:
|
|
||||||
return "G";
|
|
||||||
|
|
||||||
case KB_KEY_H:
|
|
||||||
return "H";
|
|
||||||
|
|
||||||
case KB_KEY_I:
|
|
||||||
return "I";
|
|
||||||
|
|
||||||
case KB_KEY_J:
|
|
||||||
return "J";
|
|
||||||
|
|
||||||
case KB_KEY_K:
|
|
||||||
return "K";
|
|
||||||
|
|
||||||
case KB_KEY_L:
|
|
||||||
return "L";
|
|
||||||
|
|
||||||
case KB_KEY_M:
|
|
||||||
return "M";
|
|
||||||
|
|
||||||
case KB_KEY_N:
|
|
||||||
return "N";
|
|
||||||
|
|
||||||
case KB_KEY_O:
|
|
||||||
return "O";
|
|
||||||
|
|
||||||
case KB_KEY_P:
|
|
||||||
return "P";
|
|
||||||
|
|
||||||
case KB_KEY_Q:
|
|
||||||
return "Q";
|
|
||||||
|
|
||||||
case KB_KEY_R:
|
|
||||||
return "R";
|
|
||||||
|
|
||||||
case KB_KEY_S:
|
|
||||||
return "S";
|
|
||||||
|
|
||||||
case KB_KEY_T:
|
|
||||||
return "T";
|
|
||||||
|
|
||||||
case KB_KEY_U:
|
|
||||||
return "U";
|
|
||||||
|
|
||||||
case KB_KEY_V:
|
|
||||||
return "V";
|
|
||||||
|
|
||||||
case KB_KEY_W:
|
|
||||||
return "W";
|
|
||||||
|
|
||||||
case KB_KEY_X:
|
|
||||||
return "X";
|
|
||||||
|
|
||||||
case KB_KEY_Y:
|
|
||||||
return "Y";
|
|
||||||
|
|
||||||
case KB_KEY_Z:
|
|
||||||
return "Z";
|
|
||||||
|
|
||||||
case KB_KEY_LEFT_BRACKET:
|
|
||||||
return "Left_Bracket";
|
|
||||||
|
|
||||||
case KB_KEY_BACKSLASH:
|
|
||||||
return "Backslash";
|
|
||||||
|
|
||||||
case KB_KEY_RIGHT_BRACKET:
|
|
||||||
return "Right_Bracket";
|
|
||||||
|
|
||||||
case KB_KEY_GRAVE_ACCENT:
|
|
||||||
return "Grave_Accent";
|
|
||||||
|
|
||||||
case KB_KEY_WORLD_1:
|
|
||||||
return "World_1";
|
|
||||||
|
|
||||||
case KB_KEY_WORLD_2:
|
|
||||||
return "World_2";
|
|
||||||
|
|
||||||
case KB_KEY_ESCAPE:
|
|
||||||
return "Escape";
|
|
||||||
|
|
||||||
case KB_KEY_ENTER:
|
|
||||||
return "Enter";
|
|
||||||
|
|
||||||
case KB_KEY_TAB:
|
|
||||||
return "Tab";
|
|
||||||
|
|
||||||
case KB_KEY_BACKSPACE:
|
|
||||||
return "Backspace";
|
|
||||||
|
|
||||||
case KB_KEY_INSERT:
|
|
||||||
return "Insert";
|
|
||||||
|
|
||||||
case KB_KEY_DELETE:
|
|
||||||
return "Delete";
|
|
||||||
|
|
||||||
case KB_KEY_RIGHT:
|
|
||||||
return "Right";
|
|
||||||
|
|
||||||
case KB_KEY_LEFT:
|
|
||||||
return "Left";
|
|
||||||
|
|
||||||
case KB_KEY_DOWN:
|
|
||||||
return "Down";
|
|
||||||
|
|
||||||
case KB_KEY_UP:
|
|
||||||
return "Up";
|
|
||||||
|
|
||||||
case KB_KEY_PAGE_UP:
|
|
||||||
return "Page_Up";
|
|
||||||
|
|
||||||
case KB_KEY_PAGE_DOWN:
|
|
||||||
return "Page_Down";
|
|
||||||
|
|
||||||
case KB_KEY_HOME:
|
|
||||||
return "Home";
|
|
||||||
|
|
||||||
case KB_KEY_END:
|
|
||||||
return "End";
|
|
||||||
|
|
||||||
case KB_KEY_CAPS_LOCK:
|
|
||||||
return "Caps_Lock";
|
|
||||||
|
|
||||||
case KB_KEY_SCROLL_LOCK:
|
|
||||||
return "Scroll_Lock";
|
|
||||||
|
|
||||||
case KB_KEY_NUM_LOCK:
|
|
||||||
return "Num_Lock";
|
|
||||||
|
|
||||||
case KB_KEY_PRINT_SCREEN:
|
|
||||||
return "Print_Screen";
|
|
||||||
|
|
||||||
case KB_KEY_PAUSE:
|
|
||||||
return "Pause";
|
|
||||||
|
|
||||||
case KB_KEY_F1:
|
|
||||||
return "F1";
|
|
||||||
|
|
||||||
case KB_KEY_F2:
|
|
||||||
return "F2";
|
|
||||||
|
|
||||||
case KB_KEY_F3:
|
|
||||||
return "F3";
|
|
||||||
|
|
||||||
case KB_KEY_F4:
|
|
||||||
return "F4";
|
|
||||||
|
|
||||||
case KB_KEY_F5:
|
|
||||||
return "F5";
|
|
||||||
|
|
||||||
case KB_KEY_F6:
|
|
||||||
return "F6";
|
|
||||||
|
|
||||||
case KB_KEY_F7:
|
|
||||||
return "F7";
|
|
||||||
|
|
||||||
case KB_KEY_F8:
|
|
||||||
return "F8";
|
|
||||||
|
|
||||||
case KB_KEY_F9:
|
|
||||||
return "F9";
|
|
||||||
|
|
||||||
case KB_KEY_F10:
|
|
||||||
return "F10";
|
|
||||||
|
|
||||||
case KB_KEY_F11:
|
|
||||||
return "F11";
|
|
||||||
|
|
||||||
case KB_KEY_F12:
|
|
||||||
return "F12";
|
|
||||||
|
|
||||||
case KB_KEY_F13:
|
|
||||||
return "F13";
|
|
||||||
|
|
||||||
case KB_KEY_F14:
|
|
||||||
return "F14";
|
|
||||||
|
|
||||||
case KB_KEY_F15:
|
|
||||||
return "F15";
|
|
||||||
|
|
||||||
case KB_KEY_F16:
|
|
||||||
return "F16";
|
|
||||||
|
|
||||||
case KB_KEY_F17:
|
|
||||||
return "F17";
|
|
||||||
|
|
||||||
case KB_KEY_F18:
|
|
||||||
return "F18";
|
|
||||||
|
|
||||||
case KB_KEY_F19:
|
|
||||||
return "F19";
|
|
||||||
|
|
||||||
case KB_KEY_F20:
|
|
||||||
return "F20";
|
|
||||||
|
|
||||||
case KB_KEY_F21:
|
|
||||||
return "F21";
|
|
||||||
|
|
||||||
case KB_KEY_F22:
|
|
||||||
return "F22";
|
|
||||||
|
|
||||||
case KB_KEY_F23:
|
|
||||||
return "F23";
|
|
||||||
|
|
||||||
case KB_KEY_F24:
|
|
||||||
return "F24";
|
|
||||||
|
|
||||||
case KB_KEY_F25:
|
|
||||||
return "F25";
|
|
||||||
|
|
||||||
case KB_KEY_KP_0:
|
|
||||||
return "KP_0";
|
|
||||||
|
|
||||||
case KB_KEY_KP_1:
|
|
||||||
return "KP_1";
|
|
||||||
|
|
||||||
case KB_KEY_KP_2:
|
|
||||||
return "KP_2";
|
|
||||||
|
|
||||||
case KB_KEY_KP_3:
|
|
||||||
return "KP_3";
|
|
||||||
|
|
||||||
case KB_KEY_KP_4:
|
|
||||||
return "KP_4";
|
|
||||||
|
|
||||||
case KB_KEY_KP_5:
|
|
||||||
return "KP_5";
|
|
||||||
|
|
||||||
case KB_KEY_KP_6:
|
|
||||||
return "KP_6";
|
|
||||||
|
|
||||||
case KB_KEY_KP_7:
|
|
||||||
return "KP_7";
|
|
||||||
|
|
||||||
case KB_KEY_KP_8:
|
|
||||||
return "KP_8";
|
|
||||||
|
|
||||||
case KB_KEY_KP_9:
|
|
||||||
return "KP_9";
|
|
||||||
|
|
||||||
case KB_KEY_KP_DECIMAL:
|
|
||||||
return "KP_Decimal";
|
|
||||||
|
|
||||||
case KB_KEY_KP_DIVIDE:
|
|
||||||
return "KP_Divide";
|
|
||||||
|
|
||||||
case KB_KEY_KP_MULTIPLY:
|
|
||||||
return "KP_Multiply";
|
|
||||||
|
|
||||||
case KB_KEY_KP_SUBTRACT:
|
|
||||||
return "KP_Subtract";
|
|
||||||
|
|
||||||
case KB_KEY_KP_ADD:
|
|
||||||
return "KP_Add";
|
|
||||||
|
|
||||||
case KB_KEY_KP_ENTER:
|
|
||||||
return "KP_Enter";
|
|
||||||
|
|
||||||
case KB_KEY_KP_EQUAL:
|
|
||||||
return "KP_Equal";
|
|
||||||
|
|
||||||
case KB_KEY_LEFT_SHIFT:
|
|
||||||
return "Left_Shift";
|
|
||||||
|
|
||||||
case KB_KEY_LEFT_CONTROL:
|
|
||||||
return "Left_Control";
|
|
||||||
|
|
||||||
case KB_KEY_LEFT_ALT:
|
|
||||||
return "Left_Alt";
|
|
||||||
|
|
||||||
case KB_KEY_LEFT_SUPER:
|
|
||||||
return "Left_Super";
|
|
||||||
|
|
||||||
case KB_KEY_RIGHT_SHIFT:
|
|
||||||
return "Right_Shift";
|
|
||||||
|
|
||||||
case KB_KEY_RIGHT_CONTROL:
|
|
||||||
return "Right_Control";
|
|
||||||
|
|
||||||
case KB_KEY_RIGHT_ALT:
|
|
||||||
return "Right_Alt";
|
|
||||||
|
|
||||||
case KB_KEY_RIGHT_SUPER:
|
|
||||||
return "Right_Super";
|
|
||||||
|
|
||||||
case KB_KEY_MENU:
|
|
||||||
return "Menu";
|
|
||||||
|
|
||||||
case KB_KEY_UNKNOWN:
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
#include <MiniFB_cpp.h>
|
|
||||||
#include <MiniFB_enums.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
mfb_stub *
|
|
||||||
mfb_stub::GetInstance(struct mfb_window *window) {
|
|
||||||
static std::vector<mfb_stub *> s_instances;
|
|
||||||
|
|
||||||
for(mfb_stub *instance : s_instances) {
|
|
||||||
if(instance->m_window == window) {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s_instances.push_back(new mfb_stub);
|
|
||||||
s_instances.back()->m_window = window;
|
|
||||||
|
|
||||||
return s_instances.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_stub::active_stub(struct mfb_window *window, bool isActive) {
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_active(window, isActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_stub::resize_stub(struct mfb_window *window, int width, int height) {
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_resize(window, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_stub::keyboard_stub(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) {
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_keyboard(window, key, mod, isPressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_stub::char_input_stub(struct mfb_window *window, unsigned int code) {
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_char_input(window, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_stub::mouse_btn_stub(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed) {
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_mouse_btn(window, button, mod, isPressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_stub::mouse_move_stub(struct mfb_window *window, int x, int y) {
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_mouse_move(window, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_stub::scroll_stub(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY) {
|
|
||||||
mfb_stub *stub = mfb_stub::GetInstance(window);
|
|
||||||
stub->m_scroll(window, mod, deltaX, deltaY);
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
#include "MiniFB_internal.h"
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
//#define kUseBilinearInterpolation
|
|
||||||
|
|
||||||
#if defined(kUseBilinearInterpolation)
|
|
||||||
//-------------------------------------
|
|
||||||
static uint32_t
|
|
||||||
interpolate(uint32_t *srcImage, uint32_t x, uint32_t y, uint32_t srcOffsetX, uint32_t srcOffsetY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch) {
|
|
||||||
uint32_t incX = x + 1 < srcWidth ? 1 : 0;
|
|
||||||
uint32_t incY = y + 1 < srcHeight ? srcPitch : 0;
|
|
||||||
uint8_t *p00 = (uint8_t *) &srcImage[(srcOffsetX >> 16)];
|
|
||||||
uint8_t *p01 = (uint8_t *) &srcImage[(srcOffsetX >> 16) + incX];
|
|
||||||
uint8_t *p10 = (uint8_t *) &srcImage[(srcOffsetX >> 16) + incY];
|
|
||||||
uint8_t *p11 = (uint8_t *) &srcImage[(srcOffsetX >> 16) + incY + incX];
|
|
||||||
|
|
||||||
uint32_t wx2 = srcOffsetX & 0xffff;
|
|
||||||
uint32_t wy2 = srcOffsetY & 0xffff;
|
|
||||||
uint32_t wx1 = 0x10000 - wx2;
|
|
||||||
uint32_t wy1 = 0x10000 - wy2;
|
|
||||||
|
|
||||||
uint32_t w1 = ((uint64_t) wx1 * wy1) >> 16;
|
|
||||||
uint32_t w2 = ((uint64_t) wx2 * wy1) >> 16;
|
|
||||||
uint32_t w3 = ((uint64_t) wx1 * wy2) >> 16;
|
|
||||||
uint32_t w4 = ((uint64_t) wx2 * wy2) >> 16;
|
|
||||||
|
|
||||||
// If you don't have uint64_t
|
|
||||||
//uint32_t b = (((p00[0] * wx1 + p01[0] * wx2) >> 16) * wy1 + ((p10[0] * wx1 + p11[0] * wx2) >> 16) * wy2) >> 16;
|
|
||||||
//uint32_t g = (((p00[1] * wx1 + p01[1] * wx2) >> 16) * wy1 + ((p10[1] * wx1 + p11[1] * wx2) >> 16) * wy2) >> 16;
|
|
||||||
//uint32_t r = (((p00[2] * wx1 + p01[2] * wx2) >> 16) * wy1 + ((p10[2] * wx1 + p11[2] * wx2) >> 16) * wy2) >> 16;
|
|
||||||
//uint32_t a = (((p00[3] * wx1 + p01[3] * wx2) >> 16) * wy1 + ((p10[3] * wx1 + p11[3] * wx2) >> 16) * wy2) >> 16;
|
|
||||||
|
|
||||||
uint32_t b = ((p00[0] * w1 + p01[0] * w2) + (p10[0] * w3 + p11[0] * w4)) >> 16;
|
|
||||||
uint32_t g = ((p00[1] * w1 + p01[1] * w2) + (p10[1] * w3 + p11[1] * w4)) >> 16;
|
|
||||||
uint32_t r = ((p00[2] * w1 + p01[2] * w2) + (p10[2] * w3 + p11[2] * w4)) >> 16;
|
|
||||||
uint32_t a = ((p00[3] * w1 + p01[3] * w2) + (p10[3] * w3 + p11[3] * w4)) >> 16;
|
|
||||||
|
|
||||||
return (a << 24) + (r << 16) + (g << 8) + b;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Only for 32 bits images
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch,
|
|
||||||
uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch) {
|
|
||||||
|
|
||||||
uint32_t x, y;
|
|
||||||
uint32_t srcOffsetX, srcOffsetY;
|
|
||||||
|
|
||||||
if(srcImage == 0x0 || dstImage == 0x0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
srcImage += srcX + srcY * srcPitch;
|
|
||||||
dstImage += dstX + dstY * dstPitch;
|
|
||||||
|
|
||||||
const uint32_t deltaX = (srcWidth << 16) / dstWidth;
|
|
||||||
const uint32_t deltaY = (srcHeight << 16) / dstHeight;
|
|
||||||
|
|
||||||
srcOffsetY = 0;
|
|
||||||
for(y=0; y<dstHeight; ++y) {
|
|
||||||
srcOffsetX = 0;
|
|
||||||
for(x=0; x<dstWidth; ++x) {
|
|
||||||
#if defined(kUseBilinearInterpolation)
|
|
||||||
dstImage[x] = interpolate(srcImage, x+srcX, y+srcY, srcOffsetX, srcOffsetY, srcWidth, srcHeight, srcPitch);
|
|
||||||
#else
|
|
||||||
dstImage[x] = srcImage[srcOffsetX >> 16];
|
|
||||||
#endif
|
|
||||||
srcOffsetX += deltaX;
|
|
||||||
}
|
|
||||||
|
|
||||||
srcOffsetY += deltaY;
|
|
||||||
if(srcOffsetY >= 0x10000) {
|
|
||||||
srcImage += (srcOffsetY >> 16) * srcPitch;
|
|
||||||
srcOffsetY &= 0xffff;
|
|
||||||
}
|
|
||||||
dstImage += dstPitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
calc_dst_factor(SWindowData *window_data, uint32_t width, uint32_t height) {
|
|
||||||
if (window_data->dst_width == 0) {
|
|
||||||
window_data->dst_width = width;
|
|
||||||
}
|
|
||||||
window_data->factor_x = (float) window_data->dst_offset_x / (float) width;
|
|
||||||
window_data->factor_width = (float) window_data->dst_width / (float) width;
|
|
||||||
|
|
||||||
if (window_data->dst_height == 0) {
|
|
||||||
window_data->dst_height = height;
|
|
||||||
}
|
|
||||||
window_data->factor_y = (float) window_data->dst_offset_y / (float) height;
|
|
||||||
window_data->factor_height = (float) window_data->dst_height / (float) height;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
resize_dst(SWindowData *window_data, uint32_t width, uint32_t height) {
|
|
||||||
window_data->dst_offset_x = (uint32_t) (width * window_data->factor_x);
|
|
||||||
window_data->dst_offset_y = (uint32_t) (height * window_data->factor_y);
|
|
||||||
window_data->dst_width = (uint32_t) (width * window_data->factor_width);
|
|
||||||
window_data->dst_height = (uint32_t) (height * window_data->factor_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(USE_OPENGL_API) && !defined(USE_METAL_API)
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
set_target_fps_aux() {
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <MiniFB.h>
|
|
||||||
#include "WindowData.h"
|
|
||||||
|
|
||||||
#define kCall(func, ...) if(window_data && window_data->func) window_data->func((struct mfb_window *) window_data, __VA_ARGS__);
|
|
||||||
#define kUnused(var) (void) var;
|
|
||||||
|
|
||||||
typedef struct mfb_timer {
|
|
||||||
int64_t start_time;
|
|
||||||
int64_t delta_counter;
|
|
||||||
uint64_t time;
|
|
||||||
} mfb_timer;
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
extern short int g_keycodes[512];
|
|
||||||
void keyboard_default(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed);
|
|
||||||
|
|
||||||
void calc_dst_factor(SWindowData *window_data, uint32_t width, uint32_t height);
|
|
||||||
void resize_dst(SWindowData *window_data, uint32_t width, uint32_t height);
|
|
||||||
void set_target_fps_aux();
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,37 +0,0 @@
|
|||||||
#if defined(__linux__)
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <MiniFB.h>
|
|
||||||
|
|
||||||
extern double g_timer_frequency;
|
|
||||||
extern double g_timer_resolution;
|
|
||||||
|
|
||||||
#define kClock CLOCK_MONOTONIC
|
|
||||||
//#define kClock CLOCK_REALTIME
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
mfb_timer_tick() {
|
|
||||||
struct timespec time;
|
|
||||||
|
|
||||||
if (clock_gettime(kClock, &time) != 0) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return time.tv_sec * 1e+9 + time.tv_nsec;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
mfb_timer_init() {
|
|
||||||
struct timespec res;
|
|
||||||
|
|
||||||
if (clock_getres(kClock, &res) != 0) {
|
|
||||||
g_timer_frequency = 1e+9;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g_timer_frequency = res.tv_sec + res.tv_nsec * 1e+9;
|
|
||||||
}
|
|
||||||
g_timer_resolution = 1.0 / g_timer_frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,115 +0,0 @@
|
|||||||
#include <MiniFB.h>
|
|
||||||
#include "MiniFB_internal.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
double g_timer_frequency;
|
|
||||||
double g_timer_resolution;
|
|
||||||
double g_time_for_frame = 1.0 / 60.0;
|
|
||||||
bool g_use_hardware_sync = false;
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
extern uint64_t mfb_timer_tick(void);
|
|
||||||
extern void mfb_timer_init(void);
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_set_target_fps(uint32_t fps) {
|
|
||||||
if(fps == 0) {
|
|
||||||
g_time_for_frame = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g_time_for_frame = 1.0 / fps;
|
|
||||||
}
|
|
||||||
set_target_fps_aux();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
unsigned
|
|
||||||
mfb_get_target_fps() {
|
|
||||||
if (g_time_for_frame == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 1.0 / g_time_for_frame;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
struct mfb_timer *
|
|
||||||
mfb_timer_create() {
|
|
||||||
static int once = 1;
|
|
||||||
mfb_timer *tmr;
|
|
||||||
|
|
||||||
if(once) {
|
|
||||||
once = 0;
|
|
||||||
mfb_timer_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
tmr = malloc(sizeof(mfb_timer));
|
|
||||||
mfb_timer_reset(tmr);
|
|
||||||
|
|
||||||
return tmr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_timer_destroy(struct mfb_timer *tmr) {
|
|
||||||
if(tmr != 0x0) {
|
|
||||||
free(tmr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_timer_reset(struct mfb_timer *tmr) {
|
|
||||||
if(tmr == 0x0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
tmr->start_time = mfb_timer_tick();
|
|
||||||
tmr->delta_counter = tmr->start_time;
|
|
||||||
tmr->time = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
double
|
|
||||||
mfb_timer_now(struct mfb_timer *tmr) {
|
|
||||||
uint64_t counter;
|
|
||||||
|
|
||||||
if(tmr == 0x0)
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
counter = mfb_timer_tick();
|
|
||||||
tmr->time += (counter - tmr->start_time);
|
|
||||||
tmr->start_time = counter;
|
|
||||||
|
|
||||||
return tmr->time * g_timer_resolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
double
|
|
||||||
mfb_timer_delta(struct mfb_timer *tmr) {
|
|
||||||
int64_t counter;
|
|
||||||
uint64_t delta;
|
|
||||||
|
|
||||||
if(tmr == 0x0)
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
counter = mfb_timer_tick();
|
|
||||||
delta = (counter - tmr->delta_counter);
|
|
||||||
tmr->delta_counter = counter;
|
|
||||||
|
|
||||||
return delta * g_timer_resolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
double
|
|
||||||
mfb_timer_get_frequency() {
|
|
||||||
return g_timer_frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
double
|
|
||||||
mfb_timer_get_resolution() {
|
|
||||||
return g_timer_resolution;
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <MiniFB_enums.h>
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
typedef struct {
|
|
||||||
void *specific;
|
|
||||||
void *user_data;
|
|
||||||
|
|
||||||
mfb_active_func active_func;
|
|
||||||
mfb_resize_func resize_func;
|
|
||||||
mfb_keyboard_func keyboard_func;
|
|
||||||
mfb_char_input_func char_input_func;
|
|
||||||
mfb_mouse_button_func mouse_btn_func;
|
|
||||||
mfb_mouse_move_func mouse_move_func;
|
|
||||||
mfb_mouse_scroll_func mouse_wheel_func;
|
|
||||||
|
|
||||||
uint32_t window_width;
|
|
||||||
uint32_t window_height;
|
|
||||||
|
|
||||||
uint32_t dst_offset_x;
|
|
||||||
uint32_t dst_offset_y;
|
|
||||||
uint32_t dst_width;
|
|
||||||
uint32_t dst_height;
|
|
||||||
float factor_x;
|
|
||||||
float factor_y;
|
|
||||||
float factor_width;
|
|
||||||
float factor_height;
|
|
||||||
|
|
||||||
void *draw_buffer;
|
|
||||||
uint32_t buffer_width;
|
|
||||||
uint32_t buffer_height;
|
|
||||||
uint32_t buffer_stride;
|
|
||||||
|
|
||||||
int32_t mouse_pos_x;
|
|
||||||
int32_t mouse_pos_y;
|
|
||||||
float mouse_wheel_x;
|
|
||||||
float mouse_wheel_y;
|
|
||||||
uint8_t mouse_button_status[8];
|
|
||||||
uint8_t key_status[512];
|
|
||||||
uint32_t mod_keys;
|
|
||||||
|
|
||||||
bool is_active;
|
|
||||||
bool is_initialized;
|
|
||||||
|
|
||||||
bool close;
|
|
||||||
} SWindowData;
|
|
@ -1,473 +0,0 @@
|
|||||||
#include <android_native_app_glue.h>
|
|
||||||
#include <android/log.h>
|
|
||||||
#include <jni.h>
|
|
||||||
//--
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
//--
|
|
||||||
#include <MiniFB.h>
|
|
||||||
#include <WindowData.h>
|
|
||||||
#include "WindowData_Android.h"
|
|
||||||
|
|
||||||
#define LOG_TAG "MiniFB"
|
|
||||||
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
|
||||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
|
||||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
|
||||||
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
|
||||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
|
||||||
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__)
|
|
||||||
|
|
||||||
#define kCall(func, ...) if(window_data && window_data->func) window_data->func((struct mfb_window *) window_data, __VA_ARGS__);
|
|
||||||
|
|
||||||
#define kUnused(var) (void) var;
|
|
||||||
|
|
||||||
struct android_app *gApplication;
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
extern void
|
|
||||||
stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch,
|
|
||||||
uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch);
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
extern int
|
|
||||||
main(int argc, char *argv[]);
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
static void
|
|
||||||
draw(SWindowData *window_data, ANativeWindow_Buffer *window_buffer) {
|
|
||||||
if(window_data == 0x0 || window_data->draw_buffer == 0x0 || window_buffer == 0x0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if((window_data->buffer_width == window_buffer->width) && (window_data->buffer_height == window_buffer->height)) {
|
|
||||||
if(window_data->buffer_stride == window_buffer->stride*4) {
|
|
||||||
memcpy(window_buffer->bits, window_data->draw_buffer, window_data->buffer_width * window_data->buffer_height * 4);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
uint8_t *src = window_data->draw_buffer;
|
|
||||||
uint32_t *dst = window_buffer->bits;
|
|
||||||
for(uint32_t y=0; y<window_data->window_height; ++y) {
|
|
||||||
memcpy(dst, src, window_data->buffer_width * 4);
|
|
||||||
src += window_data->buffer_stride;
|
|
||||||
dst += window_buffer->stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
uint32_t *src = window_data->draw_buffer;
|
|
||||||
uint32_t *dst = window_buffer->bits;
|
|
||||||
stretch_image(
|
|
||||||
src, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->buffer_width,
|
|
||||||
dst, 0, 0, window_buffer->width, window_buffer->height, window_buffer->stride
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
static int32_t
|
|
||||||
handle_input(struct android_app* app, AInputEvent* event) {
|
|
||||||
SWindowData *window_data = (SWindowData *) app->userData;
|
|
||||||
if (window_data->close) {
|
|
||||||
//destroy_window_data(window_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData_Android *window_data_android = (SWindowData_Android *) window_data->specific;
|
|
||||||
|
|
||||||
int t = AInputEvent_getType(event);
|
|
||||||
int s = AInputEvent_getSource(event);
|
|
||||||
LOGV("Event: type= %d, source=%d", t, s);
|
|
||||||
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
|
|
||||||
//if (AInputEvent_getSource(event) == AINPUT_SOURCE_TOUCHSCREEN) {
|
|
||||||
int action = AMotionEvent_getAction(event);
|
|
||||||
int type = action & AMOTION_EVENT_ACTION_MASK;
|
|
||||||
switch(type) {
|
|
||||||
case AMOTION_EVENT_ACTION_POINTER_DOWN:
|
|
||||||
case AMOTION_EVENT_ACTION_POINTER_UP:
|
|
||||||
{
|
|
||||||
int idx = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
|
||||||
int id = AMotionEvent_getPointerId(event, idx);
|
|
||||||
int x = AMotionEvent_getX(event, idx);
|
|
||||||
int y = AMotionEvent_getY(event, idx);
|
|
||||||
window_data->mouse_pos_x = x | (id << 28);
|
|
||||||
window_data->mouse_pos_y = y | (id << 28);
|
|
||||||
window_data->mouse_button_status[id & 0x07] = (action == AMOTION_EVENT_ACTION_POINTER_DOWN);
|
|
||||||
kCall(mouse_btn_func, id, 0, action == AMOTION_EVENT_ACTION_POINTER_DOWN);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AMOTION_EVENT_ACTION_DOWN:
|
|
||||||
case AMOTION_EVENT_ACTION_UP:
|
|
||||||
{
|
|
||||||
int count = AMotionEvent_getPointerCount(event);
|
|
||||||
for(int i=0; i < count; ++i) {
|
|
||||||
int id = AMotionEvent_getPointerId(event, i);
|
|
||||||
int x = AMotionEvent_getX(event, i);
|
|
||||||
int y = AMotionEvent_getY(event, i);
|
|
||||||
window_data->mouse_pos_x = x | (id << 28);
|
|
||||||
window_data->mouse_pos_y = y | (id << 28);
|
|
||||||
window_data->mouse_button_status[id & 0x07] = (action == AMOTION_EVENT_ACTION_POINTER_DOWN);
|
|
||||||
kCall(mouse_btn_func, id, 0, action == AMOTION_EVENT_ACTION_DOWN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AMOTION_EVENT_ACTION_MOVE:
|
|
||||||
{
|
|
||||||
int count = AMotionEvent_getPointerCount(event);
|
|
||||||
for(int i=0; i < count; ++i){
|
|
||||||
int id = AMotionEvent_getPointerId(event, i);
|
|
||||||
int x = AMotionEvent_getX(event, i);
|
|
||||||
int y = AMotionEvent_getY(event, i);
|
|
||||||
window_data->mouse_pos_x = x | (id << 28);
|
|
||||||
window_data->mouse_pos_y = y | (id << 28);
|
|
||||||
window_data->mouse_button_status[id & 0x07] = true;
|
|
||||||
kCall(mouse_move_func, window_data->mouse_pos_x, window_data->mouse_pos_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
LOGV("Touch: event: action=%x, source=%x, type=%d", action, s, t);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->is_active = true;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
|
|
||||||
LOGV("Key event: action=%d keyCode=%d metaState=0x%x",
|
|
||||||
AKeyEvent_getAction(event),
|
|
||||||
AKeyEvent_getKeyCode(event),
|
|
||||||
AKeyEvent_getMetaState(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
static void
|
|
||||||
handle_cmd(struct android_app* app, int32_t cmd) {
|
|
||||||
static int32_t format = WINDOW_FORMAT_RGBX_8888;
|
|
||||||
static int sCurrentState = -1;
|
|
||||||
|
|
||||||
sCurrentState = cmd;
|
|
||||||
|
|
||||||
SWindowData *window_data;
|
|
||||||
SWindowData_Android *window_data_android;
|
|
||||||
|
|
||||||
window_data = (SWindowData *) app->userData;
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data_android = (SWindowData_Android *) window_data->specific;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGV("cmd: %d", cmd);
|
|
||||||
// Init: 10, 11, 0, 1, 3, 5, 4, 6
|
|
||||||
// START, RESUME, INPUT_CHANGED, INIT_WINDOW, WINDOW_RESIZED, CONTENT_RECT_CHANGED, WINDOW_REDRAW_NEEDED, GAINED_FOCUS
|
|
||||||
// Pause: 13, 7, 2, 14, 12
|
|
||||||
// PAUSE, LOST_FOCUS, TERM_WINDOW, STOP, SAVE_STATE
|
|
||||||
// Resume: 10, 11, 1, 3, 4, 6
|
|
||||||
// START, RESUME, INIT_WINDOW, WINDOW_RESIZED, WINDOW_REDRAW_NEEDED, GAINED_FOCUS
|
|
||||||
// Close: 0, 15
|
|
||||||
// INPUT_CHANGED, DESTROY
|
|
||||||
// Lower the shutter: 7, 0
|
|
||||||
// LOST_FOCUS, INPUT_CHANGED
|
|
||||||
// Raising the shutter: 6, 1
|
|
||||||
// GAINED_FOCUS, INIT_WINDOW
|
|
||||||
// Rotate: 13, 2, 14, 12, 0, 15, 10, 11, 0, 1, 3, 5, 4, 6, 4
|
|
||||||
// PAUSE, TERM_WINDOW, STOP, SAVE_STATE, (similar to Pause but LOST_FOCUS)
|
|
||||||
// INPUT_CHANGED, DESTROY, (like Close)
|
|
||||||
// START, RESUME, INPUT_CHANGED, INIT_WINDOW, WINDOW_RESIZED, CONTENT_RECT_CHANGED, WINDOW_REDRAW_NEEDED, GAINED_FOCUS (like Init)
|
|
||||||
switch (cmd) {
|
|
||||||
// The app's activity has been started.
|
|
||||||
case APP_CMD_START:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The app's activity has been resumed.
|
|
||||||
case APP_CMD_RESUME:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The AInputQueue has changed.
|
|
||||||
// Upon processing this command, android_app->inputQueue will be updated to the new queue (or NULL).
|
|
||||||
case APP_CMD_INPUT_CHANGED:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// A new ANativeWindow is ready for use.
|
|
||||||
// Upon receiving this command, android_app->window will contain the new window surface.
|
|
||||||
case APP_CMD_INIT_WINDOW:
|
|
||||||
if (app->window != NULL) {
|
|
||||||
format = ANativeWindow_getFormat(app->window);
|
|
||||||
ANativeWindow_setBuffersGeometry(app->window,
|
|
||||||
ANativeWindow_getWidth(app->window),
|
|
||||||
ANativeWindow_getHeight(app->window),
|
|
||||||
format
|
|
||||||
);
|
|
||||||
//engine_draw_frame(window_data_android);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The current ANativeWindow has been resized. Please redraw with its new size.
|
|
||||||
case APP_CMD_WINDOW_RESIZED:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The content area of the window has changed, such as from the soft input window being shown or hidden.
|
|
||||||
// You can find the new content rect in android_app::contentRect.
|
|
||||||
case APP_CMD_CONTENT_RECT_CHANGED:
|
|
||||||
if(window_data_android != 0x0) {
|
|
||||||
// This does not work
|
|
||||||
//int32_t width = window_data_android->app->contentRect.right - window_data_android->app->contentRect.left;
|
|
||||||
//int32_t height = window_data_android->app->contentRect.bottom - window_data_android->app->contentRect.top;
|
|
||||||
// TODO: Check the DPI?
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->window_width = ANativeWindow_getWidth(app->window);
|
|
||||||
window_data->window_height = ANativeWindow_getHeight(app->window);
|
|
||||||
kCall(resize_func, window_data->window_width, window_data->window_height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The system needs that the current ANativeWindow be redrawn.
|
|
||||||
// You should redraw the window before handing this to android_app_exec_cmd() in order to avoid transient drawing glitches.
|
|
||||||
case APP_CMD_WINDOW_REDRAW_NEEDED:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The app's activity window has gained input focus.
|
|
||||||
case APP_CMD_GAINED_FOCUS:
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->is_active = true;
|
|
||||||
}
|
|
||||||
kCall(active_func, true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The app's activity has been paused.
|
|
||||||
case APP_CMD_PAUSE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The app's activity window has lost input focus.
|
|
||||||
case APP_CMD_LOST_FOCUS:
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->is_active = true;
|
|
||||||
//engine_draw_frame(window_data_android);
|
|
||||||
}
|
|
||||||
kCall(active_func, false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The existing ANativeWindow needs to be terminated.
|
|
||||||
// Upon receiving this command, android_app->window still contains the existing window;
|
|
||||||
// after calling android_app_exec_cmd it will be set to NULL.
|
|
||||||
case APP_CMD_TERM_WINDOW:
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->is_active = false;
|
|
||||||
}
|
|
||||||
ANativeWindow_setBuffersGeometry(app->window,
|
|
||||||
ANativeWindow_getWidth(app->window),
|
|
||||||
ANativeWindow_getHeight(app->window),
|
|
||||||
format
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The app's activity has been stopped.
|
|
||||||
case APP_CMD_STOP:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The app should generate a new saved state for itself, to restore from later if needed.
|
|
||||||
// If you have saved state, allocate it with malloc and place it in android_app.savedState with
|
|
||||||
// the size in android_app.savedStateSize.
|
|
||||||
// The will be freed for you later.
|
|
||||||
case APP_CMD_SAVE_STATE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The app's activity is being destroyed, and waiting for the app thread to clean up and exit before proceeding.
|
|
||||||
case APP_CMD_DESTROY:
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->close = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The system is running low on memory. Try to reduce your memory use.
|
|
||||||
case APP_CMD_LOW_MEMORY:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The current device configuration has changed.
|
|
||||||
case APP_CMD_CONFIG_CHANGED:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
android_main(struct android_app* app) {
|
|
||||||
app->onAppCmd = handle_cmd;
|
|
||||||
app->onInputEvent = handle_input;
|
|
||||||
gApplication = app;
|
|
||||||
|
|
||||||
// Read all pending events.
|
|
||||||
int ident;
|
|
||||||
int events;
|
|
||||||
struct android_poll_source* source;
|
|
||||||
while(app->window == 0x0) {
|
|
||||||
while ((ident = ALooper_pollAll(0, NULL, &events, (void **) &source)) >= 0) {
|
|
||||||
// Process this event.
|
|
||||||
if (source != NULL) {
|
|
||||||
source->process(app, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we are exiting.
|
|
||||||
if (app->destroyRequested != 0) {
|
|
||||||
LOGD("Engine thread destroy requested!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char cwd[1024];
|
|
||||||
getcwd(cwd, sizeof(cwd));
|
|
||||||
char *argv[] = {
|
|
||||||
cwd,
|
|
||||||
(char *) app
|
|
||||||
};
|
|
||||||
main(2, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
struct mfb_window *
|
|
||||||
mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) {
|
|
||||||
kUnused(title);
|
|
||||||
kUnused(flags);
|
|
||||||
|
|
||||||
SWindowData *window_data = malloc(sizeof(SWindowData));
|
|
||||||
if (window_data == 0x0) {
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
memset(window_data, 0, sizeof(SWindowData));
|
|
||||||
|
|
||||||
SWindowData_Android *window_data_android = malloc(sizeof(SWindowData_Android));
|
|
||||||
if(window_data_android == 0x0) {
|
|
||||||
free(window_data);
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
memset(window_data_android, 0, sizeof(SWindowData_Android));
|
|
||||||
window_data->specific = window_data_android;
|
|
||||||
|
|
||||||
window_data->is_active = true;
|
|
||||||
window_data_android->app = gApplication;
|
|
||||||
window_data_android->timer = mfb_timer_create();
|
|
||||||
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
|
|
||||||
gApplication->userData = window_data;
|
|
||||||
if(gApplication->window != 0x0) {
|
|
||||||
window_data->window_width = ANativeWindow_getWidth(gApplication->window);
|
|
||||||
window_data->window_height = ANativeWindow_getHeight(gApplication->window);
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data->is_initialized = true;
|
|
||||||
return (struct mfb_window *) window_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
mfb_update_state
|
|
||||||
mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned height) {
|
|
||||||
if (window == 0x0) {
|
|
||||||
return STATE_INVALID_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
if (window_data->close) {
|
|
||||||
//destroy_window_data(window_data);
|
|
||||||
return STATE_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer == 0x0) {
|
|
||||||
return STATE_INVALID_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data->draw_buffer = buffer;
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
|
|
||||||
SWindowData_Android *window_data_android = (SWindowData_Android *) window_data->specific;
|
|
||||||
|
|
||||||
ANativeWindow_Buffer native_buffer;
|
|
||||||
if (ANativeWindow_lock(window_data_android->app->window, &native_buffer, NULL) < 0) {
|
|
||||||
LOGE("Unable to lock window buffer");
|
|
||||||
return STATE_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw(window_data, &native_buffer);
|
|
||||||
|
|
||||||
ANativeWindow_unlockAndPost(window_data_android->app->window);
|
|
||||||
|
|
||||||
return STATE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
extern double g_time_for_frame;
|
|
||||||
|
|
||||||
bool
|
|
||||||
mfb_wait_sync(struct mfb_window *window) {
|
|
||||||
if (window == 0x0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
if (window_data->close) {
|
|
||||||
//destroy_window_data(window_data);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData_Android *window_data_android = (SWindowData_Android *) window_data->specific;
|
|
||||||
|
|
||||||
// Read all pending events.
|
|
||||||
int ident;
|
|
||||||
int events;
|
|
||||||
struct android_poll_source *source;
|
|
||||||
double current;
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
// If not animating, we will block forever waiting for events.
|
|
||||||
// If animating, we loop until all events are read, then continue
|
|
||||||
// to draw the next frame of animation.
|
|
||||||
while ((ident = ALooper_pollAll(window_data->is_active ? 0 : -1, NULL, &events, (void **) &source)) >= 0) {
|
|
||||||
// Process this event.
|
|
||||||
if (source != NULL) {
|
|
||||||
source->process(window_data_android->app, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we are exiting.
|
|
||||||
if (window_data_android->app->destroyRequested != 0) {
|
|
||||||
LOGD("Engine thread destroy requested!");
|
|
||||||
window_data->is_active = false;
|
|
||||||
window_data->close = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current = mfb_timer_now(window_data_android->timer);
|
|
||||||
if (current >= g_time_for_frame) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mfb_timer_reset(window_data_android->timer);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y) {
|
|
||||||
kUnused(window);
|
|
||||||
|
|
||||||
if(scale_x != 0x0) {
|
|
||||||
*scale_x = 1.0f;
|
|
||||||
}
|
|
||||||
if(scale_y != 0x0) {
|
|
||||||
*scale_y = 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <MiniFB_internal.h>
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
typedef struct {
|
|
||||||
struct android_app *app;
|
|
||||||
struct mfb_timer *timer;
|
|
||||||
} SWindowData_Android;
|
|
@ -1,368 +0,0 @@
|
|||||||
#if defined(USE_OPENGL_API)
|
|
||||||
|
|
||||||
#include "MiniFB_GL.h"
|
|
||||||
#include "MiniFB_internal.h"
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
|
||||||
#include <windows/WindowData_Win.h>
|
|
||||||
#include <gl/gl.h>
|
|
||||||
#elif defined(linux)
|
|
||||||
#include <x11/WindowData_X11.h>
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#include <GL/glx.h>
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
//#define kUse_Clean_UP
|
|
||||||
#if defined(kUse_Clean_UP)
|
|
||||||
#define UseCleanUp(x) x
|
|
||||||
#else
|
|
||||||
#define UseCleanUp(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern double g_time_for_frame;
|
|
||||||
extern bool g_use_hardware_sync;
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
|
||||||
bool
|
|
||||||
setup_pixel_format(HDC hDC) {
|
|
||||||
int pixelFormat;
|
|
||||||
|
|
||||||
PIXELFORMATDESCRIPTOR pfd = {
|
|
||||||
sizeof(PIXELFORMATDESCRIPTOR), // size
|
|
||||||
1, // version
|
|
||||||
PFD_SUPPORT_OPENGL | //
|
|
||||||
PFD_DRAW_TO_WINDOW | //
|
|
||||||
PFD_DOUBLEBUFFER, // support double-buffering
|
|
||||||
PFD_TYPE_RGBA, // color type
|
|
||||||
24, // preferred color depth
|
|
||||||
0, 0, 0, 0, 0, 0, // color and shift bits (ignored)
|
|
||||||
0, // no alpha buffer
|
|
||||||
0, // alpha bits (ignored)
|
|
||||||
0, // no accumulation buffer
|
|
||||||
0, 0, 0, 0, // accum bits (ignored)
|
|
||||||
24, // depth buffer
|
|
||||||
8, // no stencil buffer
|
|
||||||
0, // no auxiliary buffers
|
|
||||||
PFD_MAIN_PLANE, // main layer
|
|
||||||
0, // reserved
|
|
||||||
0, 0, 0, // no layer, visible, damage masks
|
|
||||||
};
|
|
||||||
|
|
||||||
pixelFormat = ChoosePixelFormat(hDC, &pfd);
|
|
||||||
if (pixelFormat == 0) {
|
|
||||||
MessageBox(WindowFromDC(hDC), "ChoosePixelFormat failed.", "Error", MB_ICONERROR | MB_OK);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE) {
|
|
||||||
MessageBox(WindowFromDC(hDC), "SetPixelFormat failed.", "Error", MB_ICONERROR | MB_OK);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
|
|
||||||
typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC)(void);
|
|
||||||
PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT = 0x0;
|
|
||||||
PFNWGLGETSWAPINTERVALEXTPROC GetSwapIntervalEXT = 0x0;
|
|
||||||
|
|
||||||
#elif defined(linux)
|
|
||||||
|
|
||||||
bool
|
|
||||||
setup_pixel_format(SWindowData_X11 *window_data_x11) {
|
|
||||||
GLint glxAttribs[] = {
|
|
||||||
GLX_RGBA,
|
|
||||||
GLX_DOUBLEBUFFER,
|
|
||||||
GLX_DEPTH_SIZE, 24,
|
|
||||||
GLX_STENCIL_SIZE, 8,
|
|
||||||
GLX_RED_SIZE, 8,
|
|
||||||
GLX_GREEN_SIZE, 8,
|
|
||||||
GLX_BLUE_SIZE, 8,
|
|
||||||
GLX_DEPTH_SIZE, 24,
|
|
||||||
GLX_STENCIL_SIZE, 8,
|
|
||||||
GLX_SAMPLE_BUFFERS, 0,
|
|
||||||
GLX_SAMPLES, 0,
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
XVisualInfo* visualInfo = glXChooseVisual(window_data_x11->display, window_data_x11->screen, glxAttribs);
|
|
||||||
if (visualInfo == 0) {
|
|
||||||
fprintf(stderr, "Could not create correct visual window.\n");
|
|
||||||
XCloseDisplay(window_data_x11->display);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
window_data_x11->context = glXCreateContext(window_data_x11->display, visualInfo, NULL, GL_TRUE);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int);
|
|
||||||
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT = 0x0;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
bool
|
|
||||||
create_GL_context(SWindowData *window_data) {
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
|
||||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
|
||||||
|
|
||||||
if (setup_pixel_format(window_data_win->hdc) == false)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
window_data_win->hGLRC = wglCreateContext(window_data_win->hdc);
|
|
||||||
wglMakeCurrent(window_data_win->hdc, window_data_win->hGLRC);
|
|
||||||
init_GL(window_data);
|
|
||||||
|
|
||||||
SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) wglGetProcAddress("wglSwapIntervalEXT");
|
|
||||||
GetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC) wglGetProcAddress("wglGetSwapIntervalEXT");
|
|
||||||
set_target_fps_aux();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
#elif defined(linux)
|
|
||||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
|
||||||
|
|
||||||
GLint majorGLX, minorGLX = 0;
|
|
||||||
glXQueryVersion(window_data_x11->display, &majorGLX, &minorGLX);
|
|
||||||
if (majorGLX <= 1 && minorGLX < 2) {
|
|
||||||
fprintf(stderr, "GLX 1.2 or greater is required.\n");
|
|
||||||
XCloseDisplay(window_data_x11->display);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//fprintf(stdout, "GLX version: %d.%d\n", majorGLX, minorGLX);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setup_pixel_format(window_data_x11) == false)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
glXMakeCurrent(window_data_x11->display, window_data_x11->window, window_data_x11->context);
|
|
||||||
|
|
||||||
//fprintf(stdout, "GL Vendor: %s\n", glGetString(GL_VENDOR));
|
|
||||||
//fprintf(stdout, "GL Renderer: %s\n", glGetString(GL_RENDERER));
|
|
||||||
//fprintf(stdout, "GL Version: %s\n", glGetString(GL_VERSION));
|
|
||||||
//fprintf(stdout, "GL Shading Language: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
|
|
||||||
|
|
||||||
init_GL(window_data);
|
|
||||||
|
|
||||||
SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress("glXSwapIntervalEXT");
|
|
||||||
set_target_fps_aux();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
destroy_GL_context(SWindowData *window_data) {
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
|
||||||
|
|
||||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
|
||||||
if (window_data_win->hGLRC) {
|
|
||||||
wglMakeCurrent(NULL, NULL);
|
|
||||||
wglDeleteContext(window_data_win->hGLRC);
|
|
||||||
window_data_win->hGLRC = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(linux)
|
|
||||||
|
|
||||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
|
||||||
glXDestroyContext(window_data_x11->display, window_data_x11->context);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
#if defined(RGB)
|
|
||||||
#undef RGB
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TEXTURE0 0x84C0 // [ Core in gl 1.3, gles1 1.0, gles2 2.0, glsc2 2.0, Provided by GL_ARB_multitexture (gl) ]
|
|
||||||
#define RGB 0x1907 // [ Core in gl 1.0, gles1 1.0, gles2 2.0, glsc2 2.0 ]
|
|
||||||
#define RGBA 0x1908 // [ Core in gl 1.0, gles1 1.0, gles2 2.0, glsc2 2.0 ]
|
|
||||||
#define BGR 0x80E0 // [ Core in gl 1.2 ]
|
|
||||||
#define BGRA 0x80E1 // [ Core in gl 1.2, Provided by GL_ARB_vertex_array_bgra (gl|glcore) ]
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
init_GL(SWindowData *window_data) {
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
|
||||||
|
|
||||||
SWindowData_Win *window_data_ex = (SWindowData_Win *) window_data->specific;
|
|
||||||
|
|
||||||
#elif defined(linux)
|
|
||||||
|
|
||||||
SWindowData_X11 *window_data_ex = (SWindowData_X11 *) window_data->specific;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
glViewport(0, 0, window_data->window_width, window_data->window_height);
|
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glLoadIdentity();
|
|
||||||
glOrtho(0, window_data->window_width, window_data->window_height, 0, 2048, -2048);
|
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDisable(GL_STENCIL_TEST);
|
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
|
|
||||||
glGenTextures(1, &window_data_ex->text_id);
|
|
||||||
//glActiveTexture(TEXTURE0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, window_data_ex->text_id);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
|
|
||||||
UseCleanUp(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
|
|
||||||
UseCleanUp(glDisableClientState(GL_VERTEX_ARRAY));
|
|
||||||
UseCleanUp(glBindTexture(GL_TEXTURE_2D, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
resize_GL(SWindowData *window_data) {
|
|
||||||
if (window_data->is_initialized) {
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
|
||||||
|
|
||||||
SWindowData_Win *window_data_ex = (SWindowData_Win *) window_data->specific;
|
|
||||||
wglMakeCurrent(window_data_ex->hdc, window_data_ex->hGLRC);
|
|
||||||
|
|
||||||
#elif defined(linux)
|
|
||||||
|
|
||||||
SWindowData_X11 *window_data_ex = (SWindowData_X11 *) window_data->specific;
|
|
||||||
glXMakeCurrent(window_data_ex->display, window_data_ex->window, window_data_ex->context);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
glViewport(0, 0, window_data->window_width, window_data->window_height);
|
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glLoadIdentity();
|
|
||||||
glOrtho(0, window_data->window_width, window_data->window_height, 0, 2048, -2048);
|
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
redraw_GL(SWindowData *window_data, const void *pixels) {
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
|
||||||
|
|
||||||
SWindowData_Win *window_data_ex = (SWindowData_Win *) window_data->specific;
|
|
||||||
GLenum format = BGRA;
|
|
||||||
|
|
||||||
wglMakeCurrent(window_data_ex->hdc, window_data_ex->hGLRC);
|
|
||||||
|
|
||||||
#elif defined(linux)
|
|
||||||
|
|
||||||
SWindowData_X11 *window_data_ex = (SWindowData_X11 *) window_data->specific;
|
|
||||||
GLenum format = BGRA;
|
|
||||||
|
|
||||||
glXMakeCurrent(window_data_ex->display, window_data_ex->window, window_data_ex->context);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
float x, y, w, h;
|
|
||||||
|
|
||||||
x = (float) window_data->dst_offset_x;
|
|
||||||
y = (float) window_data->dst_offset_y;
|
|
||||||
w = (float) window_data->dst_offset_x + window_data->dst_width;
|
|
||||||
h = (float) window_data->dst_offset_y + window_data->dst_height;
|
|
||||||
|
|
||||||
float vertices[] = {
|
|
||||||
x, y,
|
|
||||||
0, 0,
|
|
||||||
|
|
||||||
w, y,
|
|
||||||
1, 0,
|
|
||||||
|
|
||||||
x, h,
|
|
||||||
0, 1,
|
|
||||||
|
|
||||||
w, h,
|
|
||||||
1, 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
UseCleanUp(glBindTexture(GL_TEXTURE_2D, window_data_ex->text_id));
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_data->buffer_width, window_data->buffer_height, 0, format, GL_UNSIGNED_BYTE, pixels);
|
|
||||||
//glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, window_data->buffer_width, window_data->buffer_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
|
||||||
|
|
||||||
UseCleanUp(glEnableClientState(GL_VERTEX_ARRAY));
|
|
||||||
UseCleanUp(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
|
||||||
glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), vertices);
|
|
||||||
glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), vertices + 2);
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
||||||
|
|
||||||
UseCleanUp(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
|
|
||||||
UseCleanUp(glDisableClientState(GL_VERTEX_ARRAY));
|
|
||||||
UseCleanUp(glBindTexture(GL_TEXTURE_2D, 0));
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
|
||||||
SwapBuffers(window_data_ex->hdc);
|
|
||||||
#elif defined(linux)
|
|
||||||
glXSwapBuffers(window_data_ex->display, window_data_ex->window);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
set_target_fps_aux() {
|
|
||||||
// Assuming the monitor refresh rate is 60 hz
|
|
||||||
int interval = (int) ((60.0 * g_time_for_frame) + 0.5);
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(WIN32)
|
|
||||||
|
|
||||||
if (SwapIntervalEXT != 0x0) {
|
|
||||||
bool success = SwapIntervalEXT(interval);
|
|
||||||
if (GetSwapIntervalEXT != 0x0) {
|
|
||||||
int currentInterval = GetSwapIntervalEXT();
|
|
||||||
if (interval != currentInterval) {
|
|
||||||
fprintf(stderr, "Cannot set target swap interval. Current swap interval is %d\n", currentInterval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (success == false) {
|
|
||||||
fprintf(stderr, "Cannot set target swap interval.\n");
|
|
||||||
}
|
|
||||||
g_use_hardware_sync = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(linux)
|
|
||||||
#define kGLX_SWAP_INTERVAL_EXT 0x20F1
|
|
||||||
#define kGLX_MAX_SWAP_INTERVAL_EXT 0x20F2
|
|
||||||
|
|
||||||
if (SwapIntervalEXT != 0x0) {
|
|
||||||
Display *dpy = glXGetCurrentDisplay();
|
|
||||||
GLXDrawable drawable = glXGetCurrentDrawable();
|
|
||||||
unsigned int currentInterval, maxInterval;
|
|
||||||
|
|
||||||
SwapIntervalEXT(dpy, drawable, interval);
|
|
||||||
glXQueryDrawable(dpy, drawable, kGLX_SWAP_INTERVAL_EXT, ¤tInterval);
|
|
||||||
if (interval != currentInterval) {
|
|
||||||
glXQueryDrawable(dpy, drawable, kGLX_MAX_SWAP_INTERVAL_EXT, &maxInterval);
|
|
||||||
fprintf(stderr, "Cannot set target swap interval. Current swap interval is %d (max: %d)\n", currentInterval, maxInterval);
|
|
||||||
}
|
|
||||||
g_use_hardware_sync = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#if defined(USE_OPENGL_API)
|
|
||||||
|
|
||||||
#include <WindowData.h>
|
|
||||||
|
|
||||||
bool create_GL_context(SWindowData *window_data);
|
|
||||||
void destroy_GL_context(SWindowData *window_data);
|
|
||||||
void init_GL(SWindowData *window_data);
|
|
||||||
void redraw_GL(SWindowData *window_data, const void *pixels);
|
|
||||||
void resize_GL(SWindowData *window_data);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <MiniFB_enums.h>
|
|
||||||
#include <WindowData.h>
|
|
||||||
#include <MetalKit/MetalKit.h>
|
|
||||||
|
|
||||||
@class iOSViewDelegate;
|
|
||||||
|
|
||||||
typedef struct Vertex {
|
|
||||||
float x, y, z, w;
|
|
||||||
} Vertex;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
iOSViewDelegate *view_delegate;
|
|
||||||
Vertex vertices[4];
|
|
||||||
} SWindowData_IOS;
|
|
@ -1,272 +0,0 @@
|
|||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
#include <mach/mach_time.h>
|
|
||||||
|
|
||||||
#include "iOSViewController.h"
|
|
||||||
#include "iOSViewDelegate.h"
|
|
||||||
#include "WindowData_IOS.h"
|
|
||||||
#include <MiniFB.h>
|
|
||||||
#include <MiniFB_internal.h>
|
|
||||||
#include <WindowData.h>
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
SWindowData *
|
|
||||||
create_window_data(unsigned width, unsigned height) {
|
|
||||||
SWindowData *window_data;
|
|
||||||
|
|
||||||
window_data = malloc(sizeof(SWindowData));
|
|
||||||
if(window_data == 0x0) {
|
|
||||||
NSLog(@"Cannot allocate window data");
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
memset(window_data, 0, sizeof(SWindowData));
|
|
||||||
|
|
||||||
SWindowData_IOS *window_data_ios = malloc(sizeof(SWindowData_IOS));
|
|
||||||
if(window_data_ios == 0x0) {
|
|
||||||
free(window_data);
|
|
||||||
NSLog(@"Cannot allocate ios window data");
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
memset((void *) window_data_ios, 0, sizeof(SWindowData_IOS));
|
|
||||||
|
|
||||||
window_data->specific = window_data_ios;
|
|
||||||
|
|
||||||
float scale = [UIScreen mainScreen].scale;
|
|
||||||
|
|
||||||
window_data->window_width = [UIScreen mainScreen].bounds.size.width * scale;
|
|
||||||
window_data->window_height = [UIScreen mainScreen].bounds.size.height * scale;
|
|
||||||
|
|
||||||
calc_dst_factor(window_data, width, height);
|
|
||||||
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
|
|
||||||
window_data->draw_buffer = malloc(width * height * 4);
|
|
||||||
if (!window_data->draw_buffer) {
|
|
||||||
free(window_data_ios);
|
|
||||||
free(window_data);
|
|
||||||
NSLog(@"Unable to create draw buffer");
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return window_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
struct mfb_window *
|
|
||||||
mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) {
|
|
||||||
UIWindow *window;
|
|
||||||
NSArray *windows;
|
|
||||||
size_t numWindows;
|
|
||||||
|
|
||||||
kUnused(title);
|
|
||||||
kUnused(flags);
|
|
||||||
|
|
||||||
@autoreleasepool {
|
|
||||||
SWindowData *window_data = create_window_data(width, height);
|
|
||||||
if (window_data == 0x0) {
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
windows = [[UIApplication sharedApplication] windows];
|
|
||||||
numWindows = [windows count];
|
|
||||||
if(numWindows > 0) {
|
|
||||||
window = [windows objectAtIndex:0];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Notice that you need to set "Launch Screen File" in:
|
|
||||||
// project > executable > general
|
|
||||||
// to get the real size with [UIScreen mainScreen].bounds].
|
|
||||||
window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
|
||||||
NSLog(@"UIApplication has no window. We create one (%f, %f).", [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
if([window.rootViewController isKindOfClass:[iOSViewController class]] == false) {
|
|
||||||
iOSViewController *controller = [[iOSViewController alloc] initWithWindowData:window_data];
|
|
||||||
[window setRootViewController:controller];
|
|
||||||
#if !__has_feature(objc_arc)
|
|
||||||
[controller release];
|
|
||||||
#endif
|
|
||||||
controller = (iOSViewController *) window.rootViewController;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
((iOSViewController *) window.rootViewController)->window_data = window_data;
|
|
||||||
}
|
|
||||||
[window makeKeyAndVisible];
|
|
||||||
|
|
||||||
window_data->is_initialized = true;
|
|
||||||
return (struct mfb_window *) window_data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
static void
|
|
||||||
destroy_window_data(SWindowData *window_data) {
|
|
||||||
if(window_data == 0x0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
@autoreleasepool {
|
|
||||||
SWindowData_IOS *window_data_ios = (SWindowData_IOS *) window_data->specific;
|
|
||||||
if(window_data_ios != 0x0) {
|
|
||||||
memset((void *) window_data_ios, 0, sizeof(SWindowData_IOS));
|
|
||||||
free(window_data_ios);
|
|
||||||
}
|
|
||||||
memset(window_data, 0, sizeof(SWindowData));
|
|
||||||
free(window_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
mfb_update_state
|
|
||||||
mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned height) {
|
|
||||||
if(window == 0x0) {
|
|
||||||
return STATE_INVALID_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
if(window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return STATE_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buffer == 0x0) {
|
|
||||||
return STATE_INVALID_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData_IOS *window_data_ios = (SWindowData_IOS *) window_data->specific;
|
|
||||||
|
|
||||||
if(window_data->buffer_width != width || window_data->buffer_height != height) {
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
window_data->draw_buffer = realloc(window_data->draw_buffer, window_data->buffer_stride * window_data->buffer_height);
|
|
||||||
|
|
||||||
[window_data_ios->view_delegate resizeTextures];
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(window_data->draw_buffer, buffer, window_data->buffer_width * window_data->buffer_height * 4);
|
|
||||||
|
|
||||||
return STATE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
mfb_update_state
|
|
||||||
mfb_update_events(struct mfb_window *window) {
|
|
||||||
if(window == 0x0) {
|
|
||||||
return STATE_INVALID_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
extern double g_time_for_frame;
|
|
||||||
|
|
||||||
bool
|
|
||||||
mfb_wait_sync(struct mfb_window *window) {
|
|
||||||
if(window == 0x0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
bool
|
|
||||||
mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) {
|
|
||||||
if(window == 0x0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
|
|
||||||
if(offset_x + width > window_data->window_width) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(offset_y + height > window_data->window_height) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data->dst_offset_x = offset_x;
|
|
||||||
window_data->dst_offset_y = offset_y;
|
|
||||||
window_data->dst_width = width;
|
|
||||||
window_data->dst_height = height;
|
|
||||||
calc_dst_factor(window_data, window_data->window_width, window_data->window_height);
|
|
||||||
|
|
||||||
float x1 = ((float) offset_x / window_data->window_width) * 2.0f - 1.0f;
|
|
||||||
float x2 = (((float) offset_x + width) / window_data->window_width) * 2.0f - 1.0f;
|
|
||||||
float y1 = ((float) offset_y / window_data->window_height) * 2.0f - 1.0f;
|
|
||||||
float y2 = (((float) offset_y + height) / window_data->window_height) * 2.0f - 1.0f;
|
|
||||||
|
|
||||||
SWindowData_IOS *window_data_ios = (SWindowData_IOS *) window_data->specific;
|
|
||||||
|
|
||||||
window_data_ios->vertices[0].x = x1;
|
|
||||||
window_data_ios->vertices[0].y = y1;
|
|
||||||
|
|
||||||
window_data_ios->vertices[1].x = x1;
|
|
||||||
window_data_ios->vertices[1].y = y2;
|
|
||||||
|
|
||||||
window_data_ios->vertices[2].x = x2;
|
|
||||||
window_data_ios->vertices[2].y = y1;
|
|
||||||
|
|
||||||
window_data_ios->vertices[3].x = x2;
|
|
||||||
window_data_ios->vertices[3].y = y2;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
extern double g_timer_frequency;
|
|
||||||
extern double g_timer_resolution;
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
mfb_timer_tick() {
|
|
||||||
static mach_timebase_info_data_t timebase = { 0 };
|
|
||||||
|
|
||||||
if (timebase.denom == 0) {
|
|
||||||
(void) mach_timebase_info(&timebase);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t time = mach_absolute_time();
|
|
||||||
|
|
||||||
//return (time * s_timebase_info.numer) / s_timebase_info.denom;
|
|
||||||
|
|
||||||
// Perform the arithmetic at 128-bit precision to avoid the overflow!
|
|
||||||
uint64_t high = (time >> 32) * timebase.numer;
|
|
||||||
uint64_t highRem = ((high % timebase.denom) << 32) / timebase.denom;
|
|
||||||
uint64_t low = (time & 0xFFFFFFFFull) * timebase.numer / timebase.denom;
|
|
||||||
high /= timebase.denom;
|
|
||||||
|
|
||||||
return (high << 32) + highRem + low;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_timer_init() {
|
|
||||||
g_timer_frequency = 1e+9;
|
|
||||||
g_timer_resolution = 1.0 / g_timer_frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y) {
|
|
||||||
(void) window;
|
|
||||||
float scale = 1.0f;
|
|
||||||
|
|
||||||
scale = [[UIScreen mainScreen] scale];
|
|
||||||
|
|
||||||
if (scale_x) {
|
|
||||||
*scale_x = scale;
|
|
||||||
if(*scale_x == 0) {
|
|
||||||
*scale_x = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale_y) {
|
|
||||||
*scale_y = scale;
|
|
||||||
if (*scale_y == 0) {
|
|
||||||
*scale_y = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
#import <MetalKit/MetalKit.h>
|
|
||||||
#include "WindowData.h"
|
|
||||||
|
|
||||||
@interface iOSView : MTKView
|
|
||||||
{
|
|
||||||
@public SWindowData *window_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
@ -1,84 +0,0 @@
|
|||||||
#include "iOSView.h"
|
|
||||||
#include <MiniFB_internal.h>
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
@implementation iOSView
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (BOOL) canBecomeFirstResponder {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
|
||||||
kUnused(event);
|
|
||||||
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
CGPoint point;
|
|
||||||
int buttonNumber = MOUSE_BTN_0;
|
|
||||||
for(UITouch *touch in touches) {
|
|
||||||
point = [touch locationInView:self];
|
|
||||||
window_data->mouse_pos_x = point.x;
|
|
||||||
window_data->mouse_pos_y = point.y;
|
|
||||||
window_data->mouse_button_status[buttonNumber & 0x07] = true;
|
|
||||||
kCall(mouse_btn_func, buttonNumber, 0, true);
|
|
||||||
++buttonNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
|
||||||
kUnused(event);
|
|
||||||
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
CGPoint point;
|
|
||||||
int buttonNumber = MOUSE_BTN_0;
|
|
||||||
for(UITouch *touch in touches) {
|
|
||||||
point = [touch locationInView:self];
|
|
||||||
window_data->mouse_pos_x = point.x;
|
|
||||||
window_data->mouse_pos_y = point.y;
|
|
||||||
window_data->mouse_button_status[buttonNumber & 0x07] = true;
|
|
||||||
kCall(mouse_move_func, point.x, point.y);
|
|
||||||
++buttonNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
|
||||||
kUnused(event);
|
|
||||||
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
CGPoint point;
|
|
||||||
int buttonNumber = MOUSE_BTN_0;
|
|
||||||
for(UITouch *touch in touches) {
|
|
||||||
point = [touch locationInView:self];
|
|
||||||
window_data->mouse_pos_x = point.x;
|
|
||||||
window_data->mouse_pos_y = point.y;
|
|
||||||
window_data->mouse_button_status[buttonNumber & 0x07] = false;
|
|
||||||
kCall(mouse_btn_func, buttonNumber, 0, false);
|
|
||||||
++buttonNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
|
||||||
kUnused(event);
|
|
||||||
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
CGPoint point;
|
|
||||||
int buttonNumber = MOUSE_BTN_0;
|
|
||||||
for(UITouch *touch in touches) {
|
|
||||||
point = [touch locationInView:self];
|
|
||||||
window_data->mouse_pos_x = point.x;
|
|
||||||
window_data->mouse_pos_y = point.y;
|
|
||||||
window_data->mouse_button_status[buttonNumber & 0x07] = false;
|
|
||||||
kCall(mouse_btn_func, buttonNumber, 0, false);
|
|
||||||
++buttonNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
@ -1,19 +0,0 @@
|
|||||||
//
|
|
||||||
// iOSViewController.h
|
|
||||||
// MiniFB
|
|
||||||
//
|
|
||||||
// Created by Carlos Aragones on 22/04/2020.
|
|
||||||
// Copyright © 2020 Carlos Aragones. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
#include "WindowData.h"
|
|
||||||
|
|
||||||
@interface iOSViewController : UIViewController
|
|
||||||
{
|
|
||||||
@public SWindowData *window_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id) initWithWindowData:(SWindowData *) windowData;
|
|
||||||
|
|
||||||
@end
|
|
@ -1,70 +0,0 @@
|
|||||||
//
|
|
||||||
// iOSViewController.m
|
|
||||||
// MiniFB
|
|
||||||
//
|
|
||||||
// Created by Carlos Aragones on 22/04/2020.
|
|
||||||
// Copyright © 2020 Carlos Aragones. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Metal/Metal.h>
|
|
||||||
#import <MetalKit/MetalKit.h>
|
|
||||||
#import "iOSViewController.h"
|
|
||||||
#import "iOSViewDelegate.h"
|
|
||||||
#import "iOSView.h"
|
|
||||||
#include "WindowData_IOS.h"
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
@implementation iOSViewController
|
|
||||||
{
|
|
||||||
iOSView *metal_view;
|
|
||||||
//iOSViewDelegate *view_delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (id) initWithWindowData:(SWindowData *) windowData {
|
|
||||||
self = [super init];
|
|
||||||
if (self) {
|
|
||||||
window_data = windowData;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) loadView {
|
|
||||||
iOSView *view = [[iOSView alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
|
||||||
// Probably the window was created automatically by an storyboard or similar
|
|
||||||
if(window_data == 0x0) {
|
|
||||||
NSLog(@"WindowData is null!");
|
|
||||||
}
|
|
||||||
view->window_data = window_data;
|
|
||||||
view.userInteractionEnabled = true;
|
|
||||||
|
|
||||||
[self setView:view];
|
|
||||||
#if !__has_feature(objc_arc)
|
|
||||||
[view release];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) viewDidLoad
|
|
||||||
{
|
|
||||||
[super viewDidLoad];
|
|
||||||
|
|
||||||
metal_view = (iOSView *) self.view;
|
|
||||||
metal_view.device = MTLCreateSystemDefaultDevice();
|
|
||||||
metal_view.backgroundColor = UIColor.blackColor;
|
|
||||||
|
|
||||||
if(!metal_view.device) {
|
|
||||||
NSLog(@"Metal is not supported on this device");
|
|
||||||
self.view = [[UIView alloc] initWithFrame:self.view.frame];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData_IOS *window_data_ios = (SWindowData_IOS *) window_data->specific;
|
|
||||||
window_data_ios->view_delegate = [[iOSViewDelegate alloc] initWithMetalKitView:metal_view windowData:window_data];
|
|
||||||
[window_data_ios->view_delegate mtkView:metal_view drawableSizeWillChange:metal_view.bounds.size];
|
|
||||||
|
|
||||||
metal_view.delegate = window_data_ios->view_delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
@ -1,23 +0,0 @@
|
|||||||
//
|
|
||||||
// Renderer.h
|
|
||||||
// MiniFB
|
|
||||||
//
|
|
||||||
// Created by Carlos Aragones on 22/04/2020.
|
|
||||||
// Copyright © 2020 Carlos Aragones. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <MetalKit/MetalKit.h>
|
|
||||||
#include "WindowData.h"
|
|
||||||
|
|
||||||
// Our platform independent renderer class.
|
|
||||||
// Implements the MTKViewDelegate protocol which allows it to accept per-frame
|
|
||||||
// update and drawable resize callbacks.
|
|
||||||
@interface iOSViewDelegate : NSObject <MTKViewDelegate>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
-(nonnull instancetype) initWithMetalKitView:(nonnull MTKView *) view windowData:(nonnull SWindowData *) windowData;
|
|
||||||
- (void) resizeTextures;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
@ -1,254 +0,0 @@
|
|||||||
//
|
|
||||||
// Renderer.m
|
|
||||||
// MiniFB
|
|
||||||
//
|
|
||||||
// Created by Carlos Aragones on 22/04/2020.
|
|
||||||
// Copyright © 2020 Carlos Aragones. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <simd/simd.h>
|
|
||||||
#import <ModelIO/ModelIO.h>
|
|
||||||
|
|
||||||
#import "iOSViewDelegate.h"
|
|
||||||
#include "WindowData_IOS.h"
|
|
||||||
#include <MiniFB.h>
|
|
||||||
#include <MiniFB_ios.h>
|
|
||||||
#include <MiniFB_internal.h>
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
#define kShader(inc, src) @inc#src
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
enum { MaxBuffersInFlight = 3 }; // Number of textures in flight (tripple buffered)
|
|
||||||
|
|
||||||
//--
|
|
||||||
NSString *g_shader_src = kShader(
|
|
||||||
"#include <metal_stdlib>\n",
|
|
||||||
using namespace metal;
|
|
||||||
|
|
||||||
//-------------
|
|
||||||
struct VertexOutput {
|
|
||||||
float4 pos [[position]];
|
|
||||||
float2 texcoord;
|
|
||||||
};
|
|
||||||
|
|
||||||
//-------------
|
|
||||||
struct Vertex {
|
|
||||||
float4 position [[position]];
|
|
||||||
};
|
|
||||||
|
|
||||||
//-------------
|
|
||||||
vertex VertexOutput
|
|
||||||
vertFunc(unsigned int vID[[vertex_id]], const device Vertex *pos [[ buffer(0) ]]) {
|
|
||||||
VertexOutput out;
|
|
||||||
|
|
||||||
out.pos = pos[vID].position;
|
|
||||||
|
|
||||||
out.texcoord.x = (float) (vID / 2);
|
|
||||||
out.texcoord.y = 1.0 - (float) (vID % 2);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------
|
|
||||||
fragment float4
|
|
||||||
fragFunc(VertexOutput input [[stage_in]], texture2d<half> colorTexture [[ texture(0) ]]) {
|
|
||||||
constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);
|
|
||||||
|
|
||||||
// Sample the texture to obtain a color
|
|
||||||
const half4 colorSample = colorTexture.sample(textureSampler, input.texcoord);
|
|
||||||
|
|
||||||
// We return the color of the texture
|
|
||||||
return float4(colorSample);
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
@implementation iOSViewDelegate {
|
|
||||||
SWindowData *window_data;
|
|
||||||
SWindowData_IOS *window_data_ios;
|
|
||||||
|
|
||||||
id<MTLDevice> metal_device;
|
|
||||||
id<MTLLibrary> metal_library;
|
|
||||||
|
|
||||||
dispatch_semaphore_t semaphore;
|
|
||||||
id<MTLCommandQueue> command_queue;
|
|
||||||
|
|
||||||
id<MTLRenderPipelineState> pipeline_state;
|
|
||||||
id<MTLTexture> texture_buffer;
|
|
||||||
|
|
||||||
uint8_t current_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
-(nonnull instancetype) initWithMetalKitView:(nonnull MTKView *) view windowData:(nonnull SWindowData *) windowData {
|
|
||||||
self = [super init];
|
|
||||||
if (self) {
|
|
||||||
window_data = windowData;
|
|
||||||
window_data_ios = (SWindowData_IOS *) windowData->specific;
|
|
||||||
|
|
||||||
view.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
|
|
||||||
view.sampleCount = 1;
|
|
||||||
|
|
||||||
metal_device = view.device;
|
|
||||||
|
|
||||||
// Used for syncing the CPU and GPU
|
|
||||||
semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
|
|
||||||
|
|
||||||
// Setup command queue
|
|
||||||
command_queue = [metal_device newCommandQueue];
|
|
||||||
|
|
||||||
[self _createShaders];
|
|
||||||
[self _createAssets];
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (bool) _createShaders {
|
|
||||||
NSError *error = 0x0;
|
|
||||||
|
|
||||||
metal_library = [metal_device newLibraryWithSource:g_shader_src
|
|
||||||
options:[[MTLCompileOptions alloc] init]
|
|
||||||
error:&error
|
|
||||||
];
|
|
||||||
if (error || !metal_library) {
|
|
||||||
NSLog(@"Unable to create shaders %@", error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLFunction> vertex_shader_func = [metal_library newFunctionWithName:@"vertFunc"];
|
|
||||||
id<MTLFunction> fragment_shader_func = [metal_library newFunctionWithName:@"fragFunc"];
|
|
||||||
|
|
||||||
if (!vertex_shader_func) {
|
|
||||||
NSLog(@"Unable to get vertFunc!\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fragment_shader_func) {
|
|
||||||
NSLog(@"Unable to get fragFunc!\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a reusable pipeline state
|
|
||||||
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
|
||||||
pipelineStateDescriptor.label = @"MiniFB_pipeline";
|
|
||||||
pipelineStateDescriptor.vertexFunction = vertex_shader_func;
|
|
||||||
pipelineStateDescriptor.fragmentFunction = fragment_shader_func;
|
|
||||||
pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm;
|
|
||||||
|
|
||||||
pipeline_state = [metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
|
|
||||||
if (!pipeline_state) {
|
|
||||||
NSLog(@"Failed to created pipeline state, error %@", error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) _createAssets {
|
|
||||||
static Vertex s_vertices[4] = {
|
|
||||||
{-1.0, -1.0, 0, 1},
|
|
||||||
{-1.0, 1.0, 0, 1},
|
|
||||||
{ 1.0, -1.0, 0, 1},
|
|
||||||
{ 1.0, 1.0, 0, 1},
|
|
||||||
};
|
|
||||||
memcpy(window_data_ios->vertices, s_vertices, sizeof(s_vertices));
|
|
||||||
|
|
||||||
MTLTextureDescriptor *td;
|
|
||||||
td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
|
||||||
width:window_data->buffer_width
|
|
||||||
height:window_data->buffer_height
|
|
||||||
mipmapped:false];
|
|
||||||
|
|
||||||
// Create the texture from the device by using the descriptor
|
|
||||||
texture_buffer = [metal_device newTextureWithDescriptor:td];
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) resizeTextures {
|
|
||||||
MTLTextureDescriptor *td;
|
|
||||||
td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
|
||||||
width:window_data->buffer_width
|
|
||||||
height:window_data->buffer_height
|
|
||||||
mipmapped:false];
|
|
||||||
|
|
||||||
// Create the texture from the device by using the descriptor
|
|
||||||
[texture_buffer release];
|
|
||||||
texture_buffer = [metal_device newTextureWithDescriptor:td];
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) drawInMTKView:(nonnull MTKView *) view {
|
|
||||||
// Wait to ensure only MaxBuffersInFlight number of frames are getting proccessed
|
|
||||||
// by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc)
|
|
||||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
||||||
|
|
||||||
current_buffer = (current_buffer + 1) % MaxBuffersInFlight;
|
|
||||||
|
|
||||||
// Create a new command buffer for each render pass to the current drawable
|
|
||||||
id<MTLCommandBuffer> commandBuffer = [command_queue commandBuffer];
|
|
||||||
commandBuffer.label = @"minifb_command_buffer";
|
|
||||||
|
|
||||||
// Add completion hander which signals semaphore when Metal and the GPU has fully
|
|
||||||
// finished processing the commands we're encoding this frame. This indicates when the
|
|
||||||
// dynamic buffers filled with our vertices, that we're writing to this frame, will no longer
|
|
||||||
// be needed by Metal and the GPU, meaning we can overwrite the buffer contents without
|
|
||||||
// corrupting the rendering.
|
|
||||||
__block dispatch_semaphore_t block_sema = semaphore;
|
|
||||||
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
|
||||||
(void)buffer;
|
|
||||||
dispatch_semaphore_signal(block_sema);
|
|
||||||
}];
|
|
||||||
|
|
||||||
// Copy the bytes from our data object into the texture
|
|
||||||
MTLRegion region = { { 0, 0, 0 }, { window_data->buffer_width, window_data->buffer_height, 1 } };
|
|
||||||
[texture_buffer replaceRegion:region mipmapLevel:0 withBytes:window_data->draw_buffer bytesPerRow:window_data->buffer_stride];
|
|
||||||
|
|
||||||
// Delay getting the currentRenderPassDescriptor until absolutely needed. This avoids
|
|
||||||
// holding onto the drawable and blocking the display pipeline any longer than necessary
|
|
||||||
MTLRenderPassDescriptor* renderPassDescriptor = view.currentRenderPassDescriptor;
|
|
||||||
if (renderPassDescriptor != nil) {
|
|
||||||
//renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
// Create a render command encoder so we can render into something
|
|
||||||
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
|
||||||
renderEncoder.label = @"minifb_command_encoder";
|
|
||||||
|
|
||||||
// Set render command encoder state
|
|
||||||
[renderEncoder setRenderPipelineState:pipeline_state];
|
|
||||||
[renderEncoder setVertexBytes:window_data_ios->vertices length:sizeof(window_data_ios->vertices) atIndex:0];
|
|
||||||
|
|
||||||
//[renderEncoder setFragmentTexture:texture_buffers[current_buffer] atIndex:0];
|
|
||||||
[renderEncoder setFragmentTexture:texture_buffer atIndex:0];
|
|
||||||
|
|
||||||
// Draw the vertices of our quads
|
|
||||||
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
|
||||||
|
|
||||||
// We're done encoding commands
|
|
||||||
[renderEncoder endEncoding];
|
|
||||||
|
|
||||||
// Schedule a present once the framebuffer is complete using the current drawable
|
|
||||||
[commandBuffer presentDrawable:view.currentDrawable];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finalize rendering here & push the command buffer to the GPU
|
|
||||||
[commandBuffer commit];
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size {
|
|
||||||
(void) view;
|
|
||||||
// Respond to drawable size or orientation changes here
|
|
||||||
float scale = [UIScreen mainScreen].scale;
|
|
||||||
|
|
||||||
window_data->window_width = size.width * scale;
|
|
||||||
window_data->window_height = size.height * scale;
|
|
||||||
resize_dst(window_data, size.width, size.height);
|
|
||||||
|
|
||||||
kCall(resize_func, size.width, size.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
@ -1,589 +0,0 @@
|
|||||||
#include <Cocoa/Cocoa.h>
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
#include <Carbon/Carbon.h>
|
|
||||||
#include <MetalKit/MetalKit.h>
|
|
||||||
#endif
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sched.h>
|
|
||||||
#include <mach/mach_time.h>
|
|
||||||
|
|
||||||
#include "OSXWindow.h"
|
|
||||||
#include "OSXView.h"
|
|
||||||
#include "OSXViewDelegate.h"
|
|
||||||
#include "WindowData_OSX.h"
|
|
||||||
#include <MiniFB.h>
|
|
||||||
#include <MiniFB_internal.h>
|
|
||||||
#include <MiniFB_enums.h>
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void init_keycodes();
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
SWindowData *
|
|
||||||
create_window_data(unsigned width, unsigned height) {
|
|
||||||
SWindowData *window_data;
|
|
||||||
|
|
||||||
window_data = malloc(sizeof(SWindowData));
|
|
||||||
if(window_data == 0x0) {
|
|
||||||
NSLog(@"Cannot allocate window data");
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
memset(window_data, 0, sizeof(SWindowData));
|
|
||||||
|
|
||||||
SWindowData_OSX *window_data_osx = malloc(sizeof(SWindowData_OSX));
|
|
||||||
if(window_data_osx == 0x0) {
|
|
||||||
free(window_data);
|
|
||||||
NSLog(@"Cannot allocate osx window data");
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
memset(window_data_osx, 0, sizeof(SWindowData_OSX));
|
|
||||||
|
|
||||||
window_data->specific = window_data_osx;
|
|
||||||
|
|
||||||
calc_dst_factor(window_data, width, height);
|
|
||||||
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
window_data->draw_buffer = malloc(width * height * 4);
|
|
||||||
if (!window_data->draw_buffer) {
|
|
||||||
free(window_data_osx);
|
|
||||||
free(window_data);
|
|
||||||
NSLog(@"Unable to create draw buffer");
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return window_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
struct mfb_window *
|
|
||||||
mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) {
|
|
||||||
@autoreleasepool {
|
|
||||||
SWindowData *window_data = create_window_data(width, height);
|
|
||||||
if (window_data == 0x0) {
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
|
||||||
|
|
||||||
init_keycodes();
|
|
||||||
|
|
||||||
[NSApplication sharedApplication];
|
|
||||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
|
||||||
|
|
||||||
NSRect rectangle, frameRect;
|
|
||||||
NSWindowStyleMask styles = 0;
|
|
||||||
|
|
||||||
if (flags & WF_BORDERLESS) {
|
|
||||||
styles |= NSWindowStyleMaskBorderless;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
styles |= NSWindowStyleMaskClosable | NSWindowStyleMaskTitled;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & WF_RESIZABLE)
|
|
||||||
styles |= NSWindowStyleMaskResizable;
|
|
||||||
|
|
||||||
if (flags & WF_FULLSCREEN) {
|
|
||||||
styles = NSWindowStyleMaskFullScreen;
|
|
||||||
NSScreen *mainScreen = [NSScreen mainScreen];
|
|
||||||
NSRect screenRect = [mainScreen frame];
|
|
||||||
window_data->window_width = screenRect.size.width;
|
|
||||||
window_data->window_height = screenRect.size.height;
|
|
||||||
rectangle = NSMakeRect(0, 0, window_data->window_width, window_data->window_height);
|
|
||||||
frameRect = rectangle;
|
|
||||||
}
|
|
||||||
else if (flags & WF_FULLSCREEN_DESKTOP) {
|
|
||||||
NSScreen *mainScreen = [NSScreen mainScreen];
|
|
||||||
NSRect screenRect = [mainScreen visibleFrame];
|
|
||||||
window_data->window_width = screenRect.size.width;
|
|
||||||
window_data->window_height = screenRect.size.height;
|
|
||||||
rectangle = NSMakeRect(0, 0, window_data->window_width, window_data->window_height);
|
|
||||||
frameRect = rectangle;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
window_data->window_width = width;
|
|
||||||
window_data->window_height = height;
|
|
||||||
rectangle = NSMakeRect(0, 0, window_data->window_width, window_data->window_height);
|
|
||||||
frameRect = [NSWindow frameRectForContentRect:rectangle styleMask:styles];
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data_osx->window = [[OSXWindow alloc] initWithContentRect:frameRect styleMask:styles backing:NSBackingStoreBuffered defer:NO windowData:window_data];
|
|
||||||
if (!window_data_osx->window) {
|
|
||||||
NSLog(@"Cannot create window");
|
|
||||||
if(window_data->draw_buffer != 0x0) {
|
|
||||||
free(window_data->draw_buffer);
|
|
||||||
window_data->draw_buffer = 0x0;
|
|
||||||
}
|
|
||||||
free(window_data_osx);
|
|
||||||
free(window_data);
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
window_data_osx->viewController = [[OSXViewDelegate alloc] initWithWindowData:window_data];
|
|
||||||
|
|
||||||
MTKView* view = [[MTKView alloc] initWithFrame:rectangle];
|
|
||||||
view.device = window_data_osx->viewController->metal_device;
|
|
||||||
view.delegate = window_data_osx->viewController;
|
|
||||||
view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
|
||||||
[window_data_osx->window.contentView addSubview:view];
|
|
||||||
|
|
||||||
//[window_data->window updateSize];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[window_data_osx->window setTitle:[NSString stringWithUTF8String:title]];
|
|
||||||
[window_data_osx->window setReleasedWhenClosed:NO];
|
|
||||||
[window_data_osx->window performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES];
|
|
||||||
[window_data_osx->window setAcceptsMouseMovedEvents:YES];
|
|
||||||
|
|
||||||
[window_data_osx->window center];
|
|
||||||
window_data_osx->timer = mfb_timer_create();
|
|
||||||
|
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
[NSApp finishLaunching];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUG)
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
NSLog(@"Window created using Metal API");
|
|
||||||
#else
|
|
||||||
NSLog(@"Window created using Cocoa API");
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
window_data->is_initialized = true;
|
|
||||||
return (struct mfb_window *) window_data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
static void
|
|
||||||
destroy_window_data(SWindowData *window_data) {
|
|
||||||
if(window_data == 0x0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
@autoreleasepool {
|
|
||||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
|
||||||
if(window_data_osx != 0x0) {
|
|
||||||
OSXWindow *window = window_data_osx->window;
|
|
||||||
[window performClose:nil];
|
|
||||||
|
|
||||||
// Flush events!
|
|
||||||
NSEvent* event;
|
|
||||||
do {
|
|
||||||
event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
|
||||||
if (event) {
|
|
||||||
[NSApp sendEvent:event];
|
|
||||||
}
|
|
||||||
} while (event);
|
|
||||||
[window removeWindowData];
|
|
||||||
|
|
||||||
mfb_timer_destroy(window_data_osx->timer);
|
|
||||||
|
|
||||||
memset(window_data_osx, 0, sizeof(SWindowData_OSX));
|
|
||||||
free(window_data_osx);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
if(window_data->draw_buffer != 0x0) {
|
|
||||||
free(window_data->draw_buffer);
|
|
||||||
window_data->draw_buffer = 0x0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
memset(window_data, 0, sizeof(SWindowData));
|
|
||||||
free(window_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
static void
|
|
||||||
update_events(SWindowData *window_data) {
|
|
||||||
NSEvent* event;
|
|
||||||
|
|
||||||
@autoreleasepool {
|
|
||||||
do {
|
|
||||||
event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
|
||||||
if (event) {
|
|
||||||
[NSApp sendEvent:event];
|
|
||||||
}
|
|
||||||
} while ((window_data->close == false) && event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
mfb_update_state
|
|
||||||
mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned height) {
|
|
||||||
if(window == 0x0) {
|
|
||||||
return STATE_INVALID_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
if(window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return STATE_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buffer == 0x0) {
|
|
||||||
return STATE_INVALID_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
if(window_data->buffer_width != width || window_data->buffer_height != height) {
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
window_data->draw_buffer = realloc(window_data->draw_buffer, window_data->buffer_stride * window_data->buffer_height);
|
|
||||||
|
|
||||||
[window_data_osx->viewController resizeTextures];
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(window_data->draw_buffer, buffer, window_data->buffer_stride * window_data->buffer_height);
|
|
||||||
#else
|
|
||||||
if(window_data->buffer_width != width || window_data->buffer_height != height) {
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data->draw_buffer = buffer;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
update_events(window_data);
|
|
||||||
if(window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return STATE_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[window_data_osx->window contentView] setNeedsDisplay:YES];
|
|
||||||
|
|
||||||
return STATE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
mfb_update_state
|
|
||||||
mfb_update_events(struct mfb_window *window) {
|
|
||||||
if(window == 0x0) {
|
|
||||||
return STATE_INVALID_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
if(window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return STATE_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
update_events(window_data);
|
|
||||||
if(window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return STATE_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
|
||||||
[[window_data_osx->window contentView] setNeedsDisplay:YES];
|
|
||||||
|
|
||||||
return STATE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
extern double g_time_for_frame;
|
|
||||||
extern bool g_use_hardware_sync;
|
|
||||||
|
|
||||||
bool
|
|
||||||
mfb_wait_sync(struct mfb_window *window) {
|
|
||||||
NSEvent* event;
|
|
||||||
|
|
||||||
if(window == 0x0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
if(window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(g_use_hardware_sync) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@autoreleasepool {
|
|
||||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
|
||||||
if(window_data_osx == 0x0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double current;
|
|
||||||
uint32_t millis = 1;
|
|
||||||
while(1) {
|
|
||||||
current = mfb_timer_now(window_data_osx->timer);
|
|
||||||
if (current >= g_time_for_frame * 0.96) {
|
|
||||||
mfb_timer_reset(window_data_osx->timer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if(current >= g_time_for_frame * 0.8) {
|
|
||||||
millis = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
usleep(millis * 1000);
|
|
||||||
//sched_yield();
|
|
||||||
|
|
||||||
if(millis == 1) {
|
|
||||||
event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
|
||||||
if (event) {
|
|
||||||
[NSApp sendEvent:event];
|
|
||||||
|
|
||||||
if(window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
bool
|
|
||||||
mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) {
|
|
||||||
if(window == 0x0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
|
|
||||||
if(offset_x + width > window_data->window_width) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(offset_y + height > window_data->window_height) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data->dst_offset_x = offset_x;
|
|
||||||
window_data->dst_offset_y = offset_y;
|
|
||||||
window_data->dst_width = width;
|
|
||||||
window_data->dst_height = height;
|
|
||||||
calc_dst_factor(window_data, window_data->window_width, window_data->window_height);
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
float x1 = ((float) offset_x / window_data->window_width) * 2.0f - 1.0f;
|
|
||||||
float x2 = (((float) offset_x + width) / window_data->window_width) * 2.0f - 1.0f;
|
|
||||||
float y1 = ((float) offset_y / window_data->window_height) * 2.0f - 1.0f;
|
|
||||||
float y2 = (((float) offset_y + height) / window_data->window_height) * 2.0f - 1.0f;
|
|
||||||
|
|
||||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
|
||||||
|
|
||||||
window_data_osx->metal.vertices[0].x = x1;
|
|
||||||
window_data_osx->metal.vertices[0].y = y1;
|
|
||||||
|
|
||||||
window_data_osx->metal.vertices[1].x = x1;
|
|
||||||
window_data_osx->metal.vertices[1].y = y2;
|
|
||||||
|
|
||||||
window_data_osx->metal.vertices[2].x = x2;
|
|
||||||
window_data_osx->metal.vertices[2].y = y1;
|
|
||||||
|
|
||||||
window_data_osx->metal.vertices[3].x = x2;
|
|
||||||
window_data_osx->metal.vertices[3].y = y2;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
extern short int g_keycodes[512];
|
|
||||||
|
|
||||||
void
|
|
||||||
init_keycodes() {
|
|
||||||
// Clear keys
|
|
||||||
for (unsigned int i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i)
|
|
||||||
g_keycodes[i] = 0;
|
|
||||||
|
|
||||||
g_keycodes[0x1D] = KB_KEY_0;
|
|
||||||
g_keycodes[0x12] = KB_KEY_1;
|
|
||||||
g_keycodes[0x13] = KB_KEY_2;
|
|
||||||
g_keycodes[0x14] = KB_KEY_3;
|
|
||||||
g_keycodes[0x15] = KB_KEY_4;
|
|
||||||
g_keycodes[0x17] = KB_KEY_5;
|
|
||||||
g_keycodes[0x16] = KB_KEY_6;
|
|
||||||
g_keycodes[0x1A] = KB_KEY_7;
|
|
||||||
g_keycodes[0x1C] = KB_KEY_8;
|
|
||||||
g_keycodes[0x19] = KB_KEY_9;
|
|
||||||
g_keycodes[0x00] = KB_KEY_A;
|
|
||||||
g_keycodes[0x0B] = KB_KEY_B;
|
|
||||||
g_keycodes[0x08] = KB_KEY_C;
|
|
||||||
g_keycodes[0x02] = KB_KEY_D;
|
|
||||||
g_keycodes[0x0E] = KB_KEY_E;
|
|
||||||
g_keycodes[0x03] = KB_KEY_F;
|
|
||||||
g_keycodes[0x05] = KB_KEY_G;
|
|
||||||
g_keycodes[0x04] = KB_KEY_H;
|
|
||||||
g_keycodes[0x22] = KB_KEY_I;
|
|
||||||
g_keycodes[0x26] = KB_KEY_J;
|
|
||||||
g_keycodes[0x28] = KB_KEY_K;
|
|
||||||
g_keycodes[0x25] = KB_KEY_L;
|
|
||||||
g_keycodes[0x2E] = KB_KEY_M;
|
|
||||||
g_keycodes[0x2D] = KB_KEY_N;
|
|
||||||
g_keycodes[0x1F] = KB_KEY_O;
|
|
||||||
g_keycodes[0x23] = KB_KEY_P;
|
|
||||||
g_keycodes[0x0C] = KB_KEY_Q;
|
|
||||||
g_keycodes[0x0F] = KB_KEY_R;
|
|
||||||
g_keycodes[0x01] = KB_KEY_S;
|
|
||||||
g_keycodes[0x11] = KB_KEY_T;
|
|
||||||
g_keycodes[0x20] = KB_KEY_U;
|
|
||||||
g_keycodes[0x09] = KB_KEY_V;
|
|
||||||
g_keycodes[0x0D] = KB_KEY_W;
|
|
||||||
g_keycodes[0x07] = KB_KEY_X;
|
|
||||||
g_keycodes[0x10] = KB_KEY_Y;
|
|
||||||
g_keycodes[0x06] = KB_KEY_Z;
|
|
||||||
|
|
||||||
g_keycodes[0x27] = KB_KEY_APOSTROPHE;
|
|
||||||
g_keycodes[0x2A] = KB_KEY_BACKSLASH;
|
|
||||||
g_keycodes[0x2B] = KB_KEY_COMMA;
|
|
||||||
g_keycodes[0x18] = KB_KEY_EQUAL;
|
|
||||||
g_keycodes[0x32] = KB_KEY_GRAVE_ACCENT;
|
|
||||||
g_keycodes[0x21] = KB_KEY_LEFT_BRACKET;
|
|
||||||
g_keycodes[0x1B] = KB_KEY_MINUS;
|
|
||||||
g_keycodes[0x2F] = KB_KEY_PERIOD;
|
|
||||||
g_keycodes[0x1E] = KB_KEY_RIGHT_BRACKET;
|
|
||||||
g_keycodes[0x29] = KB_KEY_SEMICOLON;
|
|
||||||
g_keycodes[0x2C] = KB_KEY_SLASH;
|
|
||||||
g_keycodes[0x0A] = KB_KEY_WORLD_1;
|
|
||||||
|
|
||||||
g_keycodes[0x33] = KB_KEY_BACKSPACE;
|
|
||||||
g_keycodes[0x39] = KB_KEY_CAPS_LOCK;
|
|
||||||
g_keycodes[0x75] = KB_KEY_DELETE;
|
|
||||||
g_keycodes[0x7D] = KB_KEY_DOWN;
|
|
||||||
g_keycodes[0x77] = KB_KEY_END;
|
|
||||||
g_keycodes[0x24] = KB_KEY_ENTER;
|
|
||||||
g_keycodes[0x35] = KB_KEY_ESCAPE;
|
|
||||||
g_keycodes[0x7A] = KB_KEY_F1;
|
|
||||||
g_keycodes[0x78] = KB_KEY_F2;
|
|
||||||
g_keycodes[0x63] = KB_KEY_F3;
|
|
||||||
g_keycodes[0x76] = KB_KEY_F4;
|
|
||||||
g_keycodes[0x60] = KB_KEY_F5;
|
|
||||||
g_keycodes[0x61] = KB_KEY_F6;
|
|
||||||
g_keycodes[0x62] = KB_KEY_F7;
|
|
||||||
g_keycodes[0x64] = KB_KEY_F8;
|
|
||||||
g_keycodes[0x65] = KB_KEY_F9;
|
|
||||||
g_keycodes[0x6D] = KB_KEY_F10;
|
|
||||||
g_keycodes[0x67] = KB_KEY_F11;
|
|
||||||
g_keycodes[0x6F] = KB_KEY_F12;
|
|
||||||
g_keycodes[0x69] = KB_KEY_F13;
|
|
||||||
g_keycodes[0x6B] = KB_KEY_F14;
|
|
||||||
g_keycodes[0x71] = KB_KEY_F15;
|
|
||||||
g_keycodes[0x6A] = KB_KEY_F16;
|
|
||||||
g_keycodes[0x40] = KB_KEY_F17;
|
|
||||||
g_keycodes[0x4F] = KB_KEY_F18;
|
|
||||||
g_keycodes[0x50] = KB_KEY_F19;
|
|
||||||
g_keycodes[0x5A] = KB_KEY_F20;
|
|
||||||
g_keycodes[0x73] = KB_KEY_HOME;
|
|
||||||
g_keycodes[0x72] = KB_KEY_INSERT;
|
|
||||||
g_keycodes[0x7B] = KB_KEY_LEFT;
|
|
||||||
g_keycodes[0x3A] = KB_KEY_LEFT_ALT;
|
|
||||||
g_keycodes[0x3B] = KB_KEY_LEFT_CONTROL;
|
|
||||||
g_keycodes[0x38] = KB_KEY_LEFT_SHIFT;
|
|
||||||
g_keycodes[0x37] = KB_KEY_LEFT_SUPER;
|
|
||||||
g_keycodes[0x6E] = KB_KEY_MENU;
|
|
||||||
g_keycodes[0x47] = KB_KEY_NUM_LOCK;
|
|
||||||
g_keycodes[0x79] = KB_KEY_PAGE_DOWN;
|
|
||||||
g_keycodes[0x74] = KB_KEY_PAGE_UP;
|
|
||||||
g_keycodes[0x7C] = KB_KEY_RIGHT;
|
|
||||||
g_keycodes[0x3D] = KB_KEY_RIGHT_ALT;
|
|
||||||
g_keycodes[0x3E] = KB_KEY_RIGHT_CONTROL;
|
|
||||||
g_keycodes[0x3C] = KB_KEY_RIGHT_SHIFT;
|
|
||||||
g_keycodes[0x36] = KB_KEY_RIGHT_SUPER;
|
|
||||||
g_keycodes[0x31] = KB_KEY_SPACE;
|
|
||||||
g_keycodes[0x30] = KB_KEY_TAB;
|
|
||||||
g_keycodes[0x7E] = KB_KEY_UP;
|
|
||||||
|
|
||||||
g_keycodes[0x52] = KB_KEY_KP_0;
|
|
||||||
g_keycodes[0x53] = KB_KEY_KP_1;
|
|
||||||
g_keycodes[0x54] = KB_KEY_KP_2;
|
|
||||||
g_keycodes[0x55] = KB_KEY_KP_3;
|
|
||||||
g_keycodes[0x56] = KB_KEY_KP_4;
|
|
||||||
g_keycodes[0x57] = KB_KEY_KP_5;
|
|
||||||
g_keycodes[0x58] = KB_KEY_KP_6;
|
|
||||||
g_keycodes[0x59] = KB_KEY_KP_7;
|
|
||||||
g_keycodes[0x5B] = KB_KEY_KP_8;
|
|
||||||
g_keycodes[0x5C] = KB_KEY_KP_9;
|
|
||||||
g_keycodes[0x45] = KB_KEY_KP_ADD;
|
|
||||||
g_keycodes[0x41] = KB_KEY_KP_DECIMAL;
|
|
||||||
g_keycodes[0x4B] = KB_KEY_KP_DIVIDE;
|
|
||||||
g_keycodes[0x4C] = KB_KEY_KP_ENTER;
|
|
||||||
g_keycodes[0x51] = KB_KEY_KP_EQUAL;
|
|
||||||
g_keycodes[0x43] = KB_KEY_KP_MULTIPLY;
|
|
||||||
g_keycodes[0x4E] = KB_KEY_KP_SUBTRACT;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
extern double g_timer_frequency;
|
|
||||||
extern double g_timer_resolution;
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
mfb_timer_tick() {
|
|
||||||
static mach_timebase_info_data_t timebase = { 0 };
|
|
||||||
|
|
||||||
if (timebase.denom == 0) {
|
|
||||||
(void) mach_timebase_info(&timebase);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t time = mach_absolute_time();
|
|
||||||
|
|
||||||
//return (time * s_timebase_info.numer) / s_timebase_info.denom;
|
|
||||||
|
|
||||||
// Perform the arithmetic at 128-bit precision to avoid the overflow!
|
|
||||||
uint64_t high = (time >> 32) * timebase.numer;
|
|
||||||
uint64_t highRem = ((high % timebase.denom) << 32) / timebase.denom;
|
|
||||||
uint64_t low = (time & 0xFFFFFFFFull) * timebase.numer / timebase.denom;
|
|
||||||
high /= timebase.denom;
|
|
||||||
|
|
||||||
return (high << 32) + highRem + low;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_timer_init() {
|
|
||||||
g_timer_frequency = 1e+9;
|
|
||||||
g_timer_resolution = 1.0 / g_timer_frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y) {
|
|
||||||
float scale = 1.0f;
|
|
||||||
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
|
||||||
|
|
||||||
scale = [window_data_osx->window backingScaleFactor];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
scale = [[NSScreen mainScreen] backingScaleFactor];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale_x) {
|
|
||||||
*scale_x = scale;
|
|
||||||
if(*scale_x == 0) {
|
|
||||||
*scale_x = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale_y) {
|
|
||||||
*scale_y = scale;
|
|
||||||
if (*scale_y == 0) {
|
|
||||||
*scale_y = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
|
|
||||||
#include "WindowData.h"
|
|
||||||
|
|
||||||
@interface OSXView : NSView
|
|
||||||
{
|
|
||||||
@public SWindowData *window_data;
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
@private NSTrackingArea *tracking_area;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
@ -1,240 +0,0 @@
|
|||||||
#import "OSXView.h"
|
|
||||||
#import "OSXWindow.h"
|
|
||||||
#import "WindowData_OSX.h"
|
|
||||||
#include <MiniFB_internal.h>
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
@implementation OSXView
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)updateTrackingAreas {
|
|
||||||
if(tracking_area != nil) {
|
|
||||||
[self removeTrackingArea:tracking_area];
|
|
||||||
[tracking_area release];
|
|
||||||
}
|
|
||||||
|
|
||||||
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
|
|
||||||
tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds]
|
|
||||||
options:opts
|
|
||||||
owner:self
|
|
||||||
userInfo:nil];
|
|
||||||
[self addTrackingArea:tracking_area];
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (NSRect)resizeRect {
|
|
||||||
const CGFloat resizeBoxSize = 16.0;
|
|
||||||
const CGFloat contentViewPadding = 5.5;
|
|
||||||
|
|
||||||
NSRect contentViewRect = [[self window] contentRectForFrameRect:[[self window] frame]];
|
|
||||||
NSRect resizeRect = NSMakeRect(
|
|
||||||
NSMaxX(contentViewRect) + contentViewPadding,
|
|
||||||
NSMinY(contentViewRect) - resizeBoxSize - contentViewPadding,
|
|
||||||
resizeBoxSize,
|
|
||||||
resizeBoxSize
|
|
||||||
);
|
|
||||||
|
|
||||||
return resizeRect;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)drawRect:(NSRect)rect {
|
|
||||||
(void)rect;
|
|
||||||
|
|
||||||
if(window_data == 0x0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
|
||||||
if (!window_data_osx || !window_data_osx->window || !window_data->draw_buffer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
|
|
||||||
|
|
||||||
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
|
|
||||||
CGDataProviderRef provider = CGDataProviderCreateWithData(0x0,
|
|
||||||
window_data->draw_buffer,
|
|
||||||
window_data->buffer_width * window_data->buffer_height * 4,
|
|
||||||
0x0
|
|
||||||
);
|
|
||||||
|
|
||||||
CGImageRef img = CGImageCreate(window_data->buffer_width
|
|
||||||
, window_data->buffer_height
|
|
||||||
, 8
|
|
||||||
, 32
|
|
||||||
, window_data->buffer_width * 4
|
|
||||||
, space
|
|
||||||
, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little
|
|
||||||
, provider
|
|
||||||
, 0x0
|
|
||||||
, false
|
|
||||||
, kCGRenderingIntentDefault
|
|
||||||
);
|
|
||||||
|
|
||||||
const CGFloat components[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
|
||||||
const CGColorRef black = CGColorCreate(space, components);
|
|
||||||
|
|
||||||
CGColorSpaceRelease(space);
|
|
||||||
CGDataProviderRelease(provider);
|
|
||||||
|
|
||||||
if(window_data->dst_offset_x != 0 || window_data->dst_offset_y != 0 || window_data->dst_width != window_data->window_width || window_data->dst_height != window_data->window_height) {
|
|
||||||
CGContextSetFillColorWithColor(context, black);
|
|
||||||
CGContextFillRect(context, rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Sometimes there is a crash here
|
|
||||||
CGContextDrawImage(context,
|
|
||||||
CGRectMake(window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height),
|
|
||||||
img
|
|
||||||
);
|
|
||||||
|
|
||||||
CGImageRelease(img);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (BOOL)acceptsFirstMouse:(NSEvent *)event {
|
|
||||||
(void)event;
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)mouseDown:(NSEvent*)event {
|
|
||||||
(void)event;
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->mouse_button_status[MOUSE_BTN_1] = true;
|
|
||||||
kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)mouseUp:(NSEvent*)event {
|
|
||||||
(void)event;
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->mouse_button_status[MOUSE_BTN_1] = false;
|
|
||||||
kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)rightMouseDown:(NSEvent*)event {
|
|
||||||
(void)event;
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->mouse_button_status[MOUSE_BTN_2] = true;
|
|
||||||
kCall(mouse_btn_func, MOUSE_BTN_2, window_data->mod_keys, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)rightMouseUp:(NSEvent*)event {
|
|
||||||
(void)event;
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->mouse_button_status[MOUSE_BTN_2] = false;
|
|
||||||
kCall(mouse_btn_func, MOUSE_BTN_2, window_data->mod_keys, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)otherMouseDown:(NSEvent *)event {
|
|
||||||
(void)event;
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->mouse_button_status[[event buttonNumber] & 0x07] = true;
|
|
||||||
kCall(mouse_btn_func, [event buttonNumber], window_data->mod_keys, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)otherMouseUp:(NSEvent *)event {
|
|
||||||
(void)event;
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->mouse_button_status[[event buttonNumber] & 0x07] = false;
|
|
||||||
kCall(mouse_btn_func, [event buttonNumber], window_data->mod_keys, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)scrollWheel:(NSEvent *)event {
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->mouse_wheel_x = [event deltaX];
|
|
||||||
window_data->mouse_wheel_y = [event deltaY];
|
|
||||||
kCall(mouse_wheel_func, window_data->mod_keys, window_data->mouse_wheel_x, window_data->mouse_wheel_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)mouseDragged:(NSEvent *)event {
|
|
||||||
[self mouseMoved:event];
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)rightMouseDragged:(NSEvent *)event {
|
|
||||||
[self mouseMoved:event];
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)otherMouseDragged:(NSEvent *)event {
|
|
||||||
[self mouseMoved:event];
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)mouseMoved:(NSEvent *)event {
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
NSPoint point = [event locationInWindow];
|
|
||||||
//NSPoint localPoint = [self convertPoint:point fromView:nil];
|
|
||||||
window_data->mouse_pos_x = point.x;
|
|
||||||
#if defined(USE_INVERTED_Y_ON_MACOS)
|
|
||||||
window_data->mouse_pos_y = point.y;
|
|
||||||
#else
|
|
||||||
window_data->mouse_pos_y = window_data->window_height - point.y;
|
|
||||||
#endif
|
|
||||||
kCall(mouse_move_func, window_data->mouse_pos_x, window_data->mouse_pos_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)mouseExited:(NSEvent *)event {
|
|
||||||
(void)event;
|
|
||||||
//printf("mouse exit\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)mouseEntered:(NSEvent *)event {
|
|
||||||
(void)event;
|
|
||||||
//printf("mouse enter\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (BOOL)canBecomeKeyView {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (NSView *)nextValidKeyView {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (NSView *)previousValidKeyView {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (BOOL)acceptsFirstResponder {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)viewDidMoveToWindow {
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void)dealloc {
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
@ -1,35 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
|
|
||||||
#import <MetalKit/MetalKit.h>
|
|
||||||
#include "WindowData_OSX.h"
|
|
||||||
|
|
||||||
// Number of textures in flight (tripple buffered)
|
|
||||||
enum { MaxBuffersInFlight = 3 };
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@interface OSXViewDelegate : NSViewController<MTKViewDelegate>
|
|
||||||
{
|
|
||||||
@public SWindowData *window_data;
|
|
||||||
@public SWindowData_OSX *window_data_osx;
|
|
||||||
|
|
||||||
id<MTLDevice> metal_device;
|
|
||||||
id<MTLLibrary> metal_library;
|
|
||||||
|
|
||||||
dispatch_semaphore_t semaphore; // Used for syncing with CPU/GPU
|
|
||||||
id<MTLCommandQueue> command_queue;
|
|
||||||
|
|
||||||
id<MTLRenderPipelineState> pipeline_state;
|
|
||||||
id<MTLTexture> texture_buffers[MaxBuffersInFlight];
|
|
||||||
|
|
||||||
int current_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id) initWithWindowData:(SWindowData *) windowData;
|
|
||||||
- (void) resizeTextures;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,261 +0,0 @@
|
|||||||
#include "OSXViewDelegate.h"
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
|
|
||||||
#import <MetalKit/MetalKit.h>
|
|
||||||
|
|
||||||
extern double g_time_for_frame;
|
|
||||||
extern bool g_use_hardware_sync;
|
|
||||||
//--
|
|
||||||
bool g_target_fps_changed = true;
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
void
|
|
||||||
set_target_fps_aux() {
|
|
||||||
g_target_fps_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
#define kShader(inc, src) @inc#src
|
|
||||||
|
|
||||||
NSString *g_shader_src = kShader(
|
|
||||||
"#include <metal_stdlib>\n",
|
|
||||||
using namespace metal;
|
|
||||||
|
|
||||||
//-------------
|
|
||||||
struct VertexOutput {
|
|
||||||
float4 pos [[position]];
|
|
||||||
float2 texcoord;
|
|
||||||
};
|
|
||||||
|
|
||||||
//-------------
|
|
||||||
struct Vertex {
|
|
||||||
float4 position [[position]];
|
|
||||||
};
|
|
||||||
|
|
||||||
//-------------
|
|
||||||
vertex VertexOutput
|
|
||||||
vertFunc(unsigned int vID[[vertex_id]], const device Vertex *pos [[ buffer(0) ]]) {
|
|
||||||
VertexOutput out;
|
|
||||||
|
|
||||||
out.pos = pos[vID].position;
|
|
||||||
|
|
||||||
out.texcoord.x = (float) (vID / 2);
|
|
||||||
out.texcoord.y = 1.0 - (float) (vID % 2);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------
|
|
||||||
fragment float4
|
|
||||||
fragFunc(VertexOutput input [[stage_in]], texture2d<half> colorTexture [[ texture(0) ]]) {
|
|
||||||
constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);
|
|
||||||
|
|
||||||
// Sample the texture to obtain a color
|
|
||||||
const half4 colorSample = colorTexture.sample(textureSampler, input.texcoord);
|
|
||||||
|
|
||||||
// We return the color of the texture
|
|
||||||
return float4(colorSample);
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
@implementation OSXViewDelegate
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (id) initWithWindowData:(SWindowData *) windowData {
|
|
||||||
self = [super init];
|
|
||||||
if (self) {
|
|
||||||
window_data = windowData;
|
|
||||||
window_data_osx = (SWindowData_OSX *) windowData->specific;
|
|
||||||
|
|
||||||
metal_device = MTLCreateSystemDefaultDevice();
|
|
||||||
if (!metal_device) {
|
|
||||||
NSLog(@"Metal is not supported on this device");
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used for syncing the CPU and GPU
|
|
||||||
semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
|
|
||||||
|
|
||||||
// Setup command queue
|
|
||||||
command_queue = [metal_device newCommandQueue];
|
|
||||||
|
|
||||||
// MacOS Mojave is ignoring view.preferredFramesPerSecond
|
|
||||||
// MacOS Big Sur is ignoring commandBuffer:presentDrawable:afterMinimumDuration:
|
|
||||||
//id<MTLCommandBuffer> commandBuffer = [command_queue commandBuffer];
|
|
||||||
//if ([commandBuffer respondsToSelector:@selector(presentDrawable:afterMinimumDuration:)]) {
|
|
||||||
// g_use_hardware_sync = true;
|
|
||||||
//}
|
|
||||||
|
|
||||||
[self _createShaders];
|
|
||||||
[self _createAssets];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (bool) _createShaders {
|
|
||||||
NSError *error = 0x0;
|
|
||||||
|
|
||||||
metal_library = [metal_device newLibraryWithSource:g_shader_src
|
|
||||||
options:[[MTLCompileOptions alloc] init]
|
|
||||||
error:&error
|
|
||||||
];
|
|
||||||
if (error || !metal_library) {
|
|
||||||
NSLog(@"Unable to create shaders %@", error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLFunction> vertex_shader_func = [metal_library newFunctionWithName:@"vertFunc"];
|
|
||||||
id<MTLFunction> fragment_shader_func = [metal_library newFunctionWithName:@"fragFunc"];
|
|
||||||
|
|
||||||
if (!vertex_shader_func) {
|
|
||||||
NSLog(@"Unable to get vertFunc!\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fragment_shader_func) {
|
|
||||||
NSLog(@"Unable to get fragFunc!\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a reusable pipeline state
|
|
||||||
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
|
||||||
pipelineStateDescriptor.label = @"MiniFB_pipeline";
|
|
||||||
pipelineStateDescriptor.vertexFunction = vertex_shader_func;
|
|
||||||
pipelineStateDescriptor.fragmentFunction = fragment_shader_func;
|
|
||||||
pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm;
|
|
||||||
|
|
||||||
pipeline_state = [metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
|
|
||||||
if (!pipeline_state) {
|
|
||||||
NSLog(@"Failed to created pipeline state, error %@", error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) _createAssets {
|
|
||||||
static Vertex s_vertices[4] = {
|
|
||||||
{-1.0, -1.0, 0, 1},
|
|
||||||
{-1.0, 1.0, 0, 1},
|
|
||||||
{ 1.0, -1.0, 0, 1},
|
|
||||||
{ 1.0, 1.0, 0, 1},
|
|
||||||
};
|
|
||||||
memcpy(window_data_osx->metal.vertices, s_vertices, sizeof(s_vertices));
|
|
||||||
|
|
||||||
MTLTextureDescriptor *td;
|
|
||||||
td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
|
||||||
width:window_data->buffer_width
|
|
||||||
height:window_data->buffer_height
|
|
||||||
mipmapped:false];
|
|
||||||
|
|
||||||
// Create the texture from the device by using the descriptor
|
|
||||||
for (size_t i = 0; i < MaxBuffersInFlight; ++i) {
|
|
||||||
texture_buffers[i] = [metal_device newTextureWithDescriptor:td];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) resizeTextures {
|
|
||||||
MTLTextureDescriptor *td;
|
|
||||||
td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
|
||||||
width:window_data->buffer_width
|
|
||||||
height:window_data->buffer_height
|
|
||||||
mipmapped:false];
|
|
||||||
|
|
||||||
// Create the texture from the device by using the descriptor
|
|
||||||
for (size_t i = 0; i < MaxBuffersInFlight; ++i) {
|
|
||||||
[texture_buffers[i] release];
|
|
||||||
texture_buffers[i] = [metal_device newTextureWithDescriptor:td];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) drawInMTKView:(nonnull MTKView *) view {
|
|
||||||
if (g_target_fps_changed) {
|
|
||||||
// MacOS is ignoring this :(
|
|
||||||
if (g_time_for_frame == 0) {
|
|
||||||
// Contrary to what is stated in the documentation,
|
|
||||||
// 0 means that it does not update. Like pause.
|
|
||||||
view.preferredFramesPerSecond = 9999;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
view.preferredFramesPerSecond = (int) (1.0 / g_time_for_frame);
|
|
||||||
}
|
|
||||||
g_target_fps_changed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait to ensure only MaxBuffersInFlight number of frames are getting proccessed
|
|
||||||
// by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc)
|
|
||||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
||||||
|
|
||||||
current_buffer = (current_buffer + 1) % MaxBuffersInFlight;
|
|
||||||
|
|
||||||
// Create a new command buffer for each render pass to the current drawable
|
|
||||||
id<MTLCommandBuffer> commandBuffer = [command_queue commandBuffer];
|
|
||||||
commandBuffer.label = @"minifb_command_buffer";
|
|
||||||
|
|
||||||
// Add completion hander which signals semaphore when Metal and the GPU has fully
|
|
||||||
// finished processing the commands we're encoding this frame. This indicates when the
|
|
||||||
// dynamic buffers filled with our vertices, that we're writing to this frame, will no longer
|
|
||||||
// be needed by Metal and the GPU, meaning we can overwrite the buffer contents without
|
|
||||||
// corrupting the rendering.
|
|
||||||
__block dispatch_semaphore_t block_sema = semaphore;
|
|
||||||
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
|
||||||
(void)buffer;
|
|
||||||
dispatch_semaphore_signal(block_sema);
|
|
||||||
}];
|
|
||||||
|
|
||||||
// Copy the bytes from our data object into the texture
|
|
||||||
MTLRegion region = { { 0, 0, 0 }, { window_data->buffer_width, window_data->buffer_height, 1 } };
|
|
||||||
[texture_buffers[current_buffer] replaceRegion:region mipmapLevel:0 withBytes:window_data->draw_buffer bytesPerRow:window_data->buffer_stride];
|
|
||||||
|
|
||||||
// Delay getting the currentRenderPassDescriptor until absolutely needed. This avoids
|
|
||||||
// holding onto the drawable and blocking the display pipeline any longer than necessary
|
|
||||||
MTLRenderPassDescriptor* renderPassDescriptor = view.currentRenderPassDescriptor;
|
|
||||||
if (renderPassDescriptor != nil) {
|
|
||||||
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
// Create a render command encoder so we can render into something
|
|
||||||
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
|
||||||
renderEncoder.label = @"minifb_command_encoder";
|
|
||||||
|
|
||||||
// Set render command encoder state
|
|
||||||
[renderEncoder setRenderPipelineState:pipeline_state];
|
|
||||||
[renderEncoder setVertexBytes:window_data_osx->metal.vertices length:sizeof(window_data_osx->metal.vertices) atIndex:0];
|
|
||||||
|
|
||||||
[renderEncoder setFragmentTexture:texture_buffers[current_buffer] atIndex:0];
|
|
||||||
|
|
||||||
// Draw the vertices of our quads
|
|
||||||
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
|
||||||
|
|
||||||
// We're done encoding commands
|
|
||||||
[renderEncoder endEncoding];
|
|
||||||
|
|
||||||
// Schedule a present once the framebuffer is complete using the current drawable
|
|
||||||
//if ([commandBuffer respondsToSelector:@selector(presentDrawable:afterMinimumDuration:)]) {
|
|
||||||
// // MacOS Big Sur is ignoring this
|
|
||||||
// [commandBuffer presentDrawable:view.currentDrawable afterMinimumDuration:g_time_for_frame];
|
|
||||||
//}
|
|
||||||
//else {
|
|
||||||
[commandBuffer presentDrawable:view.currentDrawable];
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finalize rendering here & push the command buffer to the GPU
|
|
||||||
[commandBuffer commit];
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
- (void) mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size {
|
|
||||||
(void)view;
|
|
||||||
(void)size;
|
|
||||||
// resize
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,17 +0,0 @@
|
|||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#include <WindowData.h>
|
|
||||||
|
|
||||||
@interface OSXWindow : NSWindow<NSWindowDelegate>
|
|
||||||
{
|
|
||||||
NSView *childContentView;
|
|
||||||
@public SWindowData *window_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithContentRect:(NSRect)contentRect
|
|
||||||
styleMask:(NSWindowStyleMask)windowStyle
|
|
||||||
backing:(NSBackingStoreType)bufferingType
|
|
||||||
defer:(BOOL)deferCreation
|
|
||||||
windowData:(SWindowData *) windowData;
|
|
||||||
|
|
||||||
- (void) removeWindowData;
|
|
||||||
@end
|
|
@ -1,315 +0,0 @@
|
|||||||
#import "OSXWindow.h"
|
|
||||||
#import "OSXView.h"
|
|
||||||
#include "WindowData_OSX.h"
|
|
||||||
#include <MiniFB_internal.h>
|
|
||||||
#include <MiniFB_enums.h>
|
|
||||||
|
|
||||||
@implementation OSXWindow
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (id)initWithContentRect:(NSRect)contentRect
|
|
||||||
styleMask:(NSWindowStyleMask)windowStyle
|
|
||||||
backing:(NSBackingStoreType)bufferingType
|
|
||||||
defer:(BOOL)deferCreation
|
|
||||||
windowData:(SWindowData *) windowData
|
|
||||||
{
|
|
||||||
self = [super
|
|
||||||
initWithContentRect:contentRect
|
|
||||||
styleMask:windowStyle
|
|
||||||
backing:bufferingType
|
|
||||||
defer:deferCreation];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
[self setOpaque:YES];
|
|
||||||
[self setBackgroundColor:[NSColor clearColor]];
|
|
||||||
|
|
||||||
self.delegate = self;
|
|
||||||
|
|
||||||
self->window_data = windowData;
|
|
||||||
OSXView *view = (OSXView *) self->childContentView.superview;
|
|
||||||
view->window_data = windowData;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void) removeWindowData {
|
|
||||||
self->window_data = 0x0;
|
|
||||||
OSXView *view = (OSXView *) self->childContentView.superview;
|
|
||||||
view->window_data = 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void)dealloc
|
|
||||||
{
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
|
||||||
removeObserver:self];
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void)setContentSize:(NSSize)newSize
|
|
||||||
{
|
|
||||||
NSSize sizeDelta = newSize;
|
|
||||||
NSSize childBoundsSize = [childContentView bounds].size;
|
|
||||||
sizeDelta.width -= childBoundsSize.width;
|
|
||||||
sizeDelta.height -= childBoundsSize.height;
|
|
||||||
|
|
||||||
OSXView *frameView = [super contentView];
|
|
||||||
NSSize newFrameSize = [frameView bounds].size;
|
|
||||||
newFrameSize.width += sizeDelta.width;
|
|
||||||
newFrameSize.height += sizeDelta.height;
|
|
||||||
|
|
||||||
[super setContentSize:newFrameSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void)flagsChanged:(NSEvent *)event
|
|
||||||
{
|
|
||||||
if(window_data == 0x0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const uint32_t flags = [event modifierFlags];
|
|
||||||
uint32_t mod_keys = 0, mod_keys_aux = 0;
|
|
||||||
|
|
||||||
//NSEventModifierFlagHelp = 1 << 22,
|
|
||||||
//NSEventModifierFlagFunction = 1 << 23,
|
|
||||||
if(flags & NSEventModifierFlagCapsLock) {
|
|
||||||
mod_keys |= KB_MOD_CAPS_LOCK;
|
|
||||||
}
|
|
||||||
if(flags & NSEventModifierFlagShift) {
|
|
||||||
mod_keys |= KB_MOD_SHIFT;
|
|
||||||
}
|
|
||||||
if(flags & NSEventModifierFlagControl) {
|
|
||||||
mod_keys |= KB_MOD_CONTROL;
|
|
||||||
}
|
|
||||||
if(flags & NSEventModifierFlagOption) {
|
|
||||||
mod_keys |= KB_MOD_ALT;
|
|
||||||
}
|
|
||||||
if(flags & NSEventModifierFlagCommand) {
|
|
||||||
mod_keys |= KB_MOD_SUPER;
|
|
||||||
}
|
|
||||||
if(flags & NSEventModifierFlagNumericPad) {
|
|
||||||
mod_keys |= KB_MOD_NUM_LOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mod_keys != window_data->mod_keys) {
|
|
||||||
short int key_code = g_keycodes[[event keyCode] & 0x1ff];
|
|
||||||
if(key_code != KB_KEY_UNKNOWN) {
|
|
||||||
mod_keys_aux = mod_keys ^ window_data->mod_keys;
|
|
||||||
if(mod_keys_aux & KB_MOD_CAPS_LOCK) {
|
|
||||||
window_data->key_status[key_code] = (mod_keys & KB_MOD_CAPS_LOCK) != 0;
|
|
||||||
kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]);
|
|
||||||
}
|
|
||||||
if(mod_keys_aux & KB_MOD_SHIFT) {
|
|
||||||
window_data->key_status[key_code] = (mod_keys & KB_MOD_SHIFT) != 0;
|
|
||||||
kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]);
|
|
||||||
}
|
|
||||||
if(mod_keys_aux & KB_MOD_CONTROL) {
|
|
||||||
window_data->key_status[key_code] = (mod_keys & KB_MOD_CONTROL) != 0;
|
|
||||||
kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]);
|
|
||||||
}
|
|
||||||
if(mod_keys_aux & KB_MOD_ALT) {
|
|
||||||
window_data->key_status[key_code] = (mod_keys & KB_MOD_ALT) != 0;
|
|
||||||
kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]);
|
|
||||||
}
|
|
||||||
if(mod_keys_aux & KB_MOD_SUPER) {
|
|
||||||
window_data->key_status[key_code] = (mod_keys & KB_MOD_SUPER) != 0;
|
|
||||||
kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]);
|
|
||||||
}
|
|
||||||
if(mod_keys_aux & KB_MOD_NUM_LOCK) {
|
|
||||||
window_data->key_status[key_code] = (mod_keys & KB_MOD_NUM_LOCK) != 0;
|
|
||||||
kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window_data->mod_keys = mod_keys;
|
|
||||||
|
|
||||||
[super flagsChanged:event];
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void)keyDown:(NSEvent *)event
|
|
||||||
{
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
short int key_code = g_keycodes[[event keyCode] & 0x1ff];
|
|
||||||
window_data->key_status[key_code] = true;
|
|
||||||
kCall(keyboard_func, key_code, window_data->mod_keys, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void)keyUp:(NSEvent *)event
|
|
||||||
{
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
short int key_code = g_keycodes[[event keyCode] & 0x1ff];
|
|
||||||
window_data->key_status[key_code] = false;
|
|
||||||
kCall(keyboard_func, key_code, window_data->mod_keys, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
|
|
||||||
{
|
|
||||||
kUnused(replacementRange);
|
|
||||||
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
NSString *characters;
|
|
||||||
NSUInteger length;
|
|
||||||
|
|
||||||
if ([string isKindOfClass:[NSAttributedString class]])
|
|
||||||
characters = [string string];
|
|
||||||
else
|
|
||||||
characters = (NSString*) string;
|
|
||||||
|
|
||||||
length = [characters length];
|
|
||||||
for (NSUInteger i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
const unichar code = [characters characterAtIndex:i];
|
|
||||||
if ((code & 0xff00) == 0xf700)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
kCall(char_input_func, code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void)mainWindowChanged:(NSNotification *)notification
|
|
||||||
{
|
|
||||||
kUnused(notification);
|
|
||||||
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
if(window_data->is_active == true) {
|
|
||||||
window_data->is_active = false;
|
|
||||||
kCall(active_func, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void)setContentView:(NSView *)aView
|
|
||||||
{
|
|
||||||
if ([childContentView isEqualTo:aView]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSRect bounds = [self frame];
|
|
||||||
bounds.origin = NSZeroPoint;
|
|
||||||
|
|
||||||
OSXView *frameView = [super contentView];
|
|
||||||
if (!frameView)
|
|
||||||
{
|
|
||||||
frameView = [[[OSXView alloc] initWithFrame:bounds] autorelease];
|
|
||||||
|
|
||||||
[super setContentView:frameView];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (childContentView)
|
|
||||||
{
|
|
||||||
[childContentView removeFromSuperview];
|
|
||||||
}
|
|
||||||
childContentView = aView;
|
|
||||||
[childContentView setFrame:[self contentRectForFrameRect:bounds]];
|
|
||||||
[childContentView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
|
||||||
[frameView addSubview:childContentView];
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (NSView *)contentView
|
|
||||||
{
|
|
||||||
return childContentView;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (BOOL)canBecomeKeyWindow
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
|
||||||
{
|
|
||||||
kUnused(notification);
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->is_active = true;
|
|
||||||
kCall(active_func, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)windowDidResignKey:(NSNotification *)notification
|
|
||||||
{
|
|
||||||
kUnused(notification);
|
|
||||||
if(window_data) {
|
|
||||||
window_data->is_active = false;
|
|
||||||
kCall(active_func, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)windowWillClose:(NSNotification *)notification {
|
|
||||||
kUnused(notification);
|
|
||||||
if(window_data) {
|
|
||||||
window_data->close = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (BOOL)canBecomeMainWindow
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (NSRect)contentRectForFrameRect:(NSRect)windowFrame
|
|
||||||
{
|
|
||||||
windowFrame.origin = NSZeroPoint;
|
|
||||||
return NSInsetRect(windowFrame, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
+ (NSRect)frameRectForContentRect:(NSRect)windowContentRect styleMask:(NSWindowStyleMask)windowStyle
|
|
||||||
{
|
|
||||||
kUnused(windowStyle);
|
|
||||||
return NSInsetRect(windowContentRect, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void)willClose
|
|
||||||
{
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
window_data->close = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void)windowDidResize:(NSNotification *)notification {
|
|
||||||
kUnused(notification);
|
|
||||||
if(window_data != 0x0) {
|
|
||||||
CGSize size = [self contentRectForFrameRect:[self frame]].size;
|
|
||||||
|
|
||||||
window_data->window_width = size.width;
|
|
||||||
window_data->window_height = size.height;
|
|
||||||
resize_dst(window_data, size.width, size.height);
|
|
||||||
|
|
||||||
kCall(resize_func, size.width, size.height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <MiniFB_enums.h>
|
|
||||||
#include <WindowData.h>
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
#include <MetalKit/MetalKit.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@class OSXWindow;
|
|
||||||
@class OSXViewDelegate;
|
|
||||||
|
|
||||||
typedef struct Vertex {
|
|
||||||
float x, y, z, w;
|
|
||||||
} Vertex;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
OSXWindow *window;
|
|
||||||
OSXViewDelegate *viewController;
|
|
||||||
struct mfb_timer *timer;
|
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
|
||||||
struct {
|
|
||||||
Vertex vertices[4];
|
|
||||||
} metal;
|
|
||||||
#endif
|
|
||||||
} SWindowData_OSX;
|
|
File diff suppressed because it is too large
Load Diff
@ -1,46 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <MiniFB_enums.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
struct wl_display;
|
|
||||||
struct wl_registry;
|
|
||||||
struct wl_compositor;
|
|
||||||
struct wl_shell;
|
|
||||||
struct wl_seat;
|
|
||||||
struct wl_keyboard;
|
|
||||||
struct wl_pointer;
|
|
||||||
struct wl_callback;
|
|
||||||
struct wl_shm;
|
|
||||||
struct wl_shm_pool;
|
|
||||||
struct wl_surface;
|
|
||||||
struct wl_shell_surface;
|
|
||||||
struct wl_buffer;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
struct wl_display *display;
|
|
||||||
struct wl_registry *registry;
|
|
||||||
struct wl_compositor *compositor;
|
|
||||||
struct wl_shell *shell;
|
|
||||||
struct wl_seat *seat;
|
|
||||||
struct wl_keyboard *keyboard;
|
|
||||||
|
|
||||||
struct wl_pointer *pointer;
|
|
||||||
struct wl_cursor_theme *cursor_theme;
|
|
||||||
struct wl_cursor *default_cursor;
|
|
||||||
struct wl_surface *cursor_surface;
|
|
||||||
|
|
||||||
struct wl_shm *shm;
|
|
||||||
struct wl_shm_pool *shm_pool;
|
|
||||||
struct wl_surface *surface;
|
|
||||||
struct wl_shell_surface *shell_surface;
|
|
||||||
|
|
||||||
uint32_t seat_version;
|
|
||||||
uint32_t shm_format;
|
|
||||||
uint32_t *shm_ptr;
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
struct mfb_timer *timer;
|
|
||||||
} SWindowData_Way;
|
|
@ -1,973 +0,0 @@
|
|||||||
#include <MiniFB.h>
|
|
||||||
#include <MiniFB_internal.h>
|
|
||||||
#include <WindowData.h>
|
|
||||||
#include "WindowData_Win.h"
|
|
||||||
#if defined(USE_OPENGL_API)
|
|
||||||
#include "gl/MiniFB_GL.h"
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Copied (and modified) from Windows Kit 10 to avoid setting _WIN32_WINNT to a higher version
|
|
||||||
typedef enum mfb_PROCESS_DPI_AWARENESS {
|
|
||||||
mfb_PROCESS_DPI_UNAWARE = 0,
|
|
||||||
mfb_PROCESS_SYSTEM_DPI_AWARE = 1,
|
|
||||||
mfb_PROCESS_PER_MONITOR_DPI_AWARE = 2
|
|
||||||
} mfb_PROCESS_DPI_AWARENESS;
|
|
||||||
|
|
||||||
typedef enum mfb_MONITOR_DPI_TYPE {
|
|
||||||
mfb_MDT_EFFECTIVE_DPI = 0,
|
|
||||||
mfb_MDT_ANGULAR_DPI = 1,
|
|
||||||
mfb_MDT_RAW_DPI = 2,
|
|
||||||
mfb_MDT_DEFAULT = mfb_MDT_EFFECTIVE_DPI
|
|
||||||
} mfb_MONITOR_DPI_TYPE;
|
|
||||||
|
|
||||||
#define mfb_DPI_AWARENESS_CONTEXT_UNAWARE ((HANDLE) -1)
|
|
||||||
#define mfb_DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((HANDLE) -2)
|
|
||||||
#define mfb_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((HANDLE) -3)
|
|
||||||
#define mfb_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4)
|
|
||||||
#define mfb_DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((HANDLE) -5)
|
|
||||||
|
|
||||||
// user32.dll
|
|
||||||
typedef BOOL(WINAPI *PFN_SetProcessDPIAware)(void);
|
|
||||||
typedef BOOL(WINAPI *PFN_SetProcessDpiAwarenessContext)(HANDLE);
|
|
||||||
typedef UINT(WINAPI *PFN_GetDpiForWindow)(HWND);
|
|
||||||
typedef BOOL(WINAPI *PFN_EnableNonClientDpiScaling)(HWND);
|
|
||||||
|
|
||||||
HMODULE mfb_user32_dll = 0x0;
|
|
||||||
PFN_SetProcessDPIAware mfb_SetProcessDPIAware = 0x0;
|
|
||||||
PFN_SetProcessDpiAwarenessContext mfb_SetProcessDpiAwarenessContext = 0x0;
|
|
||||||
PFN_GetDpiForWindow mfb_GetDpiForWindow = 0x0;
|
|
||||||
PFN_EnableNonClientDpiScaling mfb_EnableNonClientDpiScaling = 0x0;
|
|
||||||
|
|
||||||
// shcore.dll
|
|
||||||
typedef HRESULT(WINAPI *PFN_SetProcessDpiAwareness)(mfb_PROCESS_DPI_AWARENESS);
|
|
||||||
typedef HRESULT(WINAPI *PFN_GetDpiForMonitor)(HMONITOR, mfb_MONITOR_DPI_TYPE, UINT *, UINT *);
|
|
||||||
|
|
||||||
HMODULE mfb_shcore_dll = 0x0;
|
|
||||||
PFN_SetProcessDpiAwareness mfb_SetProcessDpiAwareness = 0x0;
|
|
||||||
PFN_GetDpiForMonitor mfb_GetDpiForMonitor = 0x0;
|
|
||||||
|
|
||||||
//--
|
|
||||||
void
|
|
||||||
load_functions() {
|
|
||||||
if(mfb_user32_dll == 0x0) {
|
|
||||||
mfb_user32_dll = LoadLibraryA("user32.dll");
|
|
||||||
if (mfb_user32_dll != 0x0) {
|
|
||||||
mfb_SetProcessDPIAware = (PFN_SetProcessDPIAware) GetProcAddress(mfb_user32_dll, "SetProcessDPIAware");
|
|
||||||
mfb_SetProcessDpiAwarenessContext = (PFN_SetProcessDpiAwarenessContext) GetProcAddress(mfb_user32_dll, "SetProcessDpiAwarenessContext");
|
|
||||||
mfb_GetDpiForWindow = (PFN_GetDpiForWindow) GetProcAddress(mfb_user32_dll, "GetDpiForWindow");
|
|
||||||
mfb_EnableNonClientDpiScaling = (PFN_EnableNonClientDpiScaling) GetProcAddress(mfb_user32_dll, "EnableNonClientDpiScaling");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mfb_shcore_dll == 0x0) {
|
|
||||||
mfb_shcore_dll = LoadLibraryA("shcore.dll");
|
|
||||||
if (mfb_shcore_dll != 0x0) {
|
|
||||||
mfb_SetProcessDpiAwareness = (PFN_SetProcessDpiAwareness) GetProcAddress(mfb_shcore_dll, "SetProcessDpiAwareness");
|
|
||||||
mfb_GetDpiForMonitor = (PFN_GetDpiForMonitor) GetProcAddress(mfb_shcore_dll, "GetDpiForMonitor");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--
|
|
||||||
// NOT Thread safe. Just convenient (Don't do this at home guys)
|
|
||||||
char *
|
|
||||||
GetErrorMessage() {
|
|
||||||
static char buffer[256];
|
|
||||||
|
|
||||||
buffer[0] = 0;
|
|
||||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
||||||
NULL, // Not used with FORMAT_MESSAGE_FROM_SYSTEM
|
|
||||||
GetLastError(),
|
|
||||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
||||||
buffer,
|
|
||||||
sizeof(buffer),
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--
|
|
||||||
void
|
|
||||||
dpi_aware() {
|
|
||||||
if (mfb_SetProcessDpiAwarenessContext != 0x0) {
|
|
||||||
if(mfb_SetProcessDpiAwarenessContext(mfb_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) == false) {
|
|
||||||
uint32_t error = GetLastError();
|
|
||||||
if(error == ERROR_INVALID_PARAMETER) {
|
|
||||||
error = NO_ERROR;
|
|
||||||
if(mfb_SetProcessDpiAwarenessContext(mfb_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE) == false) {
|
|
||||||
error = GetLastError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(error != NO_ERROR) {
|
|
||||||
fprintf(stderr, "Error (SetProcessDpiAwarenessContext): %s\n", GetErrorMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (mfb_SetProcessDpiAwareness != 0x0) {
|
|
||||||
if(mfb_SetProcessDpiAwareness(mfb_PROCESS_PER_MONITOR_DPI_AWARE) != S_OK) {
|
|
||||||
fprintf(stderr, "Error (SetProcessDpiAwareness): %s\n", GetErrorMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (mfb_SetProcessDPIAware != 0x0) {
|
|
||||||
if(mfb_SetProcessDPIAware() == false) {
|
|
||||||
fprintf(stderr, "Error (SetProcessDPIAware): %s\n", GetErrorMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--
|
|
||||||
void
|
|
||||||
get_monitor_scale(HWND hWnd, float *scale_x, float *scale_y) {
|
|
||||||
UINT x, y;
|
|
||||||
|
|
||||||
if(mfb_GetDpiForMonitor != 0x0) {
|
|
||||||
HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
|
|
||||||
mfb_GetDpiForMonitor(monitor, mfb_MDT_EFFECTIVE_DPI, &x, &y);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const HDC dc = GetDC(hWnd);
|
|
||||||
x = GetDeviceCaps(dc, LOGPIXELSX);
|
|
||||||
y = GetDeviceCaps(dc, LOGPIXELSY);
|
|
||||||
ReleaseDC(NULL, dc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale_x) {
|
|
||||||
*scale_x = x / (float) USER_DEFAULT_SCREEN_DPI;
|
|
||||||
if(*scale_x == 0) {
|
|
||||||
*scale_x = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale_y) {
|
|
||||||
*scale_y = y / (float) USER_DEFAULT_SCREEN_DPI;
|
|
||||||
if (*scale_y == 0) {
|
|
||||||
*scale_y = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void
|
|
||||||
mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y) {
|
|
||||||
HWND hWnd = 0x0;
|
|
||||||
|
|
||||||
if(window != 0x0) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
|
||||||
hWnd = window_data_win->window;
|
|
||||||
}
|
|
||||||
get_monitor_scale(hWnd, scale_x, scale_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
long s_window_style = WS_POPUP | WS_SYSMENU | WS_CAPTION;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void init_keycodes();
|
|
||||||
|
|
||||||
uint32_t translate_mod();
|
|
||||||
mfb_key translate_key(unsigned int wParam, unsigned long lParam);
|
|
||||||
void destroy_window_data(SWindowData *window_data);
|
|
||||||
|
|
||||||
LRESULT CALLBACK
|
|
||||||
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
||||||
LRESULT res = 0;
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
||||||
SWindowData_Win *window_data_win = 0x0;
|
|
||||||
if (window_data != 0x0) {
|
|
||||||
window_data_win = (SWindowData_Win *) window_data->specific;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (message)
|
|
||||||
{
|
|
||||||
case WM_NCCREATE:
|
|
||||||
{
|
|
||||||
if(mfb_EnableNonClientDpiScaling)
|
|
||||||
mfb_EnableNonClientDpiScaling(hWnd);
|
|
||||||
|
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
//case 0x02E4://WM_GETDPISCALEDSIZE:
|
|
||||||
//{
|
|
||||||
// SIZE* size = (SIZE*) lParam;
|
|
||||||
// WORD dpi = LOWORD(wParam);
|
|
||||||
// return true;
|
|
||||||
// break;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
//case WM_DPICHANGED:
|
|
||||||
//{
|
|
||||||
// const float xscale = HIWORD(wParam);
|
|
||||||
// const float yscale = LOWORD(wParam);
|
|
||||||
// break;
|
|
||||||
//}
|
|
||||||
|
|
||||||
#if !defined(USE_OPENGL_API)
|
|
||||||
case WM_PAINT:
|
|
||||||
{
|
|
||||||
if (window_data && window_data->draw_buffer && window_data_win) {
|
|
||||||
StretchDIBits(window_data_win->hdc, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->draw_buffer,
|
|
||||||
window_data_win->bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
|
|
||||||
}
|
|
||||||
ValidateRect(hWnd, 0x0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case WM_DESTROY:
|
|
||||||
case WM_CLOSE:
|
|
||||||
{
|
|
||||||
if (window_data) {
|
|
||||||
window_data->close = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_KEYDOWN:
|
|
||||||
case WM_SYSKEYDOWN:
|
|
||||||
case WM_KEYUP:
|
|
||||||
case WM_SYSKEYUP:
|
|
||||||
{
|
|
||||||
if (window_data) {
|
|
||||||
mfb_key key_code = translate_key((unsigned int)wParam, (unsigned long)lParam);
|
|
||||||
int is_pressed = !((lParam >> 31) & 1);
|
|
||||||
window_data->mod_keys = translate_mod();
|
|
||||||
|
|
||||||
if (key_code == KB_KEY_UNKNOWN)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
window_data->key_status[key_code] = (uint8_t) is_pressed;
|
|
||||||
kCall(keyboard_func, key_code, window_data->mod_keys, is_pressed);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_CHAR:
|
|
||||||
case WM_SYSCHAR:
|
|
||||||
case WM_UNICHAR:
|
|
||||||
{
|
|
||||||
|
|
||||||
if (window_data) {
|
|
||||||
if (message == WM_UNICHAR && wParam == UNICODE_NOCHAR) {
|
|
||||||
// WM_UNICHAR is not sent by Windows, but is sent by some third-party input method engine
|
|
||||||
// Returning TRUE here announces support for this message
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
kCall(char_input_func, (unsigned int) wParam);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_LBUTTONUP:
|
|
||||||
case WM_RBUTTONUP:
|
|
||||||
case WM_MBUTTONUP:
|
|
||||||
case WM_XBUTTONUP:
|
|
||||||
case WM_LBUTTONDOWN:
|
|
||||||
case WM_LBUTTONDBLCLK:
|
|
||||||
case WM_RBUTTONDOWN:
|
|
||||||
case WM_RBUTTONDBLCLK:
|
|
||||||
case WM_MBUTTONDOWN:
|
|
||||||
case WM_MBUTTONDBLCLK:
|
|
||||||
case WM_XBUTTONDOWN:
|
|
||||||
case WM_XBUTTONDBLCLK:
|
|
||||||
{
|
|
||||||
if (window_data) {
|
|
||||||
mfb_mouse_button button = MOUSE_BTN_0;
|
|
||||||
window_data->mod_keys = translate_mod();
|
|
||||||
int is_pressed = 0;
|
|
||||||
switch(message) {
|
|
||||||
case WM_LBUTTONDOWN:
|
|
||||||
is_pressed = 1;
|
|
||||||
case WM_LBUTTONUP:
|
|
||||||
button = MOUSE_BTN_1;
|
|
||||||
break;
|
|
||||||
case WM_RBUTTONDOWN:
|
|
||||||
is_pressed = 1;
|
|
||||||
case WM_RBUTTONUP:
|
|
||||||
button = MOUSE_BTN_2;
|
|
||||||
break;
|
|
||||||
case WM_MBUTTONDOWN:
|
|
||||||
is_pressed = 1;
|
|
||||||
case WM_MBUTTONUP:
|
|
||||||
button = MOUSE_BTN_3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? MOUSE_BTN_5 : MOUSE_BTN_6);
|
|
||||||
if (message == WM_XBUTTONDOWN) {
|
|
||||||
is_pressed = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window_data->mouse_button_status[button & 0x07] = is_pressed;
|
|
||||||
kCall(mouse_btn_func, button, window_data->mod_keys, is_pressed);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_MOUSEWHEEL:
|
|
||||||
if (window_data) {
|
|
||||||
window_data->mouse_wheel_y = (SHORT)HIWORD(wParam) / (float)WHEEL_DELTA;
|
|
||||||
kCall(mouse_wheel_func, translate_mod(), 0.0f, window_data->mouse_wheel_y);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_MOUSEHWHEEL:
|
|
||||||
// This message is only sent on Windows Vista and later
|
|
||||||
// NOTE: The X-axis is inverted for consistency with macOS and X11
|
|
||||||
if (window_data) {
|
|
||||||
window_data->mouse_wheel_x = -((SHORT)HIWORD(wParam) / (float)WHEEL_DELTA);
|
|
||||||
kCall(mouse_wheel_func, translate_mod(), window_data->mouse_wheel_x, 0.0f);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_MOUSEMOVE:
|
|
||||||
if (window_data) {
|
|
||||||
if (window_data_win->mouse_inside == false) {
|
|
||||||
window_data_win->mouse_inside = true;
|
|
||||||
TRACKMOUSEEVENT tme;
|
|
||||||
ZeroMemory(&tme, sizeof(tme));
|
|
||||||
tme.cbSize = sizeof(tme);
|
|
||||||
tme.dwFlags = TME_LEAVE;
|
|
||||||
tme.hwndTrack = hWnd;
|
|
||||||
TrackMouseEvent(&tme);
|
|
||||||
}
|
|
||||||
window_data->mouse_pos_x = (int)(short) LOWORD(lParam);
|
|
||||||
window_data->mouse_pos_y = (int)(short) HIWORD(lParam);
|
|
||||||
kCall(mouse_move_func, window_data->mouse_pos_x, window_data->mouse_pos_y);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_MOUSELEAVE:
|
|
||||||
if (window_data) {
|
|
||||||
window_data_win->mouse_inside = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_SIZE:
|
|
||||||
if (window_data) {
|
|
||||||
float scale_x, scale_y;
|
|
||||||
uint32_t width, height;
|
|
||||||
|
|
||||||
if(wParam == SIZE_MINIMIZED) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_monitor_scale(hWnd, &scale_x, &scale_y);
|
|
||||||
window_data->window_width = LOWORD(lParam);
|
|
||||||
window_data->window_height = HIWORD(lParam);
|
|
||||||
resize_dst(window_data, window_data->window_width, window_data->window_height);
|
|
||||||
|
|
||||||
#if !defined(USE_OPENGL_API)
|
|
||||||
BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->window_height, 0, 0, 0, BLACKNESS);
|
|
||||||
#else
|
|
||||||
resize_GL(window_data);
|
|
||||||
#endif
|
|
||||||
if(window_data->window_width != 0 && window_data->window_height != 0) {
|
|
||||||
width = (uint32_t) (window_data->window_width / scale_x);
|
|
||||||
height = (uint32_t) (window_data->window_height / scale_y);
|
|
||||||
kCall(resize_func, width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_SETFOCUS:
|
|
||||||
if (window_data) {
|
|
||||||
window_data->is_active = true;
|
|
||||||
kCall(active_func, true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_KILLFOCUS:
|
|
||||||
if (window_data) {
|
|
||||||
window_data->is_active = false;
|
|
||||||
kCall(active_func, false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
res = DefWindowProc(hWnd, message, wParam, lParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct mfb_window *
|
|
||||||
mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) {
|
|
||||||
RECT rect = { 0 };
|
|
||||||
int x = 0, y = 0;
|
|
||||||
|
|
||||||
load_functions();
|
|
||||||
dpi_aware();
|
|
||||||
init_keycodes();
|
|
||||||
|
|
||||||
SWindowData *window_data = malloc(sizeof(SWindowData));
|
|
||||||
if (window_data == 0x0) {
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
memset(window_data, 0, sizeof(SWindowData));
|
|
||||||
|
|
||||||
SWindowData_Win *window_data_win = malloc(sizeof(SWindowData_Win));
|
|
||||||
if(window_data_win == 0x0) {
|
|
||||||
free(window_data);
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
memset(window_data_win, 0, sizeof(SWindowData_Win));
|
|
||||||
window_data->specific = window_data_win;
|
|
||||||
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
|
|
||||||
s_window_style = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME;
|
|
||||||
if (flags & WF_FULLSCREEN) {
|
|
||||||
flags = WF_FULLSCREEN; // Remove all other flags
|
|
||||||
rect.right = GetSystemMetrics(SM_CXSCREEN);
|
|
||||||
rect.bottom = GetSystemMetrics(SM_CYSCREEN);
|
|
||||||
s_window_style = WS_POPUP & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
|
|
||||||
|
|
||||||
DEVMODE settings = { 0 };
|
|
||||||
EnumDisplaySettings(0, 0, &settings);
|
|
||||||
settings.dmPelsWidth = GetSystemMetrics(SM_CXSCREEN);
|
|
||||||
settings.dmPelsHeight = GetSystemMetrics(SM_CYSCREEN);
|
|
||||||
settings.dmBitsPerPel = 32;
|
|
||||||
settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
|
|
||||||
|
|
||||||
if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
|
|
||||||
flags = WF_FULLSCREEN_DESKTOP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & WF_BORDERLESS) {
|
|
||||||
s_window_style = WS_POPUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & WF_RESIZABLE) {
|
|
||||||
s_window_style |= WS_MAXIMIZEBOX | WS_SIZEBOX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & WF_FULLSCREEN_DESKTOP) {
|
|
||||||
s_window_style = WS_OVERLAPPEDWINDOW;
|
|
||||||
|
|
||||||
width = GetSystemMetrics(SM_CXFULLSCREEN);
|
|
||||||
height = GetSystemMetrics(SM_CYFULLSCREEN);
|
|
||||||
|
|
||||||
rect.right = width;
|
|
||||||
rect.bottom = height;
|
|
||||||
AdjustWindowRect(&rect, s_window_style, 0);
|
|
||||||
if (rect.left < 0) {
|
|
||||||
width += rect.left * 2;
|
|
||||||
rect.right += rect.left;
|
|
||||||
rect.left = 0;
|
|
||||||
}
|
|
||||||
if (rect.bottom > (LONG) height) {
|
|
||||||
height -= (rect.bottom - height);
|
|
||||||
rect.bottom += (rect.bottom - height);
|
|
||||||
rect.top = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!(flags & WF_FULLSCREEN)) {
|
|
||||||
float scale_x, scale_y;
|
|
||||||
|
|
||||||
get_monitor_scale(0, &scale_x, &scale_y);
|
|
||||||
|
|
||||||
rect.right = (LONG) (width * scale_x);
|
|
||||||
rect.bottom = (LONG) (height * scale_y);
|
|
||||||
|
|
||||||
AdjustWindowRect(&rect, s_window_style, 0);
|
|
||||||
|
|
||||||
rect.right -= rect.left;
|
|
||||||
rect.bottom -= rect.top;
|
|
||||||
|
|
||||||
x = (GetSystemMetrics(SM_CXSCREEN) - rect.right) / 2;
|
|
||||||
y = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom + rect.top) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data_win->wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
|
|
||||||
window_data_win->wc.lpfnWndProc = WndProc;
|
|
||||||
window_data_win->wc.hCursor = LoadCursor(0, IDC_ARROW);
|
|
||||||
window_data_win->wc.lpszClassName = title;
|
|
||||||
RegisterClass(&window_data_win->wc);
|
|
||||||
|
|
||||||
calc_dst_factor(window_data, width, height);
|
|
||||||
|
|
||||||
window_data->window_width = rect.right;
|
|
||||||
window_data->window_height = rect.bottom;
|
|
||||||
|
|
||||||
window_data_win->window = CreateWindowEx(
|
|
||||||
0,
|
|
||||||
title, title,
|
|
||||||
s_window_style,
|
|
||||||
x, y,
|
|
||||||
window_data->window_width, window_data->window_height,
|
|
||||||
0, 0, 0, 0);
|
|
||||||
|
|
||||||
if (!window_data_win->window) {
|
|
||||||
free(window_data);
|
|
||||||
free(window_data_win);
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetWindowLongPtr(window_data_win->window, GWLP_USERDATA, (LONG_PTR) window_data);
|
|
||||||
|
|
||||||
if (flags & WF_ALWAYS_ON_TOP)
|
|
||||||
SetWindowPos(window_data_win->window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
||||||
|
|
||||||
ShowWindow(window_data_win->window, SW_NORMAL);
|
|
||||||
|
|
||||||
window_data_win->hdc = GetDC(window_data_win->window);
|
|
||||||
|
|
||||||
#if !defined(USE_OPENGL_API)
|
|
||||||
|
|
||||||
window_data_win->bitmapInfo = (BITMAPINFO *) calloc(1, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 3);
|
|
||||||
if(window_data_win->bitmapInfo == 0x0) {
|
|
||||||
free(window_data);
|
|
||||||
free(window_data_win);
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data_win->bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
||||||
window_data_win->bitmapInfo->bmiHeader.biPlanes = 1;
|
|
||||||
window_data_win->bitmapInfo->bmiHeader.biBitCount = 32;
|
|
||||||
window_data_win->bitmapInfo->bmiHeader.biCompression = BI_BITFIELDS;
|
|
||||||
window_data_win->bitmapInfo->bmiHeader.biWidth = window_data->buffer_width;
|
|
||||||
window_data_win->bitmapInfo->bmiHeader.biHeight = -(LONG)window_data->buffer_height;
|
|
||||||
window_data_win->bitmapInfo->bmiColors[0].rgbRed = 0xff;
|
|
||||||
window_data_win->bitmapInfo->bmiColors[1].rgbGreen = 0xff;
|
|
||||||
window_data_win->bitmapInfo->bmiColors[2].rgbBlue = 0xff;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
create_GL_context(window_data);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
window_data_win->timer = mfb_timer_create();
|
|
||||||
|
|
||||||
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUG)
|
|
||||||
#if defined(USE_OPENGL_API)
|
|
||||||
printf("Window created using OpenGL API\n");
|
|
||||||
#else
|
|
||||||
printf("Window created using GDI API\n");
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
window_data->is_initialized = true;
|
|
||||||
return (struct mfb_window *) window_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
mfb_update_state
|
|
||||||
mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned height) {
|
|
||||||
MSG msg;
|
|
||||||
|
|
||||||
if (window == 0x0) {
|
|
||||||
return STATE_INVALID_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
if (window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return STATE_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer == 0x0) {
|
|
||||||
return STATE_INVALID_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data->draw_buffer = buffer;
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
|
|
||||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
|
||||||
|
|
||||||
#if !defined(USE_OPENGL_API)
|
|
||||||
|
|
||||||
window_data_win->bitmapInfo->bmiHeader.biWidth = window_data->buffer_width;
|
|
||||||
window_data_win->bitmapInfo->bmiHeader.biHeight = -(LONG) window_data->buffer_height;
|
|
||||||
InvalidateRect(window_data_win->window, 0x0, TRUE);
|
|
||||||
SendMessage(window_data_win->window, WM_PAINT, 0, 0);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
redraw_GL(window_data, buffer);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) {
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
mfb_update_state
|
|
||||||
mfb_update_events(struct mfb_window *window) {
|
|
||||||
MSG msg;
|
|
||||||
|
|
||||||
if (window == 0x0) {
|
|
||||||
return STATE_INVALID_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *)window;
|
|
||||||
if (window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return STATE_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
|
||||||
while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) {
|
|
||||||
//if(msg.message == WM_PAINT)
|
|
||||||
// return STATE_OK;
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
extern double g_time_for_frame;
|
|
||||||
extern bool g_use_hardware_sync;
|
|
||||||
|
|
||||||
bool
|
|
||||||
mfb_wait_sync(struct mfb_window *window) {
|
|
||||||
if (window == 0x0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *)window;
|
|
||||||
if (window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(g_use_hardware_sync) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MSG msg;
|
|
||||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
|
||||||
double current;
|
|
||||||
uint32_t millis = 1;
|
|
||||||
while (1) {
|
|
||||||
current = mfb_timer_now(window_data_win->timer);
|
|
||||||
if (current >= g_time_for_frame * 0.96) {
|
|
||||||
mfb_timer_reset(window_data_win->timer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if(current >= g_time_for_frame * 0.8) {
|
|
||||||
millis = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sleep(millis);
|
|
||||||
|
|
||||||
if(millis == 1 && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) {
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
|
|
||||||
if (window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void
|
|
||||||
destroy_window_data(SWindowData *window_data) {
|
|
||||||
if (window_data == 0x0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
|
||||||
|
|
||||||
#if !defined(USE_OPENGL_API)
|
|
||||||
if (window_data_win->bitmapInfo != 0x0) {
|
|
||||||
free(window_data_win->bitmapInfo);
|
|
||||||
window_data_win->bitmapInfo = 0x0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
destroy_GL_context(window_data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (window_data_win->window != 0 && window_data_win->hdc != 0) {
|
|
||||||
ReleaseDC(window_data_win->window, window_data_win->hdc);
|
|
||||||
DestroyWindow(window_data_win->window);
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data_win->window = 0;
|
|
||||||
window_data_win->hdc = 0;
|
|
||||||
|
|
||||||
mfb_timer_destroy(window_data_win->timer);
|
|
||||||
window_data_win->timer = 0x0;
|
|
||||||
|
|
||||||
window_data->draw_buffer = 0x0;
|
|
||||||
window_data->close = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
translate_mod() {
|
|
||||||
uint32_t mods = 0;
|
|
||||||
|
|
||||||
if (GetKeyState(VK_SHIFT) & 0x8000)
|
|
||||||
mods |= KB_MOD_SHIFT;
|
|
||||||
if (GetKeyState(VK_CONTROL) & 0x8000)
|
|
||||||
mods |= KB_MOD_CONTROL;
|
|
||||||
if (GetKeyState(VK_MENU) & 0x8000)
|
|
||||||
mods |= KB_MOD_ALT;
|
|
||||||
if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000)
|
|
||||||
mods |= KB_MOD_SUPER;
|
|
||||||
if (GetKeyState(VK_CAPITAL) & 1)
|
|
||||||
mods |= KB_MOD_CAPS_LOCK;
|
|
||||||
if (GetKeyState(VK_NUMLOCK) & 1)
|
|
||||||
mods |= KB_MOD_NUM_LOCK;
|
|
||||||
|
|
||||||
return mods;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
extern short int g_keycodes[512];
|
|
||||||
|
|
||||||
void
|
|
||||||
init_keycodes() {
|
|
||||||
if(g_keycodes[0x00B] != KB_KEY_0) {
|
|
||||||
g_keycodes[0x00B] = KB_KEY_0;
|
|
||||||
g_keycodes[0x002] = KB_KEY_1;
|
|
||||||
g_keycodes[0x003] = KB_KEY_2;
|
|
||||||
g_keycodes[0x004] = KB_KEY_3;
|
|
||||||
g_keycodes[0x005] = KB_KEY_4;
|
|
||||||
g_keycodes[0x006] = KB_KEY_5;
|
|
||||||
g_keycodes[0x007] = KB_KEY_6;
|
|
||||||
g_keycodes[0x008] = KB_KEY_7;
|
|
||||||
g_keycodes[0x009] = KB_KEY_8;
|
|
||||||
g_keycodes[0x00A] = KB_KEY_9;
|
|
||||||
g_keycodes[0x01E] = KB_KEY_A;
|
|
||||||
g_keycodes[0x030] = KB_KEY_B;
|
|
||||||
g_keycodes[0x02E] = KB_KEY_C;
|
|
||||||
g_keycodes[0x020] = KB_KEY_D;
|
|
||||||
g_keycodes[0x012] = KB_KEY_E;
|
|
||||||
g_keycodes[0x021] = KB_KEY_F;
|
|
||||||
g_keycodes[0x022] = KB_KEY_G;
|
|
||||||
g_keycodes[0x023] = KB_KEY_H;
|
|
||||||
g_keycodes[0x017] = KB_KEY_I;
|
|
||||||
g_keycodes[0x024] = KB_KEY_J;
|
|
||||||
g_keycodes[0x025] = KB_KEY_K;
|
|
||||||
g_keycodes[0x026] = KB_KEY_L;
|
|
||||||
g_keycodes[0x032] = KB_KEY_M;
|
|
||||||
g_keycodes[0x031] = KB_KEY_N;
|
|
||||||
g_keycodes[0x018] = KB_KEY_O;
|
|
||||||
g_keycodes[0x019] = KB_KEY_P;
|
|
||||||
g_keycodes[0x010] = KB_KEY_Q;
|
|
||||||
g_keycodes[0x013] = KB_KEY_R;
|
|
||||||
g_keycodes[0x01F] = KB_KEY_S;
|
|
||||||
g_keycodes[0x014] = KB_KEY_T;
|
|
||||||
g_keycodes[0x016] = KB_KEY_U;
|
|
||||||
g_keycodes[0x02F] = KB_KEY_V;
|
|
||||||
g_keycodes[0x011] = KB_KEY_W;
|
|
||||||
g_keycodes[0x02D] = KB_KEY_X;
|
|
||||||
g_keycodes[0x015] = KB_KEY_Y;
|
|
||||||
g_keycodes[0x02C] = KB_KEY_Z;
|
|
||||||
|
|
||||||
g_keycodes[0x028] = KB_KEY_APOSTROPHE;
|
|
||||||
g_keycodes[0x02B] = KB_KEY_BACKSLASH;
|
|
||||||
g_keycodes[0x033] = KB_KEY_COMMA;
|
|
||||||
g_keycodes[0x00D] = KB_KEY_EQUAL;
|
|
||||||
g_keycodes[0x029] = KB_KEY_GRAVE_ACCENT;
|
|
||||||
g_keycodes[0x01A] = KB_KEY_LEFT_BRACKET;
|
|
||||||
g_keycodes[0x00C] = KB_KEY_MINUS;
|
|
||||||
g_keycodes[0x034] = KB_KEY_PERIOD;
|
|
||||||
g_keycodes[0x01B] = KB_KEY_RIGHT_BRACKET;
|
|
||||||
g_keycodes[0x027] = KB_KEY_SEMICOLON;
|
|
||||||
g_keycodes[0x035] = KB_KEY_SLASH;
|
|
||||||
g_keycodes[0x056] = KB_KEY_WORLD_2;
|
|
||||||
|
|
||||||
g_keycodes[0x00E] = KB_KEY_BACKSPACE;
|
|
||||||
g_keycodes[0x153] = KB_KEY_DELETE;
|
|
||||||
g_keycodes[0x14F] = KB_KEY_END;
|
|
||||||
g_keycodes[0x01C] = KB_KEY_ENTER;
|
|
||||||
g_keycodes[0x001] = KB_KEY_ESCAPE;
|
|
||||||
g_keycodes[0x147] = KB_KEY_HOME;
|
|
||||||
g_keycodes[0x152] = KB_KEY_INSERT;
|
|
||||||
g_keycodes[0x15D] = KB_KEY_MENU;
|
|
||||||
g_keycodes[0x151] = KB_KEY_PAGE_DOWN;
|
|
||||||
g_keycodes[0x149] = KB_KEY_PAGE_UP;
|
|
||||||
g_keycodes[0x045] = KB_KEY_PAUSE;
|
|
||||||
g_keycodes[0x146] = KB_KEY_PAUSE;
|
|
||||||
g_keycodes[0x039] = KB_KEY_SPACE;
|
|
||||||
g_keycodes[0x00F] = KB_KEY_TAB;
|
|
||||||
g_keycodes[0x03A] = KB_KEY_CAPS_LOCK;
|
|
||||||
g_keycodes[0x145] = KB_KEY_NUM_LOCK;
|
|
||||||
g_keycodes[0x046] = KB_KEY_SCROLL_LOCK;
|
|
||||||
g_keycodes[0x03B] = KB_KEY_F1;
|
|
||||||
g_keycodes[0x03C] = KB_KEY_F2;
|
|
||||||
g_keycodes[0x03D] = KB_KEY_F3;
|
|
||||||
g_keycodes[0x03E] = KB_KEY_F4;
|
|
||||||
g_keycodes[0x03F] = KB_KEY_F5;
|
|
||||||
g_keycodes[0x040] = KB_KEY_F6;
|
|
||||||
g_keycodes[0x041] = KB_KEY_F7;
|
|
||||||
g_keycodes[0x042] = KB_KEY_F8;
|
|
||||||
g_keycodes[0x043] = KB_KEY_F9;
|
|
||||||
g_keycodes[0x044] = KB_KEY_F10;
|
|
||||||
g_keycodes[0x057] = KB_KEY_F11;
|
|
||||||
g_keycodes[0x058] = KB_KEY_F12;
|
|
||||||
g_keycodes[0x064] = KB_KEY_F13;
|
|
||||||
g_keycodes[0x065] = KB_KEY_F14;
|
|
||||||
g_keycodes[0x066] = KB_KEY_F15;
|
|
||||||
g_keycodes[0x067] = KB_KEY_F16;
|
|
||||||
g_keycodes[0x068] = KB_KEY_F17;
|
|
||||||
g_keycodes[0x069] = KB_KEY_F18;
|
|
||||||
g_keycodes[0x06A] = KB_KEY_F19;
|
|
||||||
g_keycodes[0x06B] = KB_KEY_F20;
|
|
||||||
g_keycodes[0x06C] = KB_KEY_F21;
|
|
||||||
g_keycodes[0x06D] = KB_KEY_F22;
|
|
||||||
g_keycodes[0x06E] = KB_KEY_F23;
|
|
||||||
g_keycodes[0x076] = KB_KEY_F24;
|
|
||||||
g_keycodes[0x038] = KB_KEY_LEFT_ALT;
|
|
||||||
g_keycodes[0x01D] = KB_KEY_LEFT_CONTROL;
|
|
||||||
g_keycodes[0x02A] = KB_KEY_LEFT_SHIFT;
|
|
||||||
g_keycodes[0x15B] = KB_KEY_LEFT_SUPER;
|
|
||||||
g_keycodes[0x137] = KB_KEY_PRINT_SCREEN;
|
|
||||||
g_keycodes[0x138] = KB_KEY_RIGHT_ALT;
|
|
||||||
g_keycodes[0x11D] = KB_KEY_RIGHT_CONTROL;
|
|
||||||
g_keycodes[0x036] = KB_KEY_RIGHT_SHIFT;
|
|
||||||
g_keycodes[0x15C] = KB_KEY_RIGHT_SUPER;
|
|
||||||
g_keycodes[0x150] = KB_KEY_DOWN;
|
|
||||||
g_keycodes[0x14B] = KB_KEY_LEFT;
|
|
||||||
g_keycodes[0x14D] = KB_KEY_RIGHT;
|
|
||||||
g_keycodes[0x148] = KB_KEY_UP;
|
|
||||||
|
|
||||||
g_keycodes[0x052] = KB_KEY_KP_0;
|
|
||||||
g_keycodes[0x04F] = KB_KEY_KP_1;
|
|
||||||
g_keycodes[0x050] = KB_KEY_KP_2;
|
|
||||||
g_keycodes[0x051] = KB_KEY_KP_3;
|
|
||||||
g_keycodes[0x04B] = KB_KEY_KP_4;
|
|
||||||
g_keycodes[0x04C] = KB_KEY_KP_5;
|
|
||||||
g_keycodes[0x04D] = KB_KEY_KP_6;
|
|
||||||
g_keycodes[0x047] = KB_KEY_KP_7;
|
|
||||||
g_keycodes[0x048] = KB_KEY_KP_8;
|
|
||||||
g_keycodes[0x049] = KB_KEY_KP_9;
|
|
||||||
g_keycodes[0x04E] = KB_KEY_KP_ADD;
|
|
||||||
g_keycodes[0x053] = KB_KEY_KP_DECIMAL;
|
|
||||||
g_keycodes[0x135] = KB_KEY_KP_DIVIDE;
|
|
||||||
g_keycodes[0x11C] = KB_KEY_KP_ENTER;
|
|
||||||
g_keycodes[0x037] = KB_KEY_KP_MULTIPLY;
|
|
||||||
g_keycodes[0x04A] = KB_KEY_KP_SUBTRACT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
mfb_key
|
|
||||||
translate_key(unsigned int wParam, unsigned long lParam) {
|
|
||||||
if (wParam == VK_CONTROL) {
|
|
||||||
MSG next;
|
|
||||||
DWORD time;
|
|
||||||
|
|
||||||
if (lParam & 0x01000000)
|
|
||||||
return KB_KEY_RIGHT_CONTROL;
|
|
||||||
|
|
||||||
time = GetMessageTime();
|
|
||||||
if (PeekMessageW(&next, 0x0, 0, 0, PM_NOREMOVE))
|
|
||||||
if (next.message == WM_KEYDOWN || next.message == WM_SYSKEYDOWN || next.message == WM_KEYUP || next.message == WM_SYSKEYUP)
|
|
||||||
if (next.wParam == VK_MENU && (next.lParam & 0x01000000) && next.time == time)
|
|
||||||
return KB_KEY_UNKNOWN;
|
|
||||||
|
|
||||||
return KB_KEY_LEFT_CONTROL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wParam == VK_PROCESSKEY)
|
|
||||||
return KB_KEY_UNKNOWN;
|
|
||||||
|
|
||||||
return (mfb_key) g_keycodes[HIWORD(lParam) & 0x1FF];
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool
|
|
||||||
mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
SWindowData_Win *window_data_win = 0x0;
|
|
||||||
float scale_x, scale_y;
|
|
||||||
|
|
||||||
if(window_data == 0x0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset_x + width > window_data->window_width) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (offset_y + height > window_data->window_height) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data_win = (SWindowData_Win *) window_data->specific;
|
|
||||||
|
|
||||||
get_monitor_scale(window_data_win->window, &scale_x, &scale_y);
|
|
||||||
window_data->dst_offset_x = (uint32_t) (offset_x * scale_x);
|
|
||||||
window_data->dst_offset_y = (uint32_t) (offset_y * scale_y);
|
|
||||||
|
|
||||||
window_data->dst_width = (uint32_t) (width * scale_x);
|
|
||||||
window_data->dst_height = (uint32_t) (height * scale_y);
|
|
||||||
|
|
||||||
calc_dst_factor(window_data, window_data->window_width, window_data->window_height);
|
|
||||||
|
|
||||||
#if !defined(USE_OPENGL_API)
|
|
||||||
window_data_win = (SWindowData_Win *) window_data->specific;
|
|
||||||
BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->window_height, 0, 0, 0, BLACKNESS);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
extern double g_timer_frequency;
|
|
||||||
extern double g_timer_resolution;
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
mfb_timer_tick() {
|
|
||||||
int64_t counter;
|
|
||||||
|
|
||||||
QueryPerformanceCounter((LARGE_INTEGER *) &counter);
|
|
||||||
|
|
||||||
return counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
mfb_timer_init() {
|
|
||||||
uint64_t frequency;
|
|
||||||
|
|
||||||
QueryPerformanceFrequency((LARGE_INTEGER *) &frequency);
|
|
||||||
|
|
||||||
g_timer_frequency = (double) ((int64_t) frequency);
|
|
||||||
g_timer_resolution = 1.0 / g_timer_frequency;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <MiniFB_enums.h>
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
HWND window;
|
|
||||||
WNDCLASS wc;
|
|
||||||
HDC hdc;
|
|
||||||
#if defined(USE_OPENGL_API)
|
|
||||||
HGLRC hGLRC;
|
|
||||||
uint32_t text_id;
|
|
||||||
#else
|
|
||||||
BITMAPINFO *bitmapInfo;
|
|
||||||
#endif
|
|
||||||
struct mfb_timer *timer;
|
|
||||||
bool mouse_inside;
|
|
||||||
} SWindowData_Win;
|
|
@ -1,28 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <MiniFB_enums.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#if defined(USE_OPENGL_API)
|
|
||||||
#include <GL/glx.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Window window;
|
|
||||||
|
|
||||||
Display *display;
|
|
||||||
int screen;
|
|
||||||
GC gc;
|
|
||||||
#if defined(USE_OPENGL_API)
|
|
||||||
GLXContext context;
|
|
||||||
uint32_t text_id;
|
|
||||||
#else
|
|
||||||
XImage *image;
|
|
||||||
void *image_buffer;
|
|
||||||
XImage *image_scaler;
|
|
||||||
uint32_t image_scaler_width;
|
|
||||||
uint32_t image_scaler_height;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct mfb_timer *timer;
|
|
||||||
} SWindowData_X11;
|
|
@ -1,865 +0,0 @@
|
|||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
#include <X11/XKBlib.h>
|
|
||||||
#include <X11/keysym.h>
|
|
||||||
#include <X11/Xatom.h>
|
|
||||||
#include <X11/cursorfont.h>
|
|
||||||
|
|
||||||
// I cannot find a way to get dpi under VirtualBox
|
|
||||||
//#include <X11/Xresource.h>
|
|
||||||
//#include <X11/extensions/Xrandr.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <MiniFB.h>
|
|
||||||
#include <MiniFB_internal.h>
|
|
||||||
#include "WindowData.h"
|
|
||||||
#include "WindowData_X11.h"
|
|
||||||
|
|
||||||
#if defined(USE_OPENGL_API)
|
|
||||||
#include <gl/MiniFB_GL.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static Atom s_delete_window_atom;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void init_keycodes(SWindowData_X11 *window_data_x11);
|
|
||||||
|
|
||||||
extern void
|
|
||||||
stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch,
|
|
||||||
uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct mfb_window *
|
|
||||||
mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) {
|
|
||||||
int depth, i, formatCount, convDepth = -1;
|
|
||||||
XPixmapFormatValues* formats;
|
|
||||||
XSetWindowAttributes windowAttributes;
|
|
||||||
XSizeHints sizeHints;
|
|
||||||
Visual* visual;
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) malloc(sizeof(SWindowData));
|
|
||||||
if (!window_data) {
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
memset(window_data, 0, sizeof(SWindowData));
|
|
||||||
|
|
||||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) malloc(sizeof(SWindowData_X11));
|
|
||||||
if (!window_data_x11) {
|
|
||||||
free(window_data);
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
memset(window_data_x11, 0, sizeof(SWindowData_X11));
|
|
||||||
window_data->specific = window_data_x11;
|
|
||||||
|
|
||||||
window_data_x11->display = XOpenDisplay(0);
|
|
||||||
if (!window_data_x11->display) {
|
|
||||||
free(window_data);
|
|
||||||
free(window_data_x11);
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_keycodes(window_data_x11);
|
|
||||||
|
|
||||||
window_data_x11->screen = DefaultScreen(window_data_x11->display);
|
|
||||||
|
|
||||||
visual = DefaultVisual(window_data_x11->display, window_data_x11->screen);
|
|
||||||
formats = XListPixmapFormats(window_data_x11->display, &formatCount);
|
|
||||||
depth = DefaultDepth(window_data_x11->display, window_data_x11->screen);
|
|
||||||
|
|
||||||
Window defaultRootWindow = DefaultRootWindow(window_data_x11->display);
|
|
||||||
|
|
||||||
for (i = 0; i < formatCount; ++i)
|
|
||||||
{
|
|
||||||
if (depth == formats[i].depth)
|
|
||||||
{
|
|
||||||
convDepth = formats[i].bits_per_pixel;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XFree(formats);
|
|
||||||
|
|
||||||
// We only support 32-bit right now
|
|
||||||
if (convDepth != 32)
|
|
||||||
{
|
|
||||||
XCloseDisplay(window_data_x11->display);
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int screenWidth = DisplayWidth(window_data_x11->display, window_data_x11->screen);
|
|
||||||
int screenHeight = DisplayHeight(window_data_x11->display, window_data_x11->screen);
|
|
||||||
|
|
||||||
windowAttributes.border_pixel = BlackPixel(window_data_x11->display, window_data_x11->screen);
|
|
||||||
windowAttributes.background_pixel = BlackPixel(window_data_x11->display, window_data_x11->screen);
|
|
||||||
windowAttributes.backing_store = NotUseful;
|
|
||||||
|
|
||||||
int posX, posY;
|
|
||||||
int windowWidth, windowHeight;
|
|
||||||
|
|
||||||
window_data->window_width = width;
|
|
||||||
window_data->window_height = height;
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
calc_dst_factor(window_data, width, height);
|
|
||||||
|
|
||||||
if (flags & WF_FULLSCREEN_DESKTOP) {
|
|
||||||
posX = 0;
|
|
||||||
posY = 0;
|
|
||||||
windowWidth = screenWidth;
|
|
||||||
windowHeight = screenHeight;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
posX = (screenWidth - width) / 2;
|
|
||||||
posY = (screenHeight - height) / 2;
|
|
||||||
windowWidth = width;
|
|
||||||
windowHeight = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data_x11->window = XCreateWindow(
|
|
||||||
window_data_x11->display,
|
|
||||||
defaultRootWindow,
|
|
||||||
posX, posY,
|
|
||||||
windowWidth, windowHeight,
|
|
||||||
0,
|
|
||||||
depth,
|
|
||||||
InputOutput,
|
|
||||||
visual,
|
|
||||||
CWBackPixel | CWBorderPixel | CWBackingStore,
|
|
||||||
&windowAttributes);
|
|
||||||
if (!window_data_x11->window)
|
|
||||||
return 0x0;
|
|
||||||
|
|
||||||
XSelectInput(window_data_x11->display, window_data_x11->window,
|
|
||||||
KeyPressMask | KeyReleaseMask
|
|
||||||
| ButtonPressMask | ButtonReleaseMask | PointerMotionMask
|
|
||||||
| StructureNotifyMask | ExposureMask
|
|
||||||
| FocusChangeMask
|
|
||||||
| EnterWindowMask | LeaveWindowMask
|
|
||||||
);
|
|
||||||
|
|
||||||
XStoreName(window_data_x11->display, window_data_x11->window, title);
|
|
||||||
|
|
||||||
if (flags & WF_BORDERLESS) {
|
|
||||||
struct StyleHints {
|
|
||||||
unsigned long flags;
|
|
||||||
unsigned long functions;
|
|
||||||
unsigned long decorations;
|
|
||||||
long inputMode;
|
|
||||||
unsigned long status;
|
|
||||||
} sh = {
|
|
||||||
.flags = 2,
|
|
||||||
.functions = 0,
|
|
||||||
.decorations = 0,
|
|
||||||
.inputMode = 0,
|
|
||||||
.status = 0,
|
|
||||||
};
|
|
||||||
Atom sh_p = XInternAtom(window_data_x11->display, "_MOTIF_WM_HINTS", True);
|
|
||||||
XChangeProperty(window_data_x11->display, window_data_x11->window, sh_p, sh_p, 32, PropModeReplace, (unsigned char*)&sh, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & WF_ALWAYS_ON_TOP) {
|
|
||||||
Atom sa_p = XInternAtom(window_data_x11->display, "_NET_WM_STATE_ABOVE", False);
|
|
||||||
XChangeProperty(window_data_x11->display, window_data_x11->window, XInternAtom(window_data_x11->display, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *)&sa_p, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & WF_FULLSCREEN) {
|
|
||||||
Atom sf_p = XInternAtom(window_data_x11->display, "_NET_WM_STATE_FULLSCREEN", True);
|
|
||||||
XChangeProperty(window_data_x11->display, window_data_x11->window, XInternAtom(window_data_x11->display, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char*)&sf_p, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
sizeHints.flags = PPosition | PMinSize | PMaxSize;
|
|
||||||
sizeHints.x = 0;
|
|
||||||
sizeHints.y = 0;
|
|
||||||
sizeHints.min_width = width;
|
|
||||||
sizeHints.min_height = height;
|
|
||||||
if (flags & WF_RESIZABLE) {
|
|
||||||
sizeHints.max_width = screenWidth;
|
|
||||||
sizeHints.max_height = screenHeight;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sizeHints.max_width = width;
|
|
||||||
sizeHints.max_height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_delete_window_atom = XInternAtom(window_data_x11->display, "WM_DELETE_WINDOW", False);
|
|
||||||
XSetWMProtocols(window_data_x11->display, window_data_x11->window, &s_delete_window_atom, 1);
|
|
||||||
|
|
||||||
#if defined(USE_OPENGL_API)
|
|
||||||
if(create_GL_context(window_data) == false) {
|
|
||||||
return 0x0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
window_data_x11->image = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, width, height, 32, width * 4);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
XSetWMNormalHints(window_data_x11->display, window_data_x11->window, &sizeHints);
|
|
||||||
XClearWindow(window_data_x11->display, window_data_x11->window);
|
|
||||||
XMapRaised(window_data_x11->display, window_data_x11->window);
|
|
||||||
XFlush(window_data_x11->display);
|
|
||||||
|
|
||||||
window_data_x11->gc = DefaultGC(window_data_x11->display, window_data_x11->screen);
|
|
||||||
|
|
||||||
window_data_x11->timer = mfb_timer_create();
|
|
||||||
|
|
||||||
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUG)
|
|
||||||
printf("Window created using X11 API\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
window_data->is_initialized = true;
|
|
||||||
return (struct mfb_window *) window_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int translate_key(int scancode);
|
|
||||||
int translate_mod(int state);
|
|
||||||
int translate_mod_ex(int key, int state, int is_pressed);
|
|
||||||
|
|
||||||
static void
|
|
||||||
processEvent(SWindowData *window_data, XEvent *event) {
|
|
||||||
switch (event->type) {
|
|
||||||
case KeyPress:
|
|
||||||
case KeyRelease:
|
|
||||||
{
|
|
||||||
mfb_key key_code = (mfb_key) translate_key(event->xkey.keycode);
|
|
||||||
int is_pressed = (event->type == KeyPress);
|
|
||||||
window_data->mod_keys = translate_mod_ex(key_code, event->xkey.state, is_pressed);
|
|
||||||
|
|
||||||
window_data->key_status[key_code] = is_pressed;
|
|
||||||
kCall(keyboard_func, key_code, (mfb_key_mod) window_data->mod_keys, is_pressed);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ButtonPress:
|
|
||||||
case ButtonRelease:
|
|
||||||
{
|
|
||||||
mfb_mouse_button button = (mfb_mouse_button) event->xbutton.button;
|
|
||||||
int is_pressed = (event->type == ButtonPress);
|
|
||||||
window_data->mod_keys = translate_mod(event->xkey.state);
|
|
||||||
|
|
||||||
// Swap mouse right and middle for parity with other platforms:
|
|
||||||
// https://github.com/emoon/minifb/issues/65
|
|
||||||
switch (button) {
|
|
||||||
case Button2:
|
|
||||||
button = Button3;
|
|
||||||
break;
|
|
||||||
case Button3:
|
|
||||||
button = Button2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (button) {
|
|
||||||
case Button1:
|
|
||||||
case Button2:
|
|
||||||
case Button3:
|
|
||||||
window_data->mouse_button_status[button & 0x07] = is_pressed;
|
|
||||||
kCall(mouse_btn_func, button, (mfb_key_mod) window_data->mod_keys, is_pressed);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Button4:
|
|
||||||
window_data->mouse_wheel_y = 1.0f;
|
|
||||||
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, window_data->mouse_wheel_y);
|
|
||||||
break;
|
|
||||||
case Button5:
|
|
||||||
window_data->mouse_wheel_y = -1.0f;
|
|
||||||
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, window_data->mouse_wheel_y);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6:
|
|
||||||
window_data->mouse_wheel_x = 1.0f;
|
|
||||||
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, window_data->mouse_wheel_x, 0.0f);
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
window_data->mouse_wheel_x = -1.0f;
|
|
||||||
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, window_data->mouse_wheel_x, 0.0f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
window_data->mouse_button_status[(button - 4) & 0x07] = is_pressed;
|
|
||||||
kCall(mouse_btn_func, (mfb_mouse_button) (button - 4), (mfb_key_mod) window_data->mod_keys, is_pressed);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MotionNotify:
|
|
||||||
window_data->mouse_pos_x = event->xmotion.x;
|
|
||||||
window_data->mouse_pos_y = event->xmotion.y;
|
|
||||||
kCall(mouse_move_func, event->xmotion.x, event->xmotion.y);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ConfigureNotify:
|
|
||||||
{
|
|
||||||
window_data->window_width = event->xconfigure.width;
|
|
||||||
window_data->window_height = event->xconfigure.height;
|
|
||||||
resize_dst(window_data, event->xconfigure.width, event->xconfigure.height);
|
|
||||||
|
|
||||||
#if defined(USE_OPENGL_API)
|
|
||||||
resize_GL(window_data);
|
|
||||||
#else
|
|
||||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
|
||||||
if(window_data_x11->image_scaler != 0x0) {
|
|
||||||
window_data_x11->image_scaler->data = 0x0;
|
|
||||||
XDestroyImage(window_data_x11->image_scaler);
|
|
||||||
window_data_x11->image_scaler = 0x0;
|
|
||||||
window_data_x11->image_scaler_width = 0;
|
|
||||||
window_data_x11->image_scaler_height = 0;
|
|
||||||
}
|
|
||||||
XClearWindow(window_data_x11->display, window_data_x11->window);
|
|
||||||
#endif
|
|
||||||
kCall(resize_func, window_data->window_width, window_data->window_height);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EnterNotify:
|
|
||||||
case LeaveNotify:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FocusIn:
|
|
||||||
window_data->is_active = true;
|
|
||||||
kCall(active_func, true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FocusOut:
|
|
||||||
window_data->is_active = false;
|
|
||||||
kCall(active_func, false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DestroyNotify:
|
|
||||||
window_data->close = true;
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ClientMessage:
|
|
||||||
{
|
|
||||||
if ((Atom)event->xclient.data.l[0] == s_delete_window_atom) {
|
|
||||||
window_data->close = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
processEvents(SWindowData *window_data) {
|
|
||||||
XEvent event;
|
|
||||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
|
||||||
|
|
||||||
while ((window_data->close == false) && XPending(window_data_x11->display)) {
|
|
||||||
XNextEvent(window_data_x11->display, &event);
|
|
||||||
processEvent(window_data, &event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void destroy_window_data(SWindowData *window_data);
|
|
||||||
|
|
||||||
mfb_update_state
|
|
||||||
mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned height) {
|
|
||||||
if (window == 0x0) {
|
|
||||||
return STATE_INVALID_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
if (window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return STATE_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer == 0x0) {
|
|
||||||
return STATE_INVALID_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(USE_OPENGL_API)
|
|
||||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
|
||||||
bool different_size = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(window_data->buffer_width != width || window_data->buffer_height != height) {
|
|
||||||
window_data->buffer_width = width;
|
|
||||||
window_data->buffer_stride = width * 4;
|
|
||||||
window_data->buffer_height = height;
|
|
||||||
#if !defined(USE_OPENGL_API)
|
|
||||||
different_size = true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(USE_OPENGL_API)
|
|
||||||
|
|
||||||
if (different_size || window_data->buffer_width != window_data->dst_width || window_data->buffer_height != window_data->dst_height) {
|
|
||||||
if (window_data_x11->image_scaler_width != window_data->dst_width || window_data_x11->image_scaler_height != window_data->dst_height) {
|
|
||||||
if (window_data_x11->image_scaler != 0x0) {
|
|
||||||
window_data_x11->image_scaler->data = 0x0;
|
|
||||||
XDestroyImage(window_data_x11->image_scaler);
|
|
||||||
}
|
|
||||||
if (window_data_x11->image_buffer != 0x0) {
|
|
||||||
free(window_data_x11->image_buffer);
|
|
||||||
window_data_x11->image_buffer = 0x0;
|
|
||||||
}
|
|
||||||
int depth = DefaultDepth(window_data_x11->display, window_data_x11->screen);
|
|
||||||
window_data_x11->image_buffer = malloc(window_data->dst_width * window_data->dst_height * 4);
|
|
||||||
if(window_data_x11->image_buffer == 0x0) {
|
|
||||||
return STATE_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
window_data_x11->image_scaler_width = window_data->dst_width;
|
|
||||||
window_data_x11->image_scaler_height = window_data->dst_height;
|
|
||||||
window_data_x11->image_scaler = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, window_data_x11->image_scaler_width, window_data_x11->image_scaler_height, 32, window_data_x11->image_scaler_width * 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window_data_x11->image_scaler != 0x0) {
|
|
||||||
stretch_image((uint32_t *) buffer, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->buffer_width,
|
|
||||||
(uint32_t *) window_data_x11->image_buffer, 0, 0, window_data->dst_width, window_data->dst_height, window_data->dst_width);
|
|
||||||
window_data_x11->image_scaler->data = (char *) window_data_x11->image_buffer;
|
|
||||||
XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image_scaler, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
window_data_x11->image->data = (char *) buffer;
|
|
||||||
XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height);
|
|
||||||
}
|
|
||||||
XFlush(window_data_x11->display);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
redraw_GL(window_data, buffer);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
processEvents(window_data);
|
|
||||||
|
|
||||||
return STATE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
mfb_update_state
|
|
||||||
mfb_update_events(struct mfb_window *window) {
|
|
||||||
if (window == 0x0) {
|
|
||||||
return STATE_INVALID_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
if (window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return STATE_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
|
||||||
XFlush(window_data_x11->display);
|
|
||||||
processEvents(window_data);
|
|
||||||
|
|
||||||
return STATE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
extern double g_time_for_frame;
|
|
||||||
extern bool g_use_hardware_sync;
|
|
||||||
|
|
||||||
bool
|
|
||||||
mfb_wait_sync(struct mfb_window *window) {
|
|
||||||
if (window == 0x0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
if (window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(g_use_hardware_sync) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
|
||||||
XFlush(window_data_x11->display);
|
|
||||||
XEvent event;
|
|
||||||
double current;
|
|
||||||
uint32_t millis = 1;
|
|
||||||
while(1) {
|
|
||||||
current = mfb_timer_now(window_data_x11->timer);
|
|
||||||
if (current >= g_time_for_frame * 0.96) {
|
|
||||||
mfb_timer_reset(window_data_x11->timer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if(current >= g_time_for_frame * 0.8) {
|
|
||||||
millis = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
usleep(millis * 1000);
|
|
||||||
//sched_yield();
|
|
||||||
|
|
||||||
if(millis == 1 && XEventsQueued(window_data_x11->display, QueuedAlready) > 0) {
|
|
||||||
XNextEvent(window_data_x11->display, &event);
|
|
||||||
processEvent(window_data, &event);
|
|
||||||
|
|
||||||
if(window_data->close) {
|
|
||||||
destroy_window_data(window_data);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void
|
|
||||||
destroy_window_data(SWindowData *window_data) {
|
|
||||||
if (window_data != 0x0) {
|
|
||||||
if (window_data->specific != 0x0) {
|
|
||||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
|
||||||
|
|
||||||
#if defined(USE_OPENGL_API)
|
|
||||||
destroy_GL_context(window_data);
|
|
||||||
#else
|
|
||||||
if (window_data_x11->image != 0x0) {
|
|
||||||
window_data_x11->image->data = 0x0;
|
|
||||||
XDestroyImage(window_data_x11->image);
|
|
||||||
XDestroyWindow(window_data_x11->display, window_data_x11->window);
|
|
||||||
XCloseDisplay(window_data_x11->display);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mfb_timer_destroy(window_data_x11->timer);
|
|
||||||
memset(window_data_x11, 0, sizeof(SWindowData_X11));
|
|
||||||
free(window_data_x11);
|
|
||||||
}
|
|
||||||
memset(window_data, 0, sizeof(SWindowData));
|
|
||||||
free(window_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
extern short int g_keycodes[512];
|
|
||||||
|
|
||||||
static int
|
|
||||||
translateKeyCodeB(int keySym) {
|
|
||||||
|
|
||||||
switch (keySym)
|
|
||||||
{
|
|
||||||
case XK_KP_0: return KB_KEY_KP_0;
|
|
||||||
case XK_KP_1: return KB_KEY_KP_1;
|
|
||||||
case XK_KP_2: return KB_KEY_KP_2;
|
|
||||||
case XK_KP_3: return KB_KEY_KP_3;
|
|
||||||
case XK_KP_4: return KB_KEY_KP_4;
|
|
||||||
case XK_KP_5: return KB_KEY_KP_5;
|
|
||||||
case XK_KP_6: return KB_KEY_KP_6;
|
|
||||||
case XK_KP_7: return KB_KEY_KP_7;
|
|
||||||
case XK_KP_8: return KB_KEY_KP_8;
|
|
||||||
case XK_KP_9: return KB_KEY_KP_9;
|
|
||||||
case XK_KP_Separator:
|
|
||||||
case XK_KP_Decimal: return KB_KEY_KP_DECIMAL;
|
|
||||||
case XK_KP_Equal: return KB_KEY_KP_EQUAL;
|
|
||||||
case XK_KP_Enter: return KB_KEY_KP_ENTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
return KB_KEY_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int translateKeyCodeA(int keySym) {
|
|
||||||
switch (keySym)
|
|
||||||
{
|
|
||||||
case XK_Escape: return KB_KEY_ESCAPE;
|
|
||||||
case XK_Tab: return KB_KEY_TAB;
|
|
||||||
case XK_Shift_L: return KB_KEY_LEFT_SHIFT;
|
|
||||||
case XK_Shift_R: return KB_KEY_RIGHT_SHIFT;
|
|
||||||
case XK_Control_L: return KB_KEY_LEFT_CONTROL;
|
|
||||||
case XK_Control_R: return KB_KEY_RIGHT_CONTROL;
|
|
||||||
case XK_Meta_L:
|
|
||||||
case XK_Alt_L: return KB_KEY_LEFT_ALT;
|
|
||||||
case XK_Mode_switch: // Mapped to Alt_R on many keyboards
|
|
||||||
case XK_ISO_Level3_Shift: // AltGr on at least some machines
|
|
||||||
case XK_Meta_R:
|
|
||||||
case XK_Alt_R: return KB_KEY_RIGHT_ALT;
|
|
||||||
case XK_Super_L: return KB_KEY_LEFT_SUPER;
|
|
||||||
case XK_Super_R: return KB_KEY_RIGHT_SUPER;
|
|
||||||
case XK_Menu: return KB_KEY_MENU;
|
|
||||||
case XK_Num_Lock: return KB_KEY_NUM_LOCK;
|
|
||||||
case XK_Caps_Lock: return KB_KEY_CAPS_LOCK;
|
|
||||||
case XK_Print: return KB_KEY_PRINT_SCREEN;
|
|
||||||
case XK_Scroll_Lock: return KB_KEY_SCROLL_LOCK;
|
|
||||||
case XK_Pause: return KB_KEY_PAUSE;
|
|
||||||
case XK_Delete: return KB_KEY_DELETE;
|
|
||||||
case XK_BackSpace: return KB_KEY_BACKSPACE;
|
|
||||||
case XK_Return: return KB_KEY_ENTER;
|
|
||||||
case XK_Home: return KB_KEY_HOME;
|
|
||||||
case XK_End: return KB_KEY_END;
|
|
||||||
case XK_Page_Up: return KB_KEY_PAGE_UP;
|
|
||||||
case XK_Page_Down: return KB_KEY_PAGE_DOWN;
|
|
||||||
case XK_Insert: return KB_KEY_INSERT;
|
|
||||||
case XK_Left: return KB_KEY_LEFT;
|
|
||||||
case XK_Right: return KB_KEY_RIGHT;
|
|
||||||
case XK_Down: return KB_KEY_DOWN;
|
|
||||||
case XK_Up: return KB_KEY_UP;
|
|
||||||
case XK_F1: return KB_KEY_F1;
|
|
||||||
case XK_F2: return KB_KEY_F2;
|
|
||||||
case XK_F3: return KB_KEY_F3;
|
|
||||||
case XK_F4: return KB_KEY_F4;
|
|
||||||
case XK_F5: return KB_KEY_F5;
|
|
||||||
case XK_F6: return KB_KEY_F6;
|
|
||||||
case XK_F7: return KB_KEY_F7;
|
|
||||||
case XK_F8: return KB_KEY_F8;
|
|
||||||
case XK_F9: return KB_KEY_F9;
|
|
||||||
case XK_F10: return KB_KEY_F10;
|
|
||||||
case XK_F11: return KB_KEY_F11;
|
|
||||||
case XK_F12: return KB_KEY_F12;
|
|
||||||
case XK_F13: return KB_KEY_F13;
|
|
||||||
case XK_F14: return KB_KEY_F14;
|
|
||||||
case XK_F15: return KB_KEY_F15;
|
|
||||||
case XK_F16: return KB_KEY_F16;
|
|
||||||
case XK_F17: return KB_KEY_F17;
|
|
||||||
case XK_F18: return KB_KEY_F18;
|
|
||||||
case XK_F19: return KB_KEY_F19;
|
|
||||||
case XK_F20: return KB_KEY_F20;
|
|
||||||
case XK_F21: return KB_KEY_F21;
|
|
||||||
case XK_F22: return KB_KEY_F22;
|
|
||||||
case XK_F23: return KB_KEY_F23;
|
|
||||||
case XK_F24: return KB_KEY_F24;
|
|
||||||
case XK_F25: return KB_KEY_F25;
|
|
||||||
|
|
||||||
// Numeric keypad
|
|
||||||
case XK_KP_Divide: return KB_KEY_KP_DIVIDE;
|
|
||||||
case XK_KP_Multiply: return KB_KEY_KP_MULTIPLY;
|
|
||||||
case XK_KP_Subtract: return KB_KEY_KP_SUBTRACT;
|
|
||||||
case XK_KP_Add: return KB_KEY_KP_ADD;
|
|
||||||
|
|
||||||
// These should have been detected in secondary keysym test above!
|
|
||||||
case XK_KP_Insert: return KB_KEY_KP_0;
|
|
||||||
case XK_KP_End: return KB_KEY_KP_1;
|
|
||||||
case XK_KP_Down: return KB_KEY_KP_2;
|
|
||||||
case XK_KP_Page_Down: return KB_KEY_KP_3;
|
|
||||||
case XK_KP_Left: return KB_KEY_KP_4;
|
|
||||||
case XK_KP_Right: return KB_KEY_KP_6;
|
|
||||||
case XK_KP_Home: return KB_KEY_KP_7;
|
|
||||||
case XK_KP_Up: return KB_KEY_KP_8;
|
|
||||||
case XK_KP_Page_Up: return KB_KEY_KP_9;
|
|
||||||
case XK_KP_Delete: return KB_KEY_KP_DECIMAL;
|
|
||||||
case XK_KP_Equal: return KB_KEY_KP_EQUAL;
|
|
||||||
case XK_KP_Enter: return KB_KEY_KP_ENTER;
|
|
||||||
|
|
||||||
// Last resort: Check for printable keys (should not happen if the XKB
|
|
||||||
// extension is available). This will give a layout dependent mapping
|
|
||||||
// (which is wrong, and we may miss some keys, especially on non-US
|
|
||||||
// keyboards), but it's better than nothing...
|
|
||||||
case XK_a: return KB_KEY_A;
|
|
||||||
case XK_b: return KB_KEY_B;
|
|
||||||
case XK_c: return KB_KEY_C;
|
|
||||||
case XK_d: return KB_KEY_D;
|
|
||||||
case XK_e: return KB_KEY_E;
|
|
||||||
case XK_f: return KB_KEY_F;
|
|
||||||
case XK_g: return KB_KEY_G;
|
|
||||||
case XK_h: return KB_KEY_H;
|
|
||||||
case XK_i: return KB_KEY_I;
|
|
||||||
case XK_j: return KB_KEY_J;
|
|
||||||
case XK_k: return KB_KEY_K;
|
|
||||||
case XK_l: return KB_KEY_L;
|
|
||||||
case XK_m: return KB_KEY_M;
|
|
||||||
case XK_n: return KB_KEY_N;
|
|
||||||
case XK_o: return KB_KEY_O;
|
|
||||||
case XK_p: return KB_KEY_P;
|
|
||||||
case XK_q: return KB_KEY_Q;
|
|
||||||
case XK_r: return KB_KEY_R;
|
|
||||||
case XK_s: return KB_KEY_S;
|
|
||||||
case XK_t: return KB_KEY_T;
|
|
||||||
case XK_u: return KB_KEY_U;
|
|
||||||
case XK_v: return KB_KEY_V;
|
|
||||||
case XK_w: return KB_KEY_W;
|
|
||||||
case XK_x: return KB_KEY_X;
|
|
||||||
case XK_y: return KB_KEY_Y;
|
|
||||||
case XK_z: return KB_KEY_Z;
|
|
||||||
case XK_1: return KB_KEY_1;
|
|
||||||
case XK_2: return KB_KEY_2;
|
|
||||||
case XK_3: return KB_KEY_3;
|
|
||||||
case XK_4: return KB_KEY_4;
|
|
||||||
case XK_5: return KB_KEY_5;
|
|
||||||
case XK_6: return KB_KEY_6;
|
|
||||||
case XK_7: return KB_KEY_7;
|
|
||||||
case XK_8: return KB_KEY_8;
|
|
||||||
case XK_9: return KB_KEY_9;
|
|
||||||
case XK_0: return KB_KEY_0;
|
|
||||||
case XK_space: return KB_KEY_SPACE;
|
|
||||||
case XK_minus: return KB_KEY_MINUS;
|
|
||||||
case XK_equal: return KB_KEY_EQUAL;
|
|
||||||
case XK_bracketleft: return KB_KEY_LEFT_BRACKET;
|
|
||||||
case XK_bracketright: return KB_KEY_RIGHT_BRACKET;
|
|
||||||
case XK_backslash: return KB_KEY_BACKSLASH;
|
|
||||||
case XK_semicolon: return KB_KEY_SEMICOLON;
|
|
||||||
case XK_apostrophe: return KB_KEY_APOSTROPHE;
|
|
||||||
case XK_grave: return KB_KEY_GRAVE_ACCENT;
|
|
||||||
case XK_comma: return KB_KEY_COMMA;
|
|
||||||
case XK_period: return KB_KEY_PERIOD;
|
|
||||||
case XK_slash: return KB_KEY_SLASH;
|
|
||||||
case XK_less: return KB_KEY_WORLD_1; // At least in some layouts...
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return KB_KEY_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
init_keycodes(SWindowData_X11 *window_data_x11) {
|
|
||||||
size_t i;
|
|
||||||
int keySym;
|
|
||||||
|
|
||||||
// Clear keys
|
|
||||||
for (i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i)
|
|
||||||
g_keycodes[i] = KB_KEY_UNKNOWN;
|
|
||||||
|
|
||||||
// Valid key code range is [8,255], according to the Xlib manual
|
|
||||||
for (i=8; i<=255; ++i) {
|
|
||||||
// Try secondary keysym, for numeric keypad keys
|
|
||||||
keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 1);
|
|
||||||
g_keycodes[i] = translateKeyCodeB(keySym);
|
|
||||||
if (g_keycodes[i] == KB_KEY_UNKNOWN) {
|
|
||||||
keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 0);
|
|
||||||
g_keycodes[i] = translateKeyCodeA(keySym);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int
|
|
||||||
translate_key(int scancode) {
|
|
||||||
if (scancode < 0 || scancode > 255)
|
|
||||||
return KB_KEY_UNKNOWN;
|
|
||||||
|
|
||||||
return g_keycodes[scancode];
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int
|
|
||||||
translate_mod(int state) {
|
|
||||||
int mod_keys = 0;
|
|
||||||
|
|
||||||
if (state & ShiftMask)
|
|
||||||
mod_keys |= KB_MOD_SHIFT;
|
|
||||||
if (state & ControlMask)
|
|
||||||
mod_keys |= KB_MOD_CONTROL;
|
|
||||||
if (state & Mod1Mask)
|
|
||||||
mod_keys |= KB_MOD_ALT;
|
|
||||||
if (state & Mod4Mask)
|
|
||||||
mod_keys |= KB_MOD_SUPER;
|
|
||||||
if (state & LockMask)
|
|
||||||
mod_keys |= KB_MOD_CAPS_LOCK;
|
|
||||||
if (state & Mod2Mask)
|
|
||||||
mod_keys |= KB_MOD_NUM_LOCK;
|
|
||||||
|
|
||||||
return mod_keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int
|
|
||||||
translate_mod_ex(int key, int state, int is_pressed) {
|
|
||||||
int mod_keys = 0;
|
|
||||||
|
|
||||||
mod_keys = translate_mod(state);
|
|
||||||
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case KB_KEY_LEFT_SHIFT:
|
|
||||||
case KB_KEY_RIGHT_SHIFT:
|
|
||||||
if (is_pressed)
|
|
||||||
mod_keys |= KB_MOD_SHIFT;
|
|
||||||
else
|
|
||||||
mod_keys &= ~KB_MOD_SHIFT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KB_KEY_LEFT_CONTROL:
|
|
||||||
case KB_KEY_RIGHT_CONTROL:
|
|
||||||
if (is_pressed)
|
|
||||||
mod_keys |= KB_MOD_CONTROL;
|
|
||||||
else
|
|
||||||
mod_keys &= ~KB_MOD_CONTROL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KB_KEY_LEFT_ALT:
|
|
||||||
case KB_KEY_RIGHT_ALT:
|
|
||||||
if (is_pressed)
|
|
||||||
mod_keys |= KB_MOD_ALT;
|
|
||||||
else
|
|
||||||
mod_keys &= ~KB_MOD_ALT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KB_KEY_LEFT_SUPER:
|
|
||||||
case KB_KEY_RIGHT_SUPER:
|
|
||||||
if (is_pressed)
|
|
||||||
mod_keys |= KB_MOD_SUPER;
|
|
||||||
else
|
|
||||||
mod_keys &= ~KB_MOD_SUPER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mod_keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool
|
|
||||||
mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) {
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
|
||||||
|
|
||||||
if (offset_x + width > window_data->window_width) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (offset_y + height > window_data->window_height) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_data->dst_offset_x = offset_x;
|
|
||||||
window_data->dst_offset_y = offset_y;
|
|
||||||
window_data->dst_width = width;
|
|
||||||
window_data->dst_height = height;
|
|
||||||
calc_dst_factor(window_data, window_data->window_width, window_data->window_height);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void
|
|
||||||
mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y) {
|
|
||||||
float x = 96.0, y = 96.0;
|
|
||||||
|
|
||||||
if(window != 0x0) {
|
|
||||||
//SWindowData *window_data = (SWindowData *) window;
|
|
||||||
//SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
|
||||||
|
|
||||||
// I cannot find a way to get dpi under VirtualBox
|
|
||||||
// XrmGetResource "Xft.dpi", "Xft.Dpi"
|
|
||||||
// XRRGetOutputInfo
|
|
||||||
// DisplayWidthMM, DisplayHeightMM
|
|
||||||
// All returning invalid values or 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale_x) {
|
|
||||||
*scale_x = x / 96.0f;
|
|
||||||
if(*scale_x == 0) {
|
|
||||||
*scale_x = 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale_y) {
|
|
||||||
*scale_y = y / 96.0f;
|
|
||||||
if (*scale_y == 0) {
|
|
||||||
*scale_y = 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user