Python Forum
simple bounding box for opengl use.
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
simple bounding box for opengl use.
#1
import numpy as np

class BoxProperty:
    def __init__(self, pos, pos2=None, div=False):
        self.pos = pos
        self.pos2 = pos2
        self.div = [1.0, 0.5][div]

    def __get__(self, instance, owner):
        if self.pos2 is None:
            return instance[self.pos]
        return instance[self.pos] + instance[self.pos2] * self.div

    def __set__(self, instance, value):
        if self.pos2 is None:
            instance[self.pos] = value
        else:
            instance[self.pos] = value - instance[self.pos2] * self.div

class BoxCombineProperty:
    def __init__(self, pos1, pos2, pos3):
        if isinstance(pos1, (tuple, list)):
            self.pos1 = BoxProperty(*pos1)
        else:
            self.pos1 = BoxProperty(pos1)

        if isinstance(pos2, (tuple, list)):
            self.pos2 = BoxProperty(*pos2)
        else:
            self.pos2 = BoxProperty(pos2)

        if isinstance(pos3, (tuple, list)):
            self.pos3 = BoxProperty(*pos3)
        else:
            self.pos3 = BoxProperty(pos3)

    def __get__(self, instance, owner):
        return (self.pos1.__get__(instance, owner),
            self.pos2.__get__(instance, owner),
            self.pos3.__get__(instance, owner))

    def __set__(self, instance, value):
        self.pos1.__set__(instance, value[0])
        self.pos2.__set__(instance, value[1])
        self.pos3.__set__(instance, value[2])

class ArrayProperty:
    def __init__(self, position):
        self.position = position

    def __get__(self, instance, owner):
        return instance[self.position]

    def __set__(self, instance, value):
        instance[self.position] = value

class BoundingBox(np.ndarray):
    def __new__(cls, x, y, z, w, h, d):
        return np.asarray((x, y, z, w, h, d)).view(cls)

    def collidepoint(self, x, y=None, z=None):
        if y is None:
            x, y, z = x

        if (self.left < x < self.right and
            self.top < y < self.bottom and
            self.front < z < self.back):
            return True
        return False

    def collidebox(self, box):
        return ( ((self[0] > box[0] and self[0] < box[3] + box[0]) or
                  (box[0] > self[0] and box[0] < self[3] + self[0])) and
                 ((self[1] > box[1] and self[1] < box[4] + box[1]) or
                  (box[1] > self[1] and box[1] < self[4] + self[1])) and
                 ((self[2] > box[2] and self[2] < box[5] + box[2]) or
                  (box[2] > self[2] and box[2] < self[5] + self[2])))

        #return ( ((self.left > box.left and self.left < box.right) or
        #          (box.left > self.left and box.left < self.right)) and
        #         ((self.top > box.top and self.top < box.bottom) or
        #          (box.top > self.top and box.top < self.bottom)) and
        #         ((self.front > box.front and self.front < box.back) or
        #          (box.front > self.front and box.front < self.back)))

    def _clamp(self, box):
        x, y, z = self[:3]
        clamp = 'xyz'

        if self[3] >= box[3]:
            x = box[0] + box[3] / 2 - self[3] / 2
        elif self[0] < box[0]:
            x = box[0]
        elif self[0] + self[3] > box[0] + box[3]:
            x = box[0] + box[3] - self[3]
        else:
            clamp = 'yz'

        if self[4] >= box[4]:
            y = box[1] + box[4] / 2 - self[4] / 2
        elif self[1] < box[1]:
            y = box[1]
        elif self[1] + self[4] > box[1] + box[4]:
            y = box[1] + box[4] - self[4]
        else:
            if clamp == 'yz':
                clamp = 'z'
            else:
                clamp = 'xz'

        if self[5] >= box[5]:
            z = box[2] + box[5] / 2 - self[5] / 2
        elif self[2] < box[2]:
            z = box[2]
        elif self[2] + self[5] > box[2] + box[5]:
            z = box[2] + box[5] - self[5]
        else:
            if clamp == 'z':
                clamp = None
            elif clamp == 'yz':
                clamp = 'y'
            elif clamp == 'xz':
                clamp = 'x'
            else:
                clamp = 'xy'

        return x, y, z, clamp

    def clamp(self, box):
        c = self._clamp(box)
        return BoundingBox(*c[:3], *self[3:]), c[3]

    def clamp_ip(self, box):
        c = self._clamp(box)
        self[:3] = c[:3]
        return c[3]

    x = ArrayProperty(0)
    y = ArrayProperty(1)
    z = ArrayProperty(2)
    w = ArrayProperty(3)
    h = ArrayProperty(4)
    d = ArrayProperty(5)

    left = ArrayProperty(0)
    top = ArrayProperty(1)
    front = ArrayProperty(2)
    right = BoxProperty(0, 3)
    bottom = BoxProperty(1, 4)
    back = BoxProperty(2, 5)

    topleft_front = BoxCombineProperty(0, 1, 2)
    topright_front = BoxCombineProperty((0, 3), 1, 2)
    bottomleft_front = BoxCombineProperty(0, (1, 4), 2)
    bottomright_front = BoxCombineProperty((0, 3), (1, 4), 2)
    topleft_back = BoxCombineProperty(0, 1, (2, 5))
    topright_back = BoxCombineProperty((0, 3), 1, (2, 5))
    bottomleft_back = BoxCombineProperty(0, (1, 4), (2, 5))
    bottomright_back = BoxCombineProperty((0, 3), (1, 4), (2, 5))

    center = BoxCombineProperty((0, 3, 1), (1, 4, 1), (2, 5, 1))
    boxsize = BoxCombineProperty(3, 4, 5)
    centerx = BoxProperty(0, 3, 1)
    centery = BoxProperty(1, 4, 1)
    centerz = BoxProperty(2, 5, 1)

def main():
    a = BoundingBox(10,10,10,50,50,50)
    b = BoundingBox(40,40,40,30,30,30)
    c = BoundingBox(10,60,10,50,50,50)
    print(a)
    print(a.collidebox(b))
    print(a.collidebox(c))
    print(b.collidebox(c))
    print(a.collidepoint(45, 20, 45))
    print(b.collidepoint(45, 20, 45))

    print()
    #a[:3] -= 20 # move in place
    print(a)
    screen = BoundingBox(0,0,50,800,600,250)
    clamp = a.clamp_ip(screen)
    print(a, clamp)
    print(screen)
    print(screen.center)

if __name__ == '__main__':
    main()
Example pyglet
import pyglet
from pyglet.gl import *
from pyglet.graphics.vertexbuffer import create_buffer
from boundingbox import BoundingBox
from random import randrange
import numpy as np
import ctypes
import math
import os

