Pregunta

Necesito cargar modelos grandes y otros datos binarios estructurados en una consola de juegos antigua basada en CD de la manera más eficiente posible.¿Cuál es la mejor manera de hacerlo?Los datos se exportarán desde una aplicación Python.Este es un proyecto de hobby bastante elaborado.

Requisitos:

  • no dependo de STL totalmente compatible con los estándares; aunque podría usar uSTL.
  • los menores gastos generales posibles.Apunta a una solución tan buena.que podría usarse en la Playstation original y, sin embargo, ser lo más moderno y elegante posible.
  • no es necesaria compatibilidad con versiones anteriores o posteriores.
  • no se deben copiar fragmentos grandes; preferiblemente los archivos se cargan en la RAM en segundo plano y se accede a todos los fragmentos grandes directamente desde allí más adelante.
  • no debe confiar en que el objetivo tenga la misma endianidad y alineación, es decirun complemento C en Python que vuelque sus estructuras en el disco no sería una muy buena idea.
  • debería permitir mover los datos cargados, ya que con archivos individuales de 1/3 del tamaño de la RAM, la fragmentación puede ser un problema.No hay MMU de la que abusar.
  • la robustez es una gran ventaja, ya que mi capacidad de atención es muy corta, es decir,Cambiaría guardar parte del código y me olvidaría de cargarlo o viceversa, por lo que al menos una protección tonta sería buena.
  • La intercambiabilidad entre los datos cargados y los datos generados en tiempo de ejecución sin sobrecarga de tiempo de ejecución y sin problemas graves de administración de memoria sería una buena ventaja.

Tengo un semi-plan de análisis en Python, encabezados C triviales y de sintaxis limitada que usarían estructuras con compensaciones en lugar de punteros, y estructuras/clases contenedoras de conveniencia en la aplicación principal con captadores que convertirían compensaciones en punteros escritos correctamente. referencias, pero me gustaría escuchar sus sugerencias.

Aclaración:La solicitud se refiere principalmente al marco de carga de datos y a cuestiones de gestión de memoria.

¿Fue útil?

Solución

Este es un patrón de desarrollo de juegos común.

El método usual es cocinar los datos en una etapa de pre-proceso fuera de línea. Las burbujas resultantes pueden transmiten en con una sobrecarga mínima. Las burbujas son dependientes de la plataforma y deben contener la alineación apropiada y-dad endian de la plataforma de destino.

En tiempo de ejecución, sólo tiene que convertir un puntero al archivo blob en memoria. Se puede tratar con estructuras jerarquizadas también. Si se mantiene una tabla de contenidos con compensaciones a todos los valores del puntero dentro de la burbuja, a continuación, puede eliminar el efecto de los punteros para apuntar a la dirección correcta. Esto es similar a cómo funciona la carga de DLL.

He estado trabajando en una biblioteca de rubí, barbacoa , que utilizo para cocinar datos para mi juego de iPhone.

Aquí está el diseño de memoria que uso para la cabecera 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
//

Así es como me carga de archivos blob binario y el arreglo de punteros:

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

barbacoa biblioteca no está lista para el prime time, pero podría darle algunas ideas sobre cómo escribir uno usted mismo en Python.

Buena suerte!

Otros consejos

En las plataformas como la Nintendo GameCube y DS, modelos 3D se almacenan normalmente en un formato personalizado muy simple:

  • Una breve de cabeza, que contiene un número mágico identificar el archivo, el número de vértices, normales, etc., y, opcionalmente, una suma de comprobación de los datos después de la cabecera (Adler-32, CRC-16, etc).
  • Una lista posiblemente comprimido de 32 bits de coma flotante 3-tuplas para cada vector y normal.
  • Una lista posiblemente comprimido de bordes o caras.
  • Todos los datos están en el formato endian nativo de la plataforma de destino.
  • El formato de compresión es a menudo trivial (Huffman), simple (Aritmética), o estándar (gzip). Todo esto requiere muy poca memoria o capacidad de cálculo.

Usted podría tomar formatos como esa como una entrada: es una representación bastante compacto

.

Mi sugerencia es utilizar un formato más similar a las estructuras de datos en memoria, para minimizar el procesamiento posterior y la copia. Si eso significa que se crea el formato mismo, que así sea. Tiene necesidades extremas, por lo que se requieren medidas extremas.

Tomo nota de que en ninguna parte de su descripción es lo que pide "facilidad de programación". : -)

Por lo tanto, esto es lo que viene a la mente para mí como una forma de crear este:

  • Los datos deben estar en el mismo formato en disco, ya que sería en la memoria del objetivo, de tal manera que puede simplemente tirar de objetos binarios de disco en la memoria sin reformateándola. Dependiendo de la cantidad de libertad que desea poner las cosas en la memoria, las "manchas" puede ser todo el archivo, o podrían ser trozos más pequeños dentro de ella; No entiendo sus datos lo suficientemente bien como para sugerir cómo subdividir, pero presumiblemente se puede. Debido a que no podemos confiar en el mismo orden de bits y la alineación en el host, tendrá que ser algo inteligente sobre la traducción de las cosas al escribir los archivos en el lado del anfitrión, pero al menos de esta manera sólo se necesita la habilidad de un lado de la transferencia en lugar de en ambos.

  • Con el fin de proporcionar un poco de seguridad de que el código del lado del objetivo y del lado del host coincide, debe escribir esto en una forma en que proporciona una única descripción de los datos y tener algo de código de generación que va a generar tanto la código C-lado de destino y el código de Python-lado del anfitrión de ella. Usted podría incluso tener su generador generar un pequeño número aleatorio "versión" en el proceso, y tienen el código del lado del anfitrión escribir esto en la cabecera del archivo y el lado objetivo de comprobarlo, y le dará un error si no coinciden . (El punto de usar un valor aleatorio es que la única información poco lo que importa es si coinciden, y usted no quiere tener que incrementar de forma manual.)

Considere el almacenamiento de sus datos como BLOB en una base de datos SQLite. SQLite es extremadamente portátil y lighweight, ANSI C, tiene tanto interfaces de Python y C ++. Esto se encargará de archivos de gran tamaño, sin fragmentación, registros de longitud variable con un acceso rápido, y así sucesivamente. El resto es sólo serialización de estructuras a esas burbujas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top