Há alguns meses, peguei novamente um PSP empoeirado de uma caixa e decidi portar meu
motor mostrado anteriormente
lá . Não houve problemas com a renderização do software - tudo funciona dessa maneira. Mas usar GU não era tão simples. Neste artigo, mostrarei um exemplo de como você pode escrever um aplicativo tridimensional simples para o PSP usando a GU.
Eu aviso antecipadamente que não existem guias de programação suficientes para o PSP e, portanto, algumas das minhas conclusões podem se mostrar incorretas. Mas, direto ao ponto.
A principal função do programa para o PSP, se alguém não souber, fica assim:
#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); }
A inicialização da GU é a seguinte:
Primeiro, solicitamos ponteiros para três buffers - buffer de tela, fora da tela e profundidade (buffer Z). Os buffers estão alinhados a 512 pixels por linha (embora o PSP tenha uma linha de 480 pixels). Você também precisa considerar o formato da cor do pixel. Neste exemplo, o formato GU_PSM_8888 é usado - 8 bits por componentes R, G, B e Alpha da cor do pixel. Para o buffer Z, o formato GU_PSM_4444 é usado simplesmente porque tem 16 bits - o buffer Z de 16 bits do PSP.
A função para consultar ponteiros para buffers é definida 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()))); }
Essas não são minhas funções - tirei-as de algum programa há muito tempo e apenas mudei um pouco. A memória está alocada na área de memória de vídeo. As texturas também devem ser colocadas lá, se possível, solicitando um ponteiro através de getStaticVramTexture, caso contrário, o desempenho diminuirá acentuadamente. Obviamente, nenhuma memória dinâmica é alocada durante essas solicitações, mas simplesmente uma parte do espaço de endereço PSP especificado é alocada para a tela e as texturas. Tanto quanto me lembro, o PSP possui apenas 2 megabytes de memória de vídeo - isso é muito pequeno para armazenar muitas texturas.
A programação do PSP GU é semelhante à programação para o OpenGL, com uma diferença - a execução dos comandos requer seu posicionamento na lista de exibição, e a memória dessa lista deve ser alocada antecipadamente e alinhada:
caractere estático não assinado __atributo __ ((alinhado (16))) DisplayList [262144];
Os comandos relacionados à transformação de coordenadas não requerem uma lista de exibição e podem ser executados em qualquer lugar do programa.
Você pode inicializar uma GU, por exemplo, assim:
Após concluir o trabalho com GU, é necessário chamar sceGuTerm ().
Depois de carregar a textura do tamanho (WidthImage; HeightImage) de qualquer maneira conveniente (um ponteiro de dados para os dados da textura - e é melhor colocá-lo na área de memória de vídeo), podemos exibi-lo.
Como exibir um polígono? Para desenhar a geometria da GU, o PSP pede para colocar todos os pontos em uma matriz, cujo ponteiro deve ser obtido primeiro com o comando sceGuGetMemory, passando o tamanho do bloco de memória solicitado em bytes. Mais abaixo neste ponteiro, você deve escrever uma matriz de pontos e pedir ao PSP para exibi-los, por exemplo, com o comando sceGumDrawArray com os parâmetros necessários. Mas qual é o formato desses pontos? Para o PSP, os dados do ponto são organizados em uma ordem específica e o tamanho da matriz que descreve um ponto deve ser múltiplo de 32 bytes: peso do vértice, coordenadas da textura, cor do ponto, normal ao ponto, coordenada do ponto. Nessa ordem. Para não me incomodar com o formato, defini um conjunto de estruturas e funções para trabalhar com eles:
Em seguida, você pode especificar a geometria (neste caso, o quadrado), por exemplo, assim:
E produza, por exemplo, assim:
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 saída, apontei para a função sceGumDrawArray o que exatamente eu desenho e qual é o formato do ponto (GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D | GU_NORMAL_32BITF | GU_TEXTURE_32BITF - o ponto consiste em cores, coordenadas, matriz de textura, coordenadas, matriz de textura, coordenadas e matriz de textura correspondentes). Desenhar só é possível com triângulos. Mas isso não é tudo ...
Tudo parece funcionar, mas só funciona se todos os pontos estiverem na frente dos olhos e visíveis. Quando pelo menos um ponto entra em alguma distância nebulosa, a GU se recusa a desenhar o polígono inteiro. Pelo que entendi, a GU do PSP exige que, em relação aos quatro planos de recorte (esquerdo, direito, superior e inferior (e o da frente saia automaticamente)), o ponto esteja dentro deste volume, caso contrário, a GU não concorda em exibi-lo. Problema. Mas nos jogos, gráficos 3D estão presentes e esses artefatos não são observados! Vamos ver como eles resolveram esse problema no PSP Quake 1, já que as fontes estão disponíveis para análise.
O que vemos da análise de origem? Mas, de fato, é isso:
Ou seja, no Quake 1, antes da conclusão, eles simplesmente transferem todos os pontos para o interior do volume que restringe a exibição ou os jogam fora (se a figura inteira não estiver visível). Como fazer isso? Você só precisa ler três matrizes - GU_PROJECTION, GU_MODEL, GU_VIEW. Multiplique-os e obtenha a matriz final de transformação de coordenadas. A partir dessa matriz, você pode retirar todos os planos necessários restringindo a vista (4 componentes do vetor resultante definem um plano com a equação ax + por + cz + w = 0). (a, b, c) é o vetor normal e w = a * x0 + b * y0 + c * z0 - caracteriza um certo ponto (x0, y0, z0) do plano. Nós não precisamos das coordenadas do ponto por conta própria - apenas saiba w.
O recorte é realizado da seguinte forma (para os quatro planos acima mencionados, sucessivamente em um ciclo):
Mas, para esse foco, precisamos das seguintes funções (desativadas do Quake 1):
E somente após realizar esse corte, você finalmente finalmente recebe corretamente a saída de gráficos tridimensionais no PSP usando a GU. Você pode criar um jogo! :)

A propósito, você também pode usar o processador de vetores PSP para produtos escalares de vetores. Por exemplo, aqui está uma função que determina se é necessário recortar (rasgado em pedaços do mesmo Quake 1 para PSP):
Tudo é simples aqui - eles colocaram os vetores planos e as coordenadas dos pontos nos registros e solicitaram à VFPU para executar o produto escalar.
→
Link para o aplicativo de exibição de textura mais simples
→
Link para o mecanismo PSP usando GU
PS: Eu sei que existem profissionais de programação para PSP. Talvez eles lhe digam por que o GU do PSP é tão organizado e como trabalhar com ele corretamente.