XeNTaX Forum Index
Forum MultiEx Commander Tools Tools Home
It is currently Mon May 29, 2017 12:22 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 47 posts ]  Go to page 1, 2, 3, 4  Next
Author Message
 Post subject: Noesis tutorial Basic Model
PostPosted: Mon Nov 28, 2011 3:07 am 
Offline
Moderator
User avatar

Joined: Sun May 18, 2008 3:01 pm
Posts: 2397
Has thanked: 56 times
Have thanks: 1134 times














You can make the ads go away by registering

First thing is a quote from Señor Casaroja.

Code:
Yo bebo cuando tengo ocasión, ya veces cuando no tengo ocasión.


Ok so noesis now supports python scripting to import and export 3d models.
There are several great reasons to use noesis over other methods.
1.Tons of supported functions are already ready for us and do not need to be added like xbox and ps2 images.
2.No need to compile scripts can be tested in real time.
3.Very fast scripting language.
http://oasis.xentax.com/index.php?content=downloads


So the first thing you will want is a file format to add to noesis.
In our example we will use [X360]Strike Witches Shirogane no Tsubasa

First thing is use quickbms to extract our files the script is here for this game
viewtopic.php?f=16&t=7751

We end up with a bunch of files the files we care about are
player01.bin the file to extract
the texture files .dds
and the model files .gmo
So we will look at CH01_TOP.GMO

So first thing we need is a bare minimum noesis script

Code:
#Noesis Python model import+export test module, imports/exports some data from/to a made-up format

from inc_noesis import *

import noesis

#rapi methods should only be used during handler callbacks
import rapi

#registerNoesisTypes is called by Noesis to allow the script to register formats.
#Do not implement this function in script files unless you want them to be dedicated format modules!
def registerNoesisTypes():
   handle = noesis.register("Strike Witches Shirogane no Tsubasa", ".gmo")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadModel(handle, noepyLoadModel) #see also noepyLoadModelRPG
       #noesis.setHandlerWriteModel(handle, noepyWriteModel)
       #noesis.setHandlerWriteAnim(handle, noepyWriteAnim)
   noesis.logPopup()
       #print("The log can be useful for catching debug prints from preview loads.\nBut don't leave it on when you release your script, or it will probably annoy people.")
   return 1

NOEPY_HEADER = "GXXM0124"

#check if it's this type based on the data
def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 16:
      return 0
   if bs.readBytes(16).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
      return 0
   return 1       

#load the model
def noepyLoadModel(data, mdlList):
   ctx = rapi.rpgCreateContext()
   bs = NoeBitStream(data)
   rapi.rpgClearBufferBinds()   
   return 1


So lets look at what we have here
handle = noesis.register("Strike Witches Shirogane no Tsubasa", ".gmo")
This line tells noesis what file type to use this script with
The first part is a text line that tells the user the name of the game "Strike Witches Shirogane no Tsubasa"
the second part is the actual file type of the format. ".gmo"

The next part
NOEPY_HEADER = "GXXM0124"
This is what this file format always starts out with and is very important to make sure noesis loads the correct script with our format.
We use this here

Code:
#check if it's this type based on the data
def noepyCheckType(data):
bs = NoeBitStream(data)
if len(data) < 16:
return 0
if bs.readBytes(16).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
return 0
return 1


so in our example file the header is always
GXXM0124 with padding 00's to make it 16 bytes
so in noesis we did 2 checks
the first if len(data) < 16:
return 0
this says if our file is < 16 bytes it cant be a valid file
The next thing we do is declare a file stream
bs = NoeBitStream(data)
now with our file stream open we read 16 bytes as a string and see if it matches our header
if bs.readBytes(16).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
return 0
so then if both of these are true we return a 1 at the end and noesis will continue on to the next part of our script.
def noepyLoadModel(data, mdlList):
this says start the model loading process
then we need to create a context for our model
ctx = rapi.rpgCreateContext()
the next command clears out all buffers this is good to add at the end of your script to free up memory it also prevents noesis from throwing an error when no model is loaded
rapi.rpgClearBufferBinds()
then finally we end our code with a success command
return 1

now if you run this code you should get this when you open the model
Image

Now we want to start reading our format so
the first interesting part of our data is at 0x1C
So we see to that offset
bs.seek(0x1C, NOESEEK_ABS) #Seek to header info
Here i see 3 values i want to read as little endian values. "normally 360 games are big endian games this game was just written so bad they dint bother to change it from pc format"
hdrInfo = bs.read("iii")
if this was big endian all you have to do in python is change it to this
hdrInfo = bs.read(">iii")
the i stands for integer in python this is a great reference table for the possible values
http://docs.python.org/library/struct.html
http://www.tutorialspoint.com/python/py ... rators.htm
this command stored 3 little endian ints into the array hdrInfo
so if we do
print(hdrInfo)
we get this in our output window
(1, 23, 1)
which is perfect as the data we read looked like this
Code:
01 00 00 00 17 00 00 00 01 00 00 00

