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 ?
This commit is contained in:
Sam Lantinga 2011-03-06 21:12:19 -08:00
parent 0a92449744
commit 6e05dee645
13 changed files with 929 additions and 844 deletions

View File

@ -1,140 +1,236 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
#LibSDL 1.3 porting and enhancements by Darren Alton (lifning)
#LibSDL 1.2.9 DS porting by Troy Davis(GPF)
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment (available from http://www.devkitpro.org). export DEVKITPRO=<path to>devkitPro")
endif
ifeq ($(strip $(DEVKITARM)),)
DEVKITARM = $(DEVKITPRO)/devkitARM
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
PATH := $(PATH):$(DEVKITARM)/bin
CC = arm-eabi-gcc
AR = arm-eabi-ar
RANLIB = arm-eabi-ranlib
include $(DEVKITARM)/ds_rules
#ifdef GL
#DEFS += -DSDL_VIDEO_OPENGL=1
#TARGET = libSDL_gl.a
#else
TARGET = libSDL.a
#endif
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))
BUILD := src
SOURCES := source
DATA := data
INCLUDES := include
#CFLAGS=$(DEFS) -Iinclude
CFLAGS = -mthumb -mthumb-interwork \
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork \
-D__NDS__ -DENABLE_NDS -DNO_SIGNAL_H -DDISABLE_THREADS -DPACKAGE=\"SDL\" \
-DVERSION=\"1.3\" -DHAVE_ALLOCA_H=1 -DHAVE_ALLOCA=1
CFLAGS := -g -Wall -O2\
-march=armv5te -mtune=arm946e-s \
-O2 -Wall -Wwrite-strings -Wpointer-arith \
-DARM9 -D__NDS__ -I$(DEVKITPRO)/libnds/include -DENABLE_NDS -DNO_SIGNAL_H -DDISABLE_THREADS -DPACKAGE=\"SDL\" -DVERSION=\"1.3\" -DHAVE_ALLOCA_H=1 -DHAVE_ALLOCA=1 -Iinclude
-fomit-frame-pointer -ffast-math \
$(ARCH)
#src/audio/disk/SDL_diskaudio.c \
#src/audio/dummy/SDL_dummyaudio.c \
CFLAGS += $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
SRCS = \
src/SDL.c \
src/SDL_assert.c \
src/SDL_compat.c \
src/SDL_error.c \
src/SDL_fatal.c \
src/SDL_hints.c \
src/SDL_log.c \
src/atomic/SDL_atomic.c \
src/atomic/SDL_spinlock.c \
src/audio/SDL_audio.c \
src/audio/SDL_audiocvt.c \
src/audio/SDL_audiodev.c \
src/audio/SDL_audiotypecvt.c \
src/audio/SDL_mixer.c \
src/audio/SDL_mixer_MMX.c \
src/audio/SDL_mixer_MMX_VC.c \
src/audio/SDL_mixer_m68k.c \
src/audio/SDL_wave.c \
src/audio/nds/SDL_ndsaudio.c \
src/cpuinfo/SDL_cpuinfo.c \
src/events/SDL_events.c \
src/events/SDL_keyboard.c \
src/events/SDL_mouse.c \
src/events/SDL_quit.c \
src/events/SDL_touch.c \
src/events/SDL_windowevents.c \
src/events/nds/SDL_ndsgesture.c \
src/file/SDL_rwops.c \
src/haptic/SDL_haptic.c \
src/haptic/nds/SDL_syshaptic.c \
src/joystick/SDL_joystick.c \
src/joystick/nds/SDL_sysjoystick.c \
src/power/SDL_power.c \
src/power/nds/SDL_syspower.c \
src/render/SDL_render.c \
src/render/SDL_yuv_sw.c \
src/render/software/SDL_render_sw.c \
src/render/software/SDL_blendpoint.c \
src/render/software/SDL_drawline.c \
src/render/software/SDL_blendline.c \
src/render/software/SDL_blendfillrect.c \
src/render/software/SDL_drawpoint.c \
src/stdlib/SDL_getenv.c \
src/stdlib/SDL_iconv.c \
src/stdlib/SDL_malloc.c \
src/stdlib/SDL_qsort.c \
src/stdlib/SDL_stdlib.c \
src/stdlib/SDL_string.c \
src/thread/SDL_thread.c \
src/thread/nds/SDL_syscond.c \
src/thread/nds/SDL_sysmutex.c \
src/thread/nds/SDL_syssem.c \
src/thread/nds/SDL_systhread.c \
src/timer/SDL_timer.c \
src/timer/nds/SDL_systimer.c \
src/video/SDL_RLEaccel.c \
src/video/SDL_blit.c \
src/video/SDL_blit_0.c \
src/video/SDL_blit_1.c \
src/video/SDL_blit_A.c \
src/video/SDL_blit_N.c \
src/video/SDL_blit_auto.c \
src/video/SDL_blit_copy.c \
src/video/SDL_blit_slow.c \
src/video/SDL_bmp.c \
src/video/SDL_fillrect.c \
src/video/SDL_pixels.c \
src/video/SDL_rect.c \
src/video/SDL_stretch.c \
src/video/SDL_surface.c \
src/video/SDL_video.c \
src/video/dummy/SDL_nullevents.c \
src/video/dummy/SDL_nullvideo.c \
src/video/nds/SDL_ndsevents.c \
src/video/nds/SDL_ndsrender.c \
src/video/nds/SDL_ndsvideo.c \
ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
OBJS = $(SRCS:.c=.o)
# Set to 0 to use a framer buffer, or 1 to use the hardware
# renderer. Alas, both cannot be used at the same time for lack of
# display/texture memory.
USE_HW_RENDERER := 1
TEST = \
test/nds-test-progs/general/general.nds \
test/nds-test-progs/sprite/sprite.nds \
test/nds-test-progs/sprite2/sprite2.nds \
ifeq ($(USE_HW_RENDERER),1)
CFLAGS += -DUSE_HW_RENDERER
else
endif
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/lib/lib$(TARGET).a
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := \
SDL.c \
SDL_assert.c \
SDL_compat.c \
SDL_error.c \
SDL_fatal.c \
SDL_hints.c \
SDL_log.c \
atomic/SDL_atomic.c \
atomic/SDL_spinlock.arm.c \
audio/SDL_audio.c \
audio/SDL_audiocvt.c \
audio/SDL_audiodev.c \
audio/SDL_audiotypecvt.c \
audio/SDL_mixer.c \
audio/SDL_mixer_MMX.c \
audio/SDL_mixer_MMX_VC.c \
audio/SDL_mixer_m68k.c \
audio/SDL_wave.c \
audio/nds/SDL_ndsaudio.c \
cpuinfo/SDL_cpuinfo.c \
events/SDL_events.c \
events/SDL_keyboard.c \
events/SDL_mouse.c \
events/SDL_quit.c \
events/SDL_touch.c \
events/SDL_windowevents.c \
events/nds/SDL_ndsgesture.c \
file/SDL_rwops.c \
haptic/SDL_haptic.c \
haptic/nds/SDL_syshaptic.c \
joystick/SDL_joystick.c \
joystick/nds/SDL_sysjoystick.c \
power/SDL_power.c \
power/nds/SDL_syspower.c \
render/SDL_render.c \
render/SDL_yuv_sw.c \
render/software/SDL_blendfillrect.c \
render/software/SDL_blendline.c \
render/software/SDL_blendpoint.c \
render/software/SDL_drawline.c \
render/software/SDL_drawpoint.c \
render/software/SDL_render_sw.c \
stdlib/SDL_getenv.c \
stdlib/SDL_iconv.c \
stdlib/SDL_malloc.c \
stdlib/SDL_qsort.c \
stdlib/SDL_stdlib.c \
stdlib/SDL_string.c \
thread/SDL_thread.c \
thread/nds/SDL_syscond.c \
thread/nds/SDL_sysmutex.c \
thread/nds/SDL_syssem.c \
thread/nds/SDL_systhread.c \
timer/SDL_timer.c \
timer/nds/SDL_systimer.c \
video/SDL_RLEaccel.c \
video/SDL_blit.c \
video/SDL_blit_0.c \
video/SDL_blit_1.c \
video/SDL_blit_A.c \
video/SDL_blit_N.c \
video/SDL_blit_auto.c \
video/SDL_blit_copy.c \
video/SDL_blit_slow.c \
video/SDL_bmp.c \
video/SDL_clipboard.c \
video/SDL_fillrect.c \
video/SDL_pixels.c \
video/SDL_rect.c \
video/SDL_stretch.c \
video/SDL_surface.c \
video/SDL_video.c \
video/nds/SDL_ndsevents.c \
video/nds/SDL_ndsvideo.c
all: $(TARGET) install nds_test
ifeq ($(USE_HW_RENDERER),1)
# Ideally we should be able to not include the SW renderer at set
# SDL_NO_COMPAT. However that breaks the build.
CFILES += render/nds/SDL_ndsrender.c
else
endif
# That file must be compiled in arm mode, not thumb mode.
src/atomic/SDL_spinlock.o: src/atomic/SDL_spinlock.c
$(CC) $(CFLAGS) -mno-thumb -o $@ -c $^
#CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
#SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
#BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
$(TARGET): $(OBJS)
$(AR) rc $(TARGET) $(OBJS)
-@ ($(RANLIB) $@ || true) >/dev/null 2>&1
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
install: $(TARGET)
@cp libSDL.a $(DEVKITPRO)/libnds/lib/
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: arm_only $(BUILD) install nds_test
lib:
@[ -d $@ ] || mkdir -p $@
$(BUILD): lib
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.ds -s
install: $(BUILD)
@cp $(OUTPUT) $(DEVKITPRO)/libnds/lib/
@mkdir -p $(DEVKITPRO)/libnds/include/SDL/
@cp include/*.h $(DEVKITPRO)/libnds/include/SDL/
nds_test:
$(MAKE) -C test/nds-test-progs/general
# $(MAKE) -C test/nds-test-progs/sprite
# $(MAKE) -C test/nds-test-progs/sprite2
$(MAKE) -C test/nds-test-progs
tags:
etags $(SRCS)
# This file must be compiled with the ARM instruction set, not
# thumb. Use devkitpro way of doing things.
arm_only: src/atomic/SDL_spinlock.arm.c
src/atomic/SDL_spinlock.arm.c: src/atomic/SDL_spinlock.c
@cp $< $@
#---------------------------------------------------------------------------------
clean:
rm -f $(OBJS)
@echo clean ...
@cd src; rm -fr $(OFILES) $(OFILES:.o=.d) lib
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -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.

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -0,0 +1,364 @@
/*
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: */

