From 19583522999f9ca2cddb178691633bc20f714b01 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 27 Dec 2007 17:12:27 +0000 Subject: [PATCH] Add $Id$ to tag.* Fix some memory leaks Compiler shader programs in finish() instead of ~Loader() since it may throw Blender exporter: Rewrite the smoothing algorithm to handle certain cases correctly --- mesh_export.py | 272 +++++++++++++++++++++++++++++++++++----- source/objectinstance.h | 3 + source/program.cpp | 10 +- source/program.h | 2 +- source/programdata.cpp | 3 + source/tag.cpp | 7 ++ source/tag.h | 7 ++ 7 files changed, 268 insertions(+), 36 deletions(-) diff --git a/mesh_export.py b/mesh_export.py index dd8e5414..eecd5a69 100644 --- a/mesh_export.py +++ b/mesh_export.py @@ -12,6 +12,10 @@ import math import bpy import Blender +def make_edge_key(i1, i2): + return (min(i1, i2), max(i1, i2)) + + class Edge: def __init__(self, me): if me.__class__==Edge: @@ -25,13 +29,16 @@ class Edge: def __getattr__(self, attr): return getattr(self._medge, attr) + def __cmp__(self, other): + return self is other + def check_smooth(self, limit): if len(self.faces)!=2: return d=Blender.Mathutils.DotVecs(self.faces[0].no, self.faces[1].no) if (d>limit and self.faces[0].smooth and self.faces[1].smooth) or d>0.999: - self.smooth=1 + self.smooth=True def other_face(self, f): if f.index==self.faces[0].index: @@ -53,15 +60,24 @@ class Vertex: self.uv=None self.orig_index=self._mvert.index self.flag=False + self.faces=[] def __getattr__(self, attr): return getattr(self._mvert, attr) + def __cmp__(self, other): + return cmp(self.index, other.index) + + def __str__(self): + return ""%(self.index, self.co[0], self.co[1], self.co[2], self.no[0], self.no[1], self.no[2]) + + __repr__=__str__ + class Face: def __init__(self, mf): self._mface=mf - self.smooth_group=None + #self.smooth_group=None self.edges=[] self.verts=[v for v in mf.verts] self.flag=False @@ -69,6 +85,14 @@ class Face: def __getattr__(self, attr): return getattr(self._mface, attr) + def __cmp__(self, other): + return cmp(self.index, other.index) + + def __str__(self): + return ""%(self.index, " ".join([str(v.index) for v in self.verts])) + + __repr__=__str__ + def get_vertices_from(self, reverse, *vt): verts=self.verts[:] if reverse: @@ -81,10 +105,9 @@ class Face: return verts[i:]+verts[:i] def get_edge(self, v1, v2): - i1=v1.index - i2=v2.index + key=make_edge_key(v1.index, v2.index) for e in self.edges: - if (e.v1.index==i1 or e.v1.index==i2) and (e.v2.index==i1 or e.v2.index==i2): + if e.key==key: return e @@ -162,6 +185,172 @@ class SmoothGroup: e.faces.append(f) +class Mesh: + def __init__(self, m): + self._mesh=m + self.verts=[Vertex(v) for v in m.verts] + self.faces=[Face(f) for f in m.faces] + + for f in self.faces: + for i in range(len(f.verts)): + f.verts[i]=self.verts[f.verts[i].index] + f.verts[i].faces.append(f) + + self.edges=dict([(e.key, Edge(e)) for e in m.edges]) + for f in self.faces: + for k in f.edge_keys: + e=self.edges[k] + e.faces.append(self.faces[f.index]) + f.edges.append(e) + + smooth_limit=math.cos(m.degr*math.pi/180) + for e in self.edges.itervalues(): + e.v1=self.verts[e.v1.index] + e.v2=self.verts[e.v2.index] + e.check_smooth(smooth_limit) + + def __getattr__(self, attr): + return getattr(self._mesh, attr) + + def split_vertices(self, debug=False): + groups=[] + for v in self.verts: + for f in v.faces: + f.flag=False + + vg=[] + for f in v.faces: + if not f.flag: + vg.append(self.find_group(v, f)) + + groups.append(vg) + + for i in range(len(self.verts)): + if len(groups[i])==1: + continue + + if debug: + print "Vertex %s has %d groups"%(self.verts[i], len(groups[i])) + + for g in groups[i][1:]: + v=Vertex(self.verts[i]) + v.index=len(self.verts) + self.verts.append(v) + + if debug: + print " -> %d"%v.index + + for f in g: + for j in range(len(f.edges)): + e=f.edges[j] + + if e.v1!=self.verts[i] and e.v2!=self.verts[i]: + continue + + if debug: + print " Splitting edge %s with faces %s"%(e.key, e.faces) + + old=e + if not e.smooth: + if len(e.faces)>=2: + k=e.faces.index(f) + e.faces.remove(f) + e=Edge(e) + f.edges[j]=e + e.faces.append(f) + else: + del self.edges[e.key] + + if e.v1==self.verts[i]: + e.v1=v + elif e.v2==self.verts[i]: + e.v2=v + + e.key=make_edge_key(e.v1.index, e.v2.index) + if not e.smooth: + self.edges[e.key]=e + + self.verts[i].faces.remove(f) + f.verts[f.verts.index(self.verts[i])]=v + v.faces.append(f) + + def find_group(self, vert, face): + face_indices=[f.index for f in vert.faces] + + face.flag=True + queue=[face] + + for f in queue: + for e in f.edges: + other=e.other_face(f) + if not other or other.index not in face_indices: + continue + + if e.smooth: + if not other.flag: + other.flag=True + queue.append(other) + + return queue + + def compute_normals(self): + for v in self.verts: + if not v.faces: + print "WTF? Vertex %s without faces?"%v + v.no=Blender.Mathutils.Vector() + for f in v.faces: + v.no+=f.no + v.no.normalize() + + def create_strip(self, face, reverse, debug): + edge=None + for e in face.edges: + other=e.other_face(face) + if other and not other.flag: + edge=e + break + + if not edge: + return None + + if debug: + print "Starting strip from %s, edge %s, reverse=%s"%([v.index for v in face.verts], (edge.v1.index, edge.v2.index), reverse) + + verts=face.get_vertices_from(reverse, edge.v1, edge.v2) + if len(verts)==3: + result=[verts[-1], verts[0]] + else: + result=[verts[-2], verts[-1]] + + while 1: + verts=face.get_vertices_from(reverse, *result[-2:]) + k=len(result)%2 + if debug: + print " Adding %s"%face + + face.flag=True + if len(verts)==4 and not k: + result.append(verts[3]) + result.append(verts[2]) + if len(verts)==4 and k: + result.append(verts[3]) + + edge=face.get_edge(*result[-2:]) + + if debug: + print " Next edge is %s"%(edge.key, ) + + next=edge.other_face(face) + if not next or next.flag: + break + face=next + + if debug: + print " %s"%[v.index for v in result] + + return result + + class Exporter: def __init__(self, fn): self.filename=fn @@ -174,8 +363,9 @@ class Exporter: self.optimize_locality=True self.debug=False self.strip_debug=False + self.smooth_debug=False - def find_smooth_group(self, face, sg): + """def find_smooth_group(self, face, sg): face.smooth_group=sg sg.faces.append(face) queue=[face] @@ -187,13 +377,13 @@ class Exporter: if other and not other.smooth_group: other.smooth_group=sg sg.faces.append(other) - queue.append(other) + queue.append(other)""" - def create_strip(self, face, reverse): + """def create_strip(self, face, reverse): edge=None for e in face.edges: other=e.other_face(face) - if other and other.smooth_group.index==face.smooth_group.index and not other.flag: + if other and "other.smooth_group.index==face.smooth_group.index" and not other.flag: edge=e break @@ -201,7 +391,7 @@ class Exporter: return None if self.strip_debug: - print "Starting strip from %s, edge %s, reverse=%s"%([v.index for v in face.verts], (edge.v1.index, edge.v2.index), reverse) + print "Starting strip from %s, edge %s, reverse=%s"%([v.index for v in face.verts], edge.key, reverse) verts=face.get_vertices_from(reverse, edge.v1, edge.v2) if len(verts)==3: @@ -228,14 +418,14 @@ class Exporter: print " Next edge is %s"%((edge.v1.index, edge.v2.index), ) next=edge.other_face(face) - if not next or next.smooth_group.index!=face.smooth_group.index or next.flag: + if not next or next.flag: break face=next if self.strip_debug: print " %s"%[v.index for v in result] - return result + return result""" def get_locality(self, strip): total=0 @@ -265,9 +455,23 @@ class Exporter: if obj.getType()!="Mesh": raise Exception, "Can only export Mesh data" - mesh=obj.getData(mesh=True) + mesh=Mesh(obj.getData(mesh=True)) + + if self.debug: + ntris=sum([len(f.verts)-2 for f in mesh.faces]) + print "Starting with %d vertices, %d faces (%d triangles) and %d edges"%(len(mesh.verts), len(mesh.faces), ntris, len(mesh.edges)) + + mesh.split_vertices(self.smooth_debug) + + if self.debug: + ntris=sum([len(f.verts)-2 for f in mesh.faces]) + print "After splitting %d vertices, %d faces (%d triangles) and %d edges"%(len(mesh.verts), len(mesh.faces), ntris, len(mesh.edges)) + + mesh.compute_normals() + + #return - faces=[Face(f) for f in mesh.faces] + """faces=[Face(f) for f in mesh.faces] edges=dict([(e.key, Edge(e)) for e in mesh.edges]) for f in faces: @@ -307,27 +511,32 @@ class Exporter: for i in range(len(smooth_groups)): sg=smooth_groups[i] print " %d: %d faces, %d vertices"%(i, len(sg.faces), len(sg.verts)) - print "%d vertices total"%len(verts) + print "%d vertices total"%len(verts)""" strips=[] if self.use_strips: + for f in mesh.faces: + f.flag=False + while 1: best=5 face=None - for f in faces: + for f in mesh.faces: if f.flag: continue score=0 for e in f.edges: other=e.other_face(f) - if other and other.smooth_group.index==f.smooth_group.index and not other.flag: + if other and not other.flag: score+=1 if score>0 and scorebest and not verts[n].flag: - next=verts[n] + if flw[n]>best and not mesh.verts[n].flag: + next=mesh.verts[n] best=flw[n]+0.9/abs(vert.index-n) if not next: - for v in verts: + for v in mesh.verts: if not v.flag: next=v break @@ -397,10 +606,10 @@ class Exporter: vert=next - verts=verts2 + mesh.verts=verts2 - for i in range(len(verts)): - verts[i].index=i + for i in range(len(mesh.verts)): + mesh.verts[i].index=i if self.debug: print "Locality after optimization: "+" ".join(["%.3f"%self.get_locality(s) for s in strips]) @@ -411,7 +620,7 @@ class Exporter: self.out_file.write("_VERTEX3\n{\n") norm=None uv=None - for v in verts: + for v in mesh.verts: if v.no!=norm: self.out_file.write("\tnormal3 %f %f %f;\n"%tuple(v.no)) norm=v.no @@ -431,7 +640,7 @@ class Exporter: self.out_file.write(";\n};\n") first=True - for f in faces: + for f in mesh.faces: if not f.flag: if first: self.out_file.write("batch TRIANGLES\n{\n") @@ -449,13 +658,15 @@ class FrontEnd: self.optimize_locality=Blender.Draw.Create(True) self.debug=Blender.Draw.Create(False) self.strip_debug=Blender.Draw.Create(False) + self.smooth_debug=Blender.Draw.Create(False) ret=Blender.Draw.PupBlock("Export MSP GL mesh", [("Use strips", self.use_strips, "Generage OpenGL triangle strips"), ("Use degen tris", self.use_degen_tris, "Use degenerate triangles to combine triangle strips"), ("Optimize locality", self.optimize_locality), ("Debugging options"), ("Debug", self.debug), - ("Debug strips", self.strip_debug)]) + ("Debug strips", self.strip_debug), + ("Debug smoothing", self.smooth_debug)]) if ret: Blender.Window.FileSelector(self.export, "Export MSP GL mesh", Blender.sys.makename(ext='.mesh')) @@ -469,6 +680,7 @@ class FrontEnd: exp.optimize_locality=self.optimize_locality.val exp.debug=self.debug.val exp.strip_debug=self.strip_debug.val + exp.smooth_debug=self.smooth_debug.val exp.export() diff --git a/source/objectinstance.h b/source/objectinstance.h index 12e0d7fb..00e98791 100644 --- a/source/objectinstance.h +++ b/source/objectinstance.h @@ -23,6 +23,9 @@ class ObjectPass; Represents a single instance of an Object. An application can derive another class from this and overload the hook functions to specify location and other instance-specific parameters for the rendered objects. + +The finish_render function generally should clean up everything done by +setup_render, unless the rendering sequence is known to allow otherwise. */ class ObjectInstance: public Renderable { diff --git a/source/program.cpp b/source/program.cpp index f057ea74..2ed6fba8 100644 --- a/source/program.cpp +++ b/source/program.cpp @@ -182,11 +182,6 @@ Program::Loader::Loader(Program &p): add("attribute", &Loader::attribute); } -Program::Loader::~Loader() -{ - prog.link(); -} - void Program::Loader::vertex_shader(const string &src) { prog.attach_shader(*new Shader(VERTEX_SHADER, src)); @@ -202,5 +197,10 @@ void Program::Loader::attribute(uint i, const string &n) prog.bind_attribute(i, n); } +void Program::Loader::finish() +{ + prog.link(); +} + } // namespace GL } // namespace Msp diff --git a/source/program.h b/source/program.h index ed541007..3b86a9c6 100644 --- a/source/program.h +++ b/source/program.h @@ -37,12 +37,12 @@ public: public: Loader(Program &); - ~Loader(); private: void vertex_shader(const std::string &); void fragment_shader(const std::string &); void attribute(uint, const std::string &); + virtual void finish(); }; Program(); diff --git a/source/programdata.cpp b/source/programdata.cpp index af2679a5..f627f2f1 100644 --- a/source/programdata.cpp +++ b/source/programdata.cpp @@ -29,7 +29,10 @@ ProgramData::~ProgramData() void ProgramData::uniform(int index, Uniform *uni) { if(index<0) + { + delete uni; return; + } map::iterator i=data.find(index); if(i!=data.end()) diff --git a/source/tag.cpp b/source/tag.cpp index c8041e0d..8e29bee1 100644 --- a/source/tag.cpp +++ b/source/tag.cpp @@ -1,3 +1,10 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + #include "tag.h" namespace Msp { diff --git a/source/tag.h b/source/tag.h index 87d4af65..b2d4fd51 100644 --- a/source/tag.h +++ b/source/tag.h @@ -1,3 +1,10 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + #ifndef MSP_GL_TAG_H_ #define MSP_GL_TAG_H_ -- 2.45.2