the next piece of information we want is at offset 0x34
so ill seek to that offset but this time i will seek relative to my current position 0x28
bs.seek(0xC, NOESEEK_REL) #Seek past junk
This next value is the vertex count so
VCount = bs.read("i")
then we skip 4 bytes
bs.seek(0x4, NOESEEK_REL) #Seek past junk
and read the face count
FCount = bs.read("i")
OK that's all we really need from the header so now we seek to the start of the data.
bs.seek(0x70, NOESEEK_ABS) #Seek to File Start
ok so here remember we read those 3 values into our array we will use them now those values represented
Texture Count 1
Bone Count 23
Material Count 1
so we make a loop to read our texture name(s)
TexNames = []
for i in range(0, hdrInfo[0]):
TexNames.append (bs.readBytes(40).decode("ASCII").rstrip("\0"))
and we will print it to verify it looks right
print(TexNames)
So now our output looks like this
(1, 23, 1)
['ch01_mm.tga']
Perfect.
So your script should be like this now.
Code:
#Noesis Python model import+export test module, imports/exports some data from/to a made-up format

from inc_noesis import *

import noesis

#rapi methods should only be used during handler callbacks
import rapi

#registerNoesisTypes is called by Noesis to allow the script to register formats.
#Do not implement this function in script files unless you want them to be dedicated format modules!
def registerNoesisTypes():
   handle = noesis.register("Strike Witches Shirogane no Tsubasa", ".gmo")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadModel(handle, noepyLoadModel) #see also noepyLoadModelRPG
       #noesis.setHandlerWriteModel(handle, noepyWriteModel)
       #noesis.setHandlerWriteAnim(handle, noepyWriteAnim)
   noesis.logPopup()
       #print("The log can be useful for catching debug prints from preview loads.\nBut don't leave it on when you release your script, or it will probably annoy people.")
   return 1

NOEPY_HEADER = "GXXM0124"

#check if it's this type based on the data
def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 16:
      return 0
   if bs.readBytes(16).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
      return 0
   return 1       

#load the model
def noepyLoadModel(data, mdlList):
   ctx = rapi.rpgCreateContext()
   bs = NoeBitStream(data)
   bs.seek(0x1C, NOESEEK_ABS) #Seek to header info
   hdrInfo = bs.read("iii")
   print(hdrInfo)
   bs.seek(0xC, NOESEEK_REL) #Seek past junk
   VCount = bs.read("i")
   bs.seek(0x4, NOESEEK_REL) #Seek past junk
   FCount = bs.read("i")
   bs.seek(0x70, NOESEEK_ABS) #Seek to File Start
   TexNames = []
   for i in range(0, hdrInfo[0]):
      TexNames.append (bs.readBytes(40).decode("ASCII").rstrip("\0"))
   print(TexNames)
   rapi.rpgClearBufferBinds()   
   return 1

Ok next come the bones
The bone format is 32 bytes bone name and 0x40 bytes bone data
so for now we will just import the name and worry about the data later
BoneNames = []
for i in range(0, hdrInfo[1]):
BoneNames.append (bs.readBytes(32).decode("ASCII").rstrip("\0"))
bs.seek(0x40, NOESEEK_REL) #Seek past bone stuff
print(BoneNames)
and the output from the print command is
Code:
['ch01_top_BackCloth', 'ch01_top_BackHair', 'ch01_top_BackHair2', 'ch01_top_FrontCloth', 'ch01_top_FrontHair', 'ch01_top_Gun', 'ch01_top_Head', 'ch01_top_LeftArm', 'ch01_top_LeftEar', 'ch01_top_LeftFinger', 'ch01_top_LeftForeArm', 'ch01_top_LeftHand', 'ch01_top_LeftShoulder', 'ch01_top_RightArm', 'ch01_top_RightEar', 'ch01_top_RightFinger', 'ch01_top_RightForeArm', 'ch01_top_RightHand', 'ch01_top_RightShoulder', 'ch01_top_Spine', 'ch01_top_Spine1', 'ch01_top_Top', 'ch01_top_neck']