View File

@ -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++;
}

View File

@ -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; \
\

View File

@ -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) {

View File

@ -1,522 +0,0 @@
/*
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 <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_render.h"
#include "../../render/SDL_sysrender.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);
#if 0
static int NDS_QueryTexturePixels(SDL_Renderer * renderer,
SDL_Texture * texture, void **pixels,
int *pitch);
#endif
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_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
int count);
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_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), /* u32 flags */
2, /* u32 num_texture_formats */
{
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_GetDisplayForWindow(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_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->RenderFillRects = NDS_RenderFillRects;
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;
renderer->driverdata = data;
renderer->CreateTexture = NDS_CreateTexture;
// renderer->QueryTexturePixels = NDS_QueryTexturePixels;
renderer->UpdateTexture = NDS_UpdateTexture;
renderer->LockTexture = NDS_LockTexture;
renderer->UnlockTexture = NDS_UnlockTexture;
renderer->DestroyTexture = NDS_DestroyTexture;
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+1) / 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();
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;
}
#if 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;
}
#endif
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_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
int count)
{
NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata;
printf("NDS_RenderFill: stub\n");
/* 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 = renderer->window;
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(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 = renderer->window;
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(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;
int i;
if (data) {
/* free anything else relevant if anything else is allocated. */
SDL_free(data);
}
SDL_free(renderer);
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -1,28 +0,0 @@
/*
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: */

View File

@ -31,110 +31,135 @@
#include <stdio.h>
#include <stdlib.h>
#include <nds.h>
#include <nds/arm9/video.h>
#include <fat.h>
#include <gl2d.h>
#include "SDL_video.h"
#include "SDL_mouse.h"
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../events/SDL_events_c.h"
#include "SDL_render.h"
#include "SDL_ndsvideo.h"
#include "SDL_ndsevents_c.h"
#include "../../render/SDL_sysrender.h"
#include "SDL_log.h"
#define NDSVID_DRIVER_NAME "nds"
/* Per Window information. */
struct NDS_WindowData {
int hw_index; /* index of sprite in OAM or bg from libnds */
int bg; /* which bg is that attached to (2 or 3) */
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) */
};
/* Per device information. */
struct NDS_DeviceData {
int has_bg2; /* backgroud 2 has been attached */
int has_bg3; /* backgroud 3 has been attached */
int sub;
};
/* Initialization/Query functions */
static int NDS_VideoInit(_THIS);
static int NDS_SetDisplayMode(_THIS, SDL_VideoDisplay *display,
SDL_DisplayMode *mode);
static void NDS_VideoQuit(_THIS);
/* SDL NDS driver bootstrap functions */
static int
NDS_Available(void)
static SDL_DisplayMode display_modes[] =
{
return (1); /* always here */
/* Only one screen */
{
.format = SDL_PIXELFORMAT_ABGR1555,
.w = SCREEN_WIDTH,
.h = SCREEN_HEIGHT,
.refresh_rate = 60,
},
/* Aggregated display (two screens) with no gap. */
{
.format = SDL_PIXELFORMAT_ABGR1555,
.w = SCREEN_WIDTH,
.h = 2*SCREEN_HEIGHT+SCREEN_GAP,
.refresh_rate = 60,
},
/* Aggregated display (two screens) with a gap. */
{
.format = SDL_PIXELFORMAT_ABGR1555,
.w = SCREEN_WIDTH,
.h = 2*SCREEN_HEIGHT,
.refresh_rate = 60,
},
/* Last entry */
{
.w = 0,
}
};
/* This function must not be optimized nor inlined, else the pointer
* to the message will be in the wrong register, and the emulator won't
* find the string. */
__attribute__ ((noinline, optimize (0)))
static void NDS_DebugOutput2(const char* message)
{
#ifdef __thumb__
asm volatile ("swi #0xfc");
#else
asm volatile ("swi #0xfc0000");
#endif
}
static int NDS_CreateWindowFramebuffer(_THIS, SDL_Window * window,
Uint32 * format, void ** pixels,
static void NDS_DebugOutput(void *userdata, int category, SDL_LogPriority priority, const char *message)
{
NDS_DebugOutput2(message);
}
/* SDL NDS driver bootstrap functions */
static int NDS_Available(void)
{
return 1; /* always here */
}
#ifndef USE_HW_RENDERER
static int NDS_CreateWindowFramebuffer(_THIS, SDL_Window *window,
Uint32 *format, void **pixels,
int *pitch)
{
struct NDS_DeviceData *data = _this->driverdata;
struct NDS_WindowData *wdata;
int bpp;
Uint32 Rmask, Gmask, Bmask, Amask;
int whichbg = -1;
const SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
const SDL_DisplayMode *mode = display->driverdata;
const Uint32 fmt = mode->format;
*format = SDL_PIXELFORMAT_BGR555;
if (fmt != SDL_PIXELFORMAT_ABGR1555) {
SDL_SetError("Unsupported pixel format (%x)", fmt);
return -1;
}
if (!SDL_PixelFormatEnumToMasks
(*format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
(fmt, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
SDL_SetError("Unknown texture format");
return -1;
}
if (!data->has_bg2)
whichbg = 2;
else if (!data->has_bg3)
whichbg = 3;
else {
SDL_SetError("Out of NDS backgrounds.");
return -1;
}
wdata = SDL_calloc(1, sizeof(struct NDS_WindowData));
if (!wdata) {
SDL_OutOfMemory();
return -1;
}
if (!data->sub) {
if (bpp == 8) {
wdata->hw_index =
bgInit(whichbg, BgType_Bmp8, BgSize_B8_256x256, 0, 0);
} else {
wdata->hw_index =
bgInit(whichbg, BgType_Bmp16, BgSize_B16_256x256, 0,
0);
}
if (bpp == 8) {
wdata->pixels_length = (SCREEN_HEIGHT+SCREEN_GAP+SCREEN_HEIGHT)*SCREEN_WIDTH;
} else {
if (bpp == 8) {
wdata->hw_index =
bgInitSub(whichbg, BgType_Bmp8, BgSize_B8_256x256, 0,
0);
} else {
wdata->hw_index =
bgInitSub(whichbg, BgType_Bmp16, BgSize_B16_256x256,
0, 0);
}
wdata->pixels_length = (SCREEN_HEIGHT+SCREEN_GAP+SCREEN_HEIGHT)*SCREEN_WIDTH*2;
}
wdata->pixels = SDL_calloc(1, wdata->pixels_length);
if (!wdata->pixels) {
SDL_free(wdata);
SDL_SetError("Not enough memory");
return -1;
}
if (bpp == 8) {
wdata->main.bg_id = bgInit(2, BgType_Bmp8, BgSize_B8_256x256, 0, 0);
wdata->sub.bg_id = bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 0, 0);
wdata->main.length = SCREEN_HEIGHT*SCREEN_WIDTH;
wdata->main.pixels = wdata->pixels;
wdata->sub.length = SCREEN_HEIGHT*SCREEN_WIDTH;
wdata->sub.pixels = (u8 *)wdata->pixels + wdata->main.length; /* or ...+SCREEN_GAP */
} else {
wdata->main.bg_id = bgInit(2, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
wdata->sub.bg_id = bgInitSub(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
wdata->main.length = SCREEN_HEIGHT*SCREEN_WIDTH*2;
wdata->main.pixels = wdata->pixels;
wdata->sub.length = SCREEN_HEIGHT*SCREEN_WIDTH*2;
wdata->sub.pixels = (u8 *)wdata->pixels + wdata->main.length; /* or ...+SCREEN_GAP */
}
wdata->bg = whichbg;
wdata->pitch = (window->w) * ((bpp+1) / 8);
wdata->bpp = bpp;
wdata->rotate = 0;
@ -142,22 +167,30 @@ static int NDS_CreateWindowFramebuffer(_THIS, SDL_Window * window,
wdata->scale.y = 0x100;
wdata->scroll.x = 0;
wdata->scroll.y = 0;
wdata->vram_pixels = (u16 *) bgGetGfxPtr(wdata->hw_index);
bgSetCenter(wdata->hw_index, 0, 0);
bgSetRotateScale(wdata->hw_index, wdata->rotate, wdata->scale.x,
wdata->main.vram_pixels = bgGetGfxPtr(wdata->main.bg_id);
wdata->sub.vram_pixels = bgGetGfxPtr(wdata->sub.bg_id);
#if 0
bgSetCenter(wdata->main.bg_id, 0, 0);
bgSetRotateScale(wdata->main.bg_id, wdata->rotate, wdata->scale.x,
wdata->scale.y);
bgSetScroll(wdata->hw_index, wdata->scroll.x, wdata->scroll.y);
bgSetScroll(wdata->main.bg_id, wdata->scroll.x, wdata->scroll.y);
#endif
#if 0
bgSetCenter(wdata->sub.bg_id, 0, 0);
bgSetRotateScale(wdata->sub.bg_id, wdata->rotate, wdata->scale.x,
wdata->scale.y);
bgSetScroll(wdata->sub.bg_id, wdata->scroll.x, wdata->scroll.y);
#endif
bgUpdate();
*pixels = wdata->vram_pixels;
*format = fmt;
*pixels = wdata->pixels;
*pitch = wdata->pitch;
if (!data->has_bg2)
data->has_bg2 = 1;
else
data->has_bg3 = 1;
window->driverdata = wdata;
return 0;
@ -166,35 +199,163 @@ static int NDS_CreateWindowFramebuffer(_THIS, SDL_Window * window,
static int NDS_UpdateWindowFramebuffer(_THIS, SDL_Window * window,
SDL_Rect * rects, int numrects)
{
/* Nothing to do because writes are done directly into the
* framebuffer. */
struct NDS_WindowData *wdata = window->driverdata;
/* Copy everything. TODO: use rects/numrects. */
DC_FlushRange(wdata->pixels, wdata->pixels_length);
swiWaitForVBlank();
dmaCopy(wdata->main.pixels, wdata->main.vram_pixels, wdata->main.length);
dmaCopy(wdata->sub.pixels, wdata->sub.vram_pixels, wdata->sub.length);
return 0;
}
static void NDS_DestroyWindowFramebuffer(_THIS, SDL_Window * window)
static void NDS_DestroyWindowFramebuffer(_THIS, SDL_Window *window)
{
struct NDS_DeviceData *data = _this->driverdata;
struct NDS_WindowData *wdata = window->driverdata;
if (wdata->bg == 2)
data->has_bg2 = 0;
else
data->has_bg3 = 0;
SDL_free(wdata->pixels);
SDL_free(wdata);
}
#endif
static void
NDS_DeleteDevice(SDL_VideoDevice * device)
#ifdef USE_HW_RENDERER
/* Set up a 2D layer construced of bitmap sprites. This holds the
* image when rendering to the top screen. From libnds example.
*/
static void initSubSprites(void)
{
oamInit(&oamSub, SpriteMapping_Bmp_2D_256, false);
int x = 0;
int y = 0;
int id = 0;
//set up a 4x3 grid of 64x64 sprites to cover the screen
for(y = 0; y < 3; y++)
for(x = 0; x < 4; x++)
{
oamSub.oamMemory[id].attribute[0] = ATTR0_BMP | ATTR0_SQUARE | (64 * y);
oamSub.oamMemory[id].attribute[1] = ATTR1_SIZE_64 | (64 * x);
oamSub.oamMemory[id].attribute[2] = ATTR2_ALPHA(1) | (8 * 32 * y) | (8 * x);
id++;
}
swiWaitForVBlank();
oamUpdate(&oamSub);
}
#endif
static int NDS_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
{
display->driverdata = mode->driverdata;
#ifdef USE_HW_RENDERER
videoSetMode(MODE_5_3D);
videoSetModeSub(MODE_5_2D);
/* initialize gl2d */
glScreen2D();
vramSetBankA(VRAM_A_TEXTURE);
vramSetBankB(VRAM_B_TEXTURE );
vramSetBankC(VRAM_C_SUB_BG_0x06200000);
vramSetBankE(VRAM_E_TEX_PALETTE);
powerOn(POWER_ALL_2D);
irqInit();
irqEnable(IRQ_VBLANK);
// sub sprites hold the bottom image when 3D directed to top
initSubSprites();
// sub background holds the top image when 3D directed to bottom
bgInitSub(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
#else
/* Select mode 5 for both screens. Can do Extended Rotation
* Background on both (BG 2 and 3). */
videoSetMode(MODE_5_2D);
videoSetModeSub(MODE_5_2D);
vramSetBankA(VRAM_A_MAIN_BG_0x06000000);
vramSetBankB(VRAM_B_TEXTURE );
vramSetBankC(VRAM_C_SUB_BG_0x06200000);
vramSetBankE(VRAM_E_TEX_PALETTE);
powerOn(POWER_ALL_2D);
irqInit();
irqEnable(IRQ_VBLANK);
#endif
return 0;
}
void NDS_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
SDL_DisplayMode *mode;
for (mode = display_modes; mode->w; mode++) {
mode->driverdata = mode; /* point back to self */
SDL_AddDisplayMode(display, mode);
}
}
static int NDS_VideoInit(_THIS)
{
SDL_VideoDisplay display;
SDL_DisplayMode mode;
SDL_zero(mode);
mode.format = SDL_PIXELFORMAT_UNKNOWN; // shoud be SDL_PIXELFORMAT_ABGR1555;
mode.w = SCREEN_WIDTH;
mode.h = 2*SCREEN_HEIGHT+SCREEN_GAP;
mode.refresh_rate = 60;
SDL_zero(display);
display.desktop_mode = mode;
SDL_AddVideoDisplay(&display);
return 0;
}
static void NDS_VideoQuit(_THIS)
{
videoSetMode(DISPLAY_SCREEN_OFF);
videoSetModeSub(DISPLAY_SCREEN_OFF);
vramSetBankA(VRAM_A_LCD);
vramSetBankB(VRAM_B_LCD);
vramSetBankC(VRAM_C_LCD);
vramSetBankD(VRAM_D_LCD);
vramSetBankE(VRAM_E_LCD);
vramSetBankF(VRAM_F_LCD);
vramSetBankG(VRAM_G_LCD);
vramSetBankH(VRAM_H_LCD);
vramSetBankI(VRAM_I_LCD);
}
static void NDS_DeleteDevice(SDL_VideoDevice * device)
{
SDL_free(device);
}
static SDL_VideoDevice *
NDS_CreateDevice(int devindex)
static SDL_VideoDevice *NDS_CreateDevice(int devindex)
{
SDL_VideoDevice *device;
fatInitDefault();
/* Initialize all variables that we clean on shutdown */
device = SDL_calloc(1, sizeof(SDL_VideoDevice));
if (!device) {
@ -212,16 +373,21 @@ NDS_CreateDevice(int devindex)
/* Set the function pointers */
device->VideoInit = NDS_VideoInit;
device->VideoQuit = NDS_VideoQuit;
device->GetDisplayModes = NDS_GetDisplayModes;
device->SetDisplayMode = NDS_SetDisplayMode;
device->PumpEvents = NDS_PumpEvents;
#ifndef USE_HW_RENDERER
device->CreateWindowFramebuffer = NDS_CreateWindowFramebuffer;
device->UpdateWindowFramebuffer = NDS_UpdateWindowFramebuffer;
device->DestroyWindowFramebuffer = NDS_DestroyWindowFramebuffer;
device->num_displays = 2; /* DS = dual screens */
#endif
device->free = NDS_DeleteDevice;
/* Set the debug output. Use only for under an emulator. Will crash the DS. */
#if 1
SDL_LogSetOutputFunction(NDS_DebugOutput, NULL);
#endif
return device;
}
@ -230,71 +396,4 @@ VideoBootStrap NDS_bootstrap = {
NDS_Available, NDS_CreateDevice
};
int
NDS_VideoInit(_THIS)
{
SDL_DisplayMode mode;
/* simple 256x192x16x60 for now */
mode.w = 256;
mode.h = 192;
mode.format = SDL_PIXELFORMAT_ABGR1555;
mode.refresh_rate = 60;
mode.driverdata = NULL;
if (SDL_AddBasicVideoDisplay(&mode) < 0) {
return -1;
}
SDL_zero(mode);
SDL_AddDisplayMode(&_this->displays[0], &mode);
powerOn(POWER_ALL_2D);
irqEnable(IRQ_VBLANK);
NDS_SetDisplayMode(_this, &_this->displays[0], &mode);
return 0;
}
static int
NDS_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
/* right now this function is just hard-coded for 256x192 ABGR1555 */
videoSetMode(MODE_5_2D | DISPLAY_BG2_ACTIVE | DISPLAY_BG3_ACTIVE | DISPLAY_BG_EXT_PALETTE | DISPLAY_SPR_1D_LAYOUT | DISPLAY_SPR_1D_BMP | DISPLAY_SPR_1D_BMP_SIZE_256 | /* (try 128 if 256 is trouble.) */
DISPLAY_SPR_ACTIVE | DISPLAY_SPR_EXT_PALETTE); /* display on main core
with lots of flags set for
flexibility/capacity to render */
/* hopefully these cover all the various things we might need to do */
vramSetBankA(VRAM_A_MAIN_BG_0x06000000);
vramSetBankB(VRAM_B_MAIN_BG_0x06020000);
vramSetBankC(VRAM_C_SUB_BG_0x06200000);
vramSetBankD(VRAM_D_MAIN_BG_0x06040000); /* not a typo. vram d can't sub */
vramSetBankE(VRAM_E_MAIN_SPRITE);
vramSetBankF(VRAM_F_SPRITE_EXT_PALETTE);
vramSetBankG(VRAM_G_BG_EXT_PALETTE);
vramSetBankH(VRAM_H_SUB_BG_EXT_PALETTE);
vramSetBankI(VRAM_I_SUB_SPRITE);
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE); /* debug text on sub
TODO: this will change
when multi-head is
introduced in render */
return 0;
}
void
NDS_VideoQuit(_THIS)
{
videoSetMode(DISPLAY_SCREEN_OFF);
videoSetModeSub(DISPLAY_SCREEN_OFF);
vramSetMainBanks(VRAM_A_LCD, VRAM_B_LCD, VRAM_C_LCD, VRAM_D_LCD);
vramSetBankE(VRAM_E_LCD);
vramSetBankF(VRAM_F_LCD);
vramSetBankG(VRAM_G_LCD);
vramSetBankH(VRAM_H_LCD);
vramSetBankI(VRAM_I_LCD);
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -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: */