Question

Je dois charger de grands modèles et d'autres données binaires structurées sur une console de jeu sur CD plus aussi efficacement que possible. Quelle est la meilleure façon de le faire? Les données seront exportées d'une application Python. Ce projet passe-temps assez complexe.

Requierements:

  • pas de dépendance à l'égard de STL conforme entièrement aux standards - i peut utiliser USTL si
  • .
  • aussi peu que possible les frais généraux. Visez une solution si bon. qu'il pourrait être utilisé sur la Playstation originale, mais aussi moderne et élégante que possible.
  • pas de compatibilité arrière / avant nécessaire.
  • aucune copie de gros morceaux autour - de préférence les fichiers sont chargés dans la RAM en arrière-plan, et tous les gros morceaux directement accessibles à partir de là plus tard
  • .
  • ne doit pas compter sur la cible ayant la même boutisme et l'alignement, à savoir un plugin C en Python qui décharge ses struct sur le disque ne serait pas une très bonne idée.
  • devrait permettre de déplacer les données chargées autour, comme des fichiers individuels 1/3 de la taille de la RAM, la fragmentation peut être un problème. Pas MMU aux abus.
  • La robustesse est un super bonus, comme ma durée d'attention est très courte, à savoir que je changerais sauver une partie du code et d'oublier le chargement ou vice-versa, si au moins une mesure de sauvegarde stupide serait bien.
  • entre les données chargées interchangeabilité et les données générées runtime sans frais généraux d'exécution et sans de graves problèmes de gestion de la mémoire serait un joli bonus.

Je sorte d'avoir un demi-plan d'analyse des en-têtes-syntaxiques limité Python trivial, C qui utiliseraient struct avec des décalages au lieu de pointeurs et wrapper de commodité struct / classes dans l'application principale avec getters qui convertirait les compensations à bien pointeurs typés / références, mais je voudrais entendre vos suggestions.

Précision:. La demande est principalement sur les questions relatives au cadre de chargement de données et de gestion de la mémoire

Était-ce utile?

La solution

Ceci est un modèle de développement de jeu commun.

L'approche habituelle est de faire cuire les données dans une étape de pré-processus hors ligne. Les blobs résultants peuvent être diffusés en continu avec un minimum de frais généraux. Les blobs dépendent plate-forme et doivent contenir le bon alignement et endian-ness de la plate-forme cible.

Lors de l'exécution, vous pouvez simplement jeter un pointeur vers le fichier blob en mémoire. Vous pouvez traiter des structures imbriquées aussi bien. Si vous gardez une table des matières avec des décalages à toutes les valeurs de pointeur dans le blob, vous pouvez alors fixer-les pointeurs pour pointer vers l'adresse correcte. Ceci est similaire à la façon dont fonctionne le chargement dll.

Je travaille sur une bibliothèque de rubis, barbecue , que j'utilise pour cuisiner des données pour mon jeu iphone.

Voici la mise en page de mémoire que j'utilise pour l'en-tête de blob:

// Memory layout
//
// p begining of file in memory.
// p + 0 : num_pointers
// p + 4 : offset 0
// p + 8 : offset 1
// ...
// p + ((num_pointers - 1) * 4) : offset n-1
// p + (num_pointers * 4) : num_pointers   // again so we can figure out 
//                                            what memory to free.
// p + ((num_pointers + 1) * 4) : start of cooked data
//

Voici comment je charger le fichier blob binaire et corriger des pointeurs:

void* bbq_load(const char* filename)
{
    unsigned char* p;
    int size = LoadFileToMemory(filename, &p);
    if(size <= 0)
        return 0;

    // get the start of the pointer table
    unsigned int* ptr_table = (unsigned int*)p;
    unsigned int num_ptrs = *ptr_table;
    ptr_table++;

    // get the start of the actual data
    // the 2 is to skip past both num_pointer values
    unsigned char* base = p + ((num_ptrs + 2) * sizeof(unsigned int));

    // fix up the pointers
    while ((ptr_table + 1) < (unsigned int*)base)
    {
        unsigned int* ptr = (unsigned int*)(base + *ptr_table);
        *ptr = (unsigned int)((unsigned char*)ptr + *ptr);
        ptr_table++;
    }

    return base;
}

Mon barbecue bibliothèque est pas tout à fait prêt pour le prime time, mais il pourrait vous donner quelques idées sur la façon d'écrire vous-même en python.

Bonne chance!

Autres conseils

Sur les plateformes comme la Nintendo GameCube et DS, les modèles 3D sont généralement stockés dans un format personnalisé très simple:

  • Une tête courte contenant un nombre magique identification du fichier, le nombre de sommets, les normales, etc., et éventuellement une somme de contrôle des données suite à l'en-tête (Adler-32, CRC-16, etc.).
  • A éventuellement comprimé liste de 32 bits à virgule flottante 3-uplets pour chaque vecteur et normal.
  • Une liste éventuellement comprimé de bords ou faces.
  • Toutes les données sont dans le format natif endian de la plate-forme cible.
  • Le format de compression est souvent trivial (Huffman), simple (arithmétique) ou standard (gzip). Tous ces éléments nécessitent très peu de mémoire ou de puissance de calcul.

Vous pouvez prendre des formats comme ça comme un signal: il est tout à fait une représentation compacte

.

Ma suggestion est d'utiliser un format plus semblable à vos structures de données en mémoire, afin de minimiser le post-traitement et la copie. Si cela signifie que vous créez vous-même le format, soit. Vous avez des besoins extrêmes, des mesures si extrêmes sont nécessaires.

Je note que nulle part dans votre description demandez-vous « facilité de programmation ». : -)

Ainsi, voici ce qui vient à l'esprit pour moi comme un moyen de créer ceci:

  • Les données doivent être dans le même format sur disque, car il serait dans la mémoire de la cible, de telle sorte qu'il peut simplement tirer blobs à partir du disque en mémoire sans reformater. Selon la quantité de liberté que vous voulez en mettre les choses en mémoire, les « blobs » pourrait être le fichier entier, ou pourraient être plus petits bits dans ce; Je ne comprends pas assez bien vos données pour suggérer comment subdivisent mais probablement vous le pouvez. Parce que nous ne pouvons pas compter sur le même boutisme et l'alignement sur l'hôte, vous aurez besoin d'être un peu intelligent de traduire les choses lors de l'écriture des fichiers sur le côté hôte, mais au moins de cette façon vous avez seulement besoin d'un côté l'intelligence du transfert plutôt que sur les deux.

  • Afin de fournir un peu d'assurance que le code côté cible et côté hôte correspond, vous devez écrire ceci dans un formulaire où vous fournissez une description de données unique et ont un code de génération qui va générer à la fois la code côté cible C et le code de python côté hôte de celui-ci. Vous pourriez même avoir votre générateur générer un petit nombre « version » aléatoire dans le processus, et ont le code côté hôte écrire ceci dans l'en-tête de fichier et le côté cible vérifier, et vous donner une erreur si elles ne correspondent pas . (Le point d'utiliser une valeur aléatoire est que le seul bit d'information que vous aimez est de savoir si elles correspondent, et vous ne voulez pas avoir à augmenter manuellement.)

Pensez à stocker vos données dans un BLOB SQLite DB. SQLite est extrêmement portable et lighweight, ANSI C, possède à la fois C ++ et Python interfaces. Cela va prendre soin de gros fichiers, pas de fragmentation, les enregistrements de longueur variable avec un accès rapide, et ainsi de suite. Le reste est juste sérialisation de struct à ces BLOBs.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top