Domanda

ho bisogno di caricare modelli di grandi dimensioni e altri dati binari strutturati su una console di gioco basata su CD più vecchio nel modo più efficiente possibile. Qual è il modo migliore per farlo? I dati verranno esportati da un'applicazione Python. Si tratta di un progetto hobby piuttosto elaborata.

requierements:

  • nessuna dipendenza da STL compatibile completamente normale - potrei usare uSTL se
  • .
  • il meno possibile in testa. Obiettivo per una soluzione così buono. che potrebbe essere utilizzato sull'originale Playstation, e tuttavia come moderno ed elegante possibile.
  • non indietro / avanti compatibilità necessario.
  • nessuna copia di pezzi di grandi dimensioni in tutto - i file di preferenza vengono caricati nella RAM in background, e tutte le grandi blocchi a cui si accede direttamente da lì in seguito
  • .
  • non deve rifarsi a bersaglio avente lo stesso endianness e l'allineamento, cioè un plugin C in Python che scarica le sue struct disco potrebbe non essere una buona idea.
  • dovrebbe permettere di spostare i dati caricati in giro, come con singoli file di 1/3 la dimensione della RAM, la frammentazione potrebbe essere un problema. No MMU ad abusi.
  • robustezza è un grande bonus, come la mia capacità di attenzione è molto breve, vale a dire vorrei cambiare salvare parte del codice e dimenticare il caricamento di una o viceversa, così almeno una salvaguardia muto sarebbe bello.
  • intercambiabilità tra i dati caricati e dati di runtime generati senza spese generali di esecuzione e senza problemi di gestione della memoria gravi sarebbe un bel bonus.

I tipi di avere un semi-progetto di analisi in Python banali, intestazioni C limitato-sintassi che userebbero le strutture con offset invece di puntatori, e le strutture convenienza involucro / classi in applicazione principale con getter che sarebbe convertire offset a correttamente puntatori digitati / riferimenti, ma mi piacerebbe sentire i vostri suggerimenti.

Chiarimento:. La richiesta è principalmente di questioni caricamento dei dati e la gestione della memoria quadro

È stato utile?

Soluzione

Si tratta di un modello comune di sviluppo del gioco.

L'approccio comune è quello di cucinare i dati in una fase di pre-processo non in linea. Le macchie risultanti possono essere trasmessi con minimo carico. Le macchie sono dipendente dalla piattaforma e devono contenere il corretto allineamento e endian-ness della piattaforma di destinazione.

In fase di runtime, si può semplicemente lanciare un puntatore al file blob in memoria. Si può trattare con strutture nidificate pure. Se si mantiene una tabella di contenuti con offset a tutti i valori di puntatore all'interno del blob, si può quindi fissare-up i puntatori per indicare l'indirizzo corretto. Questo è simile a come funziona caricamento della DLL.

Ho lavorato su una libreria rubino, barbecue , che uso per cucinare i dati per il mio gioco iPhone.

Ecco il layout di memoria che uso per l'intestazione 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
//

Ecco come si carica il file blob binario e sistemare puntatori:

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;
}

bbq biblioteca non è ancora pronto per il prime time, ma potrebbe darvi qualche idea su come scrivere uno voi stessi in Python.

Buona fortuna!

Altri suggerimenti

su piattaforme come il Nintendo GameCube e DS, i modelli 3D sono in genere memorizzati in maniera molto semplice formato personalizzato:

  • Una breve intestazione, contenente un numero magico che identifica il file, il numero di vertici, normali, ecc, e facoltativamente un valore dei dati che seguono l'intestazione (Adler-32, CRC-16, ecc).
  • Un elenco possibilmente compressa a virgola mobile 3-tuple a 32 bit per ogni vettore e normale.
  • Una lista eventualmente compresso dei bordi o facce.
  • Tutti i dati sono in formato Endian nativo della piattaforma di destinazione.
  • Il formato di compressione è spesso banale (Huffman), semplice (aritmetica), o standard (gzip). Tutti questi richiedono poca memoria o la potenza di calcolo.

Si potrebbe prendere formati così come spunto: si tratta di una rappresentazione abbastanza compatto

.

Il mio suggerimento è quello di utilizzare un formato più simile alle vostre strutture di dati in memoria, per ridurre al minimo la post-elaborazione e la copia. Se questo significa che si crea il formato da soli, così sia. Hai esigenze estreme, sono necessarie misure così estreme.

Faccio notare che da nessuna parte nella descrizione me lo chiedi per "facilità di programmazione". : -)

Quindi, ecco cosa viene in mente per me come un modo per creare questo:

  • I dati devono essere nello stesso formato su disco come sarebbe nella memoria del bersaglio, in modo da poter semplicemente tirare macchie dal disco nella memoria senza riformattazione. A seconda di quanto si vuole la libertà nel mettere le cose nella memoria, le "macchie" potrebbe essere l'intero file, o potrebbero essere i bit più piccoli al suo interno; Non capisco i dati abbastanza bene per suggerire come suddividerlo, ma presumibilmente si può. Perché non possiamo contare sulla stessa endian e l'allineamento sull'host, è necessario essere un po 'intelligente di tradurre le cose quando si scrivono i file sul lato host, ma almeno in questo modo è necessario solo la bravura da un lato del trasferimento, piuttosto che su entrambi.

  • Al fine di fornire un po 'di garanzia che il codice target-side e lato host corrisponde, si dovrebbe scrivere questo in un modulo in cui si fornisce una singola descrizione dei dati e hanno una certa generazione di codice che genererà sia il codice C bersaglio lato e il codice Python lato host da esso. Si potrebbe anche avere il generatore generare un piccolo numero casuale "versione" nel processo, e hanno il codice lato host scrittura presente nell'intestazione del file e il target-side controllare, e vi darà un errore se non corrispondono . (Il punto di usare un valore casuale è che l'unico bit di informazione che ti interessa è se corrispondono, e non si vuole avere a incrementare manualmente.)

Consideriamo l'archiviazione dei dati BLOB in uno SQLite DB. SQLite è estremamente portatile e lighweight, ANSI C, ha sia C ++ e interfacce Python. Questo si prenderà cura di file di grandi dimensioni, senza frammentazione, record di lunghezza variabile con accesso rapido, e così via. Il resto è solo la serializzazione di struct a questi BLOB.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top