Join also our Discord channel! Click here.

Sudden Attack - Noesis Script Creation

Post questions about game models here, or help out others!
User avatar
Acewell
VIP member
VIP member
Posts: 1328
Joined: Wed Nov 05, 2008 12:16 pm
Has thanked: 2677 times
Been thanked: 828 times

Re: Sudden Attack - Noesis Script Creation

Post by Acewell » Sun Mar 19, 2017 6:20 pm

okay i updated the script with a quick fix, it may or may not break other models, if it does just comment out lines 34-37 and shift+tab line 38. :D
the stride was 1 byte off and the submesh headers had an extra 2 bytes in the last 2 samples. :scaredy:
Last edited by Acewell on Sun Mar 19, 2017 7:43 pm, edited 1 time in total.

TRDaz
mega-veteran
mega-veteran
Posts: 210
Joined: Sat Sep 24, 2011 7:06 pm
Has thanked: 75 times
Been thanked: 26 times

Re: Sudden Attack - Noesis Script Creation

Post by TRDaz » Sun Mar 19, 2017 7:09 pm

Works great :D Thanks!

WPH93
n00b
Posts: 17
Joined: Sun Feb 12, 2017 5:31 pm
Been thanked: 1 time

Re: Sudden Attack - Noesis Script Creation

Post by WPH93 » Thu Mar 23, 2017 3:15 pm

shakotay2 wrote:Is #rapi.rpgBindUV1BufferOfs() still commented out in your code?
delete the # then (which disables the line from being "executed", so it's just a comment)

I'd suggest to read chrrox' Noesis tutorial to gain more understanding
otherwise you'll fall from one trouble into the other, I guess.

did you follow mariokart64n's tutorial?
" msh.setIndices(ltb.faceArray)"
" msh.setPositions(ltb.vertArray)"
is a little bit uncommon to me (doesn't seem to be part of the rapi.rpg interface)

You might be required to use self.setUVs([]) to get the uvs.
QuickBMS can not extract .rez [roll] How could I extract it,plz.

Xr79
advanced
Posts: 57
Joined: Sat Oct 05, 2013 11:45 pm
Has thanked: 6 times

Re: Sudden Attack - Noesis Script Creation

Post by Xr79 » Sun Feb 24, 2019 9:31 pm

Acewell wrote:
Sun Mar 19, 2017 6:20 pm
okay i updated the script with a quick fix, it may or may not break other models, if it does just comment out lines 34-37 and shift+tab line 38. :D
the stride was 1 byte off and the submesh headers had an extra 2 bytes in the last 2 samples. :scaredy:
Hey Acewell, I know this is an old post, I wanted to thank you for your work on the script! seriously it's awesome, there are Kpop stars in the sudden attack files and I really wanted to get the models.
but I've run into a bit of a problem. I followed your directions on commenting your script and then none of the models will open, the script compiles and works but none of the models open any more. are you sure you got the right lines to comment out there?
here is an example of one of the files that does not work with your script.
i managed to get all the files from the game even tho it's shut down for some reason you can download it on the korean site.
thank you in advance if you can offer any help with this.

User avatar
Acewell
VIP member
VIP member
Posts: 1328
Joined: Wed Nov 05, 2008 12:16 pm
Has thanked: 2677 times
Been thanked: 828 times

Re: Sudden Attack - Noesis Script Creation

Post by Acewell » Mon Feb 25, 2019 8:44 am

Xr79 wrote:
Sun Feb 24, 2019 9:31 pm
are you sure you got the right lines to comment out there?
that is a question you should probably ask yourself. :D
here is an example of one of the files that does not work with your script.
i can't see invisible samples, maybe you forgot to link it?
i don't really think there is much more i can do with this game model format.

i don't do much with model scripts any more anyway because i have
a large backlog of texture samples from many other topics to examine
and i plan to get most of them out of the way this year. :D

Xr79
advanced
Posts: 57
Joined: Sat Oct 05, 2013 11:45 pm
Has thanked: 6 times

Re: Sudden Attack - Noesis Script Creation

Post by Xr79 » Mon Feb 25, 2019 9:32 pm

Acewell wrote:
Mon Feb 25, 2019 8:44 am
Xr79 wrote:
Sun Feb 24, 2019 9:31 pm
are you sure you got the right lines to comment out there?
that is a question you should probably ask yourself. :D
here is an example of one of the files that does not work with your script.
i can't see invisible samples, maybe you forgot to link it?
i don't really think there is much more i can do with this game model format.

i don't do much with model scripts any more anyway because i have
a large backlog of texture samples from many other topics to examine
and i plan to get most of them out of the way this year. :D
If I'm being honest I wasn't expecting you to take the time to message me back, I thought it was just a shot in the dark. there was a problem sharing the sample, it's to big and all my online store are full right now.
but maybe you could show what lines to comment out? I did 34-37 and shift tabbed 38 like you said to, but it didn't work. I use note pad ++

34 if vertex_stride == 31:
35 vertex_stride = 32
36 bs.seek(0x18, NOESEEK_REL)
37 else:
38 bs.seek(0x16, NOESEEK_REL)

User avatar
Acewell
VIP member
VIP member
Posts: 1328
Joined: Wed Nov 05, 2008 12:16 pm
Has thanked: 2677 times
Been thanked: 828 times

Re: Sudden Attack - Noesis Script Creation

Post by Acewell » Tue Feb 26, 2019 5:15 am

yes those are the correct lines. :)
when i say comment them they will result to look like this:

