summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Pouzenc <ludovic@pouzenc.fr>2018-12-31 18:36:31 +0100
committerLudovic Pouzenc <ludovic@pouzenc.fr>2018-12-31 18:40:18 +0100
commita6634a415fd38b1bc86f8a9d55d4019aabc01afa (patch)
tree25e18d83d020b1bd741442cb90b2042ce12e41a8
downloadblender-export-hl1map-a6634a415fd38b1bc86f8a9d55d4019aabc01afa.tar.gz
blender-export-hl1map-a6634a415fd38b1bc86f8a9d55d4019aabc01afa.tar.bz2
blender-export-hl1map-a6634a415fd38b1bc86f8a9d55d4019aabc01afa.zip
First draft
-rwxr-xr-xdrafts/notes-blender.py26
-rwxr-xr-xdrafts/print_mapfile_to_console.py131
2 files changed, 157 insertions, 0 deletions
diff --git a/drafts/notes-blender.py b/drafts/notes-blender.py
new file mode 100755
index 0000000..4df76cf
--- /dev/null
+++ b/drafts/notes-blender.py
@@ -0,0 +1,26 @@
+import bpy
+
+bpy.ops.object.select_all(action='DESELECT')
+bpy.ops.object.select_by_type(type='MESH')
+bpy.ops.object.editmode_toggle()
+bpy.ops.mesh.remove_doubles()
+bpy.ops.mesh.vert_connect_nonplanar()
+bpy.ops.mesh.vert_connect_concave()
+bpy.ops.object.editmode_toggle()
+# https://github.com/kmammou/v-hacd
+
+
+print_entity_start(worldspawn_props)
+o = bpy.data.scenes['Scene'].objects['Suzanne']
+# o.location = 1, 2, 3
+# bpy.context.scene.update()
+mw = o.matrix_world
+me = o.data
+me.update(calc_tessface=True)
+
+#print("Mesh: %s, tessfaces: %d, vertices: %d"%(o.name,len(me.tessfaces),len(me.vertices)))
+print_brush_start()
+for fa in me.tessfaces:
+ print(" Face %d"%fa.index)
+ print(" Normal\t(local): ", fa.normal)
+
diff --git a/drafts/print_mapfile_to_console.py b/drafts/print_mapfile_to_console.py
new file mode 100755
index 0000000..2f5d179
--- /dev/null
+++ b/drafts/print_mapfile_to_console.py
@@ -0,0 +1,131 @@
+import bpy
+from mathutils import Vector
+
+def fmt3(vec3):
+ return "%.10f %.10f %.10f"%(vec3.x, vec3.y, vec3.z)
+def fmt_plane(plane3dots):
+ return "( %s ) ( %s ) ( %s )"%(fmt3(plane3dots[0]), fmt3(plane3dots[1]), fmt3(plane3dots[2]))
+def fmt_tex(tev, toff):
+ return "[ %s %.1f ]"%(fmt3(tev), toff)
+def fmt_face(plane3dots, tename, tev1, teoff1, tev2, teoff2, rot, scaleX, scaleY):
+ return "%s %s %s %s %s"%(
+ fmt_plane(plane3dots), tename,
+ fmt_tex(tev1, teoff1),
+ fmt_tex(tev2, teoff2),
+ fmt3(Vector([rot, scaleX, scaleY]))
+ )
+
+def output_entity_start(dict_props):
+ print("{")
+ for k,v in dict_props.items():
+ print("\t\"%s\" \"%s\""%(k,v))
+
+def output_brush_start():
+ print("\t{")
+
+def output_brush_face(plane3dots, tename, tev1, teoff1, tev2, teoff2, rot, scaleX, scaleY):
+ print("\t%s"%fmt_face(plane3dots, tename, tev1, teoff1, tev2, teoff2, rot, scaleX, scaleY))
+
+def output_brush_end():
+ print("\t}")
+
+def output_entity_end():
+ print("}")
+
+def normal(plane3dots):
+ v01 = plane3dots[1] - plane3dots[0]
+ v02 = plane3dots[2] - plane3dots[0]
+ n = v01.cross(v02)
+ n.normalize()
+ return n
+
+def flip(plane3dots):
+ tmp = plane3dots[2]
+ plane3dots[2] = plane3dots[1]
+ plane3dots[1] = tmp
+
+def debug(fano,plane3dots):
+ fano.normalize()
+ print(fano)
+ v01 = plane3dots[1] - plane3dots[0]
+ v02 = plane3dots[2] - plane3dots[0]
+ n = v01.cross(v02)
+ n.normalize()
+ print(n)
+ print(fano-n)
+ print()
+
+worldspawn_props = {
+ 'classname': 'worldspawn',
+ 'sounds': 1,
+ 'MaxRange': 4096,
+ 'mapversion': 220,
+ 'wad': '\\half-life\\valve\\xeno.wad;\\half-life\\valve\\decals.wad;\\half-life\\valve\\halflife.wad;\\half-life\\valve\\liquids.wad'
+}
+
+blender_to_map_scale_factor = 100
+
+# https://developer.valvesoftware.com/wiki/MAP_file_format
+output_entity_start(worldspawn_props)
+
+for o in bpy.data.scenes[0].objects:
+ if o.type != 'MESH':
+ continue
+ mat_to_map = o.matrix_world * blender_to_map_scale_factor
+ mesh = o.data
+ mesh.update(calc_tessface=True)
+ for fa in mesh.tessfaces:
+ output_brush_start()
+ tename="AAATRIGGER"
+ tev1 = Vector([1,0,0])
+ teoff1 = 0
+ tev2 = Vector([0,-1,0])
+ teoff2 = 0
+ rot = 0
+ scaleX = 1
+ scaleY = 1
+ # Make a brush in .map for each face in blender
+ # Brushes are (strangely) defined as a set of intersecting planes in .map
+ # Planes are defined with 3 3D points belonging to it
+ # "They must be in a clockwise order when facing the outside of the plane
+ # that is, the side that points outwards from the brush"
+ brfront = [None,None,None]
+ brback = [None,None,None]
+ # For now this code take the 3 first vectices of the face
+ # TODO This can cause troubles if they are colinear or with have narrow angle
+ for i in [0,1,2]:
+ vi = mesh.vertices[fa.vertices[i]].co
+ # front plane in brush will match face in blender (in global coords, with a scale factor)
+ brfront[i] = mat_to_map * vi
+ # back plane will be 1 (map) unit inside (normal facing outside, so substract it)
+ brback[2-i] = mat_to_map * ( vi - fa.normal / blender_to_map_scale_factor )
+ # Check if coords are in clockwise order, else flip them
+ fano = mat_to_map.to_3x3() * fa.normal
+ frno = normal(brfront)
+ epsilon = 0.1
+ if ( (fano - frno).length_squared > epsilon ):
+ flip(brfront)
+ flip(brback)
+ #print("Front&Back Flipped")
+ #debug(mat_to_map.to_3x3() * fa.normal, front)
+ output_brush_face(brfront, tename, tev1, teoff1, tev2, teoff2, rot, scaleX, scaleY)
+ #debug(mat_to_map.to_3x3() *-fa.normal, back)
+ output_brush_face(brback, tename, tev1, teoff1, tev2, teoff2, rot, scaleX, scaleY)
+ # make 1 side face in brush per blender edge
+ for i,j in fa.edge_keys:
+ brside = [None,None,None]
+ brside[0] = mat_to_map * ( mesh.vertices[i].co )
+ brside[1] = mat_to_map * ( mesh.vertices[j].co )
+ brside[2] = mat_to_map * ( mesh.vertices[j].co - fa.normal )
+ # Let have a plane define by a point A and a normal n
+ # Let M a point in space. M is on the plane if AM.n = 0
+ # Now we want to know if the "side" face normal is poiting outwards of the brush (<0)
+ # Take A = side[0], M = fa.center (that is inside the brush), n = normal(side)
+ if ( (mat_to_map * fa.center - brside[0]).dot(normal(brside)) < 0):
+ flip(brside)
+ #print("Side Flipped")
+ #print(normal(side))
+ output_brush_face(brside, tename, tev1, teoff1, tev2, teoff2, rot, scaleX, scaleY)
+ output_brush_end()
+
+output_entity_end()