mirror of
https://github.com/IllusionMan1212/O2048.git
synced 2026-10-24 10:12:37 +00:00
zephr/os/windows: create window and gl context
This commit is contained in:
@@ -1,3 +1,8 @@
|
|||||||
|
.vscode
|
||||||
|
.vs
|
||||||
o2048
|
o2048
|
||||||
|
o2048.exe
|
||||||
|
o2048.pdb
|
||||||
|
o2048.res
|
||||||
ols.json
|
ols.json
|
||||||
o2048.log
|
o2048.log
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
Binary file not shown.
+21
-10
@@ -16,8 +16,7 @@ FT_Int :: c.int
|
|||||||
FT_UInt :: c.uint
|
FT_UInt :: c.uint
|
||||||
@private
|
@private
|
||||||
FT_Long :: c.long
|
FT_Long :: c.long
|
||||||
@private
|
ULong :: c.ulong
|
||||||
FT_ULong :: c.ulong
|
|
||||||
@private
|
@private
|
||||||
FT_String :: c.char
|
FT_String :: c.char
|
||||||
@private
|
@private
|
||||||
@@ -87,6 +86,8 @@ LoadFlags :: enum {
|
|||||||
FT_LOAD_TARGET_LCD_V = (int(FT_Render_Mode_.LCD_V) & 15) << 16,
|
FT_LOAD_TARGET_LCD_V = (int(FT_Render_Mode_.LCD_V) & 15) << 16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#assert(size_of(OutlineFlags) == 8)
|
||||||
|
|
||||||
@private
|
@private
|
||||||
OutlineFlags :: enum {
|
OutlineFlags :: enum {
|
||||||
NONE = 0x0,
|
NONE = 0x0,
|
||||||
@@ -144,7 +145,7 @@ FT_CharMapRec_ :: struct {
|
|||||||
@private
|
@private
|
||||||
FT_CharMap :: ^FT_CharMapRec_
|
FT_CharMap :: ^FT_CharMapRec_
|
||||||
|
|
||||||
#assert(size_of(FT_Bitmap_Size) == 32)
|
#assert(size_of(FT_Bitmap_Size) == (16 when (size_of(FT_Pos) == 4) else 32))
|
||||||
|
|
||||||
@private
|
@private
|
||||||
FT_Bitmap_Size :: struct {
|
FT_Bitmap_Size :: struct {
|
||||||
@@ -180,7 +181,7 @@ FT_Vector :: struct {
|
|||||||
x, y: FT_Pos,
|
x, y: FT_Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
#assert(size_of(FT_Glyph_Metrics) == 64)
|
#assert(size_of(FT_Glyph_Metrics) == (32 when (size_of(FT_Pos) == 4) else 64))
|
||||||
|
|
||||||
@private
|
@private
|
||||||
FT_Glyph_Metrics :: struct {
|
FT_Glyph_Metrics :: struct {
|
||||||
@@ -210,6 +211,8 @@ FT_Outline :: struct {
|
|||||||
flags: OutlineFlags,
|
flags: OutlineFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#assert(size_of(FT_Glyph_Format) == 8)
|
||||||
|
|
||||||
@private
|
@private
|
||||||
FT_Glyph_Format :: enum {
|
FT_Glyph_Format :: enum {
|
||||||
NONE = (0 << 24) | (0 << 16) | (0 << 8) | 0,
|
NONE = (0 << 24) | (0 << 16) | (0 << 8) | 0,
|
||||||
@@ -220,9 +223,11 @@ FT_Glyph_Format :: enum {
|
|||||||
PLOTTER = ('p' << 24) | ('l' << 16) | ('o' << 8) | 't'
|
PLOTTER = ('p' << 24) | ('l' << 16) | ('o' << 8) | 't'
|
||||||
}
|
}
|
||||||
|
|
||||||
#assert(size_of(FT_GlyphSlotRec_) == 304)
|
// linux: 304
|
||||||
|
// windows: 248
|
||||||
|
// windows: 236 packed
|
||||||
|
#assert(size_of(FT_GlyphSlotRec_) == (248 when ODIN_OS == .Windows else 304))
|
||||||
|
|
||||||
@private
|
|
||||||
FT_GlyphSlotRec_ :: struct {
|
FT_GlyphSlotRec_ :: struct {
|
||||||
library: Library,
|
library: Library,
|
||||||
face: Face,
|
face: Face,
|
||||||
@@ -247,7 +252,7 @@ FT_GlyphSlotRec_ :: struct {
|
|||||||
subglyphs: FT_SubGlyph,
|
subglyphs: FT_SubGlyph,
|
||||||
|
|
||||||
control_data: rawptr,
|
control_data: rawptr,
|
||||||
control_len: i64,
|
control_len: c.long,
|
||||||
|
|
||||||
lsb_delta: FT_Pos,
|
lsb_delta: FT_Pos,
|
||||||
rsb_delta: FT_Pos,
|
rsb_delta: FT_Pos,
|
||||||
@@ -260,7 +265,7 @@ FT_GlyphSlotRec_ :: struct {
|
|||||||
@private
|
@private
|
||||||
FT_GlyphSlot :: ^FT_GlyphSlotRec_
|
FT_GlyphSlot :: ^FT_GlyphSlotRec_
|
||||||
|
|
||||||
#assert(size_of(FT_Size_Metrics) == 56)
|
#assert(size_of(FT_Size_Metrics) == (28 when size_of(FT_Pos) == 4 else 56))
|
||||||
|
|
||||||
@private
|
@private
|
||||||
FT_Size_Metrics :: struct {
|
FT_Size_Metrics :: struct {
|
||||||
@@ -276,7 +281,10 @@ FT_Size_Metrics :: struct {
|
|||||||
max_advance: FT_Pos, /* max horizontal advance, in 26.6 pixels */
|
max_advance: FT_Pos, /* max horizontal advance, in 26.6 pixels */
|
||||||
}
|
}
|
||||||
|
|
||||||
#assert(size_of(FT_SizeRec) == 88)
|
// linux: 88
|
||||||
|
// windows: 64 (has 4 bytes padding)
|
||||||
|
// windows: 60 packed
|
||||||
|
#assert(size_of(FT_SizeRec) == (64 when ODIN_OS == .Windows else 88))
|
||||||
|
|
||||||
@private
|
@private
|
||||||
FT_SizeRec :: struct {
|
FT_SizeRec :: struct {
|
||||||
@@ -343,7 +351,10 @@ FT_ListRec :: struct {
|
|||||||
tail: FT_ListNode,
|
tail: FT_ListNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
#assert(size_of(FT_FaceRec_) == 248)
|
// linux: 248
|
||||||
|
// windows: 216
|
||||||
|
// windows packed: 204
|
||||||
|
#assert(size_of(FT_FaceRec_) == 216)
|
||||||
|
|
||||||
@private
|
@private
|
||||||
FT_FaceRec_ :: struct {
|
FT_FaceRec_ :: struct {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
// based on system packaged freetype 2.11.1 on Ubuntu 22.04
|
||||||
|
// @INCOMPLETE
|
||||||
package freetype
|
package freetype
|
||||||
|
|
||||||
foreign import freetype "system:freetype"
|
when ODIN_OS == .Linux { foreign import freetype "system:freetype" }
|
||||||
|
when ODIN_OS == .Windows { foreign import freetype "libs/freetype.lib" }
|
||||||
|
|
||||||
foreign freetype {
|
foreign freetype {
|
||||||
@(link_name = "FT_Init_FreeType")
|
@(link_name = "FT_Init_FreeType")
|
||||||
@@ -10,7 +13,7 @@ foreign freetype {
|
|||||||
@(link_name = "FT_Set_Pixel_Sizes")
|
@(link_name = "FT_Set_Pixel_Sizes")
|
||||||
Set_Pixel_Sizes :: proc(face: Face, pixel_width: FT_UInt, pixel_height: FT_UInt) -> FT_Error ---
|
Set_Pixel_Sizes :: proc(face: Face, pixel_width: FT_UInt, pixel_height: FT_UInt) -> FT_Error ---
|
||||||
@(link_name = "FT_Load_Char")
|
@(link_name = "FT_Load_Char")
|
||||||
Load_Char :: proc(face: Face, char_code: FT_ULong, load_flags: LoadFlags) -> FT_Error ---
|
Load_Char :: proc(face: Face, char_code: ULong, load_flags: LoadFlags) -> FT_Error ---
|
||||||
@(link_name = "FT_Done_Face")
|
@(link_name = "FT_Done_Face")
|
||||||
Done_Face :: proc(face: Face) -> FT_Error ---
|
Done_Face :: proc(face: Face) -> FT_Error ---
|
||||||
@(link_name = "FT_Done_FreeType")
|
@(link_name = "FT_Done_FreeType")
|
||||||
|
|||||||
+11
-10
@@ -1,19 +1,20 @@
|
|||||||
|
// +build linux
|
||||||
package glx
|
package glx
|
||||||
|
|
||||||
import x11 "vendor:x11/xlib"
|
import x11 "vendor:x11/xlib"
|
||||||
|
|
||||||
Drawable :: x11.XID
|
Drawable :: x11.XID
|
||||||
|
|
||||||
RENDER_TYPE :: 0x8011
|
RENDER_TYPE :: 0x8011
|
||||||
RGBA_BIT :: 0x00000001
|
RGBA_BIT :: 0x00000001
|
||||||
RED_SIZE :: 8
|
RED_SIZE :: 8
|
||||||
GREEN_SIZE :: 9
|
GREEN_SIZE :: 9
|
||||||
BLUE_SIZE :: 10
|
BLUE_SIZE :: 10
|
||||||
ALPHA_SIZE :: 11
|
ALPHA_SIZE :: 11
|
||||||
DEPTH_SIZE :: 12
|
DEPTH_SIZE :: 12
|
||||||
DOUBLEBUFFER :: 5
|
DOUBLEBUFFER :: 5
|
||||||
SAMPLES :: 100001
|
SAMPLES :: 100001
|
||||||
CONTEXT_MAJOR_VERSION_ARB :: 0x2091
|
CONTEXT_MAJOR_VERSION_ARB :: 0x2091
|
||||||
CONTEXT_MINOR_VERSION_ARB :: 0x2092
|
CONTEXT_MINOR_VERSION_ARB :: 0x2092
|
||||||
CONTEXT_PROFILE_MASK_ARB :: 0x9126
|
CONTEXT_PROFILE_MASK_ARB :: 0x9126
|
||||||
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001
|
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// +build linux
|
||||||
package glx
|
package glx
|
||||||
|
|
||||||
import x11 "vendor:x11/xlib"
|
import x11 "vendor:x11/xlib"
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import gl "vendor:OpenGL"
|
|
||||||
import "glx"
|
|
||||||
import "zephr"
|
import "zephr"
|
||||||
|
|
||||||
font_path :: "assets/fonts/Rubik/Rubik-VariableFont_wght.ttf"
|
font_path :: "assets/fonts/Rubik/Rubik-VariableFont_wght.ttf"
|
||||||
icon_path :: "assets/icon-128x128.png"
|
when ODIN_OS == .Windows {icon_path :: "assets/icon-128x128.ico"}
|
||||||
|
when ODIN_OS == .Linux {icon_path :: "assets/icon-128x128.png"}
|
||||||
title :: "2048"
|
title :: "2048"
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
@@ -15,4 +14,3 @@ main :: proc() {
|
|||||||
|
|
||||||
zephr.deinit()
|
zephr.deinit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// +build linux
|
||||||
package xcursor
|
package xcursor
|
||||||
|
|
||||||
import x11 "vendor:x11/xlib"
|
import x11 "vendor:x11/xlib"
|
||||||
|
|||||||
@@ -0,0 +1,529 @@
|
|||||||
|
// +build linux
|
||||||
|
// +private
|
||||||
|
package zephr
|
||||||
|
|
||||||
|
import x11 "vendor:x11/xlib"
|
||||||
|
|
||||||
|
import "../glx"
|
||||||
|
import "../xcursor"
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
PropModeReplace :: 0
|
||||||
|
@(private="file")
|
||||||
|
XA_ATOM :: x11.Atom(4)
|
||||||
|
@(private="file")
|
||||||
|
XA_STRING :: x11.Atom(31)
|
||||||
|
@(private="file")
|
||||||
|
XA_CARDINAL :: x11.Atom(6)
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
x11_display : ^x11.Display
|
||||||
|
@(private="file")
|
||||||
|
x11_window : x11.Window
|
||||||
|
@(private="file")
|
||||||
|
x11_colormap : x11.Colormap
|
||||||
|
@(private="file")
|
||||||
|
glx_context : glx.Context
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
x11_go_fullscreen :: proc() {
|
||||||
|
// remove the resizing constraint before going fullscreen so WMs such as gnome
|
||||||
|
// can add the _NET_WM_ACTION_FULLSCREEN action to the _NET_WM_ALLOWED_ACTIONS atom
|
||||||
|
// and properly fullscreen the window
|
||||||
|
size_hints := x11.XAllocSizeHints()
|
||||||
|
|
||||||
|
zephr_ctx.window.pre_fullscreen_size.x = zephr_ctx.window.size.x
|
||||||
|
zephr_ctx.window.pre_fullscreen_size.y = zephr_ctx.window.size.y
|
||||||
|
if (size_hints != nil) {
|
||||||
|
size_hints.flags = {.PPosition, .PSize}
|
||||||
|
size_hints.width = cast(i32)zephr_ctx.window.size.x
|
||||||
|
size_hints.height = cast(i32)zephr_ctx.window.size.y
|
||||||
|
x11.XSetWMNormalHints(x11_display, x11_window, size_hints)
|
||||||
|
x11.XFree(size_hints)
|
||||||
|
}
|
||||||
|
|
||||||
|
xev: x11.XEvent
|
||||||
|
wm_state := x11.XInternAtom(x11_display, "_NET_WM_STATE", false)
|
||||||
|
fullscreen := x11.XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", false)
|
||||||
|
xev.type = .ClientMessage
|
||||||
|
xev.xclient.window = x11_window
|
||||||
|
xev.xclient.message_type = wm_state
|
||||||
|
xev.xclient.format = 32
|
||||||
|
xev.xclient.data.l[0] = 1 // _NET_WM_STATE_ADD
|
||||||
|
xev.xclient.data.l[1] = cast(int)fullscreen
|
||||||
|
xev.xclient.data.l[2] = 0
|
||||||
|
x11.XSendEvent(x11_display, x11.XDefaultRootWindow(x11_display), false,
|
||||||
|
{.SubstructureNotify, .SubstructureRedirect}, &xev)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
x11_return_fullscreen :: proc() {
|
||||||
|
xev: x11.XEvent
|
||||||
|
wm_state := x11.XInternAtom(x11_display, "_NET_WM_STATE", false)
|
||||||
|
fullscreen := x11.XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", false)
|
||||||
|
xev.type = .ClientMessage
|
||||||
|
xev.xclient.window = x11_window
|
||||||
|
xev.xclient.message_type = wm_state
|
||||||
|
xev.xclient.format = 32
|
||||||
|
xev.xclient.data.l[0] = 0 // _NET_WM_STATE_REMOVE
|
||||||
|
xev.xclient.data.l[1] = cast(int)fullscreen
|
||||||
|
xev.xclient.data.l[2] = 0
|
||||||
|
x11.XSendEvent(x11_display, x11.XDefaultRootWindow(x11_display), false,
|
||||||
|
{.SubstructureNotify, .SubstructureRedirect}, &xev)
|
||||||
|
|
||||||
|
// restore the resizing constraint as well as the pre-fullscreen window size
|
||||||
|
// when returning from fullscreen
|
||||||
|
size_hints := x11.XAllocSizeHints()
|
||||||
|
|
||||||
|
if (size_hints != nil) {
|
||||||
|
size_hints.flags = {.PPosition, .PSize}
|
||||||
|
size_hints.width = cast(i32)zephr_ctx.window.pre_fullscreen_size.x
|
||||||
|
size_hints.height = cast(i32)zephr_ctx.window.pre_fullscreen_size.y
|
||||||
|
if (zephr_ctx.window.non_resizable) {
|
||||||
|
size_hints.flags |= {.PMinSize, .PMaxSize}
|
||||||
|
size_hints.min_width = cast(i32)zephr_ctx.window.pre_fullscreen_size.x
|
||||||
|
size_hints.min_height = cast(i32)zephr_ctx.window.pre_fullscreen_size.y
|
||||||
|
size_hints.max_width = cast(i32)zephr_ctx.window.pre_fullscreen_size.x
|
||||||
|
size_hints.max_height = cast(i32)zephr_ctx.window.pre_fullscreen_size.y
|
||||||
|
}
|
||||||
|
x11.XSetWMNormalHints(x11_display, x11_window, size_hints)
|
||||||
|
x11.XFree(size_hints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_toggle_fullscreen :: proc(fullscreen: bool) {
|
||||||
|
if fullscreen {
|
||||||
|
x11_return_fullscreen()
|
||||||
|
} else {
|
||||||
|
x11_go_fullscreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
x11_assign_window_icon :: proc(icon_path: cstring, window_title: cstring) {
|
||||||
|
icon_width, icon_height: i32
|
||||||
|
icon_data := image.load(icon_path, &icon_width, &icon_height, nil, 4)
|
||||||
|
defer image.image_free(icon_data)
|
||||||
|
assert(icon_data != nil, "Failed to load icon image")
|
||||||
|
|
||||||
|
target_size := 2 + icon_width * icon_height
|
||||||
|
|
||||||
|
data := make([]u64, target_size)
|
||||||
|
|
||||||
|
// first two elements are width and height
|
||||||
|
data[0] = cast(u64)icon_width
|
||||||
|
data[1] = cast(u64)icon_height
|
||||||
|
|
||||||
|
for i in 0..<(icon_width * icon_height) {
|
||||||
|
data[i + 2] = (cast(u64)icon_data[i * 4] << 16) | (cast(u64)icon_data[i * 4 + 1] << 8) | (cast(u64)icon_data[i * 4 + 2] << 0) | (cast(u64)icon_data[i * 4 + 3] << 24)
|
||||||
|
}
|
||||||
|
|
||||||
|
net_wm_icon := x11.XInternAtom(x11_display, "_NET_WM_ICON", false)
|
||||||
|
x11.XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, raw_data(data), target_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_get_screen_size :: proc() -> Vec2 {
|
||||||
|
screen := x11.XDefaultScreenOfDisplay(x11_display)
|
||||||
|
|
||||||
|
return Vec2{cast(f32)screen.width, cast(f32)screen.height}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
x11_resize_window :: proc() {
|
||||||
|
win_attrs : x11.XWindowAttributes
|
||||||
|
x11.XGetWindowAttributes(x11_display, x11_window, &win_attrs)
|
||||||
|
gl.Viewport(0, 0, win_attrs.width, win_attrs.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
x11_create_window :: proc(window_title: cstring, window_size: Vec2, icon_path: cstring, window_non_resizable: bool) {
|
||||||
|
context.logger = logger
|
||||||
|
x11_display = x11.XOpenDisplay(nil)
|
||||||
|
|
||||||
|
if x11_display == nil {
|
||||||
|
log.error("Failed to open X11 display")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
screen_num := x11.XDefaultScreen(x11_display)
|
||||||
|
root := x11.XRootWindow(x11_display, screen_num)
|
||||||
|
visual := x11.XDefaultVisual(x11_display, screen_num)
|
||||||
|
|
||||||
|
x11_colormap = x11.XCreateColormap(x11_display, root, visual, x11.ColormapAlloc.AllocNone)
|
||||||
|
|
||||||
|
attributes: x11.XSetWindowAttributes
|
||||||
|
attributes.event_mask = {.Exposure, .KeyPress, .KeyRelease,
|
||||||
|
.StructureNotify, .ButtonPress, .ButtonRelease, .PointerMotion}
|
||||||
|
attributes.colormap = x11_colormap
|
||||||
|
|
||||||
|
screen := x11.XDefaultScreenOfDisplay(x11_display)
|
||||||
|
|
||||||
|
window_start_x := screen.width / 2 - cast(i32)window_size.x / 2
|
||||||
|
window_start_y := screen.height / 2 - cast(i32)window_size.y / 2
|
||||||
|
|
||||||
|
x11_window = x11.XCreateWindow(x11_display, root, window_start_x, window_start_y, cast(u32)window_size.x, cast(u32)window_size.y, 0,
|
||||||
|
x11.XDefaultDepth(x11_display), .InputOutput, visual,
|
||||||
|
{.CWColormap, .CWEventMask}, &attributes)
|
||||||
|
|
||||||
|
if (icon_path != "") {
|
||||||
|
x11_assign_window_icon(icon_path, window_title)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hints to the WM that the window is a normal window
|
||||||
|
// Of course this is only a hint and the WM can ignore it
|
||||||
|
net_wm_window_type := x11.XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", false)
|
||||||
|
net_wm_window_type_normal := x11.XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", false)
|
||||||
|
x11.XChangeProperty(x11_display, x11_window, net_wm_window_type, XA_ATOM, 32, PropModeReplace, &net_wm_window_type_normal, 1)
|
||||||
|
|
||||||
|
wm_delete_window := x11.XInternAtom(x11_display, "WM_DELETE_WINDOW", false)
|
||||||
|
x11.XSetWMProtocols(x11_display, x11_window, &wm_delete_window, 1)
|
||||||
|
zephr_ctx.window_delete_atom = wm_delete_window
|
||||||
|
|
||||||
|
// set window name
|
||||||
|
{
|
||||||
|
UTF8_STRING := x11.XInternAtom(x11_display, "UTF8_STRING", false)
|
||||||
|
x11.XStoreName(x11_display, x11_window, window_title)
|
||||||
|
text_property: x11.XTextProperty
|
||||||
|
text_property.value = raw_data(string(window_title))
|
||||||
|
text_property.format = 8
|
||||||
|
text_property.encoding = UTF8_STRING
|
||||||
|
text_property.nitems = len(window_title)
|
||||||
|
x11.XSetWMName(x11_display, x11_window, &text_property)
|
||||||
|
net_wm_name := x11.XInternAtom(x11_display, "_NET_WM_NAME", false)
|
||||||
|
wm_class := x11.XInternAtom(x11_display, "WM_CLASS", false)
|
||||||
|
x11.XChangeProperty(x11_display, x11_window, net_wm_name, UTF8_STRING, 8, PropModeReplace, raw_data(string(window_title)), cast(i32)len(window_title))
|
||||||
|
x11.XChangeProperty(x11_display, x11_window, wm_class, XA_STRING, 8, PropModeReplace, raw_data(string(window_title)), cast(i32)len(window_title))
|
||||||
|
|
||||||
|
// name to be displayed when the window is reduced to an icon
|
||||||
|
net_wm_icon_name := x11.XInternAtom(x11_display, "_NET_WM_ICON_NAME", false)
|
||||||
|
x11.XChangeProperty(x11_display, x11_window, net_wm_icon_name, UTF8_STRING, 8, PropModeReplace, raw_data(string(window_title)), cast(i32)len(window_title))
|
||||||
|
|
||||||
|
text_property.encoding = XA_STRING
|
||||||
|
x11.XSetWMIconName(x11_display, x11_window, &text_property)
|
||||||
|
|
||||||
|
class_hint := x11.XAllocClassHint()
|
||||||
|
|
||||||
|
if (class_hint != nil) {
|
||||||
|
class_hint.res_name = window_title
|
||||||
|
class_hint.res_class = window_title
|
||||||
|
x11.XSetClassHint(x11_display, x11_window, class_hint)
|
||||||
|
x11.XFree(class_hint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_hints := x11.XAllocSizeHints()
|
||||||
|
|
||||||
|
if (size_hints != nil) {
|
||||||
|
size_hints.flags = {.PPosition, .PSize}
|
||||||
|
/* size_hints->win_gravity = StaticGravity; */
|
||||||
|
size_hints.x = window_start_x
|
||||||
|
size_hints.y = window_start_y
|
||||||
|
size_hints.width = cast(i32)window_size.x
|
||||||
|
size_hints.height = cast(i32)window_size.y
|
||||||
|
if (window_non_resizable) {
|
||||||
|
size_hints.flags |= {.PMinSize, .PMaxSize}
|
||||||
|
size_hints.min_width = cast(i32)window_size.x
|
||||||
|
size_hints.min_height = cast(i32)window_size.y
|
||||||
|
size_hints.max_width = cast(i32)window_size.x
|
||||||
|
size_hints.max_height = cast(i32)window_size.y
|
||||||
|
}
|
||||||
|
x11.XSetWMNormalHints(x11_display, x11_window, size_hints)
|
||||||
|
x11.XFree(size_hints)
|
||||||
|
}
|
||||||
|
|
||||||
|
x11.XMapWindow(x11_display, x11_window)
|
||||||
|
|
||||||
|
gl.load_up_to(3, 3, proc(p: rawptr, name: cstring) { (cast(^rawptr)p)^ = glx.GetProcAddressARB(raw_data(string(name))) })
|
||||||
|
|
||||||
|
glx_major : i32
|
||||||
|
glx_minor : i32
|
||||||
|
glx.QueryVersion(x11_display, &glx_major, &glx_minor)
|
||||||
|
|
||||||
|
log.infof("Loaded GLX: %d.%d", glx_major, glx_minor)
|
||||||
|
|
||||||
|
visual_attributes := []i32 {
|
||||||
|
glx.RENDER_TYPE, glx.RGBA_BIT,
|
||||||
|
glx.RED_SIZE, 8,
|
||||||
|
glx.GREEN_SIZE, 8,
|
||||||
|
glx.BLUE_SIZE, 8,
|
||||||
|
glx.ALPHA_SIZE, 8,
|
||||||
|
glx.DEPTH_SIZE, 24,
|
||||||
|
glx.DOUBLEBUFFER, 1,
|
||||||
|
glx.SAMPLES, 4, // MSAA
|
||||||
|
x11.None,
|
||||||
|
}
|
||||||
|
|
||||||
|
num_fbc: i32
|
||||||
|
fbc := glx.ChooseFBConfig(x11_display, screen_num, raw_data(visual_attributes), &num_fbc)
|
||||||
|
|
||||||
|
context_attributes := []i32 {
|
||||||
|
glx.CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||||
|
glx.CONTEXT_MINOR_VERSION_ARB, 3,
|
||||||
|
glx.CONTEXT_PROFILE_MASK_ARB, glx.CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||||
|
x11.None,
|
||||||
|
}
|
||||||
|
|
||||||
|
glx_context = glx.CreateContextAttribsARB(x11_display, fbc[0], nil, true, raw_data(context_attributes))
|
||||||
|
|
||||||
|
if glx_context == nil {
|
||||||
|
log.error("Failed to create GLX context")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
glx.MakeCurrent(x11_display, x11_window, glx_context)
|
||||||
|
|
||||||
|
gl_version := gl.GetString(gl.VERSION)
|
||||||
|
|
||||||
|
log.infof("GL Version: %s", gl_version)
|
||||||
|
|
||||||
|
glx.SwapIntervalEXT(x11_display, x11_window, 1)
|
||||||
|
// we enable blending for text
|
||||||
|
gl.Enable(gl.BLEND)
|
||||||
|
gl.Enable(gl.MULTISAMPLE)
|
||||||
|
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
||||||
|
x11_resize_window()
|
||||||
|
|
||||||
|
x11.XFree(fbc)
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_init :: proc(window_title: cstring, window_size: Vec2, icon_path: cstring, window_non_resizable: bool) {
|
||||||
|
x11_create_window(window_title, window_size, icon_path, window_non_resizable)
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_shutdown :: proc() {
|
||||||
|
glx.MakeCurrent(x11_display, 0, nil)
|
||||||
|
glx.DestroyContext(x11_display, glx_context)
|
||||||
|
|
||||||
|
x11.XDestroyWindow(x11_display, x11_window)
|
||||||
|
x11.XFreeColormap(x11_display, x11_colormap)
|
||||||
|
x11.XCloseDisplay(x11_display)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
x11_mods_to_zephr_mods :: proc(scancode: Scancode, is_press: bool) -> KeyMod {
|
||||||
|
mods := zephr_ctx.keyboard.mods
|
||||||
|
|
||||||
|
if (is_press) {
|
||||||
|
if (scancode == .LEFT_SHIFT) {
|
||||||
|
mods |= {.LEFT_SHIFT, .SHIFT}
|
||||||
|
}
|
||||||
|
if (scancode == .RIGHT_SHIFT) {
|
||||||
|
mods |= {.RIGHT_SHIFT, .SHIFT}
|
||||||
|
}
|
||||||
|
if (scancode == .LEFT_CTRL) {
|
||||||
|
mods |= {.LEFT_CTRL, .CTRL}
|
||||||
|
}
|
||||||
|
if (scancode == .RIGHT_CTRL) {
|
||||||
|
mods |= {.RIGHT_CTRL, .CTRL}
|
||||||
|
}
|
||||||
|
if (scancode == .LEFT_ALT) {
|
||||||
|
mods |= {.LEFT_ALT, .ALT}
|
||||||
|
}
|
||||||
|
if (scancode == .RIGHT_ALT) {
|
||||||
|
mods |= {.RIGHT_ALT, .ALT}
|
||||||
|
}
|
||||||
|
if (scancode == .LEFT_META) {
|
||||||
|
mods |= {.LEFT_META, .META}
|
||||||
|
}
|
||||||
|
if (scancode == .RIGHT_META) {
|
||||||
|
mods |= {.RIGHT_META, .META}
|
||||||
|
}
|
||||||
|
if (scancode == .CAPS_LOCK) {
|
||||||
|
mods |= {.CAPS_LOCK}
|
||||||
|
}
|
||||||
|
if (scancode == .NUM_LOCK_OR_CLEAR) {
|
||||||
|
mods |= {.NUM_LOCK}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (scancode == .LEFT_SHIFT) {
|
||||||
|
mods &= ~{.LEFT_SHIFT}
|
||||||
|
}
|
||||||
|
if (scancode == .RIGHT_SHIFT) {
|
||||||
|
mods &= ~{.RIGHT_SHIFT}
|
||||||
|
}
|
||||||
|
if (!(.RIGHT_SHIFT in mods) && !(.LEFT_SHIFT in mods)) {
|
||||||
|
mods &= ~{.SHIFT}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scancode == .LEFT_CTRL) {
|
||||||
|
mods &= ~{.LEFT_CTRL}
|
||||||
|
}
|
||||||
|
if (scancode == .RIGHT_CTRL) {
|
||||||
|
mods &= ~{.RIGHT_CTRL}
|
||||||
|
}
|
||||||
|
if (!(.RIGHT_CTRL in mods) && !(.LEFT_CTRL in mods)) {
|
||||||
|
mods &= ~{.CTRL}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scancode == .LEFT_ALT) {
|
||||||
|
mods &= ~{.LEFT_ALT}
|
||||||
|
}
|
||||||
|
if (scancode == .RIGHT_ALT) {
|
||||||
|
mods &= ~{.RIGHT_ALT}
|
||||||
|
}
|
||||||
|
if (!(.RIGHT_ALT in mods) && !(.LEFT_ALT in mods)) {
|
||||||
|
mods &= ~{.ALT}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scancode == .LEFT_META) {
|
||||||
|
mods &= ~{.LEFT_META}
|
||||||
|
}
|
||||||
|
if (scancode == .RIGHT_META) {
|
||||||
|
mods &= ~{.RIGHT_META}
|
||||||
|
}
|
||||||
|
if (!(.RIGHT_META in mods) && !(.LEFT_META in mods)) {
|
||||||
|
mods &= ~{.META}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scancode == .CAPS_LOCK) {
|
||||||
|
mods &= ~{.CAPS_LOCK}
|
||||||
|
}
|
||||||
|
if (scancode == .NUM_LOCK_OR_CLEAR) {
|
||||||
|
mods &= ~{.NUM_LOCK}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zephr_ctx.keyboard.mods = mods
|
||||||
|
return mods
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_swapbuffers :: proc() {
|
||||||
|
glx.SwapBuffers(x11_display, x11_window)
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_get_os_events :: proc(e_out: ^Event) -> bool {
|
||||||
|
context.logger = logger
|
||||||
|
xev: x11.XEvent
|
||||||
|
|
||||||
|
for (cast(bool)x11.XPending(x11_display)) {
|
||||||
|
x11.XNextEvent(x11_display, &xev)
|
||||||
|
|
||||||
|
if xev.type == .ConfigureNotify {
|
||||||
|
xce := xev.xconfigure
|
||||||
|
|
||||||
|
if (xce.width != cast(i32)zephr_ctx.window.size.x || xce.height != cast(i32)zephr_ctx.window.size.y) {
|
||||||
|
zephr_ctx.window.size = Vec2{cast(f32)xce.width, cast(f32)xce.height}
|
||||||
|
zephr_ctx.projection = orthographic_projection_2d(0, zephr_ctx.window.size.x, zephr_ctx.window.size.y, 0)
|
||||||
|
x11_resize_window()
|
||||||
|
|
||||||
|
e_out.type = .WINDOW_RESIZED
|
||||||
|
e_out.window.width = cast(u32)xce.width
|
||||||
|
e_out.window.height = cast(u32)xce.height
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else if xev.type == .DestroyNotify {
|
||||||
|
// window destroy event
|
||||||
|
e_out.type = .WINDOW_CLOSED
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else if xev.type == .ClientMessage {
|
||||||
|
// window close event
|
||||||
|
if (cast(x11.Atom)xev.xclient.data.l[0] == zephr_ctx.window_delete_atom) {
|
||||||
|
e_out.type = .WINDOW_CLOSED
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else if xev.type == .KeyPress {
|
||||||
|
xke := xev.xkey
|
||||||
|
|
||||||
|
evdev_keycode := xke.keycode - 8
|
||||||
|
scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode]
|
||||||
|
|
||||||
|
e_out.type = .KEY_PRESSED
|
||||||
|
e_out.key.scancode = scancode
|
||||||
|
//e_out.key.code = keycode;
|
||||||
|
e_out.key.mods = x11_mods_to_zephr_mods(scancode, true)
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else if xev.type == .KeyRelease {
|
||||||
|
xke := xev.xkey
|
||||||
|
|
||||||
|
evdev_keycode := xke.keycode - 8
|
||||||
|
scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode]
|
||||||
|
|
||||||
|
e_out.type = .KEY_RELEASED
|
||||||
|
e_out.key.scancode = scancode
|
||||||
|
//e_out.key.code = keycode;
|
||||||
|
e_out.key.mods = x11_mods_to_zephr_mods(scancode, false)
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else if xev.type == .ButtonPress {
|
||||||
|
e_out.type = .MOUSE_BUTTON_PRESSED
|
||||||
|
e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y}
|
||||||
|
zephr_ctx.mouse.pressed = true
|
||||||
|
|
||||||
|
switch (xev.xbutton.button) {
|
||||||
|
case .Button1:
|
||||||
|
e_out.mouse.button = .BUTTON_LEFT
|
||||||
|
zephr_ctx.mouse.button = .BUTTON_LEFT
|
||||||
|
case .Button2:
|
||||||
|
e_out.mouse.button = .BUTTON_MIDDLE
|
||||||
|
zephr_ctx.mouse.button = .BUTTON_MIDDLE
|
||||||
|
case .Button3:
|
||||||
|
e_out.mouse.button = .BUTTON_RIGHT
|
||||||
|
zephr_ctx.mouse.button = .BUTTON_RIGHT
|
||||||
|
case .Button4:
|
||||||
|
e_out.type = .MOUSE_SCROLL
|
||||||
|
e_out.mouse.scroll_direction = .UP
|
||||||
|
case .Button5:
|
||||||
|
e_out.type = .MOUSE_SCROLL
|
||||||
|
e_out.mouse.scroll_direction = .DOWN
|
||||||
|
case cast(x11.MouseButton)8: // Back
|
||||||
|
e_out.mouse.button = .BUTTON_BACK
|
||||||
|
zephr_ctx.mouse.button = .BUTTON_BACK
|
||||||
|
case cast(x11.MouseButton)9: // Forward
|
||||||
|
e_out.mouse.button = .BUTTON_FORWARD
|
||||||
|
zephr_ctx.mouse.button = .BUTTON_FORWARD
|
||||||
|
case:
|
||||||
|
log.warnf("Unknown mouse button pressed: %d", xev.xbutton.button)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else if xev.type == .ButtonRelease {
|
||||||
|
e_out.type = .MOUSE_BUTTON_RELEASED
|
||||||
|
e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y}
|
||||||
|
zephr_ctx.mouse.released = true
|
||||||
|
zephr_ctx.mouse.pressed = false
|
||||||
|
|
||||||
|
switch (xev.xbutton.button) {
|
||||||
|
case .Button1:
|
||||||
|
e_out.mouse.button = .BUTTON_LEFT
|
||||||
|
case .Button2:
|
||||||
|
e_out.mouse.button = .BUTTON_MIDDLE
|
||||||
|
case .Button3:
|
||||||
|
e_out.mouse.button = .BUTTON_RIGHT
|
||||||
|
case .Button4:
|
||||||
|
e_out.type = .MOUSE_SCROLL
|
||||||
|
e_out.mouse.scroll_direction = .UP
|
||||||
|
case .Button5:
|
||||||
|
e_out.type = .MOUSE_SCROLL
|
||||||
|
e_out.mouse.scroll_direction = .DOWN
|
||||||
|
case cast(x11.MouseButton)8: // Back
|
||||||
|
e_out.mouse.button = .BUTTON_BACK
|
||||||
|
zephr_ctx.mouse.button = .BUTTON_BACK
|
||||||
|
case cast(x11.MouseButton)9: // Forward
|
||||||
|
e_out.mouse.button = .BUTTON_FORWARD
|
||||||
|
zephr_ctx.mouse.button = .BUTTON_FORWARD
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else if xev.type == .MappingNotify {
|
||||||
|
// input device mapping changed
|
||||||
|
if (xev.xmapping.request != .MappingKeyboard) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x11.XRefreshKeyboardMapping(&xev.xmapping)
|
||||||
|
/* x11_keyboard_map_update(); */
|
||||||
|
break
|
||||||
|
} else if xev.type == .MotionNotify {
|
||||||
|
e_out.type = .MOUSE_MOVED
|
||||||
|
e_out.mouse.pos = Vec2{cast(f32)xev.xmotion.x, cast(f32)xev.xmotion.y}
|
||||||
|
zephr_ctx.mouse.pos = e_out.mouse.pos
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
// +build windows
|
||||||
|
// +private
|
||||||
|
package zephr
|
||||||
|
|
||||||
|
import "core:log"
|
||||||
|
import "core:strings"
|
||||||
|
import "core:strconv"
|
||||||
|
import "core:os"
|
||||||
|
import win32 "core:sys/windows"
|
||||||
|
|
||||||
|
import gl "vendor:OpenGL"
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
hwnd : win32.HWND
|
||||||
|
@(private="file")
|
||||||
|
device_ctx : win32.HDC
|
||||||
|
@(private="file")
|
||||||
|
wgl_context : win32.HGLRC
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
temp_hwnd : win32.HWND
|
||||||
|
@(private="file")
|
||||||
|
temp_device_ctx : win32.HDC
|
||||||
|
@(private="file")
|
||||||
|
temp_wgl_context: win32.HGLRC
|
||||||
|
|
||||||
|
backend_get_screen_size :: proc() -> Vec2 {
|
||||||
|
screen_size := Vec2{
|
||||||
|
cast(f32)win32.GetSystemMetrics(win32.SM_CXSCREEN),
|
||||||
|
cast(f32)win32.GetSystemMetrics(win32.SM_CYSCREEN),
|
||||||
|
}
|
||||||
|
return screen_size
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_toggle_fullscreen :: proc(fullscreen: bool) {
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
init_legacy_gl :: proc(class_name: win32.wstring, hInstance: win32.HINSTANCE) {
|
||||||
|
temp_hwnd = win32.CreateWindowExW(
|
||||||
|
0,
|
||||||
|
class_name,
|
||||||
|
win32.L("Fake Window"),
|
||||||
|
win32.WS_OVERLAPPEDWINDOW,
|
||||||
|
|
||||||
|
0, 0, 1, 1,
|
||||||
|
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
hInstance,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
if temp_hwnd == nil {
|
||||||
|
log.fatal("Failed to create fake window")
|
||||||
|
}
|
||||||
|
|
||||||
|
temp_device_ctx = win32.GetDC(temp_hwnd)
|
||||||
|
|
||||||
|
if temp_device_ctx == nil {
|
||||||
|
log.error("Failed to create device context for fake window")
|
||||||
|
}
|
||||||
|
|
||||||
|
pfd := win32.PIXELFORMATDESCRIPTOR{
|
||||||
|
nSize = size_of(win32.PIXELFORMATDESCRIPTOR),
|
||||||
|
nVersion = 1,
|
||||||
|
dwFlags = win32.PFD_DRAW_TO_WINDOW | win32.PFD_SUPPORT_OPENGL,
|
||||||
|
iPixelType = win32.PFD_TYPE_RGBA,
|
||||||
|
cColorBits = 32,
|
||||||
|
cAlphaBits = 8,
|
||||||
|
cDepthBits = 24,
|
||||||
|
iLayerType = win32.PFD_MAIN_PLANE,
|
||||||
|
}
|
||||||
|
pixel_format := win32.ChoosePixelFormat(temp_device_ctx, &pfd)
|
||||||
|
if pixel_format == 0 {
|
||||||
|
log.error("Failed to choose pixel format for fake window")
|
||||||
|
}
|
||||||
|
|
||||||
|
status := win32.SetPixelFormat(temp_device_ctx, pixel_format, &pfd)
|
||||||
|
if !status {
|
||||||
|
log.error("Failed to set pixel format for fake window")
|
||||||
|
}
|
||||||
|
|
||||||
|
temp_wgl_context = win32.wglCreateContext(temp_device_ctx)
|
||||||
|
|
||||||
|
if temp_wgl_context == nil {
|
||||||
|
log.fatal("Failed to create WGL context")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.load_up_to(3, 3, win32.gl_set_proc_address)
|
||||||
|
|
||||||
|
win32.wglMakeCurrent(temp_device_ctx, temp_wgl_context)
|
||||||
|
|
||||||
|
gl_version := gl.GetString(gl.VERSION)
|
||||||
|
|
||||||
|
strs := strings.split(string(gl_version), " ")
|
||||||
|
ver := strings.split(strs[0], ".")
|
||||||
|
gl_major, gl_minor := strconv.atoi(ver[0]), strconv.atoi(ver[1])
|
||||||
|
|
||||||
|
log.debugf("Fake Window GL: %d.%d", gl_major, gl_minor)
|
||||||
|
|
||||||
|
if !(gl_major > 3 || (gl_major == 3 && gl_minor >= 3)) {
|
||||||
|
log.fatalf("You need at least OpenGL 3.3 to run this application. Your OpenGL version is %d.%d", gl_major, gl_minor)
|
||||||
|
os.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
init_gl :: proc(class_name: win32.wstring, window_title: win32.wstring, window_size: Vec2, hInstance: win32.HINSTANCE) {
|
||||||
|
screen_size := Vec2{
|
||||||
|
cast(f32)win32.GetSystemMetrics(win32.SM_CXSCREEN),
|
||||||
|
cast(f32)win32.GetSystemMetrics(win32.SM_CYSCREEN),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
win_x := screen_size.x / 2 - window_size.x / 2
|
||||||
|
win_y := screen_size.y / 2 - window_size.y / 2
|
||||||
|
|
||||||
|
hwnd := win32.CreateWindowExW(
|
||||||
|
0,
|
||||||
|
class_name,
|
||||||
|
window_title,
|
||||||
|
win32.WS_OVERLAPPEDWINDOW,
|
||||||
|
|
||||||
|
cast(i32)win_x, cast(i32)win_y, cast(i32)window_size.x, cast(i32)window_size.y,
|
||||||
|
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
hInstance,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
if hwnd == nil {
|
||||||
|
log.fatal("Failed to create window")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
device_ctx = win32.GetDC(hwnd)
|
||||||
|
|
||||||
|
if device_ctx == nil {
|
||||||
|
log.fatal("Failed to create device context")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wglChoosePixelFormatARB := cast(win32.ChoosePixelFormatARBType)win32.wglGetProcAddress("wglChoosePixelFormatARB")
|
||||||
|
wglCreateContextAttribsARB := cast(win32.CreateContextAttribsARBType)win32.wglGetProcAddress("wglCreateContextAttribsARB")
|
||||||
|
wglSwapIntervalEXT := cast(win32.SwapIntervalEXTType)win32.wglGetProcAddress("wglSwapIntervalEXT")
|
||||||
|
|
||||||
|
pixel_attribs := []i32{
|
||||||
|
win32.WGL_DRAW_TO_WINDOW_ARB, 1,
|
||||||
|
win32.WGL_SUPPORT_OPENGL_ARB, 1,
|
||||||
|
win32.WGL_DOUBLE_BUFFER_ARB, 1,
|
||||||
|
// TODO: test to see if EXCHANGE actually causes problems in fullscreen
|
||||||
|
/* WGL_SWAP_EXCHANGE_ARB causes problems with window menu in fullscreen */
|
||||||
|
win32.WGL_SWAP_METHOD_ARB, win32.WGL_SWAP_COPY_ARB,
|
||||||
|
win32.WGL_PIXEL_TYPE_ARB, win32.WGL_TYPE_RGBA_ARB,
|
||||||
|
win32.WGL_ACCELERATION_ARB, win32.WGL_FULL_ACCELERATION_ARB,
|
||||||
|
win32.WGL_COLOR_BITS_ARB, 32,
|
||||||
|
win32.WGL_ALPHA_BITS_ARB, 8,
|
||||||
|
win32.WGL_DEPTH_BITS_ARB, 24,
|
||||||
|
win32.WGL_STENCIL_BITS_ARB, 0,
|
||||||
|
win32.WGL_SAMPLES_ARB, 4,
|
||||||
|
0,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx_attribs := []i32{
|
||||||
|
win32.WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||||
|
win32.WGL_CONTEXT_MINOR_VERSION_ARB, 3,
|
||||||
|
win32.WGL_CONTEXT_PROFILE_MASK_ARB, win32.WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||||
|
0,
|
||||||
|
}
|
||||||
|
|
||||||
|
pixel_format: i32
|
||||||
|
num_formats: u32
|
||||||
|
success := wglChoosePixelFormatARB(device_ctx, raw_data(pixel_attribs), nil, 1, &pixel_format, &num_formats)
|
||||||
|
|
||||||
|
if !success {
|
||||||
|
log.error("Failed to choose pixel format")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pfd: win32.PIXELFORMATDESCRIPTOR
|
||||||
|
win32.DescribePixelFormat(device_ctx, pixel_format, size_of(win32.PIXELFORMATDESCRIPTOR), &pfd)
|
||||||
|
success = win32.SetPixelFormat(device_ctx, pixel_format, &pfd)
|
||||||
|
|
||||||
|
if !success {
|
||||||
|
log.error("Failed to set pixel format")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wgl_context = wglCreateContextAttribsARB(device_ctx, nil, raw_data(ctx_attribs))
|
||||||
|
|
||||||
|
if wgl_context == nil {
|
||||||
|
log.fatal("Failed to create WGL context")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
win32.wglMakeCurrent(temp_device_ctx, nil)
|
||||||
|
win32.wglDeleteContext(temp_wgl_context)
|
||||||
|
win32.ReleaseDC(temp_hwnd, temp_device_ctx)
|
||||||
|
win32.DestroyWindow(temp_hwnd)
|
||||||
|
|
||||||
|
win32.wglMakeCurrent(device_ctx, wgl_context)
|
||||||
|
|
||||||
|
gl_version := gl.GetString(gl.VERSION)
|
||||||
|
log.infof("GL Version: %s", gl_version)
|
||||||
|
|
||||||
|
new_success := wglSwapIntervalEXT(1)
|
||||||
|
if !new_success {
|
||||||
|
log.error("Failed to turn on v-sync")
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.load_up_to(3, 3, win32.gl_set_proc_address)
|
||||||
|
|
||||||
|
win32.ShowWindow(hwnd, win32.SW_NORMAL)
|
||||||
|
|
||||||
|
gl.Enable(gl.BLEND)
|
||||||
|
gl.Enable(gl.MULTISAMPLE)
|
||||||
|
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_init :: proc(window_title: cstring, window_size: Vec2, icon_path: cstring, window_non_resizable: bool) {
|
||||||
|
context.logger = logger
|
||||||
|
|
||||||
|
class_name := win32.L("zephr.main_window")
|
||||||
|
window_title := win32.utf8_to_wstring(string(window_title))
|
||||||
|
|
||||||
|
hInstance := win32.HINSTANCE(win32.GetModuleHandleW(nil))
|
||||||
|
//hIcon := win32.LoadImageW(nil, auto_cast win32._IDI_EXCLAMATION, win32.IMAGE_ICON, 0, 0, win32.LR_DEFAULTSIZE | win32.LR_SHARED) // works for system icons
|
||||||
|
hIcon := win32.LoadImageW(nil, win32.utf8_to_wstring(string(icon_path)), win32.IMAGE_ICON, 0, 0, win32.LR_DEFAULTSIZE | win32.LR_LOADFROMFILE)
|
||||||
|
wc := win32.WNDCLASSEXW {
|
||||||
|
// TODO: we can define our own window_proc that can handle events like window resizing and stuff
|
||||||
|
// we probably want a custom one.
|
||||||
|
cbSize = size_of(win32.WNDCLASSEXW),
|
||||||
|
style = win32.CS_HREDRAW | win32.CS_VREDRAW | win32.CS_OWNDC,
|
||||||
|
lpfnWndProc = win32.DefWindowProcW,
|
||||||
|
hInstance = hInstance,
|
||||||
|
lpszClassName = class_name,
|
||||||
|
hIcon = cast(win32.HICON)hIcon,
|
||||||
|
hIconSm = cast(win32.HICON)hIcon, // TODO: maybe we can have a 16x16 icon here. can be used on linux too
|
||||||
|
//hCursor = win32.LoadCursorW(hInstance, win32.utf8_to_wstring(string(win32.IDC_ARROW))),
|
||||||
|
}
|
||||||
|
|
||||||
|
status := win32.RegisterClassExW(&wc)
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
log.error("Failed to register class")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make process aware of system scaling per monitor
|
||||||
|
win32.SetThreadDpiAwarenessContext(win32.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)
|
||||||
|
|
||||||
|
init_legacy_gl(class_name, hInstance)
|
||||||
|
init_gl(class_name, window_title, window_size, hInstance)
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_get_os_events :: proc(e_out: ^Event) -> bool {
|
||||||
|
msg: win32.MSG
|
||||||
|
|
||||||
|
for win32.PeekMessageW(&msg, hwnd, 0, 0, win32.PM_REMOVE) != win32.FALSE {
|
||||||
|
win32.TranslateMessage(&msg)
|
||||||
|
win32.DispatchMessageW(&msg)
|
||||||
|
}
|
||||||
|
// TODO: somehow get the events from window proc here???
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_shutdown :: proc() {
|
||||||
|
win32.wglMakeCurrent(device_ctx, nil)
|
||||||
|
win32.wglDeleteContext(wgl_context)
|
||||||
|
win32.ReleaseDC(hwnd, device_ctx)
|
||||||
|
win32.DestroyWindow(hwnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_swapbuffers :: proc() {
|
||||||
|
win32.SwapBuffers(device_ctx)
|
||||||
|
}
|
||||||
+3
-3
@@ -80,7 +80,7 @@ init_freetype :: proc(font_path: cstring) -> i32 {
|
|||||||
|
|
||||||
tex_width, tex_height: u32
|
tex_width, tex_height: u32
|
||||||
for i in 32..<128 {
|
for i in 32..<128 {
|
||||||
if (FT.Load_Char(face, cast(u64)i, .RENDER) != 0) {
|
if (FT.Load_Char(face, cast(FT.ULong)i, .RENDER) != 0) {
|
||||||
log.errorf("Failed to load glyph for char '0x%x'", i)
|
log.errorf("Failed to load glyph for char '0x%x'", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ init_freetype :: proc(font_path: cstring) -> i32 {
|
|||||||
|
|
||||||
for i in 32..<128 {
|
for i in 32..<128 {
|
||||||
/* while (glyph_idx) { */
|
/* while (glyph_idx) { */
|
||||||
if (FT.Load_Char(face, cast(u64)i, .RENDER) != 0) {
|
if (FT.Load_Char(face, cast(FT.ULong)i, .RENDER) != 0) {
|
||||||
log.errorf("Failed to load glyph for char '0x%x'", i)
|
log.errorf("Failed to load glyph for char '0x%x'", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,6 +334,7 @@ draw_text_batch :: proc(batch: ^GlyphInstanceList) {
|
|||||||
|
|
||||||
get_glyph_instance_list_from_text :: proc(text: string, font_size: u32, constraints: UiConstraints, color: Color, alignment: Alignment) -> GlyphInstanceList {
|
get_glyph_instance_list_from_text :: proc(text: string, font_size: u32, constraints: UiConstraints, color: Color, alignment: Alignment) -> GlyphInstanceList {
|
||||||
constraints := constraints
|
constraints := constraints
|
||||||
|
// TODO: this use_shader might be redundant
|
||||||
use_shader(font_shader)
|
use_shader(font_shader)
|
||||||
text_color := Vec4{ cast(f32)color.r / 255, cast(f32)color.g / 255, cast(f32)color.b / 255, cast(f32)color.a / 255 }
|
text_color := Vec4{ cast(f32)color.r / 255, cast(f32)color.g / 255, cast(f32)color.b / 255, cast(f32)color.a / 255 }
|
||||||
|
|
||||||
@@ -424,4 +425,3 @@ add_text_instance :: proc(batch: ^GlyphInstanceList, text: string, font_size: u3
|
|||||||
|
|
||||||
delete(glyph_instance_list)
|
delete(glyph_instance_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+154
-544
@@ -8,9 +8,6 @@ import x11 "vendor:x11/xlib"
|
|||||||
import gl "vendor:OpenGL"
|
import gl "vendor:OpenGL"
|
||||||
import "vendor:stb/image"
|
import "vendor:stb/image"
|
||||||
|
|
||||||
import "../glx"
|
|
||||||
import "../xcursor"
|
|
||||||
|
|
||||||
Cursor :: enum {
|
Cursor :: enum {
|
||||||
ARROW,
|
ARROW,
|
||||||
IBEAM,
|
IBEAM,
|
||||||
@@ -349,7 +346,7 @@ Keyboard :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Context :: struct {
|
Context :: struct {
|
||||||
window_delete_atom: x11.Atom,
|
//window_delete_atom: x11.Atom,
|
||||||
should_quit: bool,
|
should_quit: bool,
|
||||||
screen_size: Vec2,
|
screen_size: Vec2,
|
||||||
window: Window,
|
window: Window,
|
||||||
@@ -357,7 +354,7 @@ Context :: struct {
|
|||||||
mouse: Mouse,
|
mouse: Mouse,
|
||||||
keyboard: Keyboard,
|
keyboard: Keyboard,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
cursors: [Cursor]x11.Cursor,
|
//cursors: [Cursor]x11.Cursor,
|
||||||
ui: Ui,
|
ui: Ui,
|
||||||
|
|
||||||
/* ZephrKeyboard keyboard; */
|
/* ZephrKeyboard keyboard; */
|
||||||
@@ -369,14 +366,6 @@ Context :: struct {
|
|||||||
projection: Mat4,
|
projection: Mat4,
|
||||||
}
|
}
|
||||||
|
|
||||||
@private
|
|
||||||
PropModeReplace :: 0
|
|
||||||
@private
|
|
||||||
XA_ATOM :: x11.Atom(4)
|
|
||||||
@private
|
|
||||||
XA_STRING :: x11.Atom(31)
|
|
||||||
@private
|
|
||||||
XA_CARDINAL :: x11.Atom(6)
|
|
||||||
@private
|
@private
|
||||||
FNV_HASH32_INIT :: 0x811c9dc5
|
FNV_HASH32_INIT :: 0x811c9dc5
|
||||||
@private
|
@private
|
||||||
@@ -643,306 +632,12 @@ evdev_scancode_to_zephr_scancode_map := []Scancode {
|
|||||||
236 = .NULL, // KEY_BATTERY
|
236 = .NULL, // KEY_BATTERY
|
||||||
}
|
}
|
||||||
|
|
||||||
@private
|
|
||||||
x11_display : ^x11.Display
|
|
||||||
@private
|
|
||||||
x11_window : x11.Window
|
|
||||||
@private
|
|
||||||
x11_colormap : x11.Colormap
|
|
||||||
@private
|
|
||||||
glx_context : glx.Context
|
|
||||||
@private
|
@private
|
||||||
zephr_ctx : Context
|
zephr_ctx : Context
|
||||||
@private
|
@private
|
||||||
logger : log.Logger
|
logger : log.Logger
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////
|
|
||||||
//
|
|
||||||
// X11
|
|
||||||
//
|
|
||||||
///////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
@private
|
|
||||||
x11_go_fullscreen :: proc() {
|
|
||||||
// remove the resizing constraint before going fullscreen so WMs such as gnome
|
|
||||||
// can add the _NET_WM_ACTION_FULLSCREEN action to the _NET_WM_ALLOWED_ACTIONS atom
|
|
||||||
// and properly fullscreen the window
|
|
||||||
size_hints := x11.XAllocSizeHints()
|
|
||||||
|
|
||||||
zephr_ctx.window.pre_fullscreen_size.x = zephr_ctx.window.size.x
|
|
||||||
zephr_ctx.window.pre_fullscreen_size.y = zephr_ctx.window.size.y
|
|
||||||
if (size_hints != nil) {
|
|
||||||
size_hints.flags = {.PPosition, .PSize}
|
|
||||||
size_hints.width = cast(i32)zephr_ctx.window.size.x
|
|
||||||
size_hints.height = cast(i32)zephr_ctx.window.size.y
|
|
||||||
x11.XSetWMNormalHints(x11_display, x11_window, size_hints)
|
|
||||||
x11.XFree(size_hints)
|
|
||||||
}
|
|
||||||
|
|
||||||
xev: x11.XEvent
|
|
||||||
wm_state := x11.XInternAtom(x11_display, "_NET_WM_STATE", false)
|
|
||||||
fullscreen := x11.XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", false)
|
|
||||||
xev.type = .ClientMessage
|
|
||||||
xev.xclient.window = x11_window
|
|
||||||
xev.xclient.message_type = wm_state
|
|
||||||
xev.xclient.format = 32
|
|
||||||
xev.xclient.data.l[0] = 1 // _NET_WM_STATE_ADD
|
|
||||||
xev.xclient.data.l[1] = cast(int)fullscreen
|
|
||||||
xev.xclient.data.l[2] = 0
|
|
||||||
x11.XSendEvent(x11_display, x11.XDefaultRootWindow(x11_display), false,
|
|
||||||
{.SubstructureNotify, .SubstructureRedirect}, &xev)
|
|
||||||
}
|
|
||||||
|
|
||||||
@private
|
|
||||||
x11_return_fullscreen :: proc() {
|
|
||||||
xev: x11.XEvent
|
|
||||||
wm_state := x11.XInternAtom(x11_display, "_NET_WM_STATE", false)
|
|
||||||
fullscreen := x11.XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", false)
|
|
||||||
xev.type = .ClientMessage
|
|
||||||
xev.xclient.window = x11_window
|
|
||||||
xev.xclient.message_type = wm_state
|
|
||||||
xev.xclient.format = 32
|
|
||||||
xev.xclient.data.l[0] = 0 // _NET_WM_STATE_REMOVE
|
|
||||||
xev.xclient.data.l[1] = cast(int)fullscreen
|
|
||||||
xev.xclient.data.l[2] = 0
|
|
||||||
x11.XSendEvent(x11_display, x11.XDefaultRootWindow(x11_display), false,
|
|
||||||
{.SubstructureNotify, .SubstructureRedirect}, &xev)
|
|
||||||
|
|
||||||
// restore the resizing constraint as well as the pre-fullscreen window size
|
|
||||||
// when returning from fullscreen
|
|
||||||
size_hints := x11.XAllocSizeHints()
|
|
||||||
|
|
||||||
if (size_hints != nil) {
|
|
||||||
size_hints.flags = {.PPosition, .PSize}
|
|
||||||
size_hints.width = cast(i32)zephr_ctx.window.pre_fullscreen_size.x
|
|
||||||
size_hints.height = cast(i32)zephr_ctx.window.pre_fullscreen_size.y
|
|
||||||
if (zephr_ctx.window.non_resizable) {
|
|
||||||
size_hints.flags |= {.PMinSize, .PMaxSize}
|
|
||||||
size_hints.min_width = cast(i32)zephr_ctx.window.pre_fullscreen_size.x
|
|
||||||
size_hints.min_height = cast(i32)zephr_ctx.window.pre_fullscreen_size.y
|
|
||||||
size_hints.max_width = cast(i32)zephr_ctx.window.pre_fullscreen_size.x
|
|
||||||
size_hints.max_height = cast(i32)zephr_ctx.window.pre_fullscreen_size.y
|
|
||||||
}
|
|
||||||
x11.XSetWMNormalHints(x11_display, x11_window, size_hints)
|
|
||||||
x11.XFree(size_hints)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@private
|
|
||||||
x11_toggle_fullscreen :: proc(fullscreen: bool) {
|
|
||||||
if fullscreen {
|
|
||||||
x11_return_fullscreen()
|
|
||||||
} else {
|
|
||||||
x11_go_fullscreen()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@private
|
|
||||||
x11_assign_window_icon :: proc(icon_path: cstring, window_title: cstring) {
|
|
||||||
icon_width, icon_height: i32
|
|
||||||
icon_data := image.load(icon_path, &icon_width, &icon_height, nil, 4)
|
|
||||||
defer image.image_free(icon_data)
|
|
||||||
assert(icon_data != nil, "Failed to load icon image")
|
|
||||||
|
|
||||||
target_size := 2 + icon_width * icon_height
|
|
||||||
|
|
||||||
data := make([]u64, target_size)
|
|
||||||
|
|
||||||
// first two elements are width and height
|
|
||||||
data[0] = cast(u64)icon_width
|
|
||||||
data[1] = cast(u64)icon_height
|
|
||||||
|
|
||||||
for i in 0..<(icon_width * icon_height) {
|
|
||||||
data[i + 2] = (cast(u64)icon_data[i * 4] << 16) | (cast(u64)icon_data[i * 4 + 1] << 8) | (cast(u64)icon_data[i * 4 + 2] << 0) | (cast(u64)icon_data[i * 4 + 3] << 24)
|
|
||||||
}
|
|
||||||
|
|
||||||
net_wm_icon := x11.XInternAtom(x11_display, "_NET_WM_ICON", false)
|
|
||||||
x11.XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, raw_data(data), target_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
@private
|
|
||||||
x11_get_screen_size :: proc() -> Vec2 {
|
|
||||||
screen := x11.XDefaultScreenOfDisplay(x11_display)
|
|
||||||
|
|
||||||
return Vec2{cast(f32)screen.width, cast(f32)screen.height}
|
|
||||||
}
|
|
||||||
|
|
||||||
@private
|
|
||||||
x11_resize_window :: proc() {
|
|
||||||
win_attrs : x11.XWindowAttributes
|
|
||||||
x11.XGetWindowAttributes(x11_display, x11_window, &win_attrs)
|
|
||||||
gl.Viewport(0, 0, win_attrs.width, win_attrs.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
@private
|
|
||||||
x11_create_window :: proc(window_title: cstring, window_size: Vec2, icon_path: cstring, window_non_resizable: bool) {
|
|
||||||
context.logger = logger
|
|
||||||
x11_display = x11.XOpenDisplay(nil)
|
|
||||||
|
|
||||||
if x11_display == nil {
|
|
||||||
log.error("Failed to open X11 display")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
screen_num := x11.XDefaultScreen(x11_display)
|
|
||||||
root := x11.XRootWindow(x11_display, screen_num)
|
|
||||||
visual := x11.XDefaultVisual(x11_display, screen_num)
|
|
||||||
|
|
||||||
x11_colormap = x11.XCreateColormap(x11_display, root, visual, x11.ColormapAlloc.AllocNone)
|
|
||||||
|
|
||||||
attributes: x11.XSetWindowAttributes
|
|
||||||
attributes.event_mask = {.Exposure, .KeyPress, .KeyRelease,
|
|
||||||
.StructureNotify, .ButtonPress, .ButtonRelease, .PointerMotion}
|
|
||||||
attributes.colormap = x11_colormap
|
|
||||||
|
|
||||||
screen := x11.XDefaultScreenOfDisplay(x11_display)
|
|
||||||
|
|
||||||
window_start_x := screen.width / 2 - cast(i32)window_size.x / 2
|
|
||||||
window_start_y := screen.height / 2 - cast(i32)window_size.y / 2
|
|
||||||
|
|
||||||
x11_window = x11.XCreateWindow(x11_display, root, window_start_x, window_start_y, cast(u32)window_size.x, cast(u32)window_size.y, 0,
|
|
||||||
x11.XDefaultDepth(x11_display), .InputOutput, visual,
|
|
||||||
{.CWColormap, .CWEventMask}, &attributes)
|
|
||||||
|
|
||||||
if (icon_path != "") {
|
|
||||||
x11_assign_window_icon(icon_path, window_title)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hints to the WM that the window is a normal window
|
|
||||||
// Of course this is only a hint and the WM can ignore it
|
|
||||||
net_wm_window_type := x11.XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", false)
|
|
||||||
net_wm_window_type_normal := x11.XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", false)
|
|
||||||
x11.XChangeProperty(x11_display, x11_window, net_wm_window_type, XA_ATOM, 32, PropModeReplace, &net_wm_window_type_normal, 1)
|
|
||||||
|
|
||||||
wm_delete_window := x11.XInternAtom(x11_display, "WM_DELETE_WINDOW", false)
|
|
||||||
x11.XSetWMProtocols(x11_display, x11_window, &wm_delete_window, 1)
|
|
||||||
zephr_ctx.window_delete_atom = wm_delete_window
|
|
||||||
|
|
||||||
// set window name
|
|
||||||
{
|
|
||||||
UTF8_STRING := x11.XInternAtom(x11_display, "UTF8_STRING", false)
|
|
||||||
x11.XStoreName(x11_display, x11_window, window_title)
|
|
||||||
text_property: x11.XTextProperty
|
|
||||||
text_property.value = raw_data(string(window_title))
|
|
||||||
text_property.format = 8
|
|
||||||
text_property.encoding = UTF8_STRING
|
|
||||||
text_property.nitems = len(window_title)
|
|
||||||
x11.XSetWMName(x11_display, x11_window, &text_property)
|
|
||||||
net_wm_name := x11.XInternAtom(x11_display, "_NET_WM_NAME", false)
|
|
||||||
wm_class := x11.XInternAtom(x11_display, "WM_CLASS", false)
|
|
||||||
x11.XChangeProperty(x11_display, x11_window, net_wm_name, UTF8_STRING, 8, PropModeReplace, raw_data(string(window_title)), cast(i32)len(window_title))
|
|
||||||
x11.XChangeProperty(x11_display, x11_window, wm_class, XA_STRING, 8, PropModeReplace, raw_data(string(window_title)), cast(i32)len(window_title))
|
|
||||||
|
|
||||||
// name to be displayed when the window is reduced to an icon
|
|
||||||
net_wm_icon_name := x11.XInternAtom(x11_display, "_NET_WM_ICON_NAME", false)
|
|
||||||
x11.XChangeProperty(x11_display, x11_window, net_wm_icon_name, UTF8_STRING, 8, PropModeReplace, raw_data(string(window_title)), cast(i32)len(window_title))
|
|
||||||
|
|
||||||
text_property.encoding = XA_STRING
|
|
||||||
x11.XSetWMIconName(x11_display, x11_window, &text_property)
|
|
||||||
|
|
||||||
class_hint := x11.XAllocClassHint()
|
|
||||||
|
|
||||||
if (class_hint != nil) {
|
|
||||||
class_hint.res_name = window_title
|
|
||||||
class_hint.res_class = window_title
|
|
||||||
x11.XSetClassHint(x11_display, x11_window, class_hint)
|
|
||||||
x11.XFree(class_hint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_hints := x11.XAllocSizeHints()
|
|
||||||
|
|
||||||
if (size_hints != nil) {
|
|
||||||
size_hints.flags = {.PPosition, .PSize}
|
|
||||||
/* size_hints->win_gravity = StaticGravity; */
|
|
||||||
size_hints.x = window_start_x
|
|
||||||
size_hints.y = window_start_y
|
|
||||||
size_hints.width = cast(i32)window_size.x
|
|
||||||
size_hints.height = cast(i32)window_size.y
|
|
||||||
if (window_non_resizable) {
|
|
||||||
size_hints.flags |= {.PMinSize, .PMaxSize}
|
|
||||||
size_hints.min_width = cast(i32)window_size.x
|
|
||||||
size_hints.min_height = cast(i32)window_size.y
|
|
||||||
size_hints.max_width = cast(i32)window_size.x
|
|
||||||
size_hints.max_height = cast(i32)window_size.y
|
|
||||||
}
|
|
||||||
x11.XSetWMNormalHints(x11_display, x11_window, size_hints)
|
|
||||||
x11.XFree(size_hints)
|
|
||||||
}
|
|
||||||
|
|
||||||
x11.XMapWindow(x11_display, x11_window)
|
|
||||||
|
|
||||||
gl.load_up_to(3, 3, proc(p: rawptr, name: cstring) { (cast(^rawptr)p)^ = glx.GetProcAddressARB(raw_data(string(name))) })
|
|
||||||
|
|
||||||
glx_major : i32
|
|
||||||
glx_minor : i32
|
|
||||||
glx.QueryVersion(x11_display, &glx_major, &glx_minor)
|
|
||||||
|
|
||||||
log.infof("Loaded GLX: %d.%d", glx_major, glx_minor)
|
|
||||||
|
|
||||||
visual_attributes := []i32 {
|
|
||||||
glx.RENDER_TYPE, glx.RGBA_BIT,
|
|
||||||
glx.RED_SIZE, 8,
|
|
||||||
glx.GREEN_SIZE, 8,
|
|
||||||
glx.BLUE_SIZE, 8,
|
|
||||||
glx.ALPHA_SIZE, 8,
|
|
||||||
glx.DEPTH_SIZE, 24,
|
|
||||||
glx.DOUBLEBUFFER, 1,
|
|
||||||
glx.SAMPLES, 4, // MSAA
|
|
||||||
x11.None,
|
|
||||||
}
|
|
||||||
|
|
||||||
num_fbc: i32
|
|
||||||
fbc := glx.ChooseFBConfig(x11_display, screen_num, raw_data(visual_attributes), &num_fbc)
|
|
||||||
|
|
||||||
context_attributes := []i32 {
|
|
||||||
glx.CONTEXT_MAJOR_VERSION_ARB, 3,
|
|
||||||
glx.CONTEXT_MINOR_VERSION_ARB, 3,
|
|
||||||
glx.CONTEXT_PROFILE_MASK_ARB, glx.CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
||||||
x11.None,
|
|
||||||
}
|
|
||||||
|
|
||||||
glx_context = glx.CreateContextAttribsARB(x11_display, fbc[0], nil, true, raw_data(context_attributes))
|
|
||||||
|
|
||||||
if glx_context == nil {
|
|
||||||
log.error("Failed to create GLX context")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
glx.MakeCurrent(x11_display, x11_window, glx_context)
|
|
||||||
|
|
||||||
gl_version := gl.GetString(gl.VERSION)
|
|
||||||
|
|
||||||
log.infof("GL Version: %s", gl_version)
|
|
||||||
|
|
||||||
glx.SwapIntervalEXT(x11_display, x11_window, 1)
|
|
||||||
// we enable blending for text
|
|
||||||
gl.Enable(gl.BLEND)
|
|
||||||
gl.Enable(gl.MULTISAMPLE)
|
|
||||||
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
|
||||||
x11_resize_window()
|
|
||||||
|
|
||||||
x11.XFree(fbc)
|
|
||||||
}
|
|
||||||
|
|
||||||
@private
|
|
||||||
x11_init :: proc(window_title: cstring, window_size: Vec2, icon_path: cstring, window_non_resizable: bool) {
|
|
||||||
x11_create_window(window_title, window_size, icon_path, window_non_resizable)
|
|
||||||
}
|
|
||||||
|
|
||||||
@private
|
|
||||||
x11_close :: proc() {
|
|
||||||
glx.MakeCurrent(x11_display, 0, nil)
|
|
||||||
glx.DestroyContext(x11_display, glx_context)
|
|
||||||
|
|
||||||
x11.XDestroyWindow(x11_display, x11_window)
|
|
||||||
x11.XFreeColormap(x11_display, x11_colormap)
|
|
||||||
x11.XCloseDisplay(x11_display)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
//
|
//
|
||||||
// Zephr
|
// Zephr
|
||||||
@@ -957,7 +652,7 @@ init :: proc(font_path: cstring, icon_path: cstring, window_title: cstring, wind
|
|||||||
//int res = audio_init();
|
//int res = audio_init();
|
||||||
//CORE_ASSERT(res == 0, "Failed to initialize audio");
|
//CORE_ASSERT(res == 0, "Failed to initialize audio");
|
||||||
|
|
||||||
x11_init(window_title, window_size, icon_path, window_non_resizable)
|
backend_init(window_title, window_size, icon_path, window_non_resizable)
|
||||||
|
|
||||||
ui_init(font_path)
|
ui_init(font_path)
|
||||||
|
|
||||||
@@ -967,22 +662,22 @@ init :: proc(font_path: cstring, icon_path: cstring, window_title: cstring, wind
|
|||||||
zephr_ctx.window.non_resizable = window_non_resizable
|
zephr_ctx.window.non_resizable = window_non_resizable
|
||||||
zephr_ctx.projection = orthographic_projection_2d(0, window_size.x, window_size.y, 0)
|
zephr_ctx.projection = orthographic_projection_2d(0, window_size.x, window_size.y, 0)
|
||||||
|
|
||||||
zephr_ctx.cursors[.ARROW] = x11.XCreateFontCursor(x11_display, .XC_left_ptr)
|
// zephr_ctx.cursors[.ARROW] = x11.XCreateFontCursor(x11_display, .XC_left_ptr)
|
||||||
zephr_ctx.cursors[.IBEAM] = x11.XCreateFontCursor(x11_display, .XC_xterm)
|
// zephr_ctx.cursors[.IBEAM] = x11.XCreateFontCursor(x11_display, .XC_xterm)
|
||||||
zephr_ctx.cursors[.CROSSHAIR] = x11.XCreateFontCursor(x11_display, .XC_crosshair)
|
// zephr_ctx.cursors[.CROSSHAIR] = x11.XCreateFontCursor(x11_display, .XC_crosshair)
|
||||||
zephr_ctx.cursors[.HAND] = x11.XCreateFontCursor(x11_display, .XC_hand1)
|
// zephr_ctx.cursors[.HAND] = x11.XCreateFontCursor(x11_display, .XC_hand1)
|
||||||
zephr_ctx.cursors[.HRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_h_double_arrow)
|
// zephr_ctx.cursors[.HRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_h_double_arrow)
|
||||||
zephr_ctx.cursors[.VRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_v_double_arrow)
|
// zephr_ctx.cursors[.VRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_v_double_arrow)
|
||||||
|
|
||||||
// non-standard cursors
|
// non-standard cursors
|
||||||
zephr_ctx.cursors[.DISABLED] = xcursor.LibraryLoadCursor(x11_display, "crossed_circle")
|
// zephr_ctx.cursors[.DISABLED] = xcursor.LibraryLoadCursor(x11_display, "crossed_circle")
|
||||||
|
|
||||||
zephr_ctx.screen_size = x11_get_screen_size()
|
zephr_ctx.screen_size = backend_get_screen_size()
|
||||||
start_internal_timer()
|
start_internal_timer()
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit :: proc() {
|
deinit :: proc() {
|
||||||
x11_close()
|
backend_shutdown()
|
||||||
//audio_close()
|
//audio_close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,153 +722,157 @@ swap_buffers :: proc() {
|
|||||||
zephr_ctx.ui.hovered_element = 0
|
zephr_ctx.ui.hovered_element = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
glx.SwapBuffers(x11_display, x11_window)
|
backend_swapbuffers()
|
||||||
x11.XDefineCursor(x11_display, x11_window, zephr_ctx.cursors[zephr_ctx.cursor])
|
//x11.XDefineCursor(x11_display, x11_window, zephr_ctx.cursors[zephr_ctx.cursor])
|
||||||
}
|
}
|
||||||
|
|
||||||
iter_events :: proc(e_out: ^Event) -> bool {
|
iter_events :: proc(e_out: ^Event) -> bool {
|
||||||
context.logger = logger
|
return backend_get_os_events(e_out)
|
||||||
xev: x11.XEvent
|
|
||||||
|
|
||||||
for (cast(bool)x11.XPending(x11_display)) {
|
|
||||||
x11.XNextEvent(x11_display, &xev)
|
|
||||||
|
|
||||||
if xev.type == .ConfigureNotify {
|
|
||||||
xce := xev.xconfigure
|
|
||||||
|
|
||||||
if (xce.width != cast(i32)zephr_ctx.window.size.x || xce.height != cast(i32)zephr_ctx.window.size.y) {
|
|
||||||
zephr_ctx.window.size = Vec2{cast(f32)xce.width, cast(f32)xce.height}
|
|
||||||
zephr_ctx.projection = orthographic_projection_2d(0, zephr_ctx.window.size.x, zephr_ctx.window.size.y, 0)
|
|
||||||
x11_resize_window()
|
|
||||||
|
|
||||||
e_out.type = .WINDOW_RESIZED
|
|
||||||
e_out.window.width = cast(u32)xce.width
|
|
||||||
e_out.window.height = cast(u32)xce.height
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else if xev.type == .DestroyNotify {
|
|
||||||
// window destroy event
|
|
||||||
e_out.type = .WINDOW_CLOSED
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else if xev.type == .ClientMessage {
|
|
||||||
// window close event
|
|
||||||
if (cast(x11.Atom)xev.xclient.data.l[0] == zephr_ctx.window_delete_atom) {
|
|
||||||
e_out.type = .WINDOW_CLOSED
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else if xev.type == .KeyPress {
|
|
||||||
xke := xev.xkey
|
|
||||||
|
|
||||||
evdev_keycode := xke.keycode - 8
|
|
||||||
scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode]
|
|
||||||
|
|
||||||
e_out.type = .KEY_PRESSED
|
|
||||||
e_out.key.scancode = scancode
|
|
||||||
//e_out.key.code = keycode;
|
|
||||||
e_out.key.mods = x11_mods_to_zephr_mods(scancode, true)
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else if xev.type == .KeyRelease {
|
|
||||||
xke := xev.xkey
|
|
||||||
|
|
||||||
evdev_keycode := xke.keycode - 8
|
|
||||||
scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode]
|
|
||||||
|
|
||||||
e_out.type = .KEY_RELEASED
|
|
||||||
e_out.key.scancode = scancode
|
|
||||||
//e_out.key.code = keycode;
|
|
||||||
e_out.key.mods = x11_mods_to_zephr_mods(scancode, false)
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else if xev.type == .ButtonPress {
|
|
||||||
e_out.type = .MOUSE_BUTTON_PRESSED
|
|
||||||
e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y}
|
|
||||||
zephr_ctx.mouse.pressed = true
|
|
||||||
|
|
||||||
switch (xev.xbutton.button) {
|
|
||||||
case .Button1:
|
|
||||||
e_out.mouse.button = .BUTTON_LEFT
|
|
||||||
zephr_ctx.mouse.button = .BUTTON_LEFT
|
|
||||||
case .Button2:
|
|
||||||
e_out.mouse.button = .BUTTON_MIDDLE
|
|
||||||
zephr_ctx.mouse.button = .BUTTON_MIDDLE
|
|
||||||
case .Button3:
|
|
||||||
e_out.mouse.button = .BUTTON_RIGHT
|
|
||||||
zephr_ctx.mouse.button = .BUTTON_RIGHT
|
|
||||||
case .Button4:
|
|
||||||
e_out.type = .MOUSE_SCROLL
|
|
||||||
e_out.mouse.scroll_direction = .UP
|
|
||||||
case .Button5:
|
|
||||||
e_out.type = .MOUSE_SCROLL
|
|
||||||
e_out.mouse.scroll_direction = .DOWN
|
|
||||||
case cast(x11.MouseButton)8: // Back
|
|
||||||
e_out.mouse.button = .BUTTON_BACK
|
|
||||||
zephr_ctx.mouse.button = .BUTTON_BACK
|
|
||||||
case cast(x11.MouseButton)9: // Forward
|
|
||||||
e_out.mouse.button = .BUTTON_FORWARD
|
|
||||||
zephr_ctx.mouse.button = .BUTTON_FORWARD
|
|
||||||
case:
|
|
||||||
log.warnf("Unknown mouse button pressed: %d", xev.xbutton.button)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else if xev.type == .ButtonRelease {
|
|
||||||
e_out.type = .MOUSE_BUTTON_RELEASED
|
|
||||||
e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y}
|
|
||||||
zephr_ctx.mouse.released = true
|
|
||||||
zephr_ctx.mouse.pressed = false
|
|
||||||
|
|
||||||
switch (xev.xbutton.button) {
|
|
||||||
case .Button1:
|
|
||||||
e_out.mouse.button = .BUTTON_LEFT
|
|
||||||
case .Button2:
|
|
||||||
e_out.mouse.button = .BUTTON_MIDDLE
|
|
||||||
case .Button3:
|
|
||||||
e_out.mouse.button = .BUTTON_RIGHT
|
|
||||||
case .Button4:
|
|
||||||
e_out.type = .MOUSE_SCROLL
|
|
||||||
e_out.mouse.scroll_direction = .UP
|
|
||||||
case .Button5:
|
|
||||||
e_out.type = .MOUSE_SCROLL
|
|
||||||
e_out.mouse.scroll_direction = .DOWN
|
|
||||||
case cast(x11.MouseButton)8: // Back
|
|
||||||
e_out.mouse.button = .BUTTON_BACK
|
|
||||||
zephr_ctx.mouse.button = .BUTTON_BACK
|
|
||||||
case cast(x11.MouseButton)9: // Forward
|
|
||||||
e_out.mouse.button = .BUTTON_FORWARD
|
|
||||||
zephr_ctx.mouse.button = .BUTTON_FORWARD
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else if xev.type == .MappingNotify {
|
|
||||||
// input device mapping changed
|
|
||||||
if (xev.xmapping.request != .MappingKeyboard) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
x11.XRefreshKeyboardMapping(&xev.xmapping)
|
|
||||||
/* x11_keyboard_map_update(); */
|
|
||||||
break
|
|
||||||
} else if xev.type == .MotionNotify {
|
|
||||||
e_out.type = .MOUSE_MOVED
|
|
||||||
e_out.mouse.pos = Vec2{cast(f32)xev.xmotion.x, cast(f32)xev.xmotion.y}
|
|
||||||
zephr_ctx.mouse.pos = e_out.mouse.pos
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// iter_events :: proc(e_out: ^Event) -> bool {
|
||||||
|
// context.logger = logger
|
||||||
|
// xev: x11.XEvent
|
||||||
|
|
||||||
|
// for (cast(bool)x11.XPending(x11_display)) {
|
||||||
|
// x11.XNextEvent(x11_display, &xev)
|
||||||
|
|
||||||
|
// if xev.type == .ConfigureNotify {
|
||||||
|
// xce := xev.xconfigure
|
||||||
|
|
||||||
|
// if (xce.width != cast(i32)zephr_ctx.window.size.x || xce.height != cast(i32)zephr_ctx.window.size.y) {
|
||||||
|
// zephr_ctx.window.size = Vec2{cast(f32)xce.width, cast(f32)xce.height}
|
||||||
|
// zephr_ctx.projection = orthographic_projection_2d(0, zephr_ctx.window.size.x, zephr_ctx.window.size.y, 0)
|
||||||
|
// x11_resize_window()
|
||||||
|
|
||||||
|
// e_out.type = .WINDOW_RESIZED
|
||||||
|
// e_out.window.width = cast(u32)xce.width
|
||||||
|
// e_out.window.height = cast(u32)xce.height
|
||||||
|
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// } else if xev.type == .DestroyNotify {
|
||||||
|
// // window destroy event
|
||||||
|
// e_out.type = .WINDOW_CLOSED
|
||||||
|
|
||||||
|
// return true
|
||||||
|
// } else if xev.type == .ClientMessage {
|
||||||
|
// // window close event
|
||||||
|
// if (cast(x11.Atom)xev.xclient.data.l[0] == zephr_ctx.window_delete_atom) {
|
||||||
|
// e_out.type = .WINDOW_CLOSED
|
||||||
|
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// } else if xev.type == .KeyPress {
|
||||||
|
// xke := xev.xkey
|
||||||
|
|
||||||
|
// evdev_keycode := xke.keycode - 8
|
||||||
|
// scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode]
|
||||||
|
|
||||||
|
// e_out.type = .KEY_PRESSED
|
||||||
|
// e_out.key.scancode = scancode
|
||||||
|
// //e_out.key.code = keycode;
|
||||||
|
// e_out.key.mods = x11_mods_to_zephr_mods(scancode, true)
|
||||||
|
|
||||||
|
// return true
|
||||||
|
// } else if xev.type == .KeyRelease {
|
||||||
|
// xke := xev.xkey
|
||||||
|
|
||||||
|
// evdev_keycode := xke.keycode - 8
|
||||||
|
// scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode]
|
||||||
|
|
||||||
|
// e_out.type = .KEY_RELEASED
|
||||||
|
// e_out.key.scancode = scancode
|
||||||
|
// //e_out.key.code = keycode;
|
||||||
|
// e_out.key.mods = x11_mods_to_zephr_mods(scancode, false)
|
||||||
|
|
||||||
|
// return true
|
||||||
|
// } else if xev.type == .ButtonPress {
|
||||||
|
// e_out.type = .MOUSE_BUTTON_PRESSED
|
||||||
|
// e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y}
|
||||||
|
// zephr_ctx.mouse.pressed = true
|
||||||
|
|
||||||
|
// switch (xev.xbutton.button) {
|
||||||
|
// case .Button1:
|
||||||
|
// e_out.mouse.button = .BUTTON_LEFT
|
||||||
|
// zephr_ctx.mouse.button = .BUTTON_LEFT
|
||||||
|
// case .Button2:
|
||||||
|
// e_out.mouse.button = .BUTTON_MIDDLE
|
||||||
|
// zephr_ctx.mouse.button = .BUTTON_MIDDLE
|
||||||
|
// case .Button3:
|
||||||
|
// e_out.mouse.button = .BUTTON_RIGHT
|
||||||
|
// zephr_ctx.mouse.button = .BUTTON_RIGHT
|
||||||
|
// case .Button4:
|
||||||
|
// e_out.type = .MOUSE_SCROLL
|
||||||
|
// e_out.mouse.scroll_direction = .UP
|
||||||
|
// case .Button5:
|
||||||
|
// e_out.type = .MOUSE_SCROLL
|
||||||
|
// e_out.mouse.scroll_direction = .DOWN
|
||||||
|
// case cast(x11.MouseButton)8: // Back
|
||||||
|
// e_out.mouse.button = .BUTTON_BACK
|
||||||
|
// zephr_ctx.mouse.button = .BUTTON_BACK
|
||||||
|
// case cast(x11.MouseButton)9: // Forward
|
||||||
|
// e_out.mouse.button = .BUTTON_FORWARD
|
||||||
|
// zephr_ctx.mouse.button = .BUTTON_FORWARD
|
||||||
|
// case:
|
||||||
|
// log.warnf("Unknown mouse button pressed: %d", xev.xbutton.button)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return true
|
||||||
|
// } else if xev.type == .ButtonRelease {
|
||||||
|
// e_out.type = .MOUSE_BUTTON_RELEASED
|
||||||
|
// e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y}
|
||||||
|
// zephr_ctx.mouse.released = true
|
||||||
|
// zephr_ctx.mouse.pressed = false
|
||||||
|
|
||||||
|
// switch (xev.xbutton.button) {
|
||||||
|
// case .Button1:
|
||||||
|
// e_out.mouse.button = .BUTTON_LEFT
|
||||||
|
// case .Button2:
|
||||||
|
// e_out.mouse.button = .BUTTON_MIDDLE
|
||||||
|
// case .Button3:
|
||||||
|
// e_out.mouse.button = .BUTTON_RIGHT
|
||||||
|
// case .Button4:
|
||||||
|
// e_out.type = .MOUSE_SCROLL
|
||||||
|
// e_out.mouse.scroll_direction = .UP
|
||||||
|
// case .Button5:
|
||||||
|
// e_out.type = .MOUSE_SCROLL
|
||||||
|
// e_out.mouse.scroll_direction = .DOWN
|
||||||
|
// case cast(x11.MouseButton)8: // Back
|
||||||
|
// e_out.mouse.button = .BUTTON_BACK
|
||||||
|
// zephr_ctx.mouse.button = .BUTTON_BACK
|
||||||
|
// case cast(x11.MouseButton)9: // Forward
|
||||||
|
// e_out.mouse.button = .BUTTON_FORWARD
|
||||||
|
// zephr_ctx.mouse.button = .BUTTON_FORWARD
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return true
|
||||||
|
// } else if xev.type == .MappingNotify {
|
||||||
|
// // input device mapping changed
|
||||||
|
// if (xev.xmapping.request != .MappingKeyboard) {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// x11.XRefreshKeyboardMapping(&xev.xmapping)
|
||||||
|
// /* x11_keyboard_map_update(); */
|
||||||
|
// break
|
||||||
|
// } else if xev.type == .MotionNotify {
|
||||||
|
// e_out.type = .MOUSE_MOVED
|
||||||
|
// e_out.mouse.pos = Vec2{cast(f32)xev.xmotion.x, cast(f32)xev.xmotion.y}
|
||||||
|
// zephr_ctx.mouse.pos = e_out.mouse.pos
|
||||||
|
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
|
||||||
get_window_size :: proc() -> Vec2 {
|
get_window_size :: proc() -> Vec2 {
|
||||||
return zephr_ctx.window.size
|
return zephr_ctx.window.size
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle_fullscreen :: proc() {
|
toggle_fullscreen :: proc() {
|
||||||
x11_toggle_fullscreen(zephr_ctx.window.is_fullscreen)
|
backend_toggle_fullscreen(zephr_ctx.window.is_fullscreen)
|
||||||
|
|
||||||
zephr_ctx.window.is_fullscreen = !zephr_ctx.window.is_fullscreen
|
zephr_ctx.window.is_fullscreen = !zephr_ctx.window.is_fullscreen
|
||||||
}
|
}
|
||||||
@@ -1205,94 +904,6 @@ fnv_hash32 :: proc(data: []byte, size: u32, hash: u32) -> u32 {
|
|||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
@private
|
|
||||||
x11_mods_to_zephr_mods :: proc(scancode: Scancode, is_press: bool) -> KeyMod {
|
|
||||||
mods := zephr_ctx.keyboard.mods
|
|
||||||
|
|
||||||
if (is_press) {
|
|
||||||
if (scancode == .LEFT_SHIFT) {
|
|
||||||
mods |= {.LEFT_SHIFT, .SHIFT}
|
|
||||||
}
|
|
||||||
if (scancode == .RIGHT_SHIFT) {
|
|
||||||
mods |= {.RIGHT_SHIFT, .SHIFT}
|
|
||||||
}
|
|
||||||
if (scancode == .LEFT_CTRL) {
|
|
||||||
mods |= {.LEFT_CTRL, .CTRL}
|
|
||||||
}
|
|
||||||
if (scancode == .RIGHT_CTRL) {
|
|
||||||
mods |= {.RIGHT_CTRL, .CTRL}
|
|
||||||
}
|
|
||||||
if (scancode == .LEFT_ALT) {
|
|
||||||
mods |= {.LEFT_ALT, .ALT}
|
|
||||||
}
|
|
||||||
if (scancode == .RIGHT_ALT) {
|
|
||||||
mods |= {.RIGHT_ALT, .ALT}
|
|
||||||
}
|
|
||||||
if (scancode == .LEFT_META) {
|
|
||||||
mods |= {.LEFT_META, .META}
|
|
||||||
}
|
|
||||||
if (scancode == .RIGHT_META) {
|
|
||||||
mods |= {.RIGHT_META, .META}
|
|
||||||
}
|
|
||||||
if (scancode == .CAPS_LOCK) {
|
|
||||||
mods |= {.CAPS_LOCK}
|
|
||||||
}
|
|
||||||
if (scancode == .NUM_LOCK_OR_CLEAR) {
|
|
||||||
mods |= {.NUM_LOCK}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (scancode == .LEFT_SHIFT) {
|
|
||||||
mods &= ~{.LEFT_SHIFT}
|
|
||||||
}
|
|
||||||
if (scancode == .RIGHT_SHIFT) {
|
|
||||||
mods &= ~{.RIGHT_SHIFT}
|
|
||||||
}
|
|
||||||
if (!(.RIGHT_SHIFT in mods) && !(.LEFT_SHIFT in mods)) {
|
|
||||||
mods &= ~{.SHIFT}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scancode == .LEFT_CTRL) {
|
|
||||||
mods &= ~{.LEFT_CTRL}
|
|
||||||
}
|
|
||||||
if (scancode == .RIGHT_CTRL) {
|
|
||||||
mods &= ~{.RIGHT_CTRL}
|
|
||||||
}
|
|
||||||
if (!(.RIGHT_CTRL in mods) && !(.LEFT_CTRL in mods)) {
|
|
||||||
mods &= ~{.CTRL}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scancode == .LEFT_ALT) {
|
|
||||||
mods &= ~{.LEFT_ALT}
|
|
||||||
}
|
|
||||||
if (scancode == .RIGHT_ALT) {
|
|
||||||
mods &= ~{.RIGHT_ALT}
|
|
||||||
}
|
|
||||||
if (!(.RIGHT_ALT in mods) && !(.LEFT_ALT in mods)) {
|
|
||||||
mods &= ~{.ALT}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scancode == .LEFT_META) {
|
|
||||||
mods &= ~{.LEFT_META}
|
|
||||||
}
|
|
||||||
if (scancode == .RIGHT_META) {
|
|
||||||
mods &= ~{.RIGHT_META}
|
|
||||||
}
|
|
||||||
if (!(.RIGHT_META in mods) && !(.LEFT_META in mods)) {
|
|
||||||
mods &= ~{.META}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scancode == .CAPS_LOCK) {
|
|
||||||
mods &= ~{.CAPS_LOCK}
|
|
||||||
}
|
|
||||||
if (scancode == .NUM_LOCK_OR_CLEAR) {
|
|
||||||
mods &= ~{.NUM_LOCK}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zephr_ctx.keyboard.mods = mods
|
|
||||||
return mods
|
|
||||||
}
|
|
||||||
|
|
||||||
@private
|
@private
|
||||||
logger_init :: proc() {
|
logger_init :: proc() {
|
||||||
buf : [128]byte
|
buf : [128]byte
|
||||||
@@ -1308,5 +919,4 @@ logger_init :: proc() {
|
|||||||
term_logger := log.create_console_logger(opt = TerminalLoggerOpts)
|
term_logger := log.create_console_logger(opt = TerminalLoggerOpts)
|
||||||
|
|
||||||
logger = log.create_multi_logger(file_logger, term_logger)
|
logger = log.create_multi_logger(file_logger, term_logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user