Code: Select all

# if vertex_stride == 31:
    # vertex_stride = 32
    # bs.seek(0x18, NOESEEK_REL)
# else:
bs.seek(0x16, NOESEEK_REL)
the indent of line 38 is critical, this might be where it breaks for you.
line 38 should be indented the same as line 33.
if it still doesn't work with your sample then it just doesn't work.
there is no guarantee the script works with all game samples.

mariokart64n
ultra-veteran
ultra-veteran
Posts: 546
Joined: Sun Jun 05, 2005 12:00 pm
Location: Ontario, Canada
Has thanked: 31 times
Been thanked: 181 times

Re: Sudden Attack - Noesis Script Creation

Post by mariokart64n » Sun Jun 21, 2020 7:09 pm

I was contacted about adding bone and weight support for the Noesis python plugin for sudden attack.

I started by examining my old python script, and any other scripts written by others to determine if my involvement was required.

From what I discovered there are many scripts from several people; me, TRDaz, Acewell, finale00, zaramot, shakotay2, and possibly more in circulation

All of the previous scripts suffer from a range of problems;
- Incomplete Parsing of the file Header (Address of vertex buffer sometimes incorrect)
- Incomplete Reading of the vertex data (Doesn't read the bones or the weights)
- Lack of Vertex Type detection (resulted in many 'variant' versions of the scripts to work with each ltb model.)

As far as I understand .ltb likely stands for "Lith Tech Binary" and is used in a wide range of games using the LithTech Engine including the LithTech Jupiter Engine.

Technically this Topic for "Sudden Attack" should belong in this other Topic discussing and dealing with Lith Tech Engine models in general
viewtopic.php?f=16&t=7230

However the samples that were provided to me were exclusively from Sudden Attack so i will drop my update here;

This is a Noesis Python Plugin for Sudden Attack
(has also been tested with the samples posted in this Topic by others)

Supports:
- Improved Reading and detection of file header and vertex definitions
- Mesh, Bones, Weights

Not Supported
-Materials
***see dtx script to unpack textures: viewtopic.php?p=164339#p164339

Image

Code: Select all

#	Python Script Plugin for Noesis
#
#	Read Mesh from Lith Tech Binary
#	
#	Author:	mariokart64n
#	Date:		June 20 2020
#	Source:	https://forum.xentax.com/viewtopic.php?f=16&t=15997
#

showConsole = False
NOEPY_HEADER = 0x00090001  # LTB

from inc_noesis import *

class ltb_unk032:		# 112bytes
	name_length = 0
	name = ""
	unk100 = 0
	unk101 = 0.0
	unk102 = 0.0
	unk103 = 0.0
	unk104 = 0.0
	unk105 = 0.0
	unk106 = 0.0
	unk107 = 0.0
	unk108 = 0.0
	unk109 = 0.0
	unk110 = 0.0
	unk111 = 0.0
	unk112 = 0.0
	unk113 = 0.0
	unk114 = 0.0
	unk115 = 0.0
	unk116 = 0.0
	unk117 = 0.0
	unk118 = 0.0
	unk119 = 0.0
	unk120 = 0.0
	unk121 = 0.0
	unk122 = 0.0
	unk123 = 0.0
	unk124 = 0.0
	unk125 = 0.0
	unk126 = 0.0
	unk127 = 0.0
	def read_unk032(self, f=NoeBitStream()):
		self.name_length = f.readUShort()
		self.name = f.readBytes(name_length).decode("UTF-8").rstrip("\0")
		self.unk100 = f.readUInt()
		self.unk101 = f.readFloat()
		self.unk102 = f.readFloat()
		self.unk103 = f.readFloat()
		self.unk104 = f.readFloat()
		self.unk105 = f.readFloat()
		self.unk106 = f.readFloat()
		self.unk107 = f.readFloat()
		self.unk108 = f.readFloat()
		self.unk109 = f.readFloat()
		self.unk110 = f.readFloat()
		self.unk111 = f.readFloat()
		self.unk112 = f.readFloat()
		self.unk113 = f.readFloat()
		self.unk114 = f.readFloat()
		self.unk115 = f.readFloat()
		self.unk116 = f.readFloat()
		self.unk117 = f.readFloat()
		self.unk118 = f.readFloat()
		self.unk119 = f.readFloat()
		self.unk120 = f.readFloat()
		self.unk121 = f.readFloat()
		self.unk122 = f.readFloat()
		self.unk123 = f.readFloat()
		self.unk124 = f.readFloat()
		self.unk125 = f.readFloat()
		self.unk126 = f.readFloat()
		self.unk127 = f.readFloat()
		

class ltb_node:
	node_name_length = 0
	node_name = ""
	index = 0
	unk091 = 0
	unk092 = 0
	matrix = []
	childCount = 0
	children = []
	parent = -1
	def read_node(self, f=NoeBitStream()):
		self.node_name_length = f.readUShort()
		self.node_name = f.readBytes(self.node_name_length).decode("UTF-8").rstrip("\0")
		self.index = f.readUByte()
		self.unk091 = f.readUByte()
		self.unk092 = f.readUByte()
		self.matrix = [
			f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat(),
			f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat(),
			f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat(),
			f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat()
			]
		self.childCount = f.readUInt()
		

class ltb_vert:
	position = []
	normal = []
	weights = []
	texcoord = []
	binormal = []
	tangent = []
	

class ltb_unk061:
	vert_pos = 0
	vert_count = 0
	unk072 = 0			# 4 bone indices
	unk073 = 0
	unk074 = 0
	unk075 = 0
	face_count = 0		# 3 times face count?
	def read_unk061(self, f=NoeBitStream()):
		self.vert_pos = f.readUShort()
		self.vert_count = f.readUShort()
		self.unk072 = f.readUByte()
		self.unk073 = f.readUByte()
		self.unk074 = f.readUByte()
		self.unk075 = f.readUByte()
		if self.unk072 == 0xFF:
			self.unk072 = 0
		if self.unk073 == 0xFF:
			self.unk073 = 0
		if self.unk074 == 0xFF:
			self.unk074 = 0
		if self.unk075 == 0xFF:
			self.unk075 = 0
		self.face_count = f.readUInt()
		
	

class ltb_geo:
	unk038 = 0
	unk039 = 0
	unk041 = 0
	unk042 = 0
	unk043 = 0
	unk044 = 0
	unk045 = 0
	unk046 = 0
	unk047 = 0		# addr to small table
	vertex_count = 0
	face_count = 0
	unk050 = 0		# Vertex Format?
	unk040 = 0		# Vertex Format?
	unk051 = []
	unk052 = 0
	unk053 = 0
	unk054 = 0
	unk055 = 0
	unk056 = 0
	unk057 = 0
	verts = ltb_vert()
	faces = []
	unk060 = 0		# mesh table? or bone palette?
	unk061 = []		# mesh table? or bone palette?
	unk062 = 0
	unk063 = []
	
	def guessTableAddr(self, limit, faceCount, f=NoeBitStream()):
		pos = f.tell()
		c = 0
		i = 1
		p = ltb_unk061()
		c = pos
		stop = False
		f.seek(-4, NOESEEK_REL)
		if f.readUInt() > 0:
			while i < limit and stop == False:
				f.seek((pos - (i * 0x0C) - 0x04), NOESEEK_ABS)
				if f.readUInt() == i:
					p.read_unk061(f)
					if p.face_count <= faceCount:
						c = f.tell() - 0x10
						stop = True
				i = i + 1
		f.seek(pos, NOESEEK_ABS)
		return c
	
	def read_geo(self, f=NoeBitStream()):
		i = 1
		ii = 1
		self.verts = ltb_vert()
		weight = []
		boneid = []
		vertex_addr = 0
		vertex_stride = 0
		unk040_addr = 0
		unk60_addr = 0
		self.unk038 = f.readUInt()
		self.unk039 = f.readUInt()
		self.unk041 = f.readUInt()
		self.unk042 = f.readUInt()
		self.unk043 = f.readUInt()
		self.unk044 = f.readUInt()
		self.unk045 = f.readUByte()
		self.unk046 = f.readUInt()
		self.unk047 = f.readUInt()
		unk040_addr = f.tell() + self.unk047
		self.vertex_count = f.readUInt()
		self.face_count = f.readUInt()
		self.unk050 = f.readUInt()
		self.unk040 = f.readUByte()
		
		if self.unk040 > 0:
			self.unk051 = [int] * self.unk040
		
		for i in range(0, self.unk040):
			self.unk051[i] = f.readUByte()
			
		self.unk052 = f.readUShort()
		self.unk053 = f.readUShort()
		self.unk054 = f.readUShort()
		self.unk055 = f.readUInt()
		self.unk056 = f.readUInt()
		self.unk057 = f.readUInt()
		vertex_addr = f.tell()
		f.seek(unk040_addr, NOESEEK_ABS)
		unk60_addr = self.guessTableAddr(((unk040_addr - vertex_addr) / 12), (self.face_count * 3), f)
		vertex_stride = int((unk60_addr - vertex_addr - (self.face_count * 6)) / self.vertex_count)
		vertex_stride += int((2 - (vertex_stride % 2)) % 2)
		vertex_addr = unk60_addr - (self.face_count * 6) - (self.vertex_count * vertex_stride)
		
		
		if self.vertex_count > 0:
			self.verts.position = [NoeVec3] * self.vertex_count
			self.verts.weights = [NoeVertWeight] * self.vertex_count
			self.verts.normal = [NoeVec3] * self.vertex_count
			self.verts.texcoord = [NoeVec3] * self.vertex_count
			self.verts.binormal = [NoeVec3] * self.vertex_count
			self.verts.tangent = [NoeVec3] * self.vertex_count
			
		
		for i in range(0, self.vertex_count):
			f.seek((vertex_addr + (i * vertex_stride)), NOESEEK_ABS)
			self.verts.position[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
			self.verts.normal[i] = NoeVec3((0.0, 0.0, 0.0))
			self.verts.texcoord[i] = NoeVec3((0.0, 0.0, 0.0))
			self.verts.binormal[i] = NoeVec3((0.0, 0.0, 0.0))
			self.verts.tangent[i] = NoeVec3((0.0, 0.0, 0.0))
			weight = [1.0, 0.0, 0.0, 0.0]
			boneid = [0, 0, 0, 0]
			
			
			if vertex_stride == 32:
				self.verts.normal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.texcoord[i] = NoeVec3((f.readFloat(), 1.0 - f.readFloat(), 0))
				
			elif vertex_stride == 36:
				weight = [f.readFloat(), 0.0, 0.0, 0.0]
				weight[1] = 1.0 - weight[0]
				self.verts.normal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.texcoord[i] = NoeVec3((f.readFloat(), 1.0 - f.readFloat(), 0))
				
			elif vertex_stride == 40:
				weight = [f.readFloat(), f.readFloat(), 0.0, 0.0]
				weight[2] = 1.0 - (weight[0] + weight[1])
				self.verts.normal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.texcoord[i] = NoeVec3((f.readFloat(), 1.0 - f.readFloat(), 0))
				
			elif vertex_stride == 44:
				weight = [f.readFloat(), f.readFloat(), f.readFloat(), 0.0]
				weight[3] = 1.0 - (weight[0] + weight[1] + weight[2])
				self.verts.normal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.texcoord[i] = NoeVec3((f.readFloat(), 1.0 - f.readFloat(), 0))
				
			elif vertex_stride == 56:
				self.verts.normal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.texcoord[i] = NoeVec3((f.readFloat(), 1.0 - f.readFloat(), 0))
				self.verts.binormal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.tangent[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				
			elif vertex_stride == 60:
				weight = [f.readFloat(), 0.0, 0.0, 0.0]
				weight[1] = 1.0 - weight[0]
				self.verts.normal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.texcoord[i] = NoeVec3((f.readFloat(), 1.0 - f.readFloat(), 0))
				self.verts.binormal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.tangent[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				
			elif vertex_stride == 64:
				weight = [f.readFloat(), f.readFloat(), 0.0, 0.0]
				weight[2] = 1.0 - (weight[0] + weight[1])
				self.verts.normal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.texcoord[i] = NoeVec3((f.readFloat(), 1.0 - f.readFloat(), 0))
				self.verts.binormal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.tangent[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				
			elif vertex_stride == 68:
				weight = [f.readFloat(), f.readFloat(), f.readFloat(), 0.0]
				weight[3] = 1.0 - (weight[0] + weight[1] + weight[2])
				self.verts.normal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.texcoord[i] = NoeVec3((f.readFloat(), 1.0 - f.readFloat(), 0))
				self.verts.binormal[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				self.verts.tangent[i] = NoeVec3((f.readFloat(), f.readFloat(), f.readFloat()))
				
			self.verts.weights[i] = NoeVertWeight(boneid, weight)
		
		f.seek((vertex_addr + (self.vertex_count * vertex_stride)), NOESEEK_ABS)
		
		if self.face_count > 0:
			self.faces = [int] * (self.face_count * 3)
		
		for i in range(0, self.face_count * 3):
			self.faces[i] = f.readUShort()
		
		if unk60_addr < unk040_addr:
			f.seek(unk60_addr, NOESEEK_ABS)
			self.unk060 = f.readUInt()
			
			if self.unk060 > 0:
				self.unk061 = [ltb_unk061] * self.unk060
			
			for i in range(0, self.unk060):
				self.unk061[i] = ltb_unk061()
				self.unk061[i].read_unk061(f)
				for ii in range(0, self.unk061[i].vert_count):
					self.verts.weights[ii + self.unk061[i].vert_pos].indices = [self.unk061[i].unk072, self.unk061[i].unk073, self.unk061[i].unk074, self.unk061[i].unk075]
					
		
		if self.unk047 > 0:
			f.seek(unk040_addr, NOESEEK_ABS)
			self.unk062 = f.readUByte()
			self.unk063 = [int] * self.unk062
			for i in range(0, self.unk062):
				self.unk063[i] = f.readUByte()
				
			
		
	

class ltb_mesh:
	mesh_name_length = 0
	mesh_name = ""
	lod_count = 0
	unk031 = []
	unk036 = 0
	unk037 = 0
	lods = []
	def read_mesh(self, f=NoeBitStream()):
		i = 1
		m = 1
		
		self.mesh_name_length = f.readUShort()
		self.mesh_name = f.readBytes(self.mesh_name_length).decode("UTF-8").rstrip("\0")
		self.lod_count = f.readUInt()
		
		if self.lod_count > 0:
			self.unk031 = [float] * self.lod_count
		
		for i in range(0, self.lod_count):
			self.unk031[i] = f.readFloat()
			
		self.unk036 = f.readUInt()
		self.unk037 = f.readUInt()
		self.lods = [ltb_geo] * self.lod_count
		
		for m in range(0, self.lod_count):
			self.lods[m] = ltb_geo()
			self.lods[m].read_geo(f)
			
		
		

class ltb_file:
	unk001 = 0
	unk002 = 0
	unk003 = 0
	unk004 = 0
	unk005 = 0
	unk006 = 0
	unk007 = 0
	unk008 = 0
	unk009 = 0
	node_count = 0
	mesh_count = 0
	unk012 = 0
	total_face_count = 0
	unk014 = 0
	unk015 = 0
	total_lod_count = 0
	unk017 = 0
	unk018 = 0
	unk019 = 0
	unk020 = 0
	unk021 = 0
	unk022 = 0
	unk057 = 0
	unk058 = ""
	unk023 = 0.0
	unk024 = 0
	unk025 = []
	unk026 = 0
	unk027 = 0
	meshs  = []
	nodes = []
	
	def read_ltb(self, f=NoeBitStream()):
		i = 1
		ii = 1
		self.unk001 = f.readUShort()
		self.unk002 = f.readUShort()
		self.unk003 = f.readUInt()
		self.unk004 = f.readUInt()
		self.unk005 = f.readUInt()
		self.unk006 = f.readUInt()
		self.unk007 = f.readUInt()
		self.unk008 = f.readUInt()
		self.unk009 = f.readUInt()
		self.node_count = f.readUInt()
		self.mesh_count = f.readUInt()
		self.unk012 = f.readUInt()
		self.total_face_count = f.readUInt()
		self.unk014 = f.readUInt()
		self.unk015 = f.readUInt()
		self.total_lod_count = f.readUInt()
		self.unk017 = f.readUInt()
		self.unk018 = f.readUInt()
		self.unk019 = f.readUInt()
		self.unk020 = f.readUInt()
		self.unk021 = f.readUInt()
		self.unk022 = f.readUInt()
		self.unk057 = f.readUShort()
		self.unk058 = f.readBytes(self.unk057).decode("UTF-8").rstrip("\0")
		self.unk023 = f.readFloat()
		self.unk024 = f.readUInt()
		
		if self.unk024 > 0:	# 64bytes, looks like a matrix
			self.unk025 = [[float], [float], [float], [float], [float], [float], [float], [float], [float], [float], [float], [float], [float], [float], [float], [float]] * self.unk024
		
		for i in range(0, self.unk024):
			self.unk025[i] = [
				0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 
				0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
				]
			for ii in range(0, 16):
				self.unk025[i][ii] = f.readFloat()
				
			
		
		
		self.unk026 = f.readUShort()
		self.unk027 = f.readUShort()
		
		self.meshs = [ltb_mesh] * self.mesh_count
		for i in range(0, self.mesh_count):
			self.meshs[i] = ltb_mesh()
			self.meshs[i].read_mesh(f)
			
		
		self.nodes = [ltb_node] * self.node_count
		for i in range(0, self.node_count):
			self.nodes[i] = ltb_node()
			self.nodes[i].read_node(f)
			
	
	def getChildren(self, i):
		c = 0
		p = i
		x = 0
		if i < self.node_count:
			self.nodes[i].children = []
			for c in range(0, self.nodes[i].childCount):
				p = p + 1
				self.nodes[i].children.append(p)
				if p <= self.node_count:
					p = self.getChildren(p)
		return p
	
	def getParent(self):
		for i in range(0, self.node_count):
			self.nodes[i].parent = -1
			for ii in range(0, self.node_count):
				if ii != i and self.nodes[i].parent == -1:
					for iii in range(0, len(self.nodes[ii].children)):
						if self.nodes[ii].children[iii] == int(i):
							self.nodes[i].parent = ii
	
	def create_bone_list(self):
		# generate the parents from the child counts
		self.getChildren(0)
		self.getParent()
		
		BoneList = []
		BoneMatrix43 = NoeMat43()
		BoneMatrix44 = NoeMat44()
		BoneName = ""
		ParentName = ""
		i = 0
		NumBones = self.node_count
		if NumBones > 0:
			BoneList = [NoeBone] * NumBones
			for i in range(0, NumBones):
				BoneMatrix44 = NoeMat44((
					NoeVec4((self.nodes[i].matrix[0], self.nodes[i].matrix[4], self.nodes[i].matrix[8], self.nodes[i].matrix[12])),
					NoeVec4((self.nodes[i].matrix[1], self.nodes[i].matrix[5], self.nodes[i].matrix[9], self.nodes[i].matrix[13])),
					NoeVec4((self.nodes[i].matrix[2], self.nodes[i].matrix[6], self.nodes[i].matrix[10], self.nodes[i].matrix[14])),
					NoeVec4((self.nodes[i].matrix[3], self.nodes[i].matrix[7], self.nodes[i].matrix[11], self.nodes[i].matrix[15]))
					))
				
				BoneMatrix43 = BoneMatrix44.toMat43()
				#BoneMatrix43 = BoneMatrix43.inverse()
				
				BoneName = "bone%03i" % i
				ParentName = "bone%03i" % self.nodes[i].parent
				
				if self.nodes[i].node_name != "":
					BoneName = self.nodes[i].node_name
				
				if self.nodes[i].parent > -1 and self.nodes[i].parent < NumBones:
					if self.nodes[self.nodes[i].parent].node_name != "":
						ParentName = self.nodes[self.nodes[i].parent].node_name
					
					BoneList[i] = (NoeBone(i, BoneName, BoneMatrix43, ParentName, self.nodes[i].parent))
					#BoneList[i] = (NoeBone(i, self.nodes[i].node_name, BoneMatrix43, None, -1))
				else:
					BoneList[i] = (NoeBone(i, self.nodes[i].node_name, BoneMatrix43, None, -1))
		return BoneList
	
	def create_mesh_list(self, f = NoeBitStream()):
		mshList = []
		
		if self.mesh_count > 0:
			mshList = [NoeMesh] * self.mesh_count
		
		for i in range(0, self.mesh_count):
			mshList[i] = NoeMesh(self.meshs[i].lods[0].faces, self.meshs[i].lods[0].verts.position, self.meshs[i].mesh_name)
			#mshList[i].setIndices(self.meshs[i].lods[0].faces)
			#mshList[i].setPositions(self.meshs[i].lods[0].verts.position)
			mshList[i].setNormals(self.meshs[i].lods[0].verts.normal)
			mshList[i].setUVs(self.meshs[i].lods[0].verts.texcoord, 0)
			mshList[i].setWeights(self.meshs[i].lods[0].verts.weights)
		return mshList

def noepyLoadModel(data, mdlList):
	f = NoeBitStream(data)
	if f.readUInt() != NOEPY_HEADER:
		return 0
	
	#  Check if there is a texture library
	#filename = rapi.getInputName()
	#filename = filename[:-3] + {'LTB': 'DTX'}[filename[-3:].upper()]
	#if rapi.checkFileExists(filename):
	#	t = NoeBitStream(rapi.loadIntoByteArray(filename))
	
	
	f.seek(0x00, NOESEEK_ABS)
	ltb = ltb_file()
	ltb.read_ltb(f)
	
	BoneList = []
	MeshList = []
	
	BoneList = ltb.create_bone_list()
	MeshList = ltb.create_mesh_list(f)
	
	mdl = NoeModel()
	
	mdl.setBones(BoneList)
	mdl.setMeshes(MeshList)
	
	mdlList.append(mdl)
	return 1

def noepyCheckType(data):
	if len(data) < 8:
		return 0
	f = NoeBitStream(data)
	if f.readUInt() != NOEPY_HEADER:
		return 0
	return 1


def registerNoesisTypes():
	if showConsole == True:
		noesis.logPopup()
		for i in range(0, 30): print("\n")
	handle = noesis.register("Lith Tech Binary (PC)", ".ltb")
	noesis.setHandlerTypeCheck(handle, noepyCheckType)
	noesis.setHandlerLoadModel(handle, noepyLoadModel)
	return 1
You do not have the required permissions to view the files attached to this post.
Maxscript and other finished work I've done can be found on my DeviantArt account

Post Reply