عرض رسومات ثلاثية الأبعاد على PSP

قبل شهرين ، أخرجت مرة أخرى PSP متربة من صندوق وقررت نقل محركي الذي أظهرته سابقًا هناك . لم تكن هناك مشاكل في عرض البرامج - كل شيء يعمل بهذه الطريقة. لكن استخدام GU لم يكن بهذه البساطة. في هذه المقالة ، سأوضح لك مثالًا لكيفية كتابة تطبيق بسيط ثلاثي الأبعاد لـ PSP باستخدام GU.

أحذرك مقدمًا من عدم وجود أدلة برمجة كافية لـ PSP ، وبالتالي قد تتضح أن بعض استنتاجاتي غير صحيحة. ولكن ، في صميم الموضوع.

الوظيفة الرئيسية لبرنامج PSP ، إذا كان أي شخص لا يعرف ، يبدو كما يلي:

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

تهيئة GU على النحو التالي:

أولاً ، نطلب مؤشرات إلى ثلاثة مخازن مؤقتة - حاجز للشاشة ، وخارج الشاشة ، ومخزن للعمق (Z-buffer). تتم محاذاة المخازن المؤقتة عند 512 بكسل لكل سطر (على الرغم من أن PSP يحتوي على خط 480 بكسل). تحتاج أيضًا إلى مراعاة تنسيق لون البكسل. في هذا المثال ، يتم استخدام التنسيق GU_PSM_8888 - 8 بت لكل مكون من مكونات R و G و B و Alpha بلون البكسل. بالنسبة إلى المخزن المؤقت Z ، يتم استخدام تنسيق GU_PSM_4444 ببساطة لأنه 16 بت - المخزن المؤقت Z 16 بت الخاص بـ PSP.

 //  #define SCREEN_WIDTH 480 #define SCREEN_HEIGHT 272 #define SCREEN_LINE_WIDTH 512 void* fbp0=getStaticVramBuffer(SCREEN_LINE_WIDTH, SCREEN_HEIGHT,GU_PSM_8888); void* fbp1=getStaticVramBuffer(SCREEN_LINE_WIDTH, SCREEN_HEIGHT,GU_PSM_8888); void* zbp=getStaticVramBuffer(SCREEN_LINE_WIDTH, SCREEN_HEIGHT,GU_PSM_4444); 

يتم تعريف وظيفة الاستعلام عن المؤشرات إلى المخازن المؤقتة على أنها

 #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()))); } 

هذه ليست وظائفي - لقد أخذتها من برنامج ما منذ فترة طويلة ولم تتغير إلا قليلاً. يتم تخصيص الذاكرة في منطقة ذاكرة الفيديو. يجب أيضًا وضع القوام هناك إذا أمكن ، وطلب مؤشر من خلال getStaticVramTexture ، وإلا سينخفض ​​الأداء بشكل حاد. بالطبع ، لا يتم تخصيص ذاكرة ديناميكية أثناء هذه الطلبات ، ولكن ببساطة يتم تخصيص جزء من مساحة عنوان PSP المحددة للشاشة والقوام. بقدر ما أتذكر ، فإن PSP لا يحتوي إلا على 2 ميغابايت من ذاكرة الفيديو - وهي صغيرة جدًا لتخزين الكثير من الأنسجة.

تشبه برمجة PSP GU البرمجة الخاصة بـ OpenGL بفارق واحد - يتطلب تنفيذ الأوامر وضعها في قائمة العرض ، ويجب تخصيص ذاكرة هذه القائمة مسبقًا ومواءمتها:
حرف ثابت غير موقّع __صفة __ ((محاذاة (16))) DisplayList [262144] ؛
لا تتطلب الأوامر المتعلقة بتنسيق التحويل قائمة عرض ويمكن تنفيذها في أي مكان في البرنامج.