So next is the material section
this section's size in total is 0x130
and is broken down by
0xC0 -stuff
0x28 -Material Name
0x48 -stuff
so for now we will once again read in the name
MaterialNames = []
for i in range(0, hdrInfo[2]):
bs.seek(0xC0, NOESEEK_REL) #Seek past Material stuff
MaterialNames.append (bs.readBytes(40).decode("ASCII").rstrip("\0"))
bs.seek(0x48, NOESEEK_REL) #Seek past Material stuff
print(MaterialNames)
Ok so now we are at the vertex data
0xA68
each vertex is 0x58 in size
so noesis has a very nice way to get this data for us.
VertBuff = bs.readBytes(VCount[0] * 0x58)
so now that we read all that data into a buffer we can parse that buffer
rapi.rpgBindPositionBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 0)
this says read 3 flaots at position 0 in the VertBuff and that each vertex is 88 bytes
Now we can test this quickly with these lines here
rapi.rpgCommitTriangles(None, noesis.RPGEODATA_USHORT, VCount[0], noesis.RPGEO_POINTS, 1)
mdl = rapi.rpgConstructModel()
mdlList.append(mdl) #important, don't forget to put your loaded model in the mdlList

So now we have this
Image
and here is our code so far
Code:
#Noesis Python model import+export test module, imports/exports some data from/to a made-up format

from inc_noesis import *

import noesis

#rapi methods should only be used during handler callbacks
import rapi

#registerNoesisTypes is called by Noesis to allow the script to register formats.
#Do not implement this function in script files unless you want them to be dedicated format modules!
def registerNoesisTypes():
   handle = noesis.register("Strike Witches Shirogane no Tsubasa", ".gmo")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadModel(handle, noepyLoadModel) #see also noepyLoadModelRPG
       #noesis.setHandlerWriteModel(handle, noepyWriteModel)
       #noesis.setHandlerWriteAnim(handle, noepyWriteAnim)
   noesis.logPopup()
       #print("The log can be useful for catching debug prints from preview loads.\nBut don't leave it on when you release your script, or it will probably annoy people.")
   return 1

NOEPY_HEADER = "GXXM0124"

#check if it's this type based on the data
def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 16:
      return 0
   if bs.readBytes(16).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
      return 0
   return 1       

#load the model
def noepyLoadModel(data, mdlList):
   ctx = rapi.rpgCreateContext()
   bs = NoeBitStream(data)
   bs.seek(0x1C, NOESEEK_ABS) #Seek to header info
   hdrInfo = bs.read("iii")
   print(hdrInfo)
   bs.seek(0xC, NOESEEK_REL) #Seek past junk
   VCount = bs.read("i")
   bs.seek(0x4, NOESEEK_REL) #Seek past junk
   FCount = bs.read("i")
   bs.seek(0x70, NOESEEK_ABS) #Seek to File Start

   TexNames = []
   for i in range(0, hdrInfo[0]):
      TexNames.append (bs.readBytes(40).decode("ASCII").rstrip("\0"))
   print(TexNames)


   BoneNames = []
   for i in range(0, hdrInfo[1]):
      BoneNames.append (bs.readBytes(32).decode("ASCII").rstrip("\0"))
      bs.seek(0x40, NOESEEK_REL) #Seek past bone stuff
   print(BoneNames)

   MaterialNames = []
   for i in range(0, hdrInfo[2]):
      bs.seek(0xC0, NOESEEK_REL) #Seek past Material stuff
      MaterialNames.append (bs.readBytes(40).decode("ASCII").rstrip("\0"))
      bs.seek(0x48, NOESEEK_REL) #Seek past Material stuff
   print(MaterialNames)

   VertBuff = bs.readBytes(VCount[0] * 0x58)
   rapi.rpgBindPositionBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 0)
   rapi.rpgCommitTriangles(None, noesis.RPGEODATA_USHORT, VCount[0], noesis.RPGEO_POINTS, 1)
   mdl = rapi.rpgConstructModel()
   mdlList.append(mdl)         #important, don't forget to put your loaded model in the mdlList

   rapi.rpgClearBufferBinds()   
   return 1

so now that we know our verts are good we can try to load the faces so
comment out
#rapi.rpgCommitTriangles(None, noesis.RPGEODATA_USHORT, VCount[0], noesis.RPGEO_POINTS, 1)
and put
FaceBuff = bs.readBytes(FCount[0] * 2)
rapi.rpgCommitTriangles(FaceBuff, noesis.RPGEODATA_USHORT, FCount[0], noesis.RPGEO_TRIANGLE, 1)
you might notice the model looks transparent without turning off face culling if thats the case just add this line
rapi.rpgSetOption(noesis.RPGOPT_TRIWINDBACKWARD, 1)

