From a6634a415fd38b1bc86f8a9d55d4019aabc01afa Mon Sep 17 00:00:00 2001 From: Ludovic Pouzenc Date: Mon, 31 Dec 2018 18:36:31 +0100 Subject: First draft --- drafts/notes-blender.py | 26 ++++++++ drafts/print_mapfile_to_console.py | 131 +++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100755 drafts/notes-blender.py create mode 100755 drafts/print_mapfile_to_console.py 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() -- cgit v1.2.3