s3o file specification
Moderator: Moderators
s3o file specification
Does anyone have a link to it? I've been trying to reverse engineer the spring s3o parser but I'm struggling.
Re: s3o file specification
I applaud your efforts. I, however, have no links. Sorry!
...Perhaps thesleepless' import/export tools can help you? Their Python source is likely more readable than spring's s3o code.

...Perhaps thesleepless' import/export tools can help you? Their Python source is likely more readable than spring's s3o code.
Re: s3o file specification
Its actually super simple. I have the python code ready (although it looks like SHIT) but the general concept is simple enough:
Use the pack and unpack methods to generate binary data from strings. and these are the C structs you need to parse:
Use the pack and unpack methods to generate binary data from strings. and these are the C structs you need to parse:
Code: Select all
struct S3OHeader{
char magic[12]; ///< "Spring unit\0"
int version; ///< 0 for this version
float radius; ///< radius of collision sphere
float height; ///< height of whole object
float midx; ///< these give the offset from origin(which is supposed to lay in the ground plane) to the middle of the unit collision sphere
float midy;
float midz;
int rootPiece; ///< offset in file to root piece
int collisionData; ///< offset in file to collision data, must be 0 for now (no collision data)
int texture1; ///< offset in file to char* filename of first texture
int texture2; ///< offset in file to char* filename of second texture
Code: Select all
struct Piece{
int name; ///< offset in file to char* name of this piece
int numChilds; ///< number of sub pieces this piece has
int childs; ///< file offset to table of dwords containing offsets to child pieces
int numVertices; ///< number of vertices in this piece
int vertices; ///< file offset to vertices in this piece
int vertexType; ///< 0 for now
int primitiveType; ///< type of primitives for this piece, 0=triangles,1 triangle strips,2=quads
int vertexTableSize; ///< number of indexes in vertice table
int vertexTable; ///< file offset to vertice table, vertice table is made up of dwords indicating vertices for this piece, to indicate end of a triangle strip use 0xffffffff
int collisionData; ///< offset in file to collision data, must be 0 for now (no collision data)
float xoffset; ///< offset from parent piece
float yoffset;
float zoffset;
Code: Select all
struct Vertex{
float xpos; ///< position of vertex relative piece origin
float ypos;
float zpos;
float xnormal; ///< normal of vertex relative piece rotation
float ynormal;
float znormal;
float texu; ///< texture offset for vertex
float texv;
Re: s3o file specification
Dont do the same work I did twice!
So here is the python code to fully load an s3o, and to save it as well:
So here is the python code to fully load an s3o, and to save it as well:
- Attachments
-
- s3olib.zip
- (3.07 KiB) Downloaded 22 times
Re: s3o file specification
Thanks.
The variable S3oPiece.primitives doesn't appear to get used, how do I know how to create the triangles from the vertices?
[Edit] Never mind, it appears you've stored them temporarily in a list called prims without copying it to primitives. [/Edit]
The variable S3oPiece.primitives doesn't appear to get used, how do I know how to create the triangles from the vertices?
[Edit] Never mind, it appears you've stored them temporarily in a list called prims without copying it to primitives. [/Edit]
Re: s3o file specification
Yeah may be buggy, feel free to pester me here or in lobby. Primitives is not part of spec, was only left in there cause 3do's had them.
Re: s3o file specification
Hurrah, I managed to cause an Access Violation with my s3o.
Re: s3o file specification
Access violation in upspring or engine? Its easy to screw them up, please post your code if you need help. I also recall that if you reload the s3o that you made with my code, you can easily verify it.
Re: s3o file specification
Access violation in Engine, instacrash in UpSpring.
The file also swells to ~10x the size.
The file also swells to ~10x the size.
Re: s3o file specification
Ok, I think the problem I'm having is with vertexTable. I'll have a look again in the morning.
Re: s3o file specification
Abma: I'll give that a go when I get a chance.
Beherith: Quads arn't working right for me, the vertices are coming up right but I can't seem to get it to create the faces properly. Faces(triangles) contain three indexes to their vertices and a reference to a list of all vertices in the piece.
The only idea I have is that I've misunderstood Python.
Gives output:
For the first quad. What have I overlooked?
Complete source
Beherith: Quads arn't working right for me, the vertices are coming up right but I can't seem to get it to create the faces properly. Faces(triangles) contain three indexes to their vertices and a reference to a list of all vertices in the piece.
The only idea I have is that I've misunderstood Python.
Code: Select all
elif sp.primitivetype == 2: # Quads
for x in range(len(sp.vertices)/4):
a = 4*x
b = 4*x+1
c = 4*x+2
d = 4*x+3
print 'Quad vertices:'
print sp.vertices[a].v.x, sp.vertices[a].v.y, sp.vertices[a].v.z
print sp.vertices[b].v.x, sp.vertices[b].v.y, sp.vertices[b].v.z
print sp.vertices[c].v.x, sp.vertices[c].v.y, sp.vertices[c].v.z
print sp.vertices[d].v.x, sp.vertices[d].v.y, sp.vertices[d].v.z
self.vertices.append(Vertex(sp.vertices[a].v.x, sp.vertices[a].v.y, sp.vertices[a].v.z))
self.vertices.append(Vertex(sp.vertices[b].v.x, sp.vertices[b].v.y, sp.vertices[b].v.z))
self.vertices.append(Vertex(sp.vertices[c].v.x, sp.vertices[c].v.y, sp.vertices[c].v.z))
self.faces.append(Face(a, b, c, self.vertices))
print 'First Tri vertices:'
self.faces[-1].Debug()
self.vertices.append(Vertex(sp.vertices[a].v.x, sp.vertices[a].v.y, sp.vertices[a].v.z))
self.vertices.append(Vertex(sp.vertices[c].v.x, sp.vertices[c].v.y, sp.vertices[c].v.z))
self.vertices.append(Vertex(sp.vertices[d].v.x, sp.vertices[d].v.y, sp.vertices[d].v.z))
self.faces.append(Face(a, c, d, self.vertices))
print 'Second Tri vertices:'
self.faces[-1].Debug()
Code: Select all
Quad vertices:
3.0 -1.0 1.0
1.0 -1.0 1.0
1.0 1.0 1.0
3.0 1.0 1.0
First Tri vertices:
[ 3.0 , -1.0 , 1.0 ]
[ 1.0 , -1.0 , 1.0 ]
[ 1.0 , 1.0 , 1.0 ]
Second Tri vertices:
[ 3.0 , -1.0 , 1.0 ]
[ 1.0 , 1.0 , 1.0 ]
[ 3.0 , -1.0 , 1.0 ]
Complete source
Re: s3o file specification
Looked at the code, didn't run it.
It looks like you are not using the 'vertexTable' member of Piece, instead just printing the 'vertex' members cosecutively.
I will attempt to quote the relevant sections.
You ARE reading the vertexTable (piece[8]) properly as far as I can tell, storing in self.primitives:
But in:
You just iterate through the vertices in groups of four.
Instead you'd want something like

I suppose this could be useful:
http://www.songho.ca/opengl/gl_vertexarray.html
Talks about indexed geometry in OpenGL, reputable site afaik.
Also during my first attempt at writing I accidentally pressed the Emacs shortcut for copying text (Ctrl+W) which is conveniently the same as the close tab shortcut in Firefox, you'd expect their devs to be Emacs users and get rid of of it but no they troll us :s
It looks like you are not using the 'vertexTable' member of Piece, instead just printing the 'vertex' members cosecutively.
I will attempt to quote the relevant sections.
You ARE reading the vertexTable (piece[8]) properly as far as I can tell, storing in self.primitives:
Code: Select all
#From s3olib.py
def recursereads3o
...
f.seek(piece[8])
vtable=f.read(piece[7]*4)
unpackstr=''
for i in range(0,piece[7]):
unpackstr+='l'
# print 'vtable length:',len(vtable)
self.primitives=unpack(unpackstr,vtable)
for p2 in self.primitives:
self.vertexTable.append(p2)
Code: Select all
#File Model.py
def Loads3o
...
for x in range(len(sp.vertices)/4):
a = 4*x
sp.vertices[a].v.x ...
Instead you'd want something like
Code: Select all
for x in range(len(sp.primitives)/4):
a = 4*x
sp.vertices[ sp.primitives[a] ].v.x ...

I suppose this could be useful:
http://www.songho.ca/opengl/gl_vertexarray.html
Talks about indexed geometry in OpenGL, reputable site afaik.
Also during my first attempt at writing I accidentally pressed the Emacs shortcut for copying text (Ctrl+W) which is conveniently the same as the close tab shortcut in Firefox, you'd expect their devs to be Emacs users and get rid of of it but no they troll us :s
Re: s3o file specification
I don't understand. Why doesPrint the correct values every time, yet the code just below, which should use those values, decides not to?
Code: Select all
#File Model.py
def Loads3o
...
print 'Quad vertices:'
print sp.vertices[a].v.x, sp.vertices[a].v.y, sp.vertices[a].v.z
print sp.vertices[b].v.x, sp.vertices[b].v.y, sp.vertices[b].v.z
print sp.vertices[c].v.x, sp.vertices[c].v.y, sp.vertices[c].v.z
print sp.vertices[d].v.x, sp.vertices[d].v.y, sp.vertices[d].v.z
Re: s3o file specification
For that in particular:
I believe you do:
1. self.vertices starts as empty
2. Append 3 vertices to self.vertices, it now contains: a b c
3. Make a Face with indexes 0-1-2, which is a b c
4. Append another 3 vertices to self.vertices on top of the previous ones: it now contains: a b c a c d
5. Make a Face with indexes 0-2-3 which is a c a
This is why the second Face is degenerate, two points are the same.
sp.vertices is a b c d e f g h i etc..
self.vertices is a b c a c d etc.
I'm not entirely sure what the intent/algorithm you following is, seems just broken though?
Just noticed some other things, might want to doublecheck:
Should maybe be?
length=math.sqrt(self.x*self.x+self.y*self.y+self.z*self.z)
(+ instead of comma)
And:
I believe you do:
1. self.vertices starts as empty
2. Append 3 vertices to self.vertices, it now contains: a b c
3. Make a Face with indexes 0-1-2, which is a b c
4. Append another 3 vertices to self.vertices on top of the previous ones: it now contains: a b c a c d
5. Make a Face with indexes 0-2-3 which is a c a
This is why the second Face is degenerate, two points are the same.
sp.vertices is a b c d e f g h i etc..
self.vertices is a b c a c d etc.
I'm not entirely sure what the intent/algorithm you following is, seems just broken though?
Just noticed some other things, might want to doublecheck:
Code: Select all
#File s3olib.py
def normalize(self):
length=sqrt(self.x*self.x,self.y*self.y+self.z*self.z)
length=math.sqrt(self.x*self.x+self.y*self.y+self.z*self.z)
(+ instead of comma)
And:
Code: Select all
#Structure definition in Spring source:
struct S3OHeader{
char magic[12]; ///< "Spring unit\0"
int version; ///< 0 for this version
float radius; ///< radius of collision sphere
float height; ///< height of whole object
float midx; ///< these give the offset from origin(which is supposed to lay in the ground plane) to the middle of the unit collision sphere
float midy;
float midz;
Code: Select all
#File s3olib.py at reads3o function
#The way it is read in:
#Notice how the member after radius is supposed to be height
#but it continues to index midx,midy,midz
self.version=header[0]
self.radius=header[1]
self.midx=header[2]
self.midy=header[3]
self.midz=header[4]
Re: s3o file specification
Hah, brilliant, that was the problem all along. I can't really comment on s3olib, that's purely Beheriths work.Andrej wrote:For that in particular:
I believe you do:
1. self.vertices starts as empty
2. Append 3 vertices to self.vertices, it now contains: a b c
3. Make a Face with indexes 0-1-2, which is a b c
4. Append another 3 vertices to self.vertices on top of the previous ones: it now contains: a b c a c d
5. Make a Face with indexes 0-2-3 which is a c a
This is why the second Face is degenerate, two points are the same.
sp.vertices is a b c d e f g h i etc..
self.vertices is a b c a c d etc.
I'm not entirely sure what the intent/algorithm you following is, seems just broken though?
Re: s3o file specification
I'm not sure what's happening here. Is it possible that some pieces are being saved as tristrips without being marked as such? I find it extra odd because the infantry models hat and head are part of the same piece but the head renders fine.
Re: s3o file specification
Found the bug:
in Model.py is wrong, you are not taking into account the fact that vertices can be reused. Dont iterate x over vertices, but over vertex table size.
Same goes for quads.
Code: Select all
if sp.primitivetype == 0: # Triangles
for x in range(len(sp.vertices)/3):
Same goes for quads.
Re: s3o file specification
so just iterate over vertexindextable
and not vertextable