Vor ein paar Monaten nahm ich wieder eine staubige PSP aus einer Box und beschloss, meinen zuvor gezeigten
Motor dort zu portieren. Es gab keine Probleme beim Rendern von Software - alles funktioniert so. Die Verwendung von GU war jedoch nicht so einfach. In diesem Artikel zeige ich Ihnen ein Beispiel, wie Sie mit der GU eine einfache dreidimensionale Anwendung für die PSP schreiben können.
Ich warne Sie im Voraus, dass es nicht genügend Programmierhandbücher für die PSP gibt, und daher können sich einige meiner Schlussfolgerungen als falsch herausstellen. Aber auf den Punkt.
Die Hauptfunktion des Programms für die PSP, wenn jemand nicht weiß, sieht es so aus:
#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); }
Die Initialisierung der GU ist wie folgt:
Zunächst fordern wir Zeiger auf drei Puffer an - Bildschirm, Off-Screen und Tiefenpuffer (Z-Puffer). Puffer werden mit 512 Pixel pro Zeile ausgerichtet (obwohl PSP eine Zeile von 480 Pixel hat). Sie müssen auch das Pixelfarbformat berücksichtigen. In diesem Beispiel wird das Format GU_PSM_8888 verwendet - 8 Bit pro R-, G-, B- und Alpha-Komponente der Farbe des Pixels. Für den Z-Puffer wird das Format GU_PSM_4444 einfach verwendet, weil es 16 Bit umfasst - der 16-Bit-Z-Puffer des PSP.
Die Pufferzeiger-Anforderungsfunktion ist definiert als
#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()))); }
Dies sind nicht meine Funktionen - ich habe sie vor langer Zeit aus einem Programm übernommen und nur geringfügig geändert. Der Speicher wird im Videospeicherbereich zugewiesen. Wenn möglich, sollten dort auch Texturen platziert werden, die einen Zeiger über getStaticVramTexture anfordern, da sonst die Leistung stark abnimmt. Natürlich wird während solcher Anforderungen kein dynamischer Speicher zugewiesen, sondern lediglich ein Teil des angegebenen PSP-Adressraums wird für den Bildschirm und die Texturen zugewiesen. Soweit ich mich erinnere, verfügt PSP nur über 2 Megabyte Videospeicher - dies ist sehr klein, um viele Texturen zu speichern.
Die PSP-GU-Programmierung ähnelt der Programmierung für OpenGL mit einem Unterschied: Die Ausführung von Befehlen erfordert deren Platzierung in der Anzeigeliste, und der Speicher für diese Liste muss im Voraus zugewiesen und ausgerichtet werden:
statisches vorzeichenloses Zeichen __attribute __ ((ausgerichtet (16))) DisplayList [262144];
Befehle im Zusammenhang mit der Koordinatentransformation erfordern keine Anzeigeliste und können an einer beliebigen Stelle im Programm ausgeführt werden.
Sie können eine GU beispielsweise wie folgt initialisieren:
Nachdem Sie mit GU gearbeitet haben, sollten Sie sceGuTerm () aufrufen.
Nachdem Sie die Größentextur (WidthImage; HeightImage) auf eine bequeme Weise geladen haben (ein Datenzeiger auf die Texturdaten - und es ist besser, sie im Videospeicherbereich abzurufen), können wir sie anzeigen.
Wie zeige ich ein Polygon an? Um die GU-Geometrie zu zeichnen, fordert PSP auf, alle Punkte in ein Array einzufügen, dessen Zeiger zuerst mit dem Befehl sceGuGetMemory abgerufen werden muss, wobei die Größe des angeforderten Speicherblocks in Byte übergeben wird. Weiter unten in diesem Zeiger sollten Sie ein Array von Punkten schreiben und PSP bitten, diese anzuzeigen, z. B. mit dem Befehl sceGumDrawArray mit den erforderlichen Parametern. Aber wie ist das Format dieser Punkte? Für PSP sind die Punktdaten in einer bestimmten Reihenfolge angeordnet und die Größe des Arrays, das einen Punkt beschreibt, muss ein Vielfaches von 32 Bytes sein: Scheitelpunktgewicht, Texturkoordinaten, Punktfarbe, Normalpunkt, Punktkoordinate. In dieser Reihenfolge. Um mich nicht mit dem Format zu beschäftigen, habe ich eine Reihe von Strukturen und Funktionen für die Arbeit mit ihnen definiert:
Anschließend können Sie die Geometrie (in diesem Fall das Quadrat) beispielsweise wie folgt angeben:
Und geben Sie es zum Beispiel folgendermaßen aus:
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); }
Zur Anzeige I sceGumDrawArray Funktion habe, was ich male, und was ist das Format des Punktes (GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D | GU_NORMAL_32BITF | GU_TEXTURE_32BITF - Punkt besteht aus Farbkoordinaten, Normalen, Texturkoordinaten und erfordert die entsprechenden Koordinaten auf der Matrix multipliziert wird vor dem Ziehen). Zeichnen ist nur mit Dreiecken möglich. Aber das ist noch nicht alles ...
Alles scheint zu funktionieren, aber es funktioniert nur, wenn alle Punkte vor den Augen und sichtbar sind. Sobald mindestens ein Punkt in eine neblige Entfernung gelangt, weigert sich die GU, das gesamte Polygon zu zeichnen. Soweit ich weiß, erfordert die GU der PSP, dass der Punkt in Bezug auf die vier Schnittebenen (links, rechts, oben und unten (und die vordere wird automatisch ausgeblendet)) innerhalb dieses Volumens liegt, andernfalls stimmt die GU nicht zu, ihn anzuzeigen. Problem. Aber in Spielen sind 3D-Grafiken vorhanden und solche Artefakte werden nicht beobachtet! Mal sehen, wie sie dieses Problem in PSP Quake 1 gelöst haben, da die Quellen für die Analyse verfügbar sind.
Was sehen wir aus der Quellenanalyse? Aber tatsächlich ist dies was:
Das heißt, in Quake 1 übertragen sie vor dem Abschluss einfach alle Punkte auf das Innere des Volumens, das die Ansicht einschränkt, oder werfen sie ganz weg (wenn die gesamte Figur nicht sichtbar ist). Wie geht das? Sie müssen nur drei Matrizen lesen - GU_PROJECTION, GU_MODEL, GU_VIEW. Multiplizieren Sie sie und erhalten Sie die endgültige Koordinatentransformationsmatrix. Aus dieser Matrix können Sie alle erforderlichen Ebenen herausziehen, die die Ansicht einschränken (4 Komponenten des resultierenden Vektors definieren eine Ebene mit der Gleichung ax + by + cz + w = 0). (a, b, c) ist der Normalenvektor und w = a * x0 + b * y0 + c * z0 - charakterisiert einen bestimmten Punkt (x0, y0, z0) der Ebene. Wir brauchen die Koordinaten des Punktes nicht selbst - wissen Sie einfach w.
Das Abschneiden wird wie folgt durchgeführt (für die vier oben genannten Ebenen wiederum in einem Zyklus):
Für diesen Fokus benötigen wir jedoch die folgenden Funktionen (aus Quake 1 außer Betrieb genommen):
Und erst nach einem solchen Cut-Off erhalten Sie die Ausgabe dreidimensionaler Grafiken auf der PSP mit der GU endgültig korrekt. Sie können ein Spiel erstellen! :) :)

Übrigens können Sie den PSP-Vektorprozessor auch für das Skalarprodukt von Vektoren verwenden. Hier ist zum Beispiel eine Funktion, die bestimmt, ob überhaupt ein Clipping erforderlich ist (in Stücke aus demselben Quake 1 für PSP zerrissen):
Hier ist alles einfach - sie platzierten die Ebenenvektoren und Punktkoordinaten in den Registern und baten die VFPU, das Skalarprodukt durchzuführen.
→
Link zur einfachsten Texturanzeigeanwendung
→
Link zur PSP-Engine über GU
PS Ich weiß, dass es Programmierer für PSP gibt. Vielleicht werden sie dir sagen, warum die PSP-GU so angeordnet ist und wie man richtig damit arbeitet.