Skip to content

Commit aeef2d0

Browse files
author
Nozomi Miyamori
committed
release version 3.0.0
* Support NGS1 TMC. * Improve material emulation. * Import mesh objects as separate objects. and some other improvements.
1 parent d2061f4 commit aeef2d0

File tree

12 files changed

+1604
-724
lines changed

12 files changed

+1604
-724
lines changed

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
Ninja Gaiden Sigam 2 TMC Blender Extension
2-
==========================================
1+
Ninja Gaiden Master Collection TMC Importer Blender Extension
2+
=============================================================
33

44
Author: Nozomi Miyamori
55

6-
A blender extension to import Ninja Gaiden Sigma 2 TMC into
6+
A blender extension to import Ninja Gaiden Sigma 1 and 2 TMC into
77
your blender project.
88

99
Requirements
@@ -23,9 +23,7 @@ Installation
2323
Caveats
2424
-------
2525

26-
* It does not import material parameters (e.g. color, metalness, roughness) yet
2726
* It does not support exporting a blender project to an TMC file
28-
* It may not import some TMC models (I tested the extension only with some human models)
2927

3028
License
3129
-------

src/ninja_gaiden_tmc/__init__.py

Lines changed: 81 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
# NINJA GAIDEN SIGMA 2 TMC Importer by Nozomi Miyamori is under the public domain
1+
# NINJA GAIDEN Model Importer by Nozomi Miyamori is under the public domain
22
# and also marked with CC0 1.0. This file is a part of NINJA GAIDEN SIGMA 2 TMC Importer.
33

4-
from .importer import import_ngs2_tmc
5-
64
from . import tcmlib
5+
from .ngs1.importer import import_tmc as ngs1_import_tmc
6+
from .ngs2.importer import import_tmc as ngs2_import_tmc
77

88
import bpy
99

@@ -14,14 +14,63 @@
1414
import os
1515
import mmap
1616

17-
def import_tmc_wrapper(context, tmc_path, tmcl_path):
18-
tmc_m, tmcl_m = mmap_open(tmc_path), mmap_open(tmcl_path)
19-
with tmc_m, tmcl_m:
20-
with tcmlib.ngs2.TMCParser(tmc_m, tmcl_m) as tmc:
21-
import_ngs2_tmc(context, tmc)
17+
class NGS1SelectG1TGImportTMC(Operator, ImportHelper):
18+
bl_idname = 'ninja_gaiden_tmc.ngs1_select_g1tg_import_tmc'
19+
bl_label = 'Select TMCL2 or G1TG'
20+
bl_options = {'REGISTER', 'UNDO'}
21+
22+
filter_glob: StringProperty(
23+
default="*.g1t;*.gt1;*.g1tg;*.tmcl2;*.dat",
24+
options={'SKIP_SAVE', 'HIDDEN'},
25+
)
26+
directory: StringProperty(subtype='DIR_PATH')
2227

23-
class SelectTMCLImportTMC(Operator, ImportHelper):
24-
bl_idname = 'ninja_gaiden_tmc.select_tmcl_import_tmc'
28+
tmc_path: StringProperty(
29+
subtype='FILE_PATH',
30+
default='',
31+
options={'SKIP_SAVE', 'HIDDEN'}
32+
)
33+
34+
tmcl_path: StringProperty(
35+
subtype='FILE_PATH',
36+
default='',
37+
options={'SKIP_SAVE', 'HIDDEN'}
38+
)
39+
40+
def execute(self, context):
41+
if not self.tmc_path or not self.tmcl_path:
42+
return {'CANCELLED'}
43+
44+
try:
45+
with (mmap_open(self.tmc_path) as tmc, mmap_open(self.tmcl_path) as tmcl,
46+
mmap_open(self.filepath) as g1tg, tcmlib.ngs1.TMCParser(tmc, tmcl) as tmc):
47+
ngs1_import_tmc(context, tmc, g1tg)
48+
except tcmlib.ParserError as e:
49+
self.report({'ERROR'}, f"Failed to parse TMC: {e}")
50+
return {'CANCELLED'}
51+
return {'FINISHED'}
52+
53+
class NGS1SelectTMCL(Operator, ImportHelper):
54+
bl_idname = 'ninja_gaiden_tmc.ngs1_select_tmcl'
55+
bl_label = 'Select TMCL'
56+
57+
filter_glob: StringProperty(
58+
default="*.tmcl;*.dat",
59+
options={'SKIP_SAVE', 'HIDDEN'},
60+
)
61+
directory: StringProperty(subtype='DIR_PATH')
62+
63+
tmc_path: StringProperty(
64+
subtype='FILE_PATH',
65+
default='',
66+
options={'SKIP_SAVE', 'HIDDEN'}
67+
)
68+
69+
def execute(self, context):
70+
return bpy.ops.ninja_gaiden_tmc.ngs1_select_g1tg_import_tmc('INVOKE_DEFAULT', tmc_path=self.tmc_path, tmcl_path=self.filepath, directory=self.directory)
71+
72+
class NGS2SelectTMCLImportTMC(Operator, ImportHelper):
73+
bl_idname = 'ninja_gaiden_tmc.ngs2_select_tmcl_import_tmc'
2574
bl_label = 'Select TMCL'
2675
bl_options = {'REGISTER', 'UNDO'}
2776

