src/render/psp/SDL_render_psp.c
author Gabriel Jacobo
Tue, 23 Apr 2013 16:54:52 -0300
changeset 7096 640f553441e4
parent 7037 3fedf1f25b94
child 7191 75360622e65f
permissions -rw-r--r--
Fixes PSP_DestroyTexture release of data (don't release the SDL_Texture pointer)
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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_config.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;
   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 	if(psp_texture->data != 0)
   992 	{
   993 		SDL_free(psp_texture->data);
   994 	}
   995 	SDL_free(psp_texture);
   996 	texture->driverdata = NULL;
   997 }
   998 
   999 static void
  1000 PSP_DestroyRenderer(SDL_Renderer * renderer)
  1001 {
  1002     PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata;
  1003     if (data) {
  1004 		if (!data->initialized)
  1005 			return;
  1006 
  1007 		StartDrawing(renderer);
  1008 		
  1009 		sceGuTerm();
  1010 //		vfree(data->backbuffer);
  1011 //		vfree(data->frontbuffer);
  1012 		
  1013 		data->initialized = SDL_FALSE;
  1014 		data->displayListAvail = SDL_FALSE;
  1015         SDL_free(data);
  1016     }
  1017     SDL_free(renderer);
  1018 }
  1019 
  1020 #endif /* SDL_VIDEO_RENDER_PSP */
  1021 
  1022 /* vi: set ts=4 sw=4 expandtab: */
  1023