Mercurial > sdl-ios-xcode
view src/video/nds/SDL_ndsrender.c @ 3474:1edb86163d62
Of COURSE that trick wouldn't work on all renderers. Fall back to something for now, hopefully figure out a better way to do this later.
If we have to, we can use vertical line and horizontal line textures for vertical and horizontal lines, and then create custom textures for diagonal lines and software render those. It's terrible, but at least it would be pixel perfect.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sat, 21 Nov 2009 07:22:59 +0000 |
parents | 7f684f249ec9 |
children | 64ce267332c6 |
line wrap: on
line source
/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2009 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ #include <stdio.h> #include <stdlib.h> #include <nds.h> //#include <nds/arm9/video.h> //#include <nds/arm9/sprite.h> //#include <nds/arm9/trig_lut.h> #include "SDL_config.h" #include "SDL_video.h" #include "../SDL_sysvideo.h" #include "../SDL_yuv_sw_c.h" #include "../SDL_renderer_sw.h" /* SDL NDS renderer implementation */ static SDL_Renderer *NDS_CreateRenderer(SDL_Window * window, Uint32 flags); static int NDS_ActivateRenderer(SDL_Renderer * renderer); static int NDS_DisplayModeChanged(SDL_Renderer * renderer); static int NDS_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); static int NDS_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, void **pixels, int *pitch); static int NDS_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Color * colors, int firstcolor, int ncolors); static int NDS_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, SDL_Color * colors, int firstcolor, int ncolors); static int NDS_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture); static int NDS_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture); static int NDS_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture); static int NDS_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture); static int NDS_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, const void *pixels, int pitch); static int NDS_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, int markDirty, void **pixels, int *pitch); static void NDS_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); static int NDS_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a, const SDL_Rect * rect); static int NDS_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect); static void NDS_RenderPresent(SDL_Renderer * renderer); static void NDS_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); static void NDS_DestroyRenderer(SDL_Renderer * renderer); SDL_RenderDriver NDS_RenderDriver = { NDS_CreateRenderer, {"nds", /* char* name */ (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_PRESENTVSYNC), /* u32 flags */ (SDL_TEXTUREMODULATE_NONE), /* u32 mod_modes */ (SDL_BLENDMODE_MASK), /* u32 blend_modes */ (SDL_TEXTURESCALEMODE_FAST), /* u32 scale_modes */ 3, /* u32 num_texture_formats */ { SDL_PIXELFORMAT_INDEX8, SDL_PIXELFORMAT_ABGR1555, SDL_PIXELFORMAT_BGR555, }, /* u32 texture_formats[20] */ (256), /* int max_texture_width */ (256), /* int max_texture_height */ } }; typedef struct { u8 bg_taken[4]; OamState *oam; int sub; } NDS_RenderData; typedef struct { enum { NDSTX_BG, NDSTX_SPR } type; /* represented in a bg or sprite. */ int hw_index; /* index of sprite in OAM or bg from libnds */ int pitch, bpp; /* useful information about the texture */ struct { int x, y; } scale; /* x/y stretch (24.8 fixed point) */ struct { int x, y; } scroll; /* x/y offset */ int rotate; /* -32768 to 32767, texture rotation */ u16 *vram_pixels; /* where the pixel data is stored (a pointer into VRAM) */ u16 *vram_palette; /* where the palette data is stored if it's indexed. */ /*int size; */ } NDS_TextureData; SDL_Renderer * NDS_CreateRenderer(SDL_Window * window, Uint32 flags) { SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); SDL_DisplayMode *displayMode = &display->current_mode; SDL_Renderer *renderer; NDS_RenderData *data; int i, n; int bpp; Uint32 Rmask, Gmask, Bmask, Amask; if (!SDL_PixelFormatEnumToMasks(displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { SDL_SetError("Unknown display format"); return NULL; } switch (displayMode->format) { case SDL_PIXELFORMAT_INDEX8: case SDL_PIXELFORMAT_ABGR1555: case SDL_PIXELFORMAT_BGR555: /* okay */ break; case SDL_PIXELFORMAT_RGB555: case SDL_PIXELFORMAT_RGB565: case SDL_PIXELFORMAT_ARGB1555: /* we'll take these too for now */ break; default: SDL_SetError("Warning: wrong display format for NDS!\n"); break; } renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); if (!renderer) { SDL_OutOfMemory(); return NULL; } data = (NDS_RenderData *) SDL_malloc(sizeof(*data)); if (!data) { NDS_DestroyRenderer(renderer); SDL_OutOfMemory(); return NULL; } SDL_zerop(data); renderer->RenderFill = NDS_RenderFill; renderer->RenderCopy = NDS_RenderCopy; renderer->RenderPresent = NDS_RenderPresent; renderer->DestroyRenderer = NDS_DestroyRenderer; renderer->info.name = NDS_RenderDriver.info.name; renderer->info.flags = 0; renderer->window = window->id; renderer->driverdata = data; renderer->CreateTexture = NDS_CreateTexture; renderer->QueryTexturePixels = NDS_QueryTexturePixels; renderer->SetTexturePalette = NDS_SetTexturePalette; renderer->GetTexturePalette = NDS_GetTexturePalette; renderer->SetTextureColorMod = NDS_SetTextureColorMod; renderer->SetTextureAlphaMod = NDS_SetTextureAlphaMod; renderer->SetTextureBlendMode = NDS_SetTextureBlendMode; renderer->SetTextureScaleMode = NDS_SetTextureScaleMode; renderer->UpdateTexture = NDS_UpdateTexture; renderer->LockTexture = NDS_LockTexture; renderer->UnlockTexture = NDS_UnlockTexture; renderer->DestroyTexture = NDS_DestroyTexture; renderer->info.mod_modes = NDS_RenderDriver.info.mod_modes; renderer->info.blend_modes = NDS_RenderDriver.info.blend_modes; renderer->info.scale_modes = NDS_RenderDriver.info.scale_modes; renderer->info.num_texture_formats = NDS_RenderDriver.info.num_texture_formats; SDL_memcpy(renderer->info.texture_formats, NDS_RenderDriver.info.texture_formats, sizeof(renderer->info.texture_formats)); renderer->info.max_texture_width = NDS_RenderDriver.info.max_texture_width; renderer->info.max_texture_height = NDS_RenderDriver.info.max_texture_height; data->sub = 0; /* TODO: this is hard-coded to the "main" screen. figure out how to detect whether to set it to "sub" screen. window->id, perhaps? */ data->bg_taken[2] = data->bg_taken[3] = 0; return renderer; } static int NDS_ActivateRenderer(SDL_Renderer * renderer) { NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; return 0; } static int NDS_DisplayModeChanged(SDL_Renderer * renderer) { NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; return 0; } static int NDS_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; NDS_TextureData *txdat = NULL; int i; int bpp; Uint32 Rmask, Gmask, Bmask, Amask; if (!SDL_PixelFormatEnumToMasks (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { SDL_SetError("Unknown texture format"); return -1; } /* conditional statements on w/h to place it as bg/sprite depending on which one it fits. */ if (texture->w <= 64 && texture->h <= 64) { int whichspr = -1; printf("NDS_CreateTexture: Tried to make a sprite.\n"); txdat->type = NDSTX_SPR; #if 0 for (i = 0; i < SPRITE_COUNT; ++i) { if (data->oam_copy.spriteBuffer[i].attribute[0] & ATTR0_DISABLED) { whichspr = i; break; } } if (whichspr >= 0) { SpriteEntry *sprent = &(data->oam_copy.spriteBuffer[whichspr]); int maxside = texture->w > texture->h ? texture->w : texture->h; int pitch; texture->driverdata = SDL_calloc(1, sizeof(NDS_TextureData)); txdat = (NDS_TextureData *) texture->driverdata; if (!txdat) { SDL_OutOfMemory(); return -1; } sprent->objMode = OBJMODE_BITMAP; sprent->posX = 0; sprent->posY = 0; sprent->colMode = OBJCOLOR_16; /* OBJCOLOR_256 for INDEX8 */ /* the first 32 sprites get transformation matrices. first come, first served */ if (whichspr < MATRIX_COUNT) { sprent->isRotoscale = 1; sprent->rsMatrixIdx = whichspr; } /* containing shape (square or 2:1 rectangles) */ sprent->objShape = OBJSHAPE_SQUARE; if (texture->w / 2 >= texture->h) { sprent->objShape = OBJSHAPE_WIDE; } else if (texture->h / 2 >= texture->w) { sprent->objShape = OBJSHAPE_TALL; } /* size in pixels */ /* FIXME: "pitch" is hardcoded for 2bytes per pixel. */ sprent->objSize = OBJSIZE_64; pitch = 128; if (maxside <= 8) { sprent->objSize = OBJSIZE_8; pitch = 16; } else if (maxside <= 16) { sprent->objSize = OBJSIZE_16; pitch = 32; } else if (maxside <= 32) { sprent->objSize = OBJSIZE_32; pitch = 64; } /* FIXME: this is hard-coded and will obviously only work for one sprite-texture. tells it to look at the beginning of SPRITE_GFX for its pixels. */ sprent->tileIdx = 0; /* now for the texture data */ txdat->type = NDSTX_SPR; txdat->hw_index = whichspr; txdat->dim.hdx = 0x100; txdat->dim.hdy = 0; txdat->dim.vdx = 0; txdat->dim.vdy = 0x100; txdat->dim.pitch = pitch; txdat->dim.bpp = bpp; txdat->vram_pixels = (u16 *) (data->sub ? SPRITE_GFX_SUB : SPRITE_GFX); /* FIXME: use tileIdx*boundary to point to proper location */ } else { SDL_SetError("Out of NDS sprites."); } #endif } else if (texture->w <= 256 && texture->h <= 256) { int whichbg = -1, base = 0; if (!data->bg_taken[2]) { whichbg = 2; } else if (!data->bg_taken[3]) { whichbg = 3; base = 4; } if (whichbg >= 0) { texture->driverdata = SDL_calloc(1, sizeof(NDS_TextureData)); txdat = (NDS_TextureData *) texture->driverdata; if (!txdat) { SDL_OutOfMemory(); return -1; } // hard-coded for 256x256 for now... // TODO: a series of if-elseif-else's to find the closest but larger size. if (!data->sub) { if (bpp == 8) { txdat->hw_index = bgInit(whichbg, BgType_Bmp8, BgSize_B8_256x256, 0, 0); } else { txdat->hw_index = bgInit(whichbg, BgType_Bmp16, BgSize_B16_256x256, 0, 0); } } else { if (bpp == 8) { txdat->hw_index = bgInitSub(whichbg, BgType_Bmp8, BgSize_B8_256x256, 0, 0); } else { txdat->hw_index = bgInitSub(whichbg, BgType_Bmp16, BgSize_B16_256x256, 0, 0); } } /* useful functions bgGetGfxPtr(bg3); bgSetCenter(bg3, rcX, rcY); bgSetRotateScale(bg3, angle, scaleX, scaleY); bgSetScroll(bg3, scrollX, scrollY); bgUpdate(bg3); */ txdat->type = NDSTX_BG; txdat->pitch = (texture->w) * (bpp / 8); txdat->bpp = bpp; txdat->rotate = 0; txdat->scale.x = 0x100; txdat->scale.y = 0x100; txdat->scroll.x = 0; txdat->scroll.y = 0; txdat->vram_pixels = (u16 *) bgGetGfxPtr(txdat->hw_index); bgSetCenter(txdat->hw_index, 0, 0); bgSetRotateScale(txdat->hw_index, txdat->rotate, txdat->scale.x, txdat->scale.y); bgSetScroll(txdat->hw_index, txdat->scroll.x, txdat->scroll.y); bgUpdate(txdat->hw_index); data->bg_taken[whichbg] = 1; /*txdat->size = txdat->dim.pitch * texture->h; */ } else { SDL_SetError("Out of NDS backgrounds."); } } else { SDL_SetError("Texture too big for NDS hardware."); } if (!texture->driverdata) { return -1; } return 0; } static int NDS_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, void **pixels, int *pitch) { NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; *pixels = txdat->vram_pixels; *pitch = txdat->pitch; return 0; } static int NDS_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, const void *pixels, int pitch) { NDS_TextureData *txdat; Uint8 *src, *dst; int row; size_t length; txdat = (NDS_TextureData *) texture->driverdata; src = (Uint8 *) pixels; dst = (Uint8 *) txdat->vram_pixels + rect->y * txdat->pitch + rect->x * ((txdat->bpp + 1) / 8); length = rect->w * ((txdat->bpp + 1) / 8); if (rect->w == texture->w) { dmaCopy(src, dst, length * rect->h); } else { for (row = 0; row < rect->h; ++row) { dmaCopy(src, dst, length); src += pitch; dst += txdat->pitch; } } return 0; } static int NDS_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, int markDirty, void **pixels, int *pitch) { NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; *pixels = (void *) ((u8 *) txdat->vram_pixels + rect->y * txdat->pitch + rect->x * ((txdat->bpp + 1) / 8)); *pitch = txdat->pitch; return 0; } static void NDS_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) { /* stub! */ } static int NDS_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a, const SDL_Rect * rect) { NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; SDL_Rect real_rect = *rect; u16 color; int i, j; printf("NDS_RenderFill: stub\n"); color = RGB8(r, g, b); /* macro in libnds that makes an ARGB1555 pixel */ /* TODO: make a single-color sprite and stretch it. calculate the "HDX" width modifier of the sprite by: let S be the actual sprite's width (like, 32 pixels for example) let R be the rectangle's width (maybe 50 pixels) HDX = (R<<8) / S; (it's fixed point, hence the bit shift. same goes for vertical. be sure to use 32-bit int's for the bit shift before the division!) */ return 0; } static int NDS_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect) { NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; SDL_Window *window = SDL_GetWindowFromID(renderer->window); SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); int Bpp = SDL_BYTESPERPIXEL(texture->format); if (txdat->type == NDSTX_BG) { txdat->scroll.x = dstrect->x; txdat->scroll.y = dstrect->y; } else { /* sprites not fully implemented yet */ printf("NDS_RenderCopy: used sprite!\n"); // SpriteEntry *spr = &(data->oam_copy.spriteBuffer[txdat->hw_index]); // spr->posX = dstrect->x; // spr->posY = dstrect->y; // if (txdat->hw_index < MATRIX_COUNT && spr->isRotoscale) { // } } return 0; } static void NDS_RenderPresent(SDL_Renderer * renderer) { NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; SDL_Window *window = SDL_GetWindowFromID(renderer->window); SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); /* update sprites */ // NDS_OAM_Update(&(data->oam_copy), data->sub); /* vsync for NDS */ if (renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) { swiWaitForVBlank(); } } static void NDS_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) { NDS_TextureData *txdat = texture->driverdata; /* free anything else allocated for texture */ SDL_free(txdat); } static void NDS_DestroyRenderer(SDL_Renderer * renderer) { NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; SDL_Window *window = SDL_GetWindowFromID(renderer->window); SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); int i; if (data) { /* free anything else relevant if anything else is allocated. */ SDL_free(data); } SDL_free(renderer); } static int NDS_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Color * colors, int firstcolor, int ncolors) { NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; /* set 8-bit modes in the background control registers for backgrounds, BGn_CR |= BG_256_COLOR */ return 0; } static int NDS_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, SDL_Color * colors, int firstcolor, int ncolors) { NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; /* stub! */ return 0; } static int NDS_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) { /* stub! */ return 0; } static int NDS_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) { /* stub! */ return 0; } static int NDS_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) { /* stub! */ return 0; } static int NDS_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture) { /* stub! (note: NDS hardware scaling is nearest neighbor.) */ return 0; } /* vi: set ts=4 sw=4 expandtab: */