View topic - s3o file specification



All times are UTC + 1 hour


Post new topic Reply to topic  [ 19 posts ] 
Author Message
 Post subject: s3o file specification
PostPosted: 29 Jul 2011, 07:34 
Moderator
User avatar

Joined: 23 Nov 2005, 06:16
Location: Dunedin, New Zealand
Does anyone have a link to it? I've been trying to reverse engineer the spring s3o parser but I'm struggling.


Top
 Offline Profile  
 
PostPosted: 29 Jul 2011, 07:40 
Zero-K Developer
User avatar

Joined: 10 Sep 2008, 02:11
Location: In search for TheTruth (TM)
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.


Top
 Offline Profile  
 
PostPosted: 29 Jul 2011, 08:33 
Moderator
User avatar

Joined: 26 Oct 2007, 15:21
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:

Code:
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:
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:
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;


Top
 Offline Profile  
 
PostPosted: 29 Jul 2011, 08:40 
Moderator
User avatar

Joined: 26 Oct 2007, 15:21
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:


Attachments:
s3olib.zip [3.07 KiB]
Downloaded 14 times
Top
 Offline Profile  
 
PostPosted: 29 Jul 2011, 10:47 
Moderator
User avatar

Joined: 23 Nov 2005, 06:16
Location: Dunedin, New Zealand
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]


Top
 Offline Profile  
 
PostPosted: 29 Jul 2011, 13:09 
Moderator
User avatar

Joined: 26 Oct 2007, 15:21
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.


Top
 Offline Profile  
 
PostPosted: 03 Sep 2011, 10:46 
Moderator
User avatar

Joined: 23 Nov 2005, 06:16
Location: Dunedin, New Zealand
Hurrah, I managed to cause an Access Violation with my s3o.


Top
 Offline Profile  
 
PostPosted: 03 Sep 2011, 11:36 
Moderator
User avatar

Joined: 26 Oct 2007, 15:21
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.


Top
 Offline Profile  
 
PostPosted: 03 Sep 2011, 12:03 
Moderator
User avatar

Joined: 23 Nov 2005, 06:16
Location: Dunedin, New Zealand
Access violation in Engine, instacrash in UpSpring.

The file also swells to ~10x the size.


Top
 Offline Profile  
 
PostPosted: 03 Sep 2011, 12:13 
Moderator
User avatar

Joined: 23 Nov 2005, 06:16
Location: Dunedin, New Zealand
Ok, I think the problem I'm having is with vertexTable. I'll have a look again in the morning.


Top
 Offline Profile  
 
PostPosted: 03 Sep 2011, 13:17 
Spring Developer

Joined: 31 May 2009, 23:08
@Das Bruce:

if you try with latest spring + paste infolog.txt, the crash can maybe fixed...


Top
 Offline Profile  
 
PostPosted: 07 Sep 2011, 03:04 
Moderator
User avatar

Joined: 23 Nov 2005, 06:16
Location: Dunedin, New Zealand
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.

Code:
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()

Gives output:
Code:
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 ]

For the first quad. What have I overlooked?
Complete source


Top
 Offline Profile  
 
PostPosted: 07 Sep 2011, 05:30 

Joined: 13 Aug 2006, 17:55
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:
Code:
#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)


But in:
Code:
#File Model.py
def Loads3o
...
         for x in range(len(sp.vertices)/4):
           a = 4*x
           sp.vertices[a].v.x ...


You just iterate through the vertices in groups of four.

Instead you'd want something like

Code:
for x in range(len(sp.primitives)/4):
  a = 4*x
  sp.vertices[ sp.primitives[a] ].v.x ...


Image

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


Top
 Offline Profile  
 
PostPosted: 07 Sep 2011, 06:07 
Moderator
User avatar

Joined: 23 Nov 2005, 06:16
Location: Dunedin, New Zealand
I don't understand. Why does
Code:
#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
Print the correct values every time, yet the code just below, which should use those values, decides not to?


Top
 Offline Profile  
 
PostPosted: 07 Sep 2011, 06:52 

Joined: 13 Aug 2006, 17:55
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:
Code:
#File s3olib.py
def normalize(self):
   length=sqrt(self.x*self.x,self.y*self.y+self.z*self.z)

Should maybe be?
length=math.sqrt(self.x*self.x+self.y*self.y+self.z*self.z)
(+ instead of comma)

And:
Code:
#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:
#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]


Top
 Offline Profile  
 
PostPosted: 07 Sep 2011, 07:03 
Moderator
User avatar

Joined: 23 Nov 2005, 06:16
Location: Dunedin, New Zealand
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?


Hah, brilliant, that was the problem all along. I can't really comment on s3olib, that's purely Beheriths work.


Top
 Offline Profile  
 
PostPosted: 09 Sep 2011, 12:48 
Moderator
User avatar

Joined: 23 Nov 2005, 06:16
Location: Dunedin, New Zealand
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.

Image
Attachment:
odd.png [32.8 KiB]
Downloaded 2 times


Top
 Offline Profile  
 
PostPosted: 09 Sep 2011, 14:18 
Moderator
User avatar

Joined: 26 Oct 2007, 15:21
Found the bug:

Code:
      if sp.primitivetype == 0:      # Triangles
         for x in range(len(sp.vertices)/3):


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.


Top
 Offline Profile  
 
PostPosted: 10 Sep 2011, 16:41 
Moderator
User avatar

Joined: 23 Nov 2005, 06:16
Location: Dunedin, New Zealand
Quote:
so just iterate over vertexindextable
and not vertextable


Top
 Offline Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: Bing [Bot] 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® Forum Software © phpBB Group

Site layout created by Roflcopter et al.