Il y a quelques mois, j'ai de nouveau sorti une PSP poussiéreuse d'une boîte et j'ai décidé d'y porter mon
moteur précédemment montré. Il n'y a eu aucun problème avec le rendu logiciel - tout fonctionne de cette façon. Mais utiliser GU n'était pas si simple. Dans cet article, je vais vous montrer comment vous pouvez écrire une application tridimensionnelle simple pour la PSP à l'aide du GU.
Je vous préviens à l'avance qu'il n'y a pas suffisamment de guides de programmation pour la PSP, et donc certaines de mes conclusions peuvent s'avérer incorrectes. Mais, au fait.
La fonction principale du programme pour la PSP, si quelqu'un ne le sait pas, cela ressemble Ă ceci:
#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); }
L'initialisation du GU est la suivante:
Tout d'abord, nous demandons des pointeurs vers trois tampons - écran, hors écran et tampon de profondeur (Z-buffer). Les tampons sont alignés à 512 pixels par ligne (bien que la PSP ait une ligne de 480 pixels). Vous devez également tenir compte du format de couleur des pixels. Dans cet exemple, le format GU_PSM_8888 est utilisé - 8 bits par composants R, G, B et Alpha de la couleur du pixel. Pour le tampon Z, le format GU_PSM_4444 est utilisé simplement parce qu'il est de 16 bits - le tampon Z 16 bits de la PSP.
La fonction d'interrogation des pointeurs vers les tampons est définie comme
#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()))); }
Ce ne sont pas mes fonctions - je les ai prises dans un programme il y a longtemps et je n'ai que légèrement changé. La mémoire est allouée dans la zone de mémoire vidéo. Les textures doivent également y être placées si possible, en demandant un pointeur via getStaticVramTexture, sinon les performances chuteront fortement. Bien sûr, aucune mémoire dynamique n'est allouée lors de telles requêtes, mais simplement une partie de l'espace d'adressage PSP spécifié est alloué pour l'écran et les textures. Pour autant que je me souvienne, la PSP ne dispose que de 2 mégaoctets de mémoire vidéo - elle est très petite pour stocker de nombreuses textures.
La programmation PSP GU est similaire à la programmation pour OpenGL avec une différence - l'exécution des commandes nécessite leur placement dans la liste d'affichage, et la mémoire de cette liste doit être pré-allouée et alignée:
caractère non signé statique __attribute __ ((aligné (16))) DisplayList [262144];
Les commandes liées à la transformation des coordonnées ne nécessitent pas de liste d'affichage et peuvent être exécutées n'importe où dans le programme.
Vous pouvez initialiser un GU, par exemple, comme ceci:
Après avoir terminé le travail avec GU, il est nécessaire d'appeler sceGuTerm ().
Après avoir chargé la texture de taille (WidthImage; HeightImage) de toute manière pratique (un pointeur de données vers les données de texture - et il est préférable de l’obtenir dans la zone de mémoire vidéo), nous pouvons l’afficher.
Comment afficher un polygone? Pour dessiner la géométrie GU, PSP demande de mettre tous les points dans un tableau, dont le pointeur doit d'abord être obtenu avec la commande sceGuGetMemory, en lui passant la taille du bloc de mémoire demandé en octets. Plus bas dans ce pointeur, vous devez écrire un tableau de points et demander à PSP de les afficher, par exemple, avec la commande sceGumDrawArray avec les paramètres nécessaires. Mais quel est le format de ces points? Pour PSP, les données de points sont organisées dans un ordre spécifique et la taille du tableau décrivant un point doit être un multiple de 32 octets: poids du sommet, coordonnées de texture, couleur du point, normal au point, coordonnée du point. Dans cet ordre. Afin de ne pas déranger avec le format, j'ai défini un ensemble de structures et de fonctions pour travailler avec eux:
Ensuite, vous pouvez spécifier la géométrie (dans ce cas, le carré), par exemple, comme ceci:
Et sortez-le, par exemple, comme ceci:
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); }
Pour la sortie, j'ai indiqué à la fonction sceGumDrawArray ce que je dessine exactement et quel est le format du point (GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D | GU_NORMAL_32BITF | GU_TEXTURE_32BITF - le point est composé de couleurs, de coordonnées, normales, de coordonnées de texture et de multiplication correspondantes). Le dessin n'est possible qu'avec des triangles. Mais ce n'est pas tout ...
Tout semble fonctionner, mais cela ne fonctionne que si tous les points sont devant les yeux et visibles. Une fois qu'au moins un point se trouve dans une certaine distance brumeuse, le GU refuse de dessiner le polygone entier. Si je comprends bien, le GU de la PSP exige que, par rapport aux quatre plans de détourage (gauche, droite, haut et bas (et le devant se révélera automatiquement)), le point se trouve à l'intérieur de ce volume, sinon le GU n'accepte pas de l'afficher. Problème. Mais dans les jeux, les graphismes 3D sont présents et de tels artefacts ne sont pas observés! Voyons comment ils ont résolu ce problème dans PSP Quake 1, car les sources sont disponibles pour analyse.
Que voyons-nous de l'analyse des sources? Mais en fait, c'est ce que:
Autrement dit, dans Quake 1, avant la conclusion, ils transfèrent simplement tous les points à l'intérieur du volume qui restreint la vue, ou les jettent complètement (si la figure entière n'est pas visible). Comment faire ça? Il vous suffit de lire trois matrices - GU_PROJECTION, GU_MODEL, GU_VIEW. Multipliez-les et obtenez la matrice de transformation de coordonnées finale. De cette matrice, vous pouvez retirer tous les plans nécessaires restreignant la vue (4 composantes du vecteur résultant définissent un plan avec l'équation ax + par + cz + w = ​​0). (a, b, c) est le vecteur normal, et w = a * x0 + b * y0 + c * z0 - caractérise un certain point (x0, y0, z0) du plan. Nous n'avons pas besoin des coordonnées du point nous-mêmes - sachez simplement w.
L'écrêtage s'effectue comme suit (pour les quatre plans susmentionnés tour à tour dans un cycle):
Mais pour ce focus, nous avons besoin des fonctions suivantes (désaffectées de Quake 1):
Et seulement après avoir effectué une telle coupure, vous recevez enfin enfin correctement la sortie des graphiques en trois dimensions sur la PSP en utilisant le GU. Vous pouvez créer un jeu! :)

Par ailleurs, vous pouvez également utiliser le processeur vectoriel PSP pour le produit scalaire des vecteurs. Par exemple, voici une fonction qui détermine si l'écrêtage est requis (déchiré en morceaux du même Quake 1 pour PSP):
Tout est simple ici - ils ont placé les vecteurs plans et les coordonnées ponctuelles dans les registres et ont demandé au VFPU de réaliser le produit scalaire.
→
Lien vers l'application d'affichage de texture la plus simple
→
Lien vers le moteur PSP Ă l'aide de GU
PS Je sais qu'il existe des professionnels de la programmation pour PSP. Peut-être qu'ils vous diront pourquoi le GU PSP est ainsi organisé et comment l'utiliser correctement.