init
This commit is contained in:
80
tools/blender_mapping.py
Normal file
80
tools/blender_mapping.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import bpy
|
||||
import os
|
||||
|
||||
bl_info = {
|
||||
"name": "Funnymap export",
|
||||
"author": "kotofyt",
|
||||
"version": (1, 0),
|
||||
"blender": (4, 3, 0),
|
||||
"location": "File > Export > Funnymap (.map)",
|
||||
"description": "Export meshes as funnymaps",
|
||||
"category": "Import-Export",
|
||||
}
|
||||
|
||||
|
||||
import bpy
|
||||
import os
|
||||
from bpy_extras.io_utils import ExportHelper
|
||||
from bpy.types import Operator
|
||||
from bpy.props import StringProperty
|
||||
|
||||
class ExportFunnymap(Operator, ExportHelper):
|
||||
"""Export to Funnymap"""
|
||||
bl_idname = "export_scene.fmap"
|
||||
bl_label = "Export Funnymap"
|
||||
filename_ext = ".map"
|
||||
|
||||
filter_glob: StringProperty(
|
||||
default="*.map",
|
||||
options={'HIDDEN'},
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
return export_my_format(self.filepath)
|
||||
|
||||
def export_my_format(filepath):
|
||||
with open(filepath, 'w') as f:
|
||||
f.write("{\n")
|
||||
f.write("\"classname\" \"worldspawn\"\n")
|
||||
f.write("{\n")
|
||||
|
||||
for obj in bpy.context.scene.objects:
|
||||
if obj.type == 'MESH':
|
||||
mesh = obj.to_mesh()
|
||||
mesh.calc_loop_triangles()
|
||||
uv_layer = mesh.uv_layers.active.data if mesh.uv_layers.active else None
|
||||
for tri in mesh.loop_triangles:
|
||||
for loop_index in tri.loops:
|
||||
vert = mesh.vertices[mesh.loops[loop_index].vertex_index]
|
||||
world_pos = obj.matrix_world @ vert.co
|
||||
f.write(f"({world_pos.x:.6f} {world_pos.y:.6f} {world_pos.z:.6f}) ")
|
||||
for loop_index in tri.loops:
|
||||
if uv_layer:
|
||||
uv = uv_layer[loop_index].uv
|
||||
f.write(f"({uv.x:.6f} {uv.y:.6f}) ")
|
||||
f.write(f"BRICK0\n");
|
||||
f.write("}\n")
|
||||
f.write("}\n")
|
||||
for obj in bpy.context.scene.objects:
|
||||
if obj.type == 'LIGHT':
|
||||
light = obj.data
|
||||
f.write("{\n")
|
||||
f.write("\"classname\" \"light\"\n")
|
||||
f.write(f"\"intensity\" \"{light.energy/128}\"\n")
|
||||
f.write("}\n")
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(ExportFunnymap.bl_idname, text="Funnymap (.map)")
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(ExportFunnymap)
|
||||
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_class(ExportFunnymap)
|
||||
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
53
tools/makepak64.py
Normal file
53
tools/makepak64.py
Normal file
@@ -0,0 +1,53 @@
|
||||
#
|
||||
# Copyright (C) 2013 The Tome of Preach
|
||||
# Copyright (C) 2025 kotofyt
|
||||
#
|
||||
# This script implement generator of 64 bit version of pak.
|
||||
# Basically all size 32 bit offsets and sizes replaced with 64 bit values
|
||||
#
|
||||
# Original source code is available at https://tomeofpreach.wordpress.com/2013/06/22/makepak-py/
|
||||
#
|
||||
|
||||
import sys
|
||||
import struct
|
||||
import os
|
||||
|
||||
#dummy class for stuffing the file headers into
|
||||
class FileEntry:
|
||||
pass
|
||||
|
||||
#arguments are source directory, then target filename e.g. "pak1.pak"
|
||||
rootdir = sys.argv[1]
|
||||
pakfilename = sys.argv[2]
|
||||
|
||||
pakfile = open(pakfilename,"wb")
|
||||
|
||||
#write a dummy header to start with
|
||||
pakfile.write(struct.Struct("<8s2q").pack(b"rttpacku",0,0))
|
||||
|
||||
#walk the directory recursively, add the files and record the file entries
|
||||
offset = 24
|
||||
fileentries = []
|
||||
for root, subFolders, files in os.walk(rootdir):
|
||||
for file in files:
|
||||
entry = FileEntry()
|
||||
impfilename = os.path.join(root,file)
|
||||
entry.filename = os.path.relpath(impfilename,rootdir).replace("\\","/")
|
||||
with open(impfilename, "rb") as importfile:
|
||||
pakfile.write(importfile.read())
|
||||
entry.offset = offset
|
||||
entry.length = importfile.tell()
|
||||
offset = offset + entry.length
|
||||
fileentries.append(entry)
|
||||
tablesize = 0
|
||||
|
||||
#after all the file data, write the list of entries
|
||||
for entry in fileentries:
|
||||
pakfile.write(struct.Struct("<56s").pack(entry.filename.encode("ascii")))
|
||||
pakfile.write(struct.Struct("<q").pack(entry.offset))
|
||||
pakfile.write(struct.Struct("<q").pack(entry.length))
|
||||
tablesize = tablesize + 72
|
||||
|
||||
#return to the header and write the values correctly
|
||||
pakfile.seek(0)
|
||||
pakfile.write(struct.Struct("<8s2q").pack(b"rttpacku",offset,tablesize))
|
||||
112
tools/mapcc.py
Normal file
112
tools/mapcc.py
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
import sys
|
||||
import struct
|
||||
import os
|
||||
import re
|
||||
|
||||
def parse_map(file_path):
|
||||
with open(file_path, 'r') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
entities = []
|
||||
stack = []
|
||||
current_entity = None
|
||||
current_brush = None
|
||||
face_pattern = re.compile(r"""
|
||||
(?:\(\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*\)\s*)
|
||||
(?:\(\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*\)\s*)
|
||||
(?:\(\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*\)\s*)
|
||||
(?:\(\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*\)\s*)
|
||||
(?:\(\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*\)\s*)
|
||||
(?:\(\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*\)\s*)
|
||||
(\S+)
|
||||
""", re.VERBOSE)
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('//'):
|
||||
continue
|
||||
|
||||
if line == '{':
|
||||
stack.append('{')
|
||||
if current_entity is None:
|
||||
current_entity = {'classname': None, 'keyvalues': {}, 'brushes': []}
|
||||
elif current_brush is None:
|
||||
current_brush = []
|
||||
continue
|
||||
|
||||
if line == '}':
|
||||
if current_brush is not None:
|
||||
current_entity['brushes'] = current_brush
|
||||
current_brush = None
|
||||
else:
|
||||
entities.append(current_entity)
|
||||
current_entity = None
|
||||
stack.pop()
|
||||
continue
|
||||
|
||||
if current_brush is not None:
|
||||
m = face_pattern.match(line)
|
||||
if m:
|
||||
points = [
|
||||
(float(m.group(1)), float(m.group(2)), float(m.group(3))),
|
||||
(float(m.group(4)), float(m.group(5)), float(m.group(6))),
|
||||
(float(m.group(7)), float(m.group(8)), float(m.group(9))),
|
||||
]
|
||||
uvs = [
|
||||
(float(m.group(10)), float(m.group(11))),
|
||||
(float(m.group(12)), float(m.group(13))),
|
||||
(float(m.group(14)), float(m.group(15))),
|
||||
]
|
||||
texture = m.group(16)
|
||||
|
||||
face = {
|
||||
'points': points,
|
||||
'uvs': uvs,
|
||||
'texture': texture,
|
||||
}
|
||||
current_brush.append(face)
|
||||
else:
|
||||
print(f"Warning: Could not parse face line: {line}")
|
||||
continue
|
||||
|
||||
if current_entity is not None:
|
||||
if line.startswith('"'):
|
||||
parts = re.findall(r'"([^"]*)"', line)
|
||||
if len(parts) == 2:
|
||||
key, value = parts
|
||||
if key == "classname":
|
||||
current_entity['classname'] = value
|
||||
else:
|
||||
current_entity['keyvalues'][key] = value
|
||||
else:
|
||||
print(f"Warning: Unexpected line in entity: {line}")
|
||||
|
||||
return entities
|
||||
|
||||
|
||||
if (len(sys.argv)==1):
|
||||
print("mapcc.py is a rtt's .map to .fmap converter");
|
||||
print("key changes:");
|
||||
print("- uses triangles instead of brushes");
|
||||
print("- uses uv coordinates instead of brushes");
|
||||
print("use better map editor instead of this");
|
||||
exit(0)
|
||||
entities = parse_map(sys.argv[1])
|
||||
pakfilename = sys.argv[2]
|
||||
pakfile = open(pakfilename,"wb")
|
||||
pakfile.write(struct.Struct("<8sI").pack(b"rttfmapc",len(entities)))
|
||||
for i, e in enumerate(entities):
|
||||
pakfile.write(struct.Struct(f"<{len(e['classname'])+1}s").pack(str(e['classname']).encode("ascii")))
|
||||
pakfile.write(struct.Struct("<I").pack(len(e['brushes'])))
|
||||
pakfile.write(struct.Struct("<I").pack(len(e['keyvalues'])))
|
||||
for k, v in e['keyvalues'].items():
|
||||
pakfile.write(struct.Struct(f"<{len(k)+1}s").pack(k.encode("ascii")))
|
||||
pakfile.write(struct.Struct(f"<{len(v)+1}s").pack(v.encode("ascii")))
|
||||
for k, face in enumerate(e['brushes']):
|
||||
# the fuck
|
||||
for i in range(9):
|
||||
pakfile.write(struct.Struct(f"<f").pack(float(face['points'][int(i/3)][i%3])))
|
||||
for i in range(6):
|
||||
pakfile.write(struct.Struct(f"<f").pack(float(face['uvs'][int(i//2)][i%2])))
|
||||
pakfile.write(struct.Struct(f"<{len(face['texture'])+1}s").pack(face['texture'].encode("ascii")))
|
||||
Reference in New Issue
Block a user