Hace un par de meses, nuevamente saqué una PSP polvorienta de una caja y decidí portar allí mi
motor que se mostró anteriormente. No hubo problemas con la representación del software: todo funciona de esta manera. Pero usar GU no fue tan simple. En este artículo, le mostraré un ejemplo de cómo puede escribir una aplicación tridimensional simple para PSP utilizando la GU.
Te advierto de antemano que no hay suficientes guías de programación para la PSP y, por lo tanto, algunas de mis conclusiones pueden resultar incorrectas. Pero, al punto.
La función principal del programa para la PSP, si alguien no lo sabe, se ve así:
#include <pspkernel.h> #include <pspdebug.h> #include <pspdisplay.h> //---------------------------------------------------------------------------------------- PSP_MODULE_INFO("GUTexture", 0, 1, 1); PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER|THREAD_ATTR_VFPU); void dump_threadstatus(void); bool done=false; int exit_callback(int arg1,int arg2,void *common) { done=true; return(0); } int CallbackThread(SceSize args, void *argp) { int cbid; cbid=sceKernelCreateCallback("Exit Callback",exit_callback,NULL); sceKernelRegisterExitCallback(cbid); sceKernelSleepThreadCB(); return(0); } int SetupCallbacks(void) { int thid = 0; thid=sceKernelCreateThread("update_thread",CallbackThread,0x11,0xFA0,0,0); if(thid>=0) sceKernelStartThread(thid, 0, 0); return(thid); } //---------------------------------------------------------------------------------------- // //---------------------------------------------------------------------------------------- int main(int argc, char **argv) { pspDebugScreenInit(); // SetupCallbacks(); // ………. // sceKernelExitGame(); return(0); }
La inicialización de la GU es la siguiente:
Primero, solicitamos punteros a tres buffers: pantalla, fuera de pantalla y profundidad (Z-buffer). Los buffers están alineados a 512 píxeles por línea (aunque PSP tiene una línea de 480 píxeles). También debe tener en cuenta el formato de color de píxeles. En este ejemplo, se utiliza el formato GU_PSM_8888: 8 bits por R, G, B y componentes alfa del color del píxel. Para el búfer Z, el formato GU_PSM_4444 se usa simplemente porque tiene 16 bits, el búfer Z de 16 bits del PSP.
La función para consultar punteros a buffers se define como
#include <pspge.h> #include <pspgu.h> static unsigned int staticOffset=0; static unsigned int getMemorySize(unsigned int width,unsigned int height,unsigned int psm) { switch (psm) { case GU_PSM_T4: return((width*height)>>1); case GU_PSM_T8: return(width*height); case GU_PSM_5650: case GU_PSM_5551: case GU_PSM_4444: case GU_PSM_T16: return(2*width*height); case GU_PSM_8888: case GU_PSM_T32: return(4*width*height); default: return(0); } } void* getStaticVramBuffer(unsigned int width,unsigned int height,unsigned int psm) { unsigned int memSize=getMemorySize(width,height,psm); void* result=(void*)staticOffset; staticOffset+=memSize; return(result); } void* getStaticVramTexture(unsigned int width,unsigned int height,unsigned int psm) { void* result=getStaticVramBuffer(width,height,psm); return((void*)(((unsigned int)result) + ((unsigned int)sceGeEdramGetAddr()))); }
Estas no son mis funciones: las tomé de algún programa hace mucho tiempo y solo cambié ligeramente. La memoria se asigna en el área de memoria de video. Las texturas también deben colocarse allí si es posible, solicitando un puntero a través de getStaticVramTexture, de lo contrario el rendimiento disminuirá bruscamente. Por supuesto, no se asigna memoria dinámica durante tales solicitudes, sino que simplemente se asigna una parte del espacio de direcciones PSP especificado para la pantalla y las texturas. Hasta donde recuerdo, PSP tiene solo 2 megabytes de memoria de video, es muy pequeño para almacenar muchas texturas.
La programación de PSP GU es similar a la programación para OpenGL con una diferencia: la ejecución de comandos requiere su ubicación en la lista de visualización, y la memoria para esta lista debe asignarse por adelantado y alinearse:
char estático sin signo __attribute__ ((alineado (16))) DisplayList [262144];
Los comandos relacionados con la transformación de coordenadas no requieren una lista de visualización y se pueden ejecutar en cualquier parte del programa.
Puede inicializar una GU, por ejemplo, así:
Después de completar el trabajo con GU, es necesario llamar a sceGuTerm ().
Después de cargar una textura de tamaño (WidthImage; HeightImage) de cualquier manera conveniente (un puntero de datos para texturizar datos, y es mejor colocarlo en el área de memoria de video), podemos mostrarlo.
¿Cómo mostrar un polígono? Para dibujar la geometría GU, PSP solicita colocar todos los puntos en una matriz, el puntero al que primero debe obtenerse con el comando sceGuGetMemory, pasándole el tamaño del bloque de memoria solicitado en bytes. Más abajo en este puntero, debe escribir una matriz de puntos y pedirle a PSP que los muestre, por ejemplo, con el comando sceGumDrawArray con los parámetros necesarios. Pero, ¿cuál es el formato de estos puntos? Para PSP, los datos de puntos se organizan en un orden específico y el tamaño de la matriz que describe un punto debe ser un múltiplo de 32 bytes: peso de vértice, coordenadas de textura, color de punto, normal a punto, coordenada de punto. En ese orden Para no molestarme con el formato, definí un conjunto de estructuras y funciones para trabajar con ellos:
Luego puede especificar la geometría (en este caso, el cuadrado), por ejemplo, así:
Y generarlo, por ejemplo, así:
size_t vertex_amount=vector_point.size(); SGuNVCTPoint *sGuNVCTPoint_Ptr=(SGuNVCTPoint*)sceGuGetMemory(vertex_amount*sizeof(SGuNVCTPoint)); if (sGuNVCTPoint_Ptr!=NULL) { for(size_t n=0;n<vertex_amount;n++) sGuNVCTPoint_Ptr[n]=vector_point[n]; sceGumDrawArray(GU_TRIANGLE_FAN,GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D|GU_NORMAL_32BITF|GU_TEXTURE_32BITF,vertex_amount,0,sGuNVCTPoint_Ptr); }
Para la salida, señalé a la función sceGumDrawArray qué es exactamente lo que dibujo y cuál es el formato del punto (GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D | GU_NORMAL_32BITF | GU_TEXTURE_32BITF - el punto consiste en el color, las coordenadas, la multiplicación, la normalidad, la textura normal, las coordenadas correspondientes. Dibujar solo es posible con triángulos. Pero eso no es todo ...
Todo parece funcionar, pero solo funciona si todos los puntos están delante de los ojos y son visibles. Una vez que al menos un punto entra en una distancia de niebla, el GU se niega a dibujar todo el polígono. Según tengo entendido, la GU de la PSP requiere que, en relación con los cuatro planos de recorte (izquierdo, derecho, superior e inferior (y el frontal se verá automáticamente)), el punto se encuentra dentro de este volumen; de lo contrario, la GU no acepta mostrarlo. Problema ¡Pero en los juegos, los gráficos 3D están presentes y no se observan tales artefactos! Veamos cómo resolvieron este problema en PSP Quake 1, ya que las fuentes están disponibles para su análisis.
¿Qué vemos en el análisis de la fuente? Pero, de hecho, esto es lo que:
Es decir, en Quake 1, antes de la conclusión, simplemente transfieren todos los puntos al interior del volumen que restringe la vista, o los descartan por completo (si la figura completa no es visible). Como hacer esto Solo necesita leer tres matrices: GU_PROJECTION, GU_MODEL, GU_VIEW. Multiplíquelos y obtenga la matriz de transformación de coordenadas final. De esta matriz, puede extraer todos los planos necesarios que restringen la vista (4 componentes del vector resultante definen un plano con la ecuación ax + by + cz + w = 0). (a, b, c) es el vector normal, y w = a * x0 + b * y0 + c * z0 - caracteriza un cierto punto (x0, y0, z0) del plano. No necesitamos las coordenadas del punto nosotros mismos, solo sepamos w.
El recorte se realiza de la siguiente manera (para los cuatro planos mencionados a su vez en un ciclo):
Pero para este enfoque, necesitamos las siguientes funciones (retiradas del Quake 1):
Y solo después de realizar tal corte, finalmente finalmente recibe correctamente la salida de gráficos tridimensionales en la PSP utilizando la GU. ¡Puedes crear un juego! :)

Por cierto, también puede usar el procesador de vectores PSP para productos escalares de vectores. Por ejemplo, aquí hay una función que determina si se requiere recorte (desgarrado del mismo Quake 1 para PSP):
Aquí todo es simple: colocaron los vectores planos y las coordenadas de los puntos en los registros y le pidieron a la VFPU que realizara el producto escalar.
→
Enlace a la aplicación de visualización de texturas más simple
→
Enlace al motor PSP usando GU
PD : Sé que hay profesionales de programación para PSP. Tal vez le dirán por qué la GU de PSP está tan organizada y cómo trabajar con ella correctamente.