يمكنك تهيئة GU ، على سبيل المثال ، مثل:

 //    PSP #define VIRTUAL_SCREEN_SIZE 2048 //   #define SCREEN_ASPECT 16.0f/9.0f //   #define NEAR_PLANE_Z 5.0f //   #define FAR_PLANE_Z 4096.0f //  #define EYE_ANGLE 60.0f //  GU sceGuInit(); //        -    , .. GU_DIRECT sceGuStart(GU_DIRECT,DisplayList); //   -  ,    ,   (,   ) sceGuDrawBuffer(GU_PSM_8888,fbp0,SCREEN_LINE_WIDTH); //    -  ,   ,   sceGuDispBuffer(SCREEN_WIDTH,SCREEN_HEIGHT,fbp1,SCREEN_LINE_WIDTH); //   -           sceGuDepthBuffer(zbp,SCREEN_LINE_WIDTH); //      4096x4096 ( PSP    ) sceGuOffset(VIRTUAL_SCREEN_SIZE-(SCREEN_WIDTH/2),VIRTUAL_SCREEN_SIZE-(SCREEN_HEIGHT/2));//   //   -  -      sceGuViewport(VIRTUAL_SCREEN_SIZE,VIRTUAL_SCREEN_SIZE,SCREEN_WIDTH,SCREEN_HEIGHT); //      -      (     0  65535 !) sceGuDepthRange(65535,0); //        sceGuScissor(0,0,SCREEN_WIDTH,SCREEN_HEIGHT); sceGuEnable(GU_SCISSOR_TEST); sceGuEnable(GU_CLIP_PLANES); //   sceGumMatrixMode(GU_PROJECTION); sceGumLoadIdentity(); sceGumPerspective(EYE_ANGLE,SCREEN_ASPECT,NEAR_PLANE_Z,FAR_PLANE_Z); //      sceGuShadeModel(GU_SMOOTH); //   sceGuDepthFunc(GU_GEQUAL); sceGuEnable(GU_DEPTH_TEST); sceGuDepthMask(GU_FALSE); //   ,      sceGuFrontFace(GU_CCW); sceGuDisable(GU_CULL_FACE); //  sceGuDisable(GU_BLEND); sceGuBlendFunc(GU_ADD,GU_SRC_ALPHA,GU_ONE_MINUS_SRC_ALPHA,0,0); //   sceGuFinish(); sceGuSync(GU_SYNC_WAIT,GU_SYNC_FINISH); sceGuDisplay(GU_TRUE); 

بعد الانتهاء من العمل مع GU ، من الضروري استدعاء sceGuTerm ().

بعد تحميل نسيج الحجم (WidthImage ؛ HeightImage) بأي طريقة مناسبة (مؤشر البيانات إلى بيانات النسيج - ومن الأفضل الحصول عليه في منطقة ذاكرة الفيديو) ، يمكننا عرضه.

  //  sceGuStart(GU_DIRECT,DisplayList); //     sceGuClearColor(0); sceGuClearDepth(0); sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); //   sceGumMatrixMode(GU_PROJECTION); sceGumLoadIdentity(); sceGumPerspective(EYE_ANGLE,SCREEN_ASPECT,NEAR_PLANE_Z,FAR_PLANE_Z); sceGumUpdateMatrix();. //  sceGumMatrixMode(GU_TEXTURE); sceGumLoadIdentity(); sceGumMatrixMode(GU_VIEW); sceGumLoadIdentity(); sceGumMatrixMode(GU_MODEL); sceGumLoadIdentity(); //    sceGuColor(0xffffffff);//  sceGuEnable(GU_TEXTURE_2D); sceGuTexMode(GU_PSM_8888,0,0,0); sceGuTexImage(0,WidthImage,HeightImage,WidthImage,Data); sceGuTexFunc(GU_TFX_MODULATE,GU_TCC_RGBA); sceGuTexFilter(GU_NEAREST,GU_NEAREST); sceGuTexWrap(GU_REPEAT,GU_REPEAT); sceGuTexScale(1,1); sceGuTexOffset(0,0); //      … sceGuDisable(GU_TEXTURE_2D); //    sceGuFinish(); sceGuSync(GU_SYNC_WAIT,GU_SYNC_FINISH); //  ,     sceDisplayWaitVblankStart(); sceGuSwapBuffers(); 

