8e8c8735352cc0c67da9511d72ad69431dbf42e5
[platform/upstream/SDL.git] / src / render / psp / SDL_render_psp.c
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22
23 #if SDL_VIDEO_RENDER_PSP
24
25 #include "SDL_hints.h"
26 #include "../SDL_sysrender.h"
27
28 #include <pspkernel.h>
29 #include <pspdisplay.h>
30 #include <pspgu.h>
31 #include <pspgum.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <math.h>
35 #include <pspge.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <vram.h>
39
40
41
42
43 /* PSP renderer implementation, based on the PGE  */
44
45
46 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
47
48
49 static SDL_Renderer *PSP_CreateRenderer(SDL_Window * window, Uint32 flags);
50 static void PSP_WindowEvent(SDL_Renderer * renderer,
51                              const SDL_WindowEvent *event);
52 static int PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
53 static int PSP_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
54                               const SDL_Rect * rect, const void *pixels,
55                               int pitch);
56 static int PSP_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
57                             const SDL_Rect * rect, void **pixels, int *pitch);
58 static void PSP_UnlockTexture(SDL_Renderer * renderer,
59                                SDL_Texture * texture);
60 static int PSP_SetRenderTarget(SDL_Renderer * renderer,
61                                  SDL_Texture * texture);
62 static int PSP_UpdateViewport(SDL_Renderer * renderer);
63 static int PSP_RenderClear(SDL_Renderer * renderer);
64 static int PSP_RenderDrawPoints(SDL_Renderer * renderer,
65                                  const SDL_FPoint * points, int count);
66 static int PSP_RenderDrawLines(SDL_Renderer * renderer,
67                                 const SDL_FPoint * points, int count);
68 static int PSP_RenderFillRects(SDL_Renderer * renderer,
69                                 const SDL_FRect * rects, int count);
70 static int PSP_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
71                            const SDL_Rect * srcrect,
72                            const SDL_FRect * dstrect);
73 static int PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
74                     Uint32 pixel_format, void * pixels, int pitch);
75 static int PSP_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
76                          const SDL_Rect * srcrect, const SDL_FRect * dstrect,
77                          const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
78 static void PSP_RenderPresent(SDL_Renderer * renderer);
79 static void PSP_DestroyTexture(SDL_Renderer * renderer,
80                                 SDL_Texture * texture);
81 static void PSP_DestroyRenderer(SDL_Renderer * renderer);
82
83 /*
84 SDL_RenderDriver PSP_RenderDriver = {
85     PSP_CreateRenderer,
86     {
87      "PSP",
88      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
89      1,
90      {SDL_PIXELFORMAT_ABGR8888},
91      0,
92      0}
93 };
94 */
95 SDL_RenderDriver PSP_RenderDriver = {
96     .CreateRenderer = PSP_CreateRenderer,
97     .info = {
98         .name = "PSP",
99         .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE,
100         .num_texture_formats = 4,
101         .texture_formats = { [0] = SDL_PIXELFORMAT_BGR565,
102                                                  [1] = SDL_PIXELFORMAT_ABGR1555,
103                                                  [2] = SDL_PIXELFORMAT_ABGR4444,
104                                                  [3] = SDL_PIXELFORMAT_ABGR8888,
105         },
106         .max_texture_width = 512,
107         .max_texture_height = 512,
108      }
109 };
110
111 #define PSP_SCREEN_WIDTH    480
112 #define PSP_SCREEN_HEIGHT   272
113
114 #define PSP_FRAME_BUFFER_WIDTH  512
115 #define PSP_FRAME_BUFFER_SIZE   (PSP_FRAME_BUFFER_WIDTH*PSP_SCREEN_HEIGHT)
116
117 static unsigned int __attribute__((aligned(16))) DisplayList[262144];
118
119
120 #define COL5650(r,g,b,a)    ((r>>3) | ((g>>2)<<5) | ((b>>3)<<11))
121 #define COL5551(r,g,b,a)    ((r>>3) | ((g>>3)<<5) | ((b>>3)<<10) | (a>0?0x7000:0))
122 #define COL4444(r,g,b,a)    ((r>>4) | ((g>>4)<<4) | ((b>>4)<<8) | ((a>>4)<<12))
123 #define COL8888(r,g,b,a)    ((r) | ((g)<<8) | ((b)<<16) | ((a)<<24))
124
125
126 typedef struct
127 {
128     void*           frontbuffer ;
129     void*           backbuffer ;
130     SDL_bool        initialized ;
131     SDL_bool        displayListAvail ;
132     unsigned int    psm ;
133     unsigned int    bpp ;
134
135     SDL_bool        vsync;
136     unsigned int    currentColor;
137     int             currentBlendMode;
138
139 } PSP_RenderData;
140
141
142 typedef struct
143 {
144     void                *data;                              /**< Image data. */
145     unsigned int        size;                               /**< Size of data in bytes. */
146     unsigned int        width;                              /**< Image width. */
147     unsigned int        height;                             /**< Image height. */
148     unsigned int        textureWidth;                       /**< Texture width (power of two). */
149     unsigned int        textureHeight;                      /**< Texture height (power of two). */
150     unsigned int        bits;                               /**< Image bits per pixel. */
151     unsigned int        format;                             /**< Image format - one of ::pgePixelFormat. */
152     unsigned int        pitch;
153     SDL_bool            swizzled;                           /**< Is image swizzled. */
154
155 } PSP_TextureData;
156
157 typedef struct
158 {
159     float   x, y, z;
160 } VertV;
161
162
163 typedef struct
164 {
165     float   u, v;
166     float   x, y, z;
167
168 } VertTV;
169
170
171 /* Return next power of 2 */
172 static int
173 TextureNextPow2(unsigned int w)
174 {
175     if(w == 0)
176         return 0;
177
178     unsigned int n = 2;
179
180     while(w > n)
181         n <<= 1;
182
183     return n;
184 }
185
186
187 static int
188 GetScaleQuality(void)
189 {
190     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
191
192     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
193         return GU_NEAREST; /* GU_NEAREST good for tile-map */
194     } else {
195         return GU_LINEAR; /* GU_LINEAR good for scaling */
196     }
197 }
198
199 static int
200 PixelFormatToPSPFMT(Uint32 format)
201 {
202     switch (format) {
203     case SDL_PIXELFORMAT_BGR565:
204         return GU_PSM_5650;
205     case SDL_PIXELFORMAT_ABGR1555:
206         return GU_PSM_5551;
207     case SDL_PIXELFORMAT_ABGR4444:
208         return GU_PSM_4444;
209     case SDL_PIXELFORMAT_ABGR8888:
210         return GU_PSM_8888;
211     default:
212         return GU_PSM_8888;
213     }
214 }
215
216 void
217 StartDrawing(SDL_Renderer * renderer)
218 {
219     PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata;
220     if(data->displayListAvail)
221         return;
222
223     sceGuStart(GU_DIRECT, DisplayList);
224     data->displayListAvail = SDL_TRUE;
225 }
226
227
228 int
229 TextureSwizzle(PSP_TextureData *psp_texture)
230 {
231     if(psp_texture->swizzled)
232         return 1;
233
234     int bytewidth = psp_texture->textureWidth*(psp_texture->bits>>3);
235     int height = psp_texture->size / bytewidth;
236
237     int rowblocks = (bytewidth>>4);
238     int rowblocksadd = (rowblocks-1)<<7;
239     unsigned int blockaddress = 0;
240     unsigned int *src = (unsigned int*) psp_texture->data;
241
242     unsigned char *data = NULL;
243     data = malloc(psp_texture->size);
244
245     int j;
246
247     for(j = 0; j < height; j++, blockaddress += 16)
248     {
249         unsigned int *block;
250
251         block = (unsigned int*)&data[blockaddress];
252
253         int i;
254
255         for(i = 0; i < rowblocks; i++)
256         {
257             *block++ = *src++;
258             *block++ = *src++;
259             *block++ = *src++;
260             *block++ = *src++;
261             block += 28;
262         }
263
264         if((j & 0x7) == 0x7)
265             blockaddress += rowblocksadd;
266     }
267
268     free(psp_texture->data);
269     psp_texture->data = data;
270     psp_texture->swizzled = SDL_TRUE;
271
272     return 1;
273 }
274 int TextureUnswizzle(PSP_TextureData *psp_texture)
275 {
276     if(!psp_texture->swizzled)
277         return 1;
278
279     int blockx, blocky;
280
281     int bytewidth = psp_texture->textureWidth*(psp_texture->bits>>3);
282     int height = psp_texture->size / bytewidth;
283
284     int widthblocks = bytewidth/16;
285     int heightblocks = height/8;
286
287     int dstpitch = (bytewidth - 16)/4;
288     int dstrow = bytewidth * 8;
289
290     unsigned int *src = (unsigned int*) psp_texture->data;
291
292     unsigned char *data = NULL;
293
294     data = malloc(psp_texture->size);
295
296     if(!data)
297         return 0;
298
299     sceKernelDcacheWritebackAll();
300
301     int j;
302
303     unsigned char *ydst = (unsigned char *)data;
304
305     for(blocky = 0; blocky < heightblocks; ++blocky)
306     {
307         unsigned char *xdst = ydst;
308
309         for(blockx = 0; blockx < widthblocks; ++blockx)
310         {
311             unsigned int *block;
312
313             block = (unsigned int*)xdst;
314
315             for(j = 0; j < 8; ++j)
316             {
317                 *(block++) = *(src++);
318                 *(block++) = *(src++);
319                 *(block++) = *(src++);
320                 *(block++) = *(src++);
321                 block += dstpitch;
322             }
323
324             xdst += 16;
325         }
326
327         ydst += dstrow;
328     }
329
330     free(psp_texture->data);
331
332     psp_texture->data = data;
333
334     psp_texture->swizzled = SDL_FALSE;
335
336     return 1;
337 }
338
339 SDL_Renderer *
340 PSP_CreateRenderer(SDL_Window * window, Uint32 flags)
341 {
342
343     SDL_Renderer *renderer;
344     PSP_RenderData *data;
345         int pixelformat;
346     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
347     if (!renderer) {
348         SDL_OutOfMemory();
349         return NULL;
350     }
351
352     data = (PSP_RenderData *) SDL_calloc(1, sizeof(*data));
353     if (!data) {
354         PSP_DestroyRenderer(renderer);
355         SDL_OutOfMemory();
356         return NULL;
357     }
358
359
360     renderer->WindowEvent = PSP_WindowEvent;
361     renderer->CreateTexture = PSP_CreateTexture;
362     renderer->UpdateTexture = PSP_UpdateTexture;
363     renderer->LockTexture = PSP_LockTexture;
364     renderer->UnlockTexture = PSP_UnlockTexture;
365     renderer->SetRenderTarget = PSP_SetRenderTarget;
366     renderer->UpdateViewport = PSP_UpdateViewport;
367     renderer->RenderClear = PSP_RenderClear;
368     renderer->RenderDrawPoints = PSP_RenderDrawPoints;
369     renderer->RenderDrawLines = PSP_RenderDrawLines;
370     renderer->RenderFillRects = PSP_RenderFillRects;
371     renderer->RenderCopy = PSP_RenderCopy;
372     renderer->RenderReadPixels = PSP_RenderReadPixels;
373     renderer->RenderCopyEx = PSP_RenderCopyEx;
374     renderer->RenderPresent = PSP_RenderPresent;
375     renderer->DestroyTexture = PSP_DestroyTexture;
376     renderer->DestroyRenderer = PSP_DestroyRenderer;
377     renderer->info = PSP_RenderDriver.info;
378     renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
379     renderer->driverdata = data;
380     renderer->window = window;
381
382     if (data->initialized != SDL_FALSE)
383         return 0;
384     data->initialized = SDL_TRUE;
385
386     if (flags & SDL_RENDERER_PRESENTVSYNC) {
387         data->vsync = SDL_TRUE;
388     } else {
389         data->vsync = SDL_FALSE;
390     }
391
392     pixelformat=PixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window));
393     switch(pixelformat)
394     {
395         case GU_PSM_4444:
396         case GU_PSM_5650:
397         case GU_PSM_5551:
398             data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<1);
399             data->backbuffer =  (unsigned int *)(0);
400             data->bpp = 2;
401             data->psm = pixelformat;
402             break;
403         default:
404             data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<2);
405             data->backbuffer =  (unsigned int *)(0);
406             data->bpp = 4;
407             data->psm = GU_PSM_8888;
408             break;
409     }
410
411     sceGuInit();
412     /* setup GU */
413     sceGuStart(GU_DIRECT, DisplayList);
414     sceGuDrawBuffer(data->psm, data->frontbuffer, PSP_FRAME_BUFFER_WIDTH);
415     sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, data->backbuffer, PSP_FRAME_BUFFER_WIDTH);
416
417
418     sceGuOffset(2048 - (PSP_SCREEN_WIDTH>>1), 2048 - (PSP_SCREEN_HEIGHT>>1));
419     sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
420
421     data->frontbuffer = vabsptr(data->frontbuffer);
422     data->backbuffer = vabsptr(data->backbuffer);
423
424     /* Scissoring */
425     sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
426     sceGuEnable(GU_SCISSOR_TEST);
427
428     /* Backface culling */
429     sceGuFrontFace(GU_CCW);
430     sceGuEnable(GU_CULL_FACE);
431
432     /* Texturing */
433     sceGuEnable(GU_TEXTURE_2D);
434     sceGuShadeModel(GU_SMOOTH);
435     sceGuTexWrap(GU_REPEAT, GU_REPEAT);
436
437     /* Blending */
438     sceGuEnable(GU_BLEND);
439     sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
440
441     sceGuTexFilter(GU_LINEAR,GU_LINEAR);
442
443     sceGuFinish();
444     sceGuSync(0,0);
445     sceDisplayWaitVblankStartCB();
446     sceGuDisplay(GU_TRUE);
447
448     return renderer;
449 }
450
451 static void
452 PSP_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
453 {
454
455 }
456
457
458 static int
459 PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
460 {
461 /*      PSP_RenderData *renderdata = (PSP_RenderData *) renderer->driverdata; */
462     PSP_TextureData* psp_texture = (PSP_TextureData*) SDL_calloc(1, sizeof(*psp_texture));
463
464     if(!psp_texture)
465         return -1;
466
467     psp_texture->swizzled = SDL_FALSE;
468     psp_texture->width = texture->w;
469     psp_texture->height = texture->h;
470     psp_texture->textureHeight = TextureNextPow2(texture->h);
471     psp_texture->textureWidth = TextureNextPow2(texture->w);
472     psp_texture->format = PixelFormatToPSPFMT(texture->format);
473
474     switch(psp_texture->format)
475     {
476         case GU_PSM_5650:
477         case GU_PSM_5551:
478         case GU_PSM_4444:
479             psp_texture->bits = 16;
480             break;
481
482         case GU_PSM_8888:
483             psp_texture->bits = 32;
484             break;
485
486         default:
487             return -1;
488     }
489
490     psp_texture->pitch = psp_texture->textureWidth * SDL_BYTESPERPIXEL(texture->format);
491     psp_texture->size = psp_texture->textureHeight*psp_texture->pitch;
492     psp_texture->data = SDL_calloc(1, psp_texture->size);
493
494     if(!psp_texture->data)
495     {
496         SDL_free(psp_texture);
497         return SDL_OutOfMemory();
498     }
499     texture->driverdata = psp_texture;
500
501     return 0;
502 }
503
504
505 void
506 TextureActivate(SDL_Texture * texture)
507 {
508     PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata;
509     int scaleMode = GetScaleQuality();
510
511     /* Swizzling is useless with small textures. */
512     if (texture->w >= 16 || texture->h >= 16)
513     {
514         TextureSwizzle(psp_texture);
515     }
516
517     sceGuEnable(GU_TEXTURE_2D);
518     sceGuTexWrap(GU_REPEAT, GU_REPEAT);
519     sceGuTexMode(psp_texture->format, 0, 0, psp_texture->swizzled);
520     sceGuTexFilter(scaleMode, scaleMode); /* GU_NEAREST good for tile-map */
521                                           /* GU_LINEAR good for scaling */
522     sceGuTexImage(0, psp_texture->textureWidth, psp_texture->textureHeight, psp_texture->textureWidth, psp_texture->data);
523     sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
524 }
525
526
527 static int
528 PSP_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
529                    const SDL_Rect * rect, const void *pixels, int pitch)
530 {
531 /*  PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata; */
532     const Uint8 *src;
533     Uint8 *dst;
534     int row, length,dpitch;
535     src = pixels;
536
537     PSP_LockTexture(renderer, texture,rect,(void **)&dst, &dpitch);
538     length = rect->w * SDL_BYTESPERPIXEL(texture->format);
539     if (length == pitch && length == dpitch) {
540         SDL_memcpy(dst, src, length*rect->h);
541     } else {
542         for (row = 0; row < rect->h; ++row) {
543             SDL_memcpy(dst, src, length);
544             src += pitch;
545             dst += dpitch;
546         }
547     }
548
549     sceKernelDcacheWritebackAll();
550     return 0;
551 }
552
553 static int
554 PSP_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
555                  const SDL_Rect * rect, void **pixels, int *pitch)
556 {
557     PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata;
558
559     *pixels =
560         (void *) ((Uint8 *) psp_texture->data + rect->y * psp_texture->pitch +
561                   rect->x * SDL_BYTESPERPIXEL(texture->format));
562     *pitch = psp_texture->pitch;
563     return 0;
564 }
565
566 static void
567 PSP_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
568 {
569     PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata;
570     SDL_Rect rect;
571
572     /* We do whole texture updates, at least for now */
573     rect.x = 0;
574     rect.y = 0;
575     rect.w = texture->w;
576     rect.h = texture->h;
577     PSP_UpdateTexture(renderer, texture, &rect, psp_texture->data, psp_texture->pitch);
578 }
579
580 static int
581 PSP_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
582 {
583
584     return 0;
585 }
586
587 static int
588 PSP_UpdateViewport(SDL_Renderer * renderer)
589 {
590
591     return 0;
592 }
593
594
595 static void
596 PSP_SetBlendMode(SDL_Renderer * renderer, int blendMode)
597 {
598     PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata;
599     if (blendMode != data-> currentBlendMode) {
600         switch (blendMode) {
601         case SDL_BLENDMODE_NONE:
602                 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
603                 sceGuDisable(GU_BLEND);
604             break;
605         case SDL_BLENDMODE_BLEND:
606                 sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
607                 sceGuEnable(GU_BLEND);
608                 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 );
609             break;
610         case SDL_BLENDMODE_ADD:
611                 sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
612                 sceGuEnable(GU_BLEND);
613                 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF );
614             break;
615         case SDL_BLENDMODE_MOD:
616                 sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
617                 sceGuEnable(GU_BLEND);
618                 sceGuBlendFunc( GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0);
619             break;
620         }
621         data->currentBlendMode = blendMode;
622     }
623 }
624
625
626
627 static int
628 PSP_RenderClear(SDL_Renderer * renderer)
629 {
630     /* start list */
631     StartDrawing(renderer);
632     int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
633     sceGuClearColor(color);
634     sceGuClearDepth(0);
635     sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT|GU_FAST_CLEAR_BIT);
636
637     return 0;
638 }
639
640 static int
641 PSP_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
642                       int count)
643 {
644     int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
645     int i;
646     StartDrawing(renderer);
647     VertV* vertices = (VertV*)sceGuGetMemory(count*sizeof(VertV));
648
649     for (i = 0; i < count; ++i) {
650             vertices[i].x = points[i].x;
651             vertices[i].y = points[i].y;
652             vertices[i].z = 0.0f;
653     }
654     sceGuDisable(GU_TEXTURE_2D);
655     sceGuColor(color);
656     sceGuShadeModel(GU_FLAT);
657     sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, vertices);
658     sceGuShadeModel(GU_SMOOTH);
659     sceGuEnable(GU_TEXTURE_2D);
660
661     return 0;
662 }
663
664 static int
665 PSP_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
666                      int count)
667 {
668     int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
669     int i;
670     StartDrawing(renderer);
671     VertV* vertices = (VertV*)sceGuGetMemory(count*sizeof(VertV));
672
673     for (i = 0; i < count; ++i) {
674             vertices[i].x = points[i].x;
675             vertices[i].y = points[i].y;
676             vertices[i].z = 0.0f;
677     }
678
679     sceGuDisable(GU_TEXTURE_2D);
680     sceGuColor(color);
681     sceGuShadeModel(GU_FLAT);
682     sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, vertices);
683     sceGuShadeModel(GU_SMOOTH);
684     sceGuEnable(GU_TEXTURE_2D);
685
686     return 0;
687 }
688
689 static int
690 PSP_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
691                      int count)
692 {
693     int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
694     int i;
695     StartDrawing(renderer);
696
697     for (i = 0; i < count; ++i) {
698         const SDL_FRect *rect = &rects[i];
699         VertV* vertices = (VertV*)sceGuGetMemory((sizeof(VertV)<<1));
700         vertices[0].x = rect->x;
701         vertices[0].y = rect->y;
702         vertices[0].z = 0.0f;
703
704         vertices[1].x = rect->x + rect->w;
705         vertices[1].y = rect->y + rect->h;
706         vertices[1].z = 0.0f;
707
708         sceGuDisable(GU_TEXTURE_2D);
709         sceGuColor(color);
710         sceGuShadeModel(GU_FLAT);
711         sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
712         sceGuShadeModel(GU_SMOOTH);
713         sceGuEnable(GU_TEXTURE_2D);
714     }
715
716     return 0;
717 }
718
719
720 #define PI   3.14159265358979f
721
722 #define radToDeg(x) ((x)*180.f/PI)
723 #define degToRad(x) ((x)*PI/180.f)
724
725 float MathAbs(float x)
726 {
727     float result;
728
729     __asm__ volatile (
730         "mtv      %1, S000\n"
731         "vabs.s   S000, S000\n"
732         "mfv      %0, S000\n"
733     : "=r"(result) : "r"(x));
734
735     return result;
736 }
737
738 void MathSincos(float r, float *s, float *c)
739 {
740     __asm__ volatile (
741         "mtv      %2, S002\n"
742         "vcst.s   S003, VFPU_2_PI\n"
743         "vmul.s   S002, S002, S003\n"
744         "vrot.p   C000, S002, [s, c]\n"
745         "mfv      %0, S000\n"
746         "mfv      %1, S001\n"
747     : "=r"(*s), "=r"(*c): "r"(r));
748 }
749
750 void Swap(float *a, float *b)
751 {
752     float n=*a;
753     *a = *b;
754     *b = n;
755 }
756
757 static int
758 PSP_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
759                 const SDL_Rect * srcrect, const SDL_FRect * dstrect)
760 {
761     float x, y, width, height;
762     float u0, v0, u1, v1;
763     unsigned char alpha;
764
765     x = dstrect->x;
766     y = dstrect->y;
767     width = dstrect->w;
768     height = dstrect->h;
769
770     u0 = srcrect->x;
771     v0 = srcrect->y;
772     u1 = srcrect->x + srcrect->w;
773     v1 = srcrect->y + srcrect->h;
774
775     alpha = texture->a;
776
777     StartDrawing(renderer);
778     TextureActivate(texture);
779     PSP_SetBlendMode(renderer, renderer->blendMode);
780
781     if(alpha != 255)
782     {
783         sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
784         sceGuColor(GU_RGBA(255, 255, 255, alpha));
785     }else{
786         sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
787         sceGuColor(0xFFFFFFFF);
788     }
789
790     if((MathAbs(u1) - MathAbs(u0)) < 64.0f)
791     {
792         VertTV* vertices = (VertTV*)sceGuGetMemory((sizeof(VertTV))<<1);
793
794         vertices[0].u = u0;
795         vertices[0].v = v0;
796         vertices[0].x = x;
797         vertices[0].y = y;
798         vertices[0].z = 0;
799
800         vertices[1].u = u1;
801         vertices[1].v = v1;
802         vertices[1].x = x + width;
803         vertices[1].y = y + height;
804         vertices[1].z = 0;
805
806         sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
807     }
808     else
809     {
810         float start, end;
811         float curU = u0;
812         float curX = x;
813         float endX = x + width;
814         float slice = 64.0f;
815         float ustep = (u1 - u0)/width * slice;
816
817         if(ustep < 0.0f)
818             ustep = -ustep;
819
820         for(start = 0, end = width; start < end; start += slice)
821         {
822             VertTV* vertices = (VertTV*)sceGuGetMemory((sizeof(VertTV))<<1);
823
824             float polyWidth = ((curX + slice) > endX) ? (endX - curX) : slice;
825             float sourceWidth = ((curU + ustep) > u1) ? (u1 - curU) : ustep;
826
827             vertices[0].u = curU;
828             vertices[0].v = v0;
829             vertices[0].x = curX;
830             vertices[0].y = y;
831             vertices[0].z = 0;
832
833             curU += sourceWidth;
834             curX += polyWidth;
835
836             vertices[1].u = curU;
837             vertices[1].v = v1;
838             vertices[1].x = curX;
839             vertices[1].y = (y + height);
840             vertices[1].z = 0;
841
842             sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
843         }
844     }
845
846     if(alpha != 255)
847         sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
848     return 0;
849 }
850
851 static int
852 PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
853                     Uint32 pixel_format, void * pixels, int pitch)
854
855 {
856         return 0;
857 }
858
859
860 static int
861 PSP_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
862                 const SDL_Rect * srcrect, const SDL_FRect * dstrect,
863                 const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
864 {
865     float x, y, width, height;
866     float u0, v0, u1, v1;
867     unsigned char alpha;
868     float centerx, centery;
869
870     x = dstrect->x;
871     y = dstrect->y;
872     width = dstrect->w;
873     height = dstrect->h;
874
875     u0 = srcrect->x;
876     v0 = srcrect->y;
877     u1 = srcrect->x + srcrect->w;
878     v1 = srcrect->y + srcrect->h;
879
880     centerx = center->x;
881     centery = center->y;
882
883     alpha = texture->a;
884
885     StartDrawing(renderer);
886     TextureActivate(texture);
887     PSP_SetBlendMode(renderer, renderer->blendMode);
888
889     if(alpha != 255)
890     {
891         sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
892         sceGuColor(GU_RGBA(255, 255, 255, alpha));
893     }else{
894         sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
895         sceGuColor(0xFFFFFFFF);
896     }
897
898 /*      x += width * 0.5f; */
899 /*      y += height * 0.5f; */
900     x += centerx;
901     y += centery;
902
903     float c, s;
904
905     MathSincos(degToRad(angle), &s, &c);
906
907 /*      width *= 0.5f; */
908 /*      height *= 0.5f; */
909     width  -= centerx;
910     height -= centery;
911
912
913     float cw = c*width;
914     float sw = s*width;
915     float ch = c*height;
916     float sh = s*height;
917
918     VertTV* vertices = (VertTV*)sceGuGetMemory(sizeof(VertTV)<<2);
919
920     vertices[0].u = u0;
921     vertices[0].v = v0;
922     vertices[0].x = x - cw + sh;
923     vertices[0].y = y - sw - ch;
924     vertices[0].z = 0;
925
926     vertices[1].u = u0;
927     vertices[1].v = v1;
928     vertices[1].x = x - cw - sh;
929     vertices[1].y = y - sw + ch;
930     vertices[1].z = 0;
931
932     vertices[2].u = u1;
933     vertices[2].v = v1;
934     vertices[2].x = x + cw - sh;
935     vertices[2].y = y + sw + ch;
936     vertices[2].z = 0;
937
938     vertices[3].u = u1;
939     vertices[3].v = v0;
940     vertices[3].x = x + cw + sh;
941     vertices[3].y = y + sw - ch;
942     vertices[3].z = 0;
943
944     if (flip & SDL_FLIP_HORIZONTAL) {
945                 Swap(&vertices[0].v, &vertices[2].v);
946                 Swap(&vertices[1].v, &vertices[3].v);
947     }
948     if (flip & SDL_FLIP_VERTICAL) {
949                 Swap(&vertices[0].u, &vertices[2].u);
950                 Swap(&vertices[1].u, &vertices[3].u);
951     }
952
953     sceGuDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, vertices);
954
955     if(alpha != 255)
956         sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
957     return 0;
958 }
959
960 static void
961 PSP_RenderPresent(SDL_Renderer * renderer)
962 {
963     PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata;
964     if(!data->displayListAvail)
965         return;
966
967     data->displayListAvail = SDL_FALSE;
968     sceGuFinish();
969     sceGuSync(0,0);
970
971 /*  if(data->vsync) */
972         sceDisplayWaitVblankStart();
973
974     data->backbuffer = data->frontbuffer;
975     data->frontbuffer = vabsptr(sceGuSwapBuffers());
976
977 }
978
979 static void
980 PSP_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
981 {
982     PSP_RenderData *renderdata = (PSP_RenderData *) renderer->driverdata;
983     PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata;
984
985     if (renderdata == 0)
986         return;
987
988     if(psp_texture == 0)
989         return;
990
991     SDL_free(psp_texture->data);
992     SDL_free(psp_texture);
993     texture->driverdata = NULL;
994 }
995
996 static void
997 PSP_DestroyRenderer(SDL_Renderer * renderer)
998 {
999     PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata;
1000     if (data) {
1001         if (!data->initialized)
1002             return;
1003
1004         StartDrawing(renderer);
1005
1006         sceGuTerm();
1007 /*      vfree(data->backbuffer); */
1008 /*      vfree(data->frontbuffer); */
1009
1010         data->initialized = SDL_FALSE;
1011         data->displayListAvail = SDL_FALSE;
1012         SDL_free(data);
1013     }
1014     SDL_free(renderer);
1015 }
1016
1017 #endif /* SDL_VIDEO_RENDER_PSP */
1018
1019 /* vi: set ts=4 sw=4 expandtab: */
1020