More OpenGL bindings

This commit is contained in:
Kovid Goyal 2016-11-03 10:30:35 +05:30
parent cded235526
commit 06b42a7e1c
5 changed files with 142 additions and 31 deletions

View File

@ -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;

View File

@ -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()

View File

@ -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) \

View File

@ -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)

View File

@ -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. '''