كيفية عرض مضلع؟ لرسم هندسة GU ، يطلب PSP وضع جميع النقاط في مصفوفة ، يجب الحصول على المؤشر أولاً باستخدام الأمر sceGuGetMemory ، بتمريره حجم كتلة الذاكرة المطلوبة بالبايت. بعد هذا المؤشر ، يجب كتابة مجموعة من النقاط واطلب من PSP عرضها ، على سبيل المثال ، باستخدام الأمر sceGumDrawArray مع المعلمات الضرورية. ولكن ما هو شكل هذه النقاط؟ بالنسبة لـ PSP ، يتم ترتيب بيانات النقاط بترتيب معين ويجب أن يكون حجم المصفوفة التي تصف نقطة واحدة مضاعفات 32 بايت: وزن الرأس ، إحداثيات النسيج ، لون النقطة ، عادي إلى نقطة ، إحداثيات نقطة. بهذا الترتيب. لكي لا تهتم بالتنسيق ، حددت مجموعة من الهياكل والوظائف للعمل معها:

 //#pragma pack(1) //[for vertices(1-8)] [weights (0-8)] [texture uv] [color] [normal] [vertex] [/for] #pragma pack(1) //  struct SGuVertex { float X; float Y; float Z; }; //   struct SGuNormal { float Nx; float Ny; float Nz; }; //  struct SGuTexture { float U; float V; }; //  struct SGuColor { unsigned long Color; }; #pragma pack() #pragma pack(32) //  , , ,  struct SGuNVCTPoint { SGuTexture sGuTexture; SGuColor sGuColor; SGuNormal sGuNormal; SGuVertex sGuVertex; }; #pragma pack() void SetVertexCoord(SGuVertex &sGuVertex,float x,float y,float z);//   void SetNormalCoord(SGuNormal &sGuNormal,float nx,float ny,float nz);//   void SetTextureCoord(SGuTexture &sGuTexture,float u,float v);//   void SetColorValue(SGuColor &sGuColor,unsigned long color);//  //---------------------------------------------------------------------------------------------------- //   //---------------------------------------------------------------------------------------------------- void CMain::SetVertexCoord(SGuVertex &sGuVertex,float x,float y,float z) { sGuVertex.X=x; sGuVertex.Y=y; sGuVertex.Z=z; } //---------------------------------------------------------------------------------------------------- //   //---------------------------------------------------------------------------------------------------- void CMain::SetNormalCoord(SGuNormal &sGuNormal,float nx,float ny,float nz) { sGuNormal.Nx=nx; sGuNormal.Ny=ny; sGuNormal.Nz=nz; } //---------------------------------------------------------------------------------------------------- //   //---------------------------------------------------------------------------------------------------- void CMain::SetTextureCoord(SGuTexture &sGuTexture,float u,float v) { sGuTexture.U=u; sGuTexture.V=v; } //---------------------------------------------------------------------------------------------------- //  //---------------------------------------------------------------------------------------------------- void CMain::SetColorValue(SGuColor &sGuColor,unsigned long color) { sGuColor.Color=color; } 

ثم يمكنك تحديد الشكل الهندسي (في هذه الحالة ، المربع) ، على سبيل المثال ، مثل:

  //  SGuNVCTPoint sGuNVCTPoint; vector<SGuNVCTPoint> vector_point; SetVertexCoord(sGuNVCTPoint.sGuVertex,-100,100,0); SetTextureCoord(sGuNVCTPoint.sGuTexture,0,0); SetNormalCoord(sGuNVCTPoint.sGuNormal,0,0,1); SetColorValue(sGuNVCTPoint.sGuColor,0xFFFFFFFF); vector_point.push_back(sGuNVCTPoint); SetVertexCoord(sGuNVCTPoint.sGuVertex,100,100,0); SetTextureCoord(sGuNVCTPoint.sGuTexture,1,0); SetNormalCoord(sGuNVCTPoint.sGuNormal,0,0,1); SetColorValue(sGuNVCTPoint.sGuColor,0xFFFFFFFF); vector_point.push_back(sGuNVCTPoint); SetVertexCoord(sGuNVCTPoint.sGuVertex,100,-100,0); SetTextureCoord(sGuNVCTPoint.sGuTexture,1,1); SetNormalCoord(sGuNVCTPoint.sGuNormal,0,0,1); SetColorValue(sGuNVCTPoint.sGuColor,0xFFFFFFFF); vector_point.push_back(sGuNVCTPoint); SetVertexCoord(sGuNVCTPoint.sGuVertex,-100,-100,0); SetTextureCoord(sGuNVCTPoint.sGuTexture,0,1); SetNormalCoord(sGuNVCTPoint.sGuNormal,0,0,1); SetColorValue(sGuNVCTPoint.sGuColor,0xFFFFFFFF); vector_point.push_back(sGuNVCTPoint); 