#           base on gl3n row major
def perspective(width, height, fov, near, far):
    array = np.array([0 for i in range(16)], dtype=GLfloat).reshape(4,4)
    mat = np.matrix(array)
    aspect = width/height
    top = near * math.tan(fov * (math.pi/360.0))
    bottom = -top
    right = top * aspect
    left = -right

    mat[0,0] = (2 * near) / (right - left)
    mat[0,2] = (right + left) / (right - left)
    mat[1,1] = (2 * near) / (top - bottom)
    mat[1,2] = (top + bottom) / (top - bottom)
    mat[2,2] = -(far + near) / (far - near)
    mat[2,3] = -(2 * far + near)  / (far - near)
    mat[3,2] = -1
    return mat

def normalized(array):
    if np.linalg.norm(array) != 0:
        return array / np.linalg.norm(array)
    return array

def matrix_idenity():
    return np.matrix(np.identity(4, GLfloat))

def look_at(eye, target, up):
    look_dir = normalized(target - eye)
    up_dir = normalized(up)
    right_dir = normalized(np.cross(look_dir, up_dir))
    perp_up_dir = np.cross(right_dir, look_dir)

    mat = matrix_idenity()
    mat[0] = np.append(right_dir, [-np.dot(eye, right_dir)])
    mat[1] = np.append(perp_up_dir, [-np.dot(eye, perp_up_dir)])
    mat[2] = np.append(-look_dir, [np.dot(eye, look_dir)])

    return mat

def unit_vector(data):
    data = np.array(data, dtype=GLfloat, copy=True)
    if data.ndim == 1:
        data /= math.sqrt(np.dot(data, data))
        return data

def rotation(alpha, axis):
    cosa = math.cos(alpha)
    sina = math.sin(alpha)
    axis = unit_vector(axis)
    R = np.diag([cosa, cosa, cosa])
    R += np.outer(axis, axis) * (1.0 - cosa)
    axis *= sina
    R += np.array([[0.0, -axis[2], axis[1]],
                   [axis[2], 0.0, -axis[0]],
                   [-axis[1], axis[0], 0.0]], GLfloat)
    M = np.identity(4)
    M[:3, :3] = R
    return M

class Face:
    FRONT = 1     # counter clockwise
    BACK = 2
    LEFT = 4     # counter clockwise
    RIGHT = 8
    TOP = 16     # counter clockwise
    BOTTOM = 32
    ALL = 63

def create_cube(size, face=Face.ALL, element=True):
    array = np.array([
    size, size, size,       #0  + + + right   top      front
    -size, -size, -size,    #1  - - - left    bottom   back
    size, -size, -size,     #2  + - - right   bottom   back
    size, size, -size,      #3  + + - right   top      back
    -size, size, -size,     #4  - + - left    top      back
    -size, size, size,      #5  - + + left    top      front
    -size, -size, size,     #6  - - + left    bottom   front
    size, -size, size       #7  + - + right   bottom   front
    ], GLfloat)

    elements = np.array([], GLuint)
    if face & Face.BACK:
        elements = np.append(elements, [1,3,2,3,1,4])
    if face & Face.FRONT:
        elements = np.append(elements, [6,7,0,0,5,6])
    if face & Face.LEFT:
        elements = np.append(elements, [5,4,1,1,6,5])
    if face & Face.RIGHT:
        elements = np.append(elements, [0,2,3,2,0,7])
    if face & Face.TOP:
        elements = np.append(elements, [4,0,3,0,4,5])
    if face & Face.BOTTOM:
        elements = np.append(elements, [1,2,7,7,6,1])

    if element:
        return array, elements

    pylist = []
    for i in elements:
        n = i * 3
        pylist.extend(array[n:n + 3])

    return np.array(pylist, GLfloat)

class Shader:
    def __init__(self, vstring, fstring):
        self.program = GLuint(glCreateProgram())

        if not os.path.exists(vstring):
            print(vstring, "doesn't exists")
            return

        if not os.path.exists(fstring):
            print(fstring, "doesn't exists")
            return

        vbuffer = open(vstring, 'r')
        vshader = glCreateShader(GL_VERTEX_SHADER)
        vbuff = ctypes.create_string_buffer(vbuffer.read().encode())
        vtext = ctypes.cast(ctypes.pointer(ctypes.pointer(vbuff)), ctypes.POINTER(ctypes.POINTER(GLchar)))
        glShaderSource(vshader, 1, vtext, None)
        glCompileShader(vshader)

        success = GLint()
        infoLog = ctypes.create_string_buffer(512)
        glGetShaderiv(vshader, GL_COMPILE_STATUS, ctypes.byref(success))
        if not success:
            glGetShaderInfoLog(vshader, 512, None, infoLog)
            print("Error: Vertex Shader ", infoLog.value)

        fbuffer = open(fstring, 'r')
        fshader = glCreateShader(GL_FRAGMENT_SHADER)
        fbuff = ctypes.create_string_buffer(fbuffer.read().encode())
        ftext = ctypes.cast(ctypes.pointer(ctypes.pointer(fbuff)), ctypes.POINTER(ctypes.POINTER(GLchar)))
        glShaderSource(fshader, 1, ftext, None)
        glCompileShader(fshader)

        glGetShaderiv(fshader, GL_COMPILE_STATUS, ctypes.byref(success))
        if not success:
            glGetShaderInfoLog(fshader, 512, None, infoLog)
            print("Error: Fragment Shader ", infoLog.value)

        glAttachShader(self.program, vshader)
        glAttachShader(self.program, fshader)
        glLinkProgram(self.program)

        glGetProgramiv(self.program, GL_LINK_STATUS, ctypes.byref(success))
        if not success:
            glGetShaderInfoLog(fshader, 512, None, infoLog)
            print("Error: Program ", infoLog.value)

        # clean up
        glDeleteShader(vshader)
        glDeleteShader(fshader)
        vbuffer.close()
        fbuffer.close()

    def uniformMatrix4fv(self, key, count, transpose, value):
        buff = ctypes.create_string_buffer(key.encode())
        location = glGetUniformLocation(self.program, buff)
        nvalue = np.array(value, GLfloat) # .flatten()
        nref = nvalue.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
        glUniformMatrix4fv(location, count, transpose, nref)

    def use(self):
        glUseProgram(self.program)

    def destroy(self):
        glDeleteProgram(self.program)

class CubeRandom:
    def __init__(self, w, h):
        ar = np.arange(0, 1, 0.1)
        self.box = BoundingBox(np.random.choice(ar), np.random.choice(ar),
                np.random.choice(ar), 0.1, 0.1, 0.1).astype(float)
        speed = np.arange(0, 0.05, 0.002)
        self.dir = np.array([np.random.choice(speed) for i in range(3)])

    def move(self, screenbox):
        screenbox = BoundingBox(0.0, 0.0, 0.0, 2.0, 2.0, 2.0)
        self.box[:3] += self.dir
        clamp = self.box.clamp_ip(screenbox)
        if clamp is None:
            return
        if 'x' in clamp:
            self.dir[0] = -self.dir[0]
        if 'y' in clamp:
            self.dir[1] = -self.dir[1]
        if 'z' in clamp:
            self.dir[2] = -self.dir[2]

class Window(pyglet.window.Window):
    def __init__(self):
        pyglet.window.Window.__init__(self)
        self.context.config.alpha_size = 8
        self.context.config.buffer_size = 32
        self.context.config.sample_buffers = 1
        self.context.config.samples = 4

        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LESS)
        glClearColor(0.1, 0.0, 0.0, 1.0)
        glViewport(0, 0, self.width, self.height)

        self.model = matrix_idenity()
        self.view = look_at(
            np.array([4,3,3], dtype=GLfloat),
            np.array([0,0,0], dtype=GLfloat),
            np.array([0,1,0], dtype=GLfloat))

        self.projection = perspective(self.width, self.height, 45.0, 1.0, 100.0)
        self.mvp = self.projection * self.view * self.model

        self.vertices = create_cube(0.1, element=False)
        print("How many vertices.", len(self.vertices) / 3)
        color_choice = [[1.0,0.0,0.0], [0.0,1.0,0.0], [0.0,0.0,1.0],
            [1.0,0.0,1.0], [1.0,1.0,0.0], [0.0,0.5,1.0]]
        colors = []
        for i in range(6):
            color = color_choice[i]
            colors.extend(color + color + color + color + color + color)
        self.colors = np.array(colors, GLfloat)
        print("How many colors.", len(self.colors) / 3)

        self.vao = GLuint()
        glGenVertexArrays(1, self.vao)
        glBindVertexArray(self.vao)

        self.vbo = create_buffer(self.vertices.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW)
        self.vbo.set_data(self.vertices.ctypes.data)
        self.vbo.bind()

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(0);

        self.color_vbo = create_buffer(self.colors.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW)
        self.color_vbo.set_data(self.colors.ctypes.data)
        self.color_vbo.bind()

        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(1);
        glBindVertexArray(0);

        self.tick = 0.0
        self.shader = Shader('vshader.glsl', 'fshader.glsl')
        pyglet.clock.schedule_interval(self.tick_update, 1.0 / 30.0)
        self.screenbox = BoundingBox(0,0,10, self.width, self.height, 100)
        self.cubes = [CubeRandom(self.width, self.height) for i in range(6)]

    def tick_update(self, dt):
        self.tick += dt
        #self.model = rotation(self.tick, np.array([0.2, 0.4, 0.2], GLfloat))
        for cube in self.cubes:
            cube.move(self.screenbox)
        #self.mvp = self.projection * self.view * self.model

    def on_draw(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        self.shader.use()
        #self.shader.uniformMatrix4fv('mvp', 1, GL_TRUE, self.mvp)

        glBindVertexArray(self.vao);
        for cube in self.cubes:
            model = np.identity(4)
            model[0::1, 3][:3] = cube.box[:3]
            mvp = self.projection * self.view * np.matrix(model)
            self.shader.uniformMatrix4fv('mvp', 1, GL_TRUE, mvp)
            glDrawArrays(GL_TRIANGLES, 0, len(self.vertices))
        glBindVertexArray(0)

    def clean_up(self):
        self.shader.destroy()
        self.vbo.delete()
        self.color_vbo.delete()
        glDeleteVertexArrays(1, self.vao)

if __name__ == '__main__':
    window = Window()
    pyglet.app.run()
    window.clean_up()
99 percent of computer problems exists between chair and keyboard.
Reply
#2
Made very small improvement
import numpy as np

class BoxProperty:
    def __init__(self, pos, pos2=None, div=False):
        self.pos = pos
        self.pos2 = pos2
        self.div = [1.0, 0.5][div]

    def __get__(self, instance, owner):
        if self.pos2 is None:
            return instance[self.pos]
        return instance[self.pos] + instance[self.pos2] * self.div

    def __set__(self, instance, value):
        if self.pos2 is None:
            instance[self.pos] = value
        else:
            instance[self.pos] = value - instance[self.pos2] * self.div

class BoxCombineProperty:
    def __init__(self, pos1, pos2, pos3):
        if isinstance(pos1, (tuple, list)):
            self.pos1 = BoxProperty(*pos1)
        else:
            self.pos1 = BoxProperty(pos1)

        if isinstance(pos2, (tuple, list)):
            self.pos2 = BoxProperty(*pos2)
        else:
            self.pos2 = BoxProperty(pos2)

        if isinstance(pos3, (tuple, list)):
            self.pos3 = BoxProperty(*pos3)
        else:
            self.pos3 = BoxProperty(pos3)

    def __get__(self, instance, owner):
        return (self.pos1.__get__(instance, owner),
            self.pos2.__get__(instance, owner),
            self.pos3.__get__(instance, owner))

    def __set__(self, instance, value):
        self.pos1.__set__(instance, value[0])
        self.pos2.__set__(instance, value[1])
        self.pos3.__set__(instance, value[2])

class ArrayProperty:
    def __init__(self, position):
        self.position = position

    def __get__(self, instance, owner):
        return instance[self.position]

    def __set__(self, instance, value):
        instance[self.position] = value

class BoundingBox(np.ndarray):
    def __new__(cls, x, y, z, w, h, d):
        return np.asarray((x, y, z, w, h, d)).view(cls)

    def collidepoint(self, x, y=None, z=None):
        if y is None:
            x, y, z = x

        if (self.left < x < self.right and
            self.top < y < self.bottom and
            self.front < z < self.back):
            return True
        return False

    def collidebox(self, box):
        return ( ((self[0] > box[0] and self[0] < box[3] + box[0]) or
                  (box[0] > self[0] and box[0] < self[3] + self[0])) and
                 ((self[1] > box[1] and self[1] < box[4] + box[1]) or
                  (box[1] > self[1] and box[1] < self[4] + self[1])) and
                 ((self[2] > box[2] and self[2] < box[5] + box[2]) or
                  (box[2] > self[2] and box[2] < self[5] + self[2])))

        #return ( ((self.left > box.left and self.left < box.right) or
        #          (box.left > self.left and box.left < self.right)) and
        #         ((self.top > box.top and self.top < box.bottom) or
        #          (box.top > self.top and box.top < self.bottom)) and
        #         ((self.front > box.front and self.front < box.back) or
        #          (box.front > self.front and box.front < self.back)))

    def _clamp(self, box):
        x, y, z = self[:3]
        clamp = 'xyz'

        if self[3] >= box[3]:
            x = box[0] + box[3] / 2 - self[3] / 2
        elif self[0] < box[0]:
            x = box[0]
        elif self[0] + self[3] > box[0] + box[3]:
            x = box[0] + box[3] - self[3]
        else:
            clamp = 'yz'

        if self[4] >= box[4]:
            y = box[1] + box[4] / 2 - self[4] / 2
        elif self[1] < box[1]:
            y = box[1]
        elif self[1] + self[4] > box[1] + box[4]:
            y = box[1] + box[4] - self[4]
        else:
            clamp = clamp.replace('y', '')

        if self[5] >= box[5]:
            z = box[2] + box[5] / 2 - self[5] / 2
        elif self[2] < box[2]:
            z = box[2]
        elif self[2] + self[5] > box[2] + box[5]:
            z = box[2] + box[5] - self[5]
        else:
            clamp = clamp.replace('z', '')

        return x, y, z, clamp

    def clamp(self, box):
        c = self._clamp(box)
        return BoundingBox(*c[:3], *self[3:]), c[3]

    def clamp_ip(self, box):
        c = self._clamp(box)
        self[:3] = c[:3]
        return c[3]

    x = ArrayProperty(0)
    y = ArrayProperty(1)
    z = ArrayProperty(2)
    w = ArrayProperty(3)
    h = ArrayProperty(4)
    d = ArrayProperty(5)

    left = ArrayProperty(0)
    top = ArrayProperty(1)
    front = ArrayProperty(2)
    right = BoxProperty(0, 3)
    bottom = BoxProperty(1, 4)
    back = BoxProperty(2, 5)

    topleft_front = BoxCombineProperty(0, 1, 2)
    topright_front = BoxCombineProperty((0, 3), 1, 2)
    bottomleft_front = BoxCombineProperty(0, (1, 4), 2)
    bottomright_front = BoxCombineProperty((0, 3), (1, 4), 2)
    topleft_back = BoxCombineProperty(0, 1, (2, 5))
    topright_back = BoxCombineProperty((0, 3), 1, (2, 5))
    bottomleft_back = BoxCombineProperty(0, (1, 4), (2, 5))
    bottomright_back = BoxCombineProperty((0, 3), (1, 4), (2, 5))

    center = BoxCombineProperty((0, 3, 1), (1, 4, 1), (2, 5, 1))
    boxsize = BoxCombineProperty(3, 4, 5)
    centerx = BoxProperty(0, 3, 1)
    centery = BoxProperty(1, 4, 1)
    centerz = BoxProperty(2, 5, 1)

def main():
    a = BoundingBox(10,10,10,50,50,50)
    b = BoundingBox(40,40,40,30,30,30)
    c = BoundingBox(10,60,10,50,50,50)
    print(a)
    print(a.collidebox(b))
    print(a.collidebox(c))
    print(b.collidebox(c))
    print(a.collidepoint(45, 20, 45))
    print(b.collidepoint(45, 20, 45))

    print()
    #a[:3] -= 20 # move in place
    print(a)
    screen = BoundingBox(0,0,50,800,600,250)
    clamp = a.clamp_ip(screen)
    print(a, clamp)
    print(screen)
    print(screen.center)

if __name__ == '__main__':
    main()
Example pyglet. Now with mouse and wasd, qe movement.
import pyglet
from pyglet.gl import *
from pyglet.graphics.vertexbuffer import create_buffer
from boundingbox import BoundingBox
from random import randrange
import numpy as np
import ctypes
import math
import os

#           base on gl3n row major
def perspective(width, height, fov, near, far):
    array = np.array([0 for i in range(16)], dtype=GLfloat).reshape(4,4)
    mat = np.matrix(array)
    aspect = width/height
    top = near * math.tan(fov * (math.pi/360.0))
    bottom = -top
    right = top * aspect
    left = -right

    mat[0,0] = (2 * near) / (right - left)
    mat[0,2] = (right + left) / (right - left)
    mat[1,1] = (2 * near) / (top - bottom)
    mat[1,2] = (top + bottom) / (top - bottom)
    mat[2,2] = -(far + near) / (far - near)
    mat[2,3] = -(2 * far + near)  / (far - near)
    mat[3,2] = -1
    return mat

def normalized(array):
    if np.linalg.norm(array) != 0:
        return array / np.linalg.norm(array)
    return array

def matrix_idenity():
    return np.matrix(np.identity(4, GLfloat))

def look_at(eye, target, up):
    look_dir = normalized(target - eye)
    up_dir = normalized(up)
    right_dir = normalized(np.cross(look_dir, up_dir))
    perp_up_dir = np.cross(right_dir, look_dir)

    mat = matrix_idenity()
    mat[0] = np.append(right_dir, [-np.dot(eye, right_dir)])
    mat[1] = np.append(perp_up_dir, [-np.dot(eye, perp_up_dir)])
    mat[2] = np.append(-look_dir, [np.dot(eye, look_dir)])

    return mat

def unit_vector(data):
    data = np.array(data, dtype=GLfloat, copy=True)
    if data.ndim == 1:
        data /= math.sqrt(np.dot(data, data))
        return data

def rotation(alpha, axis):
    cosa = math.cos(alpha)
    sina = math.sin(alpha)
    axis = unit_vector(axis)
    R = np.diag([cosa, cosa, cosa])
    R += np.outer(axis, axis) * (1.0 - cosa)
    axis *= sina
    R += np.array([[0.0, -axis[2], axis[1]],
                   [axis[2], 0.0, -axis[0]],
                   [-axis[1], axis[0], 0.0]], GLfloat)
    M = np.identity(4)
    M[:3, :3] = R
    return M

class Face:
    FRONT = 1     # counter clockwise
    BACK = 2
    LEFT = 4     # counter clockwise
    RIGHT = 8
    TOP = 16     # counter clockwise
    BOTTOM = 32
    ALL = 63

def create_cube(size, face=Face.ALL, element=True):
    array = np.array([
    size, size, size,       #0  + + + right   top      front
    -size, -size, -size,    #1  - - - left    bottom   back
    size, -size, -size,     #2  + - - right   bottom   back
    size, size, -size,      #3  + + - right   top      back
    -size, size, -size,     #4  - + - left    top      back
    -size, size, size,      #5  - + + left    top      front
    -size, -size, size,     #6  - - + left    bottom   front
    size, -size, size       #7  + - + right   bottom   front
    ], GLfloat)

    elements = np.array([], GLuint)
    if face & Face.BACK:
        elements = np.append(elements, [1,3,2,3,1,4])
    if face & Face.FRONT:
        elements = np.append(elements, [6,7,0,0,5,6])
    if face & Face.LEFT:
        elements = np.append(elements, [5,4,1,1,6,5])
    if face & Face.RIGHT:
        elements = np.append(elements, [0,2,3,2,0,7])
    if face & Face.TOP:
        elements = np.append(elements, [4,0,3,0,4,5])
    if face & Face.BOTTOM:
        elements = np.append(elements, [1,2,7,7,6,1])

    if element:
        return array, elements

    pylist = []
    for i in elements:
        n = i * 3
        pylist.extend(array[n:n + 3])

    return np.array(pylist, GLfloat)

class Shader:
    def __init__(self, vstring, fstring):
        self.program = GLuint(glCreateProgram())

        if not os.path.exists(vstring):
            print(vstring, "doesn't exists")
            return

        if not os.path.exists(fstring):
            print(fstring, "doesn't exists")
            return

        vbuffer = open(vstring, 'r')
        vshader = glCreateShader(GL_VERTEX_SHADER)
        vbuff = ctypes.create_string_buffer(vbuffer.read().encode())
        vtext = ctypes.cast(ctypes.pointer(ctypes.pointer(vbuff)), ctypes.POINTER(ctypes.POINTER(GLchar)))
        glShaderSource(vshader, 1, vtext, None)
        glCompileShader(vshader)

        success = GLint()
        infoLog = ctypes.create_string_buffer(512)
        glGetShaderiv(vshader, GL_COMPILE_STATUS, ctypes.byref(success))
        if not success:
            glGetShaderInfoLog(vshader, 512, None, infoLog)
            print("Error: Vertex Shader ", infoLog.value)

        fbuffer = open(fstring, 'r')
        fshader = glCreateShader(GL_FRAGMENT_SHADER)
        fbuff = ctypes.create_string_buffer(fbuffer.read().encode())
        ftext = ctypes.cast(ctypes.pointer(ctypes.pointer(fbuff)), ctypes.POINTER(ctypes.POINTER(GLchar)))
        glShaderSource(fshader, 1, ftext, None)
        glCompileShader(fshader)

        glGetShaderiv(fshader, GL_COMPILE_STATUS, ctypes.byref(success))
        if not success:
            glGetShaderInfoLog(fshader, 512, None, infoLog)
            print("Error: Fragment Shader ", infoLog.value)

        glAttachShader(self.program, vshader)
        glAttachShader(self.program, fshader)
        glLinkProgram(self.program)

        glGetProgramiv(self.program, GL_LINK_STATUS, ctypes.byref(success))
        if not success:
            glGetShaderInfoLog(fshader, 512, None, infoLog)
            print("Error: Program ", infoLog.value)

        # clean up
        glDeleteShader(vshader)
        glDeleteShader(fshader)
        vbuffer.close()
        fbuffer.close()

    def uniformMatrix4fv(self, key, count, transpose, value):
        buff = ctypes.create_string_buffer(key.encode())
        location = glGetUniformLocation(self.program, buff)
        nvalue = np.array(value, GLfloat) # .flatten()
        nref = nvalue.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
        glUniformMatrix4fv(location, count, transpose, nref)

    def use(self):
        glUseProgram(self.program)

    def destroy(self):
        glDeleteProgram(self.program)

class Camera:
    def __init__(self):
        self.position = np.array((0.0, 1.0, 5.0))
        self.front = np.array((0.0, 0.0, 0.0))
        self.up = np.array((0.0, 1.0, 0.0))

        self.yaw = -80.0
        self.pitch = 0.0
        self.sensitivity = 0.05
        self.speed = 1.0

        self.push_front()

    def view(self):
        return look_at(self.position, self.position + self.front, self.up)

    def push_front(self):
        self.front[0] = np.cos(np.radians(self.yaw)) * np.cos(np.radians(self.pitch))
        self.front[1] = np.sin(np.radians(self.pitch))
        self.front[2] = np.sin(np.radians(self.yaw)) * np.cos(np.radians(self.pitch))

    def mouse_motion(self, dx, dy):
        self.yaw += dx * self.sensitivity
        self.yaw %= 360
        self.pitch -= dy * self.sensitivity

        if self.pitch > 89.0:
            self.pitch = 89.0
        if self.pitch < -89.0:
            self.pitch = -89.0

        self.push_front()

    def movement(self, keys, dt):
        if keys[pyglet.window.key.W]:
            self.position += self.front * self.speed * dt
        elif keys[pyglet.window.key.S]:
            self.position -= self.front * self.speed * dt

        if keys[pyglet.window.key.A]:
            self.position -= normalized(np.cross(self.front, self.up)) * self.speed * dt
        elif keys[pyglet.window.key.D]:
            self.position += normalized(np.cross(self.front, self.up)) * self.speed * dt

        if keys[pyglet.window.key.Q]:
            self.yaw -= 20.0 * dt
            self.push_front()
        elif keys[pyglet.window.key.E]:
            self.yaw += 20.0 * dt
            self.push_front()

class CubeRandom:
    def __init__(self, w, h):
        ar = np.arange(0, 1, 0.1)
        self.box = BoundingBox(np.random.choice(ar), np.random.choice(ar),
                np.random.choice(ar), 0.1, 0.1, 0.1).astype(float)
        speed = np.arange(0, 0.05, 0.002)
        self.dir = np.array([np.random.choice(speed) for i in range(3)])

    def move(self, screenbox):
        screenbox = BoundingBox(0.0, 0.0, 0.0, 2.0, 2.0, 2.0)
        self.box[:3] += self.dir
        clamp = self.box.clamp_ip(screenbox)
        if 'x' in clamp:
            self.dir[0] = -self.dir[0]
        if 'y' in clamp:
            self.dir[1] = -self.dir[1]
        if 'z' in clamp:
            self.dir[2] = -self.dir[2]

class Window(pyglet.window.Window):
    def __init__(self):
        pyglet.window.Window.__init__(self)
        self.context.config.alpha_size = 8
        self.context.config.buffer_size = 32
        self.context.config.sample_buffers = 1
        self.context.config.samples = 4

        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LESS)
        glClearColor(0.1, 0.0, 0.0, 1.0)
        glViewport(0, 0, self.width, self.height)
        self.set_exclusive_mouse(True)

        self.camera = Camera()
        self.model = matrix_idenity()
        #self.view = camera.view()
        self.projection = perspective(self.width, self.height, 45.0, 1.0, 100.0)
        #self.mvp = self.projection * self.view * self.model

        self.vertices = create_cube(0.1, element=False)
        print("How many vertices.", len(self.vertices) / 3)
        color_choice = [[1.0,0.0,0.0], [0.0,1.0,0.0], [0.0,0.0,1.0],
            [1.0,0.0,1.0], [1.0,1.0,0.0], [0.0,0.5,1.0]]
        colors = []
        for i in range(6):
            color = color_choice[i]
            colors.extend(color + color + color + color + color + color)
        self.colors = np.array(colors, GLfloat)
        print("How many colors.", len(self.colors) / 3)

        self.vao = GLuint()
        glGenVertexArrays(1, self.vao)
        glBindVertexArray(self.vao)

        self.vbo = create_buffer(self.vertices.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW)
        self.vbo.set_data(self.vertices.ctypes.data)
        self.vbo.bind()

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(0);

        self.color_vbo = create_buffer(self.colors.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW)
        self.color_vbo.set_data(self.colors.ctypes.data)
        self.color_vbo.bind()

        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(1);
        glBindVertexArray(0);

        self.keys = pyglet.window.key.KeyStateHandler()
        self.push_handlers(self.keys, self.on_mouse_motion)
        self.tick = 0.0
        self.shader = Shader('vshader.glsl', 'fshader.glsl')
        pyglet.clock.schedule_interval(self.tick_update, 1.0 / 30.0)
        self.screenbox = BoundingBox(0,0,10, self.width, self.height, 100)
        self.cubes = [CubeRandom(self.width, self.height) for i in range(6)]
        self.still_cubes = [(10,0,0), (0,10,0), (0,0,10), (-10,0,0), (0,-10,0), (0,0,-10),
            (10,10,0), (10,0,10), (0,10,10), (-10,-10,0), (-10,0,-10), (0,-10,-10),]

    def on_mouse_motion(self, x, y, dx, dy):
        self.camera.mouse_motion(dx, dy)

    def tick_update(self, dt):
        self.tick += dt
        self.camera.movement(self.keys, dt)
        for cube in self.cubes:
            cube.move(self.screenbox)

    def on_draw(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        self.shader.use()
        #self.shader.uniformMatrix4fv('mvp', 1, GL_TRUE, self.mvp)

        view = self.camera.view()
        glBindVertexArray(self.vao);
        for cube in self.cubes:
            model = np.identity(4)
            model[0::1, 3][:3] = cube.box[:3]
            mvp = self.projection * view * np.matrix(model)
            self.shader.uniformMatrix4fv('mvp', 1, GL_TRUE, mvp)
            glDrawArrays(GL_TRIANGLES, 0, len(self.vertices))

        for pos in self.still_cubes:
            model = np.identity(4)
            model[0::1, 3][:3] = pos
            mvp = self.projection * view * np.matrix(model)
            self.shader.uniformMatrix4fv('mvp', 1, GL_TRUE, mvp)
            glDrawArrays(GL_TRIANGLES, 0, len(self.vertices))

        glBindVertexArray(0)

    def clean_up(self):
        self.shader.destroy()
        self.vbo.delete()
        self.color_vbo.delete()
        glDeleteVertexArrays(1, self.vao)

if __name__ == '__main__':
    window = Window()
    pyglet.app.run()
    window.clean_up()
99 percent of computer problems exists between chair and keyboard.
Reply
#3
Improve pyglet example.
commonglet.py
import os
import ctypes
import pyglet
import numpy as np
from pyglet.gl import *
from glmath import normalize, GlMat

class VertexArray:
    def __init__(self, size=1):
        self.vao = GLuint(0)
        self.size = size
        glGenVertexArrays(size, self.vao)

    def attribute(self, index, size, gl_type, gl_norm, stride, pointer):
        glVertexAttribPointer(index, size, gl_type, gl_norm, stride, pointer)
        glEnableVertexAttribArray(index)

    def bind(self):
        glBindVertexArray(self.vao)

    def destroy(self):
        glDeleteVertexArrays(self.size, self.vao)

    def disable_attribute(self, n):
        glDisableVertexAttribArray(n)

    def enable_attribute(self, n):
        glEnableVertexAttribArray(n)

    def unbind(self):
        glBindVertexArray(0)

class Shader:
    def __init__(self, vstring, fstring):
        self.program = GLuint(glCreateProgram())

        if not os.path.exists(vstring):
            print(vstring, "doesn't exists")
            return

        if not os.path.exists(fstring):
            print(fstring, "doesn't exists")
            return

        vbuffer = open(vstring, 'r')
        vshader = glCreateShader(GL_VERTEX_SHADER)
        vbuff = ctypes.create_string_buffer(vbuffer.read().encode())
        vtext = ctypes.cast(ctypes.pointer(ctypes.pointer(vbuff)), ctypes.POINTER(ctypes.POINTER(GLchar)))
        glShaderSource(vshader, 1, vtext, None)
        glCompileShader(vshader)

        success = GLint()
        infoLog = ctypes.create_string_buffer(512)
        glGetShaderiv(vshader, GL_COMPILE_STATUS, ctypes.byref(success))
        if not success:
            glGetShaderInfoLog(vshader, 512, None, infoLog)
            print("Error: Vertex Shader ", infoLog.value)

        fbuffer = open(fstring, 'r')
        fshader = glCreateShader(GL_FRAGMENT_SHADER)
        fbuff = ctypes.create_string_buffer(fbuffer.read().encode())
        ftext = ctypes.cast(ctypes.pointer(ctypes.pointer(fbuff)), ctypes.POINTER(ctypes.POINTER(GLchar)))
        glShaderSource(fshader, 1, ftext, None)
        glCompileShader(fshader)

        glGetShaderiv(fshader, GL_COMPILE_STATUS, ctypes.byref(success))
        if not success:
            glGetShaderInfoLog(fshader, 512, None, infoLog)
            print("Error: Fragment Shader ", infoLog.value)

        glAttachShader(self.program, vshader)
        glAttachShader(self.program, fshader)
        glLinkProgram(self.program)

        glGetProgramiv(self.program, GL_LINK_STATUS, ctypes.byref(success))
        if not success:
            glGetShaderInfoLog(fshader, 512, None, infoLog)
            print("Error: Program ", infoLog.value)

        # clean up
        glDeleteShader(vshader)
        glDeleteShader(fshader)
        vbuffer.close()
        fbuffer.close()

    def uniformMatrix4fv(self, key, count, transpose, value):
        buff = ctypes.create_string_buffer(key.encode())
        location = glGetUniformLocation(self.program, buff)
        nvalue = np.array(value, GLfloat) # .flatten()
        nref = nvalue.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
        glUniformMatrix4fv(location, count, transpose, nref)

    def use(self):
        glUseProgram(self.program)

    def destroy(self):
        glDeleteProgram(self.program)

class Camera:
    def __init__(self,
        position = np.array((0.0, 0.0, 5.0)),
        yaw = -90,
        pitch = 0,
        roll = 0,
        sensitivity = 0.05,
        speed = 5.0,
        turn = 70.0):

        self.position = position
        self.front = np.array((0,0,0), float)
        self.top = np.array((0.0, 1.0, 0.0))

        self.yaw = float(yaw)
        self.pitch = float(pitch)
        self.roll = float(roll)
        self.sensitivity = sensitivity
        self.speed = speed
        self.turn = turn

        self.update()

    def view(self):
        return GlMat.look_at(self.position, self.position + self.front, self.up)

    def constrain_pitch(self):
        if self.pitch > 89.0:
            self.pitch = 89.0
        if self.pitch < -89.0:
            self.pitch = -89.0

    def update(self):
        self.front[0] = np.cos(np.radians(self.yaw)) * np.cos(np.radians(self.pitch))
        self.front[1] = np.sin(np.radians(self.pitch))
        self.front[2] = np.sin(np.radians(self.yaw)) * np.cos(np.radians(self.pitch))
        self.front = normalize(self.front)
        self.across = normalize(np.cross(self.front, self.top))
        self.up = normalize(np.cross(self.across, self.front))
        # roll
        self.up[0] = np.sin(np.radians(self.roll)) * np.cos(np.radians(self.pitch))
        self.up[1] = np.cos(np.radians(self.roll)) * np.cos(np.radians(self.pitch))
        self.up[2] = np.sin(np.radians(self.pitch))
        self.up = normalize(self.up)

    def mouse_motion(self, dx, dy):
        self.yaw += dx * self.sensitivity
        self.yaw %= 360
        self.pitch -= dy * self.sensitivity
        self.constrain_pitch()
        self.update()

    def movement(self, keys, dt):
        if keys[pyglet.window.key.SPACE]:
            self.pitch = 0.0
            self.roll = 0.0
            self.update()

        if keys[pyglet.window.key.W]:
            self.position += self.front * self.speed * dt
        elif keys[pyglet.window.key.S]:
            self.position -= self.front * self.speed * dt

        if keys[pyglet.window.key.A]:
            self.position -= self.across * self.speed * dt
        elif keys[pyglet.window.key.D]:
            self.position += self.across * self.speed * dt

        if keys[pyglet.window.key.Q]:
            self.yaw -= self.turn * dt
            self.update()
        elif keys[pyglet.window.key.E]:
            self.yaw += self.turn * dt
            self.update()

    def movement_plus(self, keys, dt):
        self.movement(keys, dt)

        # works but needs more testing
        if keys[pyglet.window.key.Z]:
            self.roll -= self.turn * dt
            self.update()
        elif keys[pyglet.window.key.X]:
            self.roll += self.turn * dt
            self.update()

        if keys[pyglet.window.key.R]:
            self.position += normalize(self.up) * self.speed * dt
        elif keys[pyglet.window.key.F]:
            self.position -= normalize(self.up) * self.speed * dt
glmath.py
import numpy as np
import numpy.matlib as matlib

def normalize(array):
    norm = np.linalg.norm(array)
    if norm != 0:
        return array / norm
    return array

# row major, base on gl3n
class GlMat(np.matrix):
    def __new__(cls, data=None, dtype=float):
        if data is None:
            data = matlib.identity(4, dtype)
        return np.asmatrix(data, dtype).view(cls)

    def identity(self):
        self[:] = matlib.identity(4, self.dtype)

    def translate(self, vec3):
        for i in range(3):
            self[i,3] += vec3[i]

    def translation(self, vec3):
        for i in range(3):
            self[i,3] = vec3[i]

    def rotate(self, alpha, x, y, z):
        self[:] = GlMat.rotation(alpha, x, y, z) * self

    def rotatex(self, alpha):
        self[:] = GlMat.xrotation(alpha) * self

    def rotatey(self, alpha):
        self[:] = GlMat.yrotation(alpha) * self

    def rotatez(self, alpha):
        self[:] = GlMat.zrotation(alpha) * self

    @staticmethod
    def rotation(alpha, x, y, z):
        mult = GlMat()
        axis = normalize(np.array((x,y,z)))
        cosa = np.cos(alpha)
        sina = np.sin(alpha)
        temp = np.array((1 - cosa) * axis)

        mult[0,0] = temp[0] * axis[0] + cosa
        mult[0,1] = temp[0] * axis[1] + sina * axis[2]
        mult[0,2] = temp[0] * axis[2] - sina * axis[1]
        mult[1,0] = temp[1] * axis[0] - sina * axis[2]
        mult[1,1] = temp[1] * axis[1] + cosa
        mult[1,2] = temp[1] * axis[2] + sina * axis[0]
        mult[2,0] = temp[2] * axis[0] + sina * axis[1]
        mult[2,1] = temp[2] * axis[1] - sina * axis[0]
        mult[2,2] = temp[2] * axis[2] + cosa
        return mult

    @staticmethod
    def xrotation(alpha):
        mult = GlMat()
        cosa = np.cos(alpha)
        sina = np.sin(alpha)

        mult[1,1] = cosa
        mult[1,2] = -sina
        mult[2,1] = sina
        mult[2,2] = cosa
        return mult

    @staticmethod
    def yrotation(alpha):
        mult = GlMat()
        cosa = np.cos(alpha)
        sina = np.sin(alpha)

        mult[0,0] = cosa
        mult[0,2] = sina
        mult[2,0] = -sina
        mult[2,2] = cosa
        return mult

    @staticmethod
    def zrotation(alpha):
        mult = GlMat()
        cosa = np.cos(alpha)
        sina = np.sin(alpha)

        mult[0,0] = cosa
        mult[0,1] = -sina
        mult[1,0] = sina
        mult[1,1] = cosa
        return mult

    @staticmethod
    def perspective(width, height, fov, near, far):
        mat = GlMat()
        aspect = width/height
        top = near * np.tan(fov * (np.pi/360.0))
        bottom = -top
        right = top * aspect
        left = -right

        mat[0,0] = (2 * near) / (right - left)
        mat[0,2] = (right + left) / (right - left)
        mat[1,1] = (2 * near) / (top - bottom)
        mat[1,2] = (top + bottom) / (top - bottom)
        mat[2,2] = -(far + near) / (far - near)
        mat[2,3] = -(2 * far + near)  / (far - near)
        mat[3,2] = -1
        return mat

    @staticmethod
    def look_at(eye, target, up):
        look_dir = normalize(target - eye)
        up_dir = normalize(up)
        right_dir = normalize(np.cross(look_dir, up_dir))
        perp_up_dir = np.cross(right_dir, look_dir)

        mat = GlMat()
        mat[0] = np.append(right_dir, [-np.dot(eye, right_dir)])
        mat[1] = np.append(perp_up_dir, [-np.dot(eye, perp_up_dir)])
        mat[2] = np.append(-look_dir, [np.dot(eye, look_dir)])
        return mat

if __name__ == '__main__':
    m = GlMat()
    m.translate(np.array((1,2,3)))
    m.rotatez(0.2)
    print(m)
    print(GlMat.rotation(0.5,0.1,0.2,0.3))
shapes.py
import numpy as np
import numpy.matlib as matlib

def normalize(array):
    norm = np.linalg.norm(array)
    if norm != 0:
        return array / norm
    return array

# row major, base on gl3n
class GlMat(np.matrix):
    def __new__(cls, data=None, dtype=float):
        if data is None:
            data = matlib.identity(4, dtype)
        return np.asmatrix(data, dtype).view(cls)

    def identity(self):
        self[:] = matlib.identity(4, self.dtype)

    def translate(self, vec3):
        for i in range(3):
            self[i,3] += vec3[i]

    def translation(self, vec3):
        for i in range(3):
            self[i,3] = vec3[i]

    def rotate(self, alpha, x, y, z):
        self[:] = GlMat.rotation(alpha, x, y, z) * self

    def rotatex(self, alpha):
        self[:] = GlMat.xrotation(alpha) * self

    def rotatey(self, alpha):
        self[:] = GlMat.yrotation(alpha) * self

    def rotatez(self, alpha):
        self[:] = GlMat.zrotation(alpha) * self

    @staticmethod
    def rotation(alpha, x, y, z):
        mult = GlMat()
        axis = normalize(np.array((x,y,z)))
        cosa = np.cos(alpha)
        sina = np.sin(alpha)
        temp = np.array((1 - cosa) * axis)

        mult[0,0] = temp[0] * axis[0] + cosa
        mult[0,1] = temp[0] * axis[1] + sina * axis[2]
        mult[0,2] = temp[0] * axis[2] - sina * axis[1]
        mult[1,0] = temp[1] * axis[0] - sina * axis[2]
        mult[1,1] = temp[1] * axis[1] + cosa
        mult[1,2] = temp[1] * axis[2] + sina * axis[0]
        mult[2,0] = temp[2] * axis[0] + sina * axis[1]
        mult[2,1] = temp[2] * axis[1] - sina * axis[0]
        mult[2,2] = temp[2] * axis[2] + cosa
        return mult

    @staticmethod
    def xrotation(alpha):
        mult = GlMat()
        cosa = np.cos(alpha)
        sina = np.sin(alpha)

        mult[1,1] = cosa
        mult[1,2] = -sina
        mult[2,1] = sina
        mult[2,2] = cosa
        return mult

    @staticmethod
    def yrotation(alpha):
        mult = GlMat()
        cosa = np.cos(alpha)
        sina = np.sin(alpha)

        mult[0,0] = cosa
        mult[0,2] = sina
        mult[2,0] = -sina
        mult[2,2] = cosa
        return mult

    @staticmethod
    def zrotation(alpha):
        mult = GlMat()
        cosa = np.cos(alpha)
        sina = np.sin(alpha)

        mult[0,0] = cosa
        mult[0,1] = -sina
        mult[1,0] = sina
        mult[1,1] = cosa
        return mult

    @staticmethod
    def perspective(width, height, fov, near, far):
        mat = GlMat()
        aspect = width/height
        top = near * np.tan(fov * (np.pi/360.0))
        bottom = -top
        right = top * aspect
        left = -right

        mat[0,0] = (2 * near) / (right - left)
        mat[0,2] = (right + left) / (right - left)
        mat[1,1] = (2 * near) / (top - bottom)
        mat[1,2] = (top + bottom) / (top - bottom)
        mat[2,2] = -(far + near) / (far - near)
        mat[2,3] = -(2 * far + near)  / (far - near)
        mat[3,2] = -1
        return mat

    @staticmethod
    def look_at(eye, target, up):
        look_dir = normalize(target - eye)
        up_dir = normalize(up)
        right_dir = normalize(np.cross(look_dir, up_dir))
        perp_up_dir = np.cross(right_dir, look_dir)

        mat = GlMat()
        mat[0] = np.append(right_dir, [-np.dot(eye, right_dir)])
        mat[1] = np.append(perp_up_dir, [-np.dot(eye, perp_up_dir)])
        mat[2] = np.append(-look_dir, [np.dot(eye, look_dir)])
        return mat

if __name__ == '__main__':
    m = GlMat()
    m.translate(np.array((1,2,3)))
    m.rotatez(0.2)
    print(m)
    print(GlMat.rotation(0.5,0.1,0.2,0.3))
cube.py main
import ctypes
import pyglet
import numpy as np
from pyglet.gl import *
from boundingbox import BoundingBox
from shapes import create_cube, Face
from glmath import GlMat, normalize
from commonglet import VertexArray, Shader, Camera
from pyglet.graphics.vertexbuffer import create_buffer

class CubeRandom:
    def __init__(self):
        ar = np.arange(-1, 1, 0.1)
        self.box = BoundingBox(np.random.choice(ar), np.random.choice(ar),
                np.random.choice(ar), 0.1, 0.1, 0.1).astype(float)
        speed = np.arange(-0.05, 0.05, 0.002)
        self.dir = np.array([np.random.choice(speed) for i in range(3)])

    def move(self):
        screenbox = BoundingBox(-5.0, -5.0, -5.0, 10.0, 10.0, 10.0)
        self.box[:3] += self.dir
        clamp = self.box.clamp_ip(screenbox)
        if 'x' in clamp:
            self.dir[0] = -self.dir[0]
        if 'y' in clamp:
            self.dir[1] = -self.dir[1]
        if 'z' in clamp:
            self.dir[2] = -self.dir[2]

class Window(pyglet.window.Window):
    def __init__(self):
        pyglet.window.Window.__init__(self)
        self.set_location(100,100)
        self._gl_setup()
        self._cube_setup(0.2)
        self.cube_shader = Shader('vshader.glsl', 'fshader.glsl')
        pyglet.clock.schedule_interval(self.time_update, 1.0 / 30.0)
        self.projection = GlMat.perspective(self.width, self.height, 45.0, 1.0, 100.0)

        self.cubes = [CubeRandom() for i in range(10)]

        self.set_exclusive_mouse(True)
        self.camera = Camera(np.array((0, 0, 20), float))
        self.keys = pyglet.window.key.KeyStateHandler()
        self.push_handlers(self.keys, self.on_mouse_motion)

    def on_mouse_motion(self, x, y, dx, dy):
        self.camera.mouse_motion(dx, dy)

    def time_update(self, dt):
        self.camera.movement_plus(self.keys, dt)
        for cube in self.cubes:
            cube.move()

    def _gl_setup(self):
        self.context.config.alpha_size = 8
        self.context.config.buffer_size = 32
        self.context.config.sample_buffers = 1
        self.context.config.samples = 4

        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LESS)
        glClearColor(0.1, 0.0, 0.0, 1.0)
        glViewport(0, 0, self.width, self.height)

    def _cube_setup(self, size):
        color_choice = [
            [1.0,0.0,0.0],
            [0.0,1.0,0.0],
            [0.0,0.0,1.0],
            [1.0,0.0,1.0],
            [1.0,1.0,0.0],
            [0.0,0.5,1.0]]

        colors = []
        for i in range(6):
            color = color_choice[i]
            colors.extend(color + color + color + color + color + color)
        self.colors = np.array(colors, GLfloat)
        self.vertices = create_cube(size, element=False)

        self.cube_vao = VertexArray()
        self.cube_vao.bind()

        self.cube_vbo = create_buffer(self.vertices.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW)
        self.cube_vbo.set_data(self.vertices.ctypes.data)
        self.cube_vbo.bind()
        self.cube_vao.attribute(0, 3, GL_FLOAT, GL_FALSE, 0, 0)

        self.cube_color_vbo = create_buffer(self.colors.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW)
        self.cube_color_vbo.set_data(self.colors.ctypes.data)
        self.cube_color_vbo.bind()
        self.cube_vao.attribute(1, 3, GL_FLOAT, GL_FALSE, 0, 0)
        self.cube_vao.unbind()

    def on_draw(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        self.cube_shader.use()
        self.cube_vao.bind()
        for cube in self.cubes:
            model = GlMat()
            model.translate(cube.box[:3])
            mvp = self.projection * self.camera.view() * model
            self.cube_shader.uniformMatrix4fv('mvp', 1, GL_TRUE, mvp)
            glDrawArrays(GL_TRIANGLES, 0, len(self.vertices))
        self.cube_vao.unbind()

    def clean_up(self):
        self.cube_vbo.delete()
        self.cube_color_vbo.delete()
        self.cube_shader.destroy()
        self.cube_vao.destroy()

if __name__ == '__main__':
    window = Window()
    pyglet.app.run()
    window.clean_up()
99 percent of computer problems exists between chair and keyboard.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020