Copyright 1993, Silicon Graphics, Inc. All rights reserved. Silicon Graphics and the Silicon Graphics logo are registered trademarks, and SGO is a trademark of Silicon Graphics. Specifications are subject to change without notice. SGO File Format SGO = (Silicon Graphics Object) SGO format is a format slightly more complicated that Spin format, but still quite simple. It allows lists of quadrilaterals, lists of triangles and triangle meshes. The first word in the file is the SGO magic number: word 1: 0x5424 (4 bytes) Following next is a set of objects: . . . Each of the tokens is 4 bytes long. The tokens are: OBJ_QUADLIST (= 1) OBJ_TRILIST (= 2) OBJ_TRIMESH (= 3) OBJ_END (= 4) the end of data token. The next word following any of the three object types is the number of longs in the data for that object. For OBJ_QUADLIST and OBJ_TRILIST (quadrilateral list and triangle list), there are 9 floats of data for each vertex. The first three are the components of the normal vector at the vertex; the next three are the color components (R, G, B), all between 0.0 and 1.0, and finally there are the components of the vertex itself. For the OBJ_QUADLIST, the points are simply taken 4 at a time, so there are 9*4 = 36 floats of data for each quadrilateral. For the OBJ_TRILIST, the points are used 3 at a time, making 9*3 = 27 floats per triangle. The triangle mesh (OBJ_TRIMESH) is the most complicated of the three. The data consist of a set of vertices followed by a set of mesh control commands. The data for each vertex is the same as above -- 9 floats. The mesh controls consist of: OP_BGNTMESH (= 1) OP_SWAPTMESH (= 2) OP_ENDBGNTMESH (= 3) OP_ENDTMESH (= 4) Following the number of longs required for the entire triangle mesh data is the number of floats required for the vertex data (at 9 floats per vertex). Next comes the vertex data, and the rest of the data are longs containing triangle mesh controls. For example, a file containing a single triangle mesh object with four vertices, and nine mesh controls would look like this: word 1: 0x5424 word 2: OBJ_TRIMESH word 3: 42 = 4*9 + 1 + 5 word 4: 36 (length of data for 4 vertices) word 5-40: vertex data word 41-49: mesh controls word 50: OBJ_END When the triangle mesh is drawn, the controls are interpreted one at a time. The first control is assumed to be an OP_BGNTMESH. After each control is a long indicating how many vertex indices will follow. The vertex indices are in byte offsets. For example, vertex n is offset by n*9*4. To understand triangle meshes, consider the following example. Suppose there are 6 points arranged as follows: 0-----2-----4 \ / \ / \ \ / \ / \ 1-----3-----5 To draw the triangles 012, 123, 234, and 345, the control sequence (the mesh controls) would be: OP_BGTMESH 6 0*9*4 1*9*4 2*9*4 3*9*4 4*9*4 5*9*4 OP_ENDTMESH Two vertices are recorded in the hardware. As each new vertex is sent, a triangle is output with the two saved vertices and the new one. Then the oldest vertex is discarded and is replaced by the second oldest, and the new vertex replaces the second oldest. For the sequence above, the state looks like this: Saveold Savenew Output Triangle ------- ------- ------ OP_BGNTMESH: invalid invalid nothing point 0: invalid point 0 nothing point 1: point 0 point 1 nothing point 2: point 1 point 2 0-1-2 point 3: point 2 point 3 1-2-3 point 4: point 3 point 4 2-3-4 point 5: point 4 point 5 3-4-5 OP_ENDTMESH: invalid invalid nothing This is great if all you want to do is go down a ribbon outputting triangles. If you want to turn a corner, or to have multiple sequences, OP_SWAPTMESH reverses the contents of the Saveold and Savenew registers, and OP_ENDBGNTMESH is ends the current sequence and begins a new one. One final example should illustrate this: 0-----2-----4 \ / \ / \ \ / \ / \ 1-----3-----5 14-----13 / \ / \ / \ / \ 6-----8----10-----12 \ / \ / \ / \ / \ / \ / 7-----9-----11 To draw the pattern above, use the following mesh control sequence: OP_BGNTMESH, 6, 0*9*4, 1*9*4, 2*9*4, 3*9*4, 4*9*4, 5*9*4, OP_ENDBGNTMESH, 6, 6*9*4, 7*9*4, 8*9*4, 9*9*4, 10*9*4, 11*9*4, OP_SWAPTMESH, 1, 12*9*4, OP_SWAPTMESH, 1, 13*9*4, OP_SWAPTMESH, 2, 14*9*4, 8*9*4, OP_ENDTMESH Saveold Savenew Output Triangle ------- ------- ------ OP_BGNTMESH: invalid invalid nothing point 0: invalid point 0 nothing point 1: point 0 point 1 nothing point 2: point 1 point 2 0-1-2 point 3: point 2 point 3 1-2-3 point 4: point 3 point 4 2-3-4 point 5: point 4 point 5 3-4-5 OP_ENDBGNTMESH: invalid invalid nothing point 6: invalid point 6 nothing point 7: point 6 point 7 nothing point 8: point 7 point 8 6-7-8 point 9: point 8 point 9 7-8-9 point A: point 9 point A 8-9-A point B: point A point B 9-A-B OP_SWAPTMESH: point B point A nothing point C: point A point C B-A-C OP_SWAPTMESH: point C point A nothing point D: point A point D C-A-D OP_SWAPTMESH: point D point A nothing point E: point A point E D-A-E point 8: point E point 8 A-E-8 OP_ENDTMESH: invalid invalid nothing */ #include #define OBJ_QUADLIST 1 #define OBJ_TRILIST 2 #define OBJ_TRIMESH 3 #define OBJ_END 4 #define OP_BGNTMESH 1 #define OP_SWAPTMESH 2 #define OP_ENDBGNTMESH 3 #define OP_ENDTMESH 4 FILE *fp; long meshctl[27] = { OP_BGNTMESH, 6, 0, 1*9*4, 2*9*4, 3*9*4, 4*9*4, 5*9*4, OP_ENDBGNTMESH, 6, 6*9*4, 7*9*4, 8*9*4, 9*9*4, 10*9*4, 11*9*4, OP_SWAPTMESH, 1, 12*9*4, OP_SWAPTMESH, 1, 13*9*4, OP_SWAPTMESH, 2, 14*9*4, 8*9*4, OP_ENDTMESH }; float meshdata[15][3] = { {3, 11, 0}, {5, 8, 0}, {7, 11, -1}, {9, 8, 0}, {11, 11, 0}, {13, 8, -1}, {2, 3, 0}, {4, 0, 0}, {6, 3, -1}, {8, 0, 0}, {10, 3, 1}, {12, 0, -1}, {14, 3, 3}, {12, 6, 2}, {8, 6, -2} }; float meshnorm[15][3] = { {0, 0, 1}, {0, 1, 0}, {1, 0, 0}, {0, 0, 1}, {0, 1, 0}, {1, 0, 0}, {0, 0, 1}, {0, 1, 0}, {1, 0, 0}, {0, 0, 1}, {0, 1, 0}, {1, 0, 0}, {0, 0, 1}, {0, 1, 0}, {1, 0, 0} }; float cube[8][3] = { {-1.0, -1.0, -1.0}, {-1.0, -1.0, 1.0}, {-1.0, 1.0, 1.0}, {-1.0, 1.0, -1.0}, {1.0, -1.0, -1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, 1.0}, {1.0, 1.0, -1.0}, }; float ncube[6][3] = { {1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}, }; float nullcolor[3] = { 0.0, 0.0, 0.0 }; writesgomesh() { long typeandcount[3]; long i; typeandcount[0] = OBJ_TRIMESH; typeandcount[1] = 15*9 + 1 + 27; typeandcount[2] = 15*9; fwrite(&typeandcount[0], 4, 3, fp); for (i = 0; i < 15; i++) { fwrite(&meshnorm[i][0], 4, 3, fp); fwrite(&nullcolor[0], 4, 3, fp); fwrite(&meshdata[i][0], 4, 3, fp); } for (i = 0; i < 27; i++) fwrite(&meshctl[i], 4, 1, fp); } writesgocube() { long typeandcount[2]; typeandcount[0] = OBJ_QUADLIST; typeandcount[1] = 6*36; fwrite(&typeandcount[0], 4, 2, fp); nw(0); vw(4); nw(0); vw(5); nw(0); vw(6); nw(0); vw(7); nw(1); vw(0); nw(1); vw(1); nw(1); vw(2); nw(1); vw(3); nw(2); vw(2); nw(2); vw(3); nw(2); vw(7); nw(2); vw(6); nw(3); vw(0); nw(3); vw(1); nw(3); vw(5); nw(3); vw(4); nw(4); vw(1); nw(4); vw(2); nw(4); vw(6); nw(4); vw(5); nw(5); vw(0); nw(5); vw(3); nw(5); vw(7); nw(5); vw(4); } vw(n) long n; { fwrite(&cube[n][0], 4, 3, fp); } nw(n) long n; { fwrite(&ncube[n][0], 4, 3, fp); fwrite(&nullcolor[0], 4, 3, fp); } octvert(n) long n; { fwrite(&ncube[n][0], 4, 3, fp); fwrite(&nullcolor[0], 4, 3, fp); fwrite(&ncube[n][0], 4, 3, fp); } sgotri(a, b, c) long a, b, c; { octvert(a); octvert(b); octvert(c); } writesgooct() { long typeandcount[2]; typeandcount[0] = OBJ_TRILIST; typeandcount[1] = 8*27; fwrite(&typeandcount[0], 4, 2, fp); sgotri(0, 2, 5); sgotri(0, 5, 3); sgotri(0, 3, 4); sgotri(0, 4, 2); sgotri(1, 2, 5); sgotri(1, 5, 3); sgotri(1, 3, 4); sgotri(1, 4, 2); } main() { long end = OBJ_END; /* comment out all but one of the next three lines */ writesgoheader(); /*writesgocube();*/ /*writesgooct();*/ writesgomesh(); fwrite(&end, 4, 1, fp); fclose(fp); } writesgoheader(polycount) long polycount; { long magic; magic = 0x5424; fp = fopen("sgoout", "w"); fwrite(&magic, 4, 1, fp); }