def __init__(self, application): self.application = application self.width, self.height = width, height = application.mesh_width, application.mesh_height col = Column() self.input_height = LabelInput('Height', self).append_to(col).input self.material = LabelInput('Material', self).append_to(col).input self.widget = Widget('Terrain', col, id='terrain').append_to(application.workspace) self.default_material = Texture(2, 2, GL_RGBA, data=(140, 140, 140, 255)*4) self.vertex_texture = Texture(width, height, GL_RGBA32F) self.normal_texture = Texture(application.width, application.height, GL_RGBA32F, unit=GL_TEXTURE0) self.vertex_fbo = Framebuffer(self.vertex_texture) self.normal_fbo = Framebuffer(self.normal_texture) self.update_vertex_shader = application.shader('update_vertex.frag') self.update_normals_shader = application.shader('update_normals.frag') self.update_normals_shader.vars.offsets = 1.0/application.width, 1.0/application.height self.reset_vertex = application.shader('reset_vertex.frag') self.reset_normals = application.shader('reset_normals.frag') self.vbo = self.generate_vbo(width, height) self.reset() self.updated = None
def __init__(self, label, application): self.application = application self.id = os.urandom(16).encode('hex') application.add_node(self) self.column = Column() bar_area = Area().add_class('widget_bar') Label(label).append_to(bar_area) Button().append_to(bar_area).on_click = self.delete self.texture = application.create_texture() self.widget = Widget(bar_area, self.column).add_class('node').append_to( application.workspace) self._parameters = {} self.sources = {} self.updated = None self.optional = []
def __init__(self, label, application): self.application = application self.id = os.urandom(16).encode('hex') application.add_node(self) self.column = Column() bar_area = Area().add_class('widget_bar') Label(label).append_to(bar_area) Button().append_to(bar_area).on_click = self.delete self.texture = application.create_texture() self.widget = Widget(bar_area, self.column).add_class('node').append_to(application.workspace) self._parameters = {} self.sources = {} self.updated = None self.optional = []
def message(self, title, text): col = Column() Label(text).append_to(col) Button('Close').append_to(col).on_click = self.exit Widget(title, col, dragable=False).append_to(self.root).add_class('message')
class Terrain(object): id = 'terrain' def __init__(self, application): self.application = application self.width, self.height = width, height = application.mesh_width, application.mesh_height col = Column() self.input_height = LabelInput('Height', self).append_to(col).input self.material = LabelInput('Material', self).append_to(col).input self.widget = Widget('Terrain', col, id='terrain').append_to(application.workspace) self.default_material = Texture(2, 2, GL_RGBA, data=(140, 140, 140, 255)*4) self.vertex_texture = Texture(width, height, GL_RGBA32F) self.normal_texture = Texture(application.width, application.height, GL_RGBA32F, unit=GL_TEXTURE0) self.vertex_fbo = Framebuffer(self.vertex_texture) self.normal_fbo = Framebuffer(self.normal_texture) self.update_vertex_shader = application.shader('update_vertex.frag') self.update_normals_shader = application.shader('update_normals.frag') self.update_normals_shader.vars.offsets = 1.0/application.width, 1.0/application.height self.reset_vertex = application.shader('reset_vertex.frag') self.reset_normals = application.shader('reset_normals.frag') self.vbo = self.generate_vbo(width, height) self.reset() self.updated = None def export_obj(self, filename): if not filename.endswith('.obj'): filename += '.obj' if self.input_height.source: heightmap = self.input_height.source.texture heightmap.retrieve() width, height = self.application.width, self.application.height with open(filename, 'w') as outfile: heights = map(lambda z: (z, float(z)/height), range(height)) widths = map(lambda x: (x, float(x)/width), range(width)) for iz, z in heights: for ix, x in widths: outfile.write('v %f %f %f\n' % (x, heightmap[ix, iz][0], z)) self.normal_texture.retrieve() for normal in self.normal_texture: outfile.write('vn %f %f %f\n' % tuple(normal[:3])) heights = map(lambda x: float(x)/height, range(height)) widths = map(lambda y: float(y)/width, range(width)) for y in heights: for x in widths: outfile.write('vt %f %f\n' % (x, y)) i_width, i_height = width-1, height-1 for z in range(i_height): for x in range(i_width): p1 = x+z*width p2 = p1+width p4 = p1+1 p3 = p2+1 outfile.write('f %i/%i/%i %i/%i/%i %i/%i/%i\n' % ( p1+1, p1+1, p1+1, p2+1, p2+1, p2+1, p3+1, p3+1, p3+1 )) outfile.write('f %i/%i/%i %i/%i/%i %i/%i/%i\n' % ( p1+1, p1+1, p1+1, p3+1, p3+1, p3+1, p4+1, p4+1, p4+1 )) def export_float_array(self, filename): if not filename.endswith('.farr'): filename += '.farr' if self.input_height.source: heightmap = self.input_height.source.texture heightmap.retrieve() string = string_at(heightmap.buffer, heightmap.width*heightmap.height*4) with open(filename, 'wb') as outfile: outfile.write(string) def generate_vbo(self, width, height): #as an acceleration the arrays could be prefilled in C v4f = (c_float*(width*height*4))() width_factor, height_factor = 1.0/float(width), 1.0/float(height) for z in range(height): for x in range(width): offset = (x+z*width)*4 v4f[offset:offset+4] = x*width_factor, 0, z*height_factor, 1 i_width, i_height = width-1, height-1 indices = (c_uint*(i_width*i_height*6))() for z in range(i_height): for x in range(i_width): offset = (x+z*i_width)*6 p1 = x+z*width p2 = p1+width p4 = p1+1 p3 = p2+1 indices[offset:offset+6] = p1, p2, p3, p1, p3, p4 return VertexObject( pbo = True, indices = indices, dynamic_draw_v4f = v4f, ) def open(self, data, instances): offset = data['offset'] self.widget.rect.x, self.widget.rect.y = offset['x'], offset['y'] self.widget.layout() input_id = data['input_height'] if input_id: node = instances[input_id] connect(node, self.input_height) material_id = data['material'] if material_id: node = instances[material_id] connect(node, self.material) def reset(self): view = self.application.processing_view self.vertex_fbo.textures[0] = self.vertex_texture with nested(view, self.vertex_fbo, self.reset_vertex): quad(self.width, self.height) self.vbo.vertices.copy_from(self.vertex_texture) with nested(view, self.normal_fbo, self.reset_normals): quad(self.application.width, self.application.height) def update(self): view = self.application.processing_view revision = self.revision if self.material.source: self.material.source.update() if self.input_height.source: self.input_height.source.update() if revision != self.updated: self.application.ambient_occlusion.changed = True if self.input_height.source and self.input_height.source.complete: source = self.input_height.source.texture source.unit = GL_TEXTURE0 self.vertex_fbo.textures[0] = self.vertex_texture with nested(view, self.vertex_fbo, source, self.update_vertex_shader): quad(self.width, self.height) self.vbo.vertices.copy_from(self.vertex_texture) with nested(view, self.normal_fbo, source, self.update_normals_shader): quad(self.application.width, self.application.height) else: self.reset() self.application.ambient_occlusion.update() self.updated = revision def get_source(self): if self.input_height.source and self.input_height.source.complete: return self.input_height.source.texture @property def revision(self): if self.input_height.source: height = self.input_height.source.revision else: height = None if self.material.source: material = self.material.source.revision else: material = None return hash((height, material)) def draw(self): glPushMatrix() glTranslatef(-0.5, 0, -0.5) self.normal_texture.unit = GL_TEXTURE0 ambient_occlusion = self.application.ambient_occlusion.result ambient_occlusion.unit = GL_TEXTURE2 if self.material.source and self.material.source.complete: self.material.source.texture.unit = GL_TEXTURE1 with nested(self.normal_texture, self.material.source.texture, ambient_occlusion): self.vbo.draw(GL_TRIANGLES) else: self.default_material.unit = GL_TEXTURE1 with nested(self.normal_texture, self.default_material, ambient_occlusion): self.vbo.draw(GL_TRIANGLES) glPopMatrix()
class Terrain(object): id = 'terrain' def __init__(self, application): self.application = application self.width, self.height = width, height = application.mesh_width, application.mesh_height col = Column() self.input_height = LabelInput('Height', self).append_to(col).input self.material = LabelInput('Material', self).append_to(col).input self.widget = Widget('Terrain', col, id='terrain').append_to(application.workspace) self.default_material = Texture(2, 2, GL_RGBA, data=(140, 140, 140, 255)*4) self.vertex_texture = Texture(width, height, GL_RGBA32F) self.normal_texture = Texture(application.width, application.height, GL_RGBA32F, unit=GL_TEXTURE0) self.vertex_fbo = Framebuffer(self.vertex_texture) self.normal_fbo = Framebuffer(self.normal_texture) self.update_vertex_shader = application.shader('update_vertex.frag') self.update_normals_shader = application.shader('update_normals.frag') self.update_normals_shader.vars.offsets = 1.0/application.width, 1.0/application.height self.reset_vertex = application.shader('reset_vertex.frag') self.reset_normals = application.shader('reset_normals.frag') self.vbo = self.generate_vbo(width, height) self.reset() self.updated = None def export_obj(self, filename): if not filename.endswith('.obj'): filename += '.obj' if self.input_height.source: heightmap = self.input_height.source.texture heightmap.retrieve() width, height = self.application.width, self.application.height with open(filename, 'w') as outfile: heights = map(lambda z: (z, float(z)/height), range(height)) widths = map(lambda x: (x, float(x)/width), range(width)) for iz, z in heights: for ix, x in widths: outfile.write('v %f %f %f\n' % (x, heightmap[ix, iz][0], z)) self.normal_texture.retrieve() for normal in self.normal_texture: outfile.write('vn %f %f %f\n' % tuple(normal[:3])) heights = map(lambda x: float(x)/height, range(height)) widths = map(lambda y: float(y)/width, range(width)) for y in heights: for x in widths: outfile.write('vt %f %f\n' % (x, y)) i_width, i_height = width-1, height-1 for z in range(i_height): for x in range(i_width): p1 = x+z*width p2 = p1+width p4 = p1+1 p3 = p2+1 outfile.write('f %i/%i/%i %i/%i/%i %i/%i/%i\n' % ( p1+1, p1+1, p1+1, p2+1, p2+1, p2+1, p3+1, p3+1, p3+1 )) outfile.write('f %i/%i/%i %i/%i/%i %i/%i/%i\n' % ( p1+1, p1+1, p1+1, p3+1, p3+1, p3+1, p4+1, p4+1, p4+1 )) def export_float_array(self, filename): if not filename.endswith('.png'): filename += '.png' if self.input_height.source: heightmap = self.input_height.source.texture heightmap.retrieve() heightmap.save(filename) #print(heightmap) #source = string_at(heightmap.buffer, sizeof(heightmap.buffer)) #image = Image.frombytes("RGB", (self.width, self.height), source) #image.save(filename) def generate_vbo(self, width, height): #as an acceleration the arrays could be prefilled in C v4f = (c_float*(width*height*4))() width_factor, height_factor = 1.0/float(width), 1.0/float(height) for z in range(height): for x in range(width): offset = (x+z*width)*4 v4f[offset:offset+4] = x*width_factor, 0, z*height_factor, 1 i_width, i_height = width-1, height-1 indices = (c_uint*(i_width*i_height*6))() for z in range(i_height): for x in range(i_width): offset = (x+z*i_width)*6 p1 = x+z*width p2 = p1+width p4 = p1+1 p3 = p2+1 indices[offset:offset+6] = p1, p2, p3, p1, p3, p4 return VertexObject( pbo = True, indices = indices, dynamic_draw_v4f = v4f, ) def open(self, data, instances): offset = data['offset'] self.widget.rect.x, self.widget.rect.y = offset['x'], offset['y'] self.widget.layout() input_id = data['input_height'] if input_id: node = instances[input_id] connect(node, self.input_height) material_id = data['material'] if material_id: node = instances[material_id] connect(node, self.material) def reset(self): view = self.application.processing_view self.vertex_fbo.textures[0] = self.vertex_texture with nested(view, self.vertex_fbo, self.reset_vertex): quad(self.width, self.height) self.vbo.vertices.copy_from(self.vertex_texture) with nested(view, self.normal_fbo, self.reset_normals): quad(self.application.width, self.application.height) def update(self): view = self.application.processing_view revision = self.revision if self.material.source: self.material.source.update() if self.input_height.source: self.input_height.source.update() if revision != self.updated: if self.input_height.source and self.input_height.source.complete: source = self.input_height.source.texture source.unit = GL_TEXTURE0 self.vertex_fbo.textures[0] = self.vertex_texture with nested(view, self.vertex_fbo, source, self.update_vertex_shader): quad(self.width, self.height) self.vbo.vertices.copy_from(self.vertex_texture) with nested(view, self.normal_fbo, source, self.update_normals_shader): quad(self.application.width, self.application.height) else: self.reset() self.updated = revision @property def revision(self): if self.input_height.source: height = self.input_height.source.revision else: height = None if self.material.source: material = self.material.source.revision else: material = None return hash((height, material)) def draw(self): glPushMatrix() glTranslatef(-0.5, 0, -0.5) self.normal_texture.unit = GL_TEXTURE0 if self.material.source and self.material.source.complete: self.material.source.texture.unit = GL_TEXTURE1 with nested(self.normal_texture, self.material.source.texture): self.vbo.draw(GL_TRIANGLES) else: self.default_material.unit = GL_TEXTURE1 with nested(self.normal_texture, self.default_material): self.vbo.draw(GL_TRIANGLES) glPopMatrix()
class Node(object): def __init__(self, label, application): self.application = application self.id = os.urandom(16).encode('hex') application.add_node(self) self.column = Column() bar_area = Area().add_class('widget_bar') Label(label).append_to(bar_area) Button().append_to(bar_area).on_click = self.delete self.texture = application.create_texture() self.widget = Widget(bar_area, self.column).add_class('node').append_to(application.workspace) self._parameters = {} self.sources = {} self.updated = None self.optional = [] @property def revision(self): sources = tuple([input.source.revision if input.source else None for input in self.sources.values()]) parameters = tuple((name, param.value) for name, param in self._parameters.items()) return hash((self.__class__.__name__, parameters, sources)) def get_parameters(self): return dict((name, param.value) for name, param in self._parameters.items()) def set_parameters(self, values): for name, value in values.items(): self._parameters[name].value = value parameters = property(get_parameters, set_parameters) del get_parameters, set_parameters @property def branch_nodes(self): nodes = set([self]) for input in self.sources.values(): if input.source: nodes |= input.source.branch_nodes return nodes def update_sources(self): for input in self.sources.values(): if input.source: input.source.update() @property def complete(self): for name, input in self.sources.items(): if name in self.optional: continue else: if input.source and input.source.complete: continue else: return False return True def update(self): if self.complete: revision = self.revision self.update_sources() if revision != self.updated: self.compute() self.updated = revision def reconnect(self, data, instances): for name, id in data.items(): if id: instance = instances[id] input = self.sources[name] connect(instance, input) def delete(self): self.output.delete() self.texture.delete() for name, slot in self.sources.items(): if slot.content: slot.content.delete() slot.content = None if slot.source: slot.source = None self.widget.remove() self.application.remove_node(self) def apply(self, shader, target, *sources): view = self.application.processing_view for i, source in enumerate(sources): source.unit = GL_TEXTURE0 + i fbo = self.application.framebuffer fbo.textures[0] = target with nested(view, fbo, shader, *sources): quad(target.width, target.height)
class Node(object): def __init__(self, label, application): self.application = application self.id = os.urandom(16).encode('hex') application.add_node(self) self.column = Column() bar_area = Area().add_class('widget_bar') Label(label).append_to(bar_area) Button().append_to(bar_area).on_click = self.delete self.texture = application.create_texture() self.widget = Widget(bar_area, self.column).add_class('node').append_to( application.workspace) self._parameters = {} self.sources = {} self.updated = None self.optional = [] @property def revision(self): sources = tuple([ input.source.revision if input.source else None for input in self.sources.values() ]) parameters = tuple( (name, param.value) for name, param in self._parameters.items()) return hash((self.__class__.__name__, parameters, sources)) def get_parameters(self): return dict( (name, param.value) for name, param in self._parameters.items()) def set_parameters(self, values): for name, value in values.items(): self._parameters[name].value = value parameters = property(get_parameters, set_parameters) del get_parameters, set_parameters @property def branch_nodes(self): nodes = set([self]) for input in self.sources.values(): if input.source: nodes |= input.source.branch_nodes return nodes def update_sources(self): for input in self.sources.values(): if input.source: input.source.update() @property def complete(self): for name, input in self.sources.items(): if name in self.optional: continue else: if input.source and input.source.complete: continue else: return False return True def update(self): if self.complete: revision = self.revision self.update_sources() if revision != self.updated: self.compute() self.updated = revision def reconnect(self, data, instances): for name, id in data.items(): if id: instance = instances[id] input = self.sources[name] connect(instance, input) def delete(self): self.output.delete() self.texture.delete() for name, slot in self.sources.items(): if slot.content: slot.content.delete() slot.content = None if slot.source: slot.source = None self.widget.remove() self.application.remove_node(self) def apply(self, shader, target, *sources): view = self.application.processing_view for i, source in enumerate(sources): source.unit = GL_TEXTURE0 + i fbo = self.application.framebuffer fbo.textures[0] = target with nested(view, fbo, shader, *sources): quad(target.width, target.height)