So now you have
Image
and the code
Code:
#Noesis Python model import+export test module, imports/exports some data from/to a made-up format
from inc_noesis import *
import noesis
#rapi methods should only be used during handler callbacks
import rapi
#registerNoesisTypes is called by Noesis to allow the script to register formats.
#Do not implement this function in script files unless you want them to be dedicated format modules!
def registerNoesisTypes():
   handle = noesis.register("Strike Witches Shirogane no Tsubasa", ".gmo")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadModel(handle, noepyLoadModel) #see also noepyLoadModelRPG
       #noesis.setHandlerWriteModel(handle, noepyWriteModel)
       #noesis.setHandlerWriteAnim(handle, noepyWriteAnim)
   noesis.logPopup()
       #print("The log can be useful for catching debug prints from preview loads.\nBut don't leave it on when you release your script, or it will probably annoy people.")
   return 1

NOEPY_HEADER = "GXXM0124"

#check if it's this type based on the data
def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 16:
      return 0
   if bs.readBytes(16).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
      return 0
   return 1       

#load the model
def noepyLoadModel(data, mdlList):
   ctx = rapi.rpgCreateContext()
   rapi.rpgSetOption(noesis.RPGOPT_TRIWINDBACKWARD, 1)
   bs = NoeBitStream(data)
   bs.seek(0x1C, NOESEEK_ABS) #Seek to header info
   hdrInfo = bs.read("iii")
   print(hdrInfo)
   bs.seek(0xC, NOESEEK_REL) #Seek past junk
   VCount = bs.read("i")
   bs.seek(0x4, NOESEEK_REL) #Seek past junk
   FCount = bs.read("i")
   bs.seek(0x70, NOESEEK_ABS) #Seek to File Start

   TexNames = []
   for i in range(0, hdrInfo[0]):
      TexNames.append (bs.readBytes(40).decode("ASCII").rstrip("\0"))
   print(TexNames)


   BoneNames = []
   for i in range(0, hdrInfo[1]):
      BoneNames.append (bs.readBytes(32).decode("ASCII").rstrip("\0"))
      bs.seek(0x40, NOESEEK_REL) #Seek past bone stuff
   print(BoneNames)

   MaterialNames = []
   for i in range(0, hdrInfo[2]):
      bs.seek(0xC0, NOESEEK_REL) #Seek past Material stuff
      MaterialNames.append (bs.readBytes(40).decode("ASCII").rstrip("\0"))
      bs.seek(0x48, NOESEEK_REL) #Seek past Material stuff
   print(MaterialNames)

   VertBuff = bs.readBytes(VCount[0] * 0x58)
   rapi.rpgBindPositionBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 0)
   #rapi.rpgCommitTriangles(None, noesis.RPGEODATA_USHORT, VCount[0], noesis.RPGEO_POINTS, 1)
   FaceBuff = bs.readBytes(FCount[0] * 2)
   rapi.rpgCommitTriangles(FaceBuff, noesis.RPGEODATA_USHORT, FCount[0], noesis.RPGEO_TRIANGLE, 1)
   mdl = rapi.rpgConstructModel()
   mdlList.append(mdl)         #important, don't forget to put your loaded model in the mdlList

   rapi.rpgClearBufferBinds()   
   return 1

Ok so now we will add in our normals and uv coordinates.
rapi.rpgBindNormalBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 12)
rapi.rpgBindUV1BufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 48)

so now that we have our uv's all set we want to test them so lets make a material and assign the texture we think is needed to it.
so we need 2 arrays
texList = []
matList = []
Then we create our material with a diffuse texture
rapi.rpgSetMaterial("CH01_MM")
material = NoeMaterial("CH01_MM", "")
material.setTexture("CH01_MM.DDS")
matList.append(material)
and after we construct the model we pass
mdl.setModelMaterials(NoeModelMaterials(texList, matList))

So now we should get this result
Image
and this should be your code so far
Code:
#Noesis Python model import+export test module, imports/exports some data from/to a made-up format
from inc_noesis import *
import noesis
#rapi methods should only be used during handler callbacks
import rapi
#registerNoesisTypes is called by Noesis to allow the script to register formats.
#Do not implement this function in script files unless you want them to be dedicated format modules!
def registerNoesisTypes():
   handle = noesis.register("Strike Witches Shirogane no Tsubasa", ".gmo")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadModel(handle, noepyLoadModel) #see also noepyLoadModelRPG
       #noesis.setHandlerWriteModel(handle, noepyWriteModel)
       #noesis.setHandlerWriteAnim(handle, noepyWriteAnim)
   noesis.logPopup()
       #print("The log can be useful for catching debug prints from preview loads.\nBut don't leave it on when you release your script, or it will probably annoy people.")
   return 1

