class model: ''' class for STL file / 3d model ''' def __init__(self, stl_data, batchh=None): ''' initialise model data''' vert, norm = stl_data self.vertices = numpy.array(vert, dtype=GLfloat) self.normals = numpy.array(norm, dtype=GLfloat) self.vertex_buffer = VBO(self.vertices, 'GL_STATIC_DRAW') self.normal_buffer = VBO(self.normals, 'GL_STATIC_DRAW') # calculate model scale self.corner = self.vertices.transpose().min(1) self.corner2 = self.vertices.transpose().max(1) self.scale = abs(self.corner) + abs(self.corner2) self.scale = max(self.scale[0], self.scale[1], self.scale[2]) print 'STL File loaded in: ', loadtime print 'Object information' print 'corner 1: ', self.corner print 'corner 2: ', self.corner2 print 'object scale: ', self.scale def draw(self): ''' draw model on screen ''' glMatrixMode(GL_MODELVIEW) glPushMatrix() glLoadIdentity() # center the model glTranslate(window.width / 2, window.height / 2, -150) # scale the model glScale(150 / self.scale, 150 / self.scale, 150 / self.scale) # draw grid and coordinate lines draw_grid() draw_xyz(0, 0, 0, -20, -20) # demo rotation glRotate(rot, 1, 0, 0) glRotate(rot2, 0, 1, 0) glRotate(rot3, 0, 0, 1) self.vertex_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.normal_buffer.bind() glNormalPointer(GL_FLOAT, 0, None) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) glDrawArrays(GL_TRIANGLES, 0, len(self.vertices)) glDisableClientState(GL_NORMAL_ARRAY) glDisableClientState(GL_VERTEX_ARRAY) self.normal_buffer.unbind() self.vertex_buffer.unbind() glPopMatrix()
class GcodeModel(Model): """ Model for displaying Gcode data. """ # vertices for arrow to display the direction of movement arrow = numpy.require([ [0.0, 0.0, 0.0], [0.4, -0.1, 0.0], [0.4, 0.1, 0.0], ], 'f') layer_entry_marker = numpy.require([ [0.23, -0.14, 0.0], [0.0, 0.26, 0.0], [-0.23, -0.14, 0.0], ], 'f') layer_exit_marker = numpy.require([ [-0.23, -0.23, 0.0], [0.23, -0.23, 0.0], [0.23, 0.23, 0.0], [0.23, 0.23, 0.0], [-0.23, 0.23, 0.0], [-0.23, -0.23, 0.0], ], 'f') def load_data(self, model_data, callback=None): t_start = time.time() vertex_list = [] color_list = [] self.layer_stops = [0] self.layer_heights = [] arrow_list = [] layer_markers_list = [] self.layer_marker_stops = [0] num_layers = len(model_data) callback_every = max(1, int(math.floor(num_layers / 100))) # the first movement designates the starting point start = prev = model_data[0][0] del model_data[0][0] for layer_idx, layer in enumerate(model_data): first = layer[0] for movement in layer: vertex_list.append(prev.v) vertex_list.append(movement.v) arrow = self.arrow # position the arrow with respect to movement arrow = vector.rotate(arrow, movement.angle(prev.v), 0.0, 0.0, 1.0) arrow_list.extend(arrow) vertex_color = self.movement_color(movement) color_list.append(vertex_color) prev = movement self.layer_stops.append(len(vertex_list)) self.layer_heights.append(first.v[2]) # add the layer entry marker if layer_idx > 0 and len(model_data[layer_idx - 1]) > 0: layer_markers_list.extend(self.layer_entry_marker + model_data[layer_idx - 1][-1].v) elif layer_idx == 0 and len(layer) > 0: layer_markers_list.extend(self.layer_entry_marker + layer[0].v) # add the layer exit marker if len(layer) > 1: layer_markers_list.extend(self.layer_exit_marker + layer[-1].v) self.layer_marker_stops.append(len(layer_markers_list)) if callback and layer_idx % callback_every == 0: callback(layer_idx + 1, num_layers) self.vertices = numpy.array(vertex_list, 'f') self.colors = numpy.array(color_list, 'f') self.arrows = numpy.array(arrow_list, 'f') self.layer_markers = numpy.array(layer_markers_list, 'f') # by translating the arrow vertices outside of the loop, we achieve a # significant performance gain thanks to numpy. it would be really nice # if we could rotate in a similar fashion... self.arrows = self.arrows + self.vertices[1::2].repeat(3, 0) # for every pair of vertices of the model, there are 3 vertices for the arrow assert len(self.arrows) == ((len(self.vertices) // 2) * 3), \ 'The 2:3 ratio of model vertices to arrow vertices does not hold.' self.max_layers = len(self.layer_stops) - 1 self.num_layers_to_draw = self.max_layers self.arrows_enabled = True self.initialized = False self.vertex_count = len(self.vertices) t_end = time.time() logging.info('Initialized Gcode model in %.2f seconds' % (t_end - t_start)) logging.info('Vertex count: %d' % self.vertex_count) def movement_color(self, move): """ Return the color to use for particular type of movement. """ # default movement color is gray color = (0.6, 0.6, 0.6, 0.6) extruder_on = (move.flags & Movement.FLAG_EXTRUDER_ON or move.delta_e > 0) outer_perimeter = (move.flags & Movement.FLAG_PERIMETER and move.flags & Movement.FLAG_PERIMETER_OUTER) if extruder_on and outer_perimeter: color = (0.0, 0.875, 0.875, 0.6) # cyan elif extruder_on and move.flags & Movement.FLAG_PERIMETER: color = (0.0, 1.0, 0.0, 0.6) # green elif extruder_on and move.flags & Movement.FLAG_LOOP: color = (1.0, 0.875, 0.0, 0.6) # yellow elif extruder_on: color = (1.0, 0.0, 0.0, 0.6) # red return color # ------------------------------------------------------------------------ # DRAWING # ------------------------------------------------------------------------ def init(self): self.vertex_buffer = VBO(self.vertices, 'GL_STATIC_DRAW') self.vertex_color_buffer = VBO(self.colors.repeat( 2, 0), 'GL_STATIC_DRAW') # each pair of vertices shares the color if self.arrows_enabled: self.arrow_buffer = VBO(self.arrows, 'GL_STATIC_DRAW') self.arrow_color_buffer = VBO( self.colors.repeat(3, 0), 'GL_STATIC_DRAW') # each triplet of vertices shares the color self.layer_marker_buffer = VBO(self.layer_markers, 'GL_STATIC_DRAW') self.initialized = True def display(self, elevation=0, eye_height=0, mode_ortho=False, mode_2d=False): glPushMatrix() offset_z = self.offset_z if not mode_2d else 0 glTranslate(self.offset_x, self.offset_y, offset_z) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_COLOR_ARRAY) self._display_movements(elevation, eye_height, mode_ortho, mode_2d) if self.arrows_enabled: self._display_arrows() glDisableClientState(GL_COLOR_ARRAY) if self.arrows_enabled: self._display_layer_markers() glDisableClientState(GL_VERTEX_ARRAY) glPopMatrix() def _display_movements(self, elevation=0, eye_height=0, mode_ortho=False, mode_2d=False): self.vertex_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.vertex_color_buffer.bind() glColorPointer(4, GL_FLOAT, 0, None) if mode_2d: glScale(1.0, 1.0, 0.0) # discard z coordinates start = self.layer_stops[self.num_layers_to_draw - 1] end = self.layer_stops[self.num_layers_to_draw] glDrawArrays(GL_LINES, start, end - start) elif mode_ortho: if elevation >= 0: # draw layers in normal order, bottom to top start = 0 end = self.layer_stops[self.num_layers_to_draw] glDrawArrays(GL_LINES, start, end - start) else: # draw layers in reverse order, top to bottom stop_idx = self.num_layers_to_draw - 1 while stop_idx >= 0: start = self.layer_stops[stop_idx] end = self.layer_stops[stop_idx + 1] glDrawArrays(GL_LINES, start, end - start) stop_idx -= 1 else: # 3d projection mode reverse_threshold_layer = self._layer_up_to_height(eye_height - self.offset_z) if reverse_threshold_layer >= 0: # draw layers up to (and including) the threshold in normal order, bottom to top normal_layers_to_draw = min(self.num_layers_to_draw, reverse_threshold_layer + 1) start = 0 end = self.layer_stops[normal_layers_to_draw] glDrawArrays(GL_LINES, start, end - start) if reverse_threshold_layer + 1 < self.num_layers_to_draw: # draw layers from the threshold in reverse order, top to bottom stop_idx = self.num_layers_to_draw - 1 while stop_idx > reverse_threshold_layer: start = self.layer_stops[stop_idx] end = self.layer_stops[stop_idx + 1] glDrawArrays(GL_LINES, start, end - start) stop_idx -= 1 self.vertex_buffer.unbind() self.vertex_color_buffer.unbind() def _layer_up_to_height(self, height): """Return the index of the last layer lower than height.""" for idx in range(len(self.layer_heights) - 1, -1, -1): if self.layer_heights[idx] < height: return idx return 0 def _display_arrows(self): self.arrow_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.arrow_color_buffer.bind() glColorPointer(4, GL_FLOAT, 0, None) start = (self.layer_stops[self.num_layers_to_draw - 1] // 2) * 3 end = (self.layer_stops[self.num_layers_to_draw] // 2) * 3 glDrawArrays(GL_TRIANGLES, start, end - start) self.arrow_buffer.unbind() self.arrow_color_buffer.unbind() def _display_layer_markers(self): self.layer_marker_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) start = self.layer_marker_stops[self.num_layers_to_draw - 1] end = self.layer_marker_stops[self.num_layers_to_draw] glColor4f(0.6, 0.6, 0.6, 0.6) glDrawArrays(GL_TRIANGLES, start, end - start) self.layer_marker_buffer.unbind()
class GcodeModel(Model): """ Model for displaying Gcode data. """ # define color names for different types of extruder movements color_map = { 'red': [1.0, 0.0, 0.0, 0.6], 'yellow': [1.0, 0.875, 0.0, 0.6], 'orange': [1.0, 0.373, 0.0, 0.6], 'green': [0.0, 1.0, 0.0, 0.6], 'cyan': [0.0, 0.875, 0.875, 0.6], 'gray': [0.6, 0.6, 0.6, 0.6], } # vertices for arrow to display the direction of movement arrow = numpy.require([ [0.0, 0.0, 0.0], [0.4, -0.1, 0.0], [0.4, 0.1, 0.0], ], 'f') def __init__(self, model_data): Model.__init__(self) t_start = time.time() self.create_vertex_arrays(model_data) self.max_layers = len(self.layer_stops) - 1 self.num_layers_to_draw = self.max_layers self.arrows_enabled = True self.initialized = False t_end = time.time() logging.info('Initialized Gcode model in %.2f seconds' % (t_end - t_start)) logging.info('Vertex count: %d' % len(self.vertices)) def create_vertex_arrays(self, model_data): """ Construct vertex lists from gcode data. """ vertex_list = [] color_list = [] self.layer_stops = [0] arrow_list = [] for layer in model_data: for movement in layer: a, b = movement.point_a, movement.point_b vertex_list.append([a.x, a.y, a.z]) vertex_list.append([b.x, b.y, b.z]) arrow = self.arrow # position the arrow with respect to movement arrow = vector.rotate(arrow, movement.angle(), 0.0, 0.0, 1.0) arrow_list.extend(arrow) vertex_color = self.movement_color(movement) color_list.append(vertex_color) self.layer_stops.append(len(vertex_list)) self.vertices = numpy.array(vertex_list, 'f') self.colors = numpy.array(color_list, 'f') self.arrows = numpy.array(arrow_list, 'f') # by translating the arrow vertices outside of the loop, we achieve a # significant performance gain thanks to numpy. it would be really nice # if we could rotate in a similar fashion... self.arrows = self.arrows + self.vertices[1::2].repeat(3, 0) # for every pair of vertices of the model, there are 3 vertices for the arrow assert len(self.arrows) == ((len(self.vertices) // 2) * 3), \ 'The 2:3 ratio of model vertices to arrow vertices does not hold.' def movement_color(self, movement): """ Return the color to use for particular type of movement. """ if not movement.extruder_on: color = self.color_map['gray'] elif movement.is_loop: color = self.color_map['yellow'] elif movement.is_perimeter and movement.is_perimeter_outer: color = self.color_map['cyan'] elif movement.is_perimeter: color = self.color_map['green'] else: color = self.color_map['red'] return color # ------------------------------------------------------------------------ # DRAWING # ------------------------------------------------------------------------ def init(self): self.vertex_buffer = VBO(self.vertices, 'GL_STATIC_DRAW') self.vertex_color_buffer = VBO(self.colors.repeat(2, 0), 'GL_STATIC_DRAW') # each pair of vertices shares the color if self.arrows_enabled: self.arrow_buffer = VBO(self.arrows, 'GL_STATIC_DRAW') self.arrow_color_buffer = VBO(self.colors.repeat(3, 0), 'GL_STATIC_DRAW') # each triplet of vertices shares the color self.initialized = True def display(self, mode_2d=False): glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_COLOR_ARRAY) self._display_movements(mode_2d) if self.arrows_enabled: self._display_arrows() glDisableClientState(GL_COLOR_ARRAY) glDisableClientState(GL_VERTEX_ARRAY) def _display_movements(self, mode_2d=False): self.vertex_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.vertex_color_buffer.bind() glColorPointer(4, GL_FLOAT, 0, None) if mode_2d: glScale(1.0, 1.0, 0.0) # discard z coordinates start = self.layer_stops[self.num_layers_to_draw - 1] end = self.layer_stops[self.num_layers_to_draw] - start else: # 3d start = 0 end = self.layer_stops[self.num_layers_to_draw] glDrawArrays(GL_LINES, start, end) self.vertex_buffer.unbind() self.vertex_color_buffer.unbind() def _display_arrows(self): self.arrow_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.arrow_color_buffer.bind() glColorPointer(4, GL_FLOAT, 0, None) start = (self.layer_stops[self.num_layers_to_draw - 1] // 2) * 3 end = (self.layer_stops[self.num_layers_to_draw] // 2) * 3 glDrawArrays(GL_TRIANGLES, start, end - start) self.arrow_buffer.unbind() self.arrow_color_buffer.unbind()
class GcodeModel(Model): """ Model for displaying Gcode data. """ # vertices for arrow to display the direction of movement arrow = numpy.require([ [0.0, 0.0, 0.0], [0.4, -0.1, 0.0], [0.4, 0.1, 0.0], ], 'f') layer_entry_marker = numpy.require([ [ 0.23, -0.14, 0.0], [ 0.0, 0.26, 0.0], [-0.23, -0.14, 0.0], ], 'f') layer_exit_marker = numpy.require([ [-0.23, -0.23, 0.0], [ 0.23, -0.23, 0.0], [ 0.23, 0.23, 0.0], [ 0.23, 0.23, 0.0], [-0.23, 0.23, 0.0], [-0.23, -0.23, 0.0], ], 'f') def load_data(self, model_data, callback=None): t_start = time.time() vertex_list = [] color_list = [] self.layer_stops = [0] self.layer_heights = [] arrow_list = [] layer_markers_list = [] self.layer_marker_stops = [0] num_layers = len(model_data) callback_every = max(1, int(math.floor(num_layers / 100))) # the first movement designates the starting point start = prev = model_data[0][0] del model_data[0][0] for layer_idx, layer in enumerate(model_data): first = layer[0] for movement in layer: vertex_list.append(prev.v) vertex_list.append(movement.v) arrow = self.arrow # position the arrow with respect to movement arrow = vector.rotate(arrow, movement.angle(prev.v), 0.0, 0.0, 1.0) arrow_list.extend(arrow) vertex_color = self.movement_color(movement) color_list.append(vertex_color) prev = movement self.layer_stops.append(len(vertex_list)) self.layer_heights.append(first.v[2]) # add the layer entry marker if layer_idx > 0 and len(model_data[layer_idx - 1]) > 0: layer_markers_list.extend(self.layer_entry_marker + model_data[layer_idx-1][-1].v) elif layer_idx == 0 and len(layer) > 0: layer_markers_list.extend(self.layer_entry_marker + layer[0].v) # add the layer exit marker if len(layer) > 1: layer_markers_list.extend(self.layer_exit_marker + layer[-1].v) self.layer_marker_stops.append(len(layer_markers_list)) if callback and layer_idx % callback_every == 0: callback(layer_idx + 1, num_layers) self.vertices = numpy.array(vertex_list, 'f') self.colors = numpy.array(color_list, 'f') self.arrows = numpy.array(arrow_list, 'f') self.layer_markers = numpy.array(layer_markers_list, 'f') # by translating the arrow vertices outside of the loop, we achieve a # significant performance gain thanks to numpy. it would be really nice # if we could rotate in a similar fashion... self.arrows = self.arrows + self.vertices[1::2].repeat(3, 0) # for every pair of vertices of the model, there are 3 vertices for the arrow assert len(self.arrows) == ((len(self.vertices) // 2) * 3), \ 'The 2:3 ratio of model vertices to arrow vertices does not hold.' self.max_layers = len(self.layer_stops) - 1 self.num_layers_to_draw = self.max_layers self.arrows_enabled = True self.initialized = False self.vertex_count = len(self.vertices) t_end = time.time() logging.info('Initialized Gcode model in %.2f seconds' % (t_end - t_start)) logging.info('Vertex count: %d' % self.vertex_count) def movement_color(self, move): """ Return the color to use for particular type of movement. """ # default movement color is gray color = (0.6, 0.6, 0.6, 0.6) extruder_on = (move.flags & Movement.FLAG_EXTRUDER_ON or move.delta_e > 0) outer_perimeter = (move.flags & Movement.FLAG_PERIMETER and move.flags & Movement.FLAG_PERIMETER_OUTER) if extruder_on and outer_perimeter: color = (0.0, 0.875, 0.875, 0.6) # cyan elif extruder_on and move.flags & Movement.FLAG_PERIMETER: color = (0.0, 1.0, 0.0, 0.6) # green elif extruder_on and move.flags & Movement.FLAG_LOOP: color = (1.0, 0.875, 0.0, 0.6) # yellow elif extruder_on: color = (1.0, 0.0, 0.0, 0.6) # red return color # ------------------------------------------------------------------------ # DRAWING # ------------------------------------------------------------------------ def init(self): self.vertex_buffer = VBO(self.vertices, 'GL_STATIC_DRAW') self.vertex_color_buffer = VBO(self.colors.repeat(2, 0), 'GL_STATIC_DRAW') # each pair of vertices shares the color if self.arrows_enabled: self.arrow_buffer = VBO(self.arrows, 'GL_STATIC_DRAW') self.arrow_color_buffer = VBO(self.colors.repeat(3, 0), 'GL_STATIC_DRAW') # each triplet of vertices shares the color self.layer_marker_buffer = VBO(self.layer_markers, 'GL_STATIC_DRAW') self.initialized = True def display(self, elevation=0, eye_height=0, mode_ortho=False, mode_2d=False): glPushMatrix() offset_z = self.offset_z if not mode_2d else 0 glTranslate(self.offset_x, self.offset_y, offset_z) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_COLOR_ARRAY) self._display_movements(elevation, eye_height, mode_ortho, mode_2d) if self.arrows_enabled: self._display_arrows() glDisableClientState(GL_COLOR_ARRAY) if self.arrows_enabled: self._display_layer_markers() glDisableClientState(GL_VERTEX_ARRAY) glPopMatrix() def _display_movements(self, elevation=0, eye_height=0, mode_ortho=False, mode_2d=False): self.vertex_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.vertex_color_buffer.bind() glColorPointer(4, GL_FLOAT, 0, None) if mode_2d: glScale(1.0, 1.0, 0.0) # discard z coordinates start = self.layer_stops[self.num_layers_to_draw - 1] end = self.layer_stops[self.num_layers_to_draw] glDrawArrays(GL_LINES, start, end - start) elif mode_ortho: if elevation >= 0: # draw layers in normal order, bottom to top start = 0 end = self.layer_stops[self.num_layers_to_draw] glDrawArrays(GL_LINES, start, end - start) else: # draw layers in reverse order, top to bottom stop_idx = self.num_layers_to_draw - 1 while stop_idx >= 0: start = self.layer_stops[stop_idx] end = self.layer_stops[stop_idx + 1] glDrawArrays(GL_LINES, start, end - start) stop_idx -= 1 else: # 3d projection mode reverse_threshold_layer = self._layer_up_to_height(eye_height - self.offset_z) if reverse_threshold_layer >= 0: # draw layers up to (and including) the threshold in normal order, bottom to top normal_layers_to_draw = min(self.num_layers_to_draw, reverse_threshold_layer + 1) start = 0 end = self.layer_stops[normal_layers_to_draw] glDrawArrays(GL_LINES, start, end - start) if reverse_threshold_layer + 1 < self.num_layers_to_draw: # draw layers from the threshold in reverse order, top to bottom stop_idx = self.num_layers_to_draw - 1 while stop_idx > reverse_threshold_layer: start = self.layer_stops[stop_idx] end = self.layer_stops[stop_idx + 1] glDrawArrays(GL_LINES, start, end - start) stop_idx -= 1 self.vertex_buffer.unbind() self.vertex_color_buffer.unbind() def _layer_up_to_height(self, height): """Return the index of the last layer lower than height.""" for idx in range(len(self.layer_heights) - 1, -1, -1): if self.layer_heights[idx] < height: return idx return 0 def _display_arrows(self): self.arrow_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.arrow_color_buffer.bind() glColorPointer(4, GL_FLOAT, 0, None) start = (self.layer_stops[self.num_layers_to_draw - 1] // 2) * 3 end = (self.layer_stops[self.num_layers_to_draw] // 2) * 3 glDrawArrays(GL_TRIANGLES, start, end - start) self.arrow_buffer.unbind() self.arrow_color_buffer.unbind() def _display_layer_markers(self): self.layer_marker_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) start = self.layer_marker_stops[self.num_layers_to_draw - 1] end = self.layer_marker_stops[self.num_layers_to_draw] glColor4f(0.6, 0.6, 0.6, 0.6) glDrawArrays(GL_TRIANGLES, start, end - start) self.layer_marker_buffer.unbind()
class MSGLCanvas2D(QGLWidget): """ Canvas GL plotting in 2 dimensions """ MAX = 100. corner_=100.0 zoom_= 1.5 xrot_=220 yrot_ = 220 trans_x_ =0.0 trans_y_ = 0.0 def __init__(self, data, parent=None, **kw): """ Constructor, initialization """ QGLWidget.__init__(self, parent) self.setFormat(QGLFormat(QGL.SampleBuffers)) self.setMinimumSize(500,300)#300 self.setMouseTracking(True) self.setFocusPolicy(Qt.StrongFocus) self.data=data vertexes=[] colors=[] from utils.misc import IceAndFire maxY=max(map(max, [log10(el.y_data) for el in data])) maxX=max(map(max, [el.x_data for el in data])) rtmax=max([z.rtmin for z in data]) for el in data: for i, x in enumerate(el.x_data): c=IceAndFire.getQColor(log10(el.y_data[i])/maxY) colors.append(c) vertexes.append([(x*2*self.corner_)/maxX, (el.rt*2*self.corner_)/rtmax]) from OpenGL.arrays.vbo import VBO self.vertexes= VBO(array(vertexes,'f')) self.colors=VBO(array(colors,'f')) self.mode = "None" # "ZOOMING", "PANNING", "NONE" self.lastpos = QPoint() self.counter_trans_x = 0 self.counter_trans_y = 0 self.defaultColors = {'ticks':(0.,0.,0.,0.), 'axes':(0.,0.,0.,0.), 'curves':(0.,0.,1.,0.), 'backgroundColor':(1.,1.,1.,1.) } #self.axes=self.drawAxes() self.transformationMatrix = self.setupTransformationMatrix(self.width(), self.height()) def setupTransformationMatrix(self,w, h): """ use a matrix to translate in the gl landmark """ m = QMatrix() m.translate(-w/2, h/2) m.scale(300./w, 300./h) print w, h, w/300., 1-((h/300)-1) #m.scale((self.width()*100)/300, -(self.height()*100)/300) #self.currentSize.x = w #self.currentSize.y = h return m def inGLCoordinate(self, point): return self.transformationMatrix.map(point) def resizeGL(self, w, h): """ called when window is being resized """ glViewport(0,0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_*self.zoom_, self.corner_*self.zoom_, -self.corner_*self.zoom_, self.corner_*self.zoom_) #self.transformationMatrix = self.setupTransformationMatrix(w, h) glMatrixMode(GL_MODELVIEW) def initializeGL(self): """needed, initialize GL parameters""" #glClearColor(1.,1.,1.,1.) glDisable(GL_DEPTH_TEST) glEnable(GL_LINE_SMOOTH) glEnable(GL_POINT_SMOOTH) glHint (GL_LINE_SMOOTH_HINT, GL_NICEST) glLoadIdentity() #model view by default # self.grid_lines = self.drawGridLines() # self.ticks =self.drawAxisTick() # self.axes = self.drawAxes() def paintGL(self): """Draw the scene, needed, called each time glDraw""" glClear(GL_COLOR_BUFFER_BIT) glTranslated(self.trans_x_, self.trans_y_, 0.) #addition glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_*self.zoom_, self.corner_*self.zoom_, -self.corner_*self.zoom_, self.corner_*self.zoom_) glMatrixMode(GL_MODELVIEW) #end addition #glCallList(self.grid_lines) #glCallList(self.ticks) #glCallList(self.axes) glLineWidth(30.0) self.scatterPlot() # if self.flags == "chrom": # self.drawAxisLegend("retention time[s]", "intensity[%]") # glCallList(self.lines) # elif self.flags == "spectrum": # self.drawAxisLegend("m/z", "intensity") def drawAxes(self, width=2., colour=(0.,0.,0.)): """ Draw Axes """ #width must be a float axes = glGenLists(1) glNewList(axes, GL_COMPILE) glLineWidth(width) glColor(colour[0],colour[1],colour[2]) glBegin(GL_LINES) #x_achse glVertex2d(-self.corner_, -self.corner_) glVertex2d( self.corner_, -self.corner_) #y-achse glVertex2d(-self.corner_, -self.corner_) glVertex2d( -self.corner_, self.corner_) glEnd() glEndList() return axes def drawLegends(self, pos): """ draw legend at the specified position """ pass def drawAxisLegend(self, x_label, y_label): """ Draw Axis Legend """ font =QFont("Typewriter") #RT axis legend font.setPixelSize(12) self.renderText(self.corner_, -self.corner_-20.0, 0., x_label)# font self.renderText(-self.corner_-20.0, self.corner_, 0., y_label, font) def resetTranslations(self): """ reset the different translation to 0 """ self.trans_x_ =0. self.trans_y_ =0. self.counter_trans_x=0. self.counter_trans_y=0. def normalizeAngle(self,angle): while (angle < 0): angle += 360 * 16 while (angle > 360 * 16): angle -= 360 * 16 ########DRAWING METHODS################################################## def drawLine(self, point_, point): glBegin(GL_LINES) glVertex2d(point_.x(), point_.y()) glVertex2d(point.x(), point.y()) glEnd() def drawRect(self, p_1, p_2, p_3=None, p_4 = None): pass def drawOnePoint(self, point, colour= Qt.yellow): pass def scatterPlot(self): """ Draw Data (x, y)""" if self.vertexes is not None and self.colors is not None: self.vertexes.bind() glEnableClientState(GL_VERTEX_ARRAY) glVertexPointerf(self.vertexes) self.colors.bind() glEnableClientState(GL_COLOR_ARRAY) glColorPointerf(self.colors) glDrawArrays(GL_LINES, 0, len(self.vertexes)) self.vertexes.unbind() self.colors.unbind() #self.textures.unbind() glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) def spectrumPlot(self, points): pass def histogramPlot(self, points, bin = 5.): pass def barPlot(points, width =2.):pass ########MOUSE AND KEYBOARDS EVENTS########################################################################### def wheelEvent(self, event): if event.delta() >0: self.zoom_ -= .05 else: self.zoom_ += .05 glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_*self.zoom_, self.corner_*self.zoom_, -self.corner_*self.zoom_, self.corner_*self.zoom_) self.updateGL() glMatrixMode(GL_MODELVIEW) event.accept() def keyPressEvent(self, event): if event.key() == Qt.Key_Plus: self.zoom_ -= .1 glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_*self.zoom_, self.corner_*self.zoom_, -self.corner_*self.zoom_, self.corner_*self.zoom_) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Minus: self.zoom_ += .1 glMatrixMode(GL_PROJECTION) #// You had GL_MODELVIEW glLoadIdentity() gluOrtho2D(-self.corner_*self.zoom_, self.corner_*self.zoom_, -self.corner_*self.zoom_, self.corner_*self.zoom_) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Up: self.trans_y_ += 2 self.counter_trans_y +=2 if event.key() == Qt.Key_Down: self.trans_y_ -=2 self.counter_trans_y -=2 if event.key() == Qt.Key_Left: self.trans_x_ -=2 self.counter_trans_x -=2 if event.key() == Qt.Key_Right: self.trans_x_ +=2 self.counter_trans_x +=2 if event.key() == Qt.Key_Z: self.mode= "ZOOMING" if self.counter_trans_x < 0 and self.counter_trans_y < 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x += 1 self.counter_trans_y += 1 if self.counter_trans_x > 0 and self.counter_trans_y < 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x -= 1 self.counter_trans_y += 1 if self.counter_trans_x < 0 and self.counter_trans_y > 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x += 1 self.counter_trans_y -= 1 if self.counter_trans_x < 0 and self.counter_trans_y > 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x -= 1 self.counter_trans_y -= 1 if self.zoom_ != 1.5: self.zoom = 1.5 #self.updateGL() self.updateGL() self.resetTranslations() def mousePressEvent(self, event): if self.mode == "ZOOMING": self.mode = "None" self.computeSelection() else: self.lastpos = QPoint(event.pos()) self.setCursor(QCursor(Qt.ClosedHandCursor)) #if event.buttons() == Qt.RightButton: # self.mode = "PANNING" def computeSelection(self): print "selected" def mouseMoveEvent(self, event): dx = event.x() - self.lastpos.x() dy = event.y() - self.lastpos.y() if self.mode == "ZOOMING": font = QFont("Typewriter") self.renderText(-self.corner_ -30.0, self.corner_, 0., "ZOOMING MODE ACTIVATED", font) self.updateGL() glColor(0., 0., 1., .5) XMAX = 900.; XMIN = 180. pointer_x = (self.lastpos.x()*200.)/XMAX norm_dx = (dx*200.)/XMAX """ if pointer_x > 100. or pointer_x < 100. \ or norm_dx >100. or norm_dx<-100.: event.ignore() """ glBegin(GL_QUADS) glVertex2d(pointer_x, -100.) glVertex2d(pointer_x+ norm_dx, -100.) glVertex2d(pointer_x+ norm_dx, 100.) glVertex2d(pointer_x, 100.) glEnd() self.updateGL()#update for seeing the rectangle mapping = self.mapFromGlobal cursorPos = self.inGLCoordinate(mapping(self.cursor().pos())) QToolTip.showText(self.cursor().pos(), "x:"+str(cursorPos.x())+ \ ", y:"+str(cursorPos.y()) ) if self.mode == "None": if event.buttons()== Qt.LeftButton: self.trans_y_ -= dy/5 self.counter_trans_y -= dy/5 self.trans_x_ += dx/5 self.counter_trans_x += dx/5 self.lastpos = QPoint(event.pos()) self.glDraw() self.resetTranslations() def mouseReleaseEvent(self, event): self.setCursor(QCursor(Qt.ArrowCursor))
class GcodeModel(Model): """ Model for displaying Gcode data. """ # vertices for arrow to display the direction of movement arrow = numpy.require([ [0.0, 0.0, 0.0], [0.4, -0.1, 0.0], [0.4, 0.1, 0.0], ], 'f') def load_data(self, model_data, callback=None): t_start = time.time() vertex_list = [] color_list = [] self.layer_stops = [0] arrow_list = [] num_layers = len(model_data) for layer_idx, layer in enumerate(model_data): for movement in layer: vertex_list.append(movement.src) vertex_list.append(movement.dst) arrow = self.arrow # position the arrow with respect to movement arrow = vector.rotate(arrow, movement.angle(), 0.0, 0.0, 1.0) arrow_list.extend(arrow) vertex_color = self.movement_color(movement) color_list.append(vertex_color) self.layer_stops.append(len(vertex_list)) if callback: callback(layer_idx + 1, num_layers) self.vertices = numpy.array(vertex_list, 'f') self.colors = numpy.array(color_list, 'f') self.arrows = numpy.array(arrow_list, 'f') # by translating the arrow vertices outside of the loop, we achieve a # significant performance gain thanks to numpy. it would be really nice # if we could rotate in a similar fashion... self.arrows = self.arrows + self.vertices[1::2].repeat(3, 0) # for every pair of vertices of the model, there are 3 vertices for the arrow assert len(self.arrows) == ((len(self.vertices) // 2) * 3), \ 'The 2:3 ratio of model vertices to arrow vertices does not hold.' self.max_layers = len(self.layer_stops) - 1 self.num_layers_to_draw = self.max_layers self.arrows_enabled = True self.initialized = False t_end = time.time() logging.info('Initialized Gcode model in %.2f seconds' % (t_end - t_start)) logging.info('Vertex count: %d' % len(self.vertices)) def movement_color(self, move): """ Return the color to use for particular type of movement. """ # default movement color is gray color = [0.6, 0.6, 0.6, 0.6] extruder_on = (move.flags & Movement.FLAG_EXTRUDER_ON or move.delta_e > 0) outer_perimeter = (move.flags & Movement.FLAG_PERIMETER and move.flags & Movement.FLAG_PERIMETER_OUTER) if extruder_on and outer_perimeter: color = [0.0, 0.875, 0.875, 0.6] # cyan elif extruder_on and move.flags & Movement.FLAG_PERIMETER: color = [0.0, 1.0, 0.0, 0.6] # green elif extruder_on and move.flags & Movement.FLAG_LOOP: color = [1.0, 0.875, 0.0, 0.6] # yellow elif extruder_on: color = [1.0, 0.0, 0.0, 0.6] # red return color # ------------------------------------------------------------------------ # DRAWING # ------------------------------------------------------------------------ def init(self): self.vertex_buffer = VBO(self.vertices, 'GL_STATIC_DRAW') self.vertex_color_buffer = VBO(self.colors.repeat(2, 0), 'GL_STATIC_DRAW') # each pair of vertices shares the color if self.arrows_enabled: self.arrow_buffer = VBO(self.arrows, 'GL_STATIC_DRAW') self.arrow_color_buffer = VBO(self.colors.repeat(3, 0), 'GL_STATIC_DRAW') # each triplet of vertices shares the color self.initialized = True def display(self, mode_2d=False): glPushMatrix() glTranslate(self.offset_x, self.offset_y, 0) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_COLOR_ARRAY) self._display_movements(mode_2d) if self.arrows_enabled: self._display_arrows() glDisableClientState(GL_COLOR_ARRAY) glDisableClientState(GL_VERTEX_ARRAY) glPopMatrix() def _display_movements(self, mode_2d=False): self.vertex_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.vertex_color_buffer.bind() glColorPointer(4, GL_FLOAT, 0, None) if mode_2d: glScale(1.0, 1.0, 0.0) # discard z coordinates start = self.layer_stops[self.num_layers_to_draw - 1] end = self.layer_stops[self.num_layers_to_draw] - start else: # 3d start = 0 end = self.layer_stops[self.num_layers_to_draw] glDrawArrays(GL_LINES, start, end) self.vertex_buffer.unbind() self.vertex_color_buffer.unbind() def _display_arrows(self): self.arrow_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.arrow_color_buffer.bind() glColorPointer(4, GL_FLOAT, 0, None) start = (self.layer_stops[self.num_layers_to_draw - 1] // 2) * 3 end = (self.layer_stops[self.num_layers_to_draw] // 2) * 3 glDrawArrays(GL_TRIANGLES, start, end - start) self.arrow_buffer.unbind() self.arrow_color_buffer.unbind()
class TextDrawer: def __init__(self): self.face = None self.textures = dict() # compile rendering program self.renderProgram = GLProgram(_textVertexShaderSource, _textFragmentShaderSource) self.renderProgram.compile_and_link() # make projection uniform self.projectionUniform = GLUniform(self.renderProgram.get_program_id(), 'projection', 'mat4f') self.textColorUniform = GLUniform(self.renderProgram.get_program_id(), 'textColor', 'vec3f') self.textureSizeUniform = GLUniform( self.renderProgram.get_program_id(), 'textureSize', 'vec2f') # create rendering buffer self.vbo = VBO(_get_rendering_buffer(0, 0, 0, 0)) self.vbo.create_buffers() self.vboId = glGenBuffers(1) # initialize VAO self.vao = glGenVertexArrays(1) glBindVertexArray(self.vao) glBindBuffer(GL_ARRAY_BUFFER, self.vboId) self.vbo.bind() self.vbo.copy_data() glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 5 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(3 * ctypes.sizeof(ctypes.c_float))) glEnableVertexAttribArray(1) # self.vbo.unbind() glBindVertexArray(0) self.zNear = -1.0 self.zFar = 1.0 def delete(self): self.textures.clear() self.face = None self.renderProgram.delete() self.projectionUniform = None self.textColorUniform = None self.textureSizeUniform = None self.vbo.delete() glDeleteVertexArrays(1, [self.vao]) def load_font(self, fontFilename, fontSize): assert os.path.exists(fontFilename) self.textures.clear() self.face = ft.Face(fontFilename) self.face.set_char_size(fontSize) # load all ASCII characters for i in range(128): self.load_character(chr(i)) def load_character(self, character): assert self.face is not None assert len(character) == 1 if character not in self.textures: # load glyph in freetype self.face.load_char(character) ftBitmap = self.face.glyph.bitmap height, width = ftBitmap.rows, ftBitmap.width bitmap = np.array(ftBitmap.buffer, dtype=np.uint8).reshape( (height, width)) # create texture texture = _create_text_texture(bitmap) # add texture object to the dictionary characterSlot = CharacterSlot(texture, self.face.glyph) self.textures[character] = characterSlot def get_character(self, ch): if ch not in self.textures: self.load_character(ch) return self.textures[ch] def _draw_text(self, text, textPos, windowSize, scale, linespread, foreColor): if len(text) == 0: return blendEnabled = glIsEnabled(GL_BLEND) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) self.renderProgram.use() glBindVertexArray(self.vao) glActiveTexture(GL_TEXTURE0) foreColor = np.asarray(foreColor, np.float32) self.textColorUniform.update(foreColor) projectionMat = orthographic_projection(0.0, windowSize[0], 0.0, windowSize[1], self.zNear, self.zFar) self.projectionUniform.update(projectionMat) lineY = textPos[1] nowX = textPos[0] # split text into lines lines = text.split('\n') for line in lines: if len(line) > 0: # analyze this line bearings = [] for ch in line: charSlot = self.get_character(ch) bearings.append(charSlot.bearing[1] * scale[1]) maxBearings = max(bearings) for ch in line: charSlot = self.get_character(ch) xpos = nowX + charSlot.bearing[0] * scale[0] yLowerd = (maxBearings - charSlot.bearing[1] * scale[1]) ypos = lineY - yLowerd w = charSlot.textureSize[0] * scale[0] h = charSlot.textureSize[1] * scale[1] self.textureSizeUniform.update(np.array((w, h), np.float32)) charSlot.texture.bind() self.vbo.bind() self.vbo.set_array( _get_rendering_buffer(xpos, ypos, w, h, 0.999)) self.vbo.copy_data() self.vbo.unbind() glDrawArrays(GL_TRIANGLES, 0, 6) charSlot.texture.unbind() # the advance is number of 1/64 pixels nowX += (charSlot.advance / 64.0) * scale[0] nowX = textPos[0] yOffset = self.get_character( 'X').textureSize[1] * scale[1] * linespread lineY -= yOffset glBindVertexArray(0) if not blendEnabled: glDisable(GL_BLEND) def draw_text(self, text, textPos, windowSize, color=(1.0, 1.0, 1.0), scale=(1.0, 1.0), linespread=1.5): return self._draw_text(text, textPos, windowSize, scale, linespread, color)
prog = shaderutil.createProgram("./shader.vs", "./shader.fs") mvploc = glGetUniformLocation(prog, "mvp") positionloc = glGetAttribLocation(prog, "vs_position") colorloc = glGetAttribLocation(prog, "vs_color") # Setup VAO vertobj = glGenVertexArrays(1) glBindVertexArray(vertobj) # Setup the VBO (using the fancy VBO Object from pyopengl, doing it "manually" would also be a possibility) vertbuf = VBO(cubedata, GL_STATIC_DRAW) vertbuf.bind() glEnableVertexAttribArray(positionloc) glEnableVertexAttribArray(colorloc) glVertexAttribPointer(positionloc, 4, GL_FLOAT, GL_TRUE, 8 * 4, vertbuf+0) # "+0" since we need to create an offset. glVertexAttribPointer(colorloc, 4, GL_FLOAT, GL_TRUE, 8 * 4, vertbuf+16) # 4 * 4 Bytes per float. vertbuf.unbind() # We can unbind the VBO, since it's linked to the VAO # glBindVertexArray(0) running = True t = time.time() rotation = 0.0 while running: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glUseProgram(prog) glUniformMatrix4fv(mvploc, 1, GL_TRUE, hm.rotation(mvp, rotation,[0,1,0]).tolist()) # glBindVertexArray(vertobj) glDrawArrays(GL_TRIANGLE_STRIP, 0, 14) glDrawArrays(GL_POINTS, 0, 14) glfwSwapBuffers() # glfwPollEvents() # This would poll for key/mouse events manually. # Do the rotation thing...
class Drawable(Attributes): """Base class for objects that can be rendered by the OpenGL engine. This is the basic drawable object in the pyFormex OpenGL rendering engine. It collects all the data that are needed to properly described any object to be rendered by the OpenGL shader programs. It has a multitude of optional attributes allowing it to describe many very different objects and rendering situations. This class is however not intended to be directly used to construct an object for rendering. The :class:`Actor` class and its multiple subclasses should be used for that purpose. The Actor classes provide an easier and more logical interface, and more powerful at the same time, since they can be compound: one Actor can hold multiple Drawables. The elementary objects that can be directly drawn by the shader programs are more simple, yet very diverse. The Drawable class collects all the data that are needed by the OpenGL engine to do a proper rendering of the object. It this represents a single, versatile interface of the Actor classes with the GPU shader programs. The versatility comes from the :class:`Attributes` base class, with an unlimited set of attributes. Any undefined attribute just returns None. Some of the most important attributes are described hereafter: - `rendertype`: int: the type of rendering process that will be applied by the rendering engine to the Drawable: 0: A full 3D Actor. The Drawable will be rendered in full 3D with all active capabilities, such as camera rotation, projection, rendermode, lighting. The full object undergoes the camera transformations, and thus will appear as a 3D object in space. The object's vertices are defined in 3D world coordinates. Used in: :class:`Actor`. 1: A 2D object (often a text or an image) inserted at a 3D position. The 2D object always keeps its orientation towards the camera. When the camera changes, the object can change its position on the viewport, but the oject itself looks the same. This can be used to add annotations to (parts of) a 3D object. The object is defined in viewport coordinates, the insertion points are in 3D world coordinates. Used in: :class:`textext.Text`. 2: A 2D object inserted at a 2D position. Both object and position are defined in viewport coordinates. The object will take a fixed position on the viewport. This can be use to add decorations to the viewport (like color legends and background images). Used in: :class:`decors.ColorLegend`. 3: Like 2, but with special purpose. These Drawables are not part of the user scene, but used for system purposes (like setting the background color, or adding an elastic rectangle during mouse picking). Used in: :meth:`Canvas.createBackground`. -1: Like 1, but with different insertion points for the multiple items in the object. Used to place a list of marks at a list of points. Used in: :class:`textext.Text`. -2: A 3D object inserted at a 2D position. The 3D object will rotate when the camera changes directions, but it will always be located on the same position of the viewport. This is normally used to display a helper object showing the global axis directions. Used in: :class:`decors.Triade`. The initialization of a Drawable takes a single parameter: `parent`, which is the Actor that created the Drawable. All other parameters should be keyword arguments, and are stored as attributes in the Drawable. Methods: - `prepare...`: creates sanitized and derived attributes/data. Its action pend on current canvas settings: mode, transparent, avgnormals - `render`: push values to shader and render the object: depends on canvas and renderer. - `pick`: fake render to be used during pick operations - `str`: format the full data set of the Drawable """ # A list of acceptable attributes in the drawable # These are the parent attributes that can be overridden attributes = [ 'cullface', 'subelems', 'color', 'name', 'highlight', 'opak', 'linewidth', 'pointsize', 'lighting', 'offset', 'vbo', 'nbo', 'ibo', 'alpha', 'drawface', 'objectColor', 'useObjectColor', 'rgbamode', 'texture', 'texcoords', ] def __init__(self, parent, **kargs): """Create a new drawable.""" # Should we really restrict this???? #kargs = utils.selectDict(kargs, Drawable.attributes) Attributes.__init__(self, kargs, default=parent) #print("ATTRIBUTES STORED IN DRAWABLE",self) #print("ATTRIBUTES STORED IN PARENT",parent) # Default lighting parameter: # rendertype 0 (3D) follows canvas lighting # other rendertypes set lighting=False by default if self.rendertype != 0 and self.lighting is None: self.lighting = False # The final plexitude of the drawn objects if self.subelems is not None: self.nplex = self.subelems.shape[-1] else: self.nplex = self._fcoords.shape[-2] self.glmode = glObjType(self.nplex) self.prepareColor() #self.prepareNormals() # The normals are currently always vertex self.prepareSubelems() if self.texture is not None: self.prepareTexture() def prepareColor(self): """Prepare the colors for the shader.""" # # This should probably be moved to Actor # if self.highlight: # we set single highlight color in shader # Currently do everything in Formex model # And we always need this one self.avbo = VBO(self.fcoords) self.useObjectColor = 1 self.objectColor = np.array(colors.red) elif self.color is not None: #print("COLOR",self.color) if self.color.ndim == 1: # here we only accept a single color for front and back # different colors should have been handled before self.useObjectColor = 1 self.objectColor = self.color elif self.color.ndim == 2: self.useObjectColor = 0 self.vertexColor = at.multiplex(self.color, self.object.nplex()) #pf.debug("Multiplexing colors: %s -> %s " % (self.color.shape, self.vertexColor.shape),pf.DEBUG.OPENGL2) elif self.color.ndim == 3: self.useObjectColor = 0 self.vertexColor = self.color if self.vertexColor is not None: #print("Shader suffix:[%s]" % pf.options.shader) if pf.options.shader == 'alpha': self.alpha = 0.5 if self.vertexColor.shape[-1] == 3: # Expand to 4 !!! self.vertexColor = at.growAxis(self.vertexColor, 1, fill=0.5) self.cbo = VBO(self.vertexColor.astype(float32)) if pf.options.shader == 'alpha': size_report("Created cbo VBO", self.cbo) self.rgbamode = self.useObjectColor == 0 and self.vertexColor.shape[ -1] == 4 #### TODO: should we make this configurable ?? # # !!!!!!!!!!!! Fix a bug with AMD cards !!!!!!!!!!!!!!! # # it turns out that some? AMD? cards do not like an unbound cbo # even if that attribute is not used in the shader. # Creating a dummy color buffer seems to solve that problem # if self.cbo is None: self.cbo = VBO(np.array(colors.red)) #if self.rendertype == 3: # print("CBO DATA %s\n" % self.name,self.cbo.data) def changeVertexColor(self, color): """Change the vertex color buffer of the object. This is experimental!!! Just make sure that the passed data have the correct shape! """ if self.useObjectColor: return if pf.options.shader == 'alpha': #if color.size != self.cbo.size: size_report('color', color) size_report('cbo', self.cbo) print(self.cbo.size / color.size) print("Can not change vertex color from shape %s to shape %s" % (str(self.cbo.shape), str(color.shape))) #return self.vertexColor = self.color self.cbo = VBO(color.astype(float32)) if pf.options.shader == 'alpha': print("Replace cbo with") size_report('cbo', self.cbo) def prepareTexture(self): """Prepare texture and texture coords""" if self.useTexture == 1: if self.texcoords.ndim == 2: #curshape = self.texcoords.shape self.texcoords = at.multiplex(self.texcoords, self.object.nelems(), axis=-2) #print("Multiplexing texture coords: %s -> %s " % (curshape, self.texcoords.shape)) self.tbo = VBO(self.texcoords.astype(float32)) self.texture.activate() def prepareSubelems(self): """Create an index buffer to draw subelements This is always used for nplex > 3, but also to draw the edges for nplex=3. """ if self.ibo is None and self.subelems is not None: self.ibo = VBO(self.subelems.astype(int32), target=GL.GL_ELEMENT_ARRAY_BUFFER) def render(self, renderer): """Render the geometry of this object""" def render_geom(): if self.ibo: GL.glDrawElementsui(self.glmode, self.ibo) else: GL.glDrawArrays(self.glmode, 0, np.asarray(self.vbo.shape[:-1]).prod()) if self.offset: pf.debug("POLYGON OFFSET", pf.DEBUG.DRAW) GL.glPolygonOffset(1.0, 1.0) if self.linewidth: GL.glLineWidth(self.linewidth) renderer.shader.loadUniforms(self) if self.offset3d is not None: offset = renderer.camera.toNDC(self.offset3d) offset[..., 2] = 0. offset += (1., 1., 0.) #print(self.rendertype) #print("OFFSET=",offset) #print("COORDS=",self.vbo.data) if offset.shape == (3, ): renderer.shader.uniformVec3('offset3', offset) elif offset.ndim > 1: self.obo = VBO(offset.astype(float32)) #self.obo = VBO(self._default_dict_.fcoords+offset) #print(self._default_dict_.fcoords) #print(offset) #print(self.obo.data.shape,self.vbo.data.shape) self.obo.bind() GL.glEnableVertexAttribArray( renderer.shader.attribute['vertexOffset']) GL.glVertexAttribPointer( renderer.shader.attribute['vertexOffset'], 3, GL.GL_FLOAT, False, 0, self.obo) if self.rendertype == -2: # This is currently a special code for the Triade # It needs an object with coords in pixel values, # centered around the origin # and must have attributes x,y, set to the viewport # position of the (0,0,0) point after rotation. # rot = renderer.camera.modelview.rot x = np.dot(self._fcoords.reshape(-1, 3), rot).reshape(self._fcoords.shape) x[:, :, 0] += self.x x[:, :, 1] += self.y x[:, :, 2] = 0 self.vbo = VBO(x) self.vbo.bind() GL.glEnableVertexAttribArray(renderer.shader.attribute['vertexCoords']) GL.glVertexAttribPointer(renderer.shader.attribute['vertexCoords'], 3, GL.GL_FLOAT, False, 0, self.vbo) if self.ibo: self.ibo.bind() if self.nbo: self.nbo.bind() GL.glEnableVertexAttribArray( renderer.shader.attribute['vertexNormal']) GL.glVertexAttribPointer(renderer.shader.attribute['vertexNormal'], 3, GL.GL_FLOAT, False, 0, self.nbo) if self.cbo: self.cbo.bind() GL.glEnableVertexAttribArray( renderer.shader.attribute['vertexColor']) GL.glVertexAttribPointer(renderer.shader.attribute['vertexColor'], self.cbo.shape[-1], GL.GL_FLOAT, False, 0, self.cbo) if self.tbo: self.tbo.bind() GL.glEnableVertexAttribArray( renderer.shader.attribute['vertexTexturePos']) GL.glVertexAttribPointer( renderer.shader.attribute['vertexTexturePos'], 2, GL.GL_FLOAT, False, 0, self.tbo) if self.cullface == 'front': # Draw back faces GL.glEnable(GL.GL_CULL_FACE) GL.glCullFace(GL.GL_FRONT) elif self.cullface == 'back': # Draw front faces GL.glEnable(GL.GL_CULL_FACE) GL.glCullFace(GL.GL_BACK) else: GL.glDisable(GL.GL_CULL_FACE) # Specifiy the depth comparison function if self.ontop: GL.glDepthFunc(GL.GL_ALWAYS) # Bind the texture if self.texture: self.texture.bind() render_geom() if self.ibo: self.ibo.unbind() if self.obo: self.obo.unbind() GL.glDisableVertexAttribArray( renderer.shader.attribute['vertexOffset']) if self.cbo: self.cbo.unbind() GL.glDisableVertexAttribArray( renderer.shader.attribute['vertexColor']) if self.tbo: self.tbo.unbind() GL.glDisableVertexAttribArray( renderer.shader.attribute['vertexTexturePos']) if self.nbo: self.nbo.unbind() GL.glDisableVertexAttribArray( renderer.shader.attribute['vertexNormal']) self.vbo.unbind() GL.glDisableVertexAttribArray( renderer.shader.attribute['vertexCoords']) if self.offset: pf.debug("POLYGON OFFSET RESET", pf.DEBUG.DRAW) GL.glPolygonOffset(0.0, 0.0) def pick(self, renderer): """Pick the geometry of this object""" def render_geom(): if self.ibo: GL.glDrawElementsui(self.glmode, self.ibo) else: GL.glDrawArrays(self.glmode, 0, np.asarray(self.vbo.shape[:-1]).prod()) renderer.shader.loadUniforms(self) self.vbo.bind() GL.glEnableVertexAttribArray(renderer.shader.attribute['vertexCoords']) GL.glVertexAttribPointer(renderer.shader.attribute['vertexCoords'], 3, GL.GL_FLOAT, False, 0, self.vbo) if self.ibo: self.ibo.bind() if self.cullface == 'front': # Draw back faces GL.glEnable(GL.GL_CULL_FACE) GL.glCullFace(GL.GL_FRONT) elif self.cullface == 'back': # Draw front faces GL.glEnable(GL.GL_CULL_FACE) GL.glCullFace(GL.GL_BACK) else: GL.glDisable(GL.GL_CULL_FACE) # Specifiy the depth comparison function if self.ontop: GL.glDepthFunc(GL.GL_ALWAYS) render_geom() if self.ibo: self.ibo.unbind() self.vbo.unbind() GL.glDisableVertexAttribArray( renderer.shader.attribute['vertexCoords']) def __str__(self): keys = sorted(set(self.keys()) - set(('_default_dict_', ))) print("Keys %s" % keys) out = utils.formatDict(utils.selectDict(self, keys)) print(out) return out
class model: ''' class for STL file / 3d model ''' def __init__(self, stl_data, batchh=None): ''' initialise model data''' vert, norm = stl_data self.vertices = numpy.array(vert, dtype=GLfloat) self.normals = numpy.array(norm, dtype=GLfloat) self.vertex_buffer = VBO(self.vertices, 'GL_STATIC_DRAW') self.normal_buffer = VBO(self.normals, 'GL_STATIC_DRAW') # calculate model scale self.corner = self.vertices.transpose().min(1) self.corner2 = self.vertices.transpose().max(1) self.scale = abs(self.corner) + abs(self.corner2) self.scale = max(self.scale[0], self.scale[1], self.scale[2]) print 'STL File loaded in: ', loadtime print 'Object information' print 'corner 1: ', self.corner print 'corner 2: ', self.corner2 print 'object scale: ', self.scale def draw(self): ''' draw model on screen ''' glMatrixMode(GL_MODELVIEW) glPushMatrix() glLoadIdentity() # center the model glTranslate(window.width/2, window.height/2, -150) # scale the model glScale(150/self.scale, 150/self.scale, 150/self.scale) # draw grid and coordinate lines draw_grid() draw_xyz(0, 0, 0, -20, -20) # demo rotation glRotate(rot, 1, 0, 0) glRotate(rot2, 0, 1, 0) glRotate(rot3, 0, 0, 1) self.vertex_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.normal_buffer.bind() glNormalPointer(GL_FLOAT, 0, None) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) glDrawArrays(GL_TRIANGLES, 0, len(self.vertices)) glDisableClientState(GL_NORMAL_ARRAY) glDisableClientState(GL_VERTEX_ARRAY) self.normal_buffer.unbind() self.vertex_buffer.unbind() glPopMatrix()
# bind VAO glBindVertexArray(triangleVAO) # bind data VBO cubeDataVBO.bind() cubeDataVBO.copy_data() glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(3 * ctypes.sizeof(ctypes.c_float))) glEnableVertexAttribArray(1) # unbind VBO cubeDataVBO.unbind() # unbind VAO glBindVertexArray(0) glBindVertexArray(sphereVAO) sphereDataVBO.bind() sphereDataVBO.copy_data() glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(3 * ctypes.sizeof(ctypes.c_float))) glEnableVertexAttribArray(1) sphereDataVBO.unbind()
# enable z-buffer glEnable(GL_DEPTH_TEST) dataVBO = VBO(dataBuffer, usage='GL_STATIC_DRAW') dataVAO = glGenVertexArrays(1) glBindVertexArray(dataVAO) dataVBO.bind() dataVBO.copy_data() glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0)) glEnableVertexAttribArray(0) dataVBO.unbind() glBindVertexArray(0) renderProgram = GLProgram(waveVertexShaderSource, waveFragmentShaderSource) renderProgram.compile_and_link() waveColorUniform = GLUniform(renderProgram.get_program_id(), 'waveColor', 'vec3f') # change drawing mode # glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) startTime = glfw.get_time() soundPlayed = False
positionloc = glGetAttribLocation(prog, "vs_position") colorloc = glGetAttribLocation(prog, "vs_color") # Setup VAO vertobj = glGenVertexArrays(1) glBindVertexArray(vertobj) # Setup the VBO (using the fancy VBO Object from pyopengl, doing it "manually" would also be a possibility) vertbuf = VBO(cubedata, GL_STATIC_DRAW) vertbuf.bind() glEnableVertexAttribArray(positionloc) glEnableVertexAttribArray(colorloc) glVertexAttribPointer(positionloc, 4, GL_FLOAT, GL_TRUE, 8 * 4, vertbuf + 0) # "+0" since we need to create an offset. glVertexAttribPointer(colorloc, 4, GL_FLOAT, GL_TRUE, 8 * 4, vertbuf + 16) # 4 * 4 Bytes per float. vertbuf.unbind() # We can unbind the VBO, since it's linked to the VAO # glBindVertexArray(0) running = True t = time.time() rotation = 0.0 while running: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glUseProgram(prog) glUniformMatrix4fv(mvploc, 1, GL_TRUE, hm.rotation(mvp, rotation, [0, 1, 0]).tolist()) # glBindVertexArray(vertobj) glDrawArrays(GL_TRIANGLE_STRIP, 0, 14) glDrawArrays(GL_POINTS, 0, 14) glfwSwapBuffers() # glfwPollEvents() # This would poll for key/mouse events manually.
glBindVertexArray(gridVAO) gridVBO.bind() gridVBO.copy_data() gridEBO.bind() gridEBO.copy_data() glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(3 * ctypes.sizeof(ctypes.c_float))) glEnableVertexAttribArray(1) glBindVertexArray(0) gridVBO.unbind() renderProgram = GLProgram(vertexShaderSource, fragmentShaderSource) renderProgram.compile_and_link() lineProgram = GLProgram(lineVertexShaderSource, lineFragmentShaderSource, lineGeometryShaderSource) lineProgram.compile_and_link() # create uniforms uniformInfos = [('projection', 'mat4f'), ('view', 'mat4f'), ('model', 'mat4f'), ('lightPos', 'vec3f'), ('viewPos', 'vec3f'), ('lightColor', 'vec3f'), ('objectColor', 'vec3f'), ('ambientCoef', 'float'), ('specularCoef', 'float'), ('specularP', 'int')]
sphereDataVBO.create_buffers() sphereVAO = glGenVertexArrays(1) glBindVertexArray(sphereVAO) sphereDataVBO.bind() sphereDataVBO.copy_data() glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(3 * ctypes.sizeof(ctypes.c_float))) glEnableVertexAttribArray(1) sphereDataVBO.unbind() glBindVertexArray(0) cylinderDataVBO = VBO(cylinderData, usage='GL_STATIC_DRAW') cylinderDataVBO.create_buffers() cylinderVAO = glGenVertexArrays(1) glBindVertexArray(cylinderVAO) cylinderDataVBO.bind() cylinderDataVBO.copy_data() glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
# configure the fist 3-vector (pos) # arguments: index, size, type, normalized, stride, pointer # the stride is 6 * 4 because there are six floats per vertex, and the size of # each float is 4 bytes glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * 4, ctypes.c_void_p(0)) glEnableVertexAttribArray(0) # configure the second 3-vector (color) # the offset is 3 * 4 = 12 bytes glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * 4, ctypes.c_void_p(3 * 4)) glEnableVertexAttribArray(1) # unbind VBO verticesVBO.unbind() # unbind VAO glBindVertexArray(0) # compile shaders vertexShaderId = compile_shader(GL_VERTEX_SHADER, vertexShaderSource) fragmentShaderId = compile_shader(GL_FRAGMENT_SHADER, fragmentShaderSource) # link shaders into a program programId = glCreateProgram() glAttachShader(programId, vertexShaderId) glAttachShader(programId, fragmentShaderId) glLinkProgram(programId) linkSuccess = glGetProgramiv(programId, GL_LINK_STATUS) if not linkSuccess: infoLog = glGetProgramInfoLog(programId) print('program linkage error\n')
class instancingdemo(df.demoplate): def init(self): print "OpenGL Information:" for prop in ["GL_VENDOR", "GL_RENDERER", "GL_VERSION", "GL_SHADING_LANGUAGE_VERSION"]: print "\t%s = %s" % (prop, glGetString(globals()[prop])) self.campos = np.array([2.5, 1.5, 1.5, 1], dtype = np.float32) self.center = np.array([0.0,0.0,0.0,1.0], dtype = np.float32) self.perspective_mat = None self.mvp = None # OpenGL Stuff glEnable(GL_DEPTH_TEST) #glEnable(GL_CULL_FACE) glClearColor(1, 1, 1, 0) glPointSize(5) # Shader Stuff. with open('shader.fs') as fs, open('shader.vs') as vs: self.shader = su.Shader(list(vs), list(fs)) self.shader.bindfragdata(0, 'fragcolor') self.mvploc = self.shader.uniformlocation('mvp') self.objploc = self.shader.uniformlocation('objp') self.objoffsetloc = self.shader.uniformlocation('objoffset') self.positionloc = self.shader.attributelocation('vs_position') self.normalloc = self.shader.attributelocation('vs_normal') self.loadsquirrel() self.buildobjoffsets() def buildobjoffsets(self): objoffset = np.zeros((5,5,5,4), dtype = np.float32) start = np.array([-1, -1, -1, 0], dtype = np.float32) steps = np.arange(0, 2.1, 0.5, dtype = np.float32) for x in range(5): for y in range(5): for z in range(5): objoffset[x,y,z,] = start + np.array([steps[x], steps[y], steps[z], 0], dtype = np.float32) self.shader.use() glUniform4fv(self.objoffsetloc, 5 * 5 * 5, objoffset.flatten().tolist()) def loadsquirrel(self): # When loading the data, pad the normals to 4 floats (16bytes) since GPUs hate unaligned memory. obj = wf.ObjFileParser("squirrel.obj", padnormals = 4) self.objscale = 1 / np.max(obj.scale / 2) self.objcenter = obj.minpos + (obj.scale / 2) self.obj_mat = hm.scale(hm.identity(), [self.objscale * 0.2] * 3) self.obj_mat = hm.translation(self.obj_mat, -self.objcenter) # Generate a GL compatible indexed vertex buffer for the object self.vbdata, ibdata = obj.generateIndexedBuffer([0,1], np.uint16) vbdata = self.vbdata self.elementnum = np.shape(ibdata)[0] # VAO self.vertobj = glGenVertexArrays(1) glBindVertexArray(self.vertobj) # Setup the VBO for the vertex data. self.vertbuf = VBO(vbdata, GL_STATIC_DRAW, GL_ARRAY_BUFFER) self.vertbuf.bind() glVertexAttribPointer(self.positionloc, 4, GL_FLOAT, GL_TRUE, 8 * 4, ctypes.c_void_p(0)) glVertexAttribPointer(self.normalloc, 4, GL_FLOAT, GL_TRUE, 8 * 4, ctypes.c_void_p(16)) glEnableVertexAttribArray(self.positionloc) glEnableVertexAttribArray(self.normalloc) # Indexbuffer self.indexbuf = VBO(ibdata, GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER) self.indexbuf.bind() glBindVertexArray(0) self.vertbuf.unbind() self.indexbuf.unbind() #Animation init... self.rotation = 0 def resize(self, width, height): glViewport(0, 0, width, height) self.perspective_mat = hm.perspective(hm.identity(), 60, float(width) / height, 0.1, 6.0) self.modelview_mat = hm.lookat(hm.identity(), self.campos, self.center) self.mvp = np.dot(self.perspective_mat, self.modelview_mat) def display(self, timediff): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.shader.use() glUniformMatrix4fv(self.objploc, 1, GL_TRUE, np.dot(hm.rotation(hm.identity(), self.rotation, [0,1,0]), self.obj_mat).tolist()) glUniformMatrix4fv(self.mvploc, 1, GL_TRUE, hm.rotation(self.mvp, self.rotation / 4, [0.577350269189626] * 3).tolist()) glBindVertexArray(self.vertobj) glDrawElementsInstanced(GL_TRIANGLES, self.elementnum, GL_UNSIGNED_SHORT, ctypes.c_void_p(0), 125) glBindVertexArray(0) self.rotation += timediff / 5 * 360
class MSGLCanvas2D(QGLWidget): """ Canvas GL plotting in 2 dimensions """ MAX = 100. corner_ = 100.0 zoom_ = 1.5 xrot_ = 220 yrot_ = 220 trans_x_ = 0.0 trans_y_ = 0.0 def __init__(self, data, parent=None, **kw): """ Constructor, initialization """ QGLWidget.__init__(self, parent) self.setFormat(QGLFormat(QGL.SampleBuffers)) self.setMinimumSize(500, 300) #300 self.setMouseTracking(True) self.setFocusPolicy(Qt.StrongFocus) self.data = data vertexes = [] colors = [] from utils.misc import IceAndFire maxY = max(map(max, [log10(el.y_data) for el in data])) maxX = max(map(max, [el.x_data for el in data])) rtmax = max([z.rtmin for z in data]) for el in data: for i, x in enumerate(el.x_data): c = IceAndFire.getQColor(log10(el.y_data[i]) / maxY) colors.append(c) vertexes.append([(x * 2 * self.corner_) / maxX, (el.rt * 2 * self.corner_) / rtmax]) from OpenGL.arrays.vbo import VBO self.vertexes = VBO(array(vertexes, 'f')) self.colors = VBO(array(colors, 'f')) self.mode = "None" # "ZOOMING", "PANNING", "NONE" self.lastpos = QPoint() self.counter_trans_x = 0 self.counter_trans_y = 0 self.defaultColors = { 'ticks': (0., 0., 0., 0.), 'axes': (0., 0., 0., 0.), 'curves': (0., 0., 1., 0.), 'backgroundColor': (1., 1., 1., 1.) } #self.axes=self.drawAxes() self.transformationMatrix = self.setupTransformationMatrix( self.width(), self.height()) def setupTransformationMatrix(self, w, h): """ use a matrix to translate in the gl landmark """ m = QMatrix() m.translate(-w / 2, h / 2) m.scale(300. / w, 300. / h) print w, h, w / 300., 1 - ((h / 300) - 1) #m.scale((self.width()*100)/300, -(self.height()*100)/300) #self.currentSize.x = w #self.currentSize.y = h return m def inGLCoordinate(self, point): return self.transformationMatrix.map(point) def resizeGL(self, w, h): """ called when window is being resized """ glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_ * self.zoom_, self.corner_ * self.zoom_, -self.corner_ * self.zoom_, self.corner_ * self.zoom_) #self.transformationMatrix = self.setupTransformationMatrix(w, h) glMatrixMode(GL_MODELVIEW) def initializeGL(self): """needed, initialize GL parameters""" #glClearColor(1.,1.,1.,1.) glDisable(GL_DEPTH_TEST) glEnable(GL_LINE_SMOOTH) glEnable(GL_POINT_SMOOTH) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) glLoadIdentity() #model view by default # self.grid_lines = self.drawGridLines() # self.ticks =self.drawAxisTick() # self.axes = self.drawAxes() def paintGL(self): """Draw the scene, needed, called each time glDraw""" glClear(GL_COLOR_BUFFER_BIT) glTranslated(self.trans_x_, self.trans_y_, 0.) #addition glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_ * self.zoom_, self.corner_ * self.zoom_, -self.corner_ * self.zoom_, self.corner_ * self.zoom_) glMatrixMode(GL_MODELVIEW) #end addition #glCallList(self.grid_lines) #glCallList(self.ticks) #glCallList(self.axes) glLineWidth(30.0) self.scatterPlot() # if self.flags == "chrom": # self.drawAxisLegend("retention time[s]", "intensity[%]") # glCallList(self.lines) # elif self.flags == "spectrum": # self.drawAxisLegend("m/z", "intensity") def drawAxes(self, width=2., colour=(0., 0., 0.)): """ Draw Axes """ #width must be a float axes = glGenLists(1) glNewList(axes, GL_COMPILE) glLineWidth(width) glColor(colour[0], colour[1], colour[2]) glBegin(GL_LINES) #x_achse glVertex2d(-self.corner_, -self.corner_) glVertex2d(self.corner_, -self.corner_) #y-achse glVertex2d(-self.corner_, -self.corner_) glVertex2d(-self.corner_, self.corner_) glEnd() glEndList() return axes def drawLegends(self, pos): """ draw legend at the specified position """ pass def drawAxisLegend(self, x_label, y_label): """ Draw Axis Legend """ font = QFont("Typewriter") #RT axis legend font.setPixelSize(12) self.renderText(self.corner_, -self.corner_ - 20.0, 0., x_label) # font self.renderText(-self.corner_ - 20.0, self.corner_, 0., y_label, font) def resetTranslations(self): """ reset the different translation to 0 """ self.trans_x_ = 0. self.trans_y_ = 0. self.counter_trans_x = 0. self.counter_trans_y = 0. def normalizeAngle(self, angle): while (angle < 0): angle += 360 * 16 while (angle > 360 * 16): angle -= 360 * 16 ########DRAWING METHODS################################################## def drawLine(self, point_, point): glBegin(GL_LINES) glVertex2d(point_.x(), point_.y()) glVertex2d(point.x(), point.y()) glEnd() def drawRect(self, p_1, p_2, p_3=None, p_4=None): pass def drawOnePoint(self, point, colour=Qt.yellow): pass def scatterPlot(self): """ Draw Data (x, y)""" if self.vertexes is not None and self.colors is not None: self.vertexes.bind() glEnableClientState(GL_VERTEX_ARRAY) glVertexPointerf(self.vertexes) self.colors.bind() glEnableClientState(GL_COLOR_ARRAY) glColorPointerf(self.colors) glDrawArrays(GL_LINES, 0, len(self.vertexes)) self.vertexes.unbind() self.colors.unbind() #self.textures.unbind() glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) def spectrumPlot(self, points): pass def histogramPlot(self, points, bin=5.): pass def barPlot(points, width=2.): pass ########MOUSE AND KEYBOARDS EVENTS########################################################################### def wheelEvent(self, event): if event.delta() > 0: self.zoom_ -= .05 else: self.zoom_ += .05 glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_ * self.zoom_, self.corner_ * self.zoom_, -self.corner_ * self.zoom_, self.corner_ * self.zoom_) self.updateGL() glMatrixMode(GL_MODELVIEW) event.accept() def keyPressEvent(self, event): if event.key() == Qt.Key_Plus: self.zoom_ -= .1 glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_ * self.zoom_, self.corner_ * self.zoom_, -self.corner_ * self.zoom_, self.corner_ * self.zoom_) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Minus: self.zoom_ += .1 glMatrixMode(GL_PROJECTION) #// You had GL_MODELVIEW glLoadIdentity() gluOrtho2D(-self.corner_ * self.zoom_, self.corner_ * self.zoom_, -self.corner_ * self.zoom_, self.corner_ * self.zoom_) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Up: self.trans_y_ += 2 self.counter_trans_y += 2 if event.key() == Qt.Key_Down: self.trans_y_ -= 2 self.counter_trans_y -= 2 if event.key() == Qt.Key_Left: self.trans_x_ -= 2 self.counter_trans_x -= 2 if event.key() == Qt.Key_Right: self.trans_x_ += 2 self.counter_trans_x += 2 if event.key() == Qt.Key_Z: self.mode = "ZOOMING" if self.counter_trans_x < 0 and self.counter_trans_y < 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x += 1 self.counter_trans_y += 1 if self.counter_trans_x > 0 and self.counter_trans_y < 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x -= 1 self.counter_trans_y += 1 if self.counter_trans_x < 0 and self.counter_trans_y > 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x += 1 self.counter_trans_y -= 1 if self.counter_trans_x < 0 and self.counter_trans_y > 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x -= 1 self.counter_trans_y -= 1 if self.zoom_ != 1.5: self.zoom = 1.5 #self.updateGL() self.updateGL() self.resetTranslations() def mousePressEvent(self, event): if self.mode == "ZOOMING": self.mode = "None" self.computeSelection() else: self.lastpos = QPoint(event.pos()) self.setCursor(QCursor(Qt.ClosedHandCursor)) #if event.buttons() == Qt.RightButton: # self.mode = "PANNING" def computeSelection(self): print "selected" def mouseMoveEvent(self, event): dx = event.x() - self.lastpos.x() dy = event.y() - self.lastpos.y() if self.mode == "ZOOMING": font = QFont("Typewriter") self.renderText(-self.corner_ - 30.0, self.corner_, 0., "ZOOMING MODE ACTIVATED", font) self.updateGL() glColor(0., 0., 1., .5) XMAX = 900. XMIN = 180. pointer_x = (self.lastpos.x() * 200.) / XMAX norm_dx = (dx * 200.) / XMAX """ if pointer_x > 100. or pointer_x < 100. \ or norm_dx >100. or norm_dx<-100.: event.ignore() """ glBegin(GL_QUADS) glVertex2d(pointer_x, -100.) glVertex2d(pointer_x + norm_dx, -100.) glVertex2d(pointer_x + norm_dx, 100.) glVertex2d(pointer_x, 100.) glEnd() self.updateGL() #update for seeing the rectangle mapping = self.mapFromGlobal cursorPos = self.inGLCoordinate(mapping(self.cursor().pos())) QToolTip.showText(self.cursor().pos(), "x:"+str(cursorPos.x())+ \ ", y:"+str(cursorPos.y()) ) if self.mode == "None": if event.buttons() == Qt.LeftButton: self.trans_y_ -= dy / 5 self.counter_trans_y -= dy / 5 self.trans_x_ += dx / 5 self.counter_trans_x += dx / 5 self.lastpos = QPoint(event.pos()) self.glDraw() self.resetTranslations() def mouseReleaseEvent(self, event): self.setCursor(QCursor(Qt.ArrowCursor))
class StlModel(Model): """ Model for displaying and manipulating STL data. """ def load_data(self, model_data, callback=None): t_start = time.time() vertices, normals = model_data # convert python lists to numpy arrays for constructing vbos self.vertices = numpy.require(vertices, 'f') self.normals = numpy.require(normals, 'f') self.scaling_factor = 1.0 self.rotation_angle = { self.AXIS_X: 0.0, self.AXIS_Y: 0.0, self.AXIS_Z: 0.0, } self.mat_specular = (1.0, 1.0, 1.0, 1.0) self.mat_shininess = 50.0 self.light_position = (20.0, 20.0, 20.0) self.initialized = False t_end = time.time() logging.info('Initialized STL model in %.2f seconds' % (t_end - t_start)) logging.info('Vertex count: %d' % len(self.vertices)) def normal_data_empty(self): """ Return true if the model has no normal data. """ empty = (self.normals.max() == 0 and self.normals.min() == 0) return empty def calculate_normals(self): """ Calculate surface normals for model vertices. """ a = self.vertices[0::3] - self.vertices[1::3] b = self.vertices[1::3] - self.vertices[2::3] cross = numpy.cross(a, b) # normalize the cross product magnitudes = numpy.apply_along_axis(numpy.linalg.norm, 1, cross).reshape(-1, 1) normals = cross / magnitudes # each of 3 facet vertices shares the same normal normals = normals.repeat(3, 0) return normals # ------------------------------------------------------------------------ # DRAWING # ------------------------------------------------------------------------ def init(self): """ Create vertex buffer objects (VBOs). """ self.vertex_buffer = VBO(self.vertices, 'GL_STATIC_DRAW') if self.normal_data_empty(): logging.info('STL model has no normal data') self.normals = self.calculate_normals() self.normal_buffer = VBO(self.normals, 'GL_STATIC_DRAW') self.initialized = True def draw_facets(self): glPushMatrix() glEnable(GL_LIGHT0) glEnable(GL_LIGHT1) glShadeModel(GL_SMOOTH) # material properties (white plastic) glMaterial(GL_FRONT, GL_AMBIENT, (0.0, 0.0, 0.0, 1.0)) glMaterial(GL_FRONT, GL_DIFFUSE, (0.55, 0.55, 0.55, 1.0)) glMaterial(GL_FRONT, GL_SPECULAR, (0.7, 0.7, 0.7, 1.0)) glMaterial(GL_FRONT, GL_SHININESS, 32.0) # lights properties glLight(GL_LIGHT0, GL_AMBIENT, (0.3, 0.3, 0.3, 1.0)) glLight(GL_LIGHT0, GL_DIFFUSE, (0.3, 0.3, 0.3, 1.0)) glLight(GL_LIGHT1, GL_DIFFUSE, (0.3, 0.3, 0.3, 1.0)) # lights position glLightfv(GL_LIGHT0, GL_POSITION, self.light_position) glLightfv(GL_LIGHT1, GL_POSITION, (-20.0, -20.0, 20.0)) glColor(1.0, 1.0, 1.0) ### VBO stuff self.vertex_buffer.bind() glVertexPointer(3, GL_FLOAT, 0, None) self.normal_buffer.bind() glNormalPointer(GL_FLOAT, 0, None) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) glDrawArrays(GL_TRIANGLES, 0, len(self.vertices)) glDisableClientState(GL_NORMAL_ARRAY) glDisableClientState(GL_VERTEX_ARRAY) self.normal_buffer.unbind() self.vertex_buffer.unbind() ### end VBO stuff glDisable(GL_LIGHT1) glDisable(GL_LIGHT0) glPopMatrix() def display(self, mode_2d=False): glEnable(GL_LIGHTING) self.draw_facets() glDisable(GL_LIGHTING) # ------------------------------------------------------------------------ # TRANSFORMATIONS # ------------------------------------------------------------------------ def scale(self, factor): if factor != self.scaling_factor: logging.info('actually scaling vertices') self.vertices *= (factor / self.scaling_factor) self.scaling_factor = factor self.invalidate_bounding_box() self.modified = True def translate(self, x, y, z): self.vertices = vector.translate(self.vertices, x, y, z) self.invalidate_bounding_box() self.modified = True def rotate_rel(self, angle, axis): logging.info('rotating vertices by a relative angle of ' '%.2f degrees along the %s axis' % (angle, self.axis_letter_map[axis])) angle = angle % 360 self.vertices = vector.rotate(self.vertices, angle, *axis) self.rotation_angle[axis] += angle self.invalidate_bounding_box() self.modified = True def rotate_abs(self, angle, axis): angle = angle % 360 if self.rotation_angle[axis] == angle: return logging.info('rotating vertices by an absolute angle of ' '%.2f degrees along the %s axis' % (angle, self.axis_letter_map[axis])) final_matrix = vector.identity_matrix() # modify matrix to rotate to initial position for v in [self.AXIS_Z, self.AXIS_Y, self.AXIS_X]: matrix = vector.rotation_matrix(-self.rotation_angle[v], *v) final_matrix = final_matrix.dot(matrix) # change the angle self.rotation_angle[axis] = angle # modify matrix to rotate to new position for v in [self.AXIS_X, self.AXIS_Y, self.AXIS_Z]: matrix = vector.rotation_matrix(self.rotation_angle[v], *v) final_matrix = final_matrix.dot(matrix) self.vertices = self.vertices.dot(final_matrix) self.invalidate_bounding_box() self.modified = True
class TextDrawer_Outlined: def __init__(self): self.face = None self.stroker = None self.foreTextures = dict() self.backTextures = dict() # compile rendering program self.renderProgram = GLProgram(_textVertexShaderSource, _textFragmentShaderSource) self.renderProgram.compile_and_link() # make projection uniform self.projectionUniform = GLUniform(self.renderProgram.get_program_id(), 'projection', 'mat4f') self.textColorUniform = GLUniform(self.renderProgram.get_program_id(), 'textColor', 'vec3f') self.textureSizeUniform = GLUniform( self.renderProgram.get_program_id(), 'textureSize', 'vec2f') # create rendering buffer self.vbo = VBO(_get_rendering_buffer(0, 0, 0, 0)) self.vbo.create_buffers() self.vboId = glGenBuffers(1) # initialize VAO self.vao = glGenVertexArrays(1) glBindVertexArray(self.vao) glBindBuffer(GL_ARRAY_BUFFER, self.vboId) self.vbo.bind() self.vbo.copy_data() glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 5 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(3 * ctypes.sizeof(ctypes.c_float))) glEnableVertexAttribArray(1) # self.vbo.unbind() glBindVertexArray(0) self.zNear = -1.0 self.zFar = 1.0 def delete(self): self.foreTextures.clear() self.backTextures.clear() self.face = None self.stroker = None self.renderProgram.delete() self.projectionUniform = None self.textColorUniform = None self.textureSizeUniform = None self.vbo.delete() glDeleteVertexArrays(1, [self.vao]) def load_font(self, fontFilename, fontSize, outlineSize=2 * 64): assert os.path.exists(fontFilename) self.foreTextures.clear() self.backTextures.clear() self.face = ft.Face(fontFilename) self.face.set_char_size(fontSize) self.outlineSize = outlineSize self.stroker = ft.Stroker() self.stroker.set(outlineSize, ft.FT_STROKER_LINECAPS['FT_STROKER_LINECAP_ROUND'], ft.FT_STROKER_LINEJOINS['FT_STROKER_LINEJOIN_ROUND'], 0) # load all ASCII characters for i in range(128): self.load_character(chr(i)) def load_character(self, character): assert self.face is not None assert len(character) == 1 if character not in self.foreTextures: # load background glyph # the render option will lead to an outline glyph (not rendered) self.face.load_char(character, ft.FT_LOAD_FLAGS['FT_LOAD_DEFAULT']) backGlyph = ft.FT_Glyph() ft.FT_Get_Glyph(self.face.glyph._FT_GlyphSlot, ft.byref(backGlyph)) backGlyph = ft.Glyph(backGlyph) # add border to the glyph error = ft.FT_Glyph_StrokeBorder(ft.byref(backGlyph._FT_Glyph), self.stroker._FT_Stroker, False, False) if error: raise ft.FT_Exception(error) # the render option will lead to a rendered glyph backBitmapGlyph = backGlyph.to_bitmap( ft.FT_RENDER_MODES['FT_RENDER_MODE_NORMAL'], 0) backBitmap = backBitmapGlyph.bitmap backHeight, backWidth = backBitmap.rows, backBitmap.width backBitmap = np.array(backBitmap.buffer, dtype=np.uint8).reshape( (backHeight, backWidth)) backTexture = _create_text_texture(backBitmap) backSlot = CharacterSlot(backTexture, backBitmapGlyph) self.backTextures[character] = backSlot # load foreground glyph self.face.load_char(character, ft.FT_LOAD_FLAGS['FT_LOAD_RENDER']) foreBitmap = self.face.glyph.bitmap foreHeight, foreWidth = foreBitmap.rows, foreBitmap.width foreBitmap = np.array(foreBitmap.buffer, dtype=np.uint8).reshape( (foreHeight, foreWidth)) foreTexture = _create_text_texture(foreBitmap) foreSlot = CharacterSlot(foreTexture, self.face.glyph) self.foreTextures[character] = foreSlot def get_character(self, ch): if ch not in self.foreTextures: self.load_character(ch) return (self.foreTextures[ch], self.backTextures[ch]) def _draw_text(self, text, textPos, windowSize, scale, linespread, foreColor, backColor): if len(text) == 0: return blendEnabled = glIsEnabled(GL_BLEND) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) self.renderProgram.use() glBindVertexArray(self.vao) glActiveTexture(GL_TEXTURE0) foreColor = np.asarray(foreColor, np.float32) backColor = np.asarray(backColor, np.float32) projectionMat = orthographic_projection(0.0, windowSize[0], 0.0, windowSize[1], self.zNear, self.zFar) self.projectionUniform.update(projectionMat) lineY = textPos[1] nowX = textPos[0] # split text into lines lines = text.split('\n') for line in lines: if len(line) > 0: # analyze this line bearings = [] for ch in line: _, backSlot = self.get_character(ch) bearings.append(backSlot.bearing) minBearings_X = min(zip(*bearings), key=operator.itemgetter(0))[0] * scale[0] maxBearings_Y = max(zip(*bearings), key=operator.itemgetter(1))[1] * scale[1] nowX = -minBearings_X for ch in line: foreSlot, backSlot = self.get_character(ch) # draw the background xpos = nowX + backSlot.bearing[0] * scale[0] yLowerd = (maxBearings_Y - backSlot.bearing[1] * scale[1]) ypos = lineY - yLowerd w = backSlot.textureSize[0] * scale[0] h = backSlot.textureSize[1] * scale[1] self.textureSizeUniform.update(np.array((w, h), np.float32)) backSlot.texture.bind() self.textColorUniform.update(backColor) self.vbo.bind() self.vbo.set_array( _get_rendering_buffer(xpos, ypos, w, h, 0.99)) self.vbo.copy_data() self.vbo.unbind() glDrawArrays(GL_TRIANGLES, 0, 6) backSlot.texture.unbind() # draw the foreground xpos = nowX + foreSlot.bearing[0] * scale[0] yLowerd = (maxBearings_Y - foreSlot.bearing[1] * scale[1]) ypos = lineY - yLowerd w = foreSlot.textureSize[0] * scale[0] h = foreSlot.textureSize[1] * scale[1] foreSlot.texture.bind() self.textColorUniform.update(foreColor) self.vbo.bind() # the foreground is set closer to the screen so that it # is rendered above the background self.vbo.set_array( _get_rendering_buffer(xpos, ypos, w, h, 0.999)) self.vbo.copy_data() self.vbo.unbind() glDrawArrays(GL_TRIANGLES, 0, 6) foreSlot.texture.unbind() # the advance is number of 1/64 pixels nowX += ((foreSlot.advance + 2.0 * self.outlineSize) / 64.0) * scale[0] yOffset = self.get_character( 'X')[1].textureSize[1] * scale[1] * linespread lineY -= yOffset glBindVertexArray(0) if not blendEnabled: glDisable(GL_BLEND) def draw_text(self, text, textPos, windowSize, foreColor=(1.0, 1.0, 1.0), backColor=(0.0, 0.0, 0.0), scale=(1.0, 1.0), linespread=1.5): return self._draw_text(text, textPos, windowSize, scale, linespread, foreColor, backColor)