|   | 
							
   
SCM Specifications 
 
Introduction 
The SCM file format is a 3D object model 
file very easy to load and use, it's a little like a 3DS file format (.3ds), 
sure less rich, but very efficient. Its roots are from the ASE file format 
(.ase). The ASE file format is a 3D object model ASCII file format, it means 
that all the information containing vertices, polygons, texture coordinates or 
vertices normal vectors are written directly in a human-understanding language. 
This way is easy to understand and load, but the problem is that its very slow 
to load and very heavy to stock. The SCM file format is a kind of "compiled" ASE 
file format, you retrieve each ASE information in the SCM, but packed in a 
binary way, and this way, data are compressed and more easily recoverable. 
To give you a little example, the SCM file 
format is loaded between 50 and 100 times faster than the ASE file format, and 
SCM file size is about 10 times compressed compared to ASE. Imagine you want to 
create a game with a lot of object models, it'll be impossible for you to hold 
them all in ASE file format, and players won't enjoy to wait while long 
loadings. 
  
 
Explanations 
SCM, what it means, hehe, you'll probably 
laugh, it means Sebseb Croco Model. It's a multi-object file format, like 3DS 
file format, it's not a key-frames model like MD2. It contains every 3D 
information of each objects, and everything you need to draw your object form, 
and it also contains the texture coordinates and vertex/polygons normal vectors, 
it also contains the objects names and color, like that, you can still render 
good looking objects even if they aren't textured. 
This format has been created to be very 
easy to load, and you'll see how to do, this is a free file format and every 
tools I made are free and OpenSource, like that, you won't be able to say you 
can't load SCM object model, you'll have all the information needed to do it, in 
the documentation and in tools source codes. 
  
 
Specifications 
Ahh, enfin. Well, there is the technical 
specifications of the SCM file format, first, you'll have to declare some 
specifics little structures to store data. The SCM file contains information 
about each sub-objects in a "chunk" way. 
Structures 
There is two types of data structures used 
by SCM, they are t_vertex which will contains vertex information and t_polygon 
which will contains vertices indices. Look at what they look like. 
	
		
		typedef struct   s_vertex 
		{ 
    float        v1; 
    float        v2; 
    float        v3; 
		 
		}                
		t_vertex; | 
	 
 
This structure will hold every floating 
point, and it'll be used for vertices, texture coordinates and both vertices and 
polygons normal vectors. 
Now, the polygons data structures, they 
won't hold any floating points, but only indices to vertices data structures, to 
represent a 3D polygon, we use 3x3 floating points, but not directly because 
some points (vertices) can be re-used, so we stock every points into floating 
points, and then to draw a polygon (three points), we only use 3 indices which 
points to a floating point vertex, do you get it ? 
  
Let's look what the t_polygon 
structure look like : 
	
		| 
		 
		typedef struct   s_polygon 
		{ 
    int          p1; 
    int         
		p2; 
    int         
		p3; 
		 
		}                
		t_polygon;  | 
	 
 
You'll notice that both t_vertex and 
t_polygon structures are 12 bytes sizeof(t_vertex) and sizeof(t_polygon) will 
both give 12 on x86 architectures. You could use a #define SIZEOF_STRUCT 12, but 
you shouldn't, it's not proper to do it because in case of data type length 
change, this will make our SCM implementation wrong, so I advice you to declare 
these structures and use the sizeof() macros with. 
Macros 
Well, I think I said enough for 
structures, now let's see the defined values, there is two #define you have to 
know. First, when you load a SCM file, you have to know if you're currently 
working on a good SCM file or not, so for that, you have to check the file ID. 
Then for the sub-objects name, I also told you they were contained into the SCM 
file, so to read it properly, you have to know how many bytes are used to store 
them. 
To check the SCM file ID, you have this 
define 
	
		| #define SCM_ID        
		0x464D4353 | 
	 
 
This value is the hexadecimal equivalence 
of "SCMF" for "SCM File", so reading the first int of the SCM file (the first 4 
bytes) will tell you if they are equal to the ID. See this little sample code (I 
admit the file has just opened) : 
	
		int    
		id; 
		FILE   *fd; 
		 
		... 
		fread(&id, sizeof(int), 1, fd); 
		if (id == SCM_ID) 
   valid_scm_file(fd); 
		else 
   fprintf(stderr, 
		"error: this file is not a valid SCM file\n"); 
		... | 
	 
 
Now let's see for the objects name, there 
is a #define to set a fixed size of bytes, for the moment, this value is 16, 
it's not obligatory a multiple of 4 (sizeof(int)) but it's much better if it is. 
Well, you have to know that the name of the file is always written with a 
terminating null character, so if you set a pointer on the start of the string, 
you can give it to any strings treatment functions, but in case you need to know 
precisely the size to directly jump, the #define will help you. 
So, for an example, if you just opened 
your SCM file, and you want to jump directly to the vertices information, this 
code you'll do it : 
	
		char   *ptr; 
		 
		... 
		ptr = buff_scm; 
		ptr += 4 * sizeof(int) + SIZEOF_NAME; 
		... | 
	 
 
Because there is 4 integers and the name 
of the first object before the first vertices information of the SCM file. Well, 
now we saw structures and macros, and that you start to have a little idea of 
what is the SCM file format, we'll be able to go on to a more interesting part 
of the specification. 
Datagram 
There is the more interesting part of the 
specification I think, and also the one will make you understand more things, 
and much better :) 
  
The array is cut into two parts 
	
		| 
		4 bytes | 
		
		4 bytes | 
		
		
		SIZEOF_NAME bytes | 
		
		4 bytes | 
		
		4 bytes | 
	 
	
		| 
		SCMF (ID) | 
		
		object number | 
		
		object name | 
		
		object id | 
		
		object color | 
	 
 
The following the the suit of the 
previous array 
	
		| 4 bytes | 
		nvert 
		bytes | 
		4 bytes | 
		npoly 
		bytes | 
		4 bytes | 
		ntvert 
		bytes | 
		4 bytes | 
		ntpoly 
		bytes | 
		4 bytes | 
		nnormvert 
		bytes | 
		4 bytes | 
		nnormpoly 
		bytes | 
	 
	
		| nvert | 
		vertex 
		list 
		(t_vertex) | 
		npoly | 
		polygon 
		list 
		(t_polygon) | 
		ntvert | 
		texture 
		coordinates list 
		(t_vertex) | 
		ntpoly | 
		texture 
		coordinates polygon list 
		(t_polygon) | 
		nnormvert | 
		vertex 
		normal vector list 
		(t_vertex) | 
		nnormpoly | 
		polygon 
		normal vector list 
		(t_vertex) | 
	 
 
  
The orange part is the "header" part of 
the SCM file, these information has to be read only one time, SCMF permit you to 
know if the file is valid, and object number give you the number of objects there is 
in your SCM file, like that you know how many memory to allocate. 
The green part contains a blue and a 
purple one, representing an object, and 
is probably repeated in the file (in case you have a multiple object file). So in each 
green part (object) you have a little object "header" that contains name, id and 
color of the current object (blue part), every id are generated from 0, by incrementing, and 
the color is originally set to 0xFFFFFFFF (white) but there is very good tools 
to change it, we'll see that later. 
Well, now see the lists (purple part), the nvert integer 
give you the number of vertices there is in the vertex list, like that, you know 
how much memory to allocate, but I warn you, it's nvert * sizeof(t_vertex) 
bytes. Just repeat the same operation for the other lists. Be careful, if you 
didn't generated some lists, for example, if you decided to not generate the 
normal vectors, there will still be the integers to indicate the numbers, but 
will be set to zero, so you'll have to test it before allocating memory. 
  
Code 
There is a little sample code to load the 
data into memory, but you have the complete source code of the CScm class object 
in the download section. You have to have two variable for that (class member 
variables) 
	
		#define 
		SCM_ID         0x464D4353 
		#define SIZEOF_NAME    16 
		 
		typedef struct   s_vertex 
		{ 
    float        v1; 
    float        v2; 
    float        v3; 
		 
		}                
		t_vertex; 
		 
		typedef struct   s_polygon 
		{ 
    int          p1; 
    int          p2; 
    int          p3; 
		 
		}                
		t_polygon; 
		 
		typedef struct   s_object 
		{ 
    char         *name; 
    int          id; 
    uchar        color[4]; 
    int          
		vertex_number; 
    t_vertex     *vertex_list; 
    int          
		polygons_number; 
    t_polygon    *polygons_list; 
    int          
		texvertex_number; 
    t_vertex     *texvertex_list; 
    int          
		texpolygons_number; 
    t_polygon    *texpolygons_list; 
    int          
		normals_vertex_number; 
    t_vertex     *normals_vertex_list; 
    int          
		normals_polygons_number; 
    t_vertex     *normals_polygons_list; 
		 
		}                
		t_object; | 
	 
 
Above are the structures and defines to 
use, I wrote you the t_object structure, but you can write it as you wish, it's 
a data container and it's up to you to arrange it how it's better for yourself. 
	
		int         _object_number; 
		t_object    *_object_list; | 
	 
 
Just above are two variables that you'll 
need to load your object file, I used them as a class member variables. And 
then, two little and easy to understand functions. 
	
		int   _read_object(t_object *obj, FILE *fd) 
		{ 
    char    buff_name[SIZEOF_NAME]; 
		 
    fread(buff_name, sizeof(char), SIZEOF_NAME, fd); 
    obj->name = strdup(buff_name); 
    fread(&(obj->id), sizeof(int), 1, fd); 
    fread(obj->color, sizeof(int), 1, fd); 
    fread(&(obj->vertex_number), sizeof(int), 1, fd); 
    if (obj->vertex_number > 0) 
    { 
        obj->vertex_list = (t_vertex*)malloc(obj->vertex_number 
		* sizeof(*(obj->vertex_list))); 
        if (obj->vertex_list == NULL) 
            return (0); 
        fread(obj->vertex_list, sizeof(t_vertex), obj->vertex_number, fd); 
    } 
    fread(&(obj->polygons_number), sizeof(int), 1, fd); 
    if (obj->polygons_number > 0) 
    { 
        obj->polygons_list = (t_polygon*)malloc(obj->polygons_number 
		* sizeof(*(obj->polygons_list))); 
        if (obj->polygons_list == NULL) 
            return (0); 
        fread(obj->polygons_list, sizeof(t_polygon), obj->polygons_number, fd); 
    } 
    fread(&(obj->texvertex_number), sizeof(int), 1, fd); 
    if (obj->texvertex_number > 0) 
    { 
        obj->texvertex_list = (t_vertex*)malloc(obj->texvertex_number 
		* sizeof(*(obj->texvertex_list))); 
        if (obj->texvertex_list == NULL) 
            return (0); 
        fread(obj->texvertex_list, sizeof(t_vertex), obj->texvertex_number, fd); 
    } 
    fread(&(obj->texpolygons_number), sizeof(int), 1, fd); 
    if (obj->texpolygons_number > 0) 
    { 
        obj->texpolygons_list = (t_polygon*)malloc(obj->texpolygons_number 
		* sizeof(*(obj->texpolygons_list))); 
        if (obj->texpolygons_list == NULL) 
            return (0); 
        fread(obj->texpolygons_list, sizeof(t_polygon), obj->texpolygons_number, fd); 
    } 
    fread(&(obj->normals_vertex_number), sizeof(int), 1, fd); 
    if (obj->normals_vertex_number > 0) 
    { 
        obj->normals_vertex_list = 
		(t_vertex*)malloc(obj->normals_vertex_number * 
                                                     sizeof(*(obj->normals_vertex_list))); 
        if (obj->normals_vertex_list == NULL) 
            return (0); 
        fread(obj->normals_vertex_list, sizeof(t_vertex), obj->normals_vertex_number, fd); 
    } 
    fread(&(obj->normals_polygons_number), sizeof(int), 1, fd); 
    if (obj->normals_polygons_number > 0) 
    { 
        obj->normals_polygons_list = 
		(t_vertex*)malloc(obj->normals_polygons_number * 
                                                       sizeof(*(obj->normals_polygons_list))); 
        if (obj->normals_polygons_list == NULL) 
            return (0); 
        fread(obj->normals_polygons_list, sizeof(t_polygon), obj->normals_polygons_number, fd); 
    } 
    return (1); 
		} | 
	 
 
Here is a function to read only one 
object, it read it completely and store the data into the good buffers. It fills 
the current t_object structure. 
	
		
		int   LoadObject(char *file) 
		{ 
    int    i; 
    int    id; 
    FILE   *fd; 
		 
    fd = fopen(file, "rb"); 
    if (fd == NULL) 
        return (0); 
    fread(&id, sizeof(int), 1, fd); 
    if (id != SCM_ID) 
    { 
        fclose(fd); 
        return (0); 
    } 
    fread(&_object_number, sizeof(int), 1, fd); 
    if (_object_number <= 0) 
    { 
        fclose(fd); 
        return (0); 
    } 
    _object_list = (t_object*)malloc(_object_number * sizeof(*_object_list)); 
    if (_object_list == NULL) 
    { 
        fclose(fd); 
        return (0); 
    } 
    for (i = 0; i < _object_number; i++) 
    { 
        if (_read_object(&_object_list[i], fd) 
		== 0) 
            return (0); 
    } 
    _current_polygon = 0; 
    _current_object = 0; 
    fclose(fd); 
    return (1); 
		} | 
	 
 
And this last function first read and 
check the SCM file ID, read the number of object, allocate memory and then loop 
on all objects and use for each one the previous function. 
Sorry, I didn't colored the code, it 
would be too long to do so... This code only load SCM object file into memory, 
pretty easy right ? Sorry for the long code, and more it's a little useless 
because it won't really help you to see how to do but I let it anyway. I don't put the 
code to draw the object, but I told you the source code is available in the 
download section, and it's the source code of 
the SCM Viewer, so you'll find everything you need :) The SCM Viewer use
OpenGL as a graphic render support. 
I told you about tools, you'll see on this 
site some little, powerful and useful tools to modify objects color, objects 
name, export or import objects color pattern, and most important, you'll have 
the tool to generate SCM files from ASE files. 
							  
							 | 
							  |