Skip to content

Instantly share code, notes, and snippets.

@david-wm-sanders
Last active October 17, 2022 04:24
Show Gist options
  • Save david-wm-sanders/3e054fb0b32f18e99db25e71d6f5aefe to your computer and use it in GitHub Desktop.
Save david-wm-sanders/3e054fb0b32f18e99db25e71d6f5aefe to your computer and use it in GitHub Desktop.
Load a RWR voxel model into Blender
from dataclasses import dataclass
from pathlib import Path
import xml.etree.ElementTree as XmlET
import bpy
STEAMLIB_DIR = """C:\Program Files (x86)\Steam"""
PACKAGE_NAME = "vanilla"
RWR_INSTALL_PATH = Path(STEAMLIB_DIR) / "steamapps/common/RunningWithRifles"
PACKAGE_PATH = RWR_INSTALL_PATH / f"media/packages/{PACKAGE_NAME}"
PACKAGE_MODELS_PATH = PACKAGE_PATH / "models"
MODEL_NAME = "soldier_a1.xml"
SCALING_FACTOR = 0.2
@dataclass
class Voxel:
x: int
y: int
z: int
r: float
g: float
b: float
@dataclass
class Model:
name: str
voxels: list[Voxel]
@classmethod
def load(cls, model_path: Path) -> "Model":
with model_path.open(mode="r", encoding="utf-8") as model_file:
model_xml = XmlET.fromstring(model_file.read())
voxels = []
for voxel_elem in model_xml.findall("./voxels/voxel"):
x = int(voxel_elem.attrib["x"])
# swap y and z here (in OGRE, y is height)
y, z = int(voxel_elem.attrib["z"]), int(voxel_elem.attrib["y"])
r, g, b = float(voxel_elem.attrib["r"]), float(voxel_elem.attrib["g"]), float(voxel_elem.attrib["b"])
voxels.append(Voxel(x, y, z, r, g, b))
return cls(model_path.stem, voxels)
def draw(self):
voxel_mat = bpy.data.materials.get("VoxelMaterial")
# create a singular primitive cube to use as a template
bpy.ops.mesh.primitive_cube_add(size=SCALING_FACTOR)
# set a reference to this template voxel
template_voxel = bpy.context.object
# create a collection
voxels_collection = bpy.data.collections.new(self.name)
bpy.context.scene.collection.children.link(voxels_collection)
# draw the voxels - it is much faster to copy and adjust this template voxel than
# use `bpy.ops.mesh.primitive_cube_add(size=1)` for each and every voxel
collection_linkable = set()
for voxel in self.voxels:
# copy the template, set location, etc
copy = template_voxel.copy()
copy.data = template_voxel.data.copy()
copy.location = (float(voxel.x) * SCALING_FACTOR,
float(voxel.y) * SCALING_FACTOR,
float(voxel.z) * SCALING_FACTOR)
copy.color = (voxel.r, voxel.g, voxel.b, 1.)
copy.active_material = voxel_mat
collection_linkable.add(copy)
# link the voxels to the voxels collection
for obj in collection_linkable:
voxels_collection.objects.link(obj)
# destroy the template voxel
# bpy.ops.object.delete({"selected_objects": [template_voxel]})
with bpy.context.temp_override(selected_objects=[template_voxel]):
bpy.ops.object.delete()
if __name__ == '__main__':
print("RwR Voxel Model Renderer!")
print("Current parameters:")
print(f"{RWR_INSTALL_PATH=}")
print(f"{PACKAGE_PATH=}")
print(f"{PACKAGE_MODELS_PATH=}")
print(f"{MODEL_NAME=}")
model_path = PACKAGE_MODELS_PATH / MODEL_NAME
if not model_path.exists():
raise Exception(f"Model not found at '{model_path}'")
print(f"Loading '{model_path}'...")
voxel_model = Model.load(model_path)
print(f"Model '{MODEL_NAME}' contains {len(voxel_model.voxels)} voxels")
print(f"Drawing model...")
voxel_model.draw()
print(f"{voxel_model.voxels[0]=}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment