From: Hector Martin Date: Sun, 20 Mar 2011 07:42:48 +0000 (+0100) Subject: New Python bindings via Cython X-Git-Url: https://gitweb.aptx.org/?a=commitdiff_plain;h=2b24b889dba07e7619ce789f230a94d33392db0e;p=openlase.git New Python bindings via Cython --- diff --git a/CMakeLists.txt b/CMakeLists.txt index c8f5f11..4f864c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ endif() find_package(Threads REQUIRED) find_package(JACK REQUIRED) +find_package(PythonInterp REQUIRED) find_package(Qt4) find_package(FFmpeg) find_package(OpenGL) @@ -46,4 +47,5 @@ add_definitions(-Wall) add_subdirectory (libol) add_subdirectory (output) add_subdirectory (tools) +add_subdirectory (python) add_subdirectory (examples) diff --git a/examples/27c3_slides/CMakeLists.txt b/examples/27c3_slides/CMakeLists.txt index 636d60e..5140fd0 100644 --- a/examples/27c3_slides/CMakeLists.txt +++ b/examples/27c3_slides/CMakeLists.txt @@ -35,7 +35,7 @@ if(CURSES_FOUND AND FFMPEG_FOUND) DEPENDS ${CMAKE_SOURCE_DIR}/tools/svg2ild.py MAIN_DEPENDENCY ${NAME}.svg DEPENDS ${NAME}.svg ${NAME}.cfg - COMMAND python ${CMAKE_SOURCE_DIR}/tools/svg2ild.py -q ${ARGN} -cfg ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.cfg ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.svg ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.ild) + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/svg2ild.py -q ${ARGN} -cfg ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.cfg ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.svg ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.ild) endfunction() svg2ild(openlase-logo -noopt) diff --git a/examples/harp2.py b/examples/harp2.py new file mode 100644 index 0000000..f3ebff2 --- /dev/null +++ b/examples/harp2.py @@ -0,0 +1,185 @@ +# OpenLase - a realtime laser graphics toolkit +# +# Copyright (C) 2009-2011 Hector Martin "marcan" +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 or version 3. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# This is the laser harp sensing portion, which has nothing to do with OpenLase. +# You need OpenCV (2.2.0) and PyALSA installed +# Pass the destination ALSA MIDI client:port pair as an argument. + +# You may need to edit some constants here + +THRESHOLD=60 +WIDTH=320 +HEIGHT=240 + +VELOCITY=90 + +import sys, math +import cv + +from pyalsa import alsaseq +import pylase as ol +import threading, time + +class LaserThread(threading.Thread): + def __init__(self): + threading.Thread.__init__(self) + self.die = False + self.dots = [] + + def run(self): + ol.init() + params = ol.RenderParams() + params.render_flags = ol.RENDER_NOREORDER | ol.RENDER_GRAYSCALE + ol.setRenderParams(params) + + while not self.die: + ol.loadIdentity() + for x,y in self.dots: + ol.dot((x,y), 30, ol.C_WHITE) + + ol.renderFrame(100) + ol.shutdown() + +seq = alsaseq.Sequencer(name="default", clientname=sys.argv[0], streams = alsaseq.SEQ_OPEN_DUPLEX, mode = alsaseq.SEQ_NONBLOCK) +port = seq.create_simple_port( + name='out', + type = alsaseq.SEQ_PORT_TYPE_MIDI_GENERIC | alsaseq.SEQ_PORT_TYPE_APPLICATION, + caps = alsaseq.SEQ_PORT_CAP_READ | alsaseq.SEQ_PORT_CAP_SUBS_READ) + +def note(n, state=False): + if state: + etype = alsaseq.SEQ_EVENT_NOTEON + else: + etype = alsaseq.SEQ_EVENT_NOTEOFF + event = alsaseq.SeqEvent(type=etype) + event.set_data({'note.channel': 0, 'note.note': n, 'note.velocity': 90}) + seq.output_event(event) + seq.drain_output() + +if len(sys.argv) > 1: + toport = seq.parse_address(sys.argv[1]) + seq.connect_ports((seq.client_id, port), toport) + +def getpoints(image): + points = [] + cv.CvtColor(image, grey, cv.CV_RGB2GRAY) + cv.Threshold(grey, grey, THRESHOLD, 255, cv.CV_THRESH_BINARY) + cv.Copy(grey, grey2) + + storage = cv.CreateMemStorage(0) + contour = cv.FindContours(grey, storage, cv.CV_RETR_CCOMP, cv.CV_CHAIN_APPROX_SIMPLE) + while contour: + bound_rect = cv.BoundingRect(list(contour)) + contour = contour.h_next() + + pt = (bound_rect[0] + bound_rect[2]/2, bound_rect[1] + bound_rect[3]/2) + #cv.Circle(image, pt, 2, cv.CV_RGB(255,0,0), 1) + points.append(pt) + return points + +def near(p1, p2, d): + x,y = (p1[0]-p2[0],p1[1]-p2[1]) + dist = math.sqrt(x**2+y**2) + return dist < d + +oldstate = None + +olt = LaserThread() +print "Starting thread" + +v_off = -0.1 + +n_start = 47 +n_end = 47 + 25 +n_off = 0 + +offsets = [0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0] +xpos = [0, 0.5, 1, 1.5, 2, 3, 3.5, 4, 4.5, 5, 5.5, 6] + +def gxpos(x): + o = x // 12 + v = x % 12 + return xpos[v] + o * 7 + +dots = [] + +xstart = gxpos(n_start) +xend = gxpos(n_end) + +for n in range(n_start, n_end+1): + ld = (n + n_off) % len(offsets) + off = offsets[ld] * v_off + x = 2 * (gxpos(n + n_off) - xstart) / float(xend - xstart) + x -= 1.0 + x *= 0.99 + dots.append((-x, off)) + +olt.dots = dots + +time.sleep(1) +camera = cv.CreateCameraCapture(0) +cv.SetCaptureProperty(camera, cv.CV_CAP_PROP_FRAME_WIDTH, WIDTH) +cv.SetCaptureProperty(camera, cv.CV_CAP_PROP_FRAME_HEIGHT, HEIGHT) +cv.SetCaptureProperty(camera, cv.CV_CAP_PROP_BRIGHTNESS, 0) + +image = cv.QueryFrame(camera) +image = cv.QueryFrame(camera) +image = cv.QueryFrame(camera) + +grey = cv.CreateImage(cv.GetSize(image), cv.IPL_DEPTH_8U, 1) +grey2 = cv.CreateImage(cv.GetSize(image), cv.IPL_DEPTH_8U, 1) + + +olt.start() +print "Thread running" + +try: + for i in range(30): + image = cv.QueryFrame(camera) + refpoints = getpoints(image) + refpoints.sort(key=lambda x: -x[0]) + + print len(refpoints), n_end - n_start + 1 + + while True: + image = cv.QueryFrame(camera) + cpoints = getpoints(image) + state = [False]*len(refpoints) + for i, rp in enumerate(refpoints): + for cp in cpoints: + if near(rp,cp,4): + break + else: + state[i] = True + + if oldstate is not None: + for i,(j,k) in enumerate(zip(oldstate, state)): + if j != k: + note(n_start+len(oldstate)-i, k) + if k: + print "PRESSED: %d"%i + else: + print "RELEASED: %d"%i + oldstate = state + + cv.ShowImage("thresholded", grey2) + if cv.WaitKey(10)&0xfff == 27: + break +except: + olt.die = True + olt.join() + raise diff --git a/examples/showtext.py b/examples/showtext.py new file mode 100644 index 0000000..0a2a86a --- /dev/null +++ b/examples/showtext.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# OpenLase - a realtime laser graphics toolkit +# +# Copyright (C) 2009-2011 Hector Martin "marcan" +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 or version 3. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import pylase as ol + +import sys + +if ol.init(10) < 0: + sys.exit(1) +params = ol.RenderParams() +params.render_flags = ol.RENDER_NOREORDER | ol.RENDER_GRAYSCALE +params.on_speed = 2/120.0 +params.off_speed = 2/30.0 +params.flatness = 0.000001 +ol.setRenderParams(params) + +lines = sys.argv[1:] + +while True: + lc = len(lines) + + font = ol.getDefaultFont() + yoff = (lc/2.0) * 0.3 + + for i,line in enumerate(lines): + w = ol.getStringWidth(font, 0.3, line) + ol.drawString(font, (-w/2,yoff-i*0.3), 0.3, ol.C_WHITE, line) + + ftime = ol.renderFrame(60) diff --git a/examples/simple.py b/examples/simple.py new file mode 100644 index 0000000..da63a3a --- /dev/null +++ b/examples/simple.py @@ -0,0 +1,77 @@ +# OpenLase - a realtime laser graphics toolkit +# +# Copyright (C) 2009-2011 Hector Martin "marcan" +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 or version 3. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import pylase as ol +from math import pi + +ol.init() + +time = 0 +frames = 0 + +while True: + ol.loadIdentity3() + ol.loadIdentity() + + font = ol.getDefaultFont() + s = "Hi!" + w = ol.getStringWidth(font, 0.2, s) + ol.drawString(font, (-w/2,0.1), 0.2, ol.C_WHITE, s) + + ol.perspective(60, 1, 1, 100) + ol.translate3((0, 0, -3)) + + for i in range(2): + ol.scale3((0.6, 0.6, 0.6)) + ol.rotate3Z(time * pi * 0.1) + ol.rotate3X(time * pi * 0.8) + ol.rotate3Y(time * pi * 0.73) + + ol.begin(ol.LINESTRIP) + ol.vertex3((-1, -1, -1), ol.C_WHITE) + ol.vertex3(( 1, -1, -1), ol.C_WHITE) + ol.vertex3(( 1, 1, -1), ol.C_WHITE) + ol.vertex3((-1, 1, -1), ol.C_WHITE) + ol.vertex3((-1, -1, -1), ol.C_WHITE) + ol.vertex3((-1, -1, 1), ol.C_WHITE) + ol.end() + + ol.begin(ol.LINESTRIP); + ol.vertex3(( 1, 1, 1), ol.C_WHITE) + ol.vertex3((-1, 1, 1), ol.C_WHITE) + ol.vertex3((-1, -1, 1), ol.C_WHITE) + ol.vertex3(( 1, -1, 1), ol.C_WHITE) + ol.vertex3(( 1, 1, 1), ol.C_WHITE) + ol.vertex3(( 1, 1, -1), ol.C_WHITE) + ol.end() + + ol.begin(ol.LINESTRIP) + ol.vertex3(( 1, -1, -1), ol.C_WHITE) + ol.vertex3(( 1, -1, 1), ol.C_WHITE) + ol.end() + + ol.begin(ol.LINESTRIP) + ol.vertex3((-1, 1, 1), ol.C_WHITE) + ol.vertex3((-1, 1, -1), ol.C_WHITE) + ol.end() + + ftime = ol.renderFrame(60) + frames += 1 + time += ftime + print "Frame time: %f, FPS:%f"%(ftime, frames/time) + +ol.shutdown() diff --git a/libol/CMakeLists.txt b/libol/CMakeLists.txt index 3e26145..5a848e9 100644 --- a/libol/CMakeLists.txt +++ b/libol/CMakeLists.txt @@ -25,4 +25,4 @@ target_link_libraries (openlase ${CMAKE_THREAD_LIBS_INIT} m jack) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fontdef.c DEPENDS ${CMAKE_SOURCE_DIR}/tools/genfont.py MAIN_DEPENDENCY laserfont.svg - COMMAND python ${CMAKE_SOURCE_DIR}/tools/genfont.py ${CMAKE_CURRENT_SOURCE_DIR}/laserfont.svg ${CMAKE_CURRENT_BINARY_DIR}/fontdef.c default_font) + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/genfont.py ${CMAKE_CURRENT_SOURCE_DIR}/laserfont.svg ${CMAKE_CURRENT_BINARY_DIR}/fontdef.c default_font) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt new file mode 100644 index 0000000..61dd925 --- /dev/null +++ b/python/CMakeLists.txt @@ -0,0 +1,23 @@ +find_package(PythonLibs) +find_program(CYTHON_EXECUTABLE cython) + +if(CYTHON_EXECUTABLE MATCHES "NOTFOUND" OR NOT PYTHONLIBS_FOUND) + message(STATUS "Will NOT build python bindings (python libs or cython missing)") +else() + execute_process(COMMAND + ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" + OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE) + + add_custom_command(OUTPUT pylase.c + MAIN_DEPENDENCY pylase.pyx + COMMAND ${CYTHON_EXECUTABLE} -I ${CMAKE_SOURCE_DIR}/include -o pylase.c "${CMAKE_CURRENT_SOURCE_DIR}/pylase.pyx") + list(APPEND ADDITIONAL_MAKE_CLEAN_FILES pylase.c) + + include_directories(${PYTHON_INCLUDE_PATH} ${CMAKE_SOURCE_DIR}/include) + add_library(pylase MODULE pylase.c) + set_target_properties(pylase PROPERTIES + PREFIX "" + OUTPUT_NAME "pylase" + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(pylase openlase) +endif() diff --git a/python/pylase.pyx b/python/pylase.pyx new file mode 100644 index 0000000..7711ff7 --- /dev/null +++ b/python/pylase.pyx @@ -0,0 +1,482 @@ +# OpenLase - a realtime laser graphics toolkit +# +# Copyright (C) 2009-2011 Hector Martin "marcan" +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 or version 3. +# +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from libc.stdint cimport * + +cdef extern from "libol.h": + enum: + OL_LINESTRIP + OL_BEZIERSTRIP + OL_POINTS + enum: + _RENDER_GRAYSCALE "RENDER_GRAYSCALE" + _RENDER_NOREORDER "RENDER_NOREORDER" + _RENDER_NOREVERSE "RENDER_NOREVERSE" + + ctypedef struct OLRenderParams: + int rate + float on_speed + float off_speed + int start_wait + int start_dwell + int curve_dwell + int corner_dwell + int end_dwell + int end_wait + float curve_angle + float flatness + float snap + int render_flags + int min_length + int max_framelen + + ctypedef struct OLFrameInfo "OLFrameInfo": + int objects + int points + int resampled_points + int resampled_blacks + int padding_points + + int olInit(int buffer_count, int max_points) + + void olSetRenderParams(OLRenderParams *params) + void olGetRenderParams(OLRenderParams *params) + + ctypedef void (*AudioCallbackFunc)(float *leftbuf, float *rightbuf, int samples) + + void olSetAudioCallback(AudioCallbackFunc f) + + void olLoadIdentity() + void olPushMatrix() + void olPopMatrix() + + void olMultMatrix(float m[9]) + void olRotate(float theta) + void olTranslate(float x, float y) + void olScale(float sx, float sy) + + void olLoadIdentity3() + void olPushMatrix3() + void olPopMatrix3() + + void olMultMatrix3(float m[16]) + void olRotate3X(float theta) + void olRotate3Y(float theta) + void olRotate3Z(float theta) + void olTranslate3(float x, float y, float z) + void olScale3(float sx, float sy, float sz) + + void olFrustum (float left, float right, float bot, float ttop, float near, float far) + void olPerspective(float fovy, float aspect, float zNear, float zFar) + + void olResetColor() + void olMultColor(uint32_t color) + void olPushColor() + void olPopColor() + + void olBegin(int prim) + void olVertex(float x, float y, uint32_t color) + void olVertex3(float x, float y, float z, uint32_t color) + void olEnd() + + void olTransformVertex3(float *x, float *y, float *z) + + ctypedef void (*ShaderFunc)(float *x, float *y, uint32_t *color) + ctypedef void (*Shader3Func)(float *x, float *y, float *z, uint32_t *color) + + void olSetVertexPreShader(ShaderFunc f) + void olSetVertexShader(ShaderFunc f) + void olSetVertex3Shader(Shader3Func f) + + void olSetPixelShader(ShaderFunc f) + + void olRect(float x1, float y1, float x2, float y2, uint32_t color) + void olLine(float x1, float y1, float x2, float y2, uint32_t color) + void olDot(float x, float y, int points, uint32_t color) + + float olRenderFrame(int max_fps) nogil + + void olGetFrameInfo(OLFrameInfo *info) + + void olShutdown() + + void olSetScissor (float x0, float y0, float x1, float y1) + + void olLog(char *fmt, ...) + + ctypedef char* const_char_ptr "const char*" + ctypedef void (*LogCallbackFunc)(char *msg) + + void olSetLogCallback(LogCallbackFunc f) + +LINESTRIP = OL_LINESTRIP +BEZIERSTRIP = OL_BEZIERSTRIP +POINTS = OL_POINTS + +RENDER_GRAYSCALE = _RENDER_GRAYSCALE +RENDER_NOREORDER = _RENDER_NOREORDER +RENDER_NOREVERSE = _RENDER_NOREVERSE + +C_RED = 0xff0000 +C_GREEN = 0x00ff00 +C_BLUE = 0x0000ff +C_WHITE = 0xffffff + +cpdef uint32_t C_GREY(uint8_t x): + return 0x010101 * x + +cdef class RenderParams: + cdef public int rate + cdef public float on_speed + cdef public float off_speed + cdef public int start_wait + cdef public int start_dwell + cdef public int curve_dwell + cdef public int corner_dwell + cdef public int end_dwell + cdef public int end_wait + cdef public float curve_angle + cdef public float flatness + cdef public float snap + cdef public int render_flags + cdef public int min_length + cdef public int max_framelen + def __init__(self): + self.rate = 48000 + self.on_speed = 2/100.0 + self.off_speed = 1/30.0 + self.start_wait = 8 + self.start_dwell = 3 + self.curve_dwell = 0 + self.corner_dwell = 6 + self.end_dwell = 3 + self.end_wait = 7 + self.curve_angle = 0.866 + self.flatness = 0.00001 + self.snap = 0.00001 + self.render_flags = RENDER_GRAYSCALE + self.min_length = 0 + self.max_framelen = 0 + +cpdef setRenderParams(params): + cdef OLRenderParams cparams + cparams.rate = params.rate + cparams.on_speed = params.on_speed + cparams.off_speed = params.off_speed + cparams.start_wait = params.start_wait + cparams.start_dwell = params.start_dwell + cparams.curve_dwell = params.curve_dwell + cparams.corner_dwell = params.corner_dwell + cparams.end_dwell = params.end_dwell + cparams.end_wait = params.end_wait + cparams.curve_angle = params.curve_angle + cparams.flatness = params.flatness + cparams.snap = params.snap + cparams.render_flags = params.render_flags + cparams.min_length = params.min_length + cparams.max_framelen = params.max_framelen + olSetRenderParams(&cparams) + +cpdef getRenderParams(): + cdef OLRenderParams params + olGetRenderParams(¶ms) + pyparams = RenderParams() + pyparams.rate = params.rate + pyparams.on_speed = params.on_speed + pyparams.off_speed = params.off_speed + pyparams.start_wait = params.start_wait + pyparams.start_dwell = params.start_dwell + pyparams.curve_dwell = params.curve_dwell + pyparams.corner_dwell = params.corner_dwell + pyparams.end_dwell = params.end_dwell + pyparams.end_wait = params.end_wait + pyparams.curve_angle = params.curve_angle + pyparams.flatness = params.flatness + pyparams.snap = params.snap + pyparams.render_flags = params.render_flags + pyparams.min_length = params.min_length + pyparams.max_framelen = params.max_framelen + return pyparams + +cpdef int init(int buffer_count=4, int max_points=30000): + cdef int ret = olInit(buffer_count, max_points) + if ret < 0: + return ret + setRenderParams(RenderParams()) + return ret + +cpdef loadIdentity(): olLoadIdentity() +cpdef pushMatrix(): olPushMatrix() +cpdef popMatrix(): olPopMatrix() + +cpdef multMatrix(object m): + if len(m) == 3: + m = m[0] + m[1] + m[2] + cdef float cm[9] + for i in range(9): + cm[i] = m[i] + olMultMatrix(cm) + +cpdef rotate(float theta): olRotate(theta) +cpdef translate(tuple coord): + x, y = coord + olTranslate(x, y) +cpdef scale(tuple coord): + x, y = coord + olScale(x, y) + +_py_audiocb = None +cdef void _audiocb(float *l, float *r, int samples) with gil: + global _py_audiocb + if _py_audiocb is not None: + buf = _py_audiocb(samples) + for i in range(min(len(buf), samples)): + l[i], r[i] = buf[i] + if len(buf) < samples: + for i in range(len(buf), samples): + l[i] = r[i] = 0 + +cpdef setAudioCallback(object func): + global _py_audiocb + _py_audiocb = func + if func is not None: + olSetAudioCallback(_audiocb) + else: + olSetAudioCallback(NULL) + +cpdef loadIdentity3(): olLoadIdentity3() +cpdef pushMatrix3(): olPushMatrix3() +cpdef popMatrix3(): olPopMatrix3() + +cpdef multMatrix3(object m): + if len(m) == 4: + m = m[0] + m[1] + m[2] + m[3] + cdef float cm[16] + for i in range(16): + cm[i] = m[i] + olMultMatrix(cm) + +cpdef rotate3X(float theta): olRotate3X(theta) +cpdef rotate3Y(float theta): olRotate3Y(theta) +cpdef rotate3Z(float theta): olRotate3Z(theta) +cpdef translate3(tuple coord): + x, y, z = coord + olTranslate3(x, y, z) +cpdef scale3(tuple coord): + x, y, z = coord + olScale3(x, y, z) + +cpdef frustum(float left, float right, float bot, float top, float near, float far): + olFrustum(left, right, bot, top, near, far) +cpdef perspective(float fovy, float aspect, float zNear, float zFar): + olPerspective(fovy, aspect, zNear, zFar) + +cpdef resetColor(): olResetColor() +cpdef multColor(uint32_t color): olMultColor(color) +cpdef pushColor(): olPushColor() +cpdef popColor(): olPopColor() + +cpdef begin(int prim): olBegin(prim) +cpdef vertex(tuple coord, uint32_t color): + x, y = coord + olVertex(x, y, color) +cpdef vertex3(tuple coord, uint32_t color): + x, y, z = coord + olVertex3(x, y, z, color) +cpdef end(): olEnd() + +cpdef tuple transformVertex3(float x, float y, float z): + olTransformVertex3(&x, &y, &z) + return x, y, z + +_py_vpreshader = None +cdef void _vpreshader(float *x, float *y, uint32_t *color) with gil: + global _py_vpreshader + if _py_vpreshader is not None: + (x[0], y[0]), color[0] = _py_vpreshader((x[0], y[0]), color[0]) + +_py_vshader = None +cdef void _vshader(float *x, float *y, uint32_t *color) with gil: + global _py_vshader + if _py_vshader is not None: + (x[0], y[0]), color[0] = _py_vshader((x[0], y[0]), color[0]) + +_py_v3shader = None +cdef void _v3shader(float *x, float *y, float *z, uint32_t *color) with gil: + global _py_v3shader + if _py_v3shader is not None: + (x[0], y[0], z[0]), color[0] = _py_v3shader((x[0], y[0], z[0]), color[0]) + +_py_pshader = None +cdef void _pshader(float *x, float *y, uint32_t *color) with gil: + global _py_pshader + if _py_pshader is not None: + (x[0], y[0]), color[0] = _py_pshader((x[0], y[0]), color[0]) + +cpdef setVertexPreShader(object func): + global _py_vpreshader + _py_vpreshader = func + if func is not None: + olSetVertexPreShader(_vpreshader) + else: + olSetVertexPreShader(NULL) + +cpdef setVertexShader(object func): + global _py_vshader + _py_vshader = func + if func is not None: + olSetVertexShader(_vshader) + else: + olSetVertexShader(NULL) + +cpdef setVertex3Shader(object func): + global _py_v3shader + _py_v3shader = func + if func is not None: + olSetVertex3Shader(_v3shader) + else: + olSetVertex3Shader(NULL) + +cpdef setPixelShader(object func): + global _py_pshader + _py_pshader = func + if func is not None: + olSetPixelShader(_pshader) + else: + olSetPixelShader(NULL) + +cpdef rect(tuple start, tuple end, uint32_t color): + x1, y1 = start + x2, y2 = end + olRect(x1, y1, x2, y2, color) + +cpdef line(tuple start, tuple end, uint32_t color): + x1, y1 = start + x2, y2 = end + olLine(x1, y1, x2, y2, color) + +cpdef dot(tuple coord, int points, uint32_t color): + x, y = coord + olDot(x, y, points, color) + +cpdef float renderFrame(int max_fps): + cdef float ret + with nogil: + ret = olRenderFrame(max_fps) + return ret + +cdef class FrameInfo: + cdef readonly int objects + cdef readonly int points + cdef readonly int resampled_points + cdef readonly int resampled_blocks + cdef readonly int padding_points + +cpdef getFrameInfo(): + cdef OLFrameInfo info + olGetFrameInfo(&info) + pyinfo = FrameInfo() + pyinfo.objects = info.objects + pyinfo.points = info.points + pyinfo.resampled_points = info.resampled_points + pyinfo.resampled_blocks = info.resampled_blocks + pyinfo.padding_points = info.padding_points + return pyinfo + +cpdef shutdown(): olShutdown() + +cpdef setScissor(tuple start, tuple end): + x1, y1 = start + x2, y2 = end + olSetScissor(x1, y1, x2, y2) + +_py_logcb = None +cdef void _logcb(const_char_ptr msg): + global _py_logcb + cdef bytes msg2 = msg + if _py_logcb is not None: + _py_logcb(msg2) + +cpdef setLogCallback(object func): + global _py_logcb + _py_logcb = func + if func is not None: + olSetLogCallback(_logcb) + else: + olSetLogCallback(NULL) + +cdef extern from "text.h": + ctypedef struct _Font "Font" + + _Font *olGetDefaultFont() + float olGetCharWidth(_Font *fnt, char c) + float olGetStringWidth(_Font *fnt, float height, char *s) + float olGetCharOverlap(_Font *font, float height) + float olDrawChar(_Font *fnt, float x, float y, float height, uint32_t color, char c) + float olDrawString(_Font *fnt, float x, float y, float height, uint32_t color, char *s) + +cdef class Font: + cdef _Font *font + +cpdef getDefaultFont(): + f = Font() + f.font = olGetDefaultFont() + return f + +cpdef float getCharWidth(object font, char c): + cdef Font fnt = font + return olGetCharWidth(fnt.font, c) +cpdef float getStringWidth(object font, float height, char *s): + cdef Font fnt = font + return olGetStringWidth(fnt.font, height, s) +cpdef float getCharOverlap(object font, float height): + cdef Font fnt = font + return olGetCharOverlap(fnt.font, height) +cpdef float drawChar(object font, tuple coord, float height, uint32_t color, char c): + cdef Font fnt = font + x, y = coord + return olDrawChar(fnt.font, x, y, height, color, c) +cpdef float drawString(object font, tuple coord, float height, uint32_t color, char *s): + cdef Font fnt = font + x, y = coord + return olDrawString(fnt.font, x, y, height, color, s) + +cdef extern from "ilda.h": + ctypedef struct _IldaFile "IldaFile" + + _IldaFile *olLoadIlda(char *filename) + void olDrawIlda(_IldaFile *ild) + void olDrawIlda3D(_IldaFile *ild) + void olFreeIlda(_IldaFile *ild) + +cdef class IldaFile: + cdef _IldaFile *ilda + def __del__(self): + olFreeIlda(self.ilda) + +cpdef loadIlda(char *file): + f = IldaFile() + f.ilda = olLoadIlda(file) + return f + +cpdef drawIlda(object ilda): + cdef IldaFile f = ilda + olDrawIlda(f.ilda) + +cpdef drawIlda3D(object ilda): + cdef IldaFile f = ilda + olDrawIlda3D(f.ilda)