وإخراجها ، على سبيل المثال ، مثل هذا:

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

للإخراج ، أشرت إلى وظيفة sceGumDrawArray إلى ما أرسمه بالضبط وما هو تنسيق النقطة (GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D | GU_NORMAL_32BITF | GU_TEXTURE_32BITF - النقطة تتكون من اللون ، الإحداثيات ، العادي ، إحداثيات المصفوفة وتتطلب الضرب). الرسم ممكن فقط مع المثلثات. ولكن هذا ليس كل شيء ...

يبدو أن كل شيء يعمل ، ولكنه يعمل فقط إذا كانت جميع النقاط أمام العين ومرئية. بمجرد أن تصل نقطة واحدة على الأقل إلى مسافة ضبابية ، يرفض GU رسم المضلع بأكمله. كما أفهمها ، يتطلب GU's PSP ، بالنسبة إلى طائرات القطع الأربع (اليسار واليمين والجزء العلوي والسفلي (وستتحول الواجهة الأمامية تلقائيًا)) ، تكمن النقطة داخل هذا المجلد ، وإلا لن يوافق GU على عرضه. مشكلة. ولكن في الألعاب ، توجد رسومات ثلاثية الأبعاد ولا يتم ملاحظة مثل هذه القطع الأثرية! دعونا نرى كيف حلوا هذه المشكلة في PSP Quake 1 ، حيث أن المصادر متاحة للتحليل.

ماذا نرى من تحليل المصدر؟ لكن في الواقع ، هذا ما يلي:

  //   sceGumMatrixMode(GU_PROJECTION); ScePspFMatrix4 projection_matrix; sceGumStoreMatrix(&projection_matrix); //    sceGumMatrixMode(GU_VIEW); ScePspFMatrix4 view_matrix; sceGumStoreMatrix(&view_matrix); //   sceGumMatrixMode(GU_MODEL); ScePspFMatrix4 model_matrix; sceGumStoreMatrix(&model_matrix); sceGuFinish(); //   view-projection ScePspFMatrix4 projection_view_matrix; MultiplyScePspFMatrix4(view_matrix,projection_matrix,projection_view_matrix); //   view-projection-model ScePspFMatrix4 projection_view_model_matrix; MultiplyScePspFMatrix4(model_matrix,projection_view_matrix,projection_view_model_matrix); //  view-model ScePspFMatrix4 view_model_matrix; MultiplyScePspFMatrix4(model_matrix,view_matrix,view_model_matrix); //      (, , , ) ScePspFVector4 frustum[4];//   : ax+by+cz+d=0 // frustum[0].x=projection_view_model_matrix.x.w+projection_view_model_matrix.xx; frustum[0].y=projection_view_model_matrix.y.w+projection_view_model_matrix.yx; frustum[0].z=projection_view_model_matrix.z.w+projection_view_model_matrix.zx; frustum[0].w=projection_view_model_matrix.w.w+projection_view_model_matrix.wx; NormaliseScePspFVector4(frustum[0]); // frustum[1].x=projection_view_model_matrix.xw-projection_view_model_matrix.xx; frustum[1].y=projection_view_model_matrix.yw-projection_view_model_matrix.yx; frustum[1].z=projection_view_model_matrix.zw-projection_view_model_matrix.zx; frustum[1].w=projection_view_model_matrix.ww-projection_view_model_matrix.wx; NormaliseScePspFVector4(frustum[1]); // frustum[2].x=projection_view_model_matrix.xw-projection_view_model_matrix.xy; frustum[2].y=projection_view_model_matrix.yw-projection_view_model_matrix.yy; frustum[2].z=projection_view_model_matrix.zw-projection_view_model_matrix.zy; frustum[2].w=projection_view_model_matrix.ww-projection_view_model_matrix.wy; NormaliseScePspFVector4(frustum[2]); // frustum[3].x=projection_view_model_matrix.x.w+projection_view_model_matrix.xy; frustum[3].y=projection_view_model_matrix.y.w+projection_view_model_matrix.yy; frustum[3].z=projection_view_model_matrix.z.w+projection_view_model_matrix.zy; frustum[3].w=projection_view_model_matrix.w.w+projection_view_model_matrix.wy; NormaliseScePspFVector4(frustum[3]); 

