Tutorial 4 : sérialisation
Nous allons voir dans cette partie du tutorial comment enregistrer et sauvegarder les nouveaux atomic que nous avons créés.
Initialisation des fonctions
Implémentation des fonctions
Utilisation des fonctions
Pour pouvoir lire et écrire des fichiers .DFF, RenderWare propose déjà l'API RpAtomicRegisterPluginStream. Mais pour aider il faut passer 3 pointeurs de fonctions qui sont lecture, écriture et obtention de la taille. Cette dernière permet d'indiquer à l'API combien de bytes il y a à lire/écrire.
| static RwStream * rpStreamWrite(RwStream *stream, RwInt32 len, const void *data, RwInt32 offset, RwInt32 size) { return stream; static RwStream * return stream; static RwInt32 /*
no data to write */ |
Pour l'instant ces fonctions ne font rien mais on remplira le code plus tard! Il faut maintenant initialiser les fonctions pour indiquer à l'API qu'il faut les utiliser pour la sauvegarder et tout le touttim.
| //initialisation
du plugin RwInt32 RpAtomicNameInitialize(void) { rpExtensionOffset = RpAtomicRegisterPlugin(sizeof(char *), MAKECHUNKID(rwVENDORID_CRITERIONTK, rwID_EXAMPLE), rpConstructor, rpDestructor, NULL); RpAtomicRegisterPluginStream(MAKECHUNKID(rwVENDORID_CRITERIONTK, rwID_EXAMPLE), /* return
the offset */ |
Il ne reste plus qu'à implémenter les fonctions créées plus haut.
La première et la plus simple est rpStreamGetSize()
| static RwInt32 rpStreamGetSize(const void *data, RwInt32 offset, RwInt32 size) { char **extData = RPEXTFROMATOMIC(data); if(*extData) { return rwstrlen(*extData) +1; } /* no
data to write */ |
Maintenant on va passer à l'écriture. Pour cela on va se servir de l'API RwStreamWrite()
| static RwStream * rpStreamWrite(RwStream *stream, RwInt32 len, const void *data, RwInt32 offset, RwInt32 size) { char **extData = RPEXTFROMATOMIC(data); return stream; |
Enfin il ne reste plus qu'à écrire la lecture. Ici, il faudra allouer de la place dans l'atomic pour pouvoir écrire le nom. Ici c'est l'API RwStreamRead qui va nous être utile.
| static RwStream * rpStreamRead(RwStream *stream, RwInt32 len, void *data, RwInt32 offset, RwInt32 size) { char **extData = RPEXTFROMATOMIC(data); char * name = RwMalloc(len,rwID_NAOBJECT); if(name) { RwStreamRead(stream, name , len); *extData = name; return stream; } return stream; } |
Nous allons voir maintenant comment utiliser ces fonctions.
On va ajouter une fonction permettant de sauvegarder un atomic avec un nom de fichier spécifié. Cette fonction est à mettre dans utils.c.
| /** sauvegarde d'un atomic */ void DffSave(RpAtomic *atomic, char *filename) { if (atomic) { RwStream *stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMWRITE, filename); RpClump *clump = RpAtomicGetClump(atomic); if (stream && clump) { RpClumpStreamWrite(clump, stream); RsWarningMessage("Wrote model!"); RwStreamClose(stream, NULL); } else { RsWarningMessage("Couldn't open stream!"); } } else { RsWarningMessage("No atomic to export!"); } } |
Il faut aussi mettre l'entête de la fonction dans la utils.h
| extern void DffSave(RpAtomic *atomic, char *filename); |
On va ajouter une nouvelle entrée avec un trigger dans le menu pour pouvoir sauvegarder le fichier. Pour l'instant, on va juste mettre un nom fixe.
/** trigger pour sauvegarder un atomic */ static RwBool saveTrigger(RwBool check) { if(PickedAtomic && !check) { DffSave(PickedAtomic,"test.dff"); } return TRUE; } |
| static
RwBool InitializeMenu(void) { static RwChar fpsLabel[] = RWSTRING("FPS_F"); static RwChar nearLabel[] = RWSTRING("Near Clip"); static RwChar farLabel[] = RWSTRING("Far Clip"); static RwChar showPosLabel[] = RWSTRING("Show Position"); static RwChar namesLabel[] = RWSTRING("Name Choice_N"); static RwChar assignLabel[] = RWSTRING("Assign Name_A"); static RwChar saveLabel[] = RWSTRING("Save_S"); if( MenuOpen(TRUE, &ForegroundColor,
&BackgroundColor) ) MenuAddEntryReal(nearLabel,
&NearClip, NULL, 0.1f, 10.0f, 0.1f); MenuAddEntryInt(namesLabel,&SelectedName,NULL,0,NUMNAMES-1,1,AtomicNames); return FALSE; |
Maintenant il est possible de sauvegarder un atomic avec son nom. Une fois sauvegardé, si on le recharge, son nom est toujours là!!
Voyons voir un dernier raffinement, le nom de l'objet est utilisé comme nom de fichier.
| static RwBool saveTrigger(RwBool check) { if(PickedAtomic && !check) { const RwChar * name = RpAtomicNameGetName(PickedAtomic); if(name) { RwChar s[100]; RsSprintf(s,"%s.dff",name); DffSave(PickedAtomic,(RwChar*)s); } else { DffSave(PickedAtomic,"test.dff"); } } return TRUE; } |
On compile, on exécute, on charge des objets, on les sauvegarde, on les recharge!!

Nous avons vu comment créer un plugin. Nous allons voir dans le tutorial suivant comment créer un monde : tutorial 5