More OpenGL bindings
This commit is contained in:
parent
cded235526
commit
06b42a7e1c
@ -36,6 +36,7 @@ PyInit_fast_data_types(void) {
|
||||
if (!init_LineBuf(m)) return NULL;
|
||||
if (!init_Line(m)) return NULL;
|
||||
if (!init_Cursor(m)) return NULL;
|
||||
if (!add_module_gl_constants(m)) return NULL;
|
||||
}
|
||||
|
||||
return m;
|
||||
|
||||
@ -6,10 +6,15 @@ import glfw
|
||||
import OpenGL.GL as gl
|
||||
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.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):
|
||||
@ -61,13 +66,13 @@ class Renderer:
|
||||
with self.program:
|
||||
ul = self.program.uniform_location
|
||||
sg = self.screen_geometry
|
||||
gl.glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
|
||||
gl.glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy)
|
||||
gl.glUniform1i(ul('sprites'), self.sprites.sampler_num)
|
||||
gl.glUniform1i(ul('sprite_map'), self.sprites.buffer_sampler_num)
|
||||
gl.glUniform2f(ul('sprite_layout'), *self.sprites.layout)
|
||||
glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
|
||||
glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy)
|
||||
glUniform1i(ul('sprites'), self.sprites.sampler_num)
|
||||
glUniform1i(ul('sprite_map'), self.sprites.buffer_sampler_num)
|
||||
glUniform2f(ul('sprite_layout'), *self.sprites.layout)
|
||||
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 {{{
|
||||
|
||||
@ -78,7 +83,7 @@ def key_callback(key, action):
|
||||
|
||||
|
||||
def gl_get_unicode(k):
|
||||
ans = gl.glGetString(k)
|
||||
ans = glGetString(k)
|
||||
if isinstance(ans, bytes):
|
||||
try:
|
||||
ans = ans.decode('utf-8')
|
||||
@ -102,22 +107,22 @@ def _main():
|
||||
if not window:
|
||||
raise SystemExit("glfwCreateWindow failed")
|
||||
glfw.glfwMakeContextCurrent(window)
|
||||
glewInit()
|
||||
glfw.glfwSwapInterval(1)
|
||||
check_for_required_extensions()
|
||||
|
||||
# If everything went well the following calls
|
||||
# will display the version of opengl being used
|
||||
print('Vendor: %s' % (gl_get_unicode(gl.GL_VENDOR)))
|
||||
print('Opengl version: %s' % (gl_get_unicode(gl.GL_VERSION)))
|
||||
print('GLSL Version: %s' % (gl_get_unicode(gl.GL_SHADING_LANGUAGE_VERSION)))
|
||||
print('Renderer: %s' % (gl_get_unicode(gl.GL_RENDERER)))
|
||||
print('Vendor: %s' % (gl_get_unicode(GL_VENDOR)))
|
||||
print('Opengl version: %s' % (gl_get_unicode(GL_VERSION_C)))
|
||||
print('GLSL Version: %s' % (gl_get_unicode(GL_SHADING_LANGUAGE_VERSION)))
|
||||
print('Renderer: %s' % (gl_get_unicode(GL_RENDERER)))
|
||||
|
||||
r = Renderer(1024, 1024)
|
||||
glfw.glfwSetFramebufferSizeCallback(window, r.on_resize)
|
||||
try:
|
||||
gl.glClearColor(0.5, 0.5, 0.5, 0)
|
||||
glClearColor(0.5, 0.5, 0.5, 0)
|
||||
while not glfw.glfwWindowShouldClose(window):
|
||||
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
r.render()
|
||||
glfw.glfwSwapBuffers(window)
|
||||
glfw.glfwWaitEvents()
|
||||
|
||||
117
kitty/gl.h
117
kitty/gl.h
@ -51,13 +51,130 @@ Viewport(PyObject UNUSED *self, PyObject *args) {
|
||||
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*
|
||||
CheckError(PyObject UNUSED *self) {
|
||||
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 \
|
||||
{"enable_automatic_opengl_error_checking", (PyCFunction)enable_automatic_error_checking, METH_O, NULL}, \
|
||||
{"glewInit", (PyCFunction)_glewInit, METH_NOARGS, NULL}, \
|
||||
METH(Viewport, METH_VARARGS) \
|
||||
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 .boss import Boss
|
||||
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
|
||||
|
||||
|
||||
@ -53,7 +54,7 @@ def run_app(opts, args):
|
||||
glfw.glfwSetWindowTitle(window, appname.encode('utf-8'))
|
||||
try:
|
||||
glfw.glfwMakeContextCurrent(window)
|
||||
check_for_required_extensions()
|
||||
glewInit()
|
||||
glfw.glfwSwapInterval(1)
|
||||
boss = Boss(window, window_width, window_height, opts, args)
|
||||
glfw.glfwSetFramebufferSizeCallback(window, boss.on_window_resize)
|
||||
|
||||
@ -14,25 +14,12 @@ from .data_types import ITALIC_MASK, BOLD_MASK
|
||||
|
||||
GL_VERSION = (3, 3)
|
||||
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):
|
||||
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:
|
||||
''' Maintain sprite sheets of all rendered characters on the GPU as a texture
|
||||
array with each texture being a sprite sheet. '''
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user