mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-25 17:52:02 +02:00
More OpenGL bindings
This commit is contained in:
@@ -36,6 +36,7 @@ PyInit_fast_data_types(void) {
|
|||||||
if (!init_LineBuf(m)) return NULL;
|
if (!init_LineBuf(m)) return NULL;
|
||||||
if (!init_Line(m)) return NULL;
|
if (!init_Line(m)) return NULL;
|
||||||
if (!init_Cursor(m)) return NULL;
|
if (!init_Cursor(m)) return NULL;
|
||||||
|
if (!add_module_gl_constants(m)) return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
|
|||||||
@@ -6,10 +6,15 @@ import glfw
|
|||||||
import OpenGL.GL as gl
|
import OpenGL.GL as gl
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from kitty.shaders import ShaderProgram, GL_VERSION, Sprites, check_for_required_extensions
|
from kitty.shaders import ShaderProgram, GL_VERSION, Sprites
|
||||||
from kitty.fonts import set_font_family, cell_size
|
from kitty.fonts import set_font_family, cell_size
|
||||||
from kitty.char_grid import calculate_vertices, cell_shader
|
from kitty.char_grid import calculate_vertices, cell_shader
|
||||||
from kitty.fast_data_types import glViewport, enable_automatic_opengl_error_checking
|
from kitty.fast_data_types import (
|
||||||
|
glViewport, enable_automatic_opengl_error_checking, glClearColor,
|
||||||
|
glUniform2f, glUniform4f, glUniform2ui, glUniform1i, glewInit, glGetString,
|
||||||
|
GL_VERSION as GL_VERSION_C, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION, GL_RENDERER,
|
||||||
|
glClear, GL_COLOR_BUFFER_BIT, GL_TRIANGLE_FAN, glDrawArraysInstanced
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def rectangle_uv(left=0, top=0, right=1, bottom=1):
|
def rectangle_uv(left=0, top=0, right=1, bottom=1):
|
||||||
@@ -61,13 +66,13 @@ class Renderer:
|
|||||||
with self.program:
|
with self.program:
|
||||||
ul = self.program.uniform_location
|
ul = self.program.uniform_location
|
||||||
sg = self.screen_geometry
|
sg = self.screen_geometry
|
||||||
gl.glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
|
glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
|
||||||
gl.glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy)
|
glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy)
|
||||||
gl.glUniform1i(ul('sprites'), self.sprites.sampler_num)
|
glUniform1i(ul('sprites'), self.sprites.sampler_num)
|
||||||
gl.glUniform1i(ul('sprite_map'), self.sprites.buffer_sampler_num)
|
glUniform1i(ul('sprite_map'), self.sprites.buffer_sampler_num)
|
||||||
gl.glUniform2f(ul('sprite_layout'), *self.sprites.layout)
|
glUniform2f(ul('sprite_layout'), *self.sprites.layout)
|
||||||
with self.sprites:
|
with self.sprites:
|
||||||
gl.glDrawArraysInstanced(gl.GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum)
|
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum)
|
||||||
|
|
||||||
# window setup {{{
|
# window setup {{{
|
||||||
|
|
||||||
@@ -78,7 +83,7 @@ def key_callback(key, action):
|
|||||||
|
|
||||||
|
|
||||||
def gl_get_unicode(k):
|
def gl_get_unicode(k):
|
||||||
ans = gl.glGetString(k)
|
ans = glGetString(k)
|
||||||
if isinstance(ans, bytes):
|
if isinstance(ans, bytes):
|
||||||
try:
|
try:
|
||||||
ans = ans.decode('utf-8')
|
ans = ans.decode('utf-8')
|
||||||
@@ -102,22 +107,22 @@ def _main():
|
|||||||
if not window:
|
if not window:
|
||||||
raise SystemExit("glfwCreateWindow failed")
|
raise SystemExit("glfwCreateWindow failed")
|
||||||
glfw.glfwMakeContextCurrent(window)
|
glfw.glfwMakeContextCurrent(window)
|
||||||
|
glewInit()
|
||||||
glfw.glfwSwapInterval(1)
|
glfw.glfwSwapInterval(1)
|
||||||
check_for_required_extensions()
|
|
||||||
|
|
||||||
# If everything went well the following calls
|
# If everything went well the following calls
|
||||||
# will display the version of opengl being used
|
# will display the version of opengl being used
|
||||||
print('Vendor: %s' % (gl_get_unicode(gl.GL_VENDOR)))
|
print('Vendor: %s' % (gl_get_unicode(GL_VENDOR)))
|
||||||
print('Opengl version: %s' % (gl_get_unicode(gl.GL_VERSION)))
|
print('Opengl version: %s' % (gl_get_unicode(GL_VERSION_C)))
|
||||||
print('GLSL Version: %s' % (gl_get_unicode(gl.GL_SHADING_LANGUAGE_VERSION)))
|
print('GLSL Version: %s' % (gl_get_unicode(GL_SHADING_LANGUAGE_VERSION)))
|
||||||
print('Renderer: %s' % (gl_get_unicode(gl.GL_RENDERER)))
|
print('Renderer: %s' % (gl_get_unicode(GL_RENDERER)))
|
||||||
|
|
||||||
r = Renderer(1024, 1024)
|
r = Renderer(1024, 1024)
|
||||||
glfw.glfwSetFramebufferSizeCallback(window, r.on_resize)
|
glfw.glfwSetFramebufferSizeCallback(window, r.on_resize)
|
||||||
try:
|
try:
|
||||||
gl.glClearColor(0.5, 0.5, 0.5, 0)
|
glClearColor(0.5, 0.5, 0.5, 0)
|
||||||
while not glfw.glfwWindowShouldClose(window):
|
while not glfw.glfwWindowShouldClose(window):
|
||||||
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
|
glClear(GL_COLOR_BUFFER_BIT)
|
||||||
r.render()
|
r.render()
|
||||||
glfw.glfwSwapBuffers(window)
|
glfw.glfwSwapBuffers(window)
|
||||||
glfw.glfwWaitEvents()
|
glfw.glfwWaitEvents()
|
||||||
|
|||||||
117
kitty/gl.h
117
kitty/gl.h
@@ -51,13 +51,130 @@ Viewport(PyObject UNUSED *self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
ClearColor(PyObject UNUSED *self, PyObject *args) {
|
||||||
|
float x, y, w, h;
|
||||||
|
if (!PyArg_ParseTuple(args, "ffff", &x, &y, &w, &h)) return NULL;
|
||||||
|
glClearColor(x, y, w, h);
|
||||||
|
CHECK_ERROR;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uniforms {{{
|
||||||
|
static PyObject*
|
||||||
|
Uniform2ui(PyObject UNUSED *self, PyObject *args) {
|
||||||
|
int location;
|
||||||
|
unsigned int x, y;
|
||||||
|
if (!PyArg_ParseTuple(args, "iII", &location, &x, &y)) return NULL;
|
||||||
|
glUniform2ui(location, x, y);
|
||||||
|
CHECK_ERROR;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
Uniform1i(PyObject UNUSED *self, PyObject *args) {
|
||||||
|
int location;
|
||||||
|
int x;
|
||||||
|
if (!PyArg_ParseTuple(args, "ii", &location, &x)) return NULL;
|
||||||
|
glUniform1i(location, x);
|
||||||
|
CHECK_ERROR;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
Uniform2f(PyObject UNUSED *self, PyObject *args) {
|
||||||
|
int location;
|
||||||
|
float x, y;
|
||||||
|
if (!PyArg_ParseTuple(args, "iff", &location, &x, &y)) return NULL;
|
||||||
|
glUniform2f(location, x, y);
|
||||||
|
CHECK_ERROR;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
Uniform4f(PyObject UNUSED *self, PyObject *args) {
|
||||||
|
int location;
|
||||||
|
float x, y, a, b;
|
||||||
|
if (!PyArg_ParseTuple(args, "iffff", &location, &x, &y, &a, &b)) return NULL;
|
||||||
|
glUniform4f(location, x, y, a, b);
|
||||||
|
CHECK_ERROR;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
CheckError(PyObject UNUSED *self) {
|
CheckError(PyObject UNUSED *self) {
|
||||||
CHECK_ERROR; Py_RETURN_NONE;
|
CHECK_ERROR; Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
_glewInit(PyObject UNUSED *self) {
|
||||||
|
GLenum err = glewInit();
|
||||||
|
if (err != GLEW_OK) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError, "GLEW init failed: %s", glewGetErrorString(err));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(!GLEW_ARB_copy_image) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "OpenGL is missing the required ARB_copy_image extension");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(!GLEW_ARB_texture_storage) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "OpenGL is missing the required ARB_texture_storage extension");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
GetString(PyObject UNUSED *self, PyObject *val) {
|
||||||
|
const unsigned char *ans = glGetString(PyLong_AsUnsignedLong(val));
|
||||||
|
if (ans == NULL) { SET_GL_ERR; return NULL; }
|
||||||
|
return PyBytes_FromString((const char*)ans);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
Clear(PyObject UNUSED *self, PyObject *val) {
|
||||||
|
unsigned long m = PyLong_AsUnsignedLong(val);
|
||||||
|
glClear((GLbitfield)m);
|
||||||
|
CHECK_ERROR;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
DrawArraysInstanced(PyObject UNUSED *self, PyObject *args) {
|
||||||
|
int mode, first;
|
||||||
|
unsigned int count, primcount;
|
||||||
|
if (!PyArg_ParseTuple(args, "iiII", &mode, &first, &count, &primcount)) return NULL;
|
||||||
|
glDrawArraysInstanced(mode, first, count, primcount);
|
||||||
|
CHECK_ERROR;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_module_gl_constants(PyObject *module) {
|
||||||
|
#define GLC(x) if (PyModule_AddIntConstant(module, #x, x) != 0) { PyErr_NoMemory(); return 0; }
|
||||||
|
GLC(GL_VERSION);
|
||||||
|
GLC(GL_VENDOR);
|
||||||
|
GLC(GL_SHADING_LANGUAGE_VERSION);
|
||||||
|
GLC(GL_RENDERER);
|
||||||
|
GLC(GL_TRIANGLE_FAN);
|
||||||
|
GLC(GL_COLOR_BUFFER_BIT);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#define GL_METHODS \
|
#define GL_METHODS \
|
||||||
{"enable_automatic_opengl_error_checking", (PyCFunction)enable_automatic_error_checking, METH_O, NULL}, \
|
{"enable_automatic_opengl_error_checking", (PyCFunction)enable_automatic_error_checking, METH_O, NULL}, \
|
||||||
|
{"glewInit", (PyCFunction)_glewInit, METH_NOARGS, NULL}, \
|
||||||
METH(Viewport, METH_VARARGS) \
|
METH(Viewport, METH_VARARGS) \
|
||||||
METH(CheckError, METH_NOARGS) \
|
METH(CheckError, METH_NOARGS) \
|
||||||
|
METH(ClearColor, METH_VARARGS) \
|
||||||
|
METH(Uniform2ui, METH_VARARGS) \
|
||||||
|
METH(Uniform1i, METH_VARARGS) \
|
||||||
|
METH(Uniform2f, METH_VARARGS) \
|
||||||
|
METH(Uniform4f, METH_VARARGS) \
|
||||||
|
METH(GetString, METH_O) \
|
||||||
|
METH(Clear, METH_O) \
|
||||||
|
METH(DrawArraysInstanced, METH_VARARGS) \
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ from .config import load_config
|
|||||||
from .constants import appname, str_version, config_dir
|
from .constants import appname, str_version, config_dir
|
||||||
from .boss import Boss
|
from .boss import Boss
|
||||||
from .utils import fork_child, hangup
|
from .utils import fork_child, hangup
|
||||||
from .shaders import GL_VERSION, check_for_required_extensions
|
from .shaders import GL_VERSION
|
||||||
|
from .fast_data_types import glewInit
|
||||||
import glfw
|
import glfw
|
||||||
|
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ def run_app(opts, args):
|
|||||||
glfw.glfwSetWindowTitle(window, appname.encode('utf-8'))
|
glfw.glfwSetWindowTitle(window, appname.encode('utf-8'))
|
||||||
try:
|
try:
|
||||||
glfw.glfwMakeContextCurrent(window)
|
glfw.glfwMakeContextCurrent(window)
|
||||||
check_for_required_extensions()
|
glewInit()
|
||||||
glfw.glfwSwapInterval(1)
|
glfw.glfwSwapInterval(1)
|
||||||
boss = Boss(window, window_width, window_height, opts, args)
|
boss = Boss(window, window_width, window_height, opts, args)
|
||||||
glfw.glfwSetFramebufferSizeCallback(window, boss.on_window_resize)
|
glfw.glfwSetFramebufferSizeCallback(window, boss.on_window_resize)
|
||||||
|
|||||||
@@ -14,25 +14,12 @@ from .data_types import ITALIC_MASK, BOLD_MASK
|
|||||||
|
|
||||||
GL_VERSION = (3, 3)
|
GL_VERSION = (3, 3)
|
||||||
VERSION = GL_VERSION[0] * 100 + GL_VERSION[1] * 10
|
VERSION = GL_VERSION[0] * 100 + GL_VERSION[1] * 10
|
||||||
REQUIRED_EXTENSIONS = frozenset('GL_ARB_copy_image GL_ARB_texture_storage'.split())
|
|
||||||
|
|
||||||
|
|
||||||
def array(*args, dtype=gl.GLfloat):
|
def array(*args, dtype=gl.GLfloat):
|
||||||
return (dtype * len(args))(*args)
|
return (dtype * len(args))(*args)
|
||||||
|
|
||||||
|
|
||||||
def check_for_required_extensions():
|
|
||||||
num = gl.glGetIntegerv(gl.GL_NUM_EXTENSIONS)
|
|
||||||
required = set(REQUIRED_EXTENSIONS)
|
|
||||||
for i in range(num):
|
|
||||||
ext = gl.glGetStringi(gl.GL_EXTENSIONS, i).decode('utf-8')
|
|
||||||
required.discard(ext)
|
|
||||||
if not required:
|
|
||||||
break
|
|
||||||
if required:
|
|
||||||
raise RuntimeError('Your OpenGL implementation is missing the following required extensions: %s' % ','.join(required))
|
|
||||||
|
|
||||||
|
|
||||||
class Sprites:
|
class Sprites:
|
||||||
''' Maintain sprite sheets of all rendered characters on the GPU as a texture
|
''' Maintain sprite sheets of all rendered characters on the GPU as a texture
|
||||||
array with each texture being a sprite sheet. '''
|
array with each texture being a sprite sheet. '''
|
||||||
|
|||||||
Reference in New Issue
Block a user