NOEPY_HEADER = "GXXM0124"

#check if it's this type based on the data
def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 16:
      return 0
   if bs.readBytes(16).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
      return 0
   return 1       

#load the model
def noepyLoadModel(data, mdlList):
   ctx = rapi.rpgCreateContext()
   rapi.rpgSetOption(noesis.RPGOPT_TRIWINDBACKWARD, 1)
   bs = NoeBitStream(data)
   bs.seek(0x1C, NOESEEK_ABS) #Seek to header info
   hdrInfo = bs.read("iii")
   print(hdrInfo)
   bs.seek(0xC, NOESEEK_REL) #Seek past junk
   VCount = bs.read("i")
   bs.seek(0x4, NOESEEK_REL) #Seek past junk
   FCount = bs.read("i")
   bs.seek(0x70, NOESEEK_ABS) #Seek to File Start

   texList = []
   matList = []
   TexNames = []
   BoneNames = []
   MaterialNames = []

   for i in range(0, hdrInfo[0]):
      TexNames.append (bs.readBytes(40).decode("ASCII").rstrip("\0"))
   print(TexNames)

   for i in range(0, hdrInfo[1]):
      BoneNames.append (bs.readBytes(32).decode("ASCII").rstrip("\0"))
      bs.seek(0x40, NOESEEK_REL) #Seek past bone stuff
   print(BoneNames)

   for i in range(0, hdrInfo[2]):
      bs.seek(0xC0, NOESEEK_REL) #Seek past Material stuff
      MaterialNames.append (bs.readBytes(40).decode("ASCII").rstrip("\0"))
      bs.seek(0x48, NOESEEK_REL) #Seek past Material stuff
   print(MaterialNames)

   mname = "CH01_MM"
   material = NoeMaterial("CH01_MM", "")
   material.setTexture("CH01_MM.DDS")
   matList.append(material)

   VertBuff = bs.readBytes(VCount[0] * 0x58)
   rapi.rpgBindPositionBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 0)
   rapi.rpgBindNormalBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 12)
   rapi.rpgBindUV1BufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 48)
   FaceBuff = bs.readBytes(FCount[0] * 2)
   rapi.rpgSetMaterial("CH01_MM")
   rapi.rpgCommitTriangles(FaceBuff, noesis.RPGEODATA_USHORT, FCount[0], noesis.RPGEO_TRIANGLE, 1)

   mdl = rapi.rpgConstructModel()
   mdl.setModelMaterials(NoeModelMaterials(texList, matList))

   mdlList.append(mdl)         #important, don't forget to put your loaded model in the mdlList
   rapi.rpgClearBufferBinds()   
   return 1

Now in the model CH01_TOP.GMO there is only one material and one texture but in CH01_UNDER.GMO There are 3 textures and 3 materials.
So in order to fix this we need to find out more about our materials.
I have found the relevant information in the material and here is the structure

Structure Material {
Long -Texture ID
0xBC -unkown / not needed "its probably some color information about the material"
Material Name 0x20
0x10 -unkown / not needed
Long - Material Start Indecie
Long - Number of indecies in the material
0x38 -unkown / not needed
}

So now that we know How our material is made up lets get that information stored for use.
we will change
MaterialNames = []
for i in range(0, hdrInfo[2]):
bs.seek(0xC0, NOESEEK_REL) #Seek past Material stuff
MaterialNames.append (bs.readBytes(40).decode("ASCII").rstrip("\0"))
bs.seek(0x48, NOESEEK_REL) #Seek past Material stuff
print(MaterialNames)

into
MaterialInfo = []
for i in range(0, hdrInfo[2]):
TexID = bs.read("i")
bs.seek(0xBC, NOESEEK_REL) #Seek past Material stuff
MaterialName = (bs.readBytes(32).decode("ASCII").rstrip("\0"))
bs.seek(0x10, NOESEEK_REL) #Seek past Material stuff
IndStart = bs.read("i")
IndCount = bs.read("i")
bs.seek(0x38, NOESEEK_REL) #Seek past Material stuff
MaterialInfo.append([MaterialName, TexID[0], IndStart[0], IndCount[0]])
print(MaterialInfo)

Now we will add a loop to create our materials with the texture assigned

for i in range(0, hdrInfo[2]):
material = NoeMaterial(MaterialInfo[i][0],"")
material.setTexture(TexNames[MaterialInfo[i][1]] + ".dds")
matList.append(material)
print(matList)

