def widgetshot(widget, filename='output.png'): # detach the widget from the parent parent = widget.parent if parent: parent.remove_widget(widget) # put the widget canvas on a Fbo texture = Texture.create(size=widget.size, colorfmt='rgb') fbo = Fbo(size=widget.size, texture=texture) fbo.add(widget.canvas) # clear the fbo background fbo.bind() fbo.clear_buffer() fbo.release() # draw! fbo.draw() # get the fbo data fbo.bind() data = glReadPixels(0, 0, widget.size[0], widget.size[1], GL_RGBA, GL_UNSIGNED_BYTE) fbo.release() # save to a file surf = pygame.image.fromstring(data, widget.size, 'RGBA', True) pygame.image.save(surf, filename) # reattach to the parent if parent: parent.add_widget(widget) return True
class Renderer(Widget): def __init__(self, **kw): self.shader_file = kw.pop("shader_file", None) self.canvas = Canvas() super(Renderer, self).__init__(**kw) with self.canvas: self._viewport = Rectangle(size=self.size, pos=self.pos) self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True) self._config_fbo() self.texture = self.fbo.texture self.camera = None self.scene = None def _config_fbo(self): # set shader file here self.fbo.shader.source = self.shader_file or \ os.path.join(kivy3_path, "default.glsl") with self.fbo: Callback(self._setup_gl_context) PushMatrix() # instructions set for all instructions self._instructions = InstructionGroup() PopMatrix() Callback(self._reset_gl_context) def _setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() def _reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def render(self, scene, camera): self.scene = scene self.camera = camera self.camera.bind_to(self) self._instructions.add(scene.as_instructions()) Clock.schedule_once(self._update_matrices, -1) def on_size(self, instance, value): self.fbo.size = value self._viewport.texture = self.fbo.texture self._viewport.size = value self._update_matrices() def on_texture(self, instance, value): self._viewport.texture = value def _update_matrices(self, dt=None): if self.camera: self.fbo['projection_mat'] = self.camera.projection_matrix self.fbo['modelview_mat'] = self.camera.modelview_matrix else: raise RendererError("Camera is not defined for renderer") def set_clear_color(self, color): self.fbo.clear_color = color
class Renderer(Widget): def __init__(self, **kw): self.shader_file = kw.pop("shader_file", None) self.canvas = Canvas() super(Renderer, self).__init__(**kw) with self.canvas: self._viewport = Rectangle(size=self.size, pos=self.pos) self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self._config_fbo() self.texture = self.fbo.texture self.camera = None self.scene = None def _config_fbo(self): # set shader file here self.fbo.shader.source = self.shader_file or \ os.path.join(kivy3_path, "default.glsl") with self.fbo: Callback(self._setup_gl_context) PushMatrix() # instructions set for all instructions self._instructions = InstructionGroup() PopMatrix() Callback(self._reset_gl_context) def _setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() def _reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def render(self, scene, camera): self.scene = scene self.camera = camera self.camera.bind_to(self) self._instructions.add(scene.as_instructions()) Clock.schedule_once(self._update_matrices, -1) def add(self, obj): self._instructions.add(obj.as_instructions()) def on_size(self, instance, value): self.fbo.size = value self._viewport.texture = self.fbo.texture self._viewport.size = value self._viewport.pos = self.pos self._update_matrices() def on_pos(self, instance, value): self._viewport.pos = self.pos self._update_matrices() def on_texture(self, instance, value): self._viewport.texture = value def _update_matrices(self, dt=None): if self.camera: self.fbo['projection_mat'] = self.camera.projection_matrix self.fbo['modelview_mat'] = self.camera.modelview_matrix else: raise RendererError("Camera is not defined for renderer") def set_clear_color(self, color): self.fbo.clear_color = color
class ObjectRenderer(Widget): scene = StringProperty('') obj_id = StringProperty('') obj_translation = ListProperty([0, 0, 0]) obj_rotation = ListProperty([0, 0, 0]) obj_scale = NumericProperty(1) obj_texture = StringProperty('') texture = ObjectProperty(None, allownone=True) cam_translation = ListProperty([0, 0, 0]) cam_rotation = ListProperty([0, 0, 0]) display_all = BooleanProperty(False) light_sources = DictProperty() ambiant = NumericProperty(.5) diffuse = NumericProperty(.5) specular = NumericProperty(.5) mode = StringProperty('triangles') def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find( join(dirname(__file__), 'simple.glsl')) super(ObjectRenderer, self).__init__(**kwargs) def on_obj_rotation(self, *args): self.obj_rot_x.angle = self.obj_rotation[0] self.obj_rot_y.angle = self.obj_rotation[1] self.obj_rot_z.angle = self.obj_rotation[2] def on_cam_rotation(self, *args): self.cam_rot_x.angle = self.cam_rotation[0] self.cam_rot_y.angle = self.cam_rotation[1] self.cam_rot_z.angle = self.cam_rotation[2] def on_obj_translation(self, *args): self.obj_translate.xyz = self.cam_translation def on_cam_translation(self, *args): self.cam_translate.xyz = self.cam_translation def on_obj_scale(self, *args): self.scale.xyz = [self.obj_scale, ] * 3 def on_display_all(self, *args): self.setup_canvas() def on_light_sources(self, *args): self.fbo['light_sources'] = [ ls[:] for ls in list(self.light_sources.values())] self.fbo['nb_lights'] = len(self.light_sources) def on_ambiant(self, *args): self.fbo['ambiant'] = self.ambiant def on_diffuse(self, *args): self.fbo['diffuse'] = self.diffuse def on_specular(self, *args): self.fbo['specular'] = self.specular def on_mode(self, *args): self.setup_canvas() def setup_canvas(self, *args): if not (self.scene and self.obj_id or self.display_all): return print('setting up the scene') with self.fbo: self.fbo['ambiant'] = self.ambiant self.fbo['diffuse'] = self.diffuse self.fbo['specular'] = self.specular self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) def on_scene(self, instance, value): print("loading scene %s" % value) self._scene = ObjFileLoader(resource_find(value)) self.setup_canvas() def on_obj_id(self, *args): self.setup_canvas() def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *args): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() self.cam_translate = Translate(self.cam_translation) # Rotate(0, 1, 0, 0) self.cam_rot_x = Rotate(self.cam_rotation[0], 1, 0, 0) self.cam_rot_y = Rotate(self.cam_rotation[1], 0, 1, 0) self.cam_rot_z = Rotate(self.cam_rotation[2], 0, 0, 1) self.scale = Scale(self.obj_scale) UpdateNormalMatrix() if self.display_all: for i in self._scene.objects: self.draw_object(i) else: self.draw_object(self.obj_id) PopMatrix() def draw_object(self, obj_id): m = self._scene.objects[obj_id] self.obj_rot_x = Rotate(self.obj_rotation[0], 1, 0, 0) self.obj_rot_y = Rotate(self.obj_rotation[1], 0, 1, 0) self.obj_rot_z = Rotate(self.obj_rotation[2], 0, 0, 1) self.obj_translate = Translate(xyz=self.obj_translation) if len(m.indices) > 2 ** 16: print('%s too big! %s indices' % (obj_id, len(m.indices))) if m.texture: print("loading texture %s " % m.texture) img = Image(source=resource_find( join(dirname(self.scene), m.texture))) texture = img.texture if texture: texture.wrap = 'repeat' else: texture = None vertex_lenght = sum(x[1] for x in m.vertex_format) if len(m.vertices) % vertex_lenght: print(( ( 'warning: vertices lenght (%s)' 'is not a multiple of vertex_format lenght(%s)' ) % (len(m.vertices), vertex_lenght))) Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, texture=texture, mode=self.mode)
class Renderer(Widget): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): # self.canvas = RenderContext(compute_normal_mat=True) # self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.meshes = [] with self.canvas: self.fbo = Fbo( size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0.0, 0.0, 0.0, 0.0) ) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find("simple.glsl") # self.texture = self.fbo.texture super(Renderer, self).__init__(**kwargs) with self.fbo: # ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.0) self._touches = [] def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): # clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() # glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo["projection_mat"] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() Translate(0, 0, -4.75) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) self.roty = Rotate(-120, 0, 1, 0) # here just rotate scene for best view self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements() PopMatrix() def draw_elements(self): """ Draw separately all objects on the scene to setup separate rotation for each object """ def _draw_element(m, texture=""): mesh = Mesh(vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode="triangles") if texture: texture = Image(texture).texture mesh.texture = texture def _set_color(*color, **kw): id_color = kw.pop("id_color", (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(0.3, 0.3, 0.3), Tr=1.0, Ns=1.0, intensity=1.0, id_color=[i / 255.0 for i in id_color], ) # Draw sphere in the center sphere = self.scene.objects["Sphere"] _set_color(0.7, 0.7, 0.0, id_color=(255, 255, 0)) _draw_element(sphere, "rock.png") # Then draw other elements and totate it in different axis pyramid = self.scene.objects["Pyramid"] PushMatrix() self.pyramid_rot = Rotate(0, 0, 0, 1) _set_color(0.0, 0.0, 0.7, id_color=(0.0, 0.0, 255)) _draw_element(pyramid, "rain.png") PopMatrix() box = self.scene.objects["Box"] PushMatrix() self.box_rot = Rotate(0, 0, 1, 0) _set_color(0.7, 0.0, 0.0, id_color=(255, 0.0, 0)) _draw_element(box, "bricks.png") PopMatrix() cylinder = self.scene.objects["Cylinder"] PushMatrix() self.cylinder_rot = Rotate(0, 1, 0, 0) _set_color(0.0, 0.7, 0.0, id_color=(0.0, 255, 0)) _draw_element(cylinder, "wood.png") PopMatrix() def update_scene(self, *largs): self.pyramid_rot.angle += 0.5 self.box_rot.angle += 0.5 self.cylinder_rot.angle += 0.5 # =============== All stuff after is for trackball implementation ============= def define_rotate_angle(self, touch): x_angle = (touch.dx / self.width) * 360 y_angle = -1 * (touch.dy / self.height) * 360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here # use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = old_dx * old_dx + old_dy * old_dy Logger.debug("Old distance: %s" % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = new_dx * new_dx + new_dy * new_dy Logger.debug("New distance: %s" % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR Logger.debug("Scale up") elif new_distance == old_distance: scale = 0 else: scale = -1 * SCALE_FACTOR Logger.debug("Scale down") xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
class Paint(StencilView): scale = NumericProperty() def __init__(self, app, **kwargs): StencilView.__init__(self, **kwargs) self.app = app self.xx = 0 self.scale = 1.0 self.size_hint = (None, None) self.cursor_pos = (0, 0) self.fbo_size = DEFAULT_IMAGE_SIZE self.fbo = None self.fbo_rect = None self.tool_fbo = None self.tool_fbo_rect = None self.bg_rect = None self.rect = None self.fbo_clear_color = (1, 1, 1, 1) self.layer_undo_stack = [] self.undo_layer_index = 0 self.layer_rect = [] self.fbo_create_on_canvas() self.touches = [] self.move_image = False self.active_layer = None self.tool_buffer_enabled = True self.px = None self.py = None self.grid_texture = None self.active_layer_last_texture = None def grid_create(self, size): self.grid_texture = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tex = improc.texture_draw_grid(self.grid_texture, 255, 4) return tex def fbo_create(self, size, tex=None): if tex is None: tex = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tex.mag_filter = 'nearest' tex.min_filter = 'nearest' if self.fbo is None: self.fbo = Fbo(size=size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' else: self.fbo = Fbo(size=size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' tool_tex = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tool_tex.mag_filter = 'nearest' tool_tex.min_filter = 'nearest' if self.tool_fbo is None: self.tool_fbo = Fbo(size=size, texture=tool_tex) self.tool_fbo.texture.mag_filter = 'nearest' self.tool_fbo.texture.min_filter = 'nearest' else: self.tool_fbo = Fbo(size=size, texture=tool_tex) self.tool_fbo.texture.mag_filter = 'nearest' self.tool_fbo.texture.min_filter = 'nearest' return self.fbo def refbo(self): tex = Texture.create(size=self.fbo.texture.size, colorfmt='rgba', bufferfmt='ubyte') self.fbo = Fbo(size=tex.size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' self.fbo.draw() self.canvas.ask_update() def canvas_put_drawarea(self, texture=None): self.canvas.clear() if texture: self.fbo_size = texture.size self.fbo_create(texture.size, tex=texture) self.bg_rect = layer.Layer.layer_bg_rect with self.canvas: self.canvas.add(self.bg_rect) Color(1, 1, 1, 1) for laybox in layer.LayerBox.boxlist: if laybox.layer: if laybox.layer.texture and laybox.layer.visible: self.canvas.add(laybox.layer.rect) laybox.layer.rect.pos = self.fbo_rect.pos if self.tool_buffer_enabled: self.tool_fbo_rect = Rectangle(pos=self.fbo_rect.pos, size=self.tool_fbo.texture.size, texture=self.tool_fbo.texture) self.fbo_update_pos() self.fbo.draw() self.canvas.ask_update() def fbo_create_on_canvas(self, size=None, pos=(0, 0)): self.canvas.clear() if size is None: size = self.fbo_size else: self.fbo_size = size self.fbo_create(size) with self.canvas: Color(1, 1, 1, 1) self.fbo_rect = Rectangle(texture=self.fbo.texture, pos=pos, size=self.fbo.texture.size) self.tool_fbo_rect = Rectangle(texture=self.tool_fbo.texture, pos=pos, size=self.tool_fbo.texture.size) self.fbo.draw() self.canvas.ask_update() def fbo_clear(self): self.fbo.bind() self.fbo.clear() self.fbo.clear_color = self.fbo_clear_color self.fbo.clear_buffer() self.fbo.release() self.fbo.draw() def fbo_update_pos(self): x = self.app.aPaintLayout.size[0] / self.scale / 2 - self.fbo.size[0] / 2 y = self.app.aPaintLayout.size[1] / self.scale / 2 - self.fbo.size[1] / 2 self.fbo_rect.pos = (x, y) self.tool_fbo_rect.pos = (x, y) if self.bg_rect: self.bg_rect.pos = (x, y) if self.app.layer_ribbon: for lb in layer.LayerBox.boxlist: if lb.layer.rect: lb.layer.rect.pos = self.fbo_rect.pos def fbo_move_by_offset(self, offset): if self.bg_rect: self.bg_rect.pos = self.bg_rect.pos[0] + offset[0], self.bg_rect.pos[1] + offset[1] self.fbo_rect.pos = self.bg_rect.pos self.tool_fbo_rect.pos = self.bg_rect.pos if self.app.layer_ribbon: for lb in layer.LayerBox.boxlist: if lb.layer.rect: lb.layer.rect.pos = self.fbo_rect.pos # self.ox, self.oy = self.bg_rect.pos # def fbo_render(self, touch, width): self.fbo.bind() if touch and touch.ud.has_key('line'): with self.fbo: self.fbo.add(self.app.aColor) d = width self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) touch.ud['line'].points += self.cursor_pos self.fbo.release() self.fbo.draw() self.canvas.ask_update() def fbo_get_texture(self): return self.fbo.texture def fbo_get_pixel_color(self, touch, format='1'): self.fbo.bind() x = touch.x / self.scale - self.fbo_rect.pos[0] y = touch.y / self.scale - self.fbo_rect.pos[1] data = glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE) self.fbo.release() if format == '1': c = [ord(a) / 255.0 for a in data] else: c = [ord(a) for a in data] return c def fbo_fill_region(self, touch): x = int(touch.x / self.scale - self.fbo_rect.pos[0]) y = int(touch.y / self.scale - self.fbo_rect.pos[1]) improc.fillimage(self.fbo, (x, y), [int(255 * c) for c in self.app.aColor.rgba]) self.canvas.ask_update() def fbo_replace_color(self, touch, width): cx = int(touch.x / self.scale - self.fbo_rect.pos[0]) cy = int(touch.y / self.scale - self.fbo_rect.pos[1]) if self.px is None: self.px = cx if self.py is None: self.py = cy if (cx - self.px) > 0: tg_alpha = float((cy - self.py)) / (cx - self.px) step = int(math.copysign(1, tg_alpha)) if abs(cx - self.px) > abs(cy - self.py): coords = [(x, self.py + (x - self.px) * tg_alpha) for x in xrange(int(self.px), int(cx))] else: coords = [(self.px + (y - self.py) / tg_alpha, y) for y in xrange(int(self.py), int(cy), step)] elif (cx - self.px) < 0: tg_alpha = float((cy - self.py)) / (cx - self.px) step = int(math.copysign(1, tg_alpha)) if abs(cx - self.px) > abs(cy - self.py): coords = [(x, self.py + (x - self.px) * tg_alpha) for x in xrange(int(cx), int(self.px))] else: coords = [(self.px + (y - self.py) / tg_alpha, y) for y in xrange(int(cy), int(self.py), step)] elif (cx - self.px) == 0: if (cy - self.py) > 0: coords = [(cx, y) for y in xrange(int(self.py), int(cy))] elif (cy - self.py) < 0: coords = [(cx, y) for y in xrange(int(cy), int(self.py))] else: coords = [(cx, cy), ] self.fbo.bind() for (x, y) in coords: improc.texture_replace_color(tex=self.fbo.texture, pos=(x, y), color=0, size=(width, width)) self.fbo.release() self.fbo.clear() self.fbo.draw() self.canvas.ask_update() self.px = cx self.py = cy def pos_to_widget(self, touch): return self.to_widget(touch.x, touch.y) def scale_canvas(self, zoom): with self.canvas.before: PushMatrix() self.scale *= zoom context_instructions.Scale(zoom) with self.canvas.after: PopMatrix() self.fbo_update_pos() def on_scale(self, instance, scale): ToolBehavior.scale() def scale_pos(self, pos): return [pos[0] / self.scale - self.fbo_rect.pos[0], pos[1] / self.scale - self.fbo_rect.pos[1]] def scaled_pos(self): return [self.fbo_rect.pos[0] * self.scale, self.fbo_rect.pos[1] * self.scale] def scaled_size(self): return [self.fbo_rect.texture.size[0] * self.scale, self.fbo_rect.texture.size[1] * self.scale] def add_touch(self, touch): if touch and len(self.touches) < 2: self.touches.append(touch) if len(self.touches) >= 2: self.touch_dist = self.touches[0].distance(self.touches[1]) self.touch_dist_const = self.touch_dist self.first_touch = self.touches[0] def double_touch(self): if len(self.touches) > 1: return True # def double_touch_distance(self): # return Vector(self.touches[0].pos).distance(self.touches[1].pos) def touch_responce(self): result = False if len(self.touches) >= 2: pos1 = self.pos_to_widget(self.touches[0]) pos2 = self.touches[1].pos dist = distance(pos1, pos2) if dist > self.touch_dist + 10: self.touch_dist = dist result = 2 elif dist <= self.touch_dist - 10: self.touch_dist = dist result = 1 if abs(self.touch_dist_const - dist) < 10: result = 3 return result return False def on_touch_down(self, touch): self.tool_buffer.on_touch_down(touch) if self.collide_point(*touch.pos): if self.app.config.getint('toolbars', 'toolbar_autohide'): self.app.toolbar.animate_hide() if self.app.config.getint('toolbars', 'palette_autohide'): self.app.palette.animate_hide() if self.app.config.getint('toolbars', 'layer_ribbon_autohide'): self.app.layer_ribbon.animate_hide() if not self.collide_point(*touch.pos): if self.app.active_tool == TOOL_LINE: self.tool_line._render_and_reset_state(self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() return False touch.grab(self) self.add_touch(touch) if len(self.touches) == 1: self.active_layer_backup_texture() if self.double_touch(): self.active_layer_set_last_backup_texture() return if not self.app.layer_ribbon.get_active_layer().visible: dialog.PopupMessage("Notification", "The current layer is hidden, make it visible for edit") return if self.app.layer_ribbon.get_active_layer().texture_locked: dialog.PopupMessage("Notification", "The current layer is locked, make it unlock for edit") return if self.app.active_tool == TOOL_PENCIL1: self.fbo.bind() if touch: with self.fbo: self.fbo.add(self.app.aColor) d = 1. self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) Ellipse(pos=self.cursor_pos, size=(d, d)) touch.ud['line'] = Line(points=self.cursor_pos, width=d) self.fbo.release() self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_PENCIL2: self.fbo.bind() if touch: with self.fbo: self.fbo.add(self.app.aColor) d = 2.1 self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) Ellipse(pos=self.cursor_pos, size=(d, d)) touch.ud['line'] = Line(points=self.cursor_pos, width=d / 2.0) self.fbo.release() self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_PENCIL3: self.fbo.bind() if touch: with self.fbo: self.fbo.add(self.app.aColor) d = 3. self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) Ellipse(pos=self.cursor_pos, size=(d, d)) touch.ud['line'] = Line(points=self.cursor_pos, width=d / 2) self.fbo.release() self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_PICKER: if touch: if self.collide_point(touch.x, touch.y): c = self.fbo_get_pixel_color(touch) self.app.aColor = Color(c[0], c[1], c[2], c[3]) self.app.toolbar.tools_select(self.app.prev_tool) elif self.app.active_tool == TOOL_FILL: if touch: if self.collide_point(touch.x, touch.y): self.fbo_fill_region(touch) elif self.app.active_tool == TOOL_ERASE1: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=1) elif self.app.active_tool == TOOL_ERASE2: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=2) elif self.app.active_tool == TOOL_ERASE3: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=3) elif self.app.active_tool == TOOL_SELECT: if touch: if not self.tool_buffer.enabled: self.tool_select.on_touch_down(touch, self.fbo, self.tool_fbo) else: pass elif self.app.active_tool == TOOL_LINE: if touch: self.tool_line.on_touch_down(touch, self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_RECT: if touch: self.tool_rect.on_touch_down(touch, self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_ELLIPSE: if touch: self.tool_ellipse.on_touch_down(touch, self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_MOVE: if touch: if self.collide_point(touch.x, touch.y): self.move_image = True self.ox, self.oy = touch.pos return True def on_touch_move(self, touch): result = self.touch_responce() if result == 2: self.scale_canvas(1.02) return elif result == 1: self.scale_canvas(0.98) return elif result == 3: dist = self.touches[0].distance(self.first_touch) self.fbo_move_by_offset((dist / self.scale, dist / self.scale)) if self.app.active_tool == TOOL_PENCIL1: self.fbo_render(touch, width=1.) elif self.app.active_tool == TOOL_PENCIL2: self.fbo_render(touch, width=2.) elif self.app.active_tool == TOOL_PENCIL3: self.fbo_render(touch, width=3.) elif self.app.active_tool == TOOL_PICKER: c = self.fbo_get_pixel_color(touch) self.app.aColor = Color(c[0], c[1], c[2]) elif self.app.active_tool == TOOL_ERASE1: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=1) elif self.app.active_tool == TOOL_ERASE2: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=2) elif self.app.active_tool == TOOL_ERASE3: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=3) elif self.app.active_tool == TOOL_SELECT: if touch: if not self.tool_buffer.enabled: self.tool_select.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() else: pass elif self.app.active_tool == TOOL_LINE: if touch: self.tool_line.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_RECT: if touch: self.tool_rect.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_ELLIPSE: if touch: self.tool_ellipse.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_MOVE: if self.move_image: self.fbo_move_by_offset((touch.dx / self.scale, touch.dy / self.scale)) self.tool_buffer.on_touch_move(touch, self.fbo) def on_touch_up(self, touch): self.tool_buffer.on_touch_up(touch) if touch.grab_current is not self: return False if not self.collide_point(*touch.pos): return False touch.ungrab(self) if self.double_touch(): _not_add_too_undo = True else: _not_add_too_undo = False if touch: try: self.touches.remove(touch) except: pass if self.app.active_tool == TOOL_SELECT: if touch: self.tool_select.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_LINE: if touch: self.tool_line.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_RECT: if touch: self.tool_rect.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_ELLIPSE: if touch: self.tool_ellipse.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_MOVE: if touch: self.move_image = False elif self.app.active_tool == TOOL_ERASE1 or self.app.active_tool == TOOL_ERASE2 or self.app.active_tool == TOOL_ERASE3: if touch: self.px = None self.py = None if self.app.active_tool == TOOL_PENCIL1 or self.app.active_tool == TOOL_ERASE1 \ or self.app.active_tool == TOOL_PENCIL2 or self.app.active_tool == TOOL_ERASE2 \ or self.app.active_tool == TOOL_PENCIL3 or self.app.active_tool == TOOL_ERASE3 \ or self.app.active_tool == TOOL_FILL: rect = self.app.layer_ribbon.get_active_layer().rect pos = rect.pos[0] * self.scale, rect.pos[1] * self.scale size = rect.size[0] * self.scale, rect.size[1] * self.scale if not _not_add_too_undo: if pos[0] <= touch.x <= pos[0] + size[0] and pos[1] <= touch.y <= pos[1] + size[1]: self.add_undo_stack() return True def add_redo_stack(self): pass def add_undo_stack(self): _active_layer = self.app.layer_ribbon.get_active_layer() _active_layer.backup_texture() self.layer_undo_stack = self.layer_undo_stack[:self.undo_layer_index + 1] self.layer_undo_stack.append(_active_layer) self.undo_layer_index = len(self.layer_undo_stack) - 1 def do_undo(self, *args): if self.layer_undo_stack: if self.undo_layer_index > 0: _layer = self.layer_undo_stack[self.undo_layer_index] _layer.texture_from_backup(direction=-1) _active_layer = self.app.layer_ribbon.get_active_layer() if _layer is _active_layer: self.fbo_create(_active_layer.texture.size, _active_layer.texture) self.undo_layer_index -= 1 self.canvas_put_drawarea() self.fbo_update_pos() def active_layer_backup_texture(self): active_layer = self.app.layer_ribbon.get_active_layer() self.active_layer_last_texture = improc.texture_copy(active_layer.texture) def active_layer_set_last_backup_texture(self): active_layer = self.app.layer_ribbon.get_active_layer() # texture = active_layer.textures_array[-1] active_layer.replace_texture(self.active_layer_last_texture) self.fbo_create(active_layer.texture.size, active_layer.texture) self.canvas_put_drawarea() self.fbo_update_pos() self.canvas.ask_update() def do_redo(self, *args): if self.layer_undo_stack: if self.undo_layer_index < len(self.layer_undo_stack) - 1: self.undo_layer_index += 1 _layer = self.layer_undo_stack[self.undo_layer_index] _layer.texture_from_backup(direction=1) _active_layer = self.app.layer_ribbon.get_active_layer() if _layer is _active_layer: self.fbo_create(_active_layer.texture.size, _active_layer.texture) self.canvas_put_drawarea() self.fbo_update_pos()
class ObjectRenderer(Widget): scene = StringProperty('') obj_id = StringProperty('') obj_translation = ListProperty([0, 0, 0]) obj_rotation = ListProperty([0, 0, 0]) obj_scale = NumericProperty(1) obj_texture = StringProperty('') texture = ObjectProperty(None, allownone=True) cam_translation = ListProperty([0, 0, 0]) cam_rotation = ListProperty([0, 0, 0]) display_all = BooleanProperty(False) light_sources = DictProperty() ambiant = NumericProperty(.5) diffuse = NumericProperty(.5) specular = NumericProperty(.5) mode = StringProperty('triangles') def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find( join(dirname(__file__), 'simple.glsl')) super(ObjectRenderer, self).__init__(**kwargs) def on_obj_rotation(self, *args): self.obj_rot_x.angle = self.obj_rotation[0] self.obj_rot_y.angle = self.obj_rotation[1] self.obj_rot_z.angle = self.obj_rotation[2] def on_cam_rotation(self, *args): self.cam_rot_x.angle = self.cam_rotation[0] self.cam_rot_y.angle = self.cam_rotation[1] self.cam_rot_z.angle = self.cam_rotation[2] def on_obj_translation(self, *args): self.obj_translate.xyz = self.cam_translation def on_cam_translation(self, *args): self.cam_translate.xyz = self.cam_translation def on_obj_scale(self, *args): self.scale.xyz = [ self.obj_scale, ] * 3 def on_display_all(self, *args): self.setup_canvas() def on_light_sources(self, *args): self.fbo['light_sources'] = [ ls[:] for ls in self.light_sources.values() ] self.fbo['nb_lights'] = len(self.light_sources) def on_ambiant(self, *args): self.fbo['ambiant'] = self.ambiant def on_diffuse(self, *args): self.fbo['diffuse'] = self.diffuse def on_specular(self, *args): self.fbo['specular'] = self.specular def on_mode(self, *args): self.setup_canvas() def setup_canvas(self, *args): if not (self.scene and self.obj_id or self.display_all): return print 'setting up the scene' with self.fbo: self.fbo['ambiant'] = self.ambiant self.fbo['diffuse'] = self.diffuse self.fbo['specular'] = self.specular self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) def on_scene(self, instance, value): print "loading scene %s" % value self._scene = ObjFileLoader(resource_find(value)) self.setup_canvas() def on_obj_id(self, *args): self.setup_canvas() def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *args): asp = self.width / max(float(self.height), 1) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() self.cam_translate = Translate(self.cam_translation) # Rotate(0, 1, 0, 0) self.cam_rot_x = Rotate(self.cam_rotation[0], 1, 0, 0) self.cam_rot_y = Rotate(self.cam_rotation[1], 0, 1, 0) self.cam_rot_z = Rotate(self.cam_rotation[2], 0, 0, 1) self.scale = Scale(self.obj_scale) UpdateNormalMatrix() if self.display_all: for i in self._scene.objects: self.draw_object(i) else: self.draw_object(self.obj_id) PopMatrix() def draw_object(self, obj_id): m = self._scene.objects[obj_id] self.obj_rot_z = Rotate(self.obj_rotation[2], 0, 0, 1) self.obj_rot_y = Rotate(self.obj_rotation[1], 0, 1, 0) self.obj_rot_x = Rotate(self.obj_rotation[0], 1, 0, 0) self.obj_translate = Translate(xyz=self.obj_translation) if len(m.indices) > 2**16: print '%s too big! %s indices' % (obj_id, len(m.indices)) if m.texture: print "loading texture %s " % m.texture img = Image( source=resource_find(join(dirname(self.scene), m.texture))) texture = img.texture if texture: texture.wrap = 'repeat' else: texture = None vertex_lenght = sum(x[1] for x in m.vertex_format) if len(m.vertices) % vertex_lenght: print(('warning: vertices lenght (%s)' 'is not a multiple of vertex_format lenght(%s)') % (len(m.vertices), vertex_lenght)) Mesh(vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, texture=texture, mode=self.mode)
class Renderer(Widget): texture = ObjectProperty(None, allownone=True) def load(self, *l): self.button.disabled = True if os.path.isdir(meshdir): rep = meshdir self.fl = FileChooserListView(path=rep, rootpath=rep, filters=["*.mesh.ascii"], dirselect=False, size=(400, 400), center_x=250, center_y=250) else: rep = os.getcwd() self.fl = FileChooserListView(path=rep, filters=["*.mesh.ascii"], dirselect=False, size=(400, 400), center_x=250, center_y=250) '''if platform == 'android': rep = "." else: rep = "../../Mesh"''' self.fl.bind(selection=self.on_selected) super(Renderer, self).add_widget(self.fl) def on_selected(self, filechooser, selection): self.button.disabled = False print 'load', selection super(Renderer, self).remove_widget(self.fl) scale = 3 self.fbo.remove_group('truc') self.scene = MeshAsciiLoader(selection[0], scale) with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) def change_shader(self, *l): print 'change_shader' if self.shader == 0: self.fbo.shader.source = resource_find('simple.glsl') self.shader = 1 else: #self.fbo.shader.source = resource_find('flat.glsl') self.fbo.shader.source = resource_find('normalmap.glsl') self.shader = 0 def __init__(self, **kwargs): self.model = 0 self.shader = 0 self.canvas = Canvas() #self.scene = ObjFileLoader(resource_find("testnurbs.obj")) Logger.debug('******************************************************') scale = 3 #dir = "Duke Nukem Forever_Dr_Valencia" # error index out of range #dir = "Duke Nukem Forever_Kitty Pussoix" dir = "Duke_Nukem_by_Ventrue" #dir = "DOA5U_Rachel_Nurse/Model" #pb uv if not os.path.isdir(meshdir): self.scene = MeshAsciiLoader( resource_find(dir + "/Generic_Item.mesh.ascii"), scale) else: self.scene = MeshAsciiLoader( resource_find(meshdir + dir + "/Generic_Item.mesh.ascii"), scale) #scale = .03 #self.texturename = 'Batman_Rabbit_Head_Posed/Batman_V3_Body_D.PNG' #self.scene = PSKFileLoader(resource_find("Batman_Rabbit_Head_Posed/Batman_Rabbit_Head_Posed.psk"), scale) #self.texturename = 'Gray/Gray_C1.tga' #self.scene = PSKFileLoader(resource_find("Gray/Mike_TPP.psk"), scale) #too many indices, good for split test #self.texturename = 'CV_Talia/Talia_Body_D.tga' #self.texturename = 'CV_Talia/Talia_Legs_D.tga') #self.scene = PSKFileLoader(resource_find("CV_Talia/Talia_posed.psk"), scale) #too many indices, good for split test Logger.debug('******************************************************') with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0, 0, 0, 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) #self.fbo.shader.source = resource_find('simple.glsl') self.fbo.shader.source = resource_find('normalmap.glsl') super(Renderer, self).__init__(**kwargs) self.fbo['texture1'] = 1 self.fbo['toggletexture'] = 1 with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = [] self.button = Button(text='load') self.button.bind(on_release=self.load) super(Renderer, self).add_widget(self.button) button1 = Button(text='shader', center_x=150) button1.bind(on_release=self.change_shader) super(Renderer, self).add_widget(button1) def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): #clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() #glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 500, 1) self.fbo['projection_mat'] = proj self.fbo['diffuse_light'] = (1.0, 0.0, 0.0) self.fbo['ambient_light'] = (0.1, 0.1, 0.1) self.fbo['glLightSource0_position'] = (1.0, 1.0, 1.0, 0.0) self.fbo['glLightSource0_spotCutoff'] = 360 self.fbo['glLightModel_ambient'] = (0.2, 0.2, 0.2, 1.0) self.fbo['glLightSource0_diffuse'] = (0.7, 0.7, 0.7, 1.0) self.fbo['glLightSource0_specular'] = (.1, .1, .1, 1.0) self.fbo['glFrontMaterial_specular'] = (.10, .10, .10, 1.0) self.fbo['glFrontMaterial_shininess'] = 0.1 def setup_scene(self): Color(.5, .5, .5, 0) PushMatrix() Translate(0, -3, -5) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) # here just rotate scene for best view self.roty = Rotate(180, 0, 1, 0) self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements() PopMatrix() def draw_elements(self): #Draw separately all meshes on the scene def _draw_element(m, texture='', texture1=''): #bind the texture BEFORE the draw (Mesh) if texture1: # here, we are binding a custom texture at index 1 # this will be used as texture1 in shader. tex1 = Image(texture1).texture tex1.wrap = 'repeat' #enable of uv support >1 or <0 BindTexture(texture=tex1, index=1) #clear the texture if none else: BindTexture(source="", index=1) mesh = Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles', group='truc', ) if texture: try: texture = Image(texture).texture texture.wrap = 'repeat' #enable of uv support >1 or <0 mesh.texture = texture except: #no texture if not found or not supported pass def _set_color(*color, **kw): id_color = kw.pop('id_color', (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1., id_color=[i / 255. for i in id_color], ) for meshid in range(0, len(self.scene.objects)): # Draw each element mesh = self.scene.objects[meshid] #_set_color(0.7, 0.7, 0., id_color=(255, 255, 0)) if (mesh.diffuse != ""): _draw_element(mesh, mesh.diffuse, mesh.normal) #_draw_element(mesh, mesh.diffuse) #_draw_element(mesh, mesh.normal) else: _draw_element(mesh, self.texturename) def update_scene(self, *largs): pass # ============= All stuff after is for trackball implementation =========== def define_rotate_angle(self, touch): x_angle = (touch.dx / self.width) * 360 y_angle = -1 * (touch.dy / self.height) * 360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) return super(Renderer, self).on_touch_down(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) return super(Renderer, self).on_touch_up(touch) def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here #use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = (old_dx * old_dx + old_dy * old_dy) #Logger.debug('Old distance: %s' % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = (new_dx * new_dx + new_dy * new_dy) #Logger.debug('New distance: %s' % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR #Logger.debug('Scale up') elif new_distance == old_distance: scale = 0 else: scale = -1 * SCALE_FACTOR #Logger.debug('Scale down') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
class Renderer(Widget): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): #self.canvas = RenderContext(compute_normal_mat=True) #self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.meshes = [] with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find('simple.glsl') #self.texture = self.fbo.texture super(Renderer, self).__init__(**kwargs) with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = [] def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): #clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() #glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() Translate(0, 0, -5) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) self.roty = Rotate(-120, 0, 1, 0) # here just rotate scene for best view self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements() PopMatrix() def draw_elements(self): """ Draw separately all objects on the scene to setup separate rotation for each object """ def _draw_element(m): Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles', ) def _set_color(*color, **kw): id_color = kw.pop('id_color', (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1., id_color=[i / 255. for i in id_color], ) # Draw sphere in the center sphere = self.scene.objects['Sphere'] _set_color(0.7, 0.7, 0., id_color=(255, 255, 0)) _draw_element(sphere) # Then draw other elements and totate it in different axis pyramid = self.scene.objects['Pyramid'] PushMatrix() self.pyramid_rot = Rotate(0, 0, 0, 1) _set_color(0., 0., .7, id_color=(0., 0., 255)) _draw_element(pyramid) PopMatrix() box = self.scene.objects['Box'] PushMatrix() self.box_rot = Rotate(0, 0, 1, 0) _set_color(.7, 0., 0., id_color=(255, 0., 0)) _draw_element(box) PopMatrix() cylinder = self.scene.objects['Cylinder'] PushMatrix() self.cylinder_rot = Rotate(0, 1, 0, 0) _set_color(0.0, .7, 0., id_color=(0., 255, 0)) _draw_element(cylinder) PopMatrix() def update_scene(self, *largs): self.pyramid_rot.angle += 0.5 self.box_rot.angle += 0.5 self.cylinder_rot.angle += 0.5 # =============== All stuff after is for trackball implementation ============= def define_rotate_angle(self, touch): x_angle = (touch.dx/self.width)*360 y_angle = -1*(touch.dy/self.height)*360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) self.fbo.shader.source = 'select_mode.glsl' self.fbo.ask_update() self.fbo.draw() print(self.fbo.get_pixel_color(touch.x, touch.y)) self.fbo.shader.source = 'simple.glsl' self.fbo.ask_update() self.fbo.draw() def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here #use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = (old_dx*old_dx + old_dy*old_dy) Logger.debug('Old distance: %s' % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = (new_dx*new_dx + new_dy*new_dy) Logger.debug('New distance: %s' % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR Logger.debug('Scale up') elif new_distance == old_distance: scale = 0 else: scale = -1*SCALE_FACTOR Logger.debug('Scale down') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
class NSpect(Widget): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): LOP, dm = initFiles() #self.canvas = RenderContext(compute_normal_mat=True) #self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.LOP = LOP self.dm = dm self.meshes = [] self.panCamera = False # KEITH EDIT self.pause = True # KEITH EDIT with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find('simple.glsl') #self.texture = self.fbo.texture # *&Y*&Y*&YH*&Y*&Y*&Y*Y&* # Keith: This allows keyboard interaction # http://stackoverflow.com/questions/22137786/ self._keyboard = Window.request_keyboard(None, self) if not self._keyboard: return self._keyboard.bind(on_key_down=self.on_keyboard_down) # *&Y*&Y*&YH*&Y*&Y*&Y*Y&* super(NSpect, self).__init__(**kwargs) with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene(self.LOP, dm) PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = [] def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): #clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() #glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self, LOP, dm): Color(1, 1, 1, 0) PushMatrix() Translate(0, 0, -5) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) self.roty = Rotate(-120, 0, 1, 0) # here just rotate scene for best view self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements(LOP, dm) PopMatrix() def draw_elements(self, LOP, dm): """ Draw separately all objects on the scene to setup separate rotation for each object """ def _draw_element(m): Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles', ) def _set_color(*color, **kw): id_color = kw.pop('id_color', (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1., id_color=[i / 255. for i in id_color], ) def drawPoints(): print self.scene.objects for i in range(len(self.LOP)): PushMatrix() point = self.LOP[i] point.shape = self.scene.objects['Sphere'] point.color = _set_color(i/10., (i+1)/10., 0., id_color=(int(255/(1+i)), int(255/(1+i)), 255)) point.shape.scale = Scale((i+1)/10.0,(i+1)/10.0,(i+1)/10.0) self.LOP[i] = point print point.shape _draw_element(point.shape) point.shape.scale.origin = (point.loc[0],point.loc[1],point.loc[2]) PopMatrix() drawPoints() def update_scene(self, *largs): def randLoc(point): newLoc = (0.1*random.random(),0.1*random.random(),0.1*random.random()) oldLoc = point.shape.scale.origin newLoc = ( newLoc[0]-0.05+oldLoc[0], newLoc[1]-0.05+oldLoc[1], newLoc[2]-0.05+oldLoc[2] ) return newLoc def updateLocs(self): for i in range(len(self.LOP)): point = self.LOP[i] point.shape.scale.origin = randLoc(point) if not self.pause: updateLocs(self) pass # =============== All stuff after is for trackball implementation ============= def moveA(self): pass def moveB(self): pass def define_rotate_angle(self, touch): x_angle = (touch.dx/self.width)*360 y_angle = -1*(touch.dy/self.height)*360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) self.fbo.shader.source = 'select_mode.glsl' self.fbo.ask_update() self.fbo.draw() print self.fbo.get_pixel_color(touch.x, touch.y) self.fbo.shader.source = 'simple.glsl' self.fbo.ask_update() self.fbo.draw() # *O(U(U())(*U(*(****************** # Keith: This allows keyboard interaction def on_keyboard_down(self, keyboard, keycode, text, modifiers): if keycode[1] == 'left': if self.panCamera == True: self.x -= 10 else: self.roty.angle += 10 elif keycode[1] == 'right': if self.panCamera == True: self.x += 10 else: self.roty.angle -= 10 if keycode[1] == 'up': if self.panCamera == True: self.y += 10 else: self.rotx.angle += 10 elif keycode[1] == 'down': if self.panCamera == True: self.y -= 10 else: self.rotx.angle -= 10 elif keycode[1] == 'i': self.update_glsl() SCALE_FACTOR = 0.01 scale = SCALE_FACTOR Logger.debug('Scale up') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz) elif keycode[1] == 'o': self.update_glsl() SCALE_FACTOR = 0.01 scale = SCALE_FACTOR Logger.debug('Scale up') xyz = self.scale.xyz if scale: temp = tuple(p - scale for p in xyz) # Prevent the collection from having a negative size if temp[0] > 0: self.scale.xyz = temp elif keycode[1] == 't': self.panCamera = not self.panCamera elif keycode[1] == 'p': self.pause = not self.pause if not self.pause: print "Playing" else: print "Paused" def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here #use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = (old_dx*old_dx + old_dy*old_dy) Logger.debug('Old distance: %s' % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = (new_dx*new_dx + new_dy*new_dy) Logger.debug('New distance: %s' % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR Logger.debug('Scale up') elif new_distance == old_distance: scale = 0 else: scale = -1*SCALE_FACTOR Logger.debug('Scale down') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
class Renderer(Widget): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("brain.obj")) self.meshes = [] with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=(0, -150)) self.fbo.shader.source = resource_find('simple.glsl') super(Renderer, self).__init__(**kwargs) with self.fbo: self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() Translate(0, 0, -8) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) self.roty = Rotate(-180, 0, 1, 0) # here just rotate scene for best view self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements() PopMatrix() def draw_elements(self): """ Draw separately all objects on the scene to setup separate rotation for each object """ def _draw_element(m): Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles', ) def _set_color(*color, **kw): id_color = kw.pop('id_color', (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(.1, .1, .1), Tr=1., Ns=1., intensity=1., id_color=[i / 255. for i in id_color], ) # Draw sphere in the center brain = self.scene.objects['Brain'] _set_color(.659, .439, .361, id_color=(255, 255, 255)) _draw_element(brain) brain2 = self.scene.objects['Brain2'] _set_color(.659, .439, .361, id_color=(255, 255, 255)) _draw_element(brain2)
class SMAA(Widget): debug = OptionProperty("", options=("", "edges", "blend", "source")) """Texture to show instead of the result: - `edges` will show you the result of the edges detection shader - `blend` will show you the result of the blending shader - `source` will show you the initial drawing of children, before any pass. """ quality = OptionProperty("ultra", options=("low", "medium", "high", "ultra")) """Quality of the shader. The more you ask, the slower it will be. """ def __init__(self, **kwargs): self._g_debug = [] self._g_debug_added = False if "size" not in kwargs: from kivy.core.window import Window kwargs["size"] = Window.size self.size = kwargs["size"] self.init_smaa() super(SMAA, self).__init__() self.canvas.add(self.smaa_canvas) self.canvas.ask_update() def add_widget(self, *args): canvas = self.smaa_canvas self.canvas = self.albedo_fbo super(SMAA, self).add_widget(*args) self.canvas = canvas def remove_widget(self, *args): canvas = self.smaa_canvas self.canvas = self.albedo_fbo super(SMAA, self).remove_widget(*args) self.canvas = canvas def init_smaa(self): curdir = dirname(__file__) # load shaders sources with open(join(curdir, "SMAA.h"), "r") as fd: smaa_h = fd.read() config = """ #version 410 compatibility #define SMAA_PIXEL_SIZE vec2(1.0 / {width}, 1.0 / {height}) #define SMAA_PRESET_{quality} 1 #define SMAA_GLSL_4 1 """.format( width=self.width, height=self.height, quality=self.quality.upper() ) header_vs = ( config + """ #define SMAA_ONLY_COMPILE_VS 1 in vec2 vPosition; in vec2 vTexCoords0; uniform mat4 modelview_mat; uniform mat4 projection_mat; """ + smaa_h ) header_fs = ( config + """ #define SMAA_ONLY_COMPILE_PS 1 """ + smaa_h ) edge_vs = ( header_vs + """ out vec2 texcoord; out vec4 offset[3]; out vec4 dummy2; void main() { texcoord = vTexCoords0; vec4 dummy1 = vec4(0); SMAAEdgeDetectionVS(dummy1, dummy2, texcoord, offset); gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0); } """ ) edge_fs = ( header_fs + """ uniform sampler2D albedo_tex; in vec2 texcoord; in vec4 offset[3]; in vec4 dummy2; void main() { #if SMAA_PREDICATION == 1 gl_FragColor = SMAAColorEdgeDetectionPS(texcoord, offset, albedo_tex, depthTex); #else gl_FragColor = SMAAColorEdgeDetectionPS(texcoord, offset, albedo_tex); #endif } """ ) blend_vs = ( header_vs + """ out vec2 texcoord; out vec2 pixcoord; out vec4 offset[3]; out vec4 dummy2; void main() { texcoord = vTexCoords0; vec4 dummy1 = vec4(0); SMAABlendingWeightCalculationVS(dummy1, dummy2, texcoord, pixcoord, offset); gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0); } """ ) blend_fs = ( header_fs + """ uniform sampler2D edge_tex; uniform sampler2D area_tex; uniform sampler2D search_tex; in vec2 texcoord; in vec2 pixcoord; in vec4 offset[3]; in vec4 dummy2; void main() { gl_FragColor = SMAABlendingWeightCalculationPS(texcoord, pixcoord, offset, edge_tex, area_tex, search_tex, ivec4(0)); } """ ) neighborhood_vs = ( header_vs + """ out vec2 texcoord; out vec4 offset[2]; out vec4 dummy2; void main() { texcoord = vTexCoords0; vec4 dummy1 = vec4(0); SMAANeighborhoodBlendingVS(dummy1, dummy2, texcoord, offset); gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0); } """ ) neighborhood_fs = ( header_fs + """ uniform sampler2D albedo_tex; uniform sampler2D blend_tex; in vec2 texcoord; in vec4 offset[2]; in vec4 dummy2; void main() { gl_FragColor = SMAANeighborhoodBlendingPS(texcoord, offset, albedo_tex, blend_tex); } """ ) size = self.size self.albedo_tex = Texture.create(size=size, bufferfmt="float") self.albedo_fbo = Fbo(size=size, texture=self.albedo_tex) self.edge_tex = Texture.create(size=size, bufferfmt="float") self.edge_fbo = Fbo(size=size, vs=edge_vs, fs=edge_fs, texture=self.edge_tex) self.edge_fbo.bind() self.edge_fbo["albedo_tex"] = 0 self.edge_fbo.release() self.blend_tex = Texture.create(size=size, bufferfmt="float") self.blend_fbo = Fbo(size=size, vs=blend_vs, fs=blend_fs, texture=self.blend_tex) self.blend_fbo.bind() self.blend_fbo["edge_tex"] = 0 self.blend_fbo["area_tex"] = 1 self.blend_fbo["search_tex"] = 2 self.blend_fbo.release() self.neighborhood = RenderContext( use_parent_modelview=True, use_parent_projection=True, vs=neighborhood_vs, fs=neighborhood_fs ) with self.neighborhood: self.neighborhood["albedo_tex"] = 0 self.neighborhood["blend_tex"] = 1 self.area_tex = Texture.create(size=(AREATEX_WIDTH, AREATEX_HEIGHT), colorfmt="rg", icolorfmt="rg8") with open(join(curdir, "smaa_area.raw"), "rb") as fd: self.area_tex.blit_buffer(fd.read(), colorfmt="rg") self.search_tex = Texture.create(size=(SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT), colorfmt="red", icolorfmt="r8") self.search_tex.min_filter = "nearest" self.search_tex.mag_filter = "nearest" with open(join(curdir, "smaa_search.raw"), "rb") as fd: self.search_tex.blit_buffer(fd.read(), colorfmt="red") with self.albedo_fbo: ClearColor(0, 0, 0, 0) ClearBuffers() with self.edge_fbo: Rectangle(size=self.size, texture=self.albedo_tex) with self.blend_fbo: BindTexture(index=1, texture=self.area_tex) BindTexture(index=2, texture=self.search_tex) Rectangle(size=self.size, texture=self.edge_tex) self.neighborhood.add(self.albedo_fbo) self.neighborhood.add(Callback(lambda *x: glDisable(GL_BLEND))) self.neighborhood.add(self.edge_fbo) self.neighborhood.add(self.blend_fbo) self.neighborhood.add(Callback(lambda *x: glEnable(GL_BLEND))) with self.neighborhood: BindTexture(index=1, texture=self.blend_tex) Rectangle(size=self.size, texture=self.albedo_tex) self.smaa_canvas = Canvas() with self.smaa_canvas.before: def do_stuff(*args): self.albedo_fbo.bind() self.albedo_fbo.clear_buffer() self.albedo_fbo.release() self.edge_fbo.bind() self.edge_fbo.clear_buffer() self.edge_fbo.release() self.blend_fbo.bind() self.blend_fbo.clear_buffer() self.blend_fbo.release() self.albedo_fbo.ask_update() self.edge_fbo.ask_update() self.blend_fbo.ask_update() self.neighborhood.ask_update() Callback(do_stuff) self.smaa_canvas.add(self.neighborhood) self._g_debug_added = False self._g_debug = [ Callback(lambda *x: glDisable(GL_BLEND)), Color(0, 0, 0, 1), Rectangle(size=self.size), Color(1, 1, 1, 1), Rectangle(size=self.size), Callback(lambda *x: glEnable(GL_BLEND)), ] def on_debug(self, instance, value): g_debug = self._g_debug if self._g_debug_added: for instr in g_debug: self.canvas.after.remove(instr) if value == "": return elif value == "edges": g_debug[-2].texture = self.edge_tex elif value == "blend": g_debug[-2].texture = self.blend_tex elif value == "source": g_debug[-2].texture = self.albedo_tex self._g_debug_added = True for instr in g_debug: self.canvas.after.add(instr) def on_quality(self, instance, value): self.reload_smaa() def reload_smaa(self): debug = self.debug self.debug = "" children = self.children[:] for child in children: self.remove_widget(child) self.canvas.remove(self.smaa_canvas) self.init_smaa() self.canvas.add(self.smaa_canvas) for child in children: self.add_widget(child) self.debug = debug