Skip to content

Commit

Permalink
Release - 1.5
Browse files Browse the repository at this point in the history
  • Loading branch information
simon50keda committed Nov 11, 2016
1 parent d7732f0 commit 30f0420
Show file tree
Hide file tree
Showing 71 changed files with 6,763 additions and 863 deletions.
81 changes: 53 additions & 28 deletions addon/io_scs_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,27 @@
"name": "SCS Tools",
"description": "Setup models, Import-Export SCS data format",
"author": "Simon Lusenc (50keda), Milos Zajic (4museman)",
"version": (1, 4, "4ae6843"),
"blender": (2, 75, 0),
"version": (1, 5, "78732b8"),
"blender": (2, 78, 0),
"location": "File > Import-Export",
"wiki_url": "https://github.com/SCSSoftware/BlenderTools/wiki",
"wiki_url": "http://modding.scssoft.com/wiki/Documentation/Tools/SCS_Blender_Tools",
"tracker_url": "http://forum.scssoft.com/viewforum.php?f=163",
"support": "COMMUNITY",
"category": "Import-Export"}


def get_tools_version():
"""Returns Blender Tools version as string from bl_info["version"] dictonary value.
:return: string representation of bl_info["version"] tuple
:rtype: str
"""
ver = ""
for ver_num in bl_info["version"]:
ver += str(ver_num) + "."
return ver[:-1]


import bpy
import os
import traceback
from bpy.props import CollectionProperty, StringProperty, PointerProperty, BoolProperty
from bpy_extras.io_utils import ImportHelper, ExportHelper
from io_scs_tools.consts import Icons as _ICONS_consts
from io_scs_tools.imp import pix as _pix_import
from io_scs_tools.internals.callbacks import open_gl as _open_gl_callback
from io_scs_tools.internals.callbacks import persistent as _persistent_callback
from io_scs_tools.internals import icons as _icons
from io_scs_tools.utils import get_scs_globals as _get_scs_globals
from io_scs_tools.utils.view3d import switch_layers_visibility as _switch_layers_visibility
from io_scs_tools.utils.view3d import has_view3d_space as _has_view3d_space
from io_scs_tools.utils.printout import lprint
# importing all SCS Tools modules which creates panels in UI
from io_scs_tools import ui
Expand Down Expand Up @@ -90,6 +80,25 @@ def check(self, context):
return True

def execute(self, context):

# if paths are still initializing report that to user and don't execute import
if operators.world.SCSPathsInitialization.is_running():

self.report({'INFO'}, "Can't import yet, paths initialization is still in progress! Try again in few moments.")

# there is no way to keep current operator alive if we want to abort import sequence.
# That's why we call another import operator, which will end up with
# printing out above info and taking us back to import screen with file browser.
bpy.ops.import_mesh.pim('INVOKE_DEFAULT')

return {'FINISHED'}

if not _has_view3d_space(context.screen):
message = "Cannot import SCS Models, no 3D viewport found! Make sure you have at least one 3D view visible."
self.report({'ERROR'}, message)
lprint("E " + message)
return {'FINISHED'}

paths = [os.path.join(self.directory, name.name) for name in self.files]
if not paths:
paths.append(self.path)
Expand All @@ -111,17 +120,17 @@ def execute(self, context):
_get_scs_globals().import_in_progress = False
context.window.cursor_modal_restore()

traceback.print_exc()
lprint("E Unexpected %r accured during import, see stack trace above.", (type(e).__name__,))
trace_str = traceback.format_exc().replace("\n", "\n\t ")
lprint("E Unexpected %r accured during import:\n\t %s", (type(e).__name__, trace_str))

if result is False:
failed_files.append(str(filepath).replace("\\", "/"))

if len(failed_files) > 0:
err_message = "E Following files failed to load:\n"
err_message = "E Following files failed to load:"

for _ in failed_files:
err_message += "-> %r\n"
err_message += "\n\t -> %r\n"

lprint(err_message, tuple(failed_files), report_warnings=1, report_errors=1)

Expand Down Expand Up @@ -150,6 +159,11 @@ def draw(self, context):
layout_box_row = layout_box_col.row(align=True)
layout_box_row.prop(self, "scs_project_path_mode", toggle=True, text="Set Current Dir as Project Base", icon='SCREEN_BACK')

if operators.world.SCSPathsInitialization.is_running(): # report running path initialization operator
layout_box_row = layout_box_col.row(align=True)
layout_box_row.label("Paths initialization in progress...")
layout_box_row.label("", icon='TIME')

