VoxelEngine/Objects/Structure.py

234 lines
9 KiB
Python

from wsgiref.validate import check_errors
from OpenGL.GL.ARB.vertex_array_object import glDeleteVertexArrays
from OpenGL.GL.framebufferobjects import glBindFramebuffer
from OpenGL.GLUT import *
import OpenGL.GLUT.freeglut
from OpenGL.GLU import *
from OpenGL.GL import *
import numpy as np
from OpenGL.extensions import alternate
from Objects.Objects import Object
from Objects.Renderable import Renderable
class Structure(Renderable):
def __init__(self, x_offset=0, y_offset=1, z_offset=0):
self.Objects = {}
self.vais = {}
self.dirty = True
self.dirty_pos = True
self.dirty_color = True
self.dirty_size = True
self.x_offset = x_offset
self.y_offset = y_offset
self.z_offset = z_offset
@property
def x_offset(self):
return self._x_offset
@x_offset.setter
def x_offset(self, value):
self.dirty = True
self.dirty_pos = True
self._x_offset = value
@property
def y_offset(self):
return self._y_offset
@y_offset.setter
def y_offset(self, value):
self.dirty = True
self.dirty_pos = True
self._y_offset = value
@property
def z_offset(self):
return self._z_offset
@z_offset.setter
def z_offset(self, value):
self.dirty = True
self.dirty_pos = True
self._z_offset = value
def addShape(self, program, shape):
if not program in self.Objects.keys():
self.Objects[program] = []
self.Objects[program].append(shape)
self.dirty = True
self.dirty_color = True
self.dirty_pos = True
self.dirty_size = True
def removeShape(self, program, shape):
if program in self.Objects.keys():
self.Objects[program].remove(shape)
if len(self.Objects[program]) == 0:
self.Objects.pop(program)
self.dirty = True
self.dirty_color = True
self.dirty_pos = True
self.dirty_size = True
def buildvertexArrays(self):
if self.dirty:
# self.clearVertexArrays()
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glEnableClientState(GL_NORMAL_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
for key, objects in self.Objects.items():
needs_new_buffers = key not in self.vais.keys()
if needs_new_buffers:
tvai = GLuint(0)
tpbi = GLuint(0)
tcbi = GLuint(0)
tsbi = GLuint(0)
num = len(objects)
else:
tvai, tpbi, tcbi, tsbi, num = self.vais[key]
if needs_new_buffers:
glGenVertexArrays(1, tvai)
glBindVertexArray(tvai)
if self.dirty_pos:
if needs_new_buffers:
vid = glGetAttribLocation(key, "in_position")
glEnableVertexAttribArray(vid)
tpbi = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, tpbi)
positions = []
for o in objects:
positions.append(o.pos[0] + self.x_offset)
positions.append(o.pos[1] + self.y_offset)
positions.append(o.pos[2] + self.z_offset)
glBufferData(GL_ARRAY_BUFFER, np.array(positions, dtype=np.float32), GL_STATIC_DRAW)
if needs_new_buffers:
glVertexAttribPointer(vid, 3, GL_FLOAT, GL_FALSE, 0, None)
self.check_error("Could not create position buffer")
if self.dirty_color:
colors = []
for o in objects:
colors.append(o.color[0])
colors.append(o.color[1])
colors.append(o.color[2])
if needs_new_buffers:
tcbi = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, tcbi)
glBufferData(GL_ARRAY_BUFFER, np.array(colors, dtype=np.float32), GL_STATIC_DRAW)
if needs_new_buffers:
vc = glGetAttribLocation(key, "MyInColor")
if vc != -1:
glEnableVertexAttribArray(vc)
glVertexAttribPointer(vc, 3, GL_FLOAT, GL_FALSE, 0, None)
self.check_error("Could not create color buffer")
if self.dirty_size:
if hasattr(objects[0], 'size'):
sizes = []
for o in objects:
sizes.append(o.size[0])
sizes.append(o.size[1])
sizes.append(o.size[2])
if needs_new_buffers:
tsbi = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, tsbi)
glBufferData(GL_ARRAY_BUFFER, np.array(sizes, dtype=np.float32), GL_STATIC_DRAW)
if needs_new_buffers:
vs = glGetAttribLocation(key, "MyInSize")
if vs != -1:
glEnableVertexAttribArray(vs)
glVertexAttribPointer(vs, 3, GL_FLOAT, GL_FALSE, 0, None)
self.check_error("Could not create size buffer")
glBindVertexArray(0)
self.vais[key] = (tvai, tpbi, tcbi, tsbi, num)
self.dirty = False
self.dirty_pos = False
self.dirty_color = False
self.dirty_size = False
def clearVertexArrays(self):
temp = dict(self.vais)
self.vais = {}
for key, vertex_array_ids in temp.items():
if vertex_array_ids[1] != -1 and vertex_array_ids[1] != GLuint(-1):
glDeleteBuffers(1, [vertex_array_ids[1]])
self.check_error("Could not destroy buffer")
if vertex_array_ids[2] != -1 and vertex_array_ids[2] != GLuint(-1):
glDeleteBuffers(1, [vertex_array_ids[2]])
self.check_error("Could not destroy buffer")
if vertex_array_ids[3] != -1 and vertex_array_ids[3] != GLuint(-1):
glDeleteBuffers(1, [vertex_array_ids[3]])
self.check_error("Could not destroy buffer")
glDeleteVertexArrays(1, vertex_array_ids[0])
self.check_error("Could not destroy vertex array")
def render(self, projMatrix, geometryRotMatrix, alternateprograms=None,
preselected_program=None, projection_pos=None, rot_pos=None):
self.buildvertexArrays()
for key, vertex_array_ids in self.vais.items():
if alternateprograms == None:
program_id = key
else:
assert key in alternateprograms.keys()
program_id = alternateprograms[key]
# check if a program was preloaded
if preselected_program is not None:
# if preloaded we only want to render the matching vertex arrays
if preselected_program != program_id:
continue
else:
glUseProgram(program_id)
self.check_error("Renderingprogram is not initialized!")
if rot_pos is None:
rot = glGetUniformLocation(program_id, 'rotMatrix')
glUniformMatrix3fv(rot, 1, GL_FALSE, np.array(geometryRotMatrix))
if projection_pos is None:
projection = glGetUniformLocation(program_id, 'projModelViewMatrix')
glUniformMatrix4fv(projection, 1, GL_FALSE, np.array(projMatrix))
glBindVertexArray(vertex_array_ids[0])
glDrawArrays(GL_POINTS, 0, vertex_array_ids[4])
self.check_error("Rendering problem")
glBindVertexArray(0)
if preselected_program is None:
glUseProgram(0)
def __eq__(self, other):
if type(other) is type(self):
return self.vais == other.vais and self.Objects == other.Objects
else:
return False
class CompoundStructure(Renderable):
def __init__(self):
self.Structures = []
def addStructure(self, structure: Structure, M: np.matrix = np.identity(4, np.float),
R: np.matrix = np.identity(3, np.float)):
self.Structures.append((structure, M, R))
def render(self, projMatrix, geometryRotMatrix, alternateprograms=None,
preselected_program=None, projection_pos=None, rot_pos=None):
for (structure, M, R) in self.Structures:
structure.render(M * projMatrix, R * geometryRotMatrix, alternateprograms,
preselected_program, projection_pos, rot_pos)
def __eq__(self, other):
if type(other) is type(self):
return self.Structures == other.Structures
else:
return False