cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_render_psp.c (28135B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 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
     46extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
     47
     48
     49static SDL_Renderer *PSP_CreateRenderer(SDL_Window * window, Uint32 flags);
     50static void PSP_WindowEvent(SDL_Renderer * renderer,
     51                             const SDL_WindowEvent *event);
     52static int PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
     53static int PSP_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
     54                              const SDL_Rect * rect, const void *pixels,
     55                              int pitch);
     56static int PSP_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
     57                            const SDL_Rect * rect, void **pixels, int *pitch);
     58static void PSP_UnlockTexture(SDL_Renderer * renderer,
     59                               SDL_Texture * texture);
     60static int PSP_SetRenderTarget(SDL_Renderer * renderer,
     61                                 SDL_Texture * texture);
     62static int PSP_UpdateViewport(SDL_Renderer * renderer);
     63static int PSP_RenderClear(SDL_Renderer * renderer);
     64static int PSP_RenderDrawPoints(SDL_Renderer * renderer,
     65                                 const SDL_FPoint * points, int count);
     66static int PSP_RenderDrawLines(SDL_Renderer * renderer,
     67                                const SDL_FPoint * points, int count);
     68static int PSP_RenderFillRects(SDL_Renderer * renderer,
     69                                const SDL_FRect * rects, int count);
     70static int PSP_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
     71                           const SDL_Rect * srcrect,
     72                           const SDL_FRect * dstrect);
     73static int PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
     74                    Uint32 pixel_format, void * pixels, int pitch);
     75static 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);
     78static void PSP_RenderPresent(SDL_Renderer * renderer);
     79static void PSP_DestroyTexture(SDL_Renderer * renderer,
     80                                SDL_Texture * texture);
     81static void PSP_DestroyRenderer(SDL_Renderer * renderer);
     82
     83/*
     84SDL_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*/
     95SDL_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
    117static 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
    126typedef 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
    142typedef 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
    157typedef struct
    158{
    159    float   x, y, z;
    160} VertV;
    161
    162
    163typedef struct
    164{
    165    float   u, v;
    166    float   x, y, z;
    167
    168} VertTV;
    169
    170
    171/* Return next power of 2 */
    172static int
    173TextureNextPow2(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
    187static int
    188GetScaleQuality(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
    199static int
    200PixelFormatToPSPFMT(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
    216void
    217StartDrawing(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
    228int
    229TextureSwizzle(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}
    274int 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
    339SDL_Renderer *
    340PSP_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
    451static void
    452PSP_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
    453{
    454
    455}
    456
    457
    458static int
    459PSP_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
    505void
    506TextureActivate(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
    527static int
    528PSP_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
    553static int
    554PSP_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
    566static void
    567PSP_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
    580static int
    581PSP_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
    582{
    583
    584    return 0;
    585}
    586
    587static int
    588PSP_UpdateViewport(SDL_Renderer * renderer)
    589{
    590
    591    return 0;
    592}
    593
    594
    595static void
    596PSP_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
    627static int
    628PSP_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
    640static int
    641PSP_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
    664static int
    665PSP_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
    689static int
    690PSP_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
    725float 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
    738void 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
    750void Swap(float *a, float *b)
    751{
    752    float n=*a;
    753    *a = *b;
    754    *b = n;
    755}
    756
    757static int
    758PSP_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
    851static int
    852PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    853                    Uint32 pixel_format, void * pixels, int pitch)
    854
    855{
    856        return 0;
    857}
    858
    859
    860static int
    861PSP_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
    960static void
    961PSP_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
    979static void
    980PSP_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
    996static void
    997PSP_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