# import settings
box2 = layout.box()
col = box2.column(align=True)
Expand Down Expand Up @@ -256,11 +270,9 @@ def execute(self, context):
result = {"CANCELLED"}
context.window.cursor_modal_restore()

import traceback

traceback.print_exc()
lprint("E Unexpected %r accured during batch export, see stack trace above.",
(type(e).__name__,),
trace_str = traceback.format_exc().replace("\n", "\n\t ")
lprint("E Unexpected %r accured during batch export:\n\t %s",
(type(e).__name__, trace_str),
report_errors=1,
report_warnings=1)

Expand All @@ -273,6 +285,20 @@ def draw(self, context):
ui.shared.draw_export_panel(self.layout)


class SCSAddObject(bpy.types.Menu):
bl_idname = "INFO_MT_SCS_add_object"
bl_label = "SCS Object"
bl_description = "Creates menu for adding SCS objects."

def draw(self, context):
self.layout.operator_enum("object.scs_add_object", "new_object_type")


def add_menu_func(self, context):
self.layout.menu("INFO_MT_SCS_add_object", text="SCS Object", icon_value=_icons.get_icon(_ICONS_consts.Types.scs_logo_orange))
self.layout.separator()


def menu_func_import(self, context):
self.layout.operator(ImportSCS.bl_idname, text="SCS Formats (.pim)")

Expand All @@ -288,7 +314,7 @@ def register():

bpy.utils.register_module(__name__)

# CUSTOM ICONS CLEANUP
# CUSTOM ICONS INITIALIZATION
_icons.init()

# PROPERTIES REGISTRATION
Expand Down Expand Up @@ -358,17 +384,16 @@ def register():
# MENU REGISTRATION
bpy.types.INFO_MT_file_import.append(menu_func_import)
bpy.types.INFO_MT_file_export.append(menu_func_export)
bpy.types.INFO_MT_add.prepend(add_menu_func)


def unregister():
bpy.utils.unregister_module(__name__)

# CUSTOM ICONS CLEANUP
_icons.cleanup()

# REMOVE MENU ENTRIES
bpy.types.INFO_MT_file_export.remove(menu_func_export)
bpy.types.INFO_MT_file_import.remove(menu_func_import)
bpy.types.INFO_MT_add.remove(add_menu_func)

# REMOVE OPENGL HANDLERS
_open_gl_callback.disable()
Expand Down
56 changes: 55 additions & 1 deletion addon/io_scs_tools/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
Constants for data group of map and navigation curves
"""

from math import pi
from enum import Enum
from zipfile import ZIP_STORED, ZIP_DEFLATED, ZIP_BZIP2

Expand Down Expand Up @@ -63,6 +64,31 @@ class TerrainPoints:
vg_name_regex = "^" + vg_name_prefix.replace(".", "\\.") + "\d$"
"""Regex for matching terrain points vertex groups names on export."""

class View3DReport:
"""Constants related to 3D view report operator.
"""
# constants defining BT logo image and texts/positions of close/hide controls
BT_LOGO_IMG_NAME = ".scs_bt_logo.png"
BT_LOGO_AREA = (20, 217, 30, 50)
CLOSE_BTN_AREA = (230, 370, 26, 54)
CLOSE_BTN_TEXT = (
"[Click] Close", # used when report text is shown
"[Click/ESC] Close" # used when report text is hidden (aka condensed mode)
)
CLOSE_BTN_TEXT_POS = (
(260, 45), # used when report text is shown
(240, 45) # used when report text is hidden (aka condensed mode)
)
HIDE_BTN_AREA = (385, 530, 26, 54)
HIDE_BTN_TEXT = (
"[Click/ESC] Hide", # used when report text is shown
"[Click] Show" # used when report text is hidden (aka condensed mode)
)
HIDE_BTN_TEXT_POS = (
(400, 45), # used when report text is shown
(415, 45) # used when report text is hidden (aka condensed mode)
)


class Icons:
"""Constants related to loading of custom icons.
Expand Down Expand Up @@ -93,6 +119,7 @@ class Types:
loc_collider_convex = ".20_collider_convex.png"
scs_root = ".21_scs_root_object.png"
scs_logo = ".icon_scs_bt_logo.png"
scs_logo_orange = ".icon_scs_bt_logo_orange.png"

@staticmethod
def as_list():
Expand All @@ -105,7 +132,8 @@ def as_list():
Icons.Types.loc_prefab_node, Icons.Types.loc_prefab_sign, Icons.Types.loc_prefab_spawn, Icons.Types.loc_prefab_semaphore,
Icons.Types.loc_prefab_navigation, Icons.Types.loc_prefab_map, Icons.Types.loc_prefab_trigger,
Icons.Types.loc_collider_box, Icons.Types.loc_collider_sphere, Icons.Types.loc_collider_capsule,
Icons.Types.loc_collider_cylinder, Icons.Types.loc_collider_convex, Icons.Types.scs_root, Icons.Types.scs_logo]
Icons.Types.loc_collider_cylinder, Icons.Types.loc_collider_convex, Icons.Types.scs_root,
Icons.Types.scs_logo_orange, Icons.Types.scs_logo]


class Part:
Expand Down Expand Up @@ -301,6 +329,7 @@ class PSP:
UNLOAD_MEDIUM_POS = 19
UNLOAD_HARD_POS = 20
UNLOAD_RIGID_POS = 21
WEIGHT_CAT_POS = 22

class TST:
"""Constants representing type of traffic semaphores.
Expand All @@ -314,6 +343,8 @@ class TST:
BARRIER_DISTANCE = 6
TRAFFIC_LIGHT_BLOCKABLE = 7
BARRIER_GAS = 8
TRAFFIC_LIGHT_VIRTUAL = 9
BARRIER_AUTOMATIC = 10

class MPVF:
"""Constants represeting map point visual flags.
Expand All @@ -323,6 +354,10 @@ class MPVF:
ROAD_SIZE_2_LANE = 0x00000200
ROAD_SIZE_3_LANE = 0x00000300
ROAD_SIZE_4_LANE = 0x00000400
ROAD_SIZE_2_LANE_SPLIT = 0x00000500
ROAD_SIZE_3_LANE_SPLIT = 0x00000600
ROAD_SIZE_4_LANE_SPLIT = 0x00000700
ROAD_SIZE_3_LANE_ONE_WAY = 0x00000800
ROAD_SIZE_MANUAL = 0x00000D00
ROAD_SIZE_AUTO = 0x00000E00
ROAD_SIZE_MASK = 0x00000F00
Expand All @@ -334,6 +369,7 @@ class MPVF:
ROAD_OFFSET_15 = 0x00005000
ROAD_OFFSET_20 = 0x00006000
ROAD_OFFSET_25 = 0x00007000
ROAD_OFFSET_LANE = 0x00008000
ROAD_OFFSET_MASK = 0x0000F000
ROAD_EXT_VALUE_MASK = 0x000000FF
ROAD_OVER = 0x00010000
Expand Down Expand Up @@ -389,3 +425,21 @@ class ConvHlpr:
StoredZip = str(ZIP_STORED)
DeflatedZip = str(ZIP_DEFLATED)
Bzip2Zip = str(ZIP_BZIP2)


class SCSLigthing:
"""Constants for scs lighting scene. Lighting scene is created from sun profile loaded from SII file.
"""
scene_name = ".scs_lighting"
"""Name of lighting scene. It should be prefixed with dot to be partially hidden in scene selection theme."""

ambient_lamps = (
(".scs_ambient_z+", (pi, 0, 0), 0.5),
(".scs_ambient_z-", (0, 0, 0), 1.1)
)
"""Ambient lamps definitions. Each lamp is defined as (name, direction, energy_factor).
There has to be 6 hemi lamps to point in each direction, which should reassemble ambient lights.
Energy factor in each of lamps tells percent of given light by that ambient lamp."""

diffuse_lamp_name = ".scs_diffuse"
specular_lamp_name = ".scs_specular"
27 changes: 21 additions & 6 deletions addon/io_scs_tools/exp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from io_scs_tools.exp import pip
from io_scs_tools.exp import pis
from io_scs_tools.exp import pix
from io_scs_tools.utils import name as _name_utils
from io_scs_tools.utils import object as _object_utils
from io_scs_tools.utils import path as _path_utils
from io_scs_tools.utils import get_scs_globals as _get_scs_globals
Expand Down Expand Up @@ -57,15 +58,27 @@ def batch_export(operator_instance, init_obj_list, menu_filepath=None):

for root_object in game_objects_dict:

if not _name_utils.is_valid_scs_root_object_name(root_object.name):
lprint("E Rejecting Game Object with invalid SCS Root Object name: %r.\n\t "
"Only a-z, A-Z, 0-9 and \"._-\" characters can be used." % root_object.name)
scs_game_objects_rejected.append("> \"" + root_object.name + "\"")
continue

game_object_list = game_objects_dict[root_object]
if len(game_object_list) == 0:
lprint("E Rejecting empty Game Object with SCS Root Object name: %r\n\t " +
"Game Object has to have at least one mesh object or model locator!",
(root_object.name,))
scs_game_objects_rejected.append("> \"" + root_object.name + "\"")
continue