Now we need to have our faces load with the correct material so we use this
for i in range(0, hdrInfo[2]):
FaceBuff = bs.readBytes(MaterialInfo[i][3] * 2)
rapi.rpgSetMaterial(MaterialInfo[i][0]) #call this before before commit triangles it assignes this set of triangles to the material name given
rapi.rpgCommitTriangles(FaceBuff, noesis.RPGEODATA_USHORT, MaterialInfo[i][3], noesis.RPGEO_TRIANGLE, 1)

So now both models load with the correct textures and our code should look like this.
Code:
#Noesis Python model import+export test module, imports/exports some data from/to a made-up format
from inc_noesis import *
import noesis
#rapi methods should only be used during handler callbacks
import rapi
#registerNoesisTypes is called by Noesis to allow the script to register formats.
#Do not implement this function in script files unless you want them to be dedicated format modules!
def registerNoesisTypes():
   handle = noesis.register("Strike Witches Shirogane no Tsubasa", ".gmo")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadModel(handle, noepyLoadModel) #see also noepyLoadModelRPG
       #noesis.setHandlerWriteModel(handle, noepyWriteModel)
       #noesis.setHandlerWriteAnim(handle, noepyWriteAnim)
   noesis.logPopup()
       #print("The log can be useful for catching debug prints from preview loads.\nBut don't leave it on when you release your script, or it will probably annoy people.")
   return 1

NOEPY_HEADER = "GXXM0124"

#check if it's this type based on the data
def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 16:
      return 0
   if bs.readBytes(16).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
      return 0
   return 1       

#load the model
def noepyLoadModel(data, mdlList):
   ctx = rapi.rpgCreateContext()
   rapi.rpgSetOption(noesis.RPGOPT_TRIWINDBACKWARD, 1)
   bs = NoeBitStream(data)
   bs.seek(0x1C, NOESEEK_ABS) #Seek to header info
   hdrInfo = bs.read("iii")
   print(hdrInfo)
   bs.seek(0xC, NOESEEK_REL) #Seek past junk
   VCount = bs.read("i")
   bs.seek(0x4, NOESEEK_REL) #Seek past junk
   FCount = bs.read("i")
   bs.seek(0x70, NOESEEK_ABS) #Seek to File Start

   texList = []
   matList = []
   TexNames = []
   BoneNames = []
   MaterialInfo = []

   for i in range(0, hdrInfo[0]):
      TexNames.append (rapi.getExtensionlessName(bs.readBytes(40).decode("ASCII").rstrip("\0")))
   print(TexNames)

   for i in range(0, hdrInfo[1]):
      BoneNames.append (bs.readBytes(32).decode("ASCII").rstrip("\0"))
      bs.seek(0x40, NOESEEK_REL) #Seek past bone stuff
   print(BoneNames)

   for i in range(0, hdrInfo[2]):
      TexID = bs.read("i")
      bs.seek(0xBC, NOESEEK_REL) #Seek past Material stuff
      MaterialName = (bs.readBytes(32).decode("ASCII").rstrip("\0"))
      bs.seek(0x10, NOESEEK_REL) #Seek past Material stuff
      IndStart = bs.read("i")
      IndCount = bs.read("i")
      bs.seek(0x38, NOESEEK_REL) #Seek past Material stuff
      MaterialInfo.append([MaterialName, TexID[0], IndStart[0], IndCount[0]])
   print(MaterialInfo)

   for i in range(0, hdrInfo[2]):
      material = NoeMaterial(MaterialInfo[i][0],"")
      material.setTexture(TexNames[MaterialInfo[i][1]] + ".dds")
      matList.append(material)
      print(matList)

   VertBuff = bs.readBytes(VCount[0] * 0x58)
   rapi.rpgBindPositionBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 0)
   rapi.rpgBindNormalBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 12)
   rapi.rpgBindUV1BufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 88, 48)
   for i in range(0, hdrInfo[2]):
      FaceBuff = bs.readBytes(MaterialInfo[i][3] * 2)
      rapi.rpgSetMaterial(MaterialInfo[i][0])
      rapi.rpgCommitTriangles(FaceBuff, noesis.RPGEODATA_USHORT, MaterialInfo[i][3], noesis.RPGEO_TRIANGLE, 1)
   mdl = rapi.rpgConstructModel()
   mdl.setModelMaterials(NoeModelMaterials(texList, matList))
   mdlList.append(mdl)         #important, don't forget to put your loaded model in the mdlList   
   rapi.rpgClearBufferBinds()   
   return 1


Attachments:


You do not have the required permissions to view the files attached to this post. Register to gain access.



