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 $(DEVKITPRO)),) -$(error "Please set DEVKITPRO in your environment (available from http://www.devkitpro.org). export DEVKITPRO=devkitPro") -endif ifeq ($(strip $(DEVKITARM)),) -DEVKITARM = $(DEVKITPRO)/devkitARM +$(error "Please set DEVKITARM in your environment. export DEVKITARM=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 +#--------------------------------------------------------------------------------------- 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; -}; - -/* 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: */ 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: */