Split display from render and rework init/terminate.
This commit is contained in:
parent
0c560890a4
commit
026ead0b33
4
Makefile
4
Makefile
@ -14,9 +14,9 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
cpp/opengl/render_context_glx.cpp \
|
cpp/display/display_glx.cpp \
|
||||||
cpp/opengl/render_opengles.cpp \
|
|
||||||
cpp/events/events_x11.cpp \
|
cpp/events/events_x11.cpp \
|
||||||
|
cpp/render/render_opengles.cpp \
|
||||||
cpp/math.cpp
|
cpp/math.cpp
|
||||||
|
|
||||||
OUTPUTFILE = engine.so
|
OUTPUTFILE = engine.so
|
||||||
|
172
__init__.py
172
__init__.py
@ -19,6 +19,31 @@ from pathlib import Path
|
|||||||
|
|
||||||
_engine = ctypes.cdll.LoadLibrary(Path(__file__).parent / "engine.so")
|
_engine = ctypes.cdll.LoadLibrary(Path(__file__).parent / "engine.so")
|
||||||
|
|
||||||
|
# types.hpp
|
||||||
|
|
||||||
|
def _flag(x):
|
||||||
|
return 1 << x
|
||||||
|
|
||||||
|
def buffer(type, size):
|
||||||
|
return (type * size)()
|
||||||
|
|
||||||
|
def _voidp(x):
|
||||||
|
return x.buffer_info()[0]
|
||||||
|
|
||||||
|
def _ubytep(x):
|
||||||
|
assert x.typecode == 'B'
|
||||||
|
return x.buffer_info()[0]
|
||||||
|
|
||||||
|
def _ushortp(x):
|
||||||
|
assert x.typecode == 'H'
|
||||||
|
return x.buffer_info()[0]
|
||||||
|
|
||||||
|
def _floatp(x):
|
||||||
|
assert x.typecode == 'f'
|
||||||
|
return x.buffer_info()[0]
|
||||||
|
|
||||||
|
# math.hpp
|
||||||
|
|
||||||
class vec3(ctypes.Structure):
|
class vec3(ctypes.Structure):
|
||||||
_fields_ = ('x', ctypes.c_float), ('y', ctypes.c_float), ('z', ctypes.c_float)
|
_fields_ = ('x', ctypes.c_float), ('y', ctypes.c_float), ('z', ctypes.c_float)
|
||||||
|
|
||||||
@ -42,71 +67,14 @@ class mat3(ctypes.Structure):
|
|||||||
class mat4(ctypes.Structure):
|
class mat4(ctypes.Structure):
|
||||||
_fields_ = ('x', vec4), ('y', vec4), ('z', vec4), ('w', vec4)
|
_fields_ = ('x', vec4), ('y', vec4), ('z', vec4), ('w', vec4)
|
||||||
|
|
||||||
vec3_right = vec3(1.0, 0.0, 0.0)
|
|
||||||
vec3_forward = vec3(0.0, 1.0, 0.0)
|
|
||||||
vec3_up = vec3(0.0, 0.0, 1.0)
|
|
||||||
|
|
||||||
def _flag(x):
|
|
||||||
return 1 << x
|
|
||||||
|
|
||||||
TEXTURE_FORMAT_SRGB8_A8 = 0
|
|
||||||
TEXTURE_FORMAT_RGBA8 = 1
|
|
||||||
TEXTURE_FORMAT_RGB10_A2 = 2
|
|
||||||
TEXTURE_FORMAT_32F = 3
|
|
||||||
|
|
||||||
TEXTURE_FORMAT_TYPECODE = ('B', 'B', 'I', 'f')
|
|
||||||
TEXTURE_FORMAT_NELEMS = (4, 4, 1, 1)
|
|
||||||
|
|
||||||
TEXTURE_FLAG_3D = _flag(0)
|
|
||||||
TEXTURE_FLAG_MIPMAPS = _flag(1)
|
|
||||||
TEXTURE_FLAG_MIN_NEAREST = 0
|
|
||||||
TEXTURE_FLAG_MIN_LINEAR = _flag(2)
|
|
||||||
TEXTURE_FLAG_MAG_NEAREST = 0
|
|
||||||
TEXTURE_FLAG_MAG_LINEAR = _flag(3)
|
|
||||||
|
|
||||||
VERTEX_FORMAT_VEC3_FLOAT = 1
|
|
||||||
VERTEX_FORMAT_VEC3_INT10 = 2
|
|
||||||
VERTEX_FORMAT_VEC3_UINT10 = 3
|
|
||||||
VERTEX_FORMAT_NORMALIZE = _flag(7)
|
|
||||||
|
|
||||||
def vertex_format(*format):
|
|
||||||
return array('B', format).tobytes()
|
|
||||||
|
|
||||||
PARAM_FORMAT_VEC3_FLOAT = 1
|
|
||||||
PARAM_FORMAT_VEC3_SHORT = 2
|
|
||||||
PARAM_FORMAT_VEC3_INT10 = 3
|
|
||||||
PARAM_FORMAT_NORMALIZE = _flag(7)
|
|
||||||
|
|
||||||
def params_format(*format):
|
|
||||||
return array('B', format).tobytes()
|
|
||||||
|
|
||||||
INSTANCE_FLAG_SPAWNED = _flag(0)
|
|
||||||
INSTANCE_FLAG_VISIBLE = _flag(1)
|
|
||||||
|
|
||||||
BATCH_MAX_SIZE = 65536
|
|
||||||
|
|
||||||
def buffer(type, size):
|
|
||||||
return (type * size)()
|
|
||||||
|
|
||||||
_vec3p = ctypes.POINTER(vec3)
|
_vec3p = ctypes.POINTER(vec3)
|
||||||
_vec4p = ctypes.POINTER(vec4)
|
_vec4p = ctypes.POINTER(vec4)
|
||||||
_mat3p = ctypes.POINTER(mat3)
|
_mat3p = ctypes.POINTER(mat3)
|
||||||
_mat4p = ctypes.POINTER(mat4)
|
_mat4p = ctypes.POINTER(mat4)
|
||||||
|
|
||||||
def _voidp(x):
|
vec3_right = vec3(1.0, 0.0, 0.0)
|
||||||
return x.buffer_info()[0]
|
vec3_forward = vec3(0.0, 1.0, 0.0)
|
||||||
|
vec3_up = vec3(0.0, 0.0, 1.0)
|
||||||
def _ubytep(x):
|
|
||||||
assert x.typecode == 'B'
|
|
||||||
return x.buffer_info()[0]
|
|
||||||
|
|
||||||
def _ushortp(x):
|
|
||||||
assert x.typecode == 'H'
|
|
||||||
return x.buffer_info()[0]
|
|
||||||
|
|
||||||
def _floatp(x):
|
|
||||||
assert x.typecode == 'f'
|
|
||||||
return x.buffer_info()[0]
|
|
||||||
|
|
||||||
vec3_rotate = _engine.rk_vec3_rotate
|
vec3_rotate = _engine.rk_vec3_rotate
|
||||||
vec3_rotate.argtypes = (
|
vec3_rotate.argtypes = (
|
||||||
@ -173,13 +141,64 @@ mat4_mul_mat4.argtypes = (
|
|||||||
_mat4p, # a
|
_mat4p, # a
|
||||||
_mat4p) # b
|
_mat4p) # b
|
||||||
|
|
||||||
initialize = _engine.rk_initialize
|
# display.hpp
|
||||||
initialize.restype = ctypes.c_void_p
|
|
||||||
initialize.argtypes = (
|
create_display = _engine.rk_create_display
|
||||||
|
create_display.restype = ctypes.c_void_p
|
||||||
|
create_display.argtypes = (
|
||||||
ctypes.c_char_p, # name
|
ctypes.c_char_p, # name
|
||||||
ctypes.c_uint, # width
|
ctypes.c_uint, # width
|
||||||
ctypes.c_uint) # height
|
ctypes.c_uint) # height
|
||||||
|
|
||||||
|
destroy_display = _engine.rk_destroy_display
|
||||||
|
destroy_display.argtypes = (
|
||||||
|
ctypes.c_void_p,) # display
|
||||||
|
|
||||||
|
swap_buffers = _engine.rk_swap_buffers
|
||||||
|
swap_buffers.argtypes = (
|
||||||
|
ctypes.c_void_p,) # display
|
||||||
|
|
||||||
|
# render.hpp
|
||||||
|
|
||||||
|
TEXTURE_FORMAT_SRGB8_A8 = 0
|
||||||
|
TEXTURE_FORMAT_RGBA8 = 1
|
||||||
|
TEXTURE_FORMAT_RGB10_A2 = 2
|
||||||
|
TEXTURE_FORMAT_32F = 3
|
||||||
|
|
||||||
|
TEXTURE_FORMAT_TYPECODE = ('B', 'B', 'I', 'f')
|
||||||
|
TEXTURE_FORMAT_NELEMS = (4, 4, 1, 1)
|
||||||
|
|
||||||
|
TEXTURE_FLAG_3D = _flag(0)
|
||||||
|
TEXTURE_FLAG_MIPMAPS = _flag(1)
|
||||||
|
TEXTURE_FLAG_MIN_NEAREST = 0
|
||||||
|
TEXTURE_FLAG_MIN_LINEAR = _flag(2)
|
||||||
|
TEXTURE_FLAG_MAG_NEAREST = 0
|
||||||
|
TEXTURE_FLAG_MAG_LINEAR = _flag(3)
|
||||||
|
|
||||||
|
VERTEX_FORMAT_VEC3_FLOAT = 1
|
||||||
|
VERTEX_FORMAT_VEC3_INT10 = 2
|
||||||
|
VERTEX_FORMAT_VEC3_UINT10 = 3
|
||||||
|
VERTEX_FORMAT_NORMALIZE = _flag(7)
|
||||||
|
|
||||||
|
def vertex_format(*format):
|
||||||
|
return array('B', format).tobytes()
|
||||||
|
|
||||||
|
PARAM_FORMAT_VEC3_FLOAT = 1
|
||||||
|
PARAM_FORMAT_VEC3_SHORT = 2
|
||||||
|
PARAM_FORMAT_VEC3_INT10 = 3
|
||||||
|
PARAM_FORMAT_NORMALIZE = _flag(7)
|
||||||
|
|
||||||
|
def params_format(*format):
|
||||||
|
return array('B', format).tobytes()
|
||||||
|
|
||||||
|
INSTANCE_FLAG_SPAWNED = _flag(0)
|
||||||
|
INSTANCE_FLAG_VISIBLE = _flag(1)
|
||||||
|
|
||||||
|
BATCH_MAX_SIZE = 65536
|
||||||
|
|
||||||
|
render_initialize = _engine.rk_render_initialize
|
||||||
|
render_terminate = _engine.rk_render_terminate
|
||||||
|
|
||||||
_load_shader = _engine.rk_load_shader
|
_load_shader = _engine.rk_load_shader
|
||||||
_load_shader.restype = ctypes.c_void_p
|
_load_shader.restype = ctypes.c_void_p
|
||||||
_load_shader.argtypes = (
|
_load_shader.argtypes = (
|
||||||
@ -343,7 +362,7 @@ destroy_shader = _engine.rk_destroy_shader
|
|||||||
destroy_shader.argtypes = (
|
destroy_shader.argtypes = (
|
||||||
ctypes.c_void_p,) # shader
|
ctypes.c_void_p,) # shader
|
||||||
|
|
||||||
terminate = _engine.rk_terminate
|
# events.hpp
|
||||||
|
|
||||||
EVENT_FOCUS_IN = 0
|
EVENT_FOCUS_IN = 0
|
||||||
EVENT_FOCUS_OUT = 1
|
EVENT_FOCUS_OUT = 1
|
||||||
@ -382,12 +401,24 @@ class _Events(ctypes.Union):
|
|||||||
class Event(ctypes.Structure):
|
class Event(ctypes.Structure):
|
||||||
_fields_ = ('type', ctypes.c_uint), ('data', _Events)
|
_fields_ = ('type', ctypes.c_uint), ('data', _Events)
|
||||||
|
|
||||||
set_autorepeat = _engine.rk_set_autorepeat
|
create_events = _engine.rk_create_events
|
||||||
set_autorepeat.argtypes = (
|
create_events.restype = ctypes.c_void_p
|
||||||
ctypes.c_bool,) # autorepeat
|
create_events.argtypes = (
|
||||||
|
ctypes.c_void_p,) # display
|
||||||
|
|
||||||
set_acceleration = _engine.rk_set_acceleration
|
destroy_events = _engine.rk_destroy_events
|
||||||
set_acceleration.argtypes = (
|
destroy_events.argtypes = (
|
||||||
|
ctypes.c_void_p, # display
|
||||||
|
ctypes.c_void_p) # events
|
||||||
|
|
||||||
|
set_key_autorepeat = _engine.rk_set_key_autorepeat
|
||||||
|
set_key_autorepeat.argtypes = (
|
||||||
|
ctypes.c_void_p, # events
|
||||||
|
ctypes.c_bool) # autorepeat
|
||||||
|
|
||||||
|
set_motion_acceleration = _engine.rk_set_motion_acceleration
|
||||||
|
set_motion_acceleration.argtypes = (
|
||||||
|
ctypes.c_void_p, # events
|
||||||
ctypes.c_uint, # numerator
|
ctypes.c_uint, # numerator
|
||||||
ctypes.c_uint, # denominator
|
ctypes.c_uint, # denominator
|
||||||
ctypes.c_uint) # threshold
|
ctypes.c_uint) # threshold
|
||||||
@ -395,5 +426,6 @@ set_acceleration.argtypes = (
|
|||||||
consume_events = _engine.rk_consume_events
|
consume_events = _engine.rk_consume_events
|
||||||
consume_events.restype = ctypes.c_uint
|
consume_events.restype = ctypes.c_uint
|
||||||
consume_events.argtypes = (
|
consume_events.argtypes = (
|
||||||
ctypes.POINTER(Event), # events
|
ctypes.c_void_p, # events
|
||||||
|
ctypes.POINTER(Event), # buffer
|
||||||
ctypes.c_uint) # max_events
|
ctypes.c_uint) # max_events
|
||||||
|
34
cpp/display.hpp
Normal file
34
cpp/display.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (C) 2022 RozK
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef _RK_ENGINE_DISPLAY_H
|
||||||
|
#define _RK_ENGINE_DISPLAY_H
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
typedef rk_handle_t rk_display_t;
|
||||||
|
|
||||||
|
RK_EXPORT rk_display_t rk_create_display(
|
||||||
|
rk_char const * name,
|
||||||
|
rk_uint width,
|
||||||
|
rk_uint height);
|
||||||
|
|
||||||
|
RK_EXPORT void rk_destroy_display(
|
||||||
|
rk_display_t display);
|
||||||
|
|
||||||
|
RK_EXPORT void rk_swap_buffers(
|
||||||
|
rk_display_t display);
|
||||||
|
|
||||||
|
#endif // _RK_ENGINE_DISPLAY_H
|
243
cpp/display/display_glx.cpp
Normal file
243
cpp/display/display_glx.cpp
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
// Copyright (C) 2022 RozK
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Adapted from https://www.khronos.org/opengl/wiki/Tutorial:_OpenGL_3.0_Context_Creation_(GLX)
|
||||||
|
|
||||||
|
#include "../display.hpp"
|
||||||
|
#include "display_glx.hpp"
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
static bool rk_error_occured = false;
|
||||||
|
|
||||||
|
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||||
|
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||||
|
typedef GLXContext (*rk_CreateContextAttribsFunc)(Display *, GLXFBConfig, GLXContext, Bool, int const *);
|
||||||
|
|
||||||
|
rk_DrawElementsInstancedBaseInstanceFunc rk_DrawElementsInstancedBaseInstance = nullptr;
|
||||||
|
rk_MultiDrawElementsIndirectFunc rk_MultiDrawElementsIndirect = nullptr;
|
||||||
|
|
||||||
|
static int const rk_visual_attribs[] = {
|
||||||
|
GLX_X_RENDERABLE, True,
|
||||||
|
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||||
|
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||||
|
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
|
||||||
|
GLX_RED_SIZE, 8,
|
||||||
|
GLX_GREEN_SIZE, 8,
|
||||||
|
GLX_BLUE_SIZE, 8,
|
||||||
|
GLX_ALPHA_SIZE, 8,
|
||||||
|
GLX_DEPTH_SIZE, 24,
|
||||||
|
GLX_STENCIL_SIZE, 8,
|
||||||
|
GLX_DOUBLEBUFFER, True,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
static int const rk_context_attribs[] = {
|
||||||
|
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||||
|
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
|
||||||
|
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES_PROFILE_BIT_EXT,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rk_glx_printf(
|
||||||
|
char const * messsage) {
|
||||||
|
printf("[GLX] %s\n", messsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rk_extension_supported(
|
||||||
|
char const * extlist,
|
||||||
|
char const * extension) {
|
||||||
|
char const * where = strchr(extension, ' ');
|
||||||
|
if (where || *extension == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (char const * start = extlist;;) {
|
||||||
|
where = strstr(start, extension);
|
||||||
|
if (!where) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
char const * const terminator = where + strlen(extension);
|
||||||
|
if ((where == start || *(where - 1) == ' ') && (*terminator == ' ' || *terminator == '\0')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
start = terminator;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk_error_handler(
|
||||||
|
Display * display,
|
||||||
|
XErrorEvent * event) {
|
||||||
|
rk_error_occured = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rk_display_t rk_create_display(
|
||||||
|
rk_char const * name,
|
||||||
|
rk_uint width,
|
||||||
|
rk_uint height) {
|
||||||
|
if (!name || !width || !height) {
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
rk_display_glx * const display = new rk_display_glx;
|
||||||
|
display->display = XOpenDisplay(nullptr);
|
||||||
|
display->window = 0;
|
||||||
|
display->colormap = 0;
|
||||||
|
display->context = nullptr;
|
||||||
|
if (!display->display) {
|
||||||
|
rk_glx_printf("Failed to open X display.");
|
||||||
|
rk_destroy_display(reinterpret_cast<rk_display_t>(display));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int glx_major, glx_minor;
|
||||||
|
if (!glXQueryVersion(display->display, &glx_major, &glx_minor) ||
|
||||||
|
(glx_major == 1 && glx_minor < 3) || glx_major < 1) {
|
||||||
|
rk_glx_printf("Invalid GLX version.");
|
||||||
|
rk_destroy_display(reinterpret_cast<rk_display_t>(display));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
char const * const glx_exts = glXQueryExtensionsString(display->display, DefaultScreen(display->display));
|
||||||
|
|
||||||
|
int fbcount;
|
||||||
|
GLXFBConfig * const fbc = glXChooseFBConfig(
|
||||||
|
display->display, DefaultScreen(display->display), rk_visual_attribs, &fbcount);
|
||||||
|
if (!fbc) {
|
||||||
|
rk_glx_printf("Failed to retrieve framebuffer configs.");
|
||||||
|
rk_destroy_display(reinterpret_cast<rk_display_t>(display));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
printf("[GLX] Found %d framebuffer configs.\n", fbcount);
|
||||||
|
|
||||||
|
int best_fbc = -1;
|
||||||
|
int best_num_samp = -1;
|
||||||
|
for (int i = 0; i < fbcount; ++i) {
|
||||||
|
XVisualInfo * const vi = glXGetVisualFromFBConfig(display->display, fbc[i]);
|
||||||
|
if (vi) {
|
||||||
|
int samp_buf, samples;
|
||||||
|
glXGetFBConfigAttrib(display->display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
|
||||||
|
glXGetFBConfigAttrib(display->display, fbc[i], GLX_SAMPLES, &samples);
|
||||||
|
if (best_fbc < 0 || (samp_buf && samples > best_num_samp)) {
|
||||||
|
best_fbc = i;
|
||||||
|
best_num_samp = samples;
|
||||||
|
}
|
||||||
|
XFree(vi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best_fbc == -1) {
|
||||||
|
XFree(fbc);
|
||||||
|
rk_glx_printf("Failed to find a suitable framebuffer config.");
|
||||||
|
rk_destroy_display(reinterpret_cast<rk_display_t>(display));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
GLXFBConfig const bestFbc = fbc[best_fbc];
|
||||||
|
XFree(fbc);
|
||||||
|
printf("[GLX] Select framebuffer config with %d samples.\n", best_num_samp);
|
||||||
|
|
||||||
|
XVisualInfo * const vi = glXGetVisualFromFBConfig(display->display, bestFbc);
|
||||||
|
display->colormap = XCreateColormap(
|
||||||
|
display->display, RootWindow(display->display, vi->screen), vi->visual, AllocNone);
|
||||||
|
XSetWindowAttributes swa;
|
||||||
|
swa.colormap = display->colormap;
|
||||||
|
// swa.background_pixmap = None;
|
||||||
|
// swa.border_pixel = 0;
|
||||||
|
swa.event_mask = RK_EVENTS_MASK;
|
||||||
|
display->window = XCreateWindow(display->display, RootWindow(display->display, vi->screen),
|
||||||
|
0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
|
||||||
|
/*CWBorderPixel |*/ CWColormap | CWEventMask, &swa);
|
||||||
|
XFree(vi);
|
||||||
|
if (!display->window) {
|
||||||
|
rk_glx_printf("Failed to create window.");
|
||||||
|
rk_destroy_display(reinterpret_cast<rk_display_t>(display));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
XStoreName(display->display, display->window, name);
|
||||||
|
XMapWindow(display->display, display->window);
|
||||||
|
|
||||||
|
rk_CreateContextAttribsFunc const glXCreateContextAttribs =
|
||||||
|
reinterpret_cast<rk_CreateContextAttribsFunc>(
|
||||||
|
glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("glXCreateContextAttribsARB")));
|
||||||
|
|
||||||
|
if (!rk_extension_supported(glx_exts, "GLX_ARB_create_context") || !glXCreateContextAttribs) {
|
||||||
|
rk_glx_printf("glXCreateContextAttribsARB extension not found.");
|
||||||
|
rk_destroy_display(reinterpret_cast<rk_display_t>(display));
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
rk_error_occured = false;
|
||||||
|
int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&rk_error_handler);
|
||||||
|
display->context = glXCreateContextAttribs(display->display, bestFbc, 0, True, rk_context_attribs);
|
||||||
|
XSync(display->display, False);
|
||||||
|
XSetErrorHandler(oldHandler);
|
||||||
|
if (rk_error_occured || !display->context) {
|
||||||
|
rk_glx_printf("Failed to create context.");
|
||||||
|
rk_destroy_display(reinterpret_cast<rk_display_t>(display));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!glXIsDirect(display->display, display->context)) {
|
||||||
|
rk_glx_printf("Warning: Rendering context is indirect.");
|
||||||
|
}
|
||||||
|
glXMakeCurrent(display->display, display->window, display->context);
|
||||||
|
|
||||||
|
char const * const gl_exts = reinterpret_cast<char const *>(glGetString(GL_EXTENSIONS));
|
||||||
|
if (rk_extension_supported(gl_exts, "GL_EXT_base_instance")) {
|
||||||
|
rk_DrawElementsInstancedBaseInstance =
|
||||||
|
reinterpret_cast<rk_DrawElementsInstancedBaseInstanceFunc>(
|
||||||
|
glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("DrawElementsInstancedBaseInstance")));
|
||||||
|
if (rk_DrawElementsInstancedBaseInstance) {
|
||||||
|
rk_glx_printf("Using extension GL_EXT_base_instance::DrawElementsInstancedBaseInstance.");
|
||||||
|
if (rk_extension_supported(gl_exts, "GL_EXT_multi_draw_indirect")) {
|
||||||
|
rk_MultiDrawElementsIndirect =
|
||||||
|
reinterpret_cast<rk_MultiDrawElementsIndirectFunc>(
|
||||||
|
glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("MultiDrawElementsIndirectEXT")));
|
||||||
|
if (rk_MultiDrawElementsIndirect) {
|
||||||
|
rk_glx_printf("Using extension GL_EXT_multi_draw_indirect::MultiDrawElementsIndirectEXT.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reinterpret_cast<rk_display_t>(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk_destroy_display(
|
||||||
|
rk_display_t _display) {
|
||||||
|
rk_display_glx * const display = reinterpret_cast<rk_display_glx *>(_display);
|
||||||
|
if (display) {
|
||||||
|
if (display->display) {
|
||||||
|
glXMakeCurrent(display->display, 0, nullptr);
|
||||||
|
if (display->context) {
|
||||||
|
glXDestroyContext(display->display, display->context);
|
||||||
|
}
|
||||||
|
if (display->window) {
|
||||||
|
XDestroyWindow(display->display, display->window);
|
||||||
|
}
|
||||||
|
if (display->colormap) {
|
||||||
|
XFreeColormap(display->display, display->colormap);
|
||||||
|
}
|
||||||
|
XCloseDisplay(display->display);
|
||||||
|
}
|
||||||
|
delete display;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk_swap_buffers(
|
||||||
|
rk_display_t _display) {
|
||||||
|
rk_display_glx const * const display = reinterpret_cast<rk_display_glx const *>(_display);
|
||||||
|
if (display && display->display && display->window) {
|
||||||
|
glXSwapBuffers(display->display, display->window);
|
||||||
|
}
|
||||||
|
}
|
@ -13,10 +13,17 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#ifndef _RK_ENGINE_RENDER_CONTEXT_H
|
#ifndef _RK_ENGINE_DISPLAY_GLX_H
|
||||||
#define _RK_ENGINE_RENDER_CONTEXT_H
|
#define _RK_ENGINE_DISPLAY_GLX_H
|
||||||
|
|
||||||
#include "../render.hpp"
|
#include "../types.hpp"
|
||||||
|
#include "display_x11.hpp"
|
||||||
|
#include "../events/events_x11.hpp"
|
||||||
|
#include <GL/glx.h>
|
||||||
|
|
||||||
|
struct rk_display_glx : public rk_display_x11 {
|
||||||
|
GLXContext context;
|
||||||
|
};
|
||||||
|
|
||||||
typedef void (*rk_DrawElementsInstancedBaseInstanceFunc)(rk_uint, rk_uint, rk_uint, const void *, rk_uint, rk_uint);
|
typedef void (*rk_DrawElementsInstancedBaseInstanceFunc)(rk_uint, rk_uint, rk_uint, const void *, rk_uint, rk_uint);
|
||||||
typedef void (*rk_MultiDrawElementsIndirectFunc)(rk_uint, rk_uint, const void *, rk_uint, rk_uint);
|
typedef void (*rk_MultiDrawElementsIndirectFunc)(rk_uint, rk_uint, const void *, rk_uint, rk_uint);
|
||||||
@ -24,12 +31,4 @@ typedef void (*rk_MultiDrawElementsIndirectFunc)(rk_uint, rk_uint, const void *,
|
|||||||
extern rk_DrawElementsInstancedBaseInstanceFunc rk_DrawElementsInstancedBaseInstance;
|
extern rk_DrawElementsInstancedBaseInstanceFunc rk_DrawElementsInstancedBaseInstance;
|
||||||
extern rk_MultiDrawElementsIndirectFunc rk_MultiDrawElementsIndirect;
|
extern rk_MultiDrawElementsIndirectFunc rk_MultiDrawElementsIndirect;
|
||||||
|
|
||||||
extern rk_window_t rk_create_context(
|
#endif // _RK_ENGINE_DISPLAY_GLX_H
|
||||||
char const * name,
|
|
||||||
unsigned width,
|
|
||||||
unsigned height);
|
|
||||||
|
|
||||||
extern void rk_swap_buffers();
|
|
||||||
extern void rk_destroy_context();
|
|
||||||
|
|
||||||
#endif // _RK_ENGINE_RENDER_CONTEXT_H
|
|
27
cpp/display/display_x11.hpp
Normal file
27
cpp/display/display_x11.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (C) 2022 RozK
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef _RK_ENGINE_DISPLAY_X11_H
|
||||||
|
#define _RK_ENGINE_DISPLAY_X11_H
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
struct rk_display_x11 {
|
||||||
|
Display * display;
|
||||||
|
Window window;
|
||||||
|
Colormap colormap;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _RK_ENGINE_DISPLAY_X11_H
|
@ -17,6 +17,9 @@
|
|||||||
#define _RK_ENGINE_EVENTS_H
|
#define _RK_ENGINE_EVENTS_H
|
||||||
|
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
|
#include "display.hpp"
|
||||||
|
|
||||||
|
typedef rk_handle_t rk_events_t;
|
||||||
|
|
||||||
enum rk_event_type : rk_uint {
|
enum rk_event_type : rk_uint {
|
||||||
RK_EVENT_FOCUS_IN = 0,
|
RK_EVENT_FOCUS_IN = 0,
|
||||||
@ -52,19 +55,26 @@ struct rk_event {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool rk_initialize_events();
|
RK_EXPORT rk_events_t rk_create_events(
|
||||||
extern void rk_terminate_events();
|
rk_display_t display);
|
||||||
|
|
||||||
RK_EXPORT void rk_set_autorepeat(
|
RK_EXPORT void rk_destroy_events(
|
||||||
|
rk_display_t display,
|
||||||
|
rk_events_t events);
|
||||||
|
|
||||||
|
RK_EXPORT void rk_set_key_autorepeat(
|
||||||
|
rk_events_t events,
|
||||||
rk_bool autorepeat);
|
rk_bool autorepeat);
|
||||||
|
|
||||||
RK_EXPORT void rk_set_acceleration(
|
RK_EXPORT void rk_set_motion_acceleration(
|
||||||
|
rk_events_t events,
|
||||||
rk_uint numerator,
|
rk_uint numerator,
|
||||||
rk_uint denominator,
|
rk_uint denominator,
|
||||||
rk_uint threshold);
|
rk_uint threshold);
|
||||||
|
|
||||||
RK_EXPORT rk_uint rk_consume_events(
|
RK_EXPORT rk_uint rk_consume_events(
|
||||||
rk_event * events,
|
rk_events_t events,
|
||||||
|
rk_event * buffer,
|
||||||
rk_uint max_events);
|
rk_uint max_events);
|
||||||
|
|
||||||
#endif // _RK_ENGINE_EVENTS_H
|
#endif // _RK_ENGINE_EVENTS_H
|
||||||
|
@ -14,144 +14,168 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "../events.hpp"
|
#include "../events.hpp"
|
||||||
#include <X11/Xlib.h>
|
#include "events_x11.hpp"
|
||||||
|
#include "../display/display_x11.hpp"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
extern Display * rk_display;
|
static void rk_x11_printf(
|
||||||
extern Window rk_window;
|
char const * messsage) {
|
||||||
|
printf("[X11] %s\n", messsage);
|
||||||
unsigned rk_events_mask = FocusChangeMask |
|
|
||||||
KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
|
|
||||||
|
|
||||||
static XIM rk_input_manager = nullptr;
|
|
||||||
static XIC rk_input_context = nullptr;
|
|
||||||
|
|
||||||
static bool rk_focused = false;
|
|
||||||
static bool rk_keyboard_autorepeat = false;
|
|
||||||
static XKeyboardState rk_previous_keyboard_state;
|
|
||||||
static int rk_previous_accel_numerator, rk_accel_numerator = 1;
|
|
||||||
static int rk_previous_accel_denominator, rk_accel_denominator = 1;
|
|
||||||
static int rk_previous_threshold, rk_accel_threshold = 0;
|
|
||||||
|
|
||||||
static void rk_backup_setup() {
|
|
||||||
XGetKeyboardControl(rk_display, &rk_previous_keyboard_state);
|
|
||||||
XGetPointerControl(rk_display,
|
|
||||||
&rk_previous_accel_numerator, &rk_previous_accel_denominator, &rk_previous_threshold);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rk_restore_setup() {
|
static void rk_backup(rk_events_x11 & events) {
|
||||||
if (AutoRepeatModeOn == rk_previous_keyboard_state.global_auto_repeat) {
|
XKeyboardState backup;
|
||||||
XAutoRepeatOn(rk_display);
|
XGetKeyboardControl(events.display, &backup);
|
||||||
|
events.backup_autorepeat = (AutoRepeatModeOn == backup.global_auto_repeat);
|
||||||
|
XGetPointerControl(
|
||||||
|
events.display, &events.backup_numerator, &events.backup_denominator, &events.backup_threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_restore(rk_events_x11 & events) {
|
||||||
|
if (events.backup_autorepeat) {
|
||||||
|
XAutoRepeatOn(events.display);
|
||||||
} else {
|
} else {
|
||||||
XAutoRepeatOff(rk_display);
|
XAutoRepeatOff(events.display);
|
||||||
}
|
}
|
||||||
XChangePointerControl(rk_display, True, True,
|
XChangePointerControl(
|
||||||
rk_previous_accel_numerator, rk_previous_accel_denominator, rk_previous_threshold);
|
events.display, True, True, events.backup_numerator, events.backup_denominator, events.backup_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rk_apply_setup() {
|
static void rk_apply(rk_events_x11 & events) {
|
||||||
if (rk_keyboard_autorepeat) {
|
if (events.key_autorepeat) {
|
||||||
XAutoRepeatOn(rk_display);
|
XAutoRepeatOn(events.display);
|
||||||
} else {
|
} else {
|
||||||
XAutoRepeatOff(rk_display);
|
XAutoRepeatOff(events.display);
|
||||||
}
|
}
|
||||||
XChangePointerControl(rk_display, True, True, rk_accel_numerator, rk_accel_denominator, rk_accel_threshold);
|
XChangePointerControl(
|
||||||
|
events.display, True, True, events.motion_numerator, events.motion_denominator, events.motion_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rk_initialize_events() {
|
static void rk_focus_in(rk_events_x11 & events) {
|
||||||
rk_focused = false;
|
if (!events.focused) {
|
||||||
rk_backup_setup();
|
rk_backup(events);
|
||||||
rk_keyboard_autorepeat = (AutoRepeatModeOn == rk_previous_keyboard_state.global_auto_repeat);
|
rk_apply(events);
|
||||||
rk_accel_numerator = rk_previous_accel_numerator;
|
XGrabPointer(events.display, events.window, True,
|
||||||
rk_accel_denominator = rk_previous_accel_denominator;
|
|
||||||
rk_accel_threshold = rk_previous_threshold;
|
|
||||||
rk_input_manager = XOpenIM(rk_display, nullptr, nullptr, nullptr);
|
|
||||||
if (!rk_input_manager) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
rk_input_context = XCreateIC(rk_input_manager,
|
|
||||||
XNInputStyle, XIMPreeditNone | XIMStatusNone,
|
|
||||||
XNClientWindow, rk_window,
|
|
||||||
NULL);
|
|
||||||
if (!rk_input_context) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
XSetICFocus(rk_input_context);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_terminate_events() {
|
|
||||||
rk_restore_setup();
|
|
||||||
if (rk_input_context) {
|
|
||||||
XUnsetICFocus(rk_input_context);
|
|
||||||
XDestroyIC(rk_input_context);
|
|
||||||
rk_input_context = nullptr;
|
|
||||||
}
|
|
||||||
if (rk_input_manager) {
|
|
||||||
XCloseIM(rk_input_manager);
|
|
||||||
rk_input_manager = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk_focus_in() {
|
|
||||||
if (!rk_focused) {
|
|
||||||
rk_backup_setup();
|
|
||||||
rk_apply_setup();
|
|
||||||
XGrabPointer(rk_display, rk_window, True,
|
|
||||||
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
|
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
|
||||||
GrabModeAsync, GrabModeAsync, rk_window, None, CurrentTime);
|
GrabModeAsync, GrabModeAsync, events.window, None, CurrentTime);
|
||||||
rk_focused = true;
|
events.focused = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rk_focus_out() {
|
static void rk_focus_out(rk_events_x11 & events) {
|
||||||
if (rk_focused) {
|
if (events.focused) {
|
||||||
XUngrabPointer(rk_display, CurrentTime);
|
XUngrabPointer(events.display, CurrentTime);
|
||||||
rk_restore_setup();
|
rk_restore(events);
|
||||||
rk_focused = false;
|
events.focused = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rk_set_autorepeat(
|
rk_events_t rk_create_events(
|
||||||
|
rk_display_t _display) {
|
||||||
|
rk_display_x11 const * const display = reinterpret_cast<rk_display_x11 const *>(_display);
|
||||||
|
if (!display || !display->display || !display->window) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
rk_events_x11 * const events = new rk_events_x11;
|
||||||
|
events->display = display->display;
|
||||||
|
events->window = display->window;
|
||||||
|
events->input_manager = XOpenIM(display->display, nullptr, nullptr, nullptr);
|
||||||
|
if (!events->input_manager) {
|
||||||
|
rk_x11_printf("Failed to open input manager.");
|
||||||
|
delete events;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
events->input_context = XCreateIC(events->input_manager,
|
||||||
|
XNInputStyle, XIMPreeditNone | XIMStatusNone,
|
||||||
|
XNClientWindow, display->window,
|
||||||
|
NULL);
|
||||||
|
if (!events->input_context) {
|
||||||
|
rk_x11_printf("Failed to create input context.");
|
||||||
|
XCloseIM(events->input_manager);
|
||||||
|
delete events;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
events->focused = false;
|
||||||
|
rk_backup(*events);
|
||||||
|
events->key_autorepeat = events->backup_autorepeat;
|
||||||
|
events->motion_numerator = events->backup_numerator;
|
||||||
|
events->motion_denominator = events->backup_denominator;
|
||||||
|
events->motion_threshold = events->backup_threshold;
|
||||||
|
XSetICFocus(events->input_context);
|
||||||
|
return reinterpret_cast<rk_events_t>(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk_destroy_events(
|
||||||
|
rk_display_t _display,
|
||||||
|
rk_events_t _events) {
|
||||||
|
rk_display_x11 const * const display = reinterpret_cast<rk_display_x11 const *>(_display);
|
||||||
|
rk_events_x11 * const events = reinterpret_cast<rk_events_x11 *>(_events);
|
||||||
|
if (display && events && display->display && display->display == events->display) {
|
||||||
|
rk_restore(*events);
|
||||||
|
if (events->input_context) {
|
||||||
|
XUnsetICFocus(events->input_context);
|
||||||
|
XDestroyIC(events->input_context);
|
||||||
|
}
|
||||||
|
if (events->input_manager) {
|
||||||
|
XCloseIM(events->input_manager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (events) {
|
||||||
|
delete events;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk_set_key_autorepeat(
|
||||||
|
rk_events_t _events,
|
||||||
rk_bool autorepeat) {
|
rk_bool autorepeat) {
|
||||||
rk_keyboard_autorepeat = autorepeat;
|
rk_events_x11 * const events = reinterpret_cast<rk_events_x11 *>(_events);
|
||||||
if (rk_focused) {
|
if (events) {
|
||||||
rk_apply_setup();
|
events->key_autorepeat = autorepeat;
|
||||||
|
if (events->focused) {
|
||||||
|
rk_apply(*events);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rk_set_acceleration(
|
void rk_set_motion_acceleration(
|
||||||
|
rk_events_t _events,
|
||||||
rk_uint numerator,
|
rk_uint numerator,
|
||||||
rk_uint denominator,
|
rk_uint denominator,
|
||||||
rk_uint threshold) {
|
rk_uint threshold) {
|
||||||
rk_accel_numerator = numerator;
|
rk_events_x11 * const events = reinterpret_cast<rk_events_x11 *>(_events);
|
||||||
rk_accel_denominator = denominator;
|
if (events) {
|
||||||
rk_accel_threshold = threshold;
|
events->motion_numerator = numerator;
|
||||||
if (rk_focused) {
|
events->motion_denominator = denominator;
|
||||||
rk_apply_setup();
|
events->motion_threshold = threshold;
|
||||||
|
if (events->focused) {
|
||||||
|
rk_apply(*events);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rk_uint rk_consume_events(
|
rk_uint rk_consume_events(
|
||||||
rk_event * events,
|
rk_events_t _events,
|
||||||
|
rk_event * buffer,
|
||||||
rk_uint max_events) {
|
rk_uint max_events) {
|
||||||
static wchar_t string[256];
|
static wchar_t string[256];
|
||||||
if (!events || !max_events) {
|
rk_events_x11 * const events = reinterpret_cast<rk_events_x11 *>(_events);
|
||||||
|
if (!events || !buffer || !max_events) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
XEvent x11_event;
|
XEvent x11_event;
|
||||||
KeySym keysym;
|
KeySym keysym;
|
||||||
Status status;
|
Status status;
|
||||||
unsigned nevents = 0;
|
unsigned nevents = 0;
|
||||||
while (nevents < max_events && XCheckWindowEvent(rk_display, rk_window, rk_events_mask, &x11_event)) {
|
while (nevents < max_events && XCheckWindowEvent(events->display, events->window, RK_EVENTS_MASK, &x11_event)) {
|
||||||
if (XFilterEvent(&x11_event, 0)) {
|
if (XFilterEvent(&x11_event, 0)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rk_event & event = events[nevents];
|
rk_event & event = buffer[nevents];
|
||||||
switch (x11_event.type) {
|
switch (x11_event.type) {
|
||||||
|
|
||||||
case FocusIn:
|
case FocusIn:
|
||||||
if (NotifyNormal == x11_event.xfocus.mode) {
|
if (NotifyNormal == x11_event.xfocus.mode) {
|
||||||
rk_focus_in();
|
rk_focus_in(*events);
|
||||||
event.type = RK_EVENT_FOCUS_IN;
|
event.type = RK_EVENT_FOCUS_IN;
|
||||||
++nevents;
|
++nevents;
|
||||||
}
|
}
|
||||||
@ -159,7 +183,7 @@ rk_uint rk_consume_events(
|
|||||||
|
|
||||||
case FocusOut:
|
case FocusOut:
|
||||||
if (NotifyNormal == x11_event.xfocus.mode) {
|
if (NotifyNormal == x11_event.xfocus.mode) {
|
||||||
rk_focus_out();
|
rk_focus_out(*events);
|
||||||
event.type = RK_EVENT_FOCUS_OUT;
|
event.type = RK_EVENT_FOCUS_OUT;
|
||||||
++nevents;
|
++nevents;
|
||||||
}
|
}
|
||||||
@ -168,7 +192,7 @@ rk_uint rk_consume_events(
|
|||||||
case KeyPress:
|
case KeyPress:
|
||||||
event.type = RK_EVENT_KEY_PRESS;
|
event.type = RK_EVENT_KEY_PRESS;
|
||||||
event.key.code = x11_event.xkey.keycode;
|
event.key.code = x11_event.xkey.keycode;
|
||||||
XwcLookupString(rk_input_context, &x11_event.xkey, string, 256, &keysym, &status);
|
XwcLookupString(events->input_context, &x11_event.xkey, string, 256, &keysym, &status);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case XLookupChars:
|
case XLookupChars:
|
||||||
event.key.symbol = XLookupKeysym(&x11_event.xkey, 0);
|
event.key.symbol = XLookupKeysym(&x11_event.xkey, 0);
|
||||||
|
44
cpp/events/events_x11.hpp
Normal file
44
cpp/events/events_x11.hpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (C) 2022 RozK
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef _RK_ENGINE_EVENTS_X11_H
|
||||||
|
#define _RK_ENGINE_EVENTS_X11_H
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
enum : unsigned {
|
||||||
|
RK_EVENTS_MASK = FocusChangeMask |
|
||||||
|
KeyPressMask | KeyReleaseMask |
|
||||||
|
ButtonPressMask | ButtonReleaseMask |
|
||||||
|
PointerMotionMask
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_events_x11 {
|
||||||
|
Display * display;
|
||||||
|
Window window;
|
||||||
|
XIM input_manager;
|
||||||
|
XIC input_context;
|
||||||
|
bool focused;
|
||||||
|
bool key_autorepeat;
|
||||||
|
bool backup_autorepeat;
|
||||||
|
int motion_numerator;
|
||||||
|
int backup_numerator;
|
||||||
|
int motion_denominator;
|
||||||
|
int backup_denominator;
|
||||||
|
int motion_threshold;
|
||||||
|
int backup_threshold;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _RK_ENGINE_EVENTS_X11_H
|
@ -1,249 +0,0 @@
|
|||||||
// Copyright (C) 2022 RozK
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Adapted from https://www.khronos.org/opengl/wiki/Tutorial:_OpenGL_3.0_Context_Creation_(GLX)
|
|
||||||
|
|
||||||
#include "render_context.hpp"
|
|
||||||
#include "../events.hpp"
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstring>
|
|
||||||
#include <GLES3/gl32.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <GL/glx.h>
|
|
||||||
|
|
||||||
extern unsigned rk_events_mask;
|
|
||||||
|
|
||||||
Display * rk_display = nullptr;
|
|
||||||
Window rk_window = 0;
|
|
||||||
|
|
||||||
static Colormap rk_colormap = 0;
|
|
||||||
static GLXContext rk_context = nullptr;
|
|
||||||
static bool rk_error_occured = false;
|
|
||||||
|
|
||||||
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
||||||
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
||||||
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, int const *);
|
|
||||||
|
|
||||||
rk_DrawElementsInstancedBaseInstanceFunc rk_DrawElementsInstancedBaseInstance = nullptr;
|
|
||||||
rk_MultiDrawElementsIndirectFunc rk_MultiDrawElementsIndirect = nullptr;
|
|
||||||
|
|
||||||
static int const rk_visual_attribs[] = {
|
|
||||||
GLX_X_RENDERABLE, True,
|
|
||||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
|
||||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
|
||||||
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
|
|
||||||
GLX_RED_SIZE, 8,
|
|
||||||
GLX_GREEN_SIZE, 8,
|
|
||||||
GLX_BLUE_SIZE, 8,
|
|
||||||
GLX_ALPHA_SIZE, 8,
|
|
||||||
GLX_DEPTH_SIZE, 24,
|
|
||||||
GLX_STENCIL_SIZE, 8,
|
|
||||||
GLX_DOUBLEBUFFER, True,
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
static int const rk_context_attribs[] = {
|
|
||||||
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
|
||||||
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
|
|
||||||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES_PROFILE_BIT_EXT,
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
static void rk_printf(
|
|
||||||
char const * messsage) {
|
|
||||||
printf("[GLX] %s\n", messsage);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool rk_extension_supported(
|
|
||||||
char const * extlist,
|
|
||||||
char const * extension) {
|
|
||||||
char const * where = strchr(extension, ' ');
|
|
||||||
if (where || *extension == '\0') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (char const * start = extlist;;) {
|
|
||||||
where = strstr(start, extension);
|
|
||||||
if (!where) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
char const * const terminator = where + strlen(extension);
|
|
||||||
if ((where == start || *(where - 1) == ' ') && (*terminator == ' ' || *terminator == '\0')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
start = terminator;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rk_error_handler(
|
|
||||||
Display * display,
|
|
||||||
XErrorEvent * event) {
|
|
||||||
rk_error_occured = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rk_window_t rk_create_context(
|
|
||||||
char const * name,
|
|
||||||
unsigned width,
|
|
||||||
unsigned height) {
|
|
||||||
XSetLocaleModifiers("");
|
|
||||||
|
|
||||||
rk_display = XOpenDisplay(nullptr);
|
|
||||||
if (!rk_display) {
|
|
||||||
rk_printf("Failed to open X display.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int glx_major, glx_minor;
|
|
||||||
if (!glXQueryVersion(rk_display, &glx_major, &glx_minor) || (glx_major == 1 && glx_minor < 3) || glx_major < 1) {
|
|
||||||
rk_printf("Invalid GLX version.");
|
|
||||||
rk_destroy_context();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fbcount;
|
|
||||||
GLXFBConfig * const fbc = glXChooseFBConfig(rk_display, DefaultScreen(rk_display), rk_visual_attribs, &fbcount);
|
|
||||||
if (!fbc) {
|
|
||||||
rk_printf("Failed to retrieve framebuffer configs.");
|
|
||||||
rk_destroy_context();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
printf("[GLX] Found %d framebuffer configs.\n", fbcount);
|
|
||||||
|
|
||||||
int best_fbc = -1;
|
|
||||||
int best_num_samp = -1;
|
|
||||||
for (int i = 0; i < fbcount; ++i) {
|
|
||||||
XVisualInfo * vi = glXGetVisualFromFBConfig(rk_display, fbc[i]);
|
|
||||||
if (vi) {
|
|
||||||
int samp_buf, samples;
|
|
||||||
glXGetFBConfigAttrib(rk_display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
|
|
||||||
glXGetFBConfigAttrib(rk_display, fbc[i], GLX_SAMPLES, &samples);
|
|
||||||
if (best_fbc < 0 || (samp_buf && samples > best_num_samp)) {
|
|
||||||
best_fbc = i;
|
|
||||||
best_num_samp = samples;
|
|
||||||
}
|
|
||||||
XFree(vi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (best_fbc == -1) {
|
|
||||||
XFree(fbc);
|
|
||||||
rk_printf("Failed to find a suitable framebuffer config.");
|
|
||||||
rk_destroy_context();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
GLXFBConfig const bestFbc = fbc[best_fbc];
|
|
||||||
XFree(fbc);
|
|
||||||
printf("[GLX] Select framebuffer config with %d samples.\n", best_num_samp);
|
|
||||||
|
|
||||||
XVisualInfo * const vi = glXGetVisualFromFBConfig(rk_display, bestFbc);
|
|
||||||
rk_colormap = XCreateColormap(rk_display, RootWindow(rk_display, vi->screen), vi->visual, AllocNone);
|
|
||||||
XSetWindowAttributes swa;
|
|
||||||
swa.colormap = rk_colormap;
|
|
||||||
swa.background_pixmap = None;
|
|
||||||
swa.border_pixel = 0;
|
|
||||||
swa.event_mask = rk_events_mask;
|
|
||||||
rk_window = XCreateWindow(rk_display, RootWindow(rk_display, vi->screen),
|
|
||||||
0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
|
|
||||||
CWBorderPixel | CWColormap | CWEventMask, &swa);
|
|
||||||
XFree(vi);
|
|
||||||
if (!rk_window) {
|
|
||||||
rk_printf("Failed to create window.");
|
|
||||||
rk_destroy_context();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
XStoreName(rk_display, rk_window, name);
|
|
||||||
|
|
||||||
if (!rk_initialize_events()) {
|
|
||||||
rk_printf("Failed to initialize events.");
|
|
||||||
rk_destroy_context();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
XMapWindow(rk_display, rk_window);
|
|
||||||
|
|
||||||
char const * const glx_exts = glXQueryExtensionsString(rk_display, DefaultScreen(rk_display));
|
|
||||||
glXCreateContextAttribsARBProc const glXCreateContextAttribsARB =
|
|
||||||
reinterpret_cast<glXCreateContextAttribsARBProc>(
|
|
||||||
glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("glXCreateContextAttribsARB")));
|
|
||||||
|
|
||||||
rk_error_occured = false;
|
|
||||||
int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&rk_error_handler);
|
|
||||||
if (!rk_extension_supported(glx_exts, "GLX_ARB_create_context") || !glXCreateContextAttribsARB) {
|
|
||||||
rk_printf("glXCreateContextAttribsARB() extension not found.");
|
|
||||||
rk_destroy_context();
|
|
||||||
return nullptr;
|
|
||||||
} else {
|
|
||||||
rk_context = glXCreateContextAttribsARB(rk_display, bestFbc, 0, True, rk_context_attribs);
|
|
||||||
XSync(rk_display, False);
|
|
||||||
if (rk_error_occured || !rk_context) {
|
|
||||||
rk_printf("Failed to create context.");
|
|
||||||
rk_destroy_context();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XSetErrorHandler(oldHandler);
|
|
||||||
|
|
||||||
if (!glXIsDirect(rk_display, rk_context)) {
|
|
||||||
rk_printf("Warning: Rendering context is indirect.");
|
|
||||||
}
|
|
||||||
glXMakeCurrent(rk_display, rk_window, rk_context);
|
|
||||||
|
|
||||||
char const * const gl_exts = reinterpret_cast<char const *>(glGetString(GL_EXTENSIONS));
|
|
||||||
if (rk_extension_supported(gl_exts, "GL_EXT_base_instance")) {
|
|
||||||
rk_DrawElementsInstancedBaseInstance =
|
|
||||||
reinterpret_cast<rk_DrawElementsInstancedBaseInstanceFunc>(
|
|
||||||
glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("DrawElementsInstancedBaseInstance")));
|
|
||||||
if (rk_DrawElementsInstancedBaseInstance) {
|
|
||||||
rk_printf("Using extension GL_EXT_base_instance::DrawElementsInstancedBaseInstance.");
|
|
||||||
if (rk_extension_supported(gl_exts, "GL_EXT_multi_draw_indirect")) {
|
|
||||||
rk_MultiDrawElementsIndirect =
|
|
||||||
reinterpret_cast<rk_MultiDrawElementsIndirectFunc>(
|
|
||||||
glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("MultiDrawElementsIndirectEXT")));
|
|
||||||
if (rk_MultiDrawElementsIndirect) {
|
|
||||||
rk_printf("Using extension GL_EXT_multi_draw_indirect::MultiDrawElementsIndirectEXT.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reinterpret_cast<rk_window_t>(rk_window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_swap_buffers() {
|
|
||||||
if (rk_display && rk_window) {
|
|
||||||
glXSwapBuffers(rk_display, rk_window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_destroy_context() {
|
|
||||||
if (rk_display) {
|
|
||||||
glXMakeCurrent(rk_display, 0, nullptr);
|
|
||||||
if (rk_context) {
|
|
||||||
glXDestroyContext(rk_display, rk_context);
|
|
||||||
rk_context = nullptr;
|
|
||||||
}
|
|
||||||
rk_terminate_events();
|
|
||||||
if (rk_window) {
|
|
||||||
XDestroyWindow(rk_display, rk_window);
|
|
||||||
rk_window = 0;
|
|
||||||
}
|
|
||||||
if (rk_colormap) {
|
|
||||||
XFreeColormap(rk_display, rk_colormap);
|
|
||||||
rk_colormap = 0;
|
|
||||||
}
|
|
||||||
XCloseDisplay(rk_display);
|
|
||||||
rk_display = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,7 +19,6 @@
|
|||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
#include "math.hpp"
|
#include "math.hpp"
|
||||||
|
|
||||||
typedef rk_handle_t rk_window_t;
|
|
||||||
typedef rk_handle_t rk_shader_t;
|
typedef rk_handle_t rk_shader_t;
|
||||||
typedef rk_handle_t rk_input_t;
|
typedef rk_handle_t rk_input_t;
|
||||||
typedef rk_handle_t rk_param_t;
|
typedef rk_handle_t rk_param_t;
|
||||||
@ -28,8 +27,6 @@ typedef rk_handle_t rk_triangles_t;
|
|||||||
typedef rk_handle_t rk_vertices_t;
|
typedef rk_handle_t rk_vertices_t;
|
||||||
typedef rk_handle_t rk_batch_t;
|
typedef rk_handle_t rk_batch_t;
|
||||||
|
|
||||||
#define RK_FLAG(bit) (1 << (bit))
|
|
||||||
|
|
||||||
enum rk_texture_format : rk_uint {
|
enum rk_texture_format : rk_uint {
|
||||||
RK_TEXTURE_FORMAT_SRGB8_A8 = 0,
|
RK_TEXTURE_FORMAT_SRGB8_A8 = 0,
|
||||||
RK_TEXTURE_FORMAT_RGBA8 = 1,
|
RK_TEXTURE_FORMAT_RGBA8 = 1,
|
||||||
@ -81,10 +78,9 @@ union rk_mesh {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
RK_EXPORT rk_window_t rk_initialize(
|
RK_EXPORT void rk_render_initialize();
|
||||||
char const * name,
|
|
||||||
rk_uint width,
|
RK_EXPORT void rk_render_terminate();
|
||||||
rk_uint height);
|
|
||||||
|
|
||||||
RK_EXPORT rk_shader_t rk_load_shader(
|
RK_EXPORT rk_shader_t rk_load_shader(
|
||||||
rk_uint const vert_nlines,
|
rk_uint const vert_nlines,
|
||||||
@ -194,6 +190,4 @@ RK_EXPORT void rk_destroy_texture(
|
|||||||
RK_EXPORT void rk_destroy_shader(
|
RK_EXPORT void rk_destroy_shader(
|
||||||
rk_shader_t shader);
|
rk_shader_t shader);
|
||||||
|
|
||||||
RK_EXPORT void rk_terminate();
|
|
||||||
|
|
||||||
#endif // _RK_ENGINE_RENDER_H
|
#endif // _RK_ENGINE_RENDER_H
|
||||||
|
@ -13,17 +13,19 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "../render.hpp"
|
||||||
#include "render_opengles.hpp"
|
#include "render_opengles.hpp"
|
||||||
|
#include "../display/display_glx.hpp"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
static rk_shader const * rk_current_shader = nullptr;
|
static rk_shader const * rk_current_shader = nullptr;
|
||||||
static rk_vertices const * rk_current_vertices = nullptr;
|
static rk_vertices const * rk_current_vertices = nullptr;
|
||||||
|
|
||||||
static void rk_printf(char const * messsage) {
|
static void rk_printf(char const * message) {
|
||||||
printf("[RK_ENGINE] %s\n", messsage);
|
printf("[RK] %s\n", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define rk_error(message) { if (glGetError() != GL_NO_ERROR) { rk_printf(message); } }
|
#define rk_gl_error(_message) { if (glGetError() != GL_NO_ERROR) { printf("[GL] %s\n", (_message)); } }
|
||||||
|
|
||||||
static void rk_debug_message_callback(
|
static void rk_debug_message_callback(
|
||||||
GLenum source,
|
GLenum source,
|
||||||
@ -33,36 +35,32 @@ static void rk_debug_message_callback(
|
|||||||
GLsizei length,
|
GLsizei length,
|
||||||
GLchar const * message,
|
GLchar const * message,
|
||||||
void const * userParam) {
|
void const * userParam) {
|
||||||
printf("[RK_ENGINE][GL] (id=%d) %s\n", id, message);
|
printf("[GL] (id=%d) %s\n", id, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
rk_window_t rk_initialize(
|
void rk_render_initialize() {
|
||||||
char const * name,
|
GLubyte const * const vendor = glGetString(GL_VENDOR);
|
||||||
rk_uint width,
|
GLubyte const * const renderer = glGetString(GL_RENDERER);
|
||||||
rk_uint height) {
|
printf("[RK] vendor: %s, renderer: %s\n", vendor, renderer);
|
||||||
rk_window_t const window = rk_create_context(name, width, height);
|
GLubyte const * const version = glGetString(GL_VERSION);
|
||||||
if (window) {
|
GLubyte const * const language = glGetString(GL_SHADING_LANGUAGE_VERSION);
|
||||||
GLubyte const * const vendor = glGetString(GL_VENDOR);
|
printf("[RK] version: %s, language: %s\n", version, language);
|
||||||
GLubyte const * const renderer = glGetString(GL_RENDERER);
|
|
||||||
printf("[RK_ENGINE] vendor: %s, renderer: %s\n", vendor, renderer);
|
|
||||||
GLubyte const * const version = glGetString(GL_VERSION);
|
|
||||||
GLubyte const * const language = glGetString(GL_SHADING_LANGUAGE_VERSION);
|
|
||||||
printf("[RK_ENGINE] version: %s, language: %s\n", version, language);
|
|
||||||
|
|
||||||
glDebugMessageCallback(rk_debug_message_callback, nullptr);
|
glDebugMessageCallback(rk_debug_message_callback, nullptr);
|
||||||
glEnable(GL_DEBUG_OUTPUT);
|
glEnable(GL_DEBUG_OUTPUT);
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
glEnable(GL_DITHER);
|
glEnable(GL_DITHER);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
glDisable(GL_STENCIL_TEST);
|
glDisable(GL_STENCIL_TEST);
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glFrontFace(GL_CCW);
|
glFrontFace(GL_CCW);
|
||||||
glCullFace(GL_BACK);
|
glCullFace(GL_BACK);
|
||||||
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
|
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
|
||||||
}
|
}
|
||||||
return window;
|
|
||||||
|
void rk_render_terminate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rk_print_shader_infolog(GLuint shader) {
|
static void rk_print_shader_infolog(GLuint shader) {
|
||||||
@ -104,18 +102,18 @@ rk_shader_t rk_load_shader(
|
|||||||
rk_printf("Compiling vertex shader...");
|
rk_printf("Compiling vertex shader...");
|
||||||
glShaderSource(shader->vertex, vert_nlines, vert_lines, nullptr);
|
glShaderSource(shader->vertex, vert_nlines, vert_lines, nullptr);
|
||||||
glCompileShader(shader->vertex);
|
glCompileShader(shader->vertex);
|
||||||
rk_error("glCompileShader() failed.");
|
rk_gl_error("glCompileShader() failed.");
|
||||||
rk_print_shader_infolog(shader->vertex);
|
rk_print_shader_infolog(shader->vertex);
|
||||||
rk_printf("Compiling fragment shader...");
|
rk_printf("Compiling fragment shader...");
|
||||||
glShaderSource(shader->fragment, frag_nlines, frag_lines, nullptr);
|
glShaderSource(shader->fragment, frag_nlines, frag_lines, nullptr);
|
||||||
glCompileShader(shader->fragment);
|
glCompileShader(shader->fragment);
|
||||||
rk_error("glCompileShader() failed.");
|
rk_gl_error("glCompileShader() failed.");
|
||||||
rk_print_shader_infolog(shader->fragment);
|
rk_print_shader_infolog(shader->fragment);
|
||||||
rk_printf("Linking program...");
|
rk_printf("Linking program...");
|
||||||
glAttachShader(shader->program, shader->vertex);
|
glAttachShader(shader->program, shader->vertex);
|
||||||
glAttachShader(shader->program, shader->fragment);
|
glAttachShader(shader->program, shader->fragment);
|
||||||
glLinkProgram(shader->program);
|
glLinkProgram(shader->program);
|
||||||
rk_error("glLinkProgram() failed.");
|
rk_gl_error("glLinkProgram() failed.");
|
||||||
rk_print_program_infolog(shader->program);
|
rk_print_program_infolog(shader->program);
|
||||||
rk_printf("Done.");
|
rk_printf("Done.");
|
||||||
glReleaseShaderCompiler();
|
glReleaseShaderCompiler();
|
||||||
@ -669,7 +667,6 @@ void rk_unselect_shader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void rk_end_frame() {
|
void rk_end_frame() {
|
||||||
rk_swap_buffers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rk_destroy_batch(
|
void rk_destroy_batch(
|
||||||
@ -730,7 +727,3 @@ void rk_destroy_shader(
|
|||||||
delete shader;
|
delete shader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rk_terminate() {
|
|
||||||
rk_destroy_context();
|
|
||||||
}
|
|
@ -16,8 +16,7 @@
|
|||||||
#ifndef _RK_ENGINE_RENDER_OPENGLES_H
|
#ifndef _RK_ENGINE_RENDER_OPENGLES_H
|
||||||
#define _RK_ENGINE_RENDER_OPENGLES_H
|
#define _RK_ENGINE_RENDER_OPENGLES_H
|
||||||
|
|
||||||
#include "../render.hpp"
|
#include "../types.hpp"
|
||||||
#include "render_context.hpp"
|
|
||||||
#include <GLES3/gl32.h>
|
#include <GLES3/gl32.h>
|
||||||
#include <GLES3/gl3ext.h>
|
#include <GLES3/gl3ext.h>
|
||||||
#include <GLES3/gl3platform.h>
|
#include <GLES3/gl3platform.h>
|
@ -20,6 +20,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#define RK_EXPORT extern "C"
|
#define RK_EXPORT extern "C"
|
||||||
|
#define RK_FLAG(_bit) (1 << (_bit))
|
||||||
|
|
||||||
typedef bool rk_bool;
|
typedef bool rk_bool;
|
||||||
typedef char rk_char;
|
typedef char rk_char;
|
||||||
|
Loading…
Reference in New Issue
Block a user