Top
 Profile  
 
 Post subject: Re: Noesis tutorial (WIP) Updated 11/27/2011
PostPosted: Mon Nov 28, 2011 8:31 am 
Offline
Site Admin
User avatar

Joined: Wed Jan 15, 2003 6:45 pm
Posts: 4005
Location: Dungeons of Doom
Has thanked: 408 times
Have thanks: 544 times
Yo bebo cuando tengo ocasión, ya veces cuando no tengo ocasión. :D

Great work, Chrrox! :drunken:

_________________
Please like our Facebook page!


Top
 Profile  
 
 Post subject: Re: Noesis tutorial (WIP) Updated 11/27/2011
PostPosted: Wed Nov 30, 2011 9:16 am 
Offline
Moderator
User avatar

Joined: Mon Mar 23, 2009 2:57 am
Posts: 1003
Has thanked: 44 times
Have thanks: 467 times
Mr.Mouse wrote:
Great work, Chrrox! :drunken:

Indeed.


Top
 Profile  
 
 Post subject: Re: Noesis tutorial (WIP) Updated 11/29/2011
PostPosted: Wed Nov 30, 2011 9:29 am 
Offline
veteran
User avatar

Joined: Wed Jun 08, 2011 7:14 am
Posts: 95
Has thanked: 18 times
Have thanks: 8 times
chrrox wrote:
There are several great reasons to use noesis over other methods.



Thanks chrrox, this is just...so so awesome!


Top
 Profile  
 
 Post subject: Re: Noesis tutorial (WIP) Updated 11/29/2011
PostPosted: Wed Nov 30, 2011 2:03 pm 
Offline
veteran

Joined: Mon Nov 29, 2010 10:38 am
Posts: 157
Has thanked: 31 times
Have thanks: 2 times
Thanks chrrox
I'm not completely sure, but sucess.


Last edited by alon on Sun Apr 15, 2012 1:43 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Noesis tutorial (WIP) Updated 11/29/2011
PostPosted: Thu Dec 01, 2011 5:53 pm 
Offline
ultra-veteran
ultra-veteran

Joined: Mon Aug 11, 2008 11:30 pm
Posts: 422
Has thanked: 23 times
Have thanks: 13 times
Nice one man! Hopefully will unlock alot of more importers etc ;)


Top
 Profile  
 
 Post subject: Re: Noesis tutorial (WIP) Updated 11/29/2011
PostPosted: Fri Dec 02, 2011 12:17 am 
Offline
M-M-M-Monster veteran
M-M-M-Monster veteran