@@ -42,14 +91,15 @@ def execute(self, context):
4291
return {'CANCELLED'}
4392

4493
try:
45-
import_tmc_wrapper(context, self.tmc_path, self.filepath)
94+
with mmap_open(self.tmc_path) as tmc, mmap_open(self.filepath) as tmcl, tcmlib.ngs2.TMCParser(tmc, tmcl) as tmc:
95+
ngs2_import_tmc(context, tmc)
4696
except tcmlib.ParserError as e:
47-
self.report({'ERROR'}, "Failed to parse TMC: {e}")
97+
self.report({'ERROR'}, f"Failed to parse TMC: {e}")
4898
return {'CANCELLED'}
4999
return {'FINISHED'}
50100

51101
class ImportTMCEntry(Operator, ImportHelper):
52-
'''Load a TMC file (NGS2)'''
102+
'''Load a TMC file'''
53103
bl_idname = 'ninja_gaiden_tmc.import_tmc_entry'
54104
bl_label = 'Select TMC'
55105
old_dir = ''
@@ -58,6 +108,7 @@ class ImportTMCEntry(Operator, ImportHelper):
58108
default="*.tmc;*.dat",
59109
options={'SKIP_SAVE', 'HIDDEN'},
60110
)
111+
filename: StringProperty()
61112
directory: StringProperty(subtype='DIR_PATH')
62113

63114
def invoke(self, context, event):
@@ -66,22 +117,35 @@ def invoke(self, context, event):
66117

67118
def execute(self, context):
68119
ImportTMCEntry.old_dir = self.directory
69-
return bpy.ops.ninja_gaiden_tmc.select_tmcl_import_tmc('INVOKE_DEFAULT', tmc_path=self.filepath, directory=self.directory)
120+
try:
121+
with mmap_open(self.filepath) as tmc, tcmlib.ContainerParser(b'TMC', tmc) as tmc:
122+
min_v = tmc._minor_ver
123+
except tcmlib.ParserError as e:
124+
self.report({'ERROR'}, f"{self.filename} is not TMC")
125+
return {'CANCELLED'}
126+
if min_v == 0:
127+
return bpy.ops.ninja_gaiden_tmc.ngs1_select_tmcl('INVOKE_DEFAULT', tmc_path=self.filepath, directory=self.directory)
128+
else:
129+
return bpy.ops.ninja_gaiden_tmc.ngs2_select_tmcl_import_tmc('INVOKE_DEFAULT', tmc_path=self.filepath, directory=self.directory)
70130

71131
def mmap_open(path):
72132
with open(path, 'rb') as f:
73133
return mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
74134

75135
def menu_func_import(self, context):
76-
self.layout.operator(ImportTMCEntry.bl_idname, text="Ninja Gaiden Sigam 2 TMC (.tmc/.tmcl)")
136+
self.layout.operator(ImportTMCEntry.bl_idname, text="Ninja Gaiden Master Collection TMC (.tmc)")
77137

78138
def register():
79-
bpy.utils.register_class(SelectTMCLImportTMC)
139+
bpy.utils.register_class(NGS1SelectG1TGImportTMC)
140+
bpy.utils.register_class(NGS1SelectTMCL)
141+
bpy.utils.register_class(NGS2SelectTMCLImportTMC)
80142
bpy.utils.register_class(ImportTMCEntry)
81143
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
82144

83145
def unregister():
84-
bpy.utils.unregister_class(SelectTMCLImportTMC)
146+
bpy.utils.unregister_class(NGS1SelectG1TGImportTMC)
147+
bpy.utils.unregister_class(NGS1SelectTMCL)
148+
bpy.utils.unregister_class(NGS2SelectTMCLImportTMC)
85149
bpy.utils.unregister_class(ImportTMCEntry)
86150
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
87151

src/ninja_gaiden_tmc/blender_manifest.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
schema_version = "1.0.0"
22

33
id = "ninja_gaiden_tmc"
4-
version = "2.1.0"
5-
name = "Ninja Gaiden Sigma 2 TMC Format"
6-
tagline = "Import Ninja Gaiden Sigma 2 TMC"
4+
version = "3.0.0"
5+
name = "Ninja Gaiden Sigma 1 and 2 TMC Format"
6+
tagline = "Import Ninja Gaiden Sigma 1 and 2 TMC"
77
maintainer = "Nozomi Miyamori"
88
type = "add-on"
99

0 commit comments

Comments
 (0)