🚧 Project Status: In Development
This project is not feature-complete and is still being actively developed.
Expect unstable functionality, incomplete features, and frequent changes.
This Python module provides a wrapper around the shape data structure, offering operations for modifying existing MSTS/ORTS shape files.
Depending on how you use the module, you may end up with unusual-looking shapes, but the implemented operations will keep the shape itself error-free and usable in MSTS and Open Rails.
At this stage, only a limited set of operations is implemented, such as adding vertices, connecting them with triangles, and removing triangles. If you need additional functionality, feel free to request it by creating an issue or submitting a pull request.
List of companion modules:
- shapeio - offers functions to convert shapes between structured text format and Python objects.
- trackshape-utils - offers additional utilities for working with track shapes.
- pytkutils - handles compression and decompression of shape files through the
TK.MSTS.Tokens.dlllibrary by Okrasa Ghia.
git clone https://github.com/pgroenbaek/shapeedit.git
pip install --upgrade ./shapeeditThese examples are preliminary, not fully implemented and might change.
import shapeio
from shapeedit import ShapeEditor
my_shape = shapeio.load("./path/to/example.s")
shape_editor = ShapeEditor(my_shape)
sub_object = shape_editor.lod_control(0).distance_level(200).sub_object(0)
# Set point values of all vertices within the subobject.
for vertex in sub_object.vertices():
vertex.point.x = 0.0
vertex.point.y = 1.0
vertex.point.z = 2.0
shapeio.dump(my_shape, "./path/to/output.s")import shapeio
from shapeio.shape import Point, UVPoint, Vector
from shapeedit import ShapeEditor
my_shape = shapeio.load("./path/to/example.s")
shape_editor = ShapeEditor(my_shape)
# Add three new vertices to primitives associated with prim_state_index 22.
# Connect the three vertices added to each primitive with a triangle.
for lod_control in shape_editor.lod_controls():
for distance_level in lod_control.distance_levels():
for sub_object in distance_level.sub_objects():
for primitive in sub_object.primitives(prim_state_idx=22):
new_point1 = Point(0.0, 0.0, 0.0)
new_point2 = Point(1.0, 0.0, 0.0)
new_point3 = Point(2.0, 0.0, 1.0)
new_uv_point = UVPoint(0.0, 0.0)
new_normal = Vector(0.0, 0.0, 0.0)
new_vertex1 = primitive.add_vertex(new_point1, new_uv_point, new_normal)
new_vertex2 = primitive.add_vertex(new_point2, new_uv_point, new_normal)
new_vertex3 = primitive.add_vertex(new_point3, new_uv_point, new_normal)
primitive.insert_triangle(new_vertex1, new_vertex2, new_vertex3)
shapeio.dump(my_shape, "./path/to/output.s")import shapeio
from shapeio.shape import Point, UVPoint, Vector
from shapeedit import ShapeEditor
my_shape = shapeio.load("./path/to/example.s")
shape_editor = ShapeEditor(my_shape)
# Remove all triangles from primitives associated with any prim_state named "Rails".
for lod_control in shape_editor.lod_controls():
for distance_level in lod_control.distance_levels():
for sub_object in distance_level.sub_objects():
for primitive in sub_object.primitives(prim_state_name="Rails"):
for vertex in primitive.vertices():
primitive.remove_triangles_connected_to(vertex)
shapeio.dump(my_shape, "./path/to/output.s")You can run tests manually or use tox to test across multiple Python versions.
First, install the required dependencies:
pip install pytestThen, run tests with:
pytesttox allows you to test across multiple Python environments.
pip install toxtoxThis will execute tests in all specified Python versions.
The tox.ini file should be in your project root:
[tox]
envlist = py36, py37, py38, py39, py310
[testenv]
deps = pytest
commands = pytestModify envlist to match the Python versions you want to support.
Possible future features to be added:
- Ability to add new textures and primitives
- Ability to remove vertices from primitives
- Ability to edit things like light configurations, animations, etc.
- And possibly more..
Please make an issue if you have any good ideas, or if you need something that has not yet been implemented.
This Python module was created by Peter Grønbæk Andersen and is licensed under GNU GPL v3.