Compare commits
66 Commits
028ba40148
...
master
Author | SHA1 | Date | |
---|---|---|---|
7d35ac0e5b
|
|||
7384a014ff
|
|||
cb763962fd
|
|||
39c449a763
|
|||
a02d8e4d7d
|
|||
81d52086fe
|
|||
16c7c91508
|
|||
9181d58ecd
|
|||
a6ec35ebd1
|
|||
596caef7ee
|
|||
f463db316f
|
|||
59d13684be
|
|||
d6ec77207f
|
|||
b46b4bddba
|
|||
ebc6ededf3
|
|||
74b6f58794
|
|||
39a95e24c3
|
|||
3e0ea2560a
|
|||
558ec08614
|
|||
211762c279
|
|||
a5adfacdfd
|
|||
d0741afda7
|
|||
66980e6ea9
|
|||
a91a852887
|
|||
357066b315
|
|||
baac333b44
|
|||
ed87f292ff
|
|||
afad17d517
|
|||
beca8798bf
|
|||
e80bbe2418
|
|||
ae3333e22e
|
|||
2095e335ea
|
|||
6ec993c6f8
|
|||
38a692bc42
|
|||
7706fe3a26
|
|||
43d62948b7
|
|||
1b9ce54100
|
|||
3b21e1610a
|
|||
628f8bcaa4
|
|||
306ac3d312
|
|||
7db5304d40
|
|||
414630ecfd
|
|||
ed6c852102
|
|||
919ba9291f
|
|||
33abfd834a
|
|||
269d7821c8
|
|||
af0edd5e6d
|
|||
ad2e89f684
|
|||
6b33f8285c
|
|||
618e05bcaa
|
|||
cdfce62c90
|
|||
e286d33c35
|
|||
026ead0b33
|
|||
0c560890a4
|
|||
65b25c8be3
|
|||
abd5989de8
|
|||
61cfdbccf3
|
|||
ffffffaa79
|
|||
709974412a
|
|||
337d7b14f5
|
|||
ccce6c5d83
|
|||
abf1e87a36
|
|||
84ea17f1cc
|
|||
eaff99a5b6
|
|||
c1b9c0d17e
|
|||
ddb9b0598f
|
25
Makefile
25
Makefile
@ -1,11 +1,30 @@
|
|||||||
SOURCES = cpp/opengl/render_context_glx.cpp cpp/opengl/render_opengles.cpp cpp/math.cpp
|
# 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/>.
|
||||||
|
|
||||||
|
SOURCES = \
|
||||||
|
cpp/display/display_glx.cpp \
|
||||||
|
cpp/events/events_x11.cpp \
|
||||||
|
cpp/render/render_opengles.cpp \
|
||||||
|
cpp/math.cpp
|
||||||
|
|
||||||
OUTPUTFILE = engine.so
|
OUTPUTFILE = engine.so
|
||||||
|
|
||||||
CXXFLAGS = -fpic -Wall -Werror -O2 -flto -fomit-frame-pointer -ffast-math -funroll-loops -fno-rtti -fno-exceptions
|
CXXFLAGS = -std=c++17 -Wall -Werror -O2 -msse2 -fpic -flto -fno-rtti -fno-exceptions
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: clean $(OUTPUTFILE)
|
all: clean $(OUTPUTFILE)
|
||||||
find . -name "*.o" -type f -delete
|
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
|
688
__init__.py
688
__init__.py
@ -14,19 +14,248 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
import struct
|
|
||||||
from array import array
|
from array import array
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
_lib = ctypes.cdll.LoadLibrary(Path(__file__).parent / "engine.so")
|
_engine = ctypes.cdll.LoadLibrary(Path(__file__).parent / "engine.so")
|
||||||
|
|
||||||
|
# types.hpp
|
||||||
|
|
||||||
|
_handle = ctypes.c_void_p
|
||||||
|
|
||||||
|
def _check_handle(result, func, arguments):
|
||||||
|
assert result
|
||||||
|
return result
|
||||||
|
|
||||||
def _flag(x):
|
def _flag(x):
|
||||||
return 1 << x
|
return 1 << x
|
||||||
|
|
||||||
|
def buffer(type, size):
|
||||||
|
return (type * size)()
|
||||||
|
|
||||||
|
def _void_addr(x):
|
||||||
|
return x.buffer_info()[0]
|
||||||
|
|
||||||
|
def _ubyte_addr(x):
|
||||||
|
assert x.typecode == 'B'
|
||||||
|
return x.buffer_info()[0]
|
||||||
|
|
||||||
|
def _ushort_addr(x):
|
||||||
|
assert x.typecode == 'H'
|
||||||
|
return x.buffer_info()[0]
|
||||||
|
|
||||||
|
def _uint_addr(x):
|
||||||
|
assert x.typecode == 'I'
|
||||||
|
return x.buffer_info()[0]
|
||||||
|
|
||||||
|
def _float_addr(x):
|
||||||
|
assert x.typecode == 'f'
|
||||||
|
return x.buffer_info()[0]
|
||||||
|
|
||||||
|
# math.hpp
|
||||||
|
|
||||||
|
class vec3(ctypes.Structure):
|
||||||
|
_fields_ = ('x', ctypes.c_float), ('y', ctypes.c_float), ('z', ctypes.c_float)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
yield self.x
|
||||||
|
yield self.y
|
||||||
|
yield self.z
|
||||||
|
|
||||||
|
def set(self, x, y, z):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.z = z
|
||||||
|
|
||||||
|
class vec4(ctypes.Structure):
|
||||||
|
_fields_ = ('x', ctypes.c_float), ('y', ctypes.c_float), ('z', ctypes.c_float), ('w', ctypes.c_float)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
yield self.x
|
||||||
|
yield self.y
|
||||||
|
yield self.z
|
||||||
|
yield self.w
|
||||||
|
|
||||||
|
def set(self, x, y, z, w):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.z = z
|
||||||
|
self.w = w
|
||||||
|
|
||||||
|
class mat3(ctypes.Structure):
|
||||||
|
_fields_ = ('right', vec3), ('forward', vec3), ('up', vec3)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
yield self.right
|
||||||
|
yield self.forward
|
||||||
|
yield self.up
|
||||||
|
|
||||||
|
def set(self, right, forward, up):
|
||||||
|
self.right = right
|
||||||
|
self.forward = forward
|
||||||
|
self.up = up
|
||||||
|
|
||||||
|
class mat4(ctypes.Structure):
|
||||||
|
_fields_ = ('right', vec4), ('forward', vec4), ('up', vec4), ('origin', vec4)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
yield self.right
|
||||||
|
yield self.forward
|
||||||
|
yield self.up
|
||||||
|
yield self.origin
|
||||||
|
|
||||||
|
def set(self, right, forward, up, origin):
|
||||||
|
self.right = right
|
||||||
|
self.forward = forward
|
||||||
|
self.up = up
|
||||||
|
self.origin = origin
|
||||||
|
|
||||||
|
def set_vec3(self, right, forward, up, origin):
|
||||||
|
self.right.set(*right, 0.0)
|
||||||
|
self.forward.set(*forward, 0.0)
|
||||||
|
self.up.set(*up, 0.0)
|
||||||
|
self.origin.set(*origin, 1.0)
|
||||||
|
|
||||||
|
assert ctypes.sizeof(vec3) == ctypes.sizeof(ctypes.c_float) * 3
|
||||||
|
assert ctypes.sizeof(vec4) == ctypes.sizeof(ctypes.c_float) * 4
|
||||||
|
assert ctypes.sizeof(mat3) == ctypes.sizeof(vec3) * 3
|
||||||
|
assert ctypes.sizeof(mat4) == ctypes.sizeof(vec4) * 4
|
||||||
|
|
||||||
|
_vec3_p = ctypes.POINTER(vec3)
|
||||||
|
_vec4_p = ctypes.POINTER(vec4)
|
||||||
|
_mat3_p = ctypes.POINTER(mat3)
|
||||||
|
_mat4_p = ctypes.POINTER(mat4)
|
||||||
|
|
||||||
|
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)
|
||||||
|
vec3_origin = vec3(0.0, 0.0, 0.0)
|
||||||
|
|
||||||
|
vec4_right = vec4(1.0, 0.0, 0.0, 0.0)
|
||||||
|
vec4_forward = vec4(0.0, 1.0, 0.0, 0.0)
|
||||||
|
vec4_up = vec4(0.0, 0.0, 1.0, 0.0)
|
||||||
|
vec4_origin = vec4(0.0, 0.0, 0.0, 1.0)
|
||||||
|
|
||||||
|
mat3_identity = mat3(
|
||||||
|
vec3_right,
|
||||||
|
vec3_forward,
|
||||||
|
vec3_up)
|
||||||
|
|
||||||
|
mat4_identity = mat4(
|
||||||
|
vec4_right,
|
||||||
|
vec4_forward,
|
||||||
|
vec4_up,
|
||||||
|
vec4_origin)
|
||||||
|
|
||||||
|
vec3_rotate = _engine.rk_vec3_rotate
|
||||||
|
vec3_rotate.restype = None
|
||||||
|
vec3_rotate.argtypes = (
|
||||||
|
_vec3_p, # ret
|
||||||
|
_vec3_p, # vec3
|
||||||
|
_vec3_p, # axis
|
||||||
|
ctypes.c_float) # angle
|
||||||
|
|
||||||
|
vec3_mul_vec3 = _engine.rk_vec3_mul_vec3
|
||||||
|
vec3_mul_vec3.restype = None
|
||||||
|
vec3_mul_vec3.argtypes = (
|
||||||
|
_vec3_p, # ret
|
||||||
|
_vec3_p, # a
|
||||||
|
_vec3_p) # b
|
||||||
|
|
||||||
|
mat3_rotation = _engine.rk_mat3_rotation
|
||||||
|
mat3_rotation.restype = None
|
||||||
|
mat3_rotation.argtypes = (
|
||||||
|
_mat3_p, # ret
|
||||||
|
_vec3_p, # axis
|
||||||
|
ctypes.c_float) # angle
|
||||||
|
|
||||||
|
mat3_mul_vec3 = _engine.rk_mat3_mul_vec3
|
||||||
|
mat3_mul_vec3.restype = None
|
||||||
|
mat3_mul_vec3.argtypes = (
|
||||||
|
_vec3_p, # ret
|
||||||
|
_mat3_p, # a
|
||||||
|
_vec3_p) # b
|
||||||
|
|
||||||
|
mat3_mul_mat3 = _engine.rk_mat3_mul_mat3
|
||||||
|
mat3_mul_mat3.restype = None
|
||||||
|
mat3_mul_mat3.argtypes = (
|
||||||
|
_mat3_p, # ret
|
||||||
|
_mat3_p, # a
|
||||||
|
_mat3_p) # b
|
||||||
|
|
||||||
|
mat4_projection = _engine.rk_mat4_projection
|
||||||
|
mat4_projection.restype = None
|
||||||
|
mat4_projection.argtypes = (
|
||||||
|
_mat4_p, # ret
|
||||||
|
ctypes.c_float, # hfov
|
||||||
|
ctypes.c_float, # ratio
|
||||||
|
ctypes.c_float, # near
|
||||||
|
ctypes.c_float) # far
|
||||||
|
|
||||||
|
mat4_lookat = _engine.rk_mat4_lookat
|
||||||
|
mat4_lookat.restype = None
|
||||||
|
mat4_lookat.argtypes = (
|
||||||
|
_mat4_p, # ret
|
||||||
|
_vec3_p, # position
|
||||||
|
_vec3_p) # lookat
|
||||||
|
|
||||||
|
mat4_orbit = _engine.rk_mat4_orbit
|
||||||
|
mat4_orbit.restype = None
|
||||||
|
mat4_orbit.argtypes = (
|
||||||
|
_mat4_p, # ret
|
||||||
|
_vec3_p, # origin
|
||||||
|
ctypes.c_float, # yaw
|
||||||
|
ctypes.c_float, # pitch
|
||||||
|
ctypes.c_float) # distance
|
||||||
|
|
||||||
|
mat4_mul_vec3 = _engine.rk_mat4_mul_vec3
|
||||||
|
mat4_mul_vec3.restype = None
|
||||||
|
mat4_mul_vec3.argtypes = (
|
||||||
|
_vec3_p, # ret
|
||||||
|
_mat4_p, # a
|
||||||
|
_vec3_p, # b
|
||||||
|
ctypes.c_float) # w
|
||||||
|
|
||||||
|
mat4_mul_vec4 = _engine.rk_mat4_mul_vec4
|
||||||
|
mat4_mul_vec4.restype = None
|
||||||
|
mat4_mul_vec4.argtypes = (
|
||||||
|
_vec4_p, # ret
|
||||||
|
_mat4_p, # a
|
||||||
|
_vec4_p) # b
|
||||||
|
|
||||||
|
mat4_mul_mat4 = _engine.rk_mat4_mul_mat4
|
||||||
|
mat4_mul_mat4.restype = None
|
||||||
|
mat4_mul_mat4.argtypes = (
|
||||||
|
_mat4_p, # ret
|
||||||
|
_mat4_p, # a
|
||||||
|
_mat4_p) # b
|
||||||
|
|
||||||
|
# display.hpp
|
||||||
|
|
||||||
|
create_display = _engine.rk_create_display
|
||||||
|
create_display.restype = _handle
|
||||||
|
create_display.errcheck = _check_handle
|
||||||
|
create_display.argtypes = (
|
||||||
|
ctypes.c_char_p, # name
|
||||||
|
ctypes.c_uint, # width
|
||||||
|
ctypes.c_uint) # height
|
||||||
|
|
||||||
|
destroy_display = _engine.rk_destroy_display
|
||||||
|
destroy_display.restype = None
|
||||||
|
destroy_display.argtypes = (
|
||||||
|
ctypes.c_void_p,) # display
|
||||||
|
|
||||||
|
swap_buffers = _engine.rk_swap_buffers
|
||||||
|
swap_buffers.restype = None
|
||||||
|
swap_buffers.argtypes = (
|
||||||
|
ctypes.c_void_p,) # display
|
||||||
|
|
||||||
|
# render.hpp
|
||||||
|
|
||||||
TEXTURE_FORMAT_SRGB8_A8 = 0
|
TEXTURE_FORMAT_SRGB8_A8 = 0
|
||||||
TEXTURE_FORMAT_RGBA8 = 1
|
TEXTURE_FORMAT_RGBA8 = 1
|
||||||
TEXTURE_FORMAT_RGB10_A2 = 2
|
TEXTURE_FORMAT_RGB10_A2 = 2
|
||||||
TEXTURE_FORMAT_32F = 3
|
TEXTURE_FORMAT_FLOAT_32 = 3
|
||||||
|
|
||||||
TEXTURE_FORMAT_TYPECODE = ('B', 'B', 'I', 'f')
|
TEXTURE_FORMAT_TYPECODE = ('B', 'B', 'I', 'f')
|
||||||
TEXTURE_FORMAT_NELEMS = (4, 4, 1, 1)
|
TEXTURE_FORMAT_NELEMS = (4, 4, 1, 1)
|
||||||
@ -39,222 +268,76 @@ TEXTURE_FLAG_MAG_NEAREST = 0
|
|||||||
TEXTURE_FLAG_MAG_LINEAR = _flag(3)
|
TEXTURE_FLAG_MAG_LINEAR = _flag(3)
|
||||||
|
|
||||||
VERTEX_FORMAT_VEC3_FLOAT = 1
|
VERTEX_FORMAT_VEC3_FLOAT = 1
|
||||||
VERTEX_FORMAT_VEC3_INT10 = 2
|
VERTEX_FORMAT_VEC3_SHORT = 2
|
||||||
VERTEX_FORMAT_VEC3_UINT10 = 3
|
VERTEX_FORMAT_VEC3_INT10 = 3
|
||||||
|
VERTEX_FORMAT_VEC3_UINT10 = 4
|
||||||
|
VERTEX_FORMAT_MAT3_FLOAT = 5
|
||||||
|
VERTEX_FORMAT_MAT3_INT10 = 6
|
||||||
VERTEX_FORMAT_NORMALIZE = _flag(7)
|
VERTEX_FORMAT_NORMALIZE = _flag(7)
|
||||||
|
_VERTEX_FORMAT_MASK = VERTEX_FORMAT_NORMALIZE - 1
|
||||||
|
|
||||||
def vertex_format(*format):
|
def vertex_format(*format):
|
||||||
return array('B', format).tobytes()
|
return array('B', format).tobytes()
|
||||||
|
|
||||||
PARAM_FORMAT_VEC3_FLOAT = 1
|
_VERTEX_TYPES = (
|
||||||
PARAM_FORMAT_VEC3_SHORT = 2
|
None,
|
||||||
PARAM_FORMAT_VEC3_INT10 = 3
|
vec3, # VERTEX_FORMAT_VEC3_FLOAT
|
||||||
PARAM_FORMAT_NORMALIZE = _flag(7)
|
vec3, # VERTEX_FORMAT_VEC3_SHORT
|
||||||
|
vec3, # VERTEX_FORMAT_VEC3_INT10
|
||||||
|
vec3, # VERTEX_FORMAT_VEC3_UINT10
|
||||||
|
mat3, # VERTEX_FORMAT_MAT3_FLOAT
|
||||||
|
mat3) # VERTEX_FORMAT_MAT3_INT10
|
||||||
|
|
||||||
def params_format(*format):
|
def vertex_type(format):
|
||||||
return array('B', format).tobytes()
|
return _VERTEX_TYPES[format & _VERTEX_FORMAT_MASK]
|
||||||
|
|
||||||
INSTANCE_FLAG_SPAWNED = _flag(0)
|
INSTANCE_FLAG_SPAWNED = _flag(0)
|
||||||
INSTANCE_FLAG_VISIBLE = _flag(1)
|
INSTANCE_FLAG_VISIBLE = _flag(1)
|
||||||
|
|
||||||
BATCH_MAX_SIZE = 65536
|
BATCH_MAX_SIZE = 65536
|
||||||
|
|
||||||
#TODO: remove from engine
|
render_initialize = _engine.rk_render_initialize
|
||||||
vec2_zero = (0.0, 0.0)
|
render_initialize.restype = None
|
||||||
vec3_zero = (0.0, 0.0, 0.0)
|
render_initialize.argtypes = (
|
||||||
vec3_right = (1.0, 0.0, 0.0)
|
ctypes.c_bool,) # debug
|
||||||
vec3_forward = (0.0, 1.0, 0.0)
|
|
||||||
vec3_up = (0.0, 0.0, 1.0)
|
|
||||||
vec4_zero = (0.0, 0.0, 0.0, 1.0)
|
|
||||||
mat3_identity = (
|
|
||||||
1.0, 0.0, 0.0,
|
|
||||||
0.0, 1.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0)
|
|
||||||
mat4_identity = (
|
|
||||||
1.0, 0.0, 0.0, 0.0,
|
|
||||||
0.0, 1.0, 0.0, 1.0,
|
|
||||||
0.0, 0.0, 1.0, 0.0,
|
|
||||||
0.0, 0.0, 0.0, 1.0)
|
|
||||||
|
|
||||||
def vec2(v = vec2_zero):
|
render_terminate = _engine.rk_render_terminate
|
||||||
assert len(v) == 2
|
render_terminate.restype = None
|
||||||
return array('f', v)
|
|
||||||
|
|
||||||
def vec3(v = vec3_zero):
|
_create_shader = _engine.rk_create_shader
|
||||||
assert len(v) == 3
|
_create_shader.restype = _handle
|
||||||
return array('f', v)
|
_create_shader.errcheck = _check_handle
|
||||||
|
_create_shader.argtypes = (
|
||||||
def vec4(v = vec4_zero):
|
|
||||||
assert len(v) == 4
|
|
||||||
return array('f', v)
|
|
||||||
|
|
||||||
def mat3(m = mat3_identity):
|
|
||||||
assert len(m) == 9
|
|
||||||
return array('f', m)
|
|
||||||
|
|
||||||
def mat4(m = mat4_identity):
|
|
||||||
assert len(m) == 16
|
|
||||||
return array('f', m)
|
|
||||||
|
|
||||||
_vec2_t = (ctypes.c_float * 2)
|
|
||||||
_vec2 = _vec2_t.from_buffer
|
|
||||||
|
|
||||||
_vec3_t = (ctypes.c_float * 3)
|
|
||||||
_vec3 = _vec3_t.from_buffer
|
|
||||||
|
|
||||||
_vec4_t = (ctypes.c_float * 4)
|
|
||||||
_vec4 = _vec4_t.from_buffer
|
|
||||||
|
|
||||||
_mat3_t = (ctypes.c_float * 9)
|
|
||||||
_mat3 = _mat3_t.from_buffer
|
|
||||||
|
|
||||||
_mat4_t = (ctypes.c_float * 16)
|
|
||||||
_mat4 = _mat4_t.from_buffer
|
|
||||||
|
|
||||||
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 _uintp(x):
|
|
||||||
assert x.typecode == 'I'
|
|
||||||
return x.buffer_info()[0]
|
|
||||||
|
|
||||||
def _floatp(x):
|
|
||||||
assert x.typecode == 'f'
|
|
||||||
return x.buffer_info()[0]
|
|
||||||
|
|
||||||
_mat3_rotation = _lib.rk_mat3_rotation
|
|
||||||
_mat3_rotation.argtypes = (
|
|
||||||
_mat3_t, # ret
|
|
||||||
_vec3_t, # axis
|
|
||||||
ctypes.c_float) # angle
|
|
||||||
|
|
||||||
def mat3_rotation(ret, axis, angle):
|
|
||||||
assert len(ret) == 9 and len(axis) == 3
|
|
||||||
_mat3_rotation(_mat3(ret), _vec3(axis), angle)
|
|
||||||
|
|
||||||
_mat3_mul_vec3 = _lib.rk_mat3_mul_vec3
|
|
||||||
_mat3_mul_vec3.argtypes = (
|
|
||||||
_vec3_t, # ret
|
|
||||||
_mat3_t, # a
|
|
||||||
_vec3_t) # b
|
|
||||||
|
|
||||||
def mat3_mul_vec3(ret, a, b):
|
|
||||||
assert len(ret) == 3 and len(a) == 9 and len(b) == 3
|
|
||||||
_mat3_mul_vec3(_vec3(ret), _mat3(a), _vec3(b))
|
|
||||||
|
|
||||||
_mat3_mul_mat3 = _lib.rk_mat3_mul_mat3
|
|
||||||
_mat3_mul_mat3.argtypes = (
|
|
||||||
_mat3_t, # ret
|
|
||||||
_mat3_t, # a
|
|
||||||
_mat3_t) # b
|
|
||||||
|
|
||||||
def mat3_mul_mat3(ret, a, b):
|
|
||||||
assert len(ret) == 9 and len(a) == 9 and len(b) == 9
|
|
||||||
_mat3_mul_mat3(_mat3(ret), _mat3(a), _mat3(b))
|
|
||||||
|
|
||||||
_mat4_projection = _lib.rk_mat4_projection
|
|
||||||
_mat4_projection.argtypes = (
|
|
||||||
_mat4_t, # ret
|
|
||||||
ctypes.c_float, # hfov
|
|
||||||
ctypes.c_float, # ratio
|
|
||||||
ctypes.c_float, # near
|
|
||||||
ctypes.c_float) # far
|
|
||||||
|
|
||||||
def mat4_projection(ret, hfov, ratio, near, far):
|
|
||||||
assert len(ret) == 16
|
|
||||||
_mat4_projection(_mat4(ret), hfov, ratio, near, far)
|
|
||||||
|
|
||||||
_mat4_lookat = _lib.rk_mat4_lookat
|
|
||||||
_mat4_lookat.argtypes = (
|
|
||||||
_mat4_t, # ret
|
|
||||||
_vec3_t, # position
|
|
||||||
_vec3_t) # lookat
|
|
||||||
|
|
||||||
def mat4_lookat(ret, position, lookat):
|
|
||||||
assert len(ret) == 16 and len(position) == 3 and len(lookat) == 3
|
|
||||||
_mat4_lookat(_mat4(ret), _vec3(position), _vec3(lookat))
|
|
||||||
|
|
||||||
_mat4_mul_vec3 = _lib.rk_mat4_mul_vec3
|
|
||||||
_mat4_mul_vec3.argtypes = (
|
|
||||||
_vec3_t, # ret
|
|
||||||
_mat4_t, # a
|
|
||||||
_vec3_t, # b
|
|
||||||
ctypes.c_float) # w
|
|
||||||
|
|
||||||
def mat4_mul_vec3(ret, a, b, w):
|
|
||||||
assert len(ret) == 3 and len(a) == 16 and len(b) == 3
|
|
||||||
_mat4_mul_vec3(_vec3(ret), _mat4(a), _vec3(b), w)
|
|
||||||
|
|
||||||
_mat4_mul_vec4 = _lib.rk_mat4_mul_vec4
|
|
||||||
_mat4_mul_vec4.argtypes = (
|
|
||||||
_vec4_t, # ret
|
|
||||||
_mat4_t, # a
|
|
||||||
_vec4_t) # b
|
|
||||||
|
|
||||||
def mat4_mul_vec4(ret, a, b):
|
|
||||||
assert len(ret) == 4 and len(a) == 16 and len(b) == 4
|
|
||||||
_mat4_mul_vec4(_vec4(ret), _mat4(a), _vec4(b))
|
|
||||||
|
|
||||||
_mat4_mul_mat4 = _lib.rk_mat4_mul_mat4
|
|
||||||
_mat4_mul_mat4.argtypes = (
|
|
||||||
_mat4_t, # ret
|
|
||||||
_mat4_t, # a
|
|
||||||
_mat4_t) # b
|
|
||||||
|
|
||||||
def mat4_mul_mat4(ret, a, b):
|
|
||||||
assert len(ret) == 16 and len(a) == 16 and len(b) == 16
|
|
||||||
_mat4_mul_mat4(_mat4(ret), _mat4(a), _mat4(b))
|
|
||||||
|
|
||||||
initialize = _lib.rk_initialize
|
|
||||||
initialize.restype = ctypes.c_void_p
|
|
||||||
initialize.argtypes = (
|
|
||||||
ctypes.c_char_p, # name
|
|
||||||
ctypes.c_uint, # width
|
|
||||||
ctypes.c_uint) # height
|
|
||||||
|
|
||||||
_load_shader = _lib.rk_load_shader
|
|
||||||
_load_shader.restype = ctypes.c_void_p
|
|
||||||
_load_shader.argtypes = (
|
|
||||||
ctypes.c_uint, # vert_nlines
|
ctypes.c_uint, # vert_nlines
|
||||||
ctypes.c_void_p, # vert_lines
|
ctypes.POINTER(ctypes.c_char_p), # vert_lines
|
||||||
ctypes.c_uint, # frag_nlines
|
ctypes.c_uint, # frag_nlines
|
||||||
ctypes.c_void_p) # frag_lines
|
ctypes.POINTER(ctypes.c_char_p)) # frag_lines
|
||||||
|
|
||||||
def load_shader(vert_lines, frag_lines):
|
def create_shader(vert_lines, frag_lines):
|
||||||
vert_nlines = len(vert_lines)
|
vert_nlines = len(vert_lines)
|
||||||
vert_type = ctypes.c_char_p * vert_nlines
|
vert_type = ctypes.c_char_p * vert_nlines
|
||||||
vert_lines = vert_type(*map(ctypes.c_char_p, vert_lines))
|
vert_lines = vert_type(*map(ctypes.c_char_p, vert_lines))
|
||||||
frag_nlines = len(frag_lines)
|
frag_nlines = len(frag_lines)
|
||||||
frag_type = ctypes.c_char_p * frag_nlines
|
frag_type = ctypes.c_char_p * frag_nlines
|
||||||
frag_lines = frag_type(*map(ctypes.c_char_p, frag_lines))
|
frag_lines = frag_type(*map(ctypes.c_char_p, frag_lines))
|
||||||
return _load_shader(
|
return _create_shader(vert_nlines, vert_lines, frag_nlines, frag_lines)
|
||||||
vert_nlines, ctypes.addressof(vert_lines),
|
|
||||||
frag_nlines, ctypes.addressof(frag_lines))
|
|
||||||
|
|
||||||
resolve_input = _lib.rk_resolve_input
|
resolve_input = _engine.rk_resolve_input
|
||||||
resolve_input.restype = ctypes.c_void_p
|
resolve_input.restype = _handle
|
||||||
resolve_input.argtypes = (
|
resolve_input.argtypes = (
|
||||||
ctypes.c_void_p, # shader
|
ctypes.c_void_p, # shader
|
||||||
ctypes.c_char_p) # name
|
ctypes.c_char_p) # name
|
||||||
|
|
||||||
resolve_param = _lib.rk_resolve_param
|
resolve_param = _engine.rk_resolve_param
|
||||||
resolve_param.restype = ctypes.c_void_p
|
resolve_param.restype = _handle
|
||||||
resolve_param.argtypes = (
|
resolve_param.argtypes = (
|
||||||
ctypes.c_void_p, # shader
|
ctypes.c_void_p, # shader
|
||||||
ctypes.c_char_p) # name
|
ctypes.c_char_p) # name
|
||||||
|
|
||||||
_create_texture = _lib.rk_create_texture
|
_create_texture = _engine.rk_create_texture
|
||||||
_create_texture.restype = ctypes.c_void_p
|
_create_texture.restype = _handle
|
||||||
|
_create_texture.errcheck = _check_handle
|
||||||
_create_texture.argtypes = (
|
_create_texture.argtypes = (
|
||||||
ctypes.c_uint, # slot
|
|
||||||
ctypes.c_uint, # format
|
ctypes.c_uint, # format
|
||||||
ctypes.c_uint, # width
|
ctypes.c_uint, # width
|
||||||
ctypes.c_uint, # height
|
ctypes.c_uint, # height
|
||||||
@ -262,145 +345,224 @@ _create_texture.argtypes = (
|
|||||||
ctypes.c_uint, # flags
|
ctypes.c_uint, # flags
|
||||||
ctypes.c_void_p) # pixels
|
ctypes.c_void_p) # pixels
|
||||||
|
|
||||||
def create_texture(slot, format, width, height, nlevels, flags, pixels):
|
def create_texture(format, width, height, nlevels, flags, pixels):
|
||||||
assert pixels.typecode == TEXTURE_FORMAT_TYPECODE[format]
|
assert pixels.typecode == TEXTURE_FORMAT_TYPECODE[format]
|
||||||
assert len(pixels) == width * height * max(1, nlevels) * TEXTURE_FORMAT_NELEMS[format]
|
assert len(pixels) == width * height * max(1, nlevels) * TEXTURE_FORMAT_NELEMS[format]
|
||||||
return _create_texture(slot, format, width, height, nlevels, flags, _voidp(pixels))
|
return _create_texture(format, width, height, nlevels, flags, _void_addr(pixels))
|
||||||
|
|
||||||
_create_triangles = _lib.rk_create_triangles
|
_create_triangles = _engine.rk_create_triangles
|
||||||
_create_triangles.restype = ctypes.c_void_p
|
_create_triangles.restype = _handle
|
||||||
|
_create_triangles.errcheck = _check_handle
|
||||||
_create_triangles.argtypes = (
|
_create_triangles.argtypes = (
|
||||||
ctypes.c_uint, # nvertices
|
ctypes.c_uint, # nvertices
|
||||||
ctypes.c_void_p) # vertices
|
ctypes.c_void_p) # vertices
|
||||||
|
|
||||||
def create_triangles(vertices):
|
def create_triangles(vertices):
|
||||||
assert len(vertices) % 9 == 0
|
assert len(vertices) % 9 == 0
|
||||||
return _create_triangles(len(vertices) // 3, _floatp(vertices))
|
return _create_triangles(len(vertices) // 3, _float_addr(vertices))
|
||||||
|
|
||||||
_create_vertices = _lib.rk_create_vertices
|
_create_vertices = _engine.rk_create_vertices
|
||||||
_create_vertices.restype = ctypes.c_void_p
|
_create_vertices.restype = _handle
|
||||||
|
_create_vertices.errcheck = _check_handle
|
||||||
_create_vertices.argtypes = (
|
_create_vertices.argtypes = (
|
||||||
ctypes.c_char_p, # format
|
ctypes.c_char_p, # format
|
||||||
ctypes.c_uint, # nvertices
|
ctypes.c_uint, # nvertices
|
||||||
ctypes.c_void_p, # vertices
|
ctypes.c_void_p, # vertices
|
||||||
ctypes.c_uint, # nindices
|
ctypes.c_uint, # nindices
|
||||||
ctypes.c_void_p) # indices
|
ctypes.c_void_p, # vertices
|
||||||
|
ctypes.c_uint, # nmeshes
|
||||||
|
ctypes.c_void_p) # meshes
|
||||||
|
|
||||||
def create_vertices(format, nvertices, vertices, indices):
|
def create_vertices(format, nvertices, vertices, indices, meshes):
|
||||||
return _create_vertices(format, nvertices, _ubytep(vertices), len(indices), _ushortp(indices))
|
assert len(meshes) % 2 == 0
|
||||||
|
return _create_vertices(format,
|
||||||
|
nvertices, _ubyte_addr(vertices), len(indices), _ushort_addr(indices), len(meshes) // 2, _uint_addr(meshes))
|
||||||
|
|
||||||
create_batch = _lib.rk_create_batch
|
create_batch = _engine.rk_create_batch
|
||||||
create_batch.restype = ctypes.c_void_p
|
create_batch.restype = _handle
|
||||||
|
create_batch.errcheck = _check_handle
|
||||||
create_batch.argtypes = (
|
create_batch.argtypes = (
|
||||||
ctypes.c_void_p, # vertices
|
ctypes.c_void_p, # vertices
|
||||||
ctypes.c_uint, # max_size
|
ctypes.c_uint, # max_size
|
||||||
ctypes.c_char_p) # params_format
|
ctypes.c_char_p) # params_format
|
||||||
|
|
||||||
begin_frame = _lib.rk_begin_frame
|
fill_batch = _engine.rk_fill_batch
|
||||||
|
fill_batch.restype = None
|
||||||
|
fill_batch.argtypes = (
|
||||||
|
ctypes.c_void_p, # batch
|
||||||
|
ctypes.c_uint, # count
|
||||||
|
ctypes.POINTER(ctypes.c_ubyte), # flags
|
||||||
|
ctypes.POINTER(ctypes.c_ushort), # meshes
|
||||||
|
ctypes.POINTER(ctypes.c_void_p)) # params
|
||||||
|
|
||||||
select_shader = _lib.rk_select_shader
|
clear_buffer = _engine.rk_clear_buffer
|
||||||
|
clear_buffer.restype = None
|
||||||
|
clear_buffer.argtypes = (
|
||||||
|
ctypes.c_bool, # pixels
|
||||||
|
ctypes.c_bool, # depth
|
||||||
|
ctypes.c_bool) # stencil
|
||||||
|
|
||||||
|
select_shader = _engine.rk_select_shader
|
||||||
|
select_shader.restype = None
|
||||||
select_shader.argtypes = (
|
select_shader.argtypes = (
|
||||||
ctypes.c_void_p,) # shader
|
ctypes.c_void_p,) # shader
|
||||||
|
|
||||||
set_input_float = _lib.rk_set_input_float
|
set_input_float = _engine.rk_set_input_float
|
||||||
|
set_input_float.restype = None
|
||||||
set_input_float.argtypes = (
|
set_input_float.argtypes = (
|
||||||
ctypes.c_void_p, # input
|
ctypes.c_void_p, # input
|
||||||
ctypes.c_float) # value
|
ctypes.c_float) # value
|
||||||
|
|
||||||
_set_input_vec3 = _lib.rk_set_input_vec3
|
set_input_vec3 = _engine.rk_set_input_vec3
|
||||||
_set_input_vec3.argtypes = (
|
set_input_vec3.restype = None
|
||||||
|
set_input_vec3.argtypes = (
|
||||||
ctypes.c_void_p, # input
|
ctypes.c_void_p, # input
|
||||||
_vec3_t) # value
|
_vec3_p) # value
|
||||||
|
|
||||||
def set_input_vec3(input, value):
|
set_input_mat3 = _engine.rk_set_input_mat3
|
||||||
assert len(value) == 3
|
set_input_mat3.restype = None
|
||||||
_set_input_vec3(input, _vec3(value))
|
set_input_mat3.argtypes = (
|
||||||
|
|
||||||
_set_input_mat3 = _lib.rk_set_input_mat3
|
|
||||||
_set_input_mat3.argtypes = (
|
|
||||||
ctypes.c_void_p, # input
|
ctypes.c_void_p, # input
|
||||||
_mat3_t) # value
|
_mat3_p) # value
|
||||||
|
|
||||||
def set_input_mat3(input, value):
|
set_input_mat4 = _engine.rk_set_input_mat4
|
||||||
assert len(value) == 9
|
set_input_mat4.restype = None
|
||||||
_set_input_mat3(input, _mat3(value))
|
set_input_mat4.argtypes = (
|
||||||
|
|
||||||
_set_input_mat4 = _lib.rk_set_input_mat4
|
|
||||||
_set_input_mat4.argtypes = (
|
|
||||||
ctypes.c_void_p, # input
|
ctypes.c_void_p, # input
|
||||||
_mat4_t) # value
|
_mat4_p) # value
|
||||||
|
|
||||||
def set_input_mat4(input, value):
|
set_param_vec3 = _engine.rk_set_param_vec3
|
||||||
assert len(value) == 16
|
set_param_vec3.restype = None
|
||||||
_set_input_mat4(input, _mat4(value))
|
set_param_vec3.argtypes = (
|
||||||
|
|
||||||
_set_param_vec3 = _lib.rk_set_param_vec3
|
|
||||||
_set_param_vec3.argtypes = (
|
|
||||||
ctypes.c_uint, # layout
|
ctypes.c_uint, # layout
|
||||||
_vec3_t) # value
|
_vec3_p) # value
|
||||||
|
|
||||||
def set_param_vec3(param, value):
|
set_param_mat3 = _engine.rk_set_param_mat3
|
||||||
assert len(value) == 3
|
set_param_mat3.restype = None
|
||||||
_set_param_vec3(param, _vec3(value))
|
set_param_mat3.argtypes = (
|
||||||
|
ctypes.c_uint, # layout
|
||||||
|
_mat3_p) # value
|
||||||
|
|
||||||
select_texture = _lib.rk_select_texture
|
select_texture = _engine.rk_select_texture
|
||||||
|
select_texture.restype = None
|
||||||
select_texture.argtypes = (
|
select_texture.argtypes = (
|
||||||
ctypes.c_void_p, # texture
|
ctypes.c_uint, # slot
|
||||||
ctypes.c_void_p) # sampler
|
ctypes.c_void_p) # texture
|
||||||
|
|
||||||
draw_triangles = _lib.rk_draw_triangles
|
draw_triangles = _engine.rk_draw_triangles
|
||||||
|
draw_triangles.restype = None
|
||||||
draw_triangles.argtypes = (
|
draw_triangles.argtypes = (
|
||||||
ctypes.c_void_p,) # triangles
|
ctypes.c_void_p,) # triangles
|
||||||
|
|
||||||
select_vertices = _lib.rk_select_vertices
|
draw_batch = _engine.rk_draw_batch
|
||||||
select_vertices.argtypes = (
|
draw_batch.restype = None
|
||||||
ctypes.c_void_p,) # vertices
|
draw_batch.argtypes = (
|
||||||
|
ctypes.c_void_p,) # batch
|
||||||
|
|
||||||
_draw_batch = _lib.rk_draw_batch
|
unselect_texture = _engine.rk_unselect_texture
|
||||||
_draw_batch.argtypes = (
|
unselect_texture.restype = None
|
||||||
ctypes.c_void_p, # batch
|
|
||||||
ctypes.c_uint, # size
|
|
||||||
ctypes.c_void_p, # flags
|
|
||||||
ctypes.c_void_p, # meshes
|
|
||||||
ctypes.c_void_p) # params
|
|
||||||
|
|
||||||
def draw_batch(batch, flags, meshes, params):
|
|
||||||
size = len(flags)
|
|
||||||
assert len(meshes) == size
|
|
||||||
_draw_batch(batch, size, _ubytep(flags), _uintp(meshes), _voidp(params))
|
|
||||||
|
|
||||||
unselect_vertices = _lib.rk_unselect_vertices
|
|
||||||
unselect_vertices.argtypes = (
|
|
||||||
ctypes.c_void_p,) # vertices
|
|
||||||
|
|
||||||
unselect_texture = _lib.rk_unselect_texture
|
|
||||||
unselect_texture.argtypes = (
|
unselect_texture.argtypes = (
|
||||||
ctypes.c_void_p,) # texture
|
ctypes.c_uint, # slot
|
||||||
|
ctypes.c_void_p) # texture
|
||||||
|
|
||||||
unselect_shader = _lib.rk_unselect_shader
|
unselect_shader = _engine.rk_unselect_shader
|
||||||
|
unselect_shader.restype = None
|
||||||
unselect_shader.argtypes = (
|
unselect_shader.argtypes = (
|
||||||
ctypes.c_void_p,) # shader
|
ctypes.c_void_p,) # shader
|
||||||
|
|
||||||
end_frame = _lib.rk_end_frame
|
destroy_batch = _engine.rk_destroy_batch
|
||||||
|
destroy_batch.restype = None
|
||||||
destroy_batch = _lib.rk_destroy_batch
|
|
||||||
destroy_batch.argtypes = (
|
destroy_batch.argtypes = (
|
||||||
ctypes.c_void_p,) # batch
|
ctypes.c_void_p,) # batch
|
||||||
|
|
||||||
destroy_triangles = _lib.rk_destroy_triangles
|
destroy_triangles = _engine.rk_destroy_triangles
|
||||||
|
destroy_triangles.restype = None
|
||||||
destroy_triangles.argtypes = (
|
destroy_triangles.argtypes = (
|
||||||
ctypes.c_void_p,) # triangles
|
ctypes.c_void_p,) # triangles
|
||||||
|
|
||||||
destroy_vertices = _lib.rk_destroy_vertices
|
destroy_vertices = _engine.rk_destroy_vertices
|
||||||
|
destroy_vertices.restype = None
|
||||||
destroy_vertices.argtypes = (
|
destroy_vertices.argtypes = (
|
||||||
ctypes.c_void_p,) # vertices
|
ctypes.c_void_p,) # vertices
|
||||||
|
|
||||||
destroy_texture = _lib.rk_destroy_texture
|
destroy_texture = _engine.rk_destroy_texture
|
||||||
|
destroy_texture.restype = None
|
||||||
destroy_texture.argtypes = (
|
destroy_texture.argtypes = (
|
||||||
ctypes.c_void_p,) # texture
|
ctypes.c_void_p,) # texture
|
||||||
|
|
||||||
destroy_shader = _lib.rk_destroy_shader
|
destroy_shader = _engine.rk_destroy_shader
|
||||||
|
destroy_shader.restype = None
|
||||||
destroy_shader.argtypes = (
|
destroy_shader.argtypes = (
|
||||||
ctypes.c_void_p,) # shader
|
ctypes.c_void_p,) # shader
|
||||||
|
|
||||||
terminate = _lib.rk_terminate
|
# events.hpp
|
||||||
|
|
||||||
|
EVENT_FOCUS_IN = 0
|
||||||
|
EVENT_FOCUS_OUT = 1
|
||||||
|
EVENT_KEY_PRESS = 2
|
||||||
|
EVENT_KEY_RELEASE = 3
|
||||||
|
EVENT_BUTTON_PRESS = 4
|
||||||
|
EVENT_BUTTON_RELEASE = 5
|
||||||
|
EVENT_MOTION = 6
|
||||||
|
|
||||||
|
BUTTON_LEFT = 1
|
||||||
|
BUTTON_MIDDLE = 2
|
||||||
|
BUTTON_RIGHT = 3
|
||||||
|
BUTTON_WHEEL_UP = 4
|
||||||
|
BUTTON_WHEEL_DOWN = 5
|
||||||
|
|
||||||
|
class _EventKey(ctypes.Structure):
|
||||||
|
_fields_ = (
|
||||||
|
('code', ctypes.c_uint),
|
||||||
|
('symbol', ctypes.c_uint),
|
||||||
|
('character', ctypes.c_wchar))
|
||||||
|
|
||||||
|
class _EventButton(ctypes.Structure):
|
||||||
|
_fields_ = ('index', ctypes.c_uint),
|
||||||
|
|
||||||
|
class _EventMotion(ctypes.Structure):
|
||||||
|
_fields_ = (
|
||||||
|
('x', ctypes.c_int),
|
||||||
|
('y', ctypes.c_int))
|
||||||
|
|
||||||
|
class _Events(ctypes.Union):
|
||||||
|
_fields_ = (
|
||||||
|
('key', _EventKey),
|
||||||
|
('button', _EventButton),
|
||||||
|
('motion', _EventMotion))
|
||||||
|
|
||||||
|
class Event(ctypes.Structure):
|
||||||
|
_fields_ = ('type', ctypes.c_uint), ('data', _Events)
|
||||||
|
|
||||||
|
create_events = _engine.rk_create_events
|
||||||
|
create_events.restype = _handle
|
||||||
|
create_events.errcheck = _check_handle
|
||||||
|
create_events.argtypes = (
|
||||||
|
ctypes.c_void_p,) # display
|
||||||
|
|
||||||
|
destroy_events = _engine.rk_destroy_events
|
||||||
|
destroy_events.restype = None
|
||||||
|
destroy_events.argtypes = (
|
||||||
|
ctypes.c_void_p, # display
|
||||||
|
ctypes.c_void_p) # events
|
||||||
|
|
||||||
|
set_key_autorepeat = _engine.rk_set_key_autorepeat
|
||||||
|
set_key_autorepeat.restype = None
|
||||||
|
set_key_autorepeat.argtypes = (
|
||||||
|
ctypes.c_void_p, # events
|
||||||
|
ctypes.c_bool) # autorepeat
|
||||||
|
|
||||||
|
set_motion_acceleration = _engine.rk_set_motion_acceleration
|
||||||
|
set_motion_acceleration.restype = None
|
||||||
|
set_motion_acceleration.argtypes = (
|
||||||
|
ctypes.c_void_p, # events
|
||||||
|
ctypes.c_uint, # numerator
|
||||||
|
ctypes.c_uint, # denominator
|
||||||
|
ctypes.c_uint) # threshold
|
||||||
|
|
||||||
|
consume_events = _engine.rk_consume_events
|
||||||
|
consume_events.restype = ctypes.c_uint
|
||||||
|
consume_events.argtypes = (
|
||||||
|
ctypes.c_void_p, # events
|
||||||
|
ctypes.POINTER(Event), # buffer
|
||||||
|
ctypes.c_uint) # max_events
|
||||||
|
@ -13,21 +13,22 @@
|
|||||||
// 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_H
|
||||||
#define _RK_ENGINE_RENDER_CONTEXT_H
|
#define _RK_ENGINE_DISPLAY_H
|
||||||
|
|
||||||
#include "../render.hpp"
|
#include "types.hpp"
|
||||||
#include <GL/glx.h>
|
|
||||||
|
|
||||||
extern PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC rk_DrawElementsInstancedBaseInstance;
|
typedef rk_handle_t rk_display_t;
|
||||||
extern PFNGLMULTIDRAWELEMENTSINDIRECTPROC rk_MultiDrawElementsIndirect;
|
|
||||||
|
|
||||||
RK_EXPORT rk_window_t rk_create_context(
|
RK_EXPORT rk_display_t rk_create_display(
|
||||||
char const * name,
|
rk_char const * name,
|
||||||
rk_uint width,
|
rk_uint width,
|
||||||
rk_uint height);
|
rk_uint height);
|
||||||
|
|
||||||
RK_EXPORT void rk_swap_buffers();
|
RK_EXPORT void rk_destroy_display(
|
||||||
RK_EXPORT void rk_destroy_context();
|
rk_display_t display);
|
||||||
|
|
||||||
#endif // _RK_ENGINE_RENDER_CONTEXT_H
|
RK_EXPORT void rk_swap_buffers(
|
||||||
|
rk_display_t display);
|
||||||
|
|
||||||
|
#endif // _RK_ENGINE_DISPLAY_H
|
260
cpp/display/display_glx.cpp
Normal file
260
cpp/display/display_glx.cpp
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
// 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 "../events/events_x11.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 *);
|
||||||
|
|
||||||
|
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_x11_printf(
|
||||||
|
char const * messsage) {
|
||||||
|
printf("[X11] %s\n", messsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_glx_printf(
|
||||||
|
char const * messsage) {
|
||||||
|
printf("[GLX] %s\n", messsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rk_extension_supported(
|
||||||
|
char const * extensions,
|
||||||
|
char const * extension) {
|
||||||
|
char const * where = strchr(extension, ' ');
|
||||||
|
if (where || *extension == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (char const * start = extensions;;) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
rk_func_ptr rk_resolve_extension(
|
||||||
|
char const * extensions,
|
||||||
|
char const * extension,
|
||||||
|
char const * fn) {
|
||||||
|
if (!extensions || !extension || !fn) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!rk_extension_supported(extensions, extension)) {
|
||||||
|
printf("[GLX] Extension %s not supported\n", extension);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
rk_func_ptr const ptr = glXGetProcAddressARB(reinterpret_cast<GLubyte const *>(fn));
|
||||||
|
if (!ptr) {
|
||||||
|
printf("[GLX] Function %s::%s not found\n", extension, fn);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_x11_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));
|
||||||
|
// rk_glx_printf(glx_exts);
|
||||||
|
rk_CreateContextAttribsFunc const glXCreateContextAttribs = reinterpret_cast<rk_CreateContextAttribsFunc>(
|
||||||
|
rk_resolve_extension(glx_exts, "GLX_ARB_create_context", "glXCreateContextAttribsARB"));
|
||||||
|
if (!glXCreateContextAttribs) {
|
||||||
|
rk_destroy_display(reinterpret_cast<rk_display_t>(display));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fb_count = 0;
|
||||||
|
GLXFBConfig * fb_configs;
|
||||||
|
bool const srgb_ext = rk_extension_supported(glx_exts, "GLX_EXT_framebuffer_sRGB");
|
||||||
|
if (srgb_ext) {
|
||||||
|
rk_glx_printf("GLX_EXT_framebuffer_sRGB extension supported.");
|
||||||
|
int const visual_attribs[] = { GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, True, GLX_DOUBLEBUFFER, True, None };
|
||||||
|
fb_configs = glXChooseFBConfig(display->display, DefaultScreen(display->display), visual_attribs, &fb_count);
|
||||||
|
} else {
|
||||||
|
int const visual_attribs[] = { GLX_DOUBLEBUFFER, True, None };
|
||||||
|
fb_configs = glXChooseFBConfig(display->display, DefaultScreen(display->display), visual_attribs, &fb_count);
|
||||||
|
}
|
||||||
|
printf("[GLX] Found %d framebuffer configs.\n", fb_count);
|
||||||
|
if (!fb_configs || !fb_count) {
|
||||||
|
rk_glx_printf("Failed to retrieve framebuffer configs.");
|
||||||
|
rk_destroy_display(reinterpret_cast<rk_display_t>(display));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
GLXFBConfig fb_config;
|
||||||
|
int rs = 0;
|
||||||
|
int gs = 0;
|
||||||
|
int bs = 0;
|
||||||
|
int as = 0;
|
||||||
|
int ds = 0;
|
||||||
|
int ss = 0;
|
||||||
|
for (int fb_index = 0; fb_index < fb_count; ++fb_index) {
|
||||||
|
GLXFBConfig _config = fb_configs[fb_index];
|
||||||
|
int _rs = 0;
|
||||||
|
int _gs = 0;
|
||||||
|
int _bs = 0;
|
||||||
|
int _as = 0;
|
||||||
|
int _ds = 0;
|
||||||
|
int _ss = 0;
|
||||||
|
glXGetFBConfigAttrib(display->display, _config, GLX_RED_SIZE, &_rs);
|
||||||
|
glXGetFBConfigAttrib(display->display, _config, GLX_GREEN_SIZE, &_gs);
|
||||||
|
glXGetFBConfigAttrib(display->display, _config, GLX_BLUE_SIZE, &_bs);
|
||||||
|
glXGetFBConfigAttrib(display->display, _config, GLX_ALPHA_SIZE, &_as);
|
||||||
|
glXGetFBConfigAttrib(display->display, _config, GLX_DEPTH_SIZE, &_ds);
|
||||||
|
glXGetFBConfigAttrib(display->display, _config, GLX_STENCIL_SIZE, &_ss);
|
||||||
|
if ((_rs >= rs && _gs >= gs && _bs >= bs && _as >= as && _ds >= ds && _ss >= ss) &&
|
||||||
|
(_rs > rs || _gs > gs || _bs > bs || _as > as || _ds > ds || _ss > ss)) {
|
||||||
|
XVisualInfo * const vi = glXGetVisualFromFBConfig(display->display, _config);
|
||||||
|
if (vi) {
|
||||||
|
XFree(vi);
|
||||||
|
rs = _rs;
|
||||||
|
gs = _gs;
|
||||||
|
bs = _bs;
|
||||||
|
as = _as;
|
||||||
|
ds = _ds;
|
||||||
|
ss = _ss;
|
||||||
|
fb_config = _config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("[RK] Select framebuffer config R%dG%dB%dA%d D%dS%d.\n", rs, gs, bs, as, ds, ss);
|
||||||
|
if (srgb_ext) {
|
||||||
|
int srgb = 0;
|
||||||
|
glXGetFBConfigAttrib(display->display, fb_config, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, &srgb);
|
||||||
|
if (srgb) {
|
||||||
|
rk_glx_printf("sRGB framebuffer selected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XVisualInfo * const vi = glXGetVisualFromFBConfig(display->display, fb_config);
|
||||||
|
Window root = RootWindow(display->display, vi->screen);
|
||||||
|
display->colormap = XCreateColormap(display->display, root, vi->visual, AllocNone);
|
||||||
|
XSetWindowAttributes win_attributes;
|
||||||
|
win_attributes.colormap = display->colormap;
|
||||||
|
win_attributes.event_mask = RK_EVENTS_MASK;
|
||||||
|
display->window = XCreateWindow(display->display, root,
|
||||||
|
0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &win_attributes);
|
||||||
|
XFree(vi);
|
||||||
|
XFree(fb_configs);
|
||||||
|
if (!display->window) {
|
||||||
|
rk_x11_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_error_occured = false;
|
||||||
|
int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&rk_error_handler);
|
||||||
|
display->context = glXCreateContextAttribs(display->display, fb_config, 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);
|
||||||
|
if (srgb_ext) {
|
||||||
|
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
|
||||||
|
if (glIsEnabled(GL_FRAMEBUFFER_SRGB_EXT)) {
|
||||||
|
rk_glx_printf("sRGB framebuffer enabled.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
38
cpp/display/display_glx.hpp
Normal file
38
cpp/display/display_glx.hpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// 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_GLX_H
|
||||||
|
#define _RK_ENGINE_DISPLAY_GLX_H
|
||||||
|
|
||||||
|
#include "../types.hpp"
|
||||||
|
#include "display_x11.hpp"
|
||||||
|
#include <GL/glx.h>
|
||||||
|
|
||||||
|
struct rk_display_glx : public rk_display_x11 {
|
||||||
|
GLXContext context;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*rk_func_ptr)();
|
||||||
|
|
||||||
|
extern bool rk_extension_supported(
|
||||||
|
char const * extensions,
|
||||||
|
char const * extension);
|
||||||
|
|
||||||
|
extern rk_func_ptr rk_resolve_extension(
|
||||||
|
char const * extensions,
|
||||||
|
char const * extension,
|
||||||
|
char const * fn);
|
||||||
|
|
||||||
|
#endif // _RK_ENGINE_DISPLAY_GLX_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
|
80
cpp/events.hpp
Normal file
80
cpp/events.hpp
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// 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_H
|
||||||
|
#define _RK_ENGINE_EVENTS_H
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "display.hpp"
|
||||||
|
|
||||||
|
typedef rk_handle_t rk_events_t;
|
||||||
|
|
||||||
|
enum rk_event_type : rk_uint {
|
||||||
|
RK_EVENT_FOCUS_IN = 0,
|
||||||
|
RK_EVENT_FOCUS_OUT = 1,
|
||||||
|
RK_EVENT_KEY_PRESS = 2,
|
||||||
|
RK_EVENT_KEY_RELEASE = 3,
|
||||||
|
RK_EVENT_BUTTON_PRESS = 4,
|
||||||
|
RK_EVENT_BUTTON_RELEASE = 5,
|
||||||
|
RK_EVENT_MOTION = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_event_key {
|
||||||
|
rk_uint code;
|
||||||
|
rk_uint symbol;
|
||||||
|
rk_wchar character;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_event_button {
|
||||||
|
rk_uint index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_event_motion {
|
||||||
|
rk_int x;
|
||||||
|
rk_int y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_event {
|
||||||
|
rk_event_type type;
|
||||||
|
union {
|
||||||
|
rk_event_key key;
|
||||||
|
rk_event_button button;
|
||||||
|
rk_event_motion motion;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
RK_EXPORT rk_events_t rk_create_events(
|
||||||
|
rk_display_t display);
|
||||||
|
|
||||||
|
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_EXPORT void rk_set_motion_acceleration(
|
||||||
|
rk_events_t events,
|
||||||
|
rk_uint numerator,
|
||||||
|
rk_uint denominator,
|
||||||
|
rk_uint threshold);
|
||||||
|
|
||||||
|
RK_EXPORT rk_uint rk_consume_events(
|
||||||
|
rk_events_t events,
|
||||||
|
rk_event * buffer,
|
||||||
|
rk_uint max_events);
|
||||||
|
|
||||||
|
#endif // _RK_ENGINE_EVENTS_H
|
246
cpp/events/events_x11.cpp
Normal file
246
cpp/events/events_x11.cpp
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#include "../events.hpp"
|
||||||
|
#include "events_x11.hpp"
|
||||||
|
#include "../display/display_x11.hpp"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
static void rk_x11_printf(
|
||||||
|
char const * messsage) {
|
||||||
|
printf("[X11] %s\n", messsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_backup(rk_events_x11 & events) {
|
||||||
|
XKeyboardState backup;
|
||||||
|
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 {
|
||||||
|
XAutoRepeatOff(events.display);
|
||||||
|
}
|
||||||
|
XChangePointerControl(
|
||||||
|
events.display, True, True, events.backup_numerator, events.backup_denominator, events.backup_threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_apply(rk_events_x11 & events) {
|
||||||
|
if (events.key_autorepeat) {
|
||||||
|
XAutoRepeatOn(events.display);
|
||||||
|
} else {
|
||||||
|
XAutoRepeatOff(events.display);
|
||||||
|
}
|
||||||
|
XChangePointerControl(
|
||||||
|
events.display, True, True, events.motion_numerator, events.motion_denominator, events.motion_threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_focus_in(rk_events_x11 & events) {
|
||||||
|
if (!events.focused) {
|
||||||
|
rk_backup(events);
|
||||||
|
rk_apply(events);
|
||||||
|
XGrabPointer(events.display, events.window, True,
|
||||||
|
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
|
||||||
|
GrabModeAsync, GrabModeAsync, events.window, None, CurrentTime);
|
||||||
|
events.focused = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_focus_out(rk_events_x11 & events) {
|
||||||
|
if (events.focused) {
|
||||||
|
XUngrabPointer(events.display, CurrentTime);
|
||||||
|
rk_restore(events);
|
||||||
|
events.focused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_events_x11 * const events = reinterpret_cast<rk_events_x11 *>(_events);
|
||||||
|
if (events) {
|
||||||
|
events->key_autorepeat = autorepeat;
|
||||||
|
if (events->focused) {
|
||||||
|
rk_apply(*events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk_set_motion_acceleration(
|
||||||
|
rk_events_t _events,
|
||||||
|
rk_uint numerator,
|
||||||
|
rk_uint denominator,
|
||||||
|
rk_uint threshold) {
|
||||||
|
rk_events_x11 * const events = reinterpret_cast<rk_events_x11 *>(_events);
|
||||||
|
if (events) {
|
||||||
|
events->motion_numerator = numerator;
|
||||||
|
events->motion_denominator = denominator;
|
||||||
|
events->motion_threshold = threshold;
|
||||||
|
if (events->focused) {
|
||||||
|
rk_apply(*events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rk_uint rk_consume_events(
|
||||||
|
rk_events_t _events,
|
||||||
|
rk_event * buffer,
|
||||||
|
rk_uint max_events) {
|
||||||
|
static wchar_t string[256];
|
||||||
|
rk_events_x11 * const events = reinterpret_cast<rk_events_x11 *>(_events);
|
||||||
|
if (!events || !buffer || !max_events) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
XEvent x11_event;
|
||||||
|
KeySym keysym;
|
||||||
|
Status status;
|
||||||
|
unsigned nevents = 0;
|
||||||
|
while (nevents < max_events && XCheckWindowEvent(events->display, events->window, RK_EVENTS_MASK, &x11_event)) {
|
||||||
|
if (XFilterEvent(&x11_event, 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rk_event & event = buffer[nevents];
|
||||||
|
switch (x11_event.type) {
|
||||||
|
|
||||||
|
case FocusIn:
|
||||||
|
if (NotifyNormal == x11_event.xfocus.mode) {
|
||||||
|
rk_focus_in(*events);
|
||||||
|
event.type = RK_EVENT_FOCUS_IN;
|
||||||
|
++nevents;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FocusOut:
|
||||||
|
if (NotifyNormal == x11_event.xfocus.mode) {
|
||||||
|
rk_focus_out(*events);
|
||||||
|
event.type = RK_EVENT_FOCUS_OUT;
|
||||||
|
++nevents;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KeyPress:
|
||||||
|
event.type = RK_EVENT_KEY_PRESS;
|
||||||
|
event.key.code = x11_event.xkey.keycode;
|
||||||
|
XwcLookupString(events->input_context, &x11_event.xkey, string, 256, &keysym, &status);
|
||||||
|
switch (status) {
|
||||||
|
case XLookupChars:
|
||||||
|
event.key.symbol = XLookupKeysym(&x11_event.xkey, 0);
|
||||||
|
event.key.character = string[0];
|
||||||
|
break;
|
||||||
|
case XLookupKeySym:
|
||||||
|
event.key.symbol = keysym;
|
||||||
|
event.key.character = 0;
|
||||||
|
break;
|
||||||
|
case XLookupBoth:
|
||||||
|
event.key.symbol = keysym;
|
||||||
|
event.key.character = string[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
event.key.symbol = 0;
|
||||||
|
event.key.character = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++nevents;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KeyRelease:
|
||||||
|
event.type = RK_EVENT_KEY_RELEASE;
|
||||||
|
event.key.code = x11_event.xkey.keycode;
|
||||||
|
event.key.symbol = XLookupKeysym(&x11_event.xkey, 0);
|
||||||
|
event.key.character = 0;
|
||||||
|
++nevents;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ButtonPress:
|
||||||
|
event.type = RK_EVENT_BUTTON_PRESS;
|
||||||
|
event.button.index = x11_event.xbutton.button;
|
||||||
|
++nevents;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ButtonRelease:
|
||||||
|
event.type = RK_EVENT_BUTTON_RELEASE;
|
||||||
|
event.button.index = x11_event.xbutton.button;
|
||||||
|
++nevents;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MotionNotify:
|
||||||
|
event.type = RK_EVENT_MOTION;
|
||||||
|
event.motion.x = x11_event.xbutton.x;
|
||||||
|
event.motion.y = x11_event.xbutton.y;
|
||||||
|
++nevents;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nevents;
|
||||||
|
}
|
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
|
41
cpp/math.cpp
41
cpp/math.cpp
@ -15,10 +15,25 @@
|
|||||||
|
|
||||||
#include "math.hpp"
|
#include "math.hpp"
|
||||||
|
|
||||||
|
void rk_vec3_rotate(
|
||||||
|
rk_vec3 & ret,
|
||||||
|
rk_vec3 const & vec3,
|
||||||
|
rk_vec3 const & axis,
|
||||||
|
rk_float const angle) {
|
||||||
|
ret = glm::angleAxis(angle, axis) * vec3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk_vec3_mul_vec3(
|
||||||
|
rk_vec3 & ret,
|
||||||
|
rk_vec3 const & a,
|
||||||
|
rk_vec3 const & b) {
|
||||||
|
ret = a * b;
|
||||||
|
}
|
||||||
|
|
||||||
void rk_mat3_rotation(
|
void rk_mat3_rotation(
|
||||||
rk_mat3 & ret,
|
rk_mat3 & ret,
|
||||||
rk_vec3 const & axis,
|
rk_vec3 const & axis,
|
||||||
float const angle) {
|
rk_float const angle) {
|
||||||
ret = glm::mat3_cast(glm::angleAxis(angle, axis));
|
ret = glm::mat3_cast(glm::angleAxis(angle, axis));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,10 +53,10 @@ void rk_mat3_mul_mat3(
|
|||||||
|
|
||||||
void rk_mat4_projection(
|
void rk_mat4_projection(
|
||||||
rk_mat4 & ret,
|
rk_mat4 & ret,
|
||||||
float hfov,
|
rk_float hfov,
|
||||||
float ratio,
|
rk_float ratio,
|
||||||
float near,
|
rk_float near,
|
||||||
float far) {
|
rk_float far) {
|
||||||
ret = glm::perspectiveRH(hfov, ratio, near, far);
|
ret = glm::perspectiveRH(hfov, ratio, near, far);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,14 +64,26 @@ void rk_mat4_lookat(
|
|||||||
rk_mat4 & ret,
|
rk_mat4 & ret,
|
||||||
rk_vec3 const & position,
|
rk_vec3 const & position,
|
||||||
rk_vec3 const & lookat) {
|
rk_vec3 const & lookat) {
|
||||||
ret = glm::lookAtRH(position, lookat, glm::vec3(0.0f, 0.0f, 1.0f));
|
ret = glm::lookAtRH(position, lookat, vec3_up);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk_mat4_orbit(
|
||||||
|
rk_mat4 & ret,
|
||||||
|
rk_vec3 const & origin,
|
||||||
|
rk_float const yaw,
|
||||||
|
rk_float const pitch,
|
||||||
|
rk_float const distance) {
|
||||||
|
ret = glm::translate(
|
||||||
|
glm::lookAtRH(glm::vec3(0.f, -distance, 0.f), vec3_origin, vec3_up) *
|
||||||
|
glm::mat4(glm::angleAxis(pitch, vec3_right) * glm::angleAxis(yaw, vec3_up)),
|
||||||
|
origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rk_mat4_mul_vec3(
|
void rk_mat4_mul_vec3(
|
||||||
rk_vec3 & ret,
|
rk_vec3 & ret,
|
||||||
rk_mat4 const & a,
|
rk_mat4 const & a,
|
||||||
rk_vec3 const & b,
|
rk_vec3 const & b,
|
||||||
float const w) {
|
rk_float const w) {
|
||||||
ret = glm::vec3(a * glm::vec4(b, w));
|
ret = glm::vec3(a * glm::vec4(b, w));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
43
cpp/math.hpp
43
cpp/math.hpp
@ -26,10 +26,34 @@ typedef glm::vec4 rk_vec4;
|
|||||||
typedef glm::mat3 rk_mat3;
|
typedef glm::mat3 rk_mat3;
|
||||||
typedef glm::mat4 rk_mat4;
|
typedef glm::mat4 rk_mat4;
|
||||||
|
|
||||||
|
#define RK_CHECK_MATH_TYPE(_t, _e, _c) static_assert(sizeof(_t) == sizeof(_e) * (_c))
|
||||||
|
|
||||||
|
RK_CHECK_MATH_TYPE(rk_vec2, float, 2);
|
||||||
|
RK_CHECK_MATH_TYPE(rk_vec3, float, 3);
|
||||||
|
RK_CHECK_MATH_TYPE(rk_vec4, float, 4);
|
||||||
|
RK_CHECK_MATH_TYPE(rk_mat3, rk_vec3, 3);
|
||||||
|
RK_CHECK_MATH_TYPE(rk_mat4, rk_vec4, 4);
|
||||||
|
|
||||||
|
#define vec3_right (rk_vec3(1.f, 0.f, 0.f))
|
||||||
|
#define vec3_forward (rk_vec3(0.f, 1.f, 0.f))
|
||||||
|
#define vec3_up (rk_vec3(0.f, 0.f, 1.f))
|
||||||
|
#define vec3_origin (rk_vec3(0.f, 0.f, 0.f))
|
||||||
|
|
||||||
|
RK_EXPORT void rk_vec3_rotate(
|
||||||
|
rk_vec3 & ret,
|
||||||
|
rk_vec3 const & vec3,
|
||||||
|
rk_vec3 const & axis,
|
||||||
|
rk_float const angle);
|
||||||
|
|
||||||
|
RK_EXPORT void rk_vec3_mul_vec3(
|
||||||
|
rk_vec3 & ret,
|
||||||
|
rk_vec3 const & a,
|
||||||
|
rk_vec3 const & b);
|
||||||
|
|
||||||
RK_EXPORT void rk_mat3_rotation(
|
RK_EXPORT void rk_mat3_rotation(
|
||||||
rk_mat3 & ret,
|
rk_mat3 & ret,
|
||||||
rk_vec3 const & axis,
|
rk_vec3 const & axis,
|
||||||
float const angle);
|
rk_float const angle);
|
||||||
|
|
||||||
RK_EXPORT void rk_mat3_mul_vec3(
|
RK_EXPORT void rk_mat3_mul_vec3(
|
||||||
rk_vec3 & ret,
|
rk_vec3 & ret,
|
||||||
@ -43,21 +67,28 @@ RK_EXPORT void rk_mat3_mul_mat3(
|
|||||||
|
|
||||||
RK_EXPORT void rk_mat4_projection(
|
RK_EXPORT void rk_mat4_projection(
|
||||||
rk_mat4 & ret,
|
rk_mat4 & ret,
|
||||||
float hfov,
|
rk_float hfov,
|
||||||
float ratio,
|
rk_float ratio,
|
||||||
float near,
|
rk_float near,
|
||||||
float far);
|
rk_float far);
|
||||||
|
|
||||||
RK_EXPORT void rk_mat4_lookat(
|
RK_EXPORT void rk_mat4_lookat(
|
||||||
rk_mat4 & ret,
|
rk_mat4 & ret,
|
||||||
rk_vec3 const & position,
|
rk_vec3 const & position,
|
||||||
rk_vec3 const & lookat);
|
rk_vec3 const & lookat);
|
||||||
|
|
||||||
|
RK_EXPORT void rk_mat4_orbit(
|
||||||
|
rk_mat4 & ret,
|
||||||
|
rk_vec3 const & origin,
|
||||||
|
rk_float const yaw,
|
||||||
|
rk_float const pitch,
|
||||||
|
rk_float const distance);
|
||||||
|
|
||||||
RK_EXPORT void rk_mat4_mul_vec3(
|
RK_EXPORT void rk_mat4_mul_vec3(
|
||||||
rk_vec3 & ret,
|
rk_vec3 & ret,
|
||||||
rk_mat4 const & a,
|
rk_mat4 const & a,
|
||||||
rk_vec3 const & b,
|
rk_vec3 const & b,
|
||||||
float const w);
|
rk_float const w);
|
||||||
|
|
||||||
RK_EXPORT void rk_mat4_mul_vec4(
|
RK_EXPORT void rk_mat4_mul_vec4(
|
||||||
rk_vec4 & ret,
|
rk_vec4 & ret,
|
||||||
|
@ -1,234 +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 <cstdio>
|
|
||||||
#include <cstring>
|
|
||||||
#include <GLES3/gl32.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
|
|
||||||
static Display * rk_display = nullptr;
|
|
||||||
static Colormap rk_colormap = 0;
|
|
||||||
static Window rk_window = 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 *);
|
|
||||||
|
|
||||||
PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC rk_DrawElementsInstancedBaseInstance = nullptr;
|
|
||||||
PFNGLMULTIDRAWELEMENTSINDIRECTPROC 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,
|
|
||||||
rk_uint width,
|
|
||||||
rk_uint height) {
|
|
||||||
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 = StructureNotifyMask;
|
|
||||||
rk_window = XCreateWindow(rk_display, RootWindow(rk_display, vi->screen),
|
|
||||||
0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
|
|
||||||
CWBorderPixel | CWColormap | CWEventMask, &swa);
|
|
||||||
if (!rk_window) {
|
|
||||||
rk_printf("Failed to create window.");
|
|
||||||
rk_destroy_context();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
XFree(vi);
|
|
||||||
XStoreName(rk_display, rk_window, name);
|
|
||||||
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<const GLubyte *>("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<PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC>(
|
|
||||||
glXGetProcAddressARB(reinterpret_cast<const GLubyte *>("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<PFNGLMULTIDRAWELEMENTSINDIRECTPROC>(
|
|
||||||
glXGetProcAddressARB(reinterpret_cast<const GLubyte *>("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;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,737 +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/>.
|
|
||||||
|
|
||||||
#include "render_opengles.hpp"
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
static rk_shader const * rk_current_shader = nullptr;
|
|
||||||
static rk_vertices const * rk_current_vertices = nullptr;
|
|
||||||
|
|
||||||
static void rk_printf(char const * messsage) {
|
|
||||||
printf("[RK_ENGINE] %s\n", messsage);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define rk_error(message) { if (glGetError() != GL_NO_ERROR) { rk_printf(message); } }
|
|
||||||
|
|
||||||
static void rk_debug_message_callback(
|
|
||||||
GLenum source,
|
|
||||||
GLenum type,
|
|
||||||
GLuint id,
|
|
||||||
GLenum severity,
|
|
||||||
GLsizei length,
|
|
||||||
GLchar const * message,
|
|
||||||
void const * userParam) {
|
|
||||||
printf("[RK_ENGINE][GL] (id=%d) %s\n", id, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
rk_window_t rk_initialize(
|
|
||||||
char const * name,
|
|
||||||
rk_uint width,
|
|
||||||
rk_uint height) {
|
|
||||||
rk_window_t const window = rk_create_context(name, width, height);
|
|
||||||
if (window) {
|
|
||||||
GLubyte const * const vendor = glGetString(GL_VENDOR);
|
|
||||||
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);
|
|
||||||
glEnable(GL_DEBUG_OUTPUT);
|
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
glEnable(GL_DITHER);
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
|
||||||
glDisable(GL_STENCIL_TEST);
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glFrontFace(GL_CCW);
|
|
||||||
glCullFace(GL_BACK);
|
|
||||||
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
|
|
||||||
}
|
|
||||||
return window;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk_print_shader_infolog(GLuint shader) {
|
|
||||||
int length;
|
|
||||||
char infolog[1024];
|
|
||||||
glGetShaderInfoLog(shader, sizeof(infolog), &length, infolog);
|
|
||||||
if (length > 0) {
|
|
||||||
rk_printf(infolog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk_print_program_infolog(GLuint program) {
|
|
||||||
int length;
|
|
||||||
char infolog[1024];
|
|
||||||
glGetProgramInfoLog(program, sizeof(infolog), &length, infolog);
|
|
||||||
if (length > 0) {
|
|
||||||
rk_printf(infolog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: error handling
|
|
||||||
rk_shader_t rk_load_shader(
|
|
||||||
rk_uint const vert_nlines,
|
|
||||||
char const ** const vert_lines,
|
|
||||||
rk_uint const frag_nlines,
|
|
||||||
char const ** const frag_lines) {
|
|
||||||
rk_shader * const shader = new rk_shader;
|
|
||||||
shader->vertex = glCreateShader(GL_VERTEX_SHADER);
|
|
||||||
shader->fragment = glCreateShader(GL_FRAGMENT_SHADER);
|
|
||||||
shader->program = glCreateProgram();
|
|
||||||
if (!vert_nlines || !vert_lines) {
|
|
||||||
rk_printf("Missing vertex shader.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!frag_nlines || !frag_lines) {
|
|
||||||
rk_printf("Missing fragment shader.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
rk_printf("Compiling vertex shader...");
|
|
||||||
glShaderSource(shader->vertex, vert_nlines, vert_lines, nullptr);
|
|
||||||
glCompileShader(shader->vertex);
|
|
||||||
rk_error("glCompileShader() failed.");
|
|
||||||
rk_print_shader_infolog(shader->vertex);
|
|
||||||
rk_printf("Compiling fragment shader...");
|
|
||||||
glShaderSource(shader->fragment, frag_nlines, frag_lines, nullptr);
|
|
||||||
glCompileShader(shader->fragment);
|
|
||||||
rk_error("glCompileShader() failed.");
|
|
||||||
rk_print_shader_infolog(shader->fragment);
|
|
||||||
rk_printf("Linking program...");
|
|
||||||
glAttachShader(shader->program, shader->vertex);
|
|
||||||
glAttachShader(shader->program, shader->fragment);
|
|
||||||
glLinkProgram(shader->program);
|
|
||||||
rk_error("glLinkProgram() failed.");
|
|
||||||
rk_print_program_infolog(shader->program);
|
|
||||||
rk_printf("Done.");
|
|
||||||
glReleaseShaderCompiler();
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
rk_input_t rk_resolve_input(
|
|
||||||
rk_shader_t _shader,
|
|
||||||
char const * name) {
|
|
||||||
rk_shader const * const shader = reinterpret_cast<rk_shader const *>(_shader);
|
|
||||||
if (!shader || !name) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
GLint const uniform = glGetUniformLocation(shader->program, name);
|
|
||||||
return reinterpret_cast<rk_input_t>(uniform + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
rk_param_t rk_resolve_param(
|
|
||||||
rk_shader_t _shader,
|
|
||||||
char const * name) {
|
|
||||||
rk_shader const * const shader = reinterpret_cast<rk_shader const *>(_shader);
|
|
||||||
if (!shader || !name) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
GLint const location = glGetAttribLocation(shader->program, name);
|
|
||||||
return reinterpret_cast<rk_param_t>(location + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
rk_texture_t rk_create_texture(
|
|
||||||
rk_uint slot,
|
|
||||||
rk_texture_format format,
|
|
||||||
rk_uint width,
|
|
||||||
rk_uint height,
|
|
||||||
rk_uint nlevels,
|
|
||||||
rk_texture_flags flags,
|
|
||||||
void const * pixels) {
|
|
||||||
if (!width || !height || !pixels) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
GLint internal_format;
|
|
||||||
GLenum source_format;
|
|
||||||
GLenum source_type;
|
|
||||||
switch (format) {
|
|
||||||
case RK_TEXTURE_FORMAT_SRGB8_A8:
|
|
||||||
internal_format = GL_SRGB8_ALPHA8;
|
|
||||||
source_format = GL_RGBA;
|
|
||||||
source_type = GL_UNSIGNED_BYTE;
|
|
||||||
break;
|
|
||||||
case RK_TEXTURE_FORMAT_RGBA8:
|
|
||||||
internal_format = GL_RGBA8;
|
|
||||||
source_format = GL_RGBA;
|
|
||||||
source_type = GL_UNSIGNED_BYTE;
|
|
||||||
break;
|
|
||||||
case RK_TEXTURE_FORMAT_RGB10_A2:
|
|
||||||
internal_format = GL_RGB10_A2;
|
|
||||||
source_format = GL_RGBA;
|
|
||||||
source_type = GL_UNSIGNED_INT_2_10_10_10_REV;
|
|
||||||
break;
|
|
||||||
case RK_TEXTURE_FORMAT_32F:
|
|
||||||
internal_format = GL_R32F;
|
|
||||||
source_format = GL_RED;
|
|
||||||
source_type = GL_FLOAT;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rk_texture * const texture = new rk_texture;
|
|
||||||
glActiveTexture(GL_TEXTURE0 + slot);
|
|
||||||
glGenTextures(1, &texture->texture);
|
|
||||||
GLenum target;
|
|
||||||
if (nlevels) {
|
|
||||||
if (flags & RK_TEXTURE_FLAG_3D) {
|
|
||||||
target = GL_TEXTURE_3D;
|
|
||||||
} else {
|
|
||||||
target = GL_TEXTURE_2D_ARRAY;
|
|
||||||
}
|
|
||||||
glBindTexture(target, texture->texture);
|
|
||||||
//TODO: glTexStorage3D
|
|
||||||
glTexImage3D(target, 0, internal_format, width, height, nlevels, 0, source_format, source_type, pixels);
|
|
||||||
} else {
|
|
||||||
target = GL_TEXTURE_2D;
|
|
||||||
glBindTexture(target, texture->texture);
|
|
||||||
//TODO: glTexStorage2D
|
|
||||||
glTexImage2D(target, 0, internal_format, width, height, 0, source_format, source_type, pixels);
|
|
||||||
}
|
|
||||||
if (flags & RK_TEXTURE_FLAG_MIPMAPS) {
|
|
||||||
if (flags & RK_TEXTURE_FLAG_MIN_LINEAR) {
|
|
||||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
||||||
} else {
|
|
||||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (flags & RK_TEXTURE_FLAG_MIN_LINEAR) {
|
|
||||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
} else {
|
|
||||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flags & RK_TEXTURE_FLAG_MAG_LINEAR) {
|
|
||||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
} else {
|
|
||||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
}
|
|
||||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
||||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
||||||
glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
|
|
||||||
if (flags & RK_TEXTURE_FLAG_MIPMAPS) {
|
|
||||||
glGenerateMipmap(target);
|
|
||||||
}
|
|
||||||
texture->slot = slot;
|
|
||||||
texture->nlevels = nlevels;
|
|
||||||
glBindTexture(target, 0);
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
rk_triangles_t rk_create_triangles(
|
|
||||||
rk_uint nvertices,
|
|
||||||
rk_vec3 const * vertices) {
|
|
||||||
if (!nvertices || !vertices) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
rk_triangles * const triangles = new rk_triangles;
|
|
||||||
triangles->size = nvertices;
|
|
||||||
glGenVertexArrays(1, &triangles->array);
|
|
||||||
glBindVertexArray(triangles->array);
|
|
||||||
glGenBuffers(1, &triangles->vertices);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, triangles->vertices);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, nvertices * sizeof(rk_vec3), vertices, GL_STATIC_DRAW);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
return triangles;
|
|
||||||
}
|
|
||||||
|
|
||||||
rk_vertices_t rk_create_vertices(
|
|
||||||
rk_vertex_format const * format,
|
|
||||||
rk_uint nvertices,
|
|
||||||
void const * _vertices,
|
|
||||||
rk_uint nindices,
|
|
||||||
rk_ushort const * indices) {
|
|
||||||
if (!format || !nvertices || !_vertices || !nindices || !indices) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
rk_uint vertex_size = 0;
|
|
||||||
for (rk_vertex_format const * f = format; *f; ++f) {
|
|
||||||
switch (*f & RK_VERTEX_FORMAT_MASK) {
|
|
||||||
case RK_VERTEX_FORMAT_VEC3_FLOAT:
|
|
||||||
vertex_size += sizeof(rk_vec3);
|
|
||||||
break;
|
|
||||||
case RK_VERTEX_FORMAT_VEC3_INT10:
|
|
||||||
vertex_size += sizeof(rk_int);
|
|
||||||
break;
|
|
||||||
case RK_VERTEX_FORMAT_VEC3_UINT10:
|
|
||||||
vertex_size += sizeof(rk_uint);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rk_printf("rk_create_vertices(): invalid format.");
|
|
||||||
return nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!vertex_size) {
|
|
||||||
rk_printf("rk_create_vertices(): empty format.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
rk_vertices * const vertices = new rk_vertices;
|
|
||||||
glGenVertexArrays(1, &vertices->array);
|
|
||||||
glBindVertexArray(vertices->array);
|
|
||||||
glGenBuffers(1, &vertices->vertices);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vertices->vertices);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, nvertices * vertex_size, _vertices, GL_STATIC_DRAW);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
vertices->vertex_size = vertex_size;
|
|
||||||
vertices->layout = 0;
|
|
||||||
rk_uint offset = 0;
|
|
||||||
for (rk_vertex_format const * f = format; *f; ++f, ++vertices->layout) {
|
|
||||||
glEnableVertexAttribArray(vertices->layout);
|
|
||||||
GLboolean const normalize = (*f & RK_VERTEX_FORMAT_NORMALIZE) != 0;
|
|
||||||
switch (*f & RK_VERTEX_FORMAT_MASK) {
|
|
||||||
case RK_VERTEX_FORMAT_VEC3_FLOAT:
|
|
||||||
glVertexAttribFormat(vertices->layout, 3, GL_FLOAT, normalize, offset);
|
|
||||||
offset += sizeof(rk_vec3);
|
|
||||||
break;
|
|
||||||
case RK_VERTEX_FORMAT_VEC3_INT10:
|
|
||||||
glVertexAttribFormat(vertices->layout, 4, GL_INT_2_10_10_10_REV, normalize, offset);
|
|
||||||
offset += sizeof(rk_int);
|
|
||||||
break;
|
|
||||||
case RK_VERTEX_FORMAT_VEC3_UINT10:
|
|
||||||
glVertexAttribFormat(vertices->layout, 4, GL_UNSIGNED_INT_2_10_10_10_REV, normalize, offset);
|
|
||||||
offset += sizeof(rk_uint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
glVertexAttribBinding(vertices->layout, RK_VERTICES_BINDING);
|
|
||||||
}
|
|
||||||
glBindVertexBuffer(RK_VERTICES_BINDING, vertices->vertices, 0, vertices->vertex_size);
|
|
||||||
glGenBuffers(1, &vertices->indices);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertices->indices);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, nindices * sizeof(rk_ushort), indices, GL_STATIC_DRAW);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
return vertices;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk_pack_vec3_float(
|
|
||||||
rk_vec3 * const __restrict dst,
|
|
||||||
rk_vec3 const * const __restrict src) {
|
|
||||||
*dst = *src;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk_pack_vec3_short(
|
|
||||||
rk_vec3_short * const __restrict dst,
|
|
||||||
rk_vec3 const * const __restrict src) {
|
|
||||||
dst->x = static_cast<rk_short>(src->x);
|
|
||||||
dst->y = static_cast<rk_short>(src->y);
|
|
||||||
dst->z = static_cast<rk_short>(src->z);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk_pack_vec3_short_norm(
|
|
||||||
rk_vec3_short * const __restrict dst,
|
|
||||||
rk_vec3 const * const __restrict src) {
|
|
||||||
#define _convert(s) (static_cast<rk_short>((s) * ((s) < 0.f ? 32768.f : 32767.f)))
|
|
||||||
dst->x = _convert(src->x);
|
|
||||||
dst->y = _convert(src->y);
|
|
||||||
dst->z = _convert(src->z);
|
|
||||||
#undef _convert
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk_pack_vec3_int10(
|
|
||||||
rk_int * const __restrict dst,
|
|
||||||
rk_vec3 const * const __restrict src) {
|
|
||||||
#define _convert(s) (static_cast<rk_int>((s) * ((s) < 0.f ? 512.f : 511.f)) & 1023)
|
|
||||||
*dst = _convert(src->x) | (_convert(src->y) << 10) | (_convert(src->z) << 20);
|
|
||||||
#undef _convert
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: multiple batches per vertices
|
|
||||||
rk_batch_t rk_create_batch(
|
|
||||||
rk_vertices_t _vertices,
|
|
||||||
rk_uint max_size,
|
|
||||||
rk_param_format const * params_format) {
|
|
||||||
rk_vertices const * const vertices = reinterpret_cast<rk_vertices const *>(_vertices);
|
|
||||||
if (!vertices || !max_size || !params_format || max_size > RK_BATCH_MAX_SIZE) {
|
|
||||||
rk_printf("rk_create_batch(): invalid parameters.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
rk_uint nparams = 0;
|
|
||||||
rk_uint params_size = 0;
|
|
||||||
rk_uint packed_size = 0;
|
|
||||||
for (rk_param_format const * f = params_format; *f; ++f, ++nparams) {
|
|
||||||
switch (*f & RK_PARAM_FORMAT_MASK) {
|
|
||||||
case RK_PARAM_FORMAT_VEC3_FLOAT:
|
|
||||||
params_size += sizeof(rk_vec3);
|
|
||||||
packed_size += sizeof(rk_vec3);
|
|
||||||
break;
|
|
||||||
case RK_PARAM_FORMAT_VEC3_SHORT:
|
|
||||||
params_size += sizeof(rk_vec3);
|
|
||||||
packed_size += sizeof(rk_vec3_short);
|
|
||||||
break;
|
|
||||||
case RK_PARAM_FORMAT_VEC3_INT10:
|
|
||||||
params_size += sizeof(rk_vec3);
|
|
||||||
packed_size += sizeof(rk_int);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rk_printf("rk_create_batch(): invalid param format.");
|
|
||||||
return nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rk_batch * batch = new rk_batch;
|
|
||||||
batch->size = max_size;
|
|
||||||
batch->nparams = nparams;
|
|
||||||
batch->params_size = params_size;
|
|
||||||
batch->packed_size = packed_size;
|
|
||||||
batch->indices = new rk_ushort[max_size];
|
|
||||||
batch->commands = new rk_command[max_size * sizeof(rk_command)];
|
|
||||||
if (nparams) {
|
|
||||||
batch->packers = new rk_packer[nparams];
|
|
||||||
batch->params = new rk_ubyte[max_size * packed_size];
|
|
||||||
glGenBuffers(1, &batch->params_buffer);
|
|
||||||
rk_uint layout = vertices->layout;
|
|
||||||
rk_packer * packer = batch->packers;
|
|
||||||
rk_uint offset = 0;
|
|
||||||
glBindVertexArray(vertices->array);
|
|
||||||
for (rk_param_format const * f = params_format; *f; ++f, ++layout, ++packer) {
|
|
||||||
GLboolean const normalize = (*f & RK_PARAM_FORMAT_NORMALIZE) != 0;
|
|
||||||
glEnableVertexAttribArray(layout);
|
|
||||||
switch (*f & RK_PARAM_FORMAT_MASK) {
|
|
||||||
case RK_PARAM_FORMAT_VEC3_FLOAT:
|
|
||||||
glVertexAttribFormat(layout, 3, GL_FLOAT, normalize, offset);
|
|
||||||
packer->pack = reinterpret_cast<rk_packer_fn>(rk_pack_vec3_float);
|
|
||||||
packer->dst_incr = sizeof(rk_vec3);
|
|
||||||
packer->src_incr = sizeof(rk_vec3);
|
|
||||||
break;
|
|
||||||
case RK_PARAM_FORMAT_VEC3_SHORT:
|
|
||||||
glVertexAttribFormat(layout, 3, GL_SHORT, normalize, offset);
|
|
||||||
if (normalize) {
|
|
||||||
packer->pack = reinterpret_cast<rk_packer_fn>(rk_pack_vec3_short_norm);
|
|
||||||
} else {
|
|
||||||
packer->pack = reinterpret_cast<rk_packer_fn>(rk_pack_vec3_short);
|
|
||||||
}
|
|
||||||
packer->dst_incr = sizeof(rk_vec3_short);
|
|
||||||
packer->src_incr = sizeof(rk_vec3);
|
|
||||||
break;
|
|
||||||
case RK_PARAM_FORMAT_VEC3_INT10:
|
|
||||||
glVertexAttribFormat(layout, 4, GL_INT_2_10_10_10_REV, normalize, offset);
|
|
||||||
packer->pack = reinterpret_cast<rk_packer_fn>(rk_pack_vec3_int10);
|
|
||||||
packer->dst_incr = sizeof(rk_int);
|
|
||||||
packer->src_incr = sizeof(rk_vec3);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
offset += packer->dst_incr;
|
|
||||||
glVertexAttribBinding(layout, RK_PARAMS_BINDING);
|
|
||||||
}
|
|
||||||
glVertexBindingDivisor(RK_PARAMS_BINDING, 1);
|
|
||||||
glBindVertexBuffer(RK_PARAMS_BINDING, batch->params_buffer, 0, batch->packed_size);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
}
|
|
||||||
if (rk_MultiDrawElementsIndirect) {
|
|
||||||
glGenBuffers(1, &batch->commands_buffer);
|
|
||||||
}
|
|
||||||
return batch;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_begin_frame() {
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_select_shader(
|
|
||||||
rk_shader_t _shader) {
|
|
||||||
rk_shader * const shader = reinterpret_cast<rk_shader *>(_shader);
|
|
||||||
if (shader) {
|
|
||||||
rk_current_shader = shader;
|
|
||||||
glUseProgram(shader->program);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_set_input_float(
|
|
||||||
rk_input_t _input,
|
|
||||||
float value) {
|
|
||||||
GLint const input = reinterpret_cast<intptr_t>(_input) - 1;
|
|
||||||
if (rk_current_shader && input > -1) {
|
|
||||||
glUniform1f(input, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_set_input_vec3(
|
|
||||||
rk_input_t _input,
|
|
||||||
rk_vec3 const & value) {
|
|
||||||
GLint const input = reinterpret_cast<intptr_t>(_input) - 1;
|
|
||||||
if (rk_current_shader && input > -1) {
|
|
||||||
glUniform3fv(input, 1, glm::value_ptr(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_set_input_mat3(
|
|
||||||
rk_input_t _input,
|
|
||||||
rk_mat3 const & value) {
|
|
||||||
GLint const input = reinterpret_cast<intptr_t>(_input) - 1;
|
|
||||||
if (rk_current_shader && input > -1) {
|
|
||||||
glUniformMatrix3fv(input, 1, GL_FALSE, glm::value_ptr(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_set_input_mat4(
|
|
||||||
rk_input_t _input,
|
|
||||||
rk_mat4 const & value) {
|
|
||||||
GLint const input = reinterpret_cast<intptr_t>(_input) - 1;
|
|
||||||
if (rk_current_shader && input > -1) {
|
|
||||||
glUniformMatrix4fv(input, 1, GL_FALSE, glm::value_ptr(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_set_param_vec3(
|
|
||||||
rk_param_t _param,
|
|
||||||
rk_vec3 const & value) {
|
|
||||||
GLint const param = reinterpret_cast<intptr_t>(_param) - 1;
|
|
||||||
if (rk_current_shader && param > -1) {
|
|
||||||
glVertexAttrib3fv(param, glm::value_ptr(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_select_texture(
|
|
||||||
rk_texture_t _texture,
|
|
||||||
rk_input_t _sampler) {
|
|
||||||
rk_texture const * const texture = reinterpret_cast<rk_texture const *>(_texture);
|
|
||||||
GLint const sampler = reinterpret_cast<intptr_t>(_sampler) - 1;
|
|
||||||
if (texture && sampler > -1 && rk_current_shader) {
|
|
||||||
glActiveTexture(GL_TEXTURE0 + texture->slot);
|
|
||||||
if (texture->nlevels) {
|
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture->texture);
|
|
||||||
} else {
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->texture);
|
|
||||||
}
|
|
||||||
glUniform1i(sampler, texture->slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RK_EXPORT void rk_draw_triangles(
|
|
||||||
rk_triangles_t _triangles) {
|
|
||||||
rk_triangles const * const triangles = reinterpret_cast<rk_triangles const *>(_triangles);
|
|
||||||
if (triangles && rk_current_shader && !rk_current_vertices) {
|
|
||||||
glBindVertexArray(triangles->array);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, triangles->size);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_select_vertices(
|
|
||||||
rk_vertices_t _vertices) {
|
|
||||||
rk_vertices * const vertices = reinterpret_cast<rk_vertices *>(_vertices);
|
|
||||||
if (vertices) {
|
|
||||||
glBindVertexArray(vertices->array);
|
|
||||||
rk_current_vertices = vertices;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static rk_uint rk_batch_filter(
|
|
||||||
rk_batch & batch,
|
|
||||||
rk_uint const size,
|
|
||||||
rk_instance_flags const * flags) {
|
|
||||||
rk_ushort * indices = batch.indices;
|
|
||||||
for (rk_ushort index = 0; index < size; ++index, ++flags) {
|
|
||||||
if ((*flags & RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) == RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) {
|
|
||||||
*indices++ = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return indices - batch.indices;
|
|
||||||
}
|
|
||||||
|
|
||||||
static rk_uint rk_batch_build_commands(
|
|
||||||
rk_batch & batch,
|
|
||||||
rk_uint const ninstances,
|
|
||||||
rk_mesh const * const meshes) {
|
|
||||||
rk_command * commands = batch.commands;
|
|
||||||
rk_ushort * base = batch.indices;
|
|
||||||
rk_ushort * const last = batch.indices + ninstances;
|
|
||||||
for (rk_ushort * first = batch.indices; first < last; base = first, ++commands) {
|
|
||||||
rk_mesh const & mesh = meshes[*first++];
|
|
||||||
for ( ; first < last && meshes[*first].packed == mesh.packed; ++first) {
|
|
||||||
}
|
|
||||||
for (rk_ushort * second = first; second < last; ++second) {
|
|
||||||
rk_ushort const index = *second;
|
|
||||||
if (meshes[index].packed == mesh.packed) {
|
|
||||||
*second = *first;
|
|
||||||
*first++ = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
commands->nvertices = static_cast<GLuint>(mesh.ntriangles) * 3;
|
|
||||||
commands->ninstances = first - base;
|
|
||||||
commands->base_index = mesh.base_index;
|
|
||||||
commands->base_vertex = 0;
|
|
||||||
commands->base_instance = base - batch.indices;
|
|
||||||
}
|
|
||||||
return commands - batch.commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk_batch_convert_params(
|
|
||||||
rk_batch & batch,
|
|
||||||
rk_uint const ninstances,
|
|
||||||
rk_ubyte const * const params) {
|
|
||||||
rk_ubyte * __restrict dst = batch.params;
|
|
||||||
rk_ushort const * const last_index = batch.indices + ninstances;
|
|
||||||
rk_packer const * const last_packer = batch.packers + batch.nparams;
|
|
||||||
for (rk_ushort const * index = batch.indices; index < last_index; ++index) {
|
|
||||||
rk_ubyte const * __restrict src = ¶ms[batch.params_size * (*index)];
|
|
||||||
for (rk_packer const * packer = batch.packers; packer < last_packer; ++packer) {
|
|
||||||
packer->pack(dst, src);
|
|
||||||
dst += packer->dst_incr;
|
|
||||||
src += packer->src_incr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_draw_batch(
|
|
||||||
rk_batch_t _batch,
|
|
||||||
rk_uint size,
|
|
||||||
rk_instance_flags const * flags,
|
|
||||||
rk_mesh const * meshes,
|
|
||||||
rk_ubyte const * params) {
|
|
||||||
rk_batch & batch = *reinterpret_cast<rk_batch *>(_batch);
|
|
||||||
if (!size || size > batch.size || !flags || !meshes || !rk_current_shader || !rk_current_vertices) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rk_uint const ninstances = rk_batch_filter(batch, size, flags);
|
|
||||||
if (!ninstances) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rk_uint const ncommands = rk_batch_build_commands(batch, ninstances, meshes);
|
|
||||||
if (rk_MultiDrawElementsIndirect) {
|
|
||||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, batch.commands_buffer);
|
|
||||||
glBufferData(GL_DRAW_INDIRECT_BUFFER, ncommands * sizeof(rk_command), batch.commands, GL_STREAM_DRAW);
|
|
||||||
}
|
|
||||||
if (batch.nparams) {
|
|
||||||
rk_batch_convert_params(batch, ninstances, params);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, batch.params_buffer);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, ninstances * batch.packed_size, batch.params, GL_STREAM_DRAW);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
}
|
|
||||||
if (rk_DrawElementsInstancedBaseInstance) {
|
|
||||||
if (rk_MultiDrawElementsIndirect) {
|
|
||||||
rk_MultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, ncommands, sizeof(rk_command));
|
|
||||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
|
|
||||||
} else {
|
|
||||||
rk_command const * const last_command = batch.commands + ncommands;
|
|
||||||
for (rk_command const * command = batch.commands; command < last_command; ++command) {
|
|
||||||
rk_DrawElementsInstancedBaseInstance(
|
|
||||||
GL_TRIANGLES, command->nvertices, GL_UNSIGNED_SHORT,
|
|
||||||
reinterpret_cast<void const *>(command->base_index << 1),
|
|
||||||
command->ninstances, command->base_instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rk_uint params_offset = 0;
|
|
||||||
rk_command const * const last_command = batch.commands + ncommands;
|
|
||||||
for (rk_command const * command = batch.commands; command < last_command; ++command) {
|
|
||||||
if (batch.nparams) {
|
|
||||||
glBindVertexBuffer(RK_PARAMS_BINDING, batch.params_buffer, params_offset, batch.packed_size);
|
|
||||||
params_offset += command->ninstances * batch.packed_size;
|
|
||||||
}
|
|
||||||
glDrawElementsInstanced(
|
|
||||||
GL_TRIANGLES, command->nvertices, GL_UNSIGNED_SHORT,
|
|
||||||
reinterpret_cast<void const *>(command->base_index << 1),
|
|
||||||
command->ninstances);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_unselect_vertices(
|
|
||||||
rk_vertices_t _vertices) {
|
|
||||||
rk_current_vertices = nullptr;
|
|
||||||
glBindVertexArray(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_unselect_texture(
|
|
||||||
rk_texture_t _texture) {
|
|
||||||
rk_texture const * const texture = reinterpret_cast<rk_texture const *>(_texture);
|
|
||||||
if (texture) {
|
|
||||||
glActiveTexture(GL_TEXTURE0 + texture->slot);
|
|
||||||
if (texture->nlevels) {
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
} else {
|
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_unselect_shader(
|
|
||||||
rk_shader_t _shader) {
|
|
||||||
rk_current_shader = nullptr;
|
|
||||||
glUseProgram(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_end_frame() {
|
|
||||||
rk_swap_buffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_destroy_batch(
|
|
||||||
rk_batch_t _batch) {
|
|
||||||
rk_batch * const batch = reinterpret_cast<rk_batch *>(_batch);
|
|
||||||
if (batch) {
|
|
||||||
delete[] batch->indices;
|
|
||||||
delete[] batch->commands;
|
|
||||||
if (batch->nparams) {
|
|
||||||
delete[] batch->packers;
|
|
||||||
delete[] batch->params;
|
|
||||||
glDeleteBuffers(1, &batch->params_buffer);
|
|
||||||
}
|
|
||||||
if (rk_MultiDrawElementsIndirect) {
|
|
||||||
glDeleteBuffers(1, &batch->commands_buffer);
|
|
||||||
}
|
|
||||||
delete batch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_destroy_triangles(
|
|
||||||
rk_triangles_t _triangles) {
|
|
||||||
rk_triangles * const triangles = reinterpret_cast<rk_triangles *>(_triangles);
|
|
||||||
if (triangles) {
|
|
||||||
glDeleteBuffers(1, &triangles->vertices);
|
|
||||||
glDeleteVertexArrays(1, &triangles->array);
|
|
||||||
delete triangles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_destroy_vertices(
|
|
||||||
rk_vertices_t _vertices) {
|
|
||||||
rk_vertices * const vertices = reinterpret_cast<rk_vertices *>(_vertices);
|
|
||||||
if (vertices) {
|
|
||||||
glDeleteBuffers(1, &vertices->indices);
|
|
||||||
glDeleteBuffers(1, &vertices->vertices);
|
|
||||||
glDeleteVertexArrays(1, &vertices->array);
|
|
||||||
delete vertices;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_destroy_texture(
|
|
||||||
rk_texture_t _texture) {
|
|
||||||
rk_texture * const texture = reinterpret_cast<rk_texture *>(_texture);
|
|
||||||
if (texture) {
|
|
||||||
glDeleteTextures(1, &texture->texture);
|
|
||||||
delete texture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_destroy_shader(
|
|
||||||
rk_shader_t _shader) {
|
|
||||||
rk_shader * const shader = reinterpret_cast<rk_shader *>(_shader);
|
|
||||||
if (shader) {
|
|
||||||
glDeleteShader(shader->vertex);
|
|
||||||
glDeleteShader(shader->fragment);
|
|
||||||
glDeleteProgram(shader->program);
|
|
||||||
delete shader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rk_terminate() {
|
|
||||||
rk_destroy_context();
|
|
||||||
}
|
|
130
cpp/render.hpp
130
cpp/render.hpp
@ -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,16 +27,18 @@ 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))
|
typedef rk_uint rk_texture_format;
|
||||||
|
|
||||||
enum rk_texture_format : rk_uint {
|
enum : rk_texture_format {
|
||||||
RK_TEXTURE_FORMAT_SRGB8_A8 = 0,
|
RK_TEXTURE_FORMAT_SRGB8_A8 = 0,
|
||||||
RK_TEXTURE_FORMAT_RGBA8 = 1,
|
RK_TEXTURE_FORMAT_RGBA8 = 1,
|
||||||
RK_TEXTURE_FORMAT_RGB10_A2 = 2,
|
RK_TEXTURE_FORMAT_RGB10_A2 = 2,
|
||||||
RK_TEXTURE_FORMAT_32F = 3
|
RK_TEXTURE_FORMAT_FLOAT_32 = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum rk_texture_flags : rk_uint {
|
typedef rk_uint rk_texture_flags;
|
||||||
|
|
||||||
|
enum : rk_texture_flags {
|
||||||
RK_TEXTURE_FLAG_3D = RK_FLAG(0),
|
RK_TEXTURE_FLAG_3D = RK_FLAG(0),
|
||||||
RK_TEXTURE_FLAG_MIPMAPS = RK_FLAG(1),
|
RK_TEXTURE_FLAG_MIPMAPS = RK_FLAG(1),
|
||||||
RK_TEXTURE_FLAG_MIN_NEAREST = 0,
|
RK_TEXTURE_FLAG_MIN_NEAREST = 0,
|
||||||
@ -46,68 +47,68 @@ enum rk_texture_flags : rk_uint {
|
|||||||
RK_TEXTURE_FLAG_MAG_LINEAR = RK_FLAG(3),
|
RK_TEXTURE_FLAG_MAG_LINEAR = RK_FLAG(3),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum rk_vertex_format : rk_ubyte {
|
typedef rk_ubyte rk_vertex_format;
|
||||||
|
|
||||||
|
enum : rk_vertex_format {
|
||||||
RK_VERTEX_FORMAT_VEC3_FLOAT = 1,
|
RK_VERTEX_FORMAT_VEC3_FLOAT = 1,
|
||||||
RK_VERTEX_FORMAT_VEC3_INT10 = 2,
|
RK_VERTEX_FORMAT_VEC3_SHORT = 2,
|
||||||
RK_VERTEX_FORMAT_VEC3_UINT10 = 3
|
RK_VERTEX_FORMAT_VEC3_INT10 = 3,
|
||||||
|
RK_VERTEX_FORMAT_VEC3_UINT10 = 4,
|
||||||
|
RK_VERTEX_FORMAT_MAT3_FLOAT = 5,
|
||||||
|
RK_VERTEX_FORMAT_MAT3_INT10 = 6,
|
||||||
|
RK_VERTEX_FORMAT_NORMALIZE = RK_FLAG(7),
|
||||||
|
RK_VERTEX_FORMAT_MASK = RK_VERTEX_FORMAT_NORMALIZE - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum : rk_ubyte { RK_VERTEX_FORMAT_NORMALIZE = RK_FLAG(7) };
|
typedef rk_ubyte rk_instance_flags;
|
||||||
enum : rk_ubyte { RK_VERTEX_FORMAT_MASK = RK_VERTEX_FORMAT_NORMALIZE - 1 };
|
|
||||||
|
|
||||||
enum rk_param_format : rk_ubyte {
|
enum : rk_instance_flags {
|
||||||
RK_PARAM_FORMAT_VEC3_FLOAT = 1,
|
|
||||||
RK_PARAM_FORMAT_VEC3_SHORT = 2,
|
|
||||||
RK_PARAM_FORMAT_VEC3_INT10 = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
enum : rk_ubyte { RK_PARAM_FORMAT_NORMALIZE = RK_FLAG(7) };
|
|
||||||
enum : rk_ubyte { RK_PARAM_FORMAT_MASK = RK_PARAM_FORMAT_NORMALIZE - 1 };
|
|
||||||
|
|
||||||
enum rk_instance_flags : rk_ubyte {
|
|
||||||
RK_INSTANCE_FLAG_SPAWNED = RK_FLAG(0),
|
RK_INSTANCE_FLAG_SPAWNED = RK_FLAG(0),
|
||||||
RK_INSTANCE_FLAG_VISIBLE = RK_FLAG(1)
|
RK_INSTANCE_FLAG_VISIBLE = RK_FLAG(1),
|
||||||
|
RK_INSTANCE_FLAGS_SPAWNED_VISIBLE = RK_INSTANCE_FLAG_SPAWNED | RK_INSTANCE_FLAG_VISIBLE
|
||||||
};
|
};
|
||||||
|
|
||||||
enum : rk_ubyte { RK_INSTANCE_FLAGS_SPAWNED_VISIBLE = RK_INSTANCE_FLAG_SPAWNED | RK_INSTANCE_FLAG_VISIBLE };
|
enum : rk_uint {
|
||||||
|
RK_BATCH_MAX_SIZE = 65536
|
||||||
enum : rk_uint { RK_BATCH_MAX_SIZE = 65536 };
|
|
||||||
|
|
||||||
union rk_mesh {
|
|
||||||
rk_uint packed;
|
|
||||||
struct {
|
|
||||||
rk_ushort base_index;
|
|
||||||
rk_ushort ntriangles;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
RK_EXPORT rk_window_t rk_initialize(
|
typedef rk_ushort rk_vertex_index;
|
||||||
char const * name,
|
typedef rk_ushort rk_mesh_index;
|
||||||
rk_uint width,
|
typedef rk_ushort rk_instance_index;
|
||||||
rk_uint height);
|
typedef rk_uint rk_vertex_input;
|
||||||
|
typedef rk_uint rk_vertex_output;
|
||||||
|
|
||||||
RK_EXPORT rk_shader_t rk_load_shader(
|
struct rk_mesh {
|
||||||
|
rk_uint base_index;
|
||||||
|
rk_uint ntriangles;
|
||||||
|
};
|
||||||
|
|
||||||
|
RK_EXPORT void rk_render_initialize(
|
||||||
|
rk_bool debug);
|
||||||
|
|
||||||
|
RK_EXPORT void rk_render_terminate();
|
||||||
|
|
||||||
|
RK_EXPORT rk_shader_t rk_create_shader(
|
||||||
rk_uint const vert_nlines,
|
rk_uint const vert_nlines,
|
||||||
char const ** const vert_lines,
|
rk_char const * const * vert_lines,
|
||||||
rk_uint const frag_nlines,
|
rk_uint const frag_nlines,
|
||||||
char const ** const frag_lines);
|
rk_char const * const * frag_lines);
|
||||||
|
|
||||||
RK_EXPORT rk_input_t rk_resolve_input(
|
RK_EXPORT rk_input_t rk_resolve_input(
|
||||||
rk_shader_t shader,
|
rk_shader_t shader,
|
||||||
char const * name);
|
rk_char const * name);
|
||||||
|
|
||||||
RK_EXPORT rk_param_t rk_resolve_param(
|
RK_EXPORT rk_param_t rk_resolve_param(
|
||||||
rk_shader_t shader,
|
rk_shader_t shader,
|
||||||
char const * name);
|
rk_char const * name);
|
||||||
|
|
||||||
RK_EXPORT rk_texture_t rk_create_texture(
|
RK_EXPORT rk_texture_t rk_create_texture(
|
||||||
rk_uint slot,
|
|
||||||
rk_texture_format format,
|
rk_texture_format format,
|
||||||
rk_uint width,
|
rk_uint width,
|
||||||
rk_uint height,
|
rk_uint height,
|
||||||
rk_uint nlevels,
|
rk_uint nlevels,
|
||||||
rk_texture_flags flags,
|
rk_texture_flags flags,
|
||||||
void const * pixels);
|
rk_ubyte const * pixels);
|
||||||
|
|
||||||
RK_EXPORT rk_triangles_t rk_create_triangles(
|
RK_EXPORT rk_triangles_t rk_create_triangles(
|
||||||
rk_uint nvertices,
|
rk_uint nvertices,
|
||||||
@ -116,16 +117,28 @@ RK_EXPORT rk_triangles_t rk_create_triangles(
|
|||||||
RK_EXPORT rk_vertices_t rk_create_vertices(
|
RK_EXPORT rk_vertices_t rk_create_vertices(
|
||||||
rk_vertex_format const * format,
|
rk_vertex_format const * format,
|
||||||
rk_uint nvertices,
|
rk_uint nvertices,
|
||||||
void const * vertices,
|
rk_ubyte const * vertices,
|
||||||
rk_uint nindices,
|
rk_uint nindices,
|
||||||
rk_ushort const * indices);
|
rk_vertex_index const * indices,
|
||||||
|
rk_uint nmeshes,
|
||||||
|
rk_mesh const * meshes);
|
||||||
|
|
||||||
RK_EXPORT rk_batch_t rk_create_batch(
|
RK_EXPORT rk_batch_t rk_create_batch(
|
||||||
rk_vertices_t vertices,
|
rk_vertices_t vertices,
|
||||||
rk_uint max_size,
|
rk_uint max_size,
|
||||||
rk_param_format const * params_format);
|
rk_vertex_format const * params_format);
|
||||||
|
|
||||||
RK_EXPORT void rk_begin_frame();
|
RK_EXPORT void rk_fill_batch(
|
||||||
|
rk_batch_t batch,
|
||||||
|
rk_uint count,
|
||||||
|
rk_instance_flags const * flags,
|
||||||
|
rk_mesh_index const * meshes,
|
||||||
|
rk_vertex_input const * const * params);
|
||||||
|
|
||||||
|
RK_EXPORT void rk_clear_buffer(
|
||||||
|
rk_bool pixels,
|
||||||
|
rk_bool depth,
|
||||||
|
rk_bool stencil);
|
||||||
|
|
||||||
RK_EXPORT void rk_select_shader(
|
RK_EXPORT void rk_select_shader(
|
||||||
rk_shader_t _shader);
|
rk_shader_t _shader);
|
||||||
@ -150,34 +163,27 @@ RK_EXPORT void rk_set_param_vec3(
|
|||||||
rk_param_t param,
|
rk_param_t param,
|
||||||
rk_vec3 const & value);
|
rk_vec3 const & value);
|
||||||
|
|
||||||
|
RK_EXPORT void rk_set_param_mat3(
|
||||||
|
rk_param_t param,
|
||||||
|
rk_mat3 const & value);
|
||||||
|
|
||||||
RK_EXPORT void rk_select_texture(
|
RK_EXPORT void rk_select_texture(
|
||||||
rk_texture_t texture,
|
rk_uint slot,
|
||||||
rk_input_t sampler);
|
rk_texture_t texture);
|
||||||
|
|
||||||
RK_EXPORT void rk_draw_triangles(
|
RK_EXPORT void rk_draw_triangles(
|
||||||
rk_triangles_t triangles);
|
rk_triangles_t triangles);
|
||||||
|
|
||||||
RK_EXPORT void rk_select_vertices(
|
|
||||||
rk_vertices_t vertices);
|
|
||||||
|
|
||||||
RK_EXPORT void rk_draw_batch(
|
RK_EXPORT void rk_draw_batch(
|
||||||
rk_batch_t batch,
|
rk_batch_t batch);
|
||||||
rk_uint size,
|
|
||||||
rk_instance_flags const * flags,
|
|
||||||
rk_mesh const * meshes,
|
|
||||||
rk_ubyte const * params);
|
|
||||||
|
|
||||||
RK_EXPORT void rk_unselect_vertices(
|
|
||||||
rk_vertices_t vertices);
|
|
||||||
|
|
||||||
RK_EXPORT void rk_unselect_texture(
|
RK_EXPORT void rk_unselect_texture(
|
||||||
|
rk_uint slot,
|
||||||
rk_texture_t texture);
|
rk_texture_t texture);
|
||||||
|
|
||||||
RK_EXPORT void rk_unselect_shader(
|
RK_EXPORT void rk_unselect_shader(
|
||||||
rk_shader_t shader);
|
rk_shader_t shader);
|
||||||
|
|
||||||
RK_EXPORT void rk_end_frame();
|
|
||||||
|
|
||||||
RK_EXPORT void rk_destroy_batch(
|
RK_EXPORT void rk_destroy_batch(
|
||||||
rk_batch_t batch);
|
rk_batch_t batch);
|
||||||
|
|
||||||
@ -193,6 +199,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
|
||||||
|
1002
cpp/render/render_opengles.cpp
Normal file
1002
cpp/render/render_opengles.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,15 +17,11 @@
|
|||||||
#define _RK_ENGINE_RENDER_OPENGLES_H
|
#define _RK_ENGINE_RENDER_OPENGLES_H
|
||||||
|
|
||||||
#include "../render.hpp"
|
#include "../render.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>
|
||||||
|
|
||||||
enum : rk_uint {
|
static_assert(sizeof(rk_vertex_output) == 4);
|
||||||
RK_VERTICES_BINDING = 0,
|
|
||||||
RK_PARAMS_BINDING = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rk_shader {
|
struct rk_shader {
|
||||||
GLuint vertex;
|
GLuint vertex;
|
||||||
@ -34,31 +30,26 @@ struct rk_shader {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct rk_texture {
|
struct rk_texture {
|
||||||
rk_uint slot;
|
unsigned nlevels;
|
||||||
rk_uint nlevels;
|
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rk_triangles {
|
struct rk_triangles {
|
||||||
rk_uint size;
|
unsigned size;
|
||||||
GLuint array;
|
GLuint array;
|
||||||
GLuint vertices;
|
GLuint vertices;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rk_vertices {
|
struct rk_vertices {
|
||||||
rk_uint vertex_size;
|
unsigned nvertices;
|
||||||
rk_uint layout;
|
unsigned nindices;
|
||||||
GLuint array;
|
unsigned nmeshes;
|
||||||
GLuint vertices;
|
rk_vertex_format * format;
|
||||||
GLuint indices;
|
rk_ubyte * vertices;
|
||||||
};
|
rk_vertex_index * indices;
|
||||||
|
rk_mesh * meshes;
|
||||||
typedef void (*rk_packer_fn)(rk_ubyte * const __restrict, rk_ubyte const * const __restrict);
|
GLuint vertices_buffer;
|
||||||
|
GLuint indices_buffer;
|
||||||
struct rk_packer {
|
|
||||||
rk_packer_fn pack;
|
|
||||||
rk_uint dst_incr;
|
|
||||||
rk_uint src_incr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rk_command {
|
struct rk_command {
|
||||||
@ -69,24 +60,53 @@ struct rk_command {
|
|||||||
GLuint base_instance;
|
GLuint base_instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rk_batch {
|
typedef void (*rk_packer)(
|
||||||
rk_uint size;
|
unsigned const, // count
|
||||||
rk_uint nparams;
|
rk_instance_index const * const __restrict, // indices
|
||||||
rk_uint params_size;
|
rk_vertex_output * __restrict, // dst
|
||||||
rk_uint packed_size;
|
rk_vertex_input const * const __restrict); // src
|
||||||
rk_ushort * indices;
|
|
||||||
rk_command * commands;
|
struct rk_parameter {
|
||||||
rk_packer * packers;
|
mutable bool dirty;
|
||||||
rk_ubyte * params;
|
unsigned binding;
|
||||||
GLuint params_buffer;
|
unsigned offset;
|
||||||
GLuint commands_buffer;
|
unsigned src_size;
|
||||||
|
unsigned src_len;
|
||||||
|
unsigned dst_size;
|
||||||
|
unsigned dst_len;
|
||||||
|
rk_vertex_input * source;
|
||||||
|
rk_packer packer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rk_vec3_short {
|
struct rk_bucket {
|
||||||
rk_short x;
|
unsigned size;
|
||||||
rk_short y;
|
unsigned count;
|
||||||
rk_short z;
|
rk_instance_index * indices;
|
||||||
rk_short pad;
|
};
|
||||||
|
|
||||||
|
enum rk_batch_state {
|
||||||
|
RK_BATCH_STATE_EMPTY = 0,
|
||||||
|
RK_BATCH_STATE_FILLED = 1,
|
||||||
|
RK_BATCH_STATE_SORTED = 2,
|
||||||
|
RK_BATCH_STATE_PACKED = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_batch {
|
||||||
|
mutable rk_batch_state state;
|
||||||
|
mutable unsigned count;
|
||||||
|
mutable unsigned ninstances;
|
||||||
|
mutable unsigned ncommands;
|
||||||
|
unsigned max_size;
|
||||||
|
unsigned nparams;
|
||||||
|
rk_vertices const * vertices;
|
||||||
|
rk_instance_flags * flags;
|
||||||
|
rk_mesh_index * meshes;
|
||||||
|
rk_instance_index * indices;
|
||||||
|
rk_command * commands;
|
||||||
|
rk_parameter * params;
|
||||||
|
GLuint vertex_array;
|
||||||
|
GLuint commands_buffer;
|
||||||
|
GLuint params_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _RK_ENGINE_RENDER_OPENGLES_H
|
#endif // _RK_ENGINE_RENDER_OPENGLES_H
|
@ -18,11 +18,19 @@
|
|||||||
|
|
||||||
#include <cstdbool>
|
#include <cstdbool>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
#define RK_EXPORT extern "C"
|
#define RK_EXPORT extern "C"
|
||||||
|
#define RK_HOT gnu::hot
|
||||||
|
#define RK_FLATTEN gnu::flatten
|
||||||
|
#define RK_UNROLLED gnu::optimize("unroll-loops")
|
||||||
|
#define RK_FAST gnu::optimize("Ofast")
|
||||||
|
#define RK_INVALID_HANDLE nullptr
|
||||||
|
#define RK_FLAG(_bit) (1 << (_bit))
|
||||||
|
|
||||||
typedef void * rk_handle_t;
|
typedef bool rk_bool;
|
||||||
|
typedef char rk_char;
|
||||||
|
typedef wchar_t rk_wchar;
|
||||||
|
typedef int8_t rk_byte;
|
||||||
typedef uint8_t rk_ubyte;
|
typedef uint8_t rk_ubyte;
|
||||||
typedef int16_t rk_short;
|
typedef int16_t rk_short;
|
||||||
typedef uint16_t rk_ushort;
|
typedef uint16_t rk_ushort;
|
||||||
@ -30,5 +38,33 @@ typedef int32_t rk_int;
|
|||||||
typedef uint32_t rk_uint;
|
typedef uint32_t rk_uint;
|
||||||
typedef int64_t rk_long;
|
typedef int64_t rk_long;
|
||||||
typedef uint64_t rk_ulong;
|
typedef uint64_t rk_ulong;
|
||||||
|
typedef __int128 rk_llong;
|
||||||
|
typedef unsigned __int128 rk_ullong;
|
||||||
|
typedef float rk_float;
|
||||||
|
typedef void * rk_handle_t;
|
||||||
|
|
||||||
|
static_assert(sizeof(rk_char) == 1);
|
||||||
|
static_assert(sizeof(rk_wchar) == 4);
|
||||||
|
static_assert(sizeof(rk_float) == 4);
|
||||||
|
|
||||||
|
#pragma pack(push, 4)
|
||||||
|
|
||||||
|
template<bool _signed, unsigned _cols>
|
||||||
|
struct rk_packed {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<unsigned _cols>
|
||||||
|
struct alignas(alignof(rk_int)) rk_packed<true, _cols> {
|
||||||
|
typedef rk_int type;
|
||||||
|
rk_int packed;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<unsigned _cols>
|
||||||
|
struct alignas(alignof(rk_uint)) rk_packed<false, _cols> {
|
||||||
|
typedef rk_uint type;
|
||||||
|
rk_uint packed;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
#endif // _RK_ENGINE_TYPES_H
|
#endif // _RK_ENGINE_TYPES_H
|
||||||
|
102
cpp/utils/cmp_memcpy.hpp
Normal file
102
cpp/utils/cmp_memcpy.hpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// Copyright (C) 2023 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_CMP_MEMCPY_H
|
||||||
|
#define RK_ENGINE_CMP_MEMCPY_H
|
||||||
|
|
||||||
|
#include "../types.hpp"
|
||||||
|
|
||||||
|
template<typename _small>
|
||||||
|
[[RK_FAST]]
|
||||||
|
inline bool _rk_cmp_memcpy_small(
|
||||||
|
_small * __restrict dst,
|
||||||
|
_small const * __restrict src,
|
||||||
|
unsigned count) {
|
||||||
|
_small cmp = 0;
|
||||||
|
do {
|
||||||
|
cmp |= *dst ^ *src;
|
||||||
|
*dst++ = *src++;
|
||||||
|
} while(--count > 0);
|
||||||
|
return (cmp != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename _big, typename _small>
|
||||||
|
[[RK_FAST, RK_FLATTEN]]
|
||||||
|
inline bool _rk_cmp_memcpy_big(
|
||||||
|
_small * const __restrict _dst,
|
||||||
|
_small const * const __restrict _src,
|
||||||
|
unsigned const _count) {
|
||||||
|
unsigned const ratio = sizeof(_big) / sizeof(_small);
|
||||||
|
unsigned big_count = _count / ratio;
|
||||||
|
unsigned const small_count = _count % ratio;
|
||||||
|
_big * dst = reinterpret_cast<_big *>(_dst);
|
||||||
|
_big const * src = reinterpret_cast<_big const *>(_src);
|
||||||
|
_big cmp = 0;
|
||||||
|
do {
|
||||||
|
cmp |= *dst ^ *src;
|
||||||
|
*dst++ = *src++;
|
||||||
|
} while(--big_count > 0);
|
||||||
|
bool modified = (cmp != 0);
|
||||||
|
if (small_count) {
|
||||||
|
modified |= _rk_cmp_memcpy_small<_small>(
|
||||||
|
reinterpret_cast<_small *>(dst), reinterpret_cast<_small const *>(src), small_count);
|
||||||
|
}
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RK_CMP_MEMCPY_UNALIGNED
|
||||||
|
#define _rk_count_and_alignment(_t) (count >= (sizeof(_t) / sizeof(_small)))
|
||||||
|
#else
|
||||||
|
#define _rk_count_and_alignment(_t) ((count >= (sizeof(_t) / sizeof(_small))) && !(alignment % sizeof(_t)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename _small>
|
||||||
|
[[RK_HOT, RK_FAST, RK_FLATTEN]]
|
||||||
|
bool rk_cmp_memcpy(
|
||||||
|
_small * const __restrict _dst,
|
||||||
|
_small const * const __restrict _src,
|
||||||
|
unsigned const count) {
|
||||||
|
#ifndef RK_CMP_MEMCPY_UNALIGNED
|
||||||
|
unsigned const alignment = reinterpret_cast<uintptr_t>(_dst) | reinterpret_cast<uintptr_t const>(_src);
|
||||||
|
#endif
|
||||||
|
if (sizeof(_small) < sizeof(rk_ullong)) {
|
||||||
|
if (_rk_count_and_alignment(rk_ullong)) {
|
||||||
|
return _rk_cmp_memcpy_big<rk_ullong, _small>(_dst, _src, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sizeof(_small) < sizeof(rk_ulong)) {
|
||||||
|
if (_rk_count_and_alignment(rk_ulong)) {
|
||||||
|
return _rk_cmp_memcpy_big<rk_ulong, _small>(_dst, _src, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sizeof(_small) < sizeof(rk_uint)) {
|
||||||
|
if (_rk_count_and_alignment(rk_uint)) {
|
||||||
|
return _rk_cmp_memcpy_big<rk_uint, _small>(_dst, _src, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sizeof(_small) < sizeof(rk_ushort)) {
|
||||||
|
if (_rk_count_and_alignment(rk_ushort)) {
|
||||||
|
return _rk_cmp_memcpy_big<rk_ushort, _small>(_dst, _src, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count) {
|
||||||
|
return _rk_cmp_memcpy_small<_small>(_dst, _src, count);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef _rk_count_and_alignment
|
||||||
|
|
||||||
|
#endif // RK_ENGINE_CMP_MEMCPY_H
|
258
cpp/utils/vertex_format.hpp
Normal file
258
cpp/utils/vertex_format.hpp
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
// Copyright (C) 2023 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_VERTEX_FORMAT_H
|
||||||
|
#define RK_ENGINE_VERTEX_FORMAT_H
|
||||||
|
|
||||||
|
#include "../render.hpp"
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace rk_vertex {
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
template<typename _type>
|
||||||
|
struct alignas(alignof(_type)) rk_input {
|
||||||
|
_type input;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _type, typename _input, bool _signed, bool _normalized>
|
||||||
|
struct alignas(alignof(_type)) rk_output {
|
||||||
|
_type output;
|
||||||
|
|
||||||
|
[[RK_FAST]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input<_input> const & __restrict src) {
|
||||||
|
output = static_cast<_type>(src.input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _type, bool _signed>
|
||||||
|
struct alignas(alignof(_type)) rk_output<_type, rk_float, _signed, true> {
|
||||||
|
_type output;
|
||||||
|
|
||||||
|
[[RK_FAST]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input<rk_float> const & __restrict src) {
|
||||||
|
enum : _type { max = std::numeric_limits<_type>::max() };
|
||||||
|
output = static_cast<_type>(src.input * static_cast<float>(max));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(4)
|
||||||
|
|
||||||
|
template<typename _input, unsigned _cols>
|
||||||
|
struct alignas(4) rk_input_row {
|
||||||
|
rk_input<_input> input_col[_cols];
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _output, typename _input, unsigned _cols, bool _signed, bool _normalized>
|
||||||
|
struct alignas(4) rk_output_row {
|
||||||
|
rk_output<_output, _input, _signed, _normalized> output_col[_cols];
|
||||||
|
|
||||||
|
[[RK_FAST, RK_FLATTEN, RK_UNROLLED]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input_row<_input, _cols> const & __restrict src) {
|
||||||
|
for (unsigned col = 0; col < _cols; ++col) {
|
||||||
|
output_col[col].convert(src.input_col[col]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _output, unsigned _cols, bool _signed, bool _normalized>
|
||||||
|
struct alignas(4) rk_output_row<_output, _output, _cols, _signed, _normalized> {
|
||||||
|
rk_output<_output, _output, _signed, _normalized> output_col[_cols];
|
||||||
|
|
||||||
|
[[RK_FAST]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input_row<_output, _cols> const & __restrict src) {
|
||||||
|
static_assert(sizeof(output_col) == sizeof(src.input_col));
|
||||||
|
rk_output<_output, _output, _signed, _normalized> const * const input_col =
|
||||||
|
reinterpret_cast<rk_output<_output, _output, _signed, _normalized> const *>(src.input_col);
|
||||||
|
*output_col = *input_col;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _input, unsigned _cols, bool _signed, bool _normalized>
|
||||||
|
struct alignas(4) rk_output_row<rk_packed<_signed, _cols>, _input, _cols, _signed, _normalized> {
|
||||||
|
rk_output<rk_packed<_signed, _cols>, _input, _signed, _normalized> output_cols;
|
||||||
|
|
||||||
|
[[RK_FAST, RK_FLATTEN]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input_row<_input, _cols> const & __restrict src) {
|
||||||
|
output_cols.convert(src);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _input, unsigned _cols, unsigned _rows>
|
||||||
|
struct alignas(4) rk_input_format {
|
||||||
|
rk_input_row<_input, _cols> input_row[_rows];
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _output, typename _input, unsigned _cols, unsigned _rows, bool _signed, bool _normalized>
|
||||||
|
struct alignas(4) rk_output_format {
|
||||||
|
rk_output_row<_output, _input, _cols, _signed, _normalized> output_row[_rows];
|
||||||
|
|
||||||
|
[[RK_FAST, RK_FLATTEN, RK_UNROLLED]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input_format<_input, _cols, _rows> const & __restrict src) {
|
||||||
|
for (unsigned row = 0; row < _rows; ++row) {
|
||||||
|
output_row[row].convert(src.input_row[row]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _output, unsigned _cols, unsigned _rows, bool _signed, bool _normalized>
|
||||||
|
struct alignas(4) rk_output_format<_output, _output, _cols, _rows, _signed, _normalized> {
|
||||||
|
rk_output_row<_output, _output, _cols, _signed, _normalized> output_row[_rows];
|
||||||
|
|
||||||
|
[[RK_FAST]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input_format<_output, _cols, _rows> const & __restrict src) {
|
||||||
|
static_assert(sizeof(output_row) == sizeof(src.input_row));
|
||||||
|
rk_output_row<_output, _output, _cols, _signed, _normalized> const * const input_row =
|
||||||
|
reinterpret_cast<rk_output_row<_output, _output, _cols, _signed, _normalized> const *>(src.input_row);
|
||||||
|
*output_row = *input_row;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _input, bool _signed, bool _normalized>
|
||||||
|
struct alignas(alignof(rk_packed<_signed, 3>)) rk_output<rk_packed<_signed, 3>, _input, _signed, _normalized> {
|
||||||
|
rk_packed<_signed, 3> output;
|
||||||
|
|
||||||
|
[[RK_FAST]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input_row<_input, 3> const & __restrict src) {
|
||||||
|
typedef typename rk_packed<_signed, 3>::type packed_type;
|
||||||
|
output.packed =
|
||||||
|
((static_cast<packed_type>(src.input_col[0].input) & 1023)) |
|
||||||
|
((static_cast<packed_type>(src.input_col[1].input) & 1023) << 10) |
|
||||||
|
((static_cast<packed_type>(src.input_col[2].input) & 1023) << 20);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _input, bool _signed, bool _normalized>
|
||||||
|
struct alignas(alignof(rk_packed<_signed, 4>)) rk_output<rk_packed<_signed, 4>, _input, _signed, _normalized> {
|
||||||
|
rk_packed<_signed, 4> output;
|
||||||
|
|
||||||
|
[[RK_FAST]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input_row<_input, 4> const & __restrict src) {
|
||||||
|
typedef typename rk_packed<_signed, 4>::type packed_type;
|
||||||
|
output.packed =
|
||||||
|
((static_cast<packed_type>(src.input_col[0].input) & 1023)) |
|
||||||
|
((static_cast<packed_type>(src.input_col[1].input) & 1023) << 10) |
|
||||||
|
((static_cast<packed_type>(src.input_col[2].input) & 1023) << 20) |
|
||||||
|
((static_cast<packed_type>(src.input_col[3].input) & 3) << 30);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct alignas(alignof(rk_packed<true, 3>)) rk_output<rk_packed<true, 3>, rk_float, true, true> {
|
||||||
|
rk_packed<true, 3> output;
|
||||||
|
|
||||||
|
[[RK_FAST]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input_row<rk_float, 3> const & __restrict src) {
|
||||||
|
output.packed =
|
||||||
|
((static_cast<rk_int>(src.input_col[0].input * 511.f) & 1023)) |
|
||||||
|
((static_cast<rk_int>(src.input_col[1].input * 511.f) & 1023) << 10) |
|
||||||
|
((static_cast<rk_int>(src.input_col[2].input * 511.f) & 1023) << 20);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct alignas(alignof(rk_packed<true, 4>)) rk_output<rk_packed<true, 4>, rk_float, true, true> {
|
||||||
|
rk_packed<true, 4> output;
|
||||||
|
|
||||||
|
[[RK_FAST]]
|
||||||
|
inline void convert(
|
||||||
|
rk_input_row<rk_float, 4> const & __restrict src) {
|
||||||
|
output.packed =
|
||||||
|
((static_cast<rk_uint>(src.input_col[0].input * 511.f) & 1023)) |
|
||||||
|
((static_cast<rk_uint>(src.input_col[1].input * 511.f) & 1023) << 10) |
|
||||||
|
((static_cast<rk_uint>(src.input_col[2].input * 511.f) & 1023) << 20) |
|
||||||
|
((static_cast<rk_uint>(src.input_col[3].input) & 3) << 30);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
template<typename _output, typename _input, unsigned _cols, unsigned _rows, bool _signed, bool _normalized>
|
||||||
|
struct rk_format {
|
||||||
|
typedef rk_input<_input> input;
|
||||||
|
typedef rk_output<_output, input, _signed, _normalized> output;
|
||||||
|
|
||||||
|
typedef rk_input_row<_input, _cols> input_row;
|
||||||
|
typedef rk_output_row<_output, _input, _cols, _signed, _normalized> output_row;
|
||||||
|
|
||||||
|
typedef rk_input_format<_input, _cols, _rows> input_format;
|
||||||
|
typedef rk_output_format<_output, _input, _cols, _rows, _signed, _normalized> output_format;
|
||||||
|
|
||||||
|
static_assert(sizeof(input) == sizeof(_input));
|
||||||
|
static_assert(sizeof(output) == sizeof(_output));
|
||||||
|
static_assert((sizeof(input_row) % sizeof(rk_vertex_input)) == 0);
|
||||||
|
static_assert((sizeof(output_row) % sizeof(rk_vertex_output)) == 0);
|
||||||
|
static_assert((sizeof(input_format) % sizeof(rk_vertex_input)) == 0);
|
||||||
|
static_assert((sizeof(output_format) % sizeof(rk_vertex_output)) == 0);
|
||||||
|
|
||||||
|
static unsigned get_input_size() {
|
||||||
|
return sizeof(input_format);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned get_output_size() {
|
||||||
|
return sizeof(output_format);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned get_output_offset(unsigned const index) {
|
||||||
|
return index * sizeof(output_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[RK_FAST, RK_FLATTEN]]
|
||||||
|
inline static void convert(
|
||||||
|
output_format & __restrict dst,
|
||||||
|
input_format const & __restrict src) {
|
||||||
|
dst.convert(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[RK_HOT, RK_FAST, RK_FLATTEN]]
|
||||||
|
static void param_packer(
|
||||||
|
unsigned const count,
|
||||||
|
rk_instance_index const * const __restrict indices,
|
||||||
|
rk_vertex_output * __restrict _dst,
|
||||||
|
rk_vertex_input const * const __restrict _src) {
|
||||||
|
rk_instance_index const * const last_index = indices + count;
|
||||||
|
output_format * __restrict dst = reinterpret_cast<output_format *>(_dst);
|
||||||
|
input_format const * const __restrict src = reinterpret_cast<input_format const *>(_src);
|
||||||
|
for (rk_instance_index const * __restrict index = indices; index < last_index; ++index, ++dst) {
|
||||||
|
dst->convert(src[*index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namepace rk_vertex
|
||||||
|
|
||||||
|
typedef rk_vertex::rk_format<rk_float, rk_float, 3, 1, true, false> rk_vec3_float;
|
||||||
|
typedef rk_vertex::rk_format<rk_short, rk_float, 3, 1, true, false> rk_vec3_short;
|
||||||
|
typedef rk_vertex::rk_format<rk_short, rk_float, 3, 1, true, true> rk_vec3_short_norm;
|
||||||
|
typedef rk_vertex::rk_format<rk_packed<true, 3>, rk_float, 3, 1, true, false> rk_vec3_int10;
|
||||||
|
typedef rk_vertex::rk_format<rk_packed<true, 3>, rk_float, 3, 1, true, true> rk_vec3_int10_norm;
|
||||||
|
typedef rk_vertex::rk_format<rk_packed<false, 3>, rk_float, 3, 1, false, false> rk_vec3_uint10;
|
||||||
|
typedef rk_vertex::rk_format<rk_packed<false, 3>, rk_float, 3, 1, false, true> rk_vec3_uint10_norm;
|
||||||
|
typedef rk_vertex::rk_format<rk_float, rk_float, 3, 3, true, false> rk_mat3_float;
|
||||||
|
typedef rk_vertex::rk_format<rk_packed<true, 3>, rk_float, 3, 3, true, false> rk_mat3_int10;
|
||||||
|
typedef rk_vertex::rk_format<rk_packed<true, 3>, rk_float, 3, 3, true, true> rk_mat3_int10_norm;
|
||||||
|
|
||||||
|
#endif // RK_ENGINE_VERTEX_FORMAT_H
|
Reference in New Issue
Block a user