From b0cc819f98bf4eef3cee3fd395ae0e080c02c724 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 6 Mar 2011 21:12:19 -0800 Subject: [PATCH] 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 ? --- Makefile.ds | 350 +++++++++++++-------- README.ds | 34 ++- include/SDL_config_nintendods.h | 6 + src/render/SDL_render.c | 3 + src/render/SDL_sysrender.h | 3 + src/render/nds/SDL_ndsrender.c | 364 ++++++++++++++++++++++ src/video/SDL_RLEaccel.c | 5 +- src/video/SDL_blit.h | 14 +- src/video/SDL_video.c | 4 + src/video/nds/SDL_ndsrender.c | 522 -------------------------------- src/video/nds/SDL_ndsrender_c.h | 28 -- src/video/nds/SDL_ndsvideo.c | 421 ++++++++++++++++---------- src/video/nds/SDL_ndsvideo.h | 27 ++ 13 files changed, 933 insertions(+), 848 deletions(-) create mode 100644 src/render/nds/SDL_ndsrender.c delete mode 100644 src/video/nds/SDL_ndsrender.c delete mode 100644 src/video/nds/SDL_ndsrender_c.h diff --git a/Makefile.ds b/Makefile.ds index 06c7094df..35d078a0d 100644 --- a/Makefile.ds +++ b/Makefile.ds @@ -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 $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/ds_rules + +#--------------------------------------------------------------------------------- +# 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 + +#--------------------------------------------------------------------------------- +# 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 \ + -fomit-frame-pointer -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM9 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions + +ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s +LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +# 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 -ifeq ($(strip $(DEVKITPRO)),) -$(error "Please set DEVKITPRO in your environment (available from http://www.devkitpro.org). export DEVKITPRO=devkitPro") +ifeq ($(USE_HW_RENDERER),1) +CFLAGS += -DUSE_HW_RENDERER +else endif -ifeq ($(strip $(DEVKITARM)),) -DEVKITARM = $(DEVKITPRO)/devkitARM + +#--------------------------------------------------------------------------------- +# 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 + + +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 + +#CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +#SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +#BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- endif -PATH := $(PATH):$(DEVKITARM)/bin +#--------------------------------------------------------------------------------- -CC = arm-eabi-gcc -AR = arm-eabi-ar -RANLIB = arm-eabi-ranlib +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) -#ifdef GL -#DEFS += -DSDL_VIDEO_OPENGL=1 -#TARGET = libSDL_gl.a -#else -TARGET = libSDL.a -#endif +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) -#CFLAGS=$(DEFS) -Iinclude -CFLAGS = -mthumb -mthumb-interwork \ - -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 - -#src/audio/disk/SDL_diskaudio.c \ -#src/audio/dummy/SDL_dummyaudio.c \ - -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 \ - -OBJS = $(SRCS:.c=.o) - -TEST = \ -test/nds-test-progs/general/general.nds \ -test/nds-test-progs/sprite/sprite.nds \ -test/nds-test-progs/sprite2/sprite2.nds \ - - -all: $(TARGET) install nds_test - -# 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 $^ - -$(TARGET): $(OBJS) - $(AR) rc $(TARGET) $(OBJS) - -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 - -install: $(TARGET) - @cp libSDL.a $(DEVKITPRO)/libnds/lib/ +.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 +#--------------------------------------------------------------------------------------- diff --git a/README.ds b/README.ds index 2118620b6..b79bd121a 100644 --- a/README.ds +++ b/README.ds @@ -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. diff --git a/include/SDL_config_nintendods.h b/include/SDL_config_nintendods.h index 77845f146..a58a81794 100644 --- a/include/SDL_config_nintendods.h +++ b/include/SDL_config_nintendods.h @@ -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 */ diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 7c46a8ca5..69cdb221b 100755 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -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 */ diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 6f4e35b0b..5c8532b8a 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -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 */ diff --git a/src/render/nds/SDL_ndsrender.c b/src/render/nds/SDL_ndsrender.c new file mode 100644 index 000000000..4a9f6f0b7 --- /dev/null +++ b/src/render/nds/SDL_ndsrender.c @@ -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 +#include +#include + +#include + +#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; iformat == 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; iis_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: */ diff --git a/src/video/SDL_RLEaccel.c b/src/video/SDL_RLEaccel.c index 7527e0810..eecb6fc98 100644 --- a/src/video/SDL_RLEaccel.c +++ b/src/video/SDL_RLEaccel.c @@ -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++; } diff --git a/src/video/SDL_blit.h b/src/video/SDL_blit.h index c20097b95..f787c908e 100644 --- a/src/video/SDL_blit.h +++ b/src/video/SDL_blit.h @@ -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; \ \ diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 88774b25b..871f885af 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -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) { diff --git a/src/video/nds/SDL_ndsrender.c b/src/video/nds/SDL_ndsrender.c deleted file mode 100644 index 7e3b43fff..000000000 --- a/src/video/nds/SDL_ndsrender.c +++ /dev/null @@ -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 -#include -#include -//#include -//#include -//#include - -#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: */ diff --git a/src/video/nds/SDL_ndsrender_c.h b/src/video/nds/SDL_ndsrender_c.h deleted file mode 100644 index 739d4a507..000000000 --- a/src/video/nds/SDL_ndsrender_c.h +++ /dev/null @@ -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: */ diff --git a/src/video/nds/SDL_ndsvideo.c b/src/video/nds/SDL_ndsvideo.c index 824f7c699..efb19a0d3 100644 --- a/src/video/nds/SDL_ndsvideo.c +++ b/src/video/nds/SDL_ndsvideo.c @@ -31,110 +31,135 @@ #include #include #include -#include +#include +#include #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; +static SDL_DisplayMode display_modes[] = +{ + /* 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, + } }; -/* Initialization/Query functions */ -static int NDS_VideoInit(_THIS); -static int NDS_SetDisplayMode(_THIS, SDL_VideoDisplay *display, - SDL_DisplayMode *mode); -static void NDS_VideoQuit(_THIS); +/* 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 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) +static int NDS_Available(void) { - return (1); /* always here */ + return 1; /* always here */ } -static int NDS_CreateWindowFramebuffer(_THIS, SDL_Window * window, - Uint32 * format, void ** pixels, +#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 + +#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_DeleteDevice(SDL_VideoDevice * device) +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: */ diff --git a/src/video/nds/SDL_ndsvideo.h b/src/video/nds/SDL_ndsvideo.h index 7eefa0bee..b79b2addc 100644 --- a/src/video/nds/SDL_ndsvideo.h +++ b/src/video/nds/SDL_ndsvideo.h @@ -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: */