# update root object location to invoke update tagging on it and
# then update scene to make sure all children objects will have all transforms up to date
# NOTE: needed because Blender doesn't update objects on invisible layers on it's own
root_object.location = root_object.location
for scene in bpy.data.scenes:
scene.update()

game_object_list = game_objects_dict[root_object]

# GET CUSTOM FILE PATH
custom_filepath = _path_utils.get_custom_scs_root_export_path(root_object)

Expand Down Expand Up @@ -100,7 +113,7 @@ def batch_export(operator_instance, init_obj_list, menu_filepath=None):
filepath_message
)
else:
message = "No valid export path found! Please check \"SCS Project Base Path\" first."
message = "No valid export path found! Please check 'SCS Project Base Path' first."
lprint('E ' + message)
operator_instance.report({'ERROR'}, message.replace("\t", "").replace(" ", ""))
return {'CANCELLED'}
Expand All @@ -124,13 +137,15 @@ def batch_export(operator_instance, init_obj_list, menu_filepath=None):
lprint("I " + message)

if len(scs_game_objects_exported) + len(scs_game_objects_rejected) == 0:
message = "Nothing to export! Please set at least one 'SCS Root Object'."
message = "Nothing to export! Please setup at least one SCS Root Object."
lprint('E ' + message)
operator_instance.report({'ERROR'}, message)
return {'CANCELLED'}
else:
message = "No 'SCS Root Object' present or all of them were manually exluded from export in their settings.\n\t " \
"(For more information, please refer to 'SCS Blender Tools' documentation.)"
message = "No Game Objects to export because:\n\t " \
"1. Selection export is used and none of selected objects belongs to any SCS Game Object or\n\t " \
"2. all of the SCS Root Objects were manually exluded from export or\n\t " \
"3. there is no SCS Root Objects in the scene."
lprint('E ' + message)
operator_instance.report({'ERROR'}, message.replace("\n\t ", "\n"))
return {'CANCELLED'}
Expand Down
3 changes: 2 additions & 1 deletion addon/io_scs_tools/exp/pia.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import os

import bpy
from collections import OrderedDict
from mathutils import Vector, Matrix, Euler, Quaternion
from io_scs_tools.utils import convert as _convert_utils
from io_scs_tools.utils import get_scs_globals as _get_scs_globals
Expand Down Expand Up @@ -99,7 +100,7 @@ def _get_bone_channels(scs_root_obj, armature, scs_animation, action, export_sca
armature_mat = scs_root_obj.matrix_world.inverted() * armature.matrix_world

invalid_data = False # flag to indicate invalid data state
curves_per_bone = {} # store all the curves we are interested in per bone names
curves_per_bone = OrderedDict() # store all the curves we are interested in per bone names

for bone in armature.data.bones:
for fcurve in action.fcurves:
Expand Down
17 changes: 15 additions & 2 deletions addon/io_scs_tools/exp/pim/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,15 @@ def execute(dirpath, root_object, armature_object, skeleton_filepath, mesh_objec
mesh_pieces[pim_mat_name] = Piece(len(pim_pieces) + len(mesh_pieces), pim_materials[pim_mat_name])

nmap_uv_layer = pim_materials[pim_mat_name].get_nmap_uv_name()
if nmap_uv_layer: # if there is uv layer used for normal maps then calculate tangents on it
mesh.calc_tangents(uvmap=nmap_uv_layer)
# if there is uv layer used for normal maps and that uv layer exists on mesh then calculate tangents on it otherwise report warning
if nmap_uv_layer:

if nmap_uv_layer in mesh.uv_layers:
mesh.calc_tangents(uvmap=nmap_uv_layer)
else:
lprint("W Unable to calculate normal map tangents for object %r,\n\t "
"as it's missing UV layer with name: %r, expect problems!",
(mesh_obj.name, nmap_uv_layer))

mesh_piece = mesh_pieces[pim_mat_name]
""":type: Piece"""
Expand Down Expand Up @@ -282,6 +289,12 @@ def execute(dirpath, root_object, armature_object, skeleton_filepath, mesh_objec
# save to terrain points storage if present in correct vertex group
for group in mesh.vertices[vert_i].groups:

# if current object doesn't have vertex group found in mesh data, then ignore that group
# This can happen if multiple objects are using same mesh and
# some of them have vertex groups, but others not.
if group.group >= len(mesh_obj.vertex_groups):
continue

curr_vg_name = mesh_obj.vertex_groups[group.group].name

# if vertex group name doesn't match prescribed one ignore this vertex group
Expand Down
Loading

0 comments on commit 30f0420

Please sign in to comment.