أي في Quake 1 ، قبل الاستنتاج ، يقومون ببساطة بنقل جميع النقاط إلى داخل المجلد الذي يقيد العرض ، أو يطرحها تمامًا (إذا لم يكن الرقم بالكامل مرئيًا). كيف تفعل ذلك؟ تحتاج فقط إلى قراءة ثلاث مصفوفات - GU_PROJECTION ، GU_MODEL ، GU_VIEW. اضربهم واحصل على مصفوفة تحويل الإحداثيات النهائية. من هذه المصفوفة ، يمكنك سحب جميع الطائرات اللازمة لتقييد العرض (4 مكونات للمتجه الناتج تحدد مستوى مع فأس المعادلة + بواسطة + cz + w = ​​0). (a، b، c) هو المتجه العادي ، و w = a * x0 + b * y0 + c * z0 - يميز نقطة معينة (x0 ، y0 ، z0) للمستوى. نحن لسنا بحاجة إلى إحداثيات النقطة أنفسنا - فقط نعرف ث.

يتم تنفيذ القطع على النحو التالي (للطائرات الأربع المذكورة أعلاه بدورها في دورة):

  //  vector<SGuNVCTPoint> vector_clip_point; for(long n=0;n<4;n++) { float nx=frustum[n].x; float ny=frustum[n].y; float nz=frustum[n].z; float w=frustum[n].w; Clip(vector_point,vector_clip_point,nx,ny,nz,w); vector_point=vector_clip_point; } 

ولكن من أجل هذا التركيز ، نحتاج إلى الوظائف التالية (خرجت من الزلزال 1):

 //---------------------------------------------------------------------------------------------------- //      //---------------------------------------------------------------------------------------------------- void CMain::GetIntersectionPlaneAndLine(const SGuNVCTPoint& A,const SGuNVCTPoint& B,SGuNVCTPoint& new_point,float nx,float ny,float nz,float w) { new_point=A; float ax=A.sGuVertex.X; float ay=A.sGuVertex.Y; float az=A.sGuVertex.Z; float au=A.sGuTexture.U; float av=A.sGuTexture.V; float bx=B.sGuVertex.X; float by=B.sGuVertex.Y; float bz=B.sGuVertex.Z; float bu=B.sGuTexture.U; float bv=B.sGuTexture.V; float dx=bx-ax; float dy=by-ay; float dz=bz-az; float du=bu-au; float dv=bv-av; float top=(nx*ax)+(ny*ay)+(nz*az)+w; float bottom=(nx*dx)+(ny*dy)+(nz*dz); float time=-top/bottom; float vx=ax+time*dx; float vy=ay+time*dy; float vz=az+time*dz; float vu=au+time*du; float vv=av+time*dv; //   SetVertexCoord(new_point.sGuVertex,vx,vy,vz); SetTextureCoord(new_point.sGuTexture,vu,vv); } //---------------------------------------------------------------------------------------------------- //   //---------------------------------------------------------------------------------------------------- void CMain::Clip(const vector<SGuNVCTPoint>& vector_point_input,vector<SGuNVCTPoint>& vector_point_output,float nx,float ny,float nz,float w) { vector_point_output.clear(); long point=vector_point_input.size(); for(long n=0;n<point;n++) { long next_p=n+1; if (next_p>=point) next_p-=point; const SGuNVCTPoint *sGuNVCTPoint_Current_Ptr=&(vector_point_input[n]); float current_vx=sGuNVCTPoint_Current_Ptr->sGuVertex.X; float current_vy=sGuNVCTPoint_Current_Ptr->sGuVertex.Y; float current_vz=sGuNVCTPoint_Current_Ptr->sGuVertex.Z; //     float current_ret=current_vx*nx+current_vy*ny+current_vz*nz+w; const SGuNVCTPoint *sGuNVCTPoint_Next_Ptr=&(vector_point_input[next_p]); float next_vx=sGuNVCTPoint_Next_Ptr->sGuVertex.X; float next_vy=sGuNVCTPoint_Next_Ptr->sGuVertex.Y; float next_vz=sGuNVCTPoint_Next_Ptr->sGuVertex.Z; //     float next_ret=next_vx*nx+next_vy*ny+next_vz*nz+w; if (current_ret>0)//   { if (next_ret>0)//   { vector_point_output.push_back(*sGuNVCTPoint_Next_Ptr); } else { //    SGuNVCTPoint sGuNVCTPoint_New; GetIntersectionPlaneAndLine(*sGuNVCTPoint_Current_Ptr,*sGuNVCTPoint_Next_Ptr,sGuNVCTPoint_New,nx,ny,nz,w); vector_point_output.push_back(sGuNVCTPoint_New); } } else//    { if (next_ret>0)//   { //    SGuNVCTPoint sGuNVCTPoint_New; GetIntersectionPlaneAndLine(*sGuNVCTPoint_Current_Ptr,*sGuNVCTPoint_Next_Ptr,sGuNVCTPoint_New,nx,ny,nz,w); vector_point_output.push_back(sGuNVCTPoint_New); //   vector_point_output.push_back(*sGuNVCTPoint_Next_Ptr); } } } } 

وفقط بعد إجراء مثل هذا القطع ، ستحصل أخيرًا بشكل صحيح أخيرًا على إخراج رسومات ثلاثية الأبعاد على PSP باستخدام GU. يمكنك إنشاء لعبة! :)



بالمناسبة ، يمكنك أيضًا استخدام معالج ناقل PSP للمنتج القياسي للمتجهات. على سبيل المثال ، فيما يلي وظيفة تحدد ما إذا كان القطع مطلوبًا على الإطلاق (ممزق إلى قطع من نفس Quake 1 لـ PSP):

 //  vector<SGuNVCTPoint> vector_clip_point; //   PSP __asm__ volatile ( "ulv.q C700, %0\n" //    "ulv.q C710, %1\n" //    "ulv.q C720, %2\n" //    "ulv.q C730, %3\n" //    :: "m"(FrustumPlane[0]),"m"(FrustumPlane[1]),"m"(FrustumPlane[2]),"m"(FrustumPlane[3]) ); //   long vertex=vector_point.size(); bool clipping=false; for(long n=0;n<vertex;n++) { ScePspFVector4 current_vertex; current_vertex.x=vector_point[n].sGuVertex.X; current_vertex.y=vector_point[n].sGuVertex.Y; current_vertex.z=vector_point[n].sGuVertex.Z; current_vertex.w=1; float ret1,ret2,ret3,ret4; __asm__ volatile ( "ulv.q C610, %4\n" //      "vone.s S613\n" //       "vdot.q S620, C700, C610\n" // s620 =    "vdot.q S621, C710, C610\n" // s621 =    "vdot.q S622, C720, C610\n" // s622 =    "vdot.q S623, C730, C610\n" // s623 =    "mfv %0, S620\n" // out1 = s620 "mfv %1, S621\n" // out2 = s621 "mfv %2, S622\n" // out3 = s622 "mfv %3, S623\n" // out4 = s623 : "=r"(ret1), "=r"(ret2), "=r"(ret3), "=r"(ret4) : "m"(current_vertex) ); if (ret1<0 || ret2<0 || ret3<0 || ret4<0)//  { clipping=true; break; } } 

كل شيء بسيط هنا - وضعوا ناقلات المستوى وإحداثيات النقطة في السجلات وطلبوا من VFPU أداء المنتج القياسي.

→ رابط إلى أبسط تطبيق عرض نسيج

← ارتباط بمحرك PSP باستخدام GU

PS أعرف أن هناك مهنيين برمجة لـ PSP. ربما سيخبرونك عن سبب ترتيب PSP GU وكيفية التعامل معه بشكل صحيح.

Source: https://habr.com/ru/post/ar406049/


All Articles