Skip to content

Commit

Permalink
H1 Scenario export work
Browse files Browse the repository at this point in the history
  • Loading branch information
General-101 committed Dec 24, 2024
1 parent 0f10310 commit b9c75d7
Show file tree
Hide file tree
Showing 19 changed files with 4,331 additions and 933 deletions.
7 changes: 2 additions & 5 deletions io_scene_halo/file_tag/build_scene/build_bsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,7 @@ def build_scene(context, LEVEL, game_version, game_title, file_version, fix_rota
cluster_name = "cluster_%s" % lightmap_idx
full_mesh = bpy.data.meshes.new(cluster_name)
object_mesh = bpy.data.objects.new(cluster_name, full_mesh)
object_mesh.tag_view.data_type_enum = '1'
object_mesh.tag_view.lightmap_index = lightmap.bitmap_index
object_mesh.tag_mesh.lightmap_index = lightmap.bitmap_index

object_mesh.parent = level_root
cluster_collection_override.objects.link(object_mesh)
Expand Down Expand Up @@ -560,7 +559,6 @@ def build_scene(context, LEVEL, game_version, game_title, file_version, fix_rota
cluster_name = "cluster_%s" % cluster_idx
mesh = bpy.data.meshes.new(cluster_name)
object_mesh = bpy.data.objects.new(cluster_name, mesh)
object_mesh.tag_view.data_type_enum = '1'

object_mesh.parent = level_root
mesh_processing.get_mesh_data(LEVEL, cluster.cluster_data, mesh, material_count, materials, random_color_gen, PartFlags)
Expand Down Expand Up @@ -593,8 +591,7 @@ def build_scene(context, LEVEL, game_version, game_title, file_version, fix_rota
ob_name = instanced_geometry_instance.name

object_mesh = bpy.data.objects.new(ob_name, mesh)
object_mesh.tag_view.data_type_enum = '16'
object_mesh.tag_view.instance_lightmap_policy_enum = str(instanced_geometry_instance.lightmapping_policy)
object_mesh.tag_mesh.instance_lightmap_policy_enum = str(instanced_geometry_instance.lightmapping_policy)

object_mesh.parent = level_root
instance_collection.objects.link(object_mesh)
Expand Down
3 changes: 1 addition & 2 deletions io_scene_halo/file_tag/build_scene/build_lightmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,7 @@ def build_poops(lightmap_group, SBSP_ASSET, level_root, random_color_gen, collec
object_mesh.parent = level_root
instance_collection.objects.link(object_mesh)

object_mesh.tag_view.data_type_enum = '16'
object_mesh.tag_view.instance_lightmap_policy_enum = str(instanced_geometry_instance.lightmapping_policy)
object_mesh.tag_mesh.instance_lightmap_policy_enum = str(instanced_geometry_instance.lightmapping_policy)

matrix_scale = Matrix.Scale(instanced_geometry_instance.scale, 4)
matrix_rotation = Matrix()
Expand Down
1,009 changes: 742 additions & 267 deletions io_scene_halo/file_tag/build_scene/generate_h1_scenario.py

Large diffs are not rendered by default.

136 changes: 51 additions & 85 deletions io_scene_halo/file_tag/build_scene/generate_h2_scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,47 @@
import bmesh
import numpy as np

from math import radians
from mathutils import Euler, Matrix
from math import radians, degrees, cos, sin, asin, atan2
from . import build_bsp as build_scene_level
from ...global_functions import global_functions
from ...global_functions.parse_tags import parse_tag
from ..h2.file_scenario.format import DataTypesEnum, ObjectFlags, ClassificationEnum, LightFlags, LightmapTypeEnum, LightmappingPolicyEnum as SCNRLightmappingPolicyEnum
from ..h2.file_scenario.format import ObjectFlags, ClassificationEnum, LightFlags, LightmapTypeEnum, LightmappingPolicyEnum as SCNRLightmappingPolicyEnum
from . import build_lightmap as build_scene_lightmap
from ..h2.file_scenario.mesh_helper.build_mesh import get_object
from ...file_tag.h2.file_light.format import ShapeTypeEnum, DefaultLightmapSettingEnum
from ...file_tag.h2.file_scenery.format import LightmappingPolicyEnum

def get_rotation_euler(yaw=0, pitch=0, roll=0):
yaw = -radians(yaw)
pitch = radians(pitch)
roll = -radians(roll)

z = Matrix([[cos(yaw), -sin(yaw), 0],
[sin(yaw), cos(yaw), 0],
[0, 0, 1]])

y = Matrix([[cos(pitch), 0, sin(pitch)],
[0, 1, 0],
[-sin(pitch), 0, cos(pitch)]])

x = Matrix([[1, 0, 0],
[0, cos(roll), -sin(roll)],
[0, sin(roll), cos(roll)]])

rot_matrix = z @ y @ x
return rot_matrix.inverted().to_euler()

def get_decal_rotation_euler(yaw=0, pitch=0):
max_value = 127
forward = [0, 0, (yaw / max_value)]
up = [0, (pitch / max_value), 0]

right = np.cross(up, forward)
rot_matrix = Matrix((forward, right, up))
print(rot_matrix)
return Matrix(rot_matrix).inverted_safe(rot_matrix).to_euler()

def generate_skies(context, level_root, tag_block, report):
asset_collection = bpy.data.collections.get("Skies")
if asset_collection == None:
Expand Down Expand Up @@ -67,13 +97,7 @@ def generate_skies(context, level_root, tag_block, report):
ob.data.energy = radiosity_power * 10
ob.parent = level_root

rotation = Euler((radians(0.0), radians(90.0), radians(0.0)), 'XYZ')
pitch = Euler((radians(0.0), -radians(light.direction[1]), radians(0.0)), 'XYZ')
yaw = Euler((radians(0.0), radians(0.0), radians(light.direction[0])), 'XYZ')
rotation.rotate(pitch)
rotation.rotate(yaw)

ob.rotation_euler = rotation
ob.rotation_euler = get_rotation_euler(*light.direction)

asset_collection.objects.link(ob)

Expand All @@ -99,59 +123,46 @@ def generate_comments(context, level_root, comment_tag_block):

def get_data_type(collection_name, root, tag_path, element):
if collection_name == "BSPs":
root.tag_view.data_type_enum = str(DataTypesEnum.clusters.value)
root.tag_view.lightmap_index = -1
root.tag_mesh.lightmap_index = -1

elif collection_name == "Scenery":
root.tag_view.data_type_enum = str(DataTypesEnum.scenery.value)
#elif collection_name == "Scenery":
#set_object_data(root, tag_path, element)

elif collection_name == "Biped":
root.lock_rotation[0] = True
root.lock_rotation[1] = True

root.tag_view.data_type_enum = str(DataTypesEnum.bipeds.value)
#set_object_data(root, tag_path, element)
#set_unit_data(root, element)

elif collection_name == "Vehicle":
root.tag_view.data_type_enum = str(DataTypesEnum.vehicles.value)
#elif collection_name == "Vehicle":
#set_object_data(root, tag_path, element)
#set_unit_data(root, element)
#set_vehicle_data(root, element)

elif collection_name == "Equipment":
root.tag_view.data_type_enum = str(DataTypesEnum.equipment.value)
#elif collection_name == "Equipment":
#set_object_data(root, tag_path, element)

elif collection_name == "Weapons":
root.tag_view.data_type_enum = str(DataTypesEnum.weapons.value)
#elif collection_name == "Weapons":
#set_object_data(root, tag_path, element)

elif collection_name == "Machines":
root.tag_view.data_type_enum = str(DataTypesEnum.machines.value)
#elif collection_name == "Machines":
#set_object_data(root, tag_path, element)

elif collection_name == "Controls":
root.tag_view.data_type_enum = str(DataTypesEnum.controls.value)
#elif collection_name == "Controls":
#set_object_data(root, tag_path, element)

elif collection_name == "Light Fixtures":
root.tag_view.data_type_enum = str(DataTypesEnum.light_fixtures.value)
#elif collection_name == "Light Fixtures":
#set_object_data(root, tag_path, element)

elif collection_name == "Sound Scenery":
root.tag_view.data_type_enum = str(DataTypesEnum.sound_scenery.value)
#elif collection_name == "Sound Scenery":
#set_object_data(root, tag_path, element)

elif collection_name == "Player Starting Locations":
root.tag_view.data_type_enum = str(DataTypesEnum.player_starting_locations.value)
#elif collection_name == "Player Starting Locations":

elif collection_name == "Netgame Flags":
root.tag_view.data_type_enum = str(DataTypesEnum.netgame_flags.value)
#elif collection_name == "Netgame Flags":

elif collection_name == "Netgame Equipment":
root.tag_view.data_type_enum = str(DataTypesEnum.netgame_equipment.value)
#elif collection_name == "Netgame Equipment":

def generate_object_elements(level_root, collection_name, palette, tag_block, context, game_version, file_version, fix_rotations, report, random_color_gen):
objects_list = []
Expand Down Expand Up @@ -258,15 +269,7 @@ def generate_object_elements(level_root, collection_name, palette, tag_block, co

get_data_type(collection_name, root, pallete_item.name, element)

rotation = Euler((radians(0.0), radians(0.0), radians(0.0)), 'XYZ')
roll = Euler((radians(element.rotation[2]), radians(0.0), radians(0.0)), 'XYZ')
pitch = Euler((radians(0.0), -radians(element.rotation[1]), radians(0.0)), 'XYZ')
yaw = Euler((radians(0.0), radians(0.0), radians(element.rotation[0])), 'XYZ')
rotation.rotate(yaw)
rotation.rotate(pitch)
rotation.rotate(roll)

root.rotation_euler = rotation
root.rotation_euler = get_rotation_euler(*element.rotation)

if collection_name == "Scenery":
pallete_tag = object_tags[element.palette_index]
Expand Down Expand Up @@ -365,15 +368,7 @@ def generate_light_volumes_elements(level_root, collection_name, palette, tag_bl
if ob_scale > 0.0:
root.scale = (ob_scale, ob_scale, ob_scale)

rotation = Euler((radians(0.0), radians(0.0), radians(0.0)), 'XYZ')
roll = Euler((radians(element.rotation[2]), radians(0.0), radians(0.0)), 'XYZ')
pitch = Euler((radians(0.0), -radians(element.rotation[1]), radians(0.0)), 'XYZ')
yaw = Euler((radians(0.0), radians(0.0), radians(element.rotation[0])), 'XYZ')
rotation.rotate(yaw)
rotation.rotate(pitch)
rotation.rotate(roll)

root.rotation_euler = rotation
root.rotation_euler = get_rotation_euler(*element.rotation)

def generate_netgame_equipment_elements(level_root, tag_block, context, game_version, file_version, fix_rotations, report, random_color_gen):
asset_collection = bpy.data.collections.get("Netgame Equipment")
Expand Down Expand Up @@ -429,15 +424,7 @@ def generate_netgame_equipment_elements(level_root, tag_block, context, game_ver
ob.parent = level_root
ob.location = element.position * 100

rotation = Euler((radians(0.0), radians(0.0), radians(0.0)), 'XYZ')
roll = Euler((radians(element.orientation[2]), radians(0.0), radians(0.0)), 'XYZ')
pitch = Euler((radians(0.0), -radians(element.orientation[1]), radians(0.0)), 'XYZ')
yaw = Euler((radians(0.0), radians(0.0), radians(element.orientation[0])), 'XYZ')
rotation.rotate(yaw)
rotation.rotate(pitch)
rotation.rotate(roll)

ob.rotation_euler = rotation
ob.rotation_euler = get_rotation_euler(*element.orientation)

def generate_empties(context, level_root, collection_name, tag_block):
asset_collection = bpy.data.collections.get(collection_name)
Expand Down Expand Up @@ -469,14 +456,7 @@ def generate_camera_flags(context, level_root, collection_name, tag_block):
ob.empty_display_type = 'ARROWS'
ob.parent = level_root
ob.location = element.position * 100

rotation = Euler((radians(0.0), radians(0.0), radians(0.0)), 'XYZ')
pitch = Euler((radians(0.0), -radians(element.facing[1]), radians(0.0)), 'XYZ')
yaw = Euler((radians(0.0), radians(0.0), radians(element.facing[0])), 'XYZ')
rotation.rotate(yaw)
rotation.rotate(pitch)

ob.rotation_euler = rotation
ob.rotation_euler = get_rotation_euler(*element.facing)

asset_collection.objects.link(ob)

Expand All @@ -494,15 +474,7 @@ def generate_camera_points(context, level_root, tag_block):
ob.parent = level_root
ob.location = element.position * 100

rotation = Euler((radians(0.0), radians(0.0), radians(0.0)), 'XYZ')
roll = Euler((radians(element.orientation[2]), radians(0.0), radians(0.0)), 'XYZ')
pitch = Euler((radians(0.0), -radians(element.orientation[1]), radians(0.0)), 'XYZ')
yaw = Euler((radians(0.0), radians(0.0), radians(element.orientation[0])), 'XYZ')
rotation.rotate(yaw)
rotation.rotate(pitch)
rotation.rotate(roll)

ob.rotation_euler = rotation
ob.rotation_euler = get_rotation_euler(*element.orientation)
ob.rotation_euler.rotate_axis("X", radians(90.0))
ob.rotation_euler.rotate_axis("Y", radians(-90.0))

Expand Down Expand Up @@ -566,14 +538,8 @@ def generate_decals(level_root, collection_name, palette, tag_block, context, ga
bm.to_mesh(mesh)
bm.free()

rotation = Euler((radians(0.0), radians(0.0), radians(0.0)), 'XYZ')
pitch = Euler((radians(0.0), -radians(element.pitch), radians(0.0)), 'XYZ')
yaw = Euler((radians(0.0), radians(0.0), radians(element.yaw)), 'XYZ')
rotation.rotate(yaw)
rotation.rotate(pitch)

ob.location = element.position * 100
ob.rotation_euler = rotation
ob.rotation_euler = get_decal_rotation_euler(element.yaw, element.pitch)

def scenario_get_resources(H2_ASSET, report):
ai_resource = None
Expand Down
2 changes: 1 addition & 1 deletion io_scene_halo/file_tag/export_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def write_file(context, file_path, report):
filename_no_ext = file_path.rsplit('.scenario', 1)[0]
filepath = "%s%s" % (filename_no_ext, "_blender.scenario")
output_stream = open(filepath, 'wb')
BLENDER_ASSET = generate_scenario_scene(DONOR_ASSET)
BLENDER_ASSET = generate_scenario_scene(context, DONOR_ASSET)
build_h1_scenario(output_stream, BLENDER_ASSET, report)

return {'FINISHED'}
Expand Down
26 changes: 5 additions & 21 deletions io_scene_halo/file_tag/h1/file_scenario/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,6 @@
from enum import Flag, Enum, auto
from mathutils import Vector, Euler

class DataTypesEnum(Enum):
none = 0
clusters = auto()
scenery = auto()
bipeds = auto()
vehicles = auto()
equipment = auto()
weapons = auto()
machines = auto()
controls = auto()
light_fixtures = auto()
sound_scenery = auto()
player_starting_locations = auto()
netgame_flags = auto()
netgame_equipment = auto()
decals = auto()
encounters = auto()
instances = auto()

class ScenarioTypeEnum(Enum):
solo = 0
multiplayer = auto()
Expand Down Expand Up @@ -184,7 +165,7 @@ class StartingEquipment(Flag):
type3_grenades_only = auto()

class EncounterFlags(Flag):
not_intially_created = auto()
not_initially_created = auto()
respawn_enabled = auto()
initially_blind = auto()
initially_deaf = auto()
Expand Down Expand Up @@ -273,6 +254,9 @@ class MajorUpgradeEnum(Enum):
none = auto()
all = auto()

class StartingLocationFlags(Flag):
required = auto()

class PlatoonFlags(Flag):
flee_when_maneuvering = auto()
say_advancing_when_maneuver = auto()
Expand All @@ -288,7 +272,7 @@ class PlatoonStrengthEnum(Enum):
_50_percent_dead = auto()
_75_percent_dead = auto()
all_but_one_dead = auto()
al_dead = auto()
all_dead = auto()

class GroupEnum(Enum):
a = 0
Expand Down
3 changes: 2 additions & 1 deletion io_scene_halo/file_tag/h1/file_scenario/process_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
TeamEnum,
SearchBehaviorEnum,
GroupEnum,
StartingLocationFlags,
PlatoonFlags,
PlatoonStrengthEnum,
StateEnum,
Expand Down Expand Up @@ -492,7 +493,7 @@ def get_starting_locations(input_stream, SCENARIO, TAG, node_element):
starting_location.facing = TAG.read_degree(input_stream, TAG, tag_format.XMLData(node_element, "facing"))
input_stream.read(2) # Padding
starting_location.sequence_id = TAG.read_signed_byte(input_stream, TAG, tag_format.XMLData(node_element, "sequence id"))
starting_location.flags = TAG.read_flag_unsigned_byte(input_stream, TAG, tag_format.XMLData(node_element, "flags", GroupFlags))
starting_location.flags = TAG.read_flag_unsigned_byte(input_stream, TAG, tag_format.XMLData(node_element, "flags", StartingLocationFlags))
starting_location.return_state = TAG.read_enum_unsigned_short(input_stream, TAG, tag_format.XMLData(node_element, "return state", LeaderEnum))
starting_location.initial_state = TAG.read_enum_unsigned_short(input_stream, TAG, tag_format.XMLData(node_element, "initial state", LeaderEnum))
starting_location.actor_type = TAG.read_block_index_signed_short(input_stream, TAG, tag_format.XMLData(node_element, "actor type", None, SCENARIO.actor_palette_tag_block.count, "scenario_ai_palette_block"))
Expand Down
Loading

0 comments on commit b9c75d7

Please sign in to comment.