Commit 6e05dee6 authored by Sam Lantinga's avatar Sam Lantinga

a Nintendo ds update

Frank Zago to SDL

For those interested, here's a snapshot of the current port. I did away with
most of the previous attempt which was based of the sprite engine, because the
support is limited to 128 64x64 sprites. Instead I'm using the gl engine.
The drawback is that either the frame buffer or the gl engine can be used
because there's not that much video memory on a DS.

With minimal changes to their code, it can now run the following tests: ,
testspriteminimal, testscale and testsprite2. The last 2 only run under the
emulator for some reason. The tests are not included in this patch for size
reason.

In 16 bits mode, the 16th bit indicated transparency/opacity. If 0, the color
is not displayed. So I had to patch a few core file to set that bit to 1. See
patch for src/video/SDL_RLEaccel.c and src/video/SDL_blit.h. Is that ok, or is
there a better way ?

The nds also doesn't support windowed mode, so I force the fullscreen in
src/video/SDL_video.c.  Is that ok, or is there a better way ?

To get a smaller library, I also tried to not compile the software renderer
when the hardware renderer is compiled in, and define SDL_NO_COMPAT; however
the compilation eventually fails in SDL_surface.c because SDL_SRCCOLORKEY is
defined in SDL_compat.h. Is SDL_NO_COMPAT only for application and not SDL
itself ?
parent 0a924497
This diff is collapsed.
......@@ -3,17 +3,37 @@ Simple DirectMedia Layer for Nintendo DS
================================================================================
-Requirements-
The devkitpro SDK available at http://devkitpro.org.
Read the information at http://devkitpro.org/wiki/Getting_Started/devkitARM
The necessary packages are devkitARM, libnds and default arm7.
* The devkitpro SDK available at http://devkitpro.org.
Read the information at http://devkitpro.org/wiki/Getting_Started/devkitARM
The necessary packages are devkitARM, libnds and default arm7.
* The hardware renderer is using the libgl2d abstraction library that can be found at:
http://rel.phatcode.net/junk.php?id=117
Build it, and install the library and the header where SDL can find them (ie. in
the libnds/lib and libnds/include directories).
-Building SDL-
After setting the devkitpro environment, type:
After setting the devkitpro environment, cd into your SDL directory and type:
make -f Makefile.ds
This will compile and install the library and headers into the proper libnds directories.
Additionnaly it will compile the general test, that you can run either on the DS or with desmume:
This will compile and install the library and headers into the proper libnds
directories. Additionnaly it will compile several tests that you can run
either on the DS or with desmume. For instance:
desmume test/nds-test-progs/general/general.nds
-Notes-
* The renderer code is based on the gl like engine. It's not using the sprite engine.
* The port is very basic and incomplete:
- SDL currently has to be compiled for either framebuffer mode or render mode.
See USE_HW_RENDERER in Makefile.ds.
- some optionnal renderer functions are not implemented.
-Limitations-
* in hardware renderer mode, don't load too many textures. The internal format is
2 bytes per pixel. And there is only 256KB reserved for the textures. For instance,
testscale won't display sample.bmp, unless it's resized to a smaller picture.
* the screen size is 256 x 384. Anything else won't work.
* there is no 8 bits/pixel mode because SDL 1.3 doesn't support palettes.
Note that the port is very basic and incomplete.
......@@ -115,7 +115,11 @@ typedef unsigned __PTRDIFF_TYPE__ uintptr_t;
/* Enable various video drivers */
#define SDL_VIDEO_DRIVER_NDS 1
#ifdef USE_HW_RENDERER
#define SDL_VIDEO_RENDER_NDS 1
#else
#define SDL_VIDEO_RENDER_NDS 0
#endif
/* Enable system power support */
#define SDL_POWER_NINTENDODS 1
......@@ -123,4 +127,6 @@ typedef unsigned __PTRDIFF_TYPE__ uintptr_t;
/* Enable haptic support */
#define SDL_HAPTIC_NDS 1
#define SDL_BYTEORDER SDL_LIL_ENDIAN
#endif /* _SDL_config_nintendods_h */
......@@ -59,6 +59,9 @@ static const SDL_RenderDriver *render_drivers[] = {
#endif
#if SDL_VIDEO_RENDER_DIRECTFB
&DirectFB_RenderDriver,
#endif
#if SDL_VIDEO_RENDER_NDS
&NDS_RenderDriver,
#endif
&SW_RenderDriver
#endif /* !SDL_RENDER_DISABLED */
......
......@@ -139,6 +139,9 @@ extern SDL_RenderDriver GLES_RenderDriver;
#if SDL_VIDEO_RENDER_DIRECTFB
extern SDL_RenderDriver DirectFB_RenderDriver;
#endif
#if SDL_VIDEO_RENDER_NDS
extern SDL_RenderDriver NDS_RenderDriver;
#endif
extern SDL_RenderDriver SW_RenderDriver;
#endif /* !SDL_RENDER_DISABLED */
......
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2011 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 <gl2d.h>
#include "SDL_config.h"
#include "SDL_video.h"
#include "../../video/SDL_sysvideo.h"
#include "SDL_render.h"
#include "../SDL_sysrender.h"
#include "SDL_log.h"
/* SDL NDS renderer implementation */
extern SDL_RenderDriver NDS_RenderDriver;
typedef struct
{
/* Whether current 3D engine is on the main or sub screen. */
int is_sub;
} NDS_RenderData;
typedef struct
{
glImage image[1];
} NDS_TextureData;
static int NDS_UpdateViewport(SDL_Renderer *renderer)
{
/* Nothing to do. */
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;
int dest_y;
if (data->is_sub) {
dest_y = dstrect->y;
} else {
dest_y = dstrect->y-SCREEN_HEIGHT;
}
if (texture->w == dstrect->w && texture->h == dstrect->h) {
/* No scaling */
glSprite(dstrect->x, dest_y, GL_FLIP_NONE, txdat->image);
} else {
/* Convert the scaling proportion into a 20.12 value. */
s32 scale_w = divf32(dstrect->w << 12, texture->w << 12);
s32 scale_h = divf32(dstrect->h << 12, texture->h << 12);
glSpriteScaleXY(dstrect->x, dest_y, scale_w, scale_h, GL_FLIP_NONE, txdat->image);
}
return 0;
}
static int NDS_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
{
NDS_TextureData *txdat = NULL;
int i;
SDL_Log("NDS_CreateTexture: NDS_CreateTexture.\n");
/* Sanity checks. */
for (i=0; i<NDS_RenderDriver.info.num_texture_formats; i++) {
if (texture->format == NDS_RenderDriver.info.texture_formats[i])
break;
}
if (i == NDS_RenderDriver.info.num_texture_formats) {
SDL_SetError("Unsupported texture format (%x)", texture->format);
return -1;
}
if (texture->w > NDS_RenderDriver.info.max_texture_width) {
SDL_SetError("Texture too large (%d)", texture->w);
return -1;
}
if (texture->h > NDS_RenderDriver.info.max_texture_height) {
SDL_SetError("Texture too tall (%d)", texture->h);
return -1;
}
texture->driverdata = SDL_calloc(1, sizeof(NDS_TextureData));
txdat = (NDS_TextureData *) texture->driverdata;
if (!txdat) {
SDL_OutOfMemory();
return -1;
}
return 0;
}
static void
NDS_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{
NDS_TextureData *txdat = texture->driverdata;
/* free anything else allocated for texture */
SDL_free(txdat);
}
/* size is no more than 1024. */
static int get_gltexture_size(unsigned int size)
{
if (size > 256)
return TEXTURE_SIZE_512;
else if (size > 128)
return TEXTURE_SIZE_256;
else if (size > 64)
return TEXTURE_SIZE_128;
else if (size > 32)
return TEXTURE_SIZE_64;
else if (size > 16)
return TEXTURE_SIZE_32;
else if (size > 8)
return TEXTURE_SIZE_16;
else
return TEXTURE_SIZE_8;
}
static int NDS_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels, int pitch)
{
NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata;
SDL_Log("enter %s\n", __func__);
glLoadTileSet(txdat->image,
rect->w, rect->h,
rect->w, rect->h,
GL_RGBA,
get_gltexture_size(rect->w),
get_gltexture_size(rect->h),
TEXGEN_OFF, 0, NULL,
pixels);
return 0;
}
static int NDS_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, void **pixels, int *pitch)
{
SDL_Log("enter %s (todo)\n", __func__);
return 0;
}
static void NDS_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
{
SDL_Log("enter %s\n", __func__);
/* stub! */
}
static int NDS_RenderClear(SDL_Renderer *renderer)
{
NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
/* wait for capture unit to be ready */
while(REG_DISPCAPCNT & DCAP_ENABLE);
/* 3D engine can only work on one screen at a time. */
data->is_sub = !data->is_sub;
if (data->is_sub) {
lcdMainOnBottom();
vramSetBankC(VRAM_C_LCD);
vramSetBankD(VRAM_D_SUB_SPRITE);
REG_DISPCAPCNT = DCAP_BANK(2) | DCAP_ENABLE | DCAP_SIZE(3);
} else {
lcdMainOnTop();
vramSetBankD(VRAM_D_LCD);
vramSetBankC(VRAM_C_SUB_BG);
REG_DISPCAPCNT = DCAP_BANK(3) | DCAP_ENABLE | DCAP_SIZE(3);
}
glBegin2D();
glClearColor(renderer->r >> 3,
renderer->g >> 3,
renderer->b >> 3,
renderer->a >> 3);
return 0;
}
static void NDS_RenderPresent(SDL_Renderer * renderer)
{
// SDL_Log("enter %s\n", __func__);
glEnd2D();
glFlush( 0 );
}
static int NDS_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points,
int count)
{
NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
int i;
int color = RGB15(renderer->r >> 3,
renderer->g >> 3,
renderer->b >> 3);
for (i=0; i < count; i++) {
if (data->is_sub) {
glPutPixel(points[i].x, points[i].y, color);
} else {
glPutPixel(points[i].x, points[i].y - SCREEN_HEIGHT, color);
}
}
return 0;
}
static int NDS_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points,
int count)
{
NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
int i;
int color = RGB15(renderer->r >> 3,
renderer->g >> 3,
renderer->b >> 3);
for (i=0; i < count-1; i++) {
if (data->is_sub) {
glLine(points[i].x, points[i].y, points[i+1].x, points[i+1].y, color);
} else {
glLine(points[i].x, points[i].y - SCREEN_HEIGHT,
points[i+1].x, points[i+1].y - SCREEN_HEIGHT, color);
}
}
return 0;
}
static int NDS_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect *rects,
int count)
{
NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
int i;
int color = RGB15(renderer->r >> 3,
renderer->g >> 3,
renderer->b >> 3);
for (i=0; i<count; i++) {
if (data->is_sub) {
glBoxFilled(rects[i].x, rects[i].y,
rects[i].x + rects[i].w,
rects[i].y + rects[i].h, color);
} else {
glBoxFilled(rects[i].x, rects[i].y - SCREEN_HEIGHT,
rects[i].x + rects[i].w,
rects[i].y + rects[i].h - SCREEN_HEIGHT,
color);
}
}
return 0;
}
static SDL_Renderer *
NDS_CreateRenderer(SDL_Window * window, Uint32 flags)
{
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
SDL_DisplayMode *displayMode = &display->current_mode;
SDL_Renderer *renderer;
NDS_RenderData *data;
int bpp;
Uint32 Rmask, Gmask, Bmask, Amask;
if (displayMode->format != SDL_PIXELFORMAT_ABGR1555) {
SDL_SetError("Unsupported pixel format (%x)", displayMode->format);
return NULL;
}
if (!SDL_PixelFormatEnumToMasks(displayMode->format, &bpp,
&Rmask, &Gmask, &Bmask, &Amask)) {
SDL_SetError("Unknown display format");
return NULL;
}
renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
if (!renderer) {
SDL_OutOfMemory();
return NULL;
}
data = (NDS_RenderData *) SDL_calloc(1, sizeof(*data));
if (!data) {
SDL_free(renderer);
SDL_OutOfMemory();
return NULL;
}
renderer->info.name = NDS_RenderDriver.info.name;
renderer->info.flags = 0;
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;
renderer->UpdateViewport = NDS_UpdateViewport;
renderer->CreateTexture = NDS_CreateTexture;
renderer->DestroyTexture = NDS_DestroyTexture;
renderer->RenderCopy = NDS_RenderCopy;
renderer->UpdateTexture = NDS_UpdateTexture;
renderer->LockTexture = NDS_LockTexture;
renderer->UnlockTexture = NDS_UnlockTexture;
renderer->RenderClear = NDS_RenderClear;
renderer->RenderPresent = NDS_RenderPresent;
renderer->RenderDrawPoints = NDS_RenderDrawPoints;
renderer->RenderDrawLines = NDS_RenderDrawLines;
renderer->RenderFillRects = NDS_RenderFillRects;
return renderer;
}
SDL_RenderDriver NDS_RenderDriver = {
.CreateRenderer = NDS_CreateRenderer,
.info = {
.name = "nds",
.flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC,
.num_texture_formats = 1,
.texture_formats = { [0] = SDL_PIXELFORMAT_ABGR1555,
[1] = SDL_PIXELFORMAT_BGR555,
},
.max_texture_width = 512,
.max_texture_height = 512,
}
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -891,6 +891,9 @@ copy_opaque_16(void *dst, Uint32 * src, int n,
unsigned r, g, b;
RGB_FROM_PIXEL(*src, sfmt, r, g, b);
PIXEL_FROM_RGB(*d, dfmt, r, g, b);
#ifdef __NDS__
*d |= NDS_BIT15;
#endif
src++;
d++;
}
......@@ -948,7 +951,7 @@ copy_transl_555(void *dst, Uint32 * src, int n,
Uint16 pix;
RGBA_FROM_8888(*src, sfmt, r, g, b, a);
PIXEL_FROM_RGB(pix, dfmt, r, g, b);
*d = ((pix & 0x3e0) << 16) | (pix & 0xfc1f) | ((a << 2) & 0x3e0);
*d = ((pix & 0x3e0) << 16) | (pix & 0xfc1f) | ((a << 2) & 0x3e0) | NDS_BIT15;
src++;
d++;
}
......
......@@ -114,6 +114,16 @@ extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface * surface);
#define DECLARE_ALIGNED(t,v,a) t v
#endif
/* The Nintendo surfaces are special. Bit 15 is the transparency
* bit. It must be set for the pixel to be displayed. By setting that
* value to 0 for other platforms, their compiler should optimize it
* out. */
#ifdef __NDS__
#define NDS_BIT15 0x8000
#else
#define NDS_BIT15 0
#endif
/* Load pixel of the specified format from a buffer and get its R-G-B values */
/* FIXME: rescale values to 0..255 here? */
#define RGB_FROM_PIXEL(Pixel, fmt, r, g, b) \
......@@ -241,7 +251,7 @@ do { \
Uint16 Pixel; \
\
PIXEL_FROM_RGB(Pixel, fmt, r, g, b); \
*((Uint16 *)(buf)) = Pixel; \
*((Uint16 *)(buf)) = Pixel | NDS_BIT15; \
} \
break; \
\
......@@ -396,7 +406,7 @@ do { \
Uint16 Pixel; \
\
PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a); \
*((Uint16 *)(buf)) = Pixel; \
*((Uint16 *)(buf)) = Pixel | NDS_BIT15; \
} \
break; \
\
......
......@@ -1130,6 +1130,10 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
/* Some platforms have OpenGL enabled by default */
#if (SDL_VIDEO_OPENGL && __MACOSX__) || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
flags |= SDL_WINDOW_OPENGL;
#endif
#ifdef __NDS__
/* Always for Nintendo DS. */
flags |= SDL_WINDOW_FULLSCREEN;
#endif
if (flags & SDL_WINDOW_OPENGL) {
if (!_this->GL_CreateContext) {
......
This diff is collapsed.
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2011 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 "SDL_config.h"
/* SDL surface based renderer implementation */
extern SDL_RenderDriver NDS_RenderDriver;
/* vi: set ts=4 sw=4 expandtab: */
This diff is collapsed.
......@@ -26,6 +26,33 @@
#include "../SDL_sysvideo.h"
#define SCREEN_GAP 92 /* line-equivalent gap between the 2 screens */
/* Per Window information. */
struct NDS_WindowData {
struct {
int bg_id;
void *vram_pixels; /* where the pixel data is stored (a pointer into VRAM) */
void *pixels; /* area in user frame buffer */
int length;
} main, sub;
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 */
/* user frame buffer - todo: better way to do double buffering */
void *pixels;
int pixels_length;
};
#endif /* _SDL_ndsvideo_h */
/* vi: set ts=4 sw=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment