src/video/nds/SDL_ndsrender.c
author Sam Lantinga
Tue, 08 Feb 2011 16:50:51 -0800
changeset 5229 c015d3e63631
parent 5149 be02be2ea897
child 5246 58265e606e4e
permissions -rw-r--r--
Fixed setting the texture unit, still doesn't work.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #include <stdio.h>
    24 #include <stdlib.h>
    25 #include <nds.h>
    26 //#include <nds/arm9/video.h>
    27 //#include <nds/arm9/sprite.h>
    28 //#include <nds/arm9/trig_lut.h>
    29 
    30 #include "SDL_config.h"
    31 
    32 #include "SDL_video.h"
    33 #include "../SDL_sysvideo.h"
    34 #include "../SDL_yuv_sw_c.h"
    35 #include "../SDL_renderer_sw.h"
    36 
    37 /* SDL NDS renderer implementation */
    38 
    39 static SDL_Renderer *NDS_CreateRenderer(SDL_Window * window, Uint32 flags);
    40 static int NDS_ActivateRenderer(SDL_Renderer * renderer);
    41 static int NDS_DisplayModeChanged(SDL_Renderer * renderer);
    42 static int NDS_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    43 static int NDS_QueryTexturePixels(SDL_Renderer * renderer,
    44                                   SDL_Texture * texture, void **pixels,
    45                                   int *pitch);
    46 static int NDS_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    47                              const SDL_Rect * rect, const void *pixels,
    48                              int pitch);
    49 static int NDS_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    50                            const SDL_Rect * rect, int markDirty,
    51                            void **pixels, int *pitch);
    52 static void NDS_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    53 static int NDS_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g,
    54                           Uint8 b, Uint8 a, const SDL_Rect * rect);
    55 static int NDS_RenderCopy(SDL_Renderer * renderer,
    56                           SDL_Texture * texture,
    57                           const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    58 static void NDS_RenderPresent(SDL_Renderer * renderer);
    59 static void NDS_DestroyTexture(SDL_Renderer * renderer,
    60                                SDL_Texture * texture);
    61 static void NDS_DestroyRenderer(SDL_Renderer * renderer);
    62 
    63 
    64 SDL_RenderDriver NDS_RenderDriver = {
    65     NDS_CreateRenderer,
    66     {"nds",                     /* char* name */
    67      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),  /* u32 flags */
    68      2,                         /* u32 num_texture_formats */
    69      {
    70       SDL_PIXELFORMAT_ABGR1555,
    71       SDL_PIXELFORMAT_BGR555,
    72       },                        /* u32 texture_formats[20] */
    73      (256),                     /* int max_texture_width */
    74      (256),                     /* int max_texture_height */
    75      }
    76 };
    77 
    78 typedef struct
    79 {
    80     u8 bg_taken[4];
    81     OamState *oam;
    82     int sub;
    83 } NDS_RenderData;
    84 
    85 typedef struct
    86 {
    87     enum
    88     { NDSTX_BG, NDSTX_SPR } type;       /* represented in a bg or sprite. */
    89     int hw_index;               /* index of sprite in OAM or bg from libnds */
    90     int pitch, bpp;             /* useful information about the texture */
    91     struct
    92     {
    93         int x, y;
    94     } scale;                    /* x/y stretch (24.8 fixed point) */
    95     struct
    96     {
    97         int x, y;
    98     } scroll;                   /* x/y offset */
    99     int rotate;                 /* -32768 to 32767, texture rotation */
   100     u16 *vram_pixels;           /* where the pixel data is stored (a pointer into VRAM) */
   101     u16 *vram_palette;          /* where the palette data is stored if it's indexed. */
   102     /*int size; */
   103 } NDS_TextureData;
   104 
   105 
   106 
   107 SDL_Renderer *
   108 NDS_CreateRenderer(SDL_Window * window, Uint32 flags)
   109 {
   110     SDL_VideoDisplay *display = window->display;
   111     SDL_DisplayMode *displayMode = &display->current_mode;
   112     SDL_Renderer *renderer;
   113     NDS_RenderData *data;
   114     int i, n;
   115     int bpp;
   116     Uint32 Rmask, Gmask, Bmask, Amask;
   117 
   118     if (!SDL_PixelFormatEnumToMasks(displayMode->format, &bpp,
   119                                     &Rmask, &Gmask, &Bmask, &Amask)) {
   120         SDL_SetError("Unknown display format");
   121         return NULL;
   122     }
   123     switch (displayMode->format) {
   124     case SDL_PIXELFORMAT_ABGR1555:
   125     case SDL_PIXELFORMAT_BGR555:
   126         /* okay */
   127         break;
   128     case SDL_PIXELFORMAT_RGB555:
   129     case SDL_PIXELFORMAT_RGB565:
   130     case SDL_PIXELFORMAT_ARGB1555:
   131         /* we'll take these too for now */
   132         break;
   133     default:
   134         SDL_SetError("Warning: wrong display format for NDS!\n");
   135         break;
   136     }
   137 
   138     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   139     if (!renderer) {
   140         SDL_OutOfMemory();
   141         return NULL;
   142     }
   143 
   144     data = (NDS_RenderData *) SDL_malloc(sizeof(*data));
   145     if (!data) {
   146         NDS_DestroyRenderer(renderer);
   147         SDL_OutOfMemory();
   148         return NULL;
   149     }
   150     SDL_zerop(data);
   151 
   152     renderer->RenderFill = NDS_RenderFill;
   153     renderer->RenderCopy = NDS_RenderCopy;
   154     renderer->RenderPresent = NDS_RenderPresent;
   155     renderer->DestroyRenderer = NDS_DestroyRenderer;
   156     renderer->info.name = NDS_RenderDriver.info.name;
   157     renderer->info.flags = 0;
   158     renderer->window = window;
   159     renderer->driverdata = data;
   160     renderer->CreateTexture = NDS_CreateTexture;
   161     renderer->QueryTexturePixels = NDS_QueryTexturePixels;
   162     renderer->UpdateTexture = NDS_UpdateTexture;
   163     renderer->LockTexture = NDS_LockTexture;
   164     renderer->UnlockTexture = NDS_UnlockTexture;
   165     renderer->DestroyTexture = NDS_DestroyTexture;
   166 
   167     renderer->info.num_texture_formats =
   168         NDS_RenderDriver.info.num_texture_formats;
   169     SDL_memcpy(renderer->info.texture_formats,
   170                NDS_RenderDriver.info.texture_formats,
   171                sizeof(renderer->info.texture_formats));
   172     renderer->info.max_texture_width =
   173         NDS_RenderDriver.info.max_texture_width;
   174     renderer->info.max_texture_height =
   175         NDS_RenderDriver.info.max_texture_height;
   176 
   177     data->sub = 0;              /* TODO: this is hard-coded to the "main" screen.
   178                                    figure out how to detect whether to set it to
   179                                    "sub" screen.  window->id, perhaps? */
   180     data->bg_taken[2] = data->bg_taken[3] = 0;
   181 
   182     return renderer;
   183 }
   184 
   185 static int
   186 NDS_ActivateRenderer(SDL_Renderer * renderer)
   187 {
   188     NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
   189 
   190     return 0;
   191 }
   192 
   193 static int
   194 NDS_DisplayModeChanged(SDL_Renderer * renderer)
   195 {
   196     NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
   197 
   198     return 0;
   199 }
   200 
   201 static int
   202 NDS_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   203 {
   204     NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
   205     NDS_TextureData *txdat = NULL;
   206     int i;
   207     int bpp;
   208     Uint32 Rmask, Gmask, Bmask, Amask;
   209 
   210     if (!SDL_PixelFormatEnumToMasks
   211         (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   212         SDL_SetError("Unknown texture format");
   213         return -1;
   214     }
   215 
   216     /* conditional statements on w/h to place it as bg/sprite
   217        depending on which one it fits. */
   218     if (texture->w <= 64 && texture->h <= 64) {
   219         int whichspr = -1;
   220         printf("NDS_CreateTexture: Tried to make a sprite.\n");
   221         txdat->type = NDSTX_SPR;
   222 #if 0
   223         for (i = 0; i < SPRITE_COUNT; ++i) {
   224             if (data->oam_copy.spriteBuffer[i].attribute[0] & ATTR0_DISABLED) {
   225                 whichspr = i;
   226                 break;
   227             }
   228         }
   229         if (whichspr >= 0) {
   230             SpriteEntry *sprent = &(data->oam_copy.spriteBuffer[whichspr]);
   231             int maxside = texture->w > texture->h ? texture->w : texture->h;
   232             int pitch;
   233 
   234             texture->driverdata = SDL_calloc(1, sizeof(NDS_TextureData));
   235             txdat = (NDS_TextureData *) texture->driverdata;
   236             if (!txdat) {
   237                 SDL_OutOfMemory();
   238                 return -1;
   239             }
   240 
   241             sprent->objMode = OBJMODE_BITMAP;
   242             sprent->posX = 0;
   243             sprent->posY = 0;
   244             sprent->colMode = OBJCOLOR_16;      /* OBJCOLOR_256 for INDEX8 */
   245 
   246             /* the first 32 sprites get transformation matrices.
   247                first come, first served */
   248             if (whichspr < MATRIX_COUNT) {
   249                 sprent->isRotoscale = 1;
   250                 sprent->rsMatrixIdx = whichspr;
   251             }
   252 
   253             /* containing shape (square or 2:1 rectangles) */
   254             sprent->objShape = OBJSHAPE_SQUARE;
   255             if (texture->w / 2 >= texture->h) {
   256                 sprent->objShape = OBJSHAPE_WIDE;
   257             } else if (texture->h / 2 >= texture->w) {
   258                 sprent->objShape = OBJSHAPE_TALL;
   259             }
   260 
   261             /* size in pixels */
   262             /* FIXME: "pitch" is hardcoded for 2bytes per pixel. */
   263             sprent->objSize = OBJSIZE_64;
   264             pitch = 128;
   265             if (maxside <= 8) {
   266                 sprent->objSize = OBJSIZE_8;
   267                 pitch = 16;
   268             } else if (maxside <= 16) {
   269                 sprent->objSize = OBJSIZE_16;
   270                 pitch = 32;
   271             } else if (maxside <= 32) {
   272                 sprent->objSize = OBJSIZE_32;
   273                 pitch = 64;
   274             }
   275 
   276             /* FIXME: this is hard-coded and will obviously only work for one
   277                sprite-texture.  tells it to look at the beginning of SPRITE_GFX
   278                for its pixels. */
   279             sprent->tileIdx = 0;
   280 
   281             /* now for the texture data */
   282             txdat->type = NDSTX_SPR;
   283             txdat->hw_index = whichspr;
   284             txdat->dim.hdx = 0x100;
   285             txdat->dim.hdy = 0;
   286             txdat->dim.vdx = 0;
   287             txdat->dim.vdy = 0x100;
   288             txdat->dim.pitch = pitch;
   289             txdat->dim.bpp = bpp;
   290             txdat->vram_pixels =
   291                 (u16 *) (data->sub ? SPRITE_GFX_SUB : SPRITE_GFX);
   292             /* FIXME: use tileIdx*boundary
   293                to point to proper location */
   294         } else {
   295             SDL_SetError("Out of NDS sprites.");
   296         }
   297 #endif
   298     } else if (texture->w <= 256 && texture->h <= 256) {
   299         int whichbg = -1, base = 0;
   300         if (!data->bg_taken[2]) {
   301             whichbg = 2;
   302         } else if (!data->bg_taken[3]) {
   303             whichbg = 3;
   304             base = 4;
   305         }
   306         if (whichbg >= 0) {
   307             texture->driverdata = SDL_calloc(1, sizeof(NDS_TextureData));
   308             txdat = (NDS_TextureData *) texture->driverdata;
   309             if (!txdat) {
   310                 SDL_OutOfMemory();
   311                 return -1;
   312             }
   313 // hard-coded for 256x256 for now...
   314 // TODO: a series of if-elseif-else's to find the closest but larger size.
   315             if (!data->sub) {
   316                 if (bpp == 8) {
   317                     txdat->hw_index =
   318                         bgInit(whichbg, BgType_Bmp8, BgSize_B8_256x256, 0, 0);
   319                 } else {
   320                     txdat->hw_index =
   321                         bgInit(whichbg, BgType_Bmp16, BgSize_B16_256x256, 0,
   322                                0);
   323                 }
   324             } else {
   325                 if (bpp == 8) {
   326                     txdat->hw_index =
   327                         bgInitSub(whichbg, BgType_Bmp8, BgSize_B8_256x256, 0,
   328                                   0);
   329                 } else {
   330                     txdat->hw_index =
   331                         bgInitSub(whichbg, BgType_Bmp16, BgSize_B16_256x256,
   332                                   0, 0);
   333                 }
   334             }
   335 
   336 /*   useful functions
   337         bgGetGfxPtr(bg3);            
   338 		bgSetCenter(bg3, rcX, rcY);
   339 		bgSetRotateScale(bg3, angle, scaleX, scaleY);
   340 		bgSetScroll(bg3, scrollX, scrollY);
   341 		bgUpdate(bg3);
   342 */
   343             txdat->type = NDSTX_BG;
   344             txdat->pitch = (texture->w) * (bpp / 8);
   345             txdat->bpp = bpp;
   346             txdat->rotate = 0;
   347             txdat->scale.x = 0x100;
   348             txdat->scale.y = 0x100;
   349             txdat->scroll.x = 0;
   350             txdat->scroll.y = 0;
   351             txdat->vram_pixels = (u16 *) bgGetGfxPtr(txdat->hw_index);
   352 
   353             bgSetCenter(txdat->hw_index, 0, 0);
   354             bgSetRotateScale(txdat->hw_index, txdat->rotate, txdat->scale.x,
   355                              txdat->scale.y);
   356             bgSetScroll(txdat->hw_index, txdat->scroll.x, txdat->scroll.y);
   357             bgUpdate(txdat->hw_index);
   358 
   359             data->bg_taken[whichbg] = 1;
   360             /*txdat->size = txdat->dim.pitch * texture->h; */
   361         } else {
   362             SDL_SetError("Out of NDS backgrounds.");
   363         }
   364     } else {
   365         SDL_SetError("Texture too big for NDS hardware.");
   366     }
   367 
   368     if (!texture->driverdata) {
   369         return -1;
   370     }
   371 
   372     return 0;
   373 }
   374 
   375 static int
   376 NDS_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   377                        void **pixels, int *pitch)
   378 {
   379     NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata;
   380     *pixels = txdat->vram_pixels;
   381     *pitch = txdat->pitch;
   382     return 0;
   383 }
   384 
   385 static int
   386 NDS_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   387                   const SDL_Rect * rect, const void *pixels, int pitch)
   388 {
   389     NDS_TextureData *txdat;
   390     Uint8 *src, *dst;
   391     int row;
   392     size_t length;
   393 
   394     txdat = (NDS_TextureData *) texture->driverdata;
   395 
   396     src = (Uint8 *) pixels;
   397     dst =
   398         (Uint8 *) txdat->vram_pixels + rect->y * txdat->pitch + rect->x *
   399         ((txdat->bpp + 1) / 8);
   400     length = rect->w * ((txdat->bpp + 1) / 8);
   401 
   402     if (rect->w == texture->w) {
   403         dmaCopy(src, dst, length * rect->h);
   404     } else {
   405         for (row = 0; row < rect->h; ++row) {
   406             dmaCopy(src, dst, length);
   407             src += pitch;
   408             dst += txdat->pitch;
   409         }
   410     }
   411 
   412     return 0;
   413 }
   414 
   415 static int
   416 NDS_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   417                 const SDL_Rect * rect, int markDirty, void **pixels,
   418                 int *pitch)
   419 {
   420     NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata;
   421 
   422     *pixels = (void *) ((u8 *) txdat->vram_pixels + rect->y * txdat->pitch +
   423                         rect->x * ((txdat->bpp + 1) / 8));
   424     *pitch = txdat->pitch;
   425 
   426     return 0;
   427 }
   428 
   429 static void
   430 NDS_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   431 {
   432     /* stub! */
   433 }
   434 
   435 static int
   436 NDS_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b,
   437                Uint8 a, const SDL_Rect * rect)
   438 {
   439     NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
   440     SDL_Rect real_rect = *rect;
   441     u16 color;
   442     int i, j;
   443 
   444     printf("NDS_RenderFill: stub\n");
   445     color = RGB8(r, g, b);      /* macro in libnds that makes an ARGB1555 pixel */
   446     /* TODO: make a single-color sprite and stretch it.
   447        calculate the "HDX" width modifier of the sprite by:
   448        let S be the actual sprite's width (like, 32 pixels for example)
   449        let R be the rectangle's width (maybe 50 pixels)
   450        HDX = (R<<8) / S;
   451        (it's fixed point, hence the bit shift.  same goes for vertical.
   452        be sure to use 32-bit int's for the bit shift before the division!)
   453      */
   454 
   455     return 0;
   456 }
   457 
   458 static int
   459 NDS_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   460                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   461 {
   462     NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
   463     NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata;
   464     SDL_Window *window = renderer->window;
   465     SDL_VideoDisplay *display = window->display;
   466     int Bpp = SDL_BYTESPERPIXEL(texture->format);
   467 
   468     if (txdat->type == NDSTX_BG) {
   469         txdat->scroll.x = dstrect->x;
   470         txdat->scroll.y = dstrect->y;
   471     } else {
   472         /* sprites not fully implemented yet */
   473         printf("NDS_RenderCopy: used sprite!\n");
   474 //        SpriteEntry *spr = &(data->oam_copy.spriteBuffer[txdat->hw_index]);
   475 //        spr->posX = dstrect->x;
   476 //        spr->posY = dstrect->y;
   477 //        if (txdat->hw_index < MATRIX_COUNT && spr->isRotoscale) {          
   478 //        }
   479     }
   480 
   481     return 0;
   482 }
   483 
   484 
   485 static void
   486 NDS_RenderPresent(SDL_Renderer * renderer)
   487 {
   488     NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
   489     SDL_Window *window = renderer->window;
   490     SDL_VideoDisplay *display = window->display;
   491 
   492     /* update sprites */
   493 //    NDS_OAM_Update(&(data->oam_copy), data->sub);
   494     /* vsync for NDS */
   495     if (renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) {
   496         swiWaitForVBlank();
   497     }
   498 }
   499 
   500 static void
   501 NDS_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   502 {
   503     NDS_TextureData *txdat = texture->driverdata;
   504     /* free anything else allocated for texture */
   505     SDL_free(txdat);
   506 }
   507 
   508 static void
   509 NDS_DestroyRenderer(SDL_Renderer * renderer)
   510 {
   511     NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
   512     int i;
   513 
   514     if (data) {
   515         /* free anything else relevant if anything else is allocated. */
   516         SDL_free(data);
   517     }
   518     SDL_free(renderer);
   519 }
   520 
   521 /* vi: set ts=4 sw=4 expandtab: */