Merge branch 'master' into master
This commit is contained in:
570
src/MiniFB_common.c
Executable file
570
src/MiniFB_common.c
Executable file
@ -0,0 +1,570 @@
|
||||
#include "MiniFB.h"
|
||||
#include "WindowData.h"
|
||||
#include <MiniFB_internal.h>
|
||||
|
||||
//-------------------------------------
|
||||
short int g_keycodes[512] = { 0 };
|
||||
//-------------------------------------
|
||||
|
||||
//-------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
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";
|
||||
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
69
src/MiniFB_cpp.cpp
Executable file
69
src/MiniFB_cpp.cpp
Executable file
@ -0,0 +1,69 @@
|
||||
#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);
|
||||
}
|
77
src/MiniFB_internal.c
Normal file
77
src/MiniFB_internal.c
Normal file
@ -0,0 +1,77 @@
|
||||
#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;
|
||||
}
|
||||
}
|
26
src/MiniFB_internal.h
Executable file
26
src/MiniFB_internal.h
Executable file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "MiniFB.h"
|
||||
#include "MiniFB_enums.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 init_keycodes();
|
||||
void keyboard_default(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
32
src/MiniFB_linux.c
Normal file
32
src/MiniFB_linux.c
Normal file
@ -0,0 +1,32 @@
|
||||
#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;
|
||||
}
|
102
src/MiniFB_timer.c
Normal file
102
src/MiniFB_timer.c
Normal file
@ -0,0 +1,102 @@
|
||||
#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;
|
||||
|
||||
//-------------------------------------
|
||||
extern uint64_t mfb_timer_tick();
|
||||
extern void mfb_timer_init();
|
||||
|
||||
//-------------------------------------
|
||||
void
|
||||
mfb_set_target_fps(uint32_t fps) {
|
||||
if(fps == 0) {
|
||||
g_time_for_frame = 0;
|
||||
}
|
||||
else {
|
||||
g_time_for_frame = 1.0 / fps;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
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;
|
||||
}
|
42
src/WindowData.h
Normal file
42
src/WindowData.h
Normal file
@ -0,0 +1,42 @@
|
||||
#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;
|
||||
|
||||
void *draw_buffer;
|
||||
uint32_t buffer_width;
|
||||
uint32_t buffer_height;
|
||||
uint32_t buffer_stride;
|
||||
uint32_t mod_keys;
|
||||
bool close;
|
||||
|
||||
bool is_active;
|
||||
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];
|
||||
|
||||
} SWindowData;
|
@ -1,101 +1,543 @@
|
||||
|
||||
#include "OSXWindow.h"
|
||||
#include "OSXWindowFrameView.h"
|
||||
#include "WindowData_OSX.h"
|
||||
#include <MiniFB.h>
|
||||
#include <MiniFB_enums.h>
|
||||
#include <MiniFB_internal.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#if defined(USE_METAL_API)
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <MetalKit/MetalKit.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include "MiniFB.h"
|
||||
|
||||
void init_keycodes();
|
||||
|
||||
#if defined(USE_METAL_API)
|
||||
id<MTLDevice> g_metal_device;
|
||||
id<MTLLibrary> g_library;
|
||||
|
||||
Vertex gVertices[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},
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void* g_updateBuffer = 0;
|
||||
int g_width = 0;
|
||||
int g_height = 0;
|
||||
static OSXWindow* window_;
|
||||
NSString* g_shadersSrc = @
|
||||
" #include <metal_stdlib>\n"
|
||||
"using namespace metal;\n"
|
||||
|
||||
"struct VertexOutput {\n"
|
||||
"float4 pos [[position]];\n"
|
||||
"float2 texcoord;\n"
|
||||
"};\n"
|
||||
|
||||
"vertex VertexOutput vertFunc(unsigned int vID[[vertex_id]])\n"
|
||||
"{\n"
|
||||
"VertexOutput out;\n"
|
||||
|
||||
"out.pos.x = (float)(vID / 2) * 4.0 - 1.0;\n"
|
||||
"out.pos.y = (float)(vID % 2) * 4.0 - 1.0;\n"
|
||||
"out.pos.z = 0.0;\n"
|
||||
"out.pos.w = 1.0;\n"
|
||||
|
||||
"out.texcoord.x = (float)(vID / 2) * 2.0;\n"
|
||||
"out.texcoord.y = 1.0 - (float)(vID % 2) * 2.0;\n"
|
||||
|
||||
"return out;\n"
|
||||
"}\n"
|
||||
|
||||
"struct Vertex\n"
|
||||
"{\n"
|
||||
"float4 position [[position]];\n"
|
||||
"};\n"
|
||||
|
||||
"vertex VertexOutput vertFunc2(unsigned int vID[[vertex_id]], const device Vertex *pos [[buffer(0)]])\n"
|
||||
"{\n"
|
||||
"VertexOutput out;\n"
|
||||
|
||||
"out.pos = pos[vID].position;\n"
|
||||
|
||||
"out.texcoord.x = (float)(vID / 2);\n"
|
||||
"out.texcoord.y = 1.0 - (float)(vID % 2);\n"
|
||||
|
||||
"return out;\n"
|
||||
"}\n"
|
||||
|
||||
"fragment float4 fragFunc(VertexOutput input [[stage_in]],\n"
|
||||
"texture2d<half> colorTexture [[ texture(0) ]])\n"
|
||||
"{\n"
|
||||
"constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);\n"
|
||||
|
||||
// Sample the texture to obtain a color
|
||||
"const half4 colorSample = colorTexture.sample(textureSampler, input.texcoord);\n"
|
||||
|
||||
// We return the color of the texture
|
||||
"return float4(colorSample);\n"
|
||||
//"return float4(input.texcoord.x, input.texcoord.y, 0.0, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int mfb_open(const char* name, int width, int height)
|
||||
#if defined(USE_METAL_API)
|
||||
static bool
|
||||
create_shaders(SWindowData_OSX *window_data_osx) {
|
||||
// Error
|
||||
NSError* nsError = 0x0;
|
||||
NSError** nsErrorPtr = &nsError;
|
||||
|
||||
id<MTLLibrary> library = [g_metal_device newLibraryWithSource:g_shadersSrc
|
||||
options:[[MTLCompileOptions alloc] init]
|
||||
error:nsErrorPtr];
|
||||
|
||||
// Error update
|
||||
if (nsError || !library) {
|
||||
NSLog(@"Unable to create shaders %@", nsError);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_library = library;
|
||||
NSLog(@"Names %@", [g_library functionNames]);
|
||||
|
||||
id<MTLFunction> vertex_shader_func = [g_library newFunctionWithName:@"vertFunc2"];
|
||||
id<MTLFunction> fragment_shader_func = [g_library newFunctionWithName:@"fragFunc"];
|
||||
|
||||
if (!vertex_shader_func) {
|
||||
printf("Unable to get vertFunc!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fragment_shader_func) {
|
||||
printf("Unable to get fragFunc!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a reusable pipeline state
|
||||
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
pipelineStateDescriptor.label = @"MyPipeline";
|
||||
pipelineStateDescriptor.vertexFunction = vertex_shader_func;
|
||||
pipelineStateDescriptor.fragmentFunction = fragment_shader_func;
|
||||
pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm;
|
||||
|
||||
NSError *error = 0x0;
|
||||
window_data_osx->metal.pipeline_state = [g_metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
|
||||
if (!window_data_osx->metal.pipeline_state)
|
||||
{
|
||||
NSLog(@"Failed to created pipeline state, error %@", error);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct mfb_window *
|
||||
mfb_open(const char *title, unsigned width, unsigned height)
|
||||
{
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
g_width = width;
|
||||
g_height = height;
|
||||
|
||||
[NSApplication sharedApplication];
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
|
||||
NSWindowStyleMask styles = NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskTitled;
|
||||
|
||||
NSRect rectangle = NSMakeRect(0, 0, width, height);
|
||||
NSRect frameRect = [NSWindow frameRectForContentRect:rectangle styleMask:styles];
|
||||
window_ = [[OSXWindow alloc] initWithContentRect:frameRect styleMask:styles backing:NSBackingStoreBuffered defer:NO];
|
||||
|
||||
if (!window_)
|
||||
return 0;
|
||||
|
||||
[window_ setTitle:[NSString stringWithUTF8String:name]];
|
||||
[window_ setReleasedWhenClosed:NO];
|
||||
[window_ performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES];
|
||||
|
||||
[window_ center];
|
||||
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
[pool drain];
|
||||
|
||||
return 1;
|
||||
return mfb_open_ex(title, width, height, 0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void mfb_close()
|
||||
struct mfb_window *
|
||||
mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags)
|
||||
{
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
if (window_)
|
||||
[window_ close];
|
||||
init_keycodes();
|
||||
|
||||
[pool drain];
|
||||
SWindowData *window_data = malloc(sizeof(SWindowData));
|
||||
memset(window_data, 0, sizeof(SWindowData));
|
||||
|
||||
SWindowData_OSX *window_data_osx = malloc(sizeof(SWindowData_OSX));
|
||||
memset(window_data_osx, 0, sizeof(SWindowData_OSX));
|
||||
window_data->specific = window_data_osx;
|
||||
|
||||
window_data->window_width = width;
|
||||
window_data->window_height = height;
|
||||
|
||||
window_data->dst_width = width;
|
||||
window_data->dst_height = height;
|
||||
|
||||
window_data->buffer_width = width;
|
||||
window_data->buffer_height = height;
|
||||
window_data->buffer_stride = width * 4;
|
||||
|
||||
[NSApplication sharedApplication];
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
|
||||
#if defined(USE_METAL_API)
|
||||
g_metal_device = MTLCreateSystemDefaultDevice();
|
||||
|
||||
if (!g_metal_device) {
|
||||
printf("Your device/OS doesn't support Metal.");
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
if (!create_shaders((SWindowData_OSX *) window_data->specific)) {
|
||||
return 0x0;
|
||||
}
|
||||
#endif
|
||||
|
||||
NSWindowStyleMask styles = NSWindowStyleMaskClosable | NSWindowStyleMaskTitled;
|
||||
|
||||
if (flags & WF_BORDERLESS)
|
||||
styles |= NSWindowStyleMaskBorderless;
|
||||
|
||||
if (flags & WF_RESIZABLE)
|
||||
styles |= NSWindowStyleMaskResizable;
|
||||
|
||||
NSRect rectangle = NSMakeRect(0, 0, width, height);
|
||||
NSRect 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)
|
||||
return 0x0;
|
||||
|
||||
#if defined(USE_METAL_API)
|
||||
window_data->draw_buffer = malloc(width * height * 4);
|
||||
|
||||
if (!window_data->draw_buffer)
|
||||
return 0x0;
|
||||
|
||||
// Setup command queue
|
||||
window_data_osx->metal.command_queue = [g_metal_device newCommandQueue];
|
||||
|
||||
WindowViewController* viewController = [WindowViewController new];
|
||||
|
||||
MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init];
|
||||
|
||||
// Indicate that each pixel has a blue, green, red, and alpha channel, where each channel is
|
||||
// an 8-bit unsigned normalized value (i.e. 0 maps to 0.0 and 255 maps to 1.0)
|
||||
textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
|
||||
// Set the pixel dimensions of the texture
|
||||
textureDescriptor.width = width;
|
||||
textureDescriptor.height = height;
|
||||
|
||||
// Create the texture from the device by using the descriptor
|
||||
|
||||
for (int i = 0; i < MaxBuffersInFlight; ++i) {
|
||||
viewController->m_texture_buffers[i] = [g_metal_device newTextureWithDescriptor:textureDescriptor];
|
||||
}
|
||||
|
||||
// Used for syncing the CPU and GPU
|
||||
viewController->m_semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
|
||||
viewController->m_draw_buffer = window_data->draw_buffer;
|
||||
viewController->m_width = width;
|
||||
viewController->m_height = height;
|
||||
|
||||
MTKView* view = [[MTKView alloc] initWithFrame:rectangle];
|
||||
view.device = g_metal_device;
|
||||
view.delegate = viewController;
|
||||
view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||
[window_data_osx->window.contentView addSubview:view];
|
||||
|
||||
//window_data->buffer_width = width;
|
||||
//window_data->buffer_height = height;
|
||||
//window_data->buffer_stride = width * 4;
|
||||
|
||||
//[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];
|
||||
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
#if defined(USE_METAL_API)
|
||||
[NSApp finishLaunching];
|
||||
#endif
|
||||
|
||||
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
||||
|
||||
#if defined(USE_METAL_API)
|
||||
NSLog(@"Window created using Metal API");
|
||||
#else
|
||||
NSLog(@"Window created using Cocoa API");
|
||||
#endif
|
||||
|
||||
[pool drain];
|
||||
|
||||
return (struct mfb_window *) window_data;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int updateEvents()
|
||||
static void
|
||||
destroy_window_data(SWindowData *window_data)
|
||||
{
|
||||
int state = 0;
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
||||
if (event)
|
||||
{
|
||||
switch ([event type])
|
||||
{
|
||||
case NSEventTypeKeyDown:
|
||||
case NSEventTypeKeyUp:
|
||||
{
|
||||
state = -1;
|
||||
break;
|
||||
}
|
||||
if(window_data == 0x0)
|
||||
return;
|
||||
|
||||
default :
|
||||
{
|
||||
[NSApp sendEvent:event];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
[pool release];
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
||||
if(window_data_osx != 0x0) {
|
||||
OSXWindow *window = window_data_osx->window;
|
||||
[window removeWindowData];
|
||||
[window performClose:nil];
|
||||
|
||||
if (window_->closed)
|
||||
state = -1;
|
||||
memset(window_data_osx, 0, sizeof(SWindowData_OSX));
|
||||
free(window_data_osx);
|
||||
}
|
||||
memset(window_data, 0, sizeof(SWindowData));
|
||||
free(window_data);
|
||||
|
||||
return state;
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int mfb_update(void* buffer)
|
||||
static void
|
||||
update_events(SWindowData *window_data)
|
||||
{
|
||||
g_updateBuffer = buffer;
|
||||
int state = updateEvents();
|
||||
[[window_ contentView] setNeedsDisplay:YES];
|
||||
return state;
|
||||
NSEvent* event;
|
||||
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
do
|
||||
{
|
||||
event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
||||
if (event) {
|
||||
[NSApp sendEvent:event];
|
||||
}
|
||||
}
|
||||
while ((window_data->close == false) && event);
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
mfb_update_state
|
||||
mfb_update(struct mfb_window *window, void *buffer)
|
||||
{
|
||||
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_METAL_API)
|
||||
memcpy(window_data->draw_buffer, buffer, window_data->buffer_width * window_data->buffer_height * 4);
|
||||
#else
|
||||
window_data->draw_buffer = buffer;
|
||||
#endif
|
||||
|
||||
update_events(window_data);
|
||||
if(window_data->close == false) {
|
||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
||||
[[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 == false) {
|
||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
||||
[[window_data_osx->window contentView] setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
return STATE_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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;
|
||||
|
||||
#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;
|
||||
|
||||
gVertices[0].x = x1;
|
||||
gVertices[0].y = y1;
|
||||
|
||||
gVertices[1].x = x1;
|
||||
gVertices[1].y = y2;
|
||||
|
||||
gVertices[2].x = x2;
|
||||
gVertices[2].y = y1;
|
||||
|
||||
gVertices[3].x = x2;
|
||||
gVertices[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;
|
||||
}
|
||||
|
@ -1,11 +1,18 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
// @class OSXWindowFrameView;
|
||||
|
||||
@interface OSXWindow : NSWindow
|
||||
{
|
||||
NSView* childContentView;
|
||||
@public bool closed;
|
||||
}
|
||||
|
||||
@end
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <WindowData.h>
|
||||
// @class OSXWindowFrameView;
|
||||
|
||||
@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,153 +1,295 @@
|
||||
#import "OSXWindow.h"
|
||||
#import "OSXWindowFrameView.h"
|
||||
|
||||
@implementation OSXWindow
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (id)initWithContentRect:(NSRect)contentRect
|
||||
styleMask:(NSWindowStyleMask)windowStyle
|
||||
backing:(NSBackingStoreType)bufferingType
|
||||
defer:(BOOL)deferCreation
|
||||
{
|
||||
self = [super
|
||||
initWithContentRect:contentRect
|
||||
styleMask:windowStyle
|
||||
backing:bufferingType
|
||||
defer:deferCreation];
|
||||
if (self)
|
||||
{
|
||||
[self setOpaque:YES];
|
||||
[self setBackgroundColor:[NSColor clearColor]];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(mainWindowChanged:)
|
||||
name:NSWindowDidBecomeMainNotification
|
||||
object:self];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(mainWindowChanged:)
|
||||
name:NSWindowDidResignMainNotification
|
||||
object:self];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(willClose)
|
||||
name:NSWindowWillCloseNotification
|
||||
object:self];
|
||||
|
||||
closed = false;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (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;
|
||||
|
||||
OSXWindowFrameView *frameView = [super contentView];
|
||||
NSSize newFrameSize = [frameView bounds].size;
|
||||
newFrameSize.width += sizeDelta.width;
|
||||
newFrameSize.height += sizeDelta.height;
|
||||
|
||||
[super setContentSize:newFrameSize];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)mainWindowChanged:(NSNotification *)aNotification
|
||||
{
|
||||
(void)aNotification;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setContentView:(NSView *)aView
|
||||
{
|
||||
if ([childContentView isEqualTo:aView])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NSRect bounds = [self frame];
|
||||
bounds.origin = NSZeroPoint;
|
||||
|
||||
OSXWindowFrameView *frameView = [super contentView];
|
||||
if (!frameView)
|
||||
{
|
||||
frameView = [[[OSXWindowFrameView 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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (BOOL)canBecomeMainWindow
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (NSRect)contentRectForFrameRect:(NSRect)windowFrame
|
||||
{
|
||||
windowFrame.origin = NSZeroPoint;
|
||||
return NSInsetRect(windowFrame, 0, 0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+ (NSRect)frameRectForContentRect:(NSRect)windowContentRect styleMask:(NSWindowStyleMask)windowStyle
|
||||
{
|
||||
(void)windowStyle;
|
||||
return NSInsetRect(windowContentRect, 0, 0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)willClose
|
||||
{
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@end
|
||||
#import "OSXWindow.h"
|
||||
#import "OSXWindowFrameView.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;
|
||||
OSXWindowFrameView *view = (OSXWindowFrameView *) self->childContentView.superview;
|
||||
view->window_data = windowData;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void) removeWindowData {
|
||||
self->window_data = 0x0;
|
||||
OSXWindowFrameView *view = (OSXWindowFrameView *) 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;
|
||||
|
||||
OSXWindowFrameView *frameView = [super contentView];
|
||||
NSSize newFrameSize = [frameView bounds].size;
|
||||
newFrameSize.width += sizeDelta.width;
|
||||
newFrameSize.height += sizeDelta.height;
|
||||
|
||||
[super setContentSize:newFrameSize];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)event
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
NSString *characters;
|
||||
NSUInteger length;
|
||||
|
||||
kUnused(replacementRange);
|
||||
|
||||
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->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;
|
||||
|
||||
OSXWindowFrameView *frameView = [super contentView];
|
||||
if (!frameView)
|
||||
{
|
||||
frameView = [[[OSXWindowFrameView 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);
|
||||
window_data->is_active = true;
|
||||
kCall(active_func, true);
|
||||
}
|
||||
|
||||
- (void)windowDidResignKey:(NSNotification *)notification
|
||||
{
|
||||
kUnused(notification);
|
||||
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
|
||||
{
|
||||
window_data->close = true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)windowDidResize:(NSNotification *)notification {
|
||||
kUnused(notification);
|
||||
CGSize size = [self contentRectForFrameRect:[self frame]].size;
|
||||
|
||||
window_data->window_width = size.width;
|
||||
window_data->window_height = size.height;
|
||||
|
||||
kCall(resize_func, size.width, size.height);
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -1,8 +1,42 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface OSXWindowFrameView : NSView
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "WindowData.h"
|
||||
|
||||
#if defined(USE_METAL_API)
|
||||
#import <MetalKit/MetalKit.h>
|
||||
|
||||
typedef struct Vertex {
|
||||
float x, y, z, w;
|
||||
} Vertex;
|
||||
|
||||
// Number of textures in flight (tripple buffered)
|
||||
enum { MaxBuffersInFlight = 3 };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface WindowViewController : NSViewController<MTKViewDelegate>
|
||||
{
|
||||
@public id<MTLTexture> m_texture_buffers[MaxBuffersInFlight];
|
||||
@public int m_current_buffer;
|
||||
@public void* m_draw_buffer;
|
||||
@public int m_width;
|
||||
@public int m_height;
|
||||
// Used for syncing with CPU/GPU
|
||||
@public dispatch_semaphore_t m_semaphore;
|
||||
}
|
||||
|
||||
@end
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface OSXWindowFrameView : NSView
|
||||
{
|
||||
@public SWindowData *window_data;
|
||||
#if defined(USE_METAL_API)
|
||||
@private NSTrackingArea* trackingArea;
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
@ -1,52 +1,329 @@
|
||||
#import "OSXWindowFrameView.h"
|
||||
|
||||
@implementation OSXWindowFrameView
|
||||
|
||||
extern void* g_updateBuffer;
|
||||
extern int g_width;
|
||||
extern int g_height;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (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 (!g_updateBuffer)
|
||||
return;
|
||||
|
||||
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
|
||||
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, g_updateBuffer, g_width * g_height * 4, NULL);
|
||||
|
||||
CGImageRef img = CGImageCreate(g_width, g_height, 8, 32, g_width * 4, space, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
|
||||
provider, NULL, false, kCGRenderingIntentDefault);
|
||||
|
||||
CGColorSpaceRelease(space);
|
||||
CGDataProviderRelease(provider);
|
||||
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, g_width, g_height), img);
|
||||
|
||||
CGImageRelease(img);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#import "OSXWindowFrameView.h"
|
||||
#import "OSXWindow.h"
|
||||
#include "WindowData_OSX.h"
|
||||
#include <MiniFB_internal.h>
|
||||
|
||||
#if defined(USE_METAL_API)
|
||||
#import <MetalKit/MetalKit.h>
|
||||
|
||||
extern id<MTLDevice> g_metal_device;
|
||||
extern id<MTLLibrary> g_library;
|
||||
|
||||
extern Vertex gVertices[4];
|
||||
|
||||
@implementation WindowViewController
|
||||
|
||||
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
|
||||
{
|
||||
(void)view;
|
||||
(void)size;
|
||||
// resize
|
||||
}
|
||||
|
||||
- (void)drawInMTKView:(nonnull MTKView *)view
|
||||
{
|
||||
OSXWindow *window = (OSXWindow *) view.window;
|
||||
if(window->window_data == 0x0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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(m_semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
// Iterate through our Metal buffers, and cycle back to the first when we've written to MaxBuffersInFlight
|
||||
m_current_buffer = (m_current_buffer + 1) % MaxBuffersInFlight;
|
||||
|
||||
// Calculate the number of bytes per row of our image.
|
||||
NSUInteger bytesPerRow = 4 * m_width;
|
||||
MTLRegion region = { { 0, 0, 0 }, { m_width, m_height, 1 } };
|
||||
|
||||
// Copy the bytes from our data object into the texture
|
||||
[m_texture_buffers[m_current_buffer] replaceRegion:region
|
||||
mipmapLevel:0 withBytes:m_draw_buffer bytesPerRow:bytesPerRow];
|
||||
|
||||
// Create a new command buffer for each render pass to the current drawable
|
||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window->window_data->specific;
|
||||
id<MTLCommandBuffer> commandBuffer = [window_data_osx->metal.command_queue commandBuffer];
|
||||
commandBuffer.label = @"minifb_command_buffer";
|
||||
|
||||
// Add completion hander which signals _inFlightSemaphore 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 = m_semaphore;
|
||||
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
|
||||
{
|
||||
(void)buffer;
|
||||
dispatch_semaphore_signal(block_sema);
|
||||
}];
|
||||
|
||||
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
|
||||
OSXWindow *window = (OSXWindow *) view.window;
|
||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window->window_data->specific;
|
||||
[renderEncoder setRenderPipelineState:window_data_osx->metal.pipeline_state];
|
||||
|
||||
[renderEncoder setVertexBytes:gVertices
|
||||
length:sizeof(gVertices)
|
||||
atIndex:0];
|
||||
|
||||
[renderEncoder setFragmentTexture:m_texture_buffers[m_current_buffer] atIndex:0];
|
||||
|
||||
// Draw the vertices of our quads
|
||||
// [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
|
||||
// vertexStart:0
|
||||
// vertexCount:3];
|
||||
[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];
|
||||
}
|
||||
@end
|
||||
#endif
|
||||
|
||||
@implementation OSXWindowFrameView
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(USE_METAL_API)
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
if(trackingArea != nil) {
|
||||
[self removeTrackingArea:trackingArea];
|
||||
[trackingArea release];
|
||||
}
|
||||
|
||||
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
|
||||
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
|
||||
options:opts
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:trackingArea];
|
||||
}
|
||||
#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)
|
||||
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] graphicsPort];
|
||||
|
||||
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, CGRectMake(0, 0, window_data->window_width, window_data->window_height));
|
||||
}
|
||||
|
||||
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;
|
||||
kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, true);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)mouseUp:(NSEvent*)event
|
||||
{
|
||||
(void)event;
|
||||
kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, false);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)rightMouseDown:(NSEvent*)event
|
||||
{
|
||||
(void)event;
|
||||
kCall(mouse_btn_func, MOUSE_BTN_2, window_data->mod_keys, true);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)rightMouseUp:(NSEvent*)event
|
||||
{
|
||||
(void)event;
|
||||
kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, false);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)otherMouseDown:(NSEvent *)event
|
||||
{
|
||||
(void)event;
|
||||
kCall(mouse_btn_func, [event buttonNumber], window_data->mod_keys, true);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)otherMouseUp:(NSEvent *)event
|
||||
{
|
||||
(void)event;
|
||||
kCall(mouse_btn_func, [event buttonNumber], window_data->mod_keys, false);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)event
|
||||
{
|
||||
kCall(mouse_wheel_func, window_data->mod_keys, [event deltaX], [event deltaY]);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (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
|
||||
{
|
||||
NSPoint point = [event locationInWindow];
|
||||
//NSPoint localPoint = [self convertPoint:point fromView:nil];
|
||||
window_data->mouse_pos_x = point.x;
|
||||
window_data->mouse_pos_y = point.y;
|
||||
kCall(mouse_move_func, point.x, point.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
|
||||
|
||||
|
22
src/macosx/WindowData_OSX.h
Normal file
22
src/macosx/WindowData_OSX.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <MiniFB_enums.h>
|
||||
#include <WindowData.h>
|
||||
|
||||
#if defined(USE_METAL_API)
|
||||
#include <MetalKit/MetalKit.h>
|
||||
#endif
|
||||
|
||||
@class OSXWindow;
|
||||
|
||||
typedef struct {
|
||||
OSXWindow *window;
|
||||
struct mfb_timer *timer;
|
||||
|
||||
#if defined(USE_METAL_API)
|
||||
struct {
|
||||
id<MTLCommandQueue> command_queue;
|
||||
id<MTLRenderPipelineState> pipeline_state;
|
||||
} metal;
|
||||
#endif
|
||||
} SWindowData_OSX;
|
File diff suppressed because it is too large
Load Diff
58
src/wayland/WindowData_Way.h
Normal file
58
src/wayland/WindowData_Way.h
Normal file
@ -0,0 +1,58 @@
|
||||
#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;
|
||||
|
||||
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;
|
||||
|
||||
struct wl_buffer *draw_buffer;
|
||||
uint32_t buffer_width;
|
||||
uint32_t buffer_height;
|
||||
uint32_t buffer_stride;
|
||||
|
||||
uint32_t mod_keys;
|
||||
struct mfb_timer *timer;
|
||||
bool close;
|
||||
} SWindowData_Way;
|
@ -1,146 +1,733 @@
|
||||
#include "MiniFB.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <MiniFB.h>
|
||||
#include <MiniFB_internal.h>
|
||||
#include <WindowData.h>
|
||||
#include "WindowData_Win.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static WNDCLASS s_wc;
|
||||
static HWND s_wnd;
|
||||
static int s_close = 0;
|
||||
static int s_width;
|
||||
static int s_height;
|
||||
static HDC s_hdc;
|
||||
static void* s_buffer;
|
||||
static BITMAPINFO* s_bitmapInfo;
|
||||
long s_window_style = WS_POPUP | WS_SYSMENU | WS_CAPTION;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LRESULT res = 0;
|
||||
uint32_t translate_mod();
|
||||
mfb_key translate_key(unsigned int wParam, unsigned long lParam);
|
||||
void destroy_window_data(SWindowData *window_data);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_PAINT:
|
||||
{
|
||||
if (s_buffer)
|
||||
{
|
||||
StretchDIBits(s_hdc, 0, 0, s_width, s_height, 0, 0, s_width, s_height, s_buffer,
|
||||
s_bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
|
||||
LRESULT CALLBACK
|
||||
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
LRESULT res = 0;
|
||||
|
||||
ValidateRect(hWnd, NULL);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
switch (message)
|
||||
{
|
||||
case WM_PAINT:
|
||||
{
|
||||
if (window_data && window_data->draw_buffer && window_data_win)
|
||||
{
|
||||
//if (window_data->dst_offset_x > 0) {
|
||||
// BitBlt(window_data_win->hdc, 0, window_data->dst_offset_y, window_data->dst_offset_x, window_data->dst_height, 0, 0, 0, BLACKNESS);
|
||||
//}
|
||||
//if (window_data->dst_offset_y > 0) {
|
||||
// BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->dst_offset_y, 0, 0, 0, BLACKNESS);
|
||||
//}
|
||||
//uint32_t offsetY = window_data->dst_offset_y + window_data->dst_height;
|
||||
//if (offsetY < window_data->window_height) {
|
||||
// BitBlt(window_data_win->hdc, 0, offsetY, window_data->window_width, window_data->window_height - offsetY, 0, 0, 0, BLACKNESS);
|
||||
//}
|
||||
//uint32_t offsetX = window_data->dst_offset_x + window_data->dst_width;
|
||||
//if (offsetX < window_data->window_width) {
|
||||
// BitBlt(window_data_win->hdc, offsetX, window_data->dst_offset_y, window_data->window_width - offsetX, window_data->dst_height, 0, 0, 0, BLACKNESS);
|
||||
//}
|
||||
|
||||
case WM_KEYDOWN:
|
||||
{
|
||||
if ((wParam&0xFF) == 27)
|
||||
s_close = 1;
|
||||
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;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_DESTROY:
|
||||
case WM_CLOSE:
|
||||
{
|
||||
if (window_data) {
|
||||
window_data->close = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_CLOSE:
|
||||
{
|
||||
s_close = 1;
|
||||
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();
|
||||
|
||||
default:
|
||||
{
|
||||
res = DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
if (key_code == KB_KEY_UNKNOWN)
|
||||
return FALSE;
|
||||
|
||||
return res;
|
||||
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;
|
||||
}
|
||||
}
|
||||
kCall(mouse_btn_func, button, window_data->mod_keys, is_pressed);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MOUSEWHEEL:
|
||||
if (window_data) {
|
||||
kCall(mouse_wheel_func, translate_mod(), 0.0f, (SHORT)HIWORD(wParam) / (float)WHEEL_DELTA);
|
||||
}
|
||||
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) {
|
||||
kCall(mouse_wheel_func, translate_mod(), -((SHORT)HIWORD(wParam) / (float)WHEEL_DELTA), 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) {
|
||||
window_data->dst_offset_x = 0;
|
||||
window_data->dst_offset_y = 0;
|
||||
window_data->dst_width = LOWORD(lParam);
|
||||
window_data->dst_height = HIWORD(lParam);
|
||||
window_data->window_width = window_data->dst_width;
|
||||
window_data->window_height = window_data->dst_height;
|
||||
BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->window_height, 0, 0, 0, BLACKNESS);
|
||||
kCall(resize_func, window_data->dst_width, window_data->dst_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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int mfb_open(const char* title, int width, int height)
|
||||
{
|
||||
RECT rect = { 0 };
|
||||
struct mfb_window *
|
||||
mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) {
|
||||
RECT rect = { 0 };
|
||||
int x = 0, y = 0;
|
||||
|
||||
s_wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
|
||||
s_wc.lpfnWndProc = WndProc;
|
||||
s_wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
s_wc.lpszClassName = title;
|
||||
RegisterClass(&s_wc);
|
||||
init_keycodes();
|
||||
|
||||
rect.right = width;
|
||||
rect.bottom = height;
|
||||
SWindowData *window_data = malloc(sizeof(SWindowData));
|
||||
if (window_data == 0x0) {
|
||||
return 0x0;
|
||||
}
|
||||
memset(window_data, 0, sizeof(SWindowData));
|
||||
|
||||
AdjustWindowRect(&rect, WS_POPUP | WS_SYSMENU | WS_CAPTION, 0);
|
||||
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;
|
||||
|
||||
rect.right -= rect.left;
|
||||
rect.bottom -= rect.top;
|
||||
window_data->buffer_width = width;
|
||||
window_data->buffer_height = height;
|
||||
window_data->buffer_stride = width * 4;
|
||||
|
||||
s_width = width;
|
||||
s_height = height;
|
||||
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);
|
||||
|
||||
s_wnd = CreateWindowEx(0,
|
||||
title, title,
|
||||
WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
rect.right, rect.bottom,
|
||||
0, 0, 0, 0);
|
||||
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 (!s_wnd)
|
||||
return 0;
|
||||
if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
|
||||
flags = WF_FULLSCREEN_DESKTOP;
|
||||
}
|
||||
}
|
||||
|
||||
ShowWindow(s_wnd, SW_NORMAL);
|
||||
if (flags & WF_BORDERLESS) {
|
||||
s_window_style = WS_POPUP;
|
||||
}
|
||||
|
||||
s_bitmapInfo = (BITMAPINFO*)calloc(1, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 3);
|
||||
s_bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
s_bitmapInfo->bmiHeader.biPlanes = 1;
|
||||
s_bitmapInfo->bmiHeader.biBitCount = 32;
|
||||
s_bitmapInfo->bmiHeader.biCompression = BI_BITFIELDS;
|
||||
s_bitmapInfo->bmiHeader.biWidth = width;
|
||||
s_bitmapInfo->bmiHeader.biHeight = -height;
|
||||
s_bitmapInfo->bmiColors[0].rgbRed = 0xff;
|
||||
s_bitmapInfo->bmiColors[1].rgbGreen = 0xff;
|
||||
s_bitmapInfo->bmiColors[2].rgbBlue = 0xff;
|
||||
if (flags & WF_RESIZABLE) {
|
||||
s_window_style |= WS_MAXIMIZEBOX | WS_SIZEBOX;
|
||||
}
|
||||
|
||||
s_hdc = GetDC(s_wnd);
|
||||
if (flags & WF_FULLSCREEN_DESKTOP) {
|
||||
s_window_style = WS_OVERLAPPEDWINDOW;
|
||||
|
||||
return 1;
|
||||
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)) {
|
||||
rect.right = width;
|
||||
rect.bottom = height;
|
||||
|
||||
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);
|
||||
|
||||
if (window_data->dst_width == 0)
|
||||
window_data->dst_width = width;
|
||||
|
||||
if (window_data->dst_height == 0)
|
||||
window_data->dst_height = 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->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;
|
||||
|
||||
window_data_win->hdc = GetDC(window_data_win->window);
|
||||
|
||||
window_data_win->timer = mfb_timer_create();
|
||||
|
||||
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
||||
|
||||
return (struct mfb_window *) window_data;
|
||||
}
|
||||
|
||||
struct mfb_window *
|
||||
mfb_open(const char *title, unsigned width, unsigned height) {
|
||||
return mfb_open_ex(title, width, height, 0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int mfb_update(void* buffer)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
s_buffer = buffer;
|
||||
mfb_update_state
|
||||
mfb_update(struct mfb_window *window, void *buffer) {
|
||||
MSG msg;
|
||||
|
||||
if (window == 0x0) {
|
||||
return STATE_INVALID_WINDOW;
|
||||
}
|
||||
|
||||
InvalidateRect(s_wnd, NULL, TRUE);
|
||||
SendMessage(s_wnd, WM_PAINT, 0, 0);
|
||||
SWindowData *window_data = (SWindowData *)window;
|
||||
if (window_data->close) {
|
||||
destroy_window_data(window_data);
|
||||
return STATE_EXIT;
|
||||
}
|
||||
|
||||
while (PeekMessage(&msg, s_wnd, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
if (buffer == 0x0) {
|
||||
return STATE_INVALID_BUFFER;
|
||||
}
|
||||
|
||||
if (s_close == 1)
|
||||
return -1;
|
||||
window_data->draw_buffer = buffer;
|
||||
|
||||
return 0;
|
||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
||||
InvalidateRect(window_data_win->window, 0x0, TRUE);
|
||||
SendMessage(window_data_win->window, WM_PAINT, 0, 0);
|
||||
|
||||
while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
return STATE_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void mfb_close()
|
||||
{
|
||||
s_buffer = 0;
|
||||
free(s_bitmapInfo);
|
||||
ReleaseDC(s_wnd, s_hdc);
|
||||
DestroyWindow(s_wnd);
|
||||
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;
|
||||
|
||||
bool
|
||||
mfb_wait_sync(struct mfb_window *window) {
|
||||
MSG msg;
|
||||
|
||||
if (window == 0x0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SWindowData *window_data = (SWindowData *)window;
|
||||
if (window_data->close) {
|
||||
destroy_window_data(window_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
||||
double current;
|
||||
uint32_t millis = 1;
|
||||
while (1) {
|
||||
if(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;
|
||||
}
|
||||
|
||||
current = mfb_timer_now(window_data_win->timer);;
|
||||
if (current >= g_time_for_frame) {
|
||||
mfb_timer_reset(window_data_win->timer);
|
||||
return true;
|
||||
}
|
||||
else if(current >= g_time_for_frame * 0.8) {
|
||||
millis = 0;
|
||||
}
|
||||
|
||||
Sleep(millis);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
destroy_window_data(SWindowData *window_data) {
|
||||
if (window_data == 0x0)
|
||||
return;
|
||||
|
||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
||||
|
||||
window_data->draw_buffer = 0x0;
|
||||
if (window_data_win->bitmapInfo != 0x0) {
|
||||
free(window_data_win->bitmapInfo);
|
||||
}
|
||||
|
||||
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;
|
||||
window_data_win->bitmapInfo = 0x0;
|
||||
mfb_timer_destroy(window_data_win->timer);
|
||||
window_data_win->timer = 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() {
|
||||
|
||||
// Clear keys
|
||||
for (size_t i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i)
|
||||
g_keycodes[i] = 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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
16
src/windows/WindowData_Win.h
Normal file
16
src/windows/WindowData_Win.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <MiniFB_enums.h>
|
||||
#include <stdint.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
HWND window;
|
||||
WNDCLASS wc;
|
||||
HDC hdc;
|
||||
BITMAPINFO *bitmapInfo;
|
||||
struct mfb_timer *timer;
|
||||
bool mouse_inside;
|
||||
} SWindowData_Win;
|
21
src/x11/WindowData_X11.h
Normal file
21
src/x11/WindowData_X11.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <MiniFB_enums.h>
|
||||
#include <stdint.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
Window window;
|
||||
|
||||
Display *display;
|
||||
int screen;
|
||||
GC gc;
|
||||
XImage *image;
|
||||
|
||||
void *image_buffer;
|
||||
XImage *image_scaler;
|
||||
uint32_t image_scaler_width;
|
||||
uint32_t image_scaler_height;
|
||||
struct mfb_timer *timer;
|
||||
} SWindowData_X11;
|
@ -1,148 +1,746 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <MiniFB.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define KEY_FUNCTION 0xFF
|
||||
#define KEY_ESC 0x1B
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static Display* s_display;
|
||||
static int s_screen;
|
||||
static int s_width;
|
||||
static int s_height;
|
||||
static Window s_window;
|
||||
static GC s_gc;
|
||||
static XImage *s_ximage;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int mfb_open(const char* title, int width, int height)
|
||||
{
|
||||
int depth, i, formatCount, convDepth = -1;
|
||||
XPixmapFormatValues* formats;
|
||||
XSetWindowAttributes windowAttributes;
|
||||
XSizeHints sizeHints;
|
||||
Visual* visual;
|
||||
|
||||
s_display = XOpenDisplay(0);
|
||||
|
||||
if (!s_display)
|
||||
return -1;
|
||||
|
||||
s_screen = DefaultScreen(s_display);
|
||||
visual = DefaultVisual(s_display, s_screen);
|
||||
formats = XListPixmapFormats(s_display, &formatCount);
|
||||
depth = DefaultDepth(s_display, s_screen);
|
||||
Window defaultRootWindow = DefaultRootWindow(s_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(s_display);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int screenWidth = DisplayWidth(s_display, s_screen);
|
||||
int screenHeight = DisplayHeight(s_display, s_screen);
|
||||
|
||||
windowAttributes.border_pixel = BlackPixel(s_display, s_screen);
|
||||
windowAttributes.background_pixel = BlackPixel(s_display, s_screen);
|
||||
windowAttributes.backing_store = NotUseful;
|
||||
|
||||
s_window = XCreateWindow(s_display, defaultRootWindow, (screenWidth - width) / 2,
|
||||
(screenHeight - height) / 2, width, height, 0, depth, InputOutput,
|
||||
visual, CWBackPixel | CWBorderPixel | CWBackingStore,
|
||||
&windowAttributes);
|
||||
if (!s_window)
|
||||
return 0;
|
||||
|
||||
XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask);
|
||||
XStoreName(s_display, s_window, title);
|
||||
|
||||
sizeHints.flags = PPosition | PMinSize | PMaxSize;
|
||||
sizeHints.x = 0;
|
||||
sizeHints.y = 0;
|
||||
sizeHints.min_width = width;
|
||||
sizeHints.max_width = width;
|
||||
sizeHints.min_height = height;
|
||||
sizeHints.max_height = height;
|
||||
|
||||
XSetWMNormalHints(s_display, s_window, &sizeHints);
|
||||
XClearWindow(s_display, s_window);
|
||||
XMapRaised(s_display, s_window);
|
||||
XFlush(s_display);
|
||||
|
||||
s_gc = DefaultGC(s_display, s_screen);
|
||||
|
||||
s_ximage = XCreateImage(s_display, CopyFromParent, depth, ZPixmap, 0, NULL, width, height, 32, width * 4);
|
||||
|
||||
s_width = width;
|
||||
s_height = height;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int processEvents()
|
||||
{
|
||||
XEvent event;
|
||||
KeySym sym;
|
||||
|
||||
if (!XPending(s_display))
|
||||
return 0;
|
||||
|
||||
XNextEvent(s_display, &event);
|
||||
|
||||
if (event.type != KeyPress)
|
||||
return 0;
|
||||
|
||||
sym = XLookupKeysym(&event.xkey, 0);
|
||||
|
||||
if ((sym >> 8) != KEY_FUNCTION)
|
||||
return 0;
|
||||
|
||||
if ((sym & 0xFF) == KEY_ESC)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int mfb_update(void* buffer)
|
||||
{
|
||||
s_ximage->data = (char*)buffer;
|
||||
|
||||
XPutImage(s_display, s_window, s_gc, s_ximage, 0, 0, 0, 0, s_width, s_height);
|
||||
XFlush(s_display);
|
||||
|
||||
if (processEvents() < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void mfb_close (void)
|
||||
{
|
||||
s_ximage->data = NULL;
|
||||
XDestroyImage(s_ximage);
|
||||
XDestroyWindow(s_display, s_window);
|
||||
XCloseDisplay(s_display);
|
||||
}
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/cursorfont.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"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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;
|
||||
window_data->dst_offset_x = 0;
|
||||
window_data->dst_offset_y = 0;
|
||||
window_data->dst_width = width;
|
||||
window_data->dst_height = 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;
|
||||
}
|
||||
|
||||
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->image = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, width, height, 32, width * 4);
|
||||
|
||||
window_data_x11->timer = mfb_timer_create();
|
||||
|
||||
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
||||
|
||||
printf("Window created using X11 API\n");
|
||||
|
||||
return (struct mfb_window *) window_data;
|
||||
}
|
||||
|
||||
struct mfb_window *
|
||||
mfb_open(const char *title, unsigned width, unsigned height) {
|
||||
return mfb_open_ex(title, width, height, 0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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);
|
||||
switch (button) {
|
||||
case Button1:
|
||||
case Button2:
|
||||
case Button3:
|
||||
kCall(mouse_btn_func, button, (mfb_key_mod) window_data->mod_keys, is_pressed);
|
||||
break;
|
||||
|
||||
case Button4:
|
||||
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, 1.0f);
|
||||
break;
|
||||
case Button5:
|
||||
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, -1.0f);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 1.0f, 0.0f);
|
||||
break;
|
||||
case 7:
|
||||
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, -1.0f, 0.0f);
|
||||
break;
|
||||
|
||||
default:
|
||||
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;
|
||||
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;
|
||||
|
||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
||||
XClearWindow(window_data_x11->display, window_data_x11->window);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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(struct mfb_window *window, void *buffer) {
|
||||
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_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
||||
|
||||
if (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);
|
||||
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;
|
||||
|
||||
bool
|
||||
mfb_wait_sync(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 false;
|
||||
}
|
||||
|
||||
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) {
|
||||
if(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;
|
||||
}
|
||||
|
||||
current = mfb_timer_now(window_data_x11->timer);
|
||||
if (current >= g_time_for_frame) {
|
||||
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();
|
||||
}
|
||||
|
||||
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 (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);
|
||||
}
|
||||
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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Reference in New Issue
Block a user