Joined: Sat Apr 09, 2011 1:22 am
Posts: 2387
Has thanked: 170 times
Have thanks: 275 times
I'd like a template that I could just fill in without having to deal with the details.
Perhaps someone can make one such that I only have to write the parser function (otherwise I'll probably end up making one eventually after figuring out efficient ways to do it).

You know, something like

Code:

#register plugin and stuff
def ...

#load model
def ...

#build model
def ...

def...

#parser functions
def...

def...

def...


So for example you're reading vertex information, and then you want to pass it to the "builder" function that takes your list of vertices.
Of course, it could get complicated, but maybe for very common things like loading vertices or faces I just have to pass in a list and don't care what happens after.

_________________
Model Import Plugins/Scripts

Noesis Plugins | Reference files

Reference
Guide to 3D model reversal | 3D glossary


Top
 Profile  
 
 Post subject: Re: Noesis tutorial Basic Model
PostPosted: Tue Dec 06, 2011 6:38 pm 
Offline
veteran
User avatar

Joined: Fri Oct 21, 2011 1:33 pm
Posts: 104
Location: On my Network, unless I'm somewhere else
Has thanked: 9 times
Have thanks: 30 times
Very good tutorial Mate, Thank You.
:up:
I've used this as the base to do the SWTOR exporter instead of codeing a stand alone program.

_________________
Give a man a fish and he'll eat for a day.
Try to teach a man to fish and he'll gripe at you for not just giving him the Damn Fish!


Top
 Profile  
 
 Post subject: Re: Noesis tutorial Basic Model
PostPosted: Sun Dec 11, 2011 8:52 am 
Offline
M-M-M-Monster veteran
M-M-M-Monster veteran

Joined: Sat Apr 09, 2011 1:22 am
Posts: 2387
Has thanked: 170 times
Have thanks: 275 times
Nice tutorial, followed it and the samples that came with noesis while writing a template
The template is pretty much just me copying code from Sanae3D though, only because I'm used to it, and I like to use a lot of functions or methods. At least that way, I can re-use functions quickly without having to worry about whether it will conflict with any existing code.

Code:
...
def noepyLoadModel(data, mdlList):
   ctx = rapi.rpgCreateContext()
   parser = CrucisFatalFake_LMD(data)
   parser.parse_file()
   mdl = NoeModel(parser.meshList, None, None)
   mdlList.append(mdl)
   mdl.setModelMaterials(NoeModelMaterials(parser.texList, parser.matList))
   return 1

class CrucisFatalFake_LMD(object):
   
   def __init__(self, data):
       
      self.inFile = StructReader(data)
      self.meshList = []
      self.uvList = []
      self.vertList = ""
...


Now I just need to figure out how to assign materials flexibly...

Image

Maybe parse entire file first, and then go through the data and start building meshes and stuff...

EDIT: There we go...now I want to load the textures directly from the file.

Image

_________________
Model Import Plugins/Scripts

Noesis Plugins | Reference files

Reference
Guide to 3D model reversal | 3D glossary


Top
 Profile  
 
 Post subject: Re: Noesis tutorial Basic Model
PostPosted: Sun Apr 15, 2012 8:00 am 
Offline
M-M-M-Monster veteran
M-M-M-Monster veteran

Joined: Sat Apr 09, 2011 1:22 am
Posts: 2387
Has thanked: 170 times
Have thanks: 275 times
lol chrrox your tutorials getting nuked.

_________________
Model Import Plugins/Scripts

Noesis Plugins | Reference files

Reference
Guide to 3D model reversal | 3D glossary


Top
 Profile  
 
 Post subject: Re: Noesis tutorial Basic Model
PostPosted: Sun Apr 15, 2012 2:02 pm 
Offline
Moderator
User avatar

Joined: Sun May 18, 2008 3:01 pm
Posts: 2397
Has thanked: 56 times
Have thanks: 1134 times
meh not to big a deal.
I am going to wait for the restructure to be over before i post much to avoid it being lost.
also i don't think anyone ever used it since i didn't see any new people contribute to the site.
I don't think all these sites cared about file samples being posted i think the issue Google had was people directly linking to warez releases.


Top
 Profile  
 
 Post subject: Re: Noesis tutorial Basic Model
PostPosted: Sun Apr 15, 2012 2:59 pm 
Offline
mega-veteran
mega-veteran
User avatar

Joined: Fri Aug 05, 2011 9:31 pm
Posts: 240
Location: Antwerp
Has thanked: 13 times
Have thanks: 41 times
chrrox wrote:
also i don't think anyone ever used it since i didn't see any new people contribute to the site.


Hey! I know I don't brainfart a new script every hour like finale does, but I started with this tutorial for Noesis.


Top
 Profile  
 
 Post subject: Re: Noesis tutorial Basic Model
PostPosted: Sat Sep 01, 2012 8:39 pm 
Offline
beginner

Joined: Fri Apr 08, 2011 9:31 pm
Posts: 35
Has thanked: 12 times
Have thanks: 40 times
Hi Chrrox,

can i ask how do you use "MaterialInfo.append([MaterialName, TexID[0], IndStart[0], IndCount[0]])" the IndStart list? Because I cant see, as if it was used. If it's not than what tells to Noesis which set of face use which mat? Only the position in the list?


Top
 Profile  
 
 Post subject: Re: Noesis tutorial Basic Model
PostPosted: Sat Sep 01, 2012 8:50 pm 
Offline
Moderator
User avatar

Joined: Sun May 18, 2008 3:01 pm
Posts: 2397
Has thanked: 56 times
Have thanks: 1134 times
MaterialInfo.append([MaterialName, TexID[0], IndStart[0], IndCount[0]]) is just an array i made
it tells me how to load the mesh data correctly.
they just give a triangle list then they tell you how its broken down by materials.
so like say i had 90 faces
they would say break it down
start 0 count 25
then the next would be
start 25 count 15
then it would go
start 40 count x until no faces were left
and i am just assigning the materials to the faces as i load them.


Top
 Profile  
 
 Post subject: Re: Noesis tutorial Basic Model
PostPosted: Sun Sep 02, 2012 12:54 am 
Offline
beginner

Joined: Fri Apr 08, 2011 9:31 pm
Posts: 35
Has thanked: 12 times
Have thanks: 40 times
thanks for the info, in the meantime i finished my plugin :) just one thing left. How can i say "look for the textures in this folder". Because every folder have a texture folder and now i have to copy all texture file into the same folder as the file, and that is, hmm annoying.
My code is based on your tutorial, i use rpg, nothing immediate draw and other fancy things.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 47 posts ]  Go to page 1, 2, 3, 4  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group