Experimental support for windows with per-pixel transparency (macOS, X11 and Windows).
This commit is contained in:
parent
ec110076ca
commit
ddae098dee
|
@ -332,6 +332,14 @@ void _OS::set_borderless_window(bool p_borderless) {
|
|||
OS::get_singleton()->set_borderless_window(p_borderless);
|
||||
}
|
||||
|
||||
bool _OS::get_window_per_pixel_transparency_enabled() const {
|
||||
return OS::get_singleton()->get_window_per_pixel_transparency_enabled();
|
||||
}
|
||||
|
||||
void _OS::set_window_per_pixel_transparency_enabled(bool p_enabled) {
|
||||
OS::get_singleton()->set_window_per_pixel_transparency_enabled(p_enabled);
|
||||
}
|
||||
|
||||
bool _OS::get_borderless_window() const {
|
||||
return OS::get_singleton()->get_borderless_window();
|
||||
}
|
||||
|
@ -1063,6 +1071,9 @@ void _OS::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_borderless_window", "borderless"), &_OS::set_borderless_window);
|
||||
ClassDB::bind_method(D_METHOD("get_borderless_window"), &_OS::get_borderless_window);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_window_per_pixel_transparency_enabled"), &_OS::get_window_per_pixel_transparency_enabled);
|
||||
ClassDB::bind_method(D_METHOD("set_window_per_pixel_transparency_enabled", "enabled"), &_OS::set_window_per_pixel_transparency_enabled);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_ime_position", "position"), &_OS::set_ime_position);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_screen_orientation", "orientation"), &_OS::set_screen_orientation);
|
||||
|
@ -1180,6 +1191,7 @@ void _OS::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor"), "set_screen_orientation", "get_screen_orientation");
|
||||
ADD_GROUP("Window", "window_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_borderless"), "set_borderless_window", "get_borderless_window");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_per_pixel_transparency_enabled"), "set_window_per_pixel_transparency_enabled", "get_window_per_pixel_transparency_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_fullscreen"), "set_window_fullscreen", "is_window_fullscreen");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_maximized"), "set_window_maximized", "is_window_maximized");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_minimized"), "set_window_minimized", "is_window_minimized");
|
||||
|
|
|
@ -179,6 +179,9 @@ public:
|
|||
virtual void set_borderless_window(bool p_borderless);
|
||||
virtual bool get_borderless_window() const;
|
||||
|
||||
virtual bool get_window_per_pixel_transparency_enabled() const;
|
||||
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
|
||||
|
||||
virtual void set_ime_position(const Point2 &p_pos);
|
||||
|
||||
Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);
|
||||
|
|
|
@ -672,6 +672,7 @@ OS::OS() {
|
|||
_render_thread_mode = RENDER_THREAD_SAFE;
|
||||
|
||||
_allow_hidpi = false;
|
||||
_allow_layered = false;
|
||||
_stack_bottom = (void *)(&stack_bottom);
|
||||
|
||||
_logger = NULL;
|
||||
|
|
13
core/os/os.h
13
core/os/os.h
|
@ -65,6 +65,7 @@ class OS {
|
|||
int _exit_code;
|
||||
int _orientation;
|
||||
bool _allow_hidpi;
|
||||
bool _allow_layered;
|
||||
bool _use_vsync;
|
||||
|
||||
char *last_error;
|
||||
|
@ -102,6 +103,8 @@ public:
|
|||
bool maximized;
|
||||
bool always_on_top;
|
||||
bool use_vsync;
|
||||
bool layered_splash;
|
||||
bool layered;
|
||||
float get_aspect() const { return (float)width / (float)height; }
|
||||
VideoMode(int p_width = 1024, int p_height = 600, bool p_fullscreen = false, bool p_resizable = true, bool p_borderless_window = false, bool p_maximized = false, bool p_always_on_top = false, bool p_use_vsync = false) {
|
||||
width = p_width;
|
||||
|
@ -112,6 +115,8 @@ public:
|
|||
maximized = p_maximized;
|
||||
always_on_top = p_always_on_top;
|
||||
use_vsync = p_use_vsync;
|
||||
layered = false;
|
||||
layered_splash = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -208,6 +213,13 @@ public:
|
|||
virtual void set_borderless_window(bool p_borderless) {}
|
||||
virtual bool get_borderless_window() { return 0; }
|
||||
|
||||
virtual bool get_window_per_pixel_transparency_enabled() const { return false; }
|
||||
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled) {}
|
||||
|
||||
virtual uint8_t *get_layered_buffer_data() { return NULL; }
|
||||
virtual Size2 get_layered_buffer_size() { return Size2(0, 0); }
|
||||
virtual void swap_layered_buffer() {}
|
||||
|
||||
virtual void set_ime_position(const Point2 &p_pos) {}
|
||||
virtual void set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp) {}
|
||||
|
||||
|
@ -468,6 +480,7 @@ public:
|
|||
virtual void force_process_input(){};
|
||||
bool has_feature(const String &p_feature);
|
||||
|
||||
bool is_layered_allowed() const { return _allow_layered; }
|
||||
bool is_hidpi_allowed() const { return _allow_hidpi; }
|
||||
OS();
|
||||
virtual ~OS();
|
||||
|
|
|
@ -316,7 +316,11 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c
|
|||
glViewport(0, 0, window_w, window_h);
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(GL_FALSE);
|
||||
glClearColor(p_color.r, p_color.g, p_color.b, p_color.a);
|
||||
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
} else {
|
||||
glClearColor(p_color.r, p_color.g, p_color.b, 1.0);
|
||||
}
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
canvas->canvas_begin();
|
||||
|
@ -340,6 +344,27 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c
|
|||
|
||||
storage->free(texture);
|
||||
|
||||
if (OS::get_singleton()->is_layered_allowed()) {
|
||||
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
|
||||
#ifdef WINDOWS_ENABLED
|
||||
Size2 wndsize = OS::get_singleton()->get_layered_buffer_size();
|
||||
uint8_t *data = OS::get_singleton()->get_layered_buffer_data();
|
||||
if (data) {
|
||||
glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data);
|
||||
OS::get_singleton()->swap_layered_buffer();
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
//clear alpha
|
||||
glColorMask(false, false, false, true);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glColorMask(true, true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
OS::get_singleton()->swap_buffers();
|
||||
}
|
||||
|
||||
|
@ -373,6 +398,28 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re
|
|||
}
|
||||
|
||||
void RasterizerGLES2::end_frame(bool p_swap_buffers) {
|
||||
|
||||
if (OS::get_singleton()->is_layered_allowed()) {
|
||||
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
|
||||
#ifdef WINDOWS_ENABLED
|
||||
Size2 wndsize = OS::get_singleton()->get_layered_buffer_size();
|
||||
uint8_t *data = OS::get_singleton()->get_layered_buffer_data();
|
||||
if (data) {
|
||||
glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data);
|
||||
OS::get_singleton()->swap_layered_buffer();
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
//clear alpha
|
||||
glColorMask(false, false, false, true);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glColorMask(true, true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (p_swap_buffers)
|
||||
OS::get_singleton()->swap_buffers();
|
||||
else
|
||||
|
|
|
@ -292,7 +292,11 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
|
|||
glViewport(0, 0, window_w, window_h);
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(GL_FALSE);
|
||||
glClearColor(p_color.r, p_color.g, p_color.b, 1.0);
|
||||
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
} else {
|
||||
glClearColor(p_color.r, p_color.g, p_color.b, 1.0);
|
||||
}
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
canvas->canvas_begin();
|
||||
|
||||
|
@ -331,6 +335,27 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
|
|||
|
||||
storage->free(texture); // free since it's only one frame that stays there
|
||||
|
||||
if (OS::get_singleton()->is_layered_allowed()) {
|
||||
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
|
||||
#ifdef WINDOWS_ENABLED
|
||||
Size2 wndsize = OS::get_singleton()->get_layered_buffer_size();
|
||||
uint8_t *data = OS::get_singleton()->get_layered_buffer_data();
|
||||
if (data) {
|
||||
glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data);
|
||||
OS::get_singleton()->swap_layered_buffer();
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
//clear alpha
|
||||
glColorMask(false, false, false, true);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glColorMask(true, true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
OS::get_singleton()->swap_buffers();
|
||||
}
|
||||
|
||||
|
@ -367,6 +392,27 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re
|
|||
|
||||
void RasterizerGLES3::end_frame(bool p_swap_buffers) {
|
||||
|
||||
if (OS::get_singleton()->is_layered_allowed()) {
|
||||
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
|
||||
#ifdef WINDOWS_ENABLED
|
||||
Size2 wndsize = OS::get_singleton()->get_layered_buffer_size();
|
||||
uint8_t *data = OS::get_singleton()->get_layered_buffer_data();
|
||||
if (data) {
|
||||
glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data);
|
||||
OS::get_singleton()->swap_layered_buffer();
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
//clear alpha
|
||||
glColorMask(false, false, false, true);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glColorMask(true, true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (p_swap_buffers)
|
||||
OS::get_singleton()->swap_buffers();
|
||||
else
|
||||
|
|
|
@ -874,7 +874,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
|
||||
}
|
||||
|
||||
OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/allow_per_pixel_transparency", false);
|
||||
|
||||
video_mode.use_vsync = GLOBAL_DEF("display/window/vsync/use_vsync", true);
|
||||
video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency", false);
|
||||
video_mode.layered_splash = GLOBAL_DEF("display/window/per_pixel_transparency_splash", false);
|
||||
|
||||
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation", 2);
|
||||
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation.mobile", 3);
|
||||
|
@ -882,6 +886,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
if (editor || project_manager) {
|
||||
// The editor and project manager always detect and use hiDPI if needed
|
||||
OS::get_singleton()->_allow_hidpi = true;
|
||||
OS::get_singleton()->_allow_layered = false;
|
||||
}
|
||||
|
||||
Engine::get_singleton()->_pixel_snap = GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false);
|
||||
|
|
|
@ -99,6 +99,8 @@ public:
|
|||
id pixelFormat;
|
||||
id context;
|
||||
|
||||
bool layered_window;
|
||||
|
||||
CursorShape cursor_shape;
|
||||
NSCursor *cursors[CURSOR_MAX];
|
||||
MouseMode mouse_mode;
|
||||
|
@ -226,6 +228,10 @@ public:
|
|||
|
||||
virtual void set_borderless_window(bool p_borderless);
|
||||
virtual bool get_borderless_window();
|
||||
|
||||
virtual bool get_window_per_pixel_transparency_enabled() const;
|
||||
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
|
||||
|
||||
virtual void set_ime_position(const Point2 &p_pos);
|
||||
virtual void set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp);
|
||||
|
||||
|
|
|
@ -1330,6 +1330,9 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
|
|||
|
||||
restore_rect = Rect2(get_window_position(), get_window_size());
|
||||
|
||||
if (p_desired.layered_splash) {
|
||||
set_window_per_pixel_transparency_enabled(true);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -2037,6 +2040,8 @@ void OS_OSX::set_window_size(const Size2 p_size) {
|
|||
void OS_OSX::set_window_fullscreen(bool p_enabled) {
|
||||
|
||||
if (zoomed != p_enabled) {
|
||||
if (layered_window)
|
||||
set_window_per_pixel_transparency_enabled(false);
|
||||
[window_object toggleFullScreen:nil];
|
||||
}
|
||||
zoomed = p_enabled;
|
||||
|
@ -2118,6 +2123,39 @@ void OS_OSX::request_attention() {
|
|||
[NSApp requestUserAttention:NSCriticalRequest];
|
||||
}
|
||||
|
||||
bool OS_OSX::get_window_per_pixel_transparency_enabled() const {
|
||||
|
||||
if (!is_layered_allowed()) return false;
|
||||
return layered_window;
|
||||
}
|
||||
|
||||
void OS_OSX::set_window_per_pixel_transparency_enabled(bool p_enabled) {
|
||||
|
||||
if (!is_layered_allowed()) return;
|
||||
if (layered_window != p_enabled) {
|
||||
if (p_enabled) {
|
||||
set_borderless_window(true);
|
||||
GLint opacity = 0;
|
||||
[window_object setBackgroundColor:[NSColor clearColor]];
|
||||
[window_object setOpaque:NO];
|
||||
[window_object setHasShadow:NO];
|
||||
[context setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity];
|
||||
layered_window = true;
|
||||
} else {
|
||||
GLint opacity = 1;
|
||||
[window_object setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1]];
|
||||
[window_object setOpaque:YES];
|
||||
[window_object setHasShadow:YES];
|
||||
[context setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity];
|
||||
layered_window = false;
|
||||
}
|
||||
[context update];
|
||||
NSRect frame = [window_object frame];
|
||||
[window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, 1, 1) display:YES];
|
||||
[window_object setFrame:frame display:YES];
|
||||
}
|
||||
}
|
||||
|
||||
void OS_OSX::set_borderless_window(bool p_borderless) {
|
||||
|
||||
// OrderOut prevents a lose focus bug with the window
|
||||
|
@ -2126,6 +2164,9 @@ void OS_OSX::set_borderless_window(bool p_borderless) {
|
|||
if (p_borderless) {
|
||||
[window_object setStyleMask:NSWindowStyleMaskBorderless];
|
||||
} else {
|
||||
if (layered_window)
|
||||
set_window_per_pixel_transparency_enabled(false);
|
||||
|
||||
[window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable];
|
||||
|
||||
// Force update of the window styles
|
||||
|
@ -2430,6 +2471,7 @@ OS_OSX::OS_OSX() {
|
|||
im_position = Point2();
|
||||
im_callback = NULL;
|
||||
im_target = NULL;
|
||||
layered_window = false;
|
||||
autoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
|
|
|
@ -623,6 +623,28 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
maximized = false;
|
||||
minimized = false;
|
||||
}
|
||||
if (is_layered_allowed() && layered_window) {
|
||||
DeleteObject(hBitmap);
|
||||
|
||||
RECT r;
|
||||
GetWindowRect(hWnd, &r);
|
||||
dib_size = Size2(r.right - r.left, r.bottom - r.top);
|
||||
|
||||
BITMAPINFO bmi;
|
||||
ZeroMemory(&bmi, sizeof(BITMAPINFO));
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = dib_size.x;
|
||||
bmi.bmiHeader.biHeight = dib_size.y;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
bmi.bmiHeader.biSizeImage = dib_size.x, dib_size.y * 4;
|
||||
hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, NULL, 0x0);
|
||||
SelectObject(hDC_dib, hBitmap);
|
||||
|
||||
ZeroMemory(dib_data, dib_size.x * dib_size.y * 4);
|
||||
}
|
||||
//return 0; // Jump Back
|
||||
} break;
|
||||
|
||||
case WM_ENTERSIZEMOVE: {
|
||||
|
@ -1137,6 +1159,9 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
|
|||
SetFocus(hWnd); // Sets Keyboard Focus To
|
||||
}
|
||||
|
||||
if (p_desired.layered_splash) {
|
||||
set_window_per_pixel_transparency_enabled(true);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -1524,6 +1549,9 @@ void OS_Windows::set_window_fullscreen(bool p_enabled) {
|
|||
if (video_mode.fullscreen == p_enabled)
|
||||
return;
|
||||
|
||||
if (layered_window)
|
||||
set_window_per_pixel_transparency_enabled(false);
|
||||
|
||||
if (p_enabled) {
|
||||
|
||||
if (pre_fs_valid) {
|
||||
|
@ -1628,10 +1656,97 @@ bool OS_Windows::is_window_always_on_top() const {
|
|||
return video_mode.always_on_top;
|
||||
}
|
||||
|
||||
bool OS_Windows::get_window_per_pixel_transparency_enabled() const {
|
||||
|
||||
if (!is_layered_allowed()) return false;
|
||||
return layered_window;
|
||||
}
|
||||
|
||||
void OS_Windows::set_window_per_pixel_transparency_enabled(bool p_enabled) {
|
||||
|
||||
if (!is_layered_allowed()) return;
|
||||
if (layered_window != p_enabled) {
|
||||
if (p_enabled) {
|
||||
set_borderless_window(true);
|
||||
//enable per-pixel alpha
|
||||
hDC_dib = CreateCompatibleDC(GetDC(hWnd));
|
||||
|
||||
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
|
||||
|
||||
RECT r;
|
||||
GetWindowRect(hWnd, &r);
|
||||
dib_size = Size2(r.right - r.left, r.bottom - r.top);
|
||||
|
||||
BITMAPINFO bmi;
|
||||
ZeroMemory(&bmi, sizeof(BITMAPINFO));
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = dib_size.x;
|
||||
bmi.bmiHeader.biHeight = dib_size.y;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
bmi.bmiHeader.biSizeImage = dib_size.x * dib_size.y * 4;
|
||||
hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, NULL, 0x0);
|
||||
SelectObject(hDC_dib, hBitmap);
|
||||
|
||||
ZeroMemory(dib_data, dib_size.x * dib_size.y * 4);
|
||||
|
||||
layered_window = true;
|
||||
} else {
|
||||
//disable per-pixel alpha
|
||||
layered_window = false;
|
||||
|
||||
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
|
||||
|
||||
//cleanup
|
||||
DeleteObject(hBitmap);
|
||||
DeleteDC(hDC_dib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *OS_Windows::get_layered_buffer_data() {
|
||||
|
||||
return (is_layered_allowed() && layered_window) ? dib_data : NULL;
|
||||
}
|
||||
|
||||
Size2 OS_Windows::get_layered_buffer_size() {
|
||||
|
||||
return (is_layered_allowed() && layered_window) ? dib_size : Size2();
|
||||
}
|
||||
|
||||
void OS_Windows::swap_layered_buffer() {
|
||||
|
||||
if (is_layered_allowed() && layered_window) {
|
||||
|
||||
//premultiply alpha
|
||||
for (int y = 0; y < dib_size.y; y++) {
|
||||
for (int x = 0; x < dib_size.x; x++) {
|
||||
float alpha = (float)dib_data[y * (int)dib_size.x * 4 + x * 4 + 3] / (float)0xFF;
|
||||
dib_data[y * (int)dib_size.x * 4 + x * 4 + 0] *= alpha;
|
||||
dib_data[y * (int)dib_size.x * 4 + x * 4 + 1] *= alpha;
|
||||
dib_data[y * (int)dib_size.x * 4 + x * 4 + 2] *= alpha;
|
||||
}
|
||||
}
|
||||
//swap layered window buffer
|
||||
POINT ptSrc = { 0, 0 };
|
||||
SIZE sizeWnd = { (long)dib_size.x, (long)dib_size.y };
|
||||
BLENDFUNCTION bf;
|
||||
bf.BlendOp = AC_SRC_OVER;
|
||||
bf.BlendFlags = 0;
|
||||
bf.AlphaFormat = AC_SRC_ALPHA;
|
||||
bf.SourceConstantAlpha = 0xFF;
|
||||
UpdateLayeredWindow(hWnd, NULL, NULL, &sizeWnd, hDC_dib, &ptSrc, 0, &bf, ULW_ALPHA);
|
||||
}
|
||||
}
|
||||
|
||||
void OS_Windows::set_borderless_window(bool p_borderless) {
|
||||
if (video_mode.borderless_window == p_borderless)
|
||||
return;
|
||||
|
||||
if (!p_borderless && layered_window)
|
||||
set_window_per_pixel_transparency_enabled(false);
|
||||
|
||||
video_mode.borderless_window = p_borderless;
|
||||
|
||||
_update_window_style();
|
||||
|
@ -2558,6 +2673,8 @@ Error OS_Windows::move_to_trash(const String &p_path) {
|
|||
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
|
||||
|
||||
key_event_pos = 0;
|
||||
layered_window = false;
|
||||
hBitmap = NULL;
|
||||
force_quit = false;
|
||||
alt_mem = false;
|
||||
gr_mem = false;
|
||||
|
@ -2591,6 +2708,10 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
|
|||
}
|
||||
|
||||
OS_Windows::~OS_Windows() {
|
||||
if (is_layered_allowed() && layered_window) {
|
||||
DeleteObject(hBitmap);
|
||||
DeleteDC(hDC_dib);
|
||||
}
|
||||
#ifdef STDOUT_FILE
|
||||
fclose(stdo);
|
||||
#endif
|
||||
|
|
|
@ -93,6 +93,12 @@ class OS_Windows : public OS {
|
|||
HINSTANCE hInstance; // Holds The Instance Of The Application
|
||||
HWND hWnd;
|
||||
|
||||
HBITMAP hBitmap; //DIB section for layered window
|
||||
uint8_t *dib_data;
|
||||
Size2 dib_size;
|
||||
HDC hDC_dib;
|
||||
bool layered_window;
|
||||
|
||||
uint32_t move_timer_id;
|
||||
|
||||
HCURSOR hCursor;
|
||||
|
@ -212,6 +218,13 @@ public:
|
|||
virtual void set_borderless_window(bool p_borderless);
|
||||
virtual bool get_borderless_window();
|
||||
|
||||
virtual bool get_window_per_pixel_transparency_enabled() const;
|
||||
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
|
||||
|
||||
virtual uint8_t *get_layered_buffer_data();
|
||||
virtual Size2 get_layered_buffer_size();
|
||||
virtual void swap_layered_buffer();
|
||||
|
||||
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
|
||||
virtual Error close_dynamic_library(void *p_library_handle);
|
||||
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false);
|
||||
|
|
|
@ -116,32 +116,76 @@ Error ContextGL_X11::initialize() {
|
|||
None
|
||||
};
|
||||
|
||||
static int visual_attribs_layered[] = {
|
||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||
GLX_DOUBLEBUFFER, true,
|
||||
GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
GLX_ALPHA_SIZE, 8,
|
||||
GLX_DEPTH_SIZE, 24,
|
||||
None
|
||||
};
|
||||
|
||||
int fbcount;
|
||||
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
|
||||
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
|
||||
GLXFBConfig fbconfig;
|
||||
XVisualInfo *vi = NULL;
|
||||
|
||||
XVisualInfo *vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
|
||||
if (OS::get_singleton()->is_layered_allowed()) {
|
||||
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
|
||||
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
|
||||
|
||||
XSetWindowAttributes swa;
|
||||
for (int i = 0; i < fbcount; i++) {
|
||||
vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]);
|
||||
if (!vi)
|
||||
continue;
|
||||
|
||||
swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
|
||||
swa.border_pixel = 0;
|
||||
swa.event_mask = StructureNotifyMask;
|
||||
XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi->visual);
|
||||
if (!pict_format) {
|
||||
XFree(vi);
|
||||
vi = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
char* windowid = getenv("GODOT_WINDOWID");
|
||||
if (windowid) {
|
||||
fbconfig = fbc[i];
|
||||
if (pict_format->direct.alphaMask > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
|
||||
|
||||
XSetWindowAttributes swa;
|
||||
|
||||
swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
|
||||
swa.border_pixel = 0;
|
||||
swa.background_pixmap = None;
|
||||
swa.background_pixel = 0;
|
||||
swa.border_pixmap = None;
|
||||
swa.event_mask = StructureNotifyMask;
|
||||
|
||||
x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask | CWBackPixel, &swa);
|
||||
|
||||
//freopen("/home/punto/stdout", "w", stdout);
|
||||
//reopen("/home/punto/stderr", "w", stderr);
|
||||
x11_window = atol(windowid);
|
||||
} else {
|
||||
*/
|
||||
x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa);
|
||||
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
|
||||
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
|
||||
|
||||
vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
|
||||
|
||||
fbconfig = fbc[0];
|
||||
|
||||
XSetWindowAttributes swa;
|
||||
|
||||
swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
|
||||
swa.border_pixel = 0;
|
||||
swa.event_mask = StructureNotifyMask;
|
||||
|
||||
x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED);
|
||||
set_class_hint(x11_display, x11_window);
|
||||
XMapWindow(x11_display, x11_window);
|
||||
//};
|
||||
|
||||
int (*oldHandler)(Display *, XErrorEvent *) =
|
||||
XSetErrorHandler(&ctxErrorHandler);
|
||||
|
@ -160,7 +204,7 @@ Error ContextGL_X11::initialize() {
|
|||
None
|
||||
};
|
||||
|
||||
p->glx_context = glXCreateContextAttribsARB(x11_display, fbc[0], NULL, true, context_attribs);
|
||||
p->glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, NULL, true, context_attribs);
|
||||
ERR_EXPLAIN("Could not obtain an OpenGL 3.0 context!");
|
||||
ERR_FAIL_COND_V(!p->glx_context, ERR_UNCONFIGURED);
|
||||
} break;
|
||||
|
@ -175,7 +219,7 @@ Error ContextGL_X11::initialize() {
|
|||
None
|
||||
};
|
||||
|
||||
p->glx_context = glXCreateContextAttribsARB(x11_display, fbc[0], NULL, true, context_attribs);
|
||||
p->glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, NULL, true, context_attribs);
|
||||
ERR_EXPLAIN("Could not obtain an OpenGL 3.3 context!");
|
||||
ERR_FAIL_COND_V(ctxErrorOccurred || !p->glx_context, ERR_UNCONFIGURED);
|
||||
} break;
|
||||
|
@ -195,7 +239,6 @@ Error ContextGL_X11::initialize() {
|
|||
//glXMakeCurrent(x11_display, None, NULL);
|
||||
|
||||
XFree(vi);
|
||||
XFree(fbc);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "drivers/gl_context/context_gl.h"
|
||||
#include "os/os.h"
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
|
||||
struct ContextGL_X11_Private;
|
||||
|
||||
|
|
|
@ -42,6 +42,11 @@ def can_build():
|
|||
print("xrandr not found.. x11 disabled.")
|
||||
return False
|
||||
|
||||
x11_error = os.system("pkg-config xrender --modversion > /dev/null ")
|
||||
if (x11_error):
|
||||
print("xrender not found.. x11 disabled.")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_opts():
|
||||
|
@ -141,6 +146,7 @@ def configure(env):
|
|||
env.ParseConfig('pkg-config xcursor --cflags --libs')
|
||||
env.ParseConfig('pkg-config xinerama --cflags --libs')
|
||||
env.ParseConfig('pkg-config xrandr --cflags --libs')
|
||||
env.ParseConfig('pkg-config xrender --cflags --libs')
|
||||
|
||||
if (env['touch']):
|
||||
x11_error = os.system("pkg-config xi --modversion > /dev/null ")
|
||||
|
|
|
@ -517,6 +517,10 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
|
|||
|
||||
power_manager = memnew(PowerX11);
|
||||
|
||||
if (p_desired.layered_splash) {
|
||||
set_window_per_pixel_transparency_enabled(true);
|
||||
}
|
||||
|
||||
XEvent xevent;
|
||||
while (XPending(x11_display) > 0) {
|
||||
XNextEvent(x11_display, &xevent);
|
||||
|
@ -707,6 +711,25 @@ Point2 OS_X11::get_mouse_position() const {
|
|||
return last_mouse_pos;
|
||||
}
|
||||
|
||||
bool OS_X11::get_window_per_pixel_transparency_enabled() const {
|
||||
|
||||
if (!is_layered_allowed()) return false;
|
||||
return layered_window;
|
||||
}
|
||||
|
||||
void OS_X11::set_window_per_pixel_transparency_enabled(bool p_enabled) {
|
||||
|
||||
if (!is_layered_allowed()) return;
|
||||
if (layered_window != p_enabled) {
|
||||
if (p_enabled) {
|
||||
set_borderless_window(true);
|
||||
layered_window = true;
|
||||
} else {
|
||||
layered_window = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OS_X11::set_window_title(const String &p_title) {
|
||||
XStoreName(x11_display, x11_window, p_title.utf8().get_data());
|
||||
|
||||
|
@ -1006,9 +1029,13 @@ void OS_X11::set_window_size(const Size2 p_size) {
|
|||
}
|
||||
|
||||
void OS_X11::set_window_fullscreen(bool p_enabled) {
|
||||
|
||||
if (current_videomode.fullscreen == p_enabled)
|
||||
return;
|
||||
|
||||
if (layered_window)
|
||||
set_window_per_pixel_transparency_enabled(false);
|
||||
|
||||
if (p_enabled && current_videomode.always_on_top) {
|
||||
// Fullscreen + Always-on-top requires a maximized window on some window managers (Metacity)
|
||||
set_window_maximized(true);
|
||||
|
@ -1254,6 +1281,9 @@ void OS_X11::set_borderless_window(bool p_borderless) {
|
|||
if (current_videomode.borderless_window == p_borderless)
|
||||
return;
|
||||
|
||||
if (!p_borderless && layered_window)
|
||||
set_window_per_pixel_transparency_enabled(false);
|
||||
|
||||
current_videomode.borderless_window = p_borderless;
|
||||
|
||||
Hints hints;
|
||||
|
@ -2698,6 +2728,7 @@ OS_X11::OS_X11() {
|
|||
AudioDriverManager::add_driver(&driver_alsa);
|
||||
#endif
|
||||
|
||||
layered_window = false;
|
||||
minimized = false;
|
||||
xim_style = 0L;
|
||||
mouse_mode = MOUSE_MODE_VISIBLE;
|
||||
|
|
|
@ -171,6 +171,8 @@ class OS_X11 : public OS_Unix {
|
|||
|
||||
PowerX11 *power_manager;
|
||||
|
||||
bool layered_window;
|
||||
|
||||
CrashHandler crash_handler;
|
||||
|
||||
int audio_driver_index;
|
||||
|
@ -262,6 +264,10 @@ public:
|
|||
|
||||
virtual void set_borderless_window(bool p_borderless);
|
||||
virtual bool get_borderless_window();
|
||||
|
||||
virtual bool get_window_per_pixel_transparency_enabled() const;
|
||||
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
|
||||
|
||||
virtual void set_ime_position(const Point2 &p_pos);
|
||||
|
||||
virtual String get_unique_id() const;
|
||||
|
|
Loading…
Reference in New Issue