diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5c7247b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,7 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index b7dd9a8..063b852 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,10 @@ { "files.associations": { + "*.embeddedhtml": "html", "vector": "cpp", "filesystem": "cpp", - "cmath": "cpp" + "cmath": "cpp", + "random": "cpp" }, "terminal.integrated.defaultProfile.windows": "MSYS2", "terminal.integrated.profiles.windows": { diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..28e0e3d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,9 @@ +{ + "version": "2.0.0", + "tasks": [{ + "label": "Make & Run", + "command": "make && ", // Could be any other shell command + "args": [""], + "type": "shell", + }] +} \ No newline at end of file diff --git a/nds_framebuffer_bitmaps/Makefile b/nds_framebuffer_bitmaps/Makefile index 6b3ea64..124a7ee 100644 --- a/nds_framebuffer_bitmaps/Makefile +++ b/nds_framebuffer_bitmaps/Makefile @@ -6,6 +6,11 @@ ifeq ($(strip $(DEVKITARM)),) $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") endif +# These set the information text in the nds file +#GAME_TITLE := My Wonderful Homebrew +#GAME_SUBTITLE1 := built with devkitARM +#GAME_SUBTITLE2 := http://devitpro.org + include $(DEVKITARM)/ds_rules #--------------------------------------------------------------------------------- @@ -13,138 +18,186 @@ include $(DEVKITARM)/ds_rules # BUILD is the directory where object files & intermediate files will be placed # SOURCES is a list of directories containing source code # INCLUDES is a list of directories containing extra header files -# DATA is a list of directories containing binary data -# GRAPHICS is a list of directories containing files to be processed by grit -# -# All directories are specified relative to the project directory where -# the makefile is found -# -#--------------------------------------------------------------------------------- -TARGET := $(notdir $(CURDIR)) -BUILD := build -SOURCES := source -DATA := data -INCLUDES := include -GRAPHICS := +# DATA is a list of directories containing binary files embedded using bin2o +# GRAPHICS is a list of directories containing image files to be converted with grit +# AUDIO is a list of directories containing audio to be converted by maxmod +# ICON is the image used to create the game icon, leave blank to use default rule +# NITRO is a directory that will be accessible via NitroFS +#--------------------------------------------------------------------------------- +TARGET := $(shell basename $(CURDIR)) +BUILD := build +SOURCES := source +INCLUDES := include +DATA := data +GRAPHICS := +AUDIO := +ICON := + +# specify a directory which contains the nitro filesystem +# this is relative to the Makefile +NITRO := nitrofiles #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -mthumb -mthumb-interwork - -CFLAGS := -g -Wall -O2\ - -march=armv5te -mtune=arm946e-s -fomit-frame-pointer\ - -ffast-math \ - $(ARCH) +ARCH := -marm -mthumb-interwork -march=armv5te -mtune=arm946e-s -CFLAGS += $(INCLUDE) -DARM9 -DDEBUG -CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions - -ASFLAGS := -g $(ARCH) -LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) +CFLAGS := -g -Wall -O3\ + $(ARCH) $(INCLUDE) -DARM9 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=c++20 +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) #--------------------------------------------------------------------------------- -# any extra libraries we wish to link with the project +# any extra libraries we wish to link with the project (order is important) #--------------------------------------------------------------------------------- -LIBS := -lnds9 - - +LIBS := -lnflib + +# automatigically add libraries for NitroFS +ifneq ($(strip $(NITRO)),) +LIBS := $(LIBS) -lfilesystem -lfat +endif +# automagically add maxmod library +ifneq ($(strip $(AUDIO)),) +LIBS := $(LIBS) -lmm9 +endif + +LIBS := $(LIBS) -lnds9 + #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- -LIBDIRS := $(LIBNDS) +LIBDIRS := $(LIBNDS) $(PORTLIBS) $(DEVKITPRO)/nflib #--------------------------------------------------------------------------------- # 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)/$(TARGET) -ifneq ($(BUILDDIR), $(CURDIR)) -#--------------------------------------------------------------------------------- - -export OUTPUT := $(CURDIR)/$(TARGET) - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ - $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) +export VPATH := $(CURDIR)/$(subst /,,$(dir $(ICON)))\ + $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))\ + $(foreach dir,$(DATA),$(CURDIR)/$(dir))\ + $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) -export DEPSDIR := $(CURDIR)/$(BUILD) +export DEPSDIR := $(CURDIR)/$(BUILD) -CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) -CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) -SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) -BMPFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.bmp))) +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +# prepare NitroFS directory +ifneq ($(strip $(NITRO)),) + export NITRO_FILES := $(CURDIR)/$(NITRO) +endif + +# get audio list for maxmod +ifneq ($(strip $(AUDIO)),) + export MODFILES := $(foreach dir,$(notdir $(wildcard $(AUDIO)/*.*)),$(CURDIR)/$(AUDIO)/$(dir)) + + # place the soundbank file in NitroFS if using it + ifneq ($(strip $(NITRO)),) + export SOUNDBANK := $(NITRO_FILES)/soundbank.bin + + # otherwise, needs to be loaded from memory + else + export SOUNDBANK := soundbank.bin + BINFILES += $(SOUNDBANK) + endif +endif #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- - export LD := $(CC) + export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- - export LD := $(CXX) + export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(BMPFILES:.bmp=.o) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) + +export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export OFILES := $(PNGFILES:.png=.o) $(OFILES_BIN) $(OFILES_SOURCES) + +export HFILES := $(PNGFILES:.png=.h) $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir))\ + $(foreach dir,$(LIBDIRS),-I$(dir)/include)\ + -I$(CURDIR)/$(BUILD) +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.bmp) + + ifneq (,$(findstring $(TARGET).bmp,$(icons))) + export GAME_ICON := $(CURDIR)/$(TARGET).bmp + else + ifneq (,$(findstring icon.bmp,$(icons))) + export GAME_ICON := $(CURDIR)/icon.bmp + endif + endif +else + ifeq ($(suffix $(ICON)), .grf) + export GAME_ICON := $(CURDIR)/$(ICON) + else + export GAME_ICON := $(CURDIR)/$(BUILD)/$(notdir $(basename $(ICON))).grf + endif +endif .PHONY: $(BUILD) clean - + #--------------------------------------------------------------------------------- $(BUILD): - @[ -d $@ ] || mkdir -p $@ - @make BUILDDIR=`cd $(BUILD) && pwd` --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - + @mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + #--------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds $(TARGET).ds.gba - - + @rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds $(SOUNDBANK) + +test: + @echo "$(CXXFLAGS)" + +convert: + #--------------------------------------------------------------------------------- else - -DEPENDS := $(OFILES:.o=.d) - + #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- -$(OUTPUT).nds : $(OUTPUT).elf -$(OUTPUT).elf : $(OFILES) +$(OUTPUT).nds: $(OUTPUT).elf $(NITRO_FILES) $(GAME_ICON) +$(OUTPUT).elf: $(OFILES) +# source files depend on generated headers +$(OFILES_SOURCES) : $(HFILES) -#--------------------------------------------------------------------------------- -# The bin2o rule should be copied and modified -# for each extension used in the data directories -#--------------------------------------------------------------------------------- +# need to build soundbank first +$(OFILES): $(SOUNDBANK) #--------------------------------------------------------------------------------- -# This rule links in binary data with the .bin extension +# rule to build solution from music files #--------------------------------------------------------------------------------- -%.bin.o : %.bin +$(SOUNDBANK) : $(MODFILES) #--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) + mmutil $^ -d -o$@ -hsoundbank.h #--------------------------------------------------------------------------------- -# This rule links in binary data with the .raw extension -#--------------------------------------------------------------------------------- -%.raw.o : %.raw +%.bin.o %_bin.h : %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) @@ -153,15 +206,22 @@ $(OUTPUT).elf : $(OFILES) # This rule creates assembly source files using grit # grit takes an image file and a .grit describing how the file is to be processed # add additional rules like this for each image extension -# you use in the graphics folders +# you use in the graphics folders #--------------------------------------------------------------------------------- -%.s %.h : %.bmp %.grit +%.s %.h: %.png %.grit #--------------------------------------------------------------------------------- grit $< -fts -o$* - --include $(DEPENDS) - +#--------------------------------------------------------------------------------- +# Convert non-GRF game icon to GRF if needed +#--------------------------------------------------------------------------------- +$(GAME_ICON): $(notdir $(ICON)) +#--------------------------------------------------------------------------------- + @echo convert $(notdir $<) + @grit $< -g -gt -gB4 -gT FF00FF -m! -p -pe 16 -fh! -ftr + +-include $(DEPSDIR)/*.d + #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- diff --git a/nds_framebuffer_bitmaps/convert-assets.sh b/nds_framebuffer_bitmaps/convert-assets.sh new file mode 100644 index 0000000..0c58b16 --- /dev/null +++ b/nds_framebuffer_bitmaps/convert-assets.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +grit assets/backgrounds/test-bg.png -ftb -fh! -gb -gB16 + + +# for background in assets/backgrounds/*.png; do +# grit $background -ftb -fh! -gT000000 -gt -gB8 -mR8 -mLs +# done + +for sprite in assets/sprites/*.png; do + grit $sprite -ftb -fh! -gT000000 -gt -gB8 -m! +done + +for file in *.bin; do + mv -- "$file" "${file%.bin}" +done + +mv *.pal *.img ./nitrofiles/ diff --git a/nds_framebuffer_bitmaps/source/1_color.cpp b/nds_framebuffer_bitmaps/source/1_color.cpp new file mode 100644 index 0000000..c9ee928 --- /dev/null +++ b/nds_framebuffer_bitmaps/source/1_color.cpp @@ -0,0 +1,127 @@ +#include +#include "screen_utils.h" +#include "scene.h" +#include "../../effolkronium/random.hpp" + + +class FirstSketch : public Scene +{ + int t = 0; + + using Random = effolkronium::random_static; + + + const int palette[9] = { + COLOR(0,0,0), + COLOR(31,31,31), + COLOR(31,0,0), + COLOR(0,31,0), + COLOR(0,0,31), + COLOR(31,31,0), + COLOR(31,0,31), + COLOR(0,31,31), + COLOR(31,31,31) + }; + + typedef struct BALL{ + int row; + int col; + int size; + int rdel; + int cdel; + u16 color; + } BALL; + + + BALL ball; + BALL old_ball; + + void initialize_ball() { + ball.row = 10; + ball.col= 10; + ball.size = 5; + ball.rdel= 1; + ball.cdel = 2; + ball.color = COLOR(0,0,0); //COLOR(31,31,31); + } + + + + +public: + void setup() { + // Set the main diplay to frame buffer mode 0 (FB0). + // In FB0 VRAM A is drawn to the screen. + REG_DISPCNT_MAIN = MODE_FB0; + // Enable VRAM A + VRAM_A_CR = VRAM_ENABLE; + + initialize_ball(); + } + + + void update() { + t++; + + old_ball = ball; + + // move ball + ball.row += ball.rdel; + ball.col+= ball.cdel; + + // check for collisions with the sides of the screen + if (ball.row + ball.size > SCREENHEIGHT) { + ball.row = SCREENHEIGHT - ball.size; + ball.rdel *= -1; + } + if (ball.col + ball.size > SCREENWIDTH) { + ball.col = SCREENWIDTH- ball.size; + ball.cdel *= -1; + } + if (ball.row < 0) { + ball.row = 0; + ball.rdel *= -1; + } + if (ball.col< 0) { + ball.col = 0; + ball.cdel *= -1; + } + } + + + void draw() { + + // slightly erase everything + for (int i=0; i<100; i++) { + int randomPixel = Random::get(0, SCREENHEIGHT*SCREENWIDTH); + int randomColor = Random::get(0, 9); + VRAM_A[randomPixel] = palette[randomColor]; + // VRAM_A[randomPixel] = COLOR(0,0,0); + // VRAM_A[randomPixel] = i % 2 == 0 ? COLOR(0,0,0) : COLOR(31,31,31) + } + + // erase the ball + // rect(old_ball.row, old_ball.col, old_ball.size, old_ball.size, 0); + + // draw it in its new position + int randomRectColor = Random::get(0, 9); + rect(ball.row, ball.col, ball.size, ball.size, palette[randomRectColor]); + rect(ball.row, ball.col, ball.size, ball.size, COLOR(0,0,0)); + + int randomColor = Random::get(0, 9); + int circleSize = sin(t / 100.0) * 50.0; + drawCircleFilled(SCREENWIDTH/2, SCREENHEIGHT/2, 20, palette[randomColor]); + + for (int i=1; i<9; i++) { + drawCircleFilled(SCREENWIDTH/2, SCREENHEIGHT/2, 20, palette[randomColor]); + // drawCircleFilled(SCREENWIDTH/2, SCREENHEIGHT/2, circleSize - i *10, i %2 == 0 ? COLOR(0,0,0) : COLOR(31,31,31)); + } + + // random lines + int start = Random::get(0, SCREENHEIGHT*SCREENWIDTH); + + // for (int y =0; y<10; y++) { + // dmaFillWords(COLOR(0,0,0), VRAM_A + start * SCREENHEIGHT, 20); + // } + } +}; diff --git a/nds_framebuffer_bitmaps/source/2_bw.cpp b/nds_framebuffer_bitmaps/source/2_bw.cpp new file mode 100644 index 0000000..0b6e7ca --- /dev/null +++ b/nds_framebuffer_bitmaps/source/2_bw.cpp @@ -0,0 +1,126 @@ +#include +#include "screen_utils.h" +#include "scene.h" +#include "../../effolkronium/random.hpp" + + +class SecondSketch : public Scene +{ + int t = 0; + + using Random = effolkronium::random_static; + + + const int palette[9] = { + COLOR(0,0,0), + COLOR(31,31,31), + COLOR(31,0,0), + COLOR(0,31,0), + COLOR(0,0,31), + COLOR(31,31,0), + COLOR(31,0,31), + COLOR(0,31,31), + COLOR(31,31,31) + }; + + typedef struct BALL { + int row; + int col; + int size; + int rdel; + int cdel; + u16 color; + } BALL; + + + BALL ball; + BALL old_ball; + + void initialize_ball() { + ball.row = 10; + ball.col= 10; + ball.size = 5; + ball.rdel= 1; + ball.cdel = 2; + ball.color = COLOR(0,0,0); //COLOR(31,31,31); + } + + + + +public: + void setup() { + // Set the main diplay to frame buffer mode 0 (FB0). + // In FB0 VRAM A is drawn to the screen. + REG_DISPCNT_MAIN = MODE_FB0; + // Enable VRAM A + VRAM_A_CR = VRAM_ENABLE; + + initialize_ball(); + } + + + void update() { + t++; + + old_ball = ball; + + // move ball + ball.row += ball.rdel; + ball.col+= ball.cdel; + + // check for collisions with the sides of the screen + if (ball.row + ball.size > SCREENHEIGHT) { + ball.row = SCREENHEIGHT - ball.size; + ball.rdel *= -1; + } + if (ball.col + ball.size > SCREENWIDTH) { + ball.col = SCREENWIDTH- ball.size; + ball.cdel *= -1; + } + if (ball.row < 0) { + ball.row = 0; + ball.rdel *= -1; + } + if (ball.col< 0) { + ball.col = 0; + ball.cdel *= -1; + } + } + + + void draw() { + // slightly erase everything + for (int i=0; i<100; i++) { + int randomPixel = Random::get(0, SCREENHEIGHT*SCREENWIDTH); + // int randomColor = Random::get(0, 9); + // VRAM_A[randomPixel] = palette[randomColor]; + // VRAM_A[randomPixel] = COLOR(0,0,0); + VRAM_A[randomPixel] = i % 2 == 0 ? COLOR(0,0,0) : COLOR(31,31,31); + } + + // erase the ball + // rect(old_ball.row, old_ball.col, old_ball.size, old_ball.size, 0); + + // draw it in its new position + int randomRectColor = Random::get(0, 9); + rect(ball.row, ball.col, ball.size, ball.size, palette[randomRectColor]); + rect(ball.row, ball.col, ball.size, ball.size, COLOR(0,0,0)); + + int randomColor = Random::get(0, 9); + int circleSize = sin(t / 100.0) * 50.0; + drawCircleFilled(SCREENWIDTH/2, SCREENHEIGHT/2, 20, palette[randomColor]); + + for (int i=1; i<9; i++) { + // drawCircleFilled(SCREENWIDTH/2, SCREENHEIGHT/2, 20, palette[randomColor]); + drawCircleFilled(SCREENWIDTH/2, SCREENHEIGHT/2, circleSize - i *10, i %2 == 0 ? COLOR(0,0,0) : COLOR(31,31,31)); + } + + // random lines + int start = Random::get(0, SCREENHEIGHT*SCREENWIDTH); + + // for (int y =0; y<10; y++) { + // dmaFillWords(COLOR(0,0,0), VRAM_A + start * SCREENHEIGHT, 20); + // } + } +}; diff --git a/nds_framebuffer_bitmaps/source/3_with_sprites.cpp b/nds_framebuffer_bitmaps/source/3_with_sprites.cpp new file mode 100644 index 0000000..ddde112 --- /dev/null +++ b/nds_framebuffer_bitmaps/source/3_with_sprites.cpp @@ -0,0 +1,74 @@ +#include +#include +#include +#include "screen_utils.h" +#include "scene.h" +#include "../../effolkronium/random.hpp" + + +class WithSprites : public Scene +{ + int t = 0; + + using Random = effolkronium::random_static; + + int CIRCLE_IMG = 2; + + + void initBGSys() { + // Initialize bitmap backgrounds system + NF_InitBitmapBgSys(0, 1); + // Initialize storage buffers + NF_Init16bitsBgBuffers(); + // Initialize backbuffers + NF_Init16bitsBackBuffer(0); + // Enable backbuffers + NF_Enable16bitsBackBuffer(0); + } + +public: + void setup() { + + // Set the main diplay to frame buffer mode 0 (FB0). + // In FB0 VRAM A is drawn to the screen. + // REG_DISPCNT_MAIN = MODE_FB0; + // // Enable VRAM A + // VRAM_A_CR = VRAM_ENABLE; + + // Initialize 2D engine in both screens and use mode 0 + // NF_Set2D(0, 5); + // NF_Set2D(1, 5); + + // // Initialize NitroFS and set it as the root folder of the filesystem + // nitroFSInit(NULL); + // NF_SetRootFolder("NITROFS"); + + // initBGSys(); + + // NF_Load16bitsBg("clear", 1); + // NF_Load16bitsImage("circlesmall", CIRCLE_IMG, 16, 16); + } + + + void update() { + + } + + + void draw() { + for (int i=0; i<100; i++) { + int randomPixel = Random::get(0, SCREENHEIGHT*SCREENWIDTH); + VRAM_A[randomPixel] = i % 2 == 0 ? COLOR(0,0,0) : COLOR(31,31,31); + } + + // on touch + // touchPosition touch; + // touchRead(&touch); + + // if (touch.px > 0) { + // NF_Copy16bitsBuffer(0, 1, 1); + // NF_Flip16bitsBackBuffer(0); + // NF_Draw16bitsImage(0, CIRCLE_IMG, 100, 100, true); + // } + } +}; diff --git a/nds_framebuffer_bitmaps/source/4_pico_palette.cpp b/nds_framebuffer_bitmaps/source/4_pico_palette.cpp new file mode 100644 index 0000000..c0e3752 --- /dev/null +++ b/nds_framebuffer_bitmaps/source/4_pico_palette.cpp @@ -0,0 +1,91 @@ +#include +#include "screen_utils.h" +#include "scene.h" +#include "../../effolkronium/random.hpp" + + +class PicoPalette : public Scene +{ + int t = 0; + + int lastX = 0, lastY = 0; + + using Random = effolkronium::random_static; + + // const int palette[9] = { + // COLOR(0,0,0), + // COLOR(31,31,31), + // COLOR(31,0,0), + // COLOR(0,31,0), + // COLOR(0,0,31), + // COLOR(31,31,0), + // COLOR(31,0,31), + // COLOR(0,31,31), + // COLOR(31,31,31) + // }; + const int palette[16] = { + RGB(0,0,0), // black + RGB(29,43,83), // dark blue + RGB(126,37,83), // purple + RGB(3,135,81), // dark green + RGB(171,82,54), // brown + RGB(95,87,79), // dark grey + RGB(194,195,199), // light grey + RGB(255,240,232), // white + RGB(255,0,77), // red + RGB(255,163,1), // orange + RGB(255,236,38), // yellow + RGB(1,228,55), // green + RGB(41,173,255), // light blue + RGB(131,118,156), // indigo + RGB(255,119,168), // pink + RGB(255,204,170) // peach + }; + +public: + void setup() { + // Set the main diplay to frame buffer mode 0 (FB0). + // In FB0 VRAM A is drawn to the screen. + REG_DISPCNT_MAIN = MODE_FB0; + // Enable VRAM A + VRAM_A_CR = VRAM_ENABLE; + } + + + void update() { + t++; + } + + void drawCircleSine() { + int x = SCREENWIDTH/2 + 50 * sin(t/10.0); + int y = SCREENHEIGHT/2 + 50 * cos(t/10.0); + + drawCircleFilled(lastX, lastY, 10, palette[0]); + drawCircleFilled(x, y, 10, palette[8]); + + lastX = x; + lastY = y; + } + + void draw() { + // Visual noise + // for (int i=0; i<100; i++) { + // int randomPixel = Random::get(0, SCREENHEIGHT*SCREENWIDTH); + // int randomColor = Random::get(0, 9); + // VRAM_A[randomPixel] = palette[randomColor]; + // } + + // Draw a small rectangle for every color + int color = 0; + for (int x=0; x<4; x++) { + for (int y=0; y<4; y++) { + rect(x*16, y*16, 16, 16, palette[color]); + color++; + } + } + + drawCircleSine(); + + swiWaitForVBlank(); + } +}; diff --git a/nds_framebuffer_bitmaps/source/main.cpp b/nds_framebuffer_bitmaps/source/main.cpp index ff7ff1b..96864ac 100644 --- a/nds_framebuffer_bitmaps/source/main.cpp +++ b/nds_framebuffer_bitmaps/source/main.cpp @@ -1,204 +1,45 @@ -#include -#include -#include "../../effolkronium/random.hpp" -#include "screen_utils.h" +#include "1_color.cpp" +#include "2_bw.cpp" +#include "3_with_sprites.cpp" +#include "4_pico_palette.cpp" -int palette[] = { - COLOR(0,0,0), - COLOR(31,31,31), - COLOR(31,0,0), - COLOR(0,31,0), - COLOR(0,0,31), - COLOR(31,31,0), - COLOR(31,0,31), - COLOR(0,31,31), - COLOR(31,31,31) -}; - -// Random -------------------------------------------------------- -using Random = effolkronium::random_static; - - - -// The ball ------------------------------------------------------ -typedef struct BALL{ - int row; - int col; - int size; - int rdel; - int cdel; - u16 color; -} BALL; - -BALL ball; -BALL old_ball; - -void initialize_ball() { - ball.row = 10; - ball.col= 10; - ball.size = 5; - ball.rdel= 1; - ball.cdel = 2; - ball.color = COLOR(0,0,0); //COLOR(31,31,31); -} - - - - - -// Drawing functions -------------------------------------------- -void setPixel(int row, int col, u16 color) { - VRAM_A[OFFSET(row, col, SCREENWIDTH)] = color; -} +FirstSketch first_sketch; +SecondSketch second_sketch; +WithSprites with_sprites; +PicoPalette pico_palette; -void drawRect(int row, int col, int width, int height, u16 color) { - int r, c; - for (c=col; c= 0 && b >= 0 && c >= 0) || (a <= 0 && b <= 0 && c <= 0)) { - setPixel(x, y, color); - } - } - } - } -} - -void drawCircleFilled(int center_y, int center_x, int radius, u16 color) { - int x = 0; - int y = radius; - int d = 1 - radius; - - while (x <= y) { - for (int i = center_x - x; i <= center_x + x; i++) { - setPixel(i, center_y + y, color); // Upper half - setPixel(i, center_y - y, color); // Lower half - } - for (int i = center_x - y; i <= center_x + y; i++) { - setPixel(i, center_y + x, color); // Right half - setPixel(i, center_y - x, color); // Left half - } - - x++; - - if (d < 0) { - d += 2 * x + 1; - } else { - y--; - d += 2 * (x - y) + 1; - } - } -} - - - - -// Main routines ------------------------------------------------ -void update() { - old_ball = ball; - - // move ball - ball.row += ball.rdel; - ball.col+= ball.cdel; - - // check for collisions with the sides of the screen - if (ball.row + ball.size > SCREENHEIGHT) { - ball.row = SCREENHEIGHT - ball.size; - ball.rdel *= -1; - } - if (ball.col + ball.size > SCREENWIDTH) { - ball.col = SCREENWIDTH- ball.size; - ball.cdel *= -1; - } - if (ball.row < 0) { - ball.row = 0; - ball.rdel *= -1; - } - if (ball.col< 0) { - ball.col = 0; - ball.cdel *= -1; - } -} - -void draw() { - // slightly erase everything - for (int i=0; i<100; i++) { - int randomPixel = Random::get(0, SCREENHEIGHT*SCREENWIDTH); - int randomColor = Random::get(0, 9); - VRAM_A[randomPixel] = palette[randomColor]; - // VRAM_A[randomPixel] = COLOR(0,0,0); - } - - // erase the ball - // drawRect(old_ball.row, old_ball.col, old_ball.size, old_ball.size, 0); - - // draw it in its new position - int randomRectColor = Random::get(0, 9); - drawRect(ball.row, ball.col, ball.size, ball.size, palette[randomRectColor]); - drawRect(ball.row, ball.col, ball.size, ball.size, COLOR(0,0,0)); +Scene* scenes[] = { + &first_sketch, + &second_sketch, + &with_sprites, + &pico_palette +}; - int randomColor = Random::get(0, 9); - // drawCircleFilled(SCREENWIDTH/2, SCREENHEIGHT/2, 20, palette[randomColor]); - drawCircleFilled(SCREENWIDTH/2, SCREENHEIGHT/2, 20, COLOR(0,0,0)); -} +int currentSceneIndex = 3; int main(void) { - // Set the main diplay to frame buffer mode 0 (FB0). - // In FB0 VRAM A is drawn to the screen. - REG_DISPCNT_MAIN = MODE_FB0; - - // Enable VRAM A - VRAM_A_CR = VRAM_ENABLE; - - initialize_ball(); + Scene* currentScene = scenes[currentSceneIndex]; + currentScene->setup(); // main loop while(1) { - update(); - // waitForVblank(); - draw(); + scanKeys(); + int keys = keysDown(); + if (keys & KEY_UP) { + currentSceneIndex = (currentSceneIndex + 1) % 4; + currentScene = scenes[currentSceneIndex]; + currentScene->setup(); + } else if (keys & KEY_DOWN) { + currentSceneIndex = (currentSceneIndex - 1 + 4) % 4; + currentScene = scenes[currentSceneIndex]; + currentScene->setup(); + } + + currentScene->update(); + currentScene->draw(); } return 0; diff --git a/nds_framebuffer_bitmaps/source/scene.h b/nds_framebuffer_bitmaps/source/scene.h new file mode 100644 index 0000000..01df3a6 --- /dev/null +++ b/nds_framebuffer_bitmaps/source/scene.h @@ -0,0 +1,13 @@ +#ifndef SCENE_H + +#define SCENE_H + + +class Scene { + public: + virtual void setup(); + virtual void update(); + virtual void draw(); +}; + +#endif \ No newline at end of file diff --git a/nds_framebuffer_bitmaps/source/screen_utils.h b/nds_framebuffer_bitmaps/source/screen_utils.h index 7086864..d1cf7d7 100644 --- a/nds_framebuffer_bitmaps/source/screen_utils.h +++ b/nds_framebuffer_bitmaps/source/screen_utils.h @@ -1,3 +1,10 @@ +#include + +#ifndef SCREEN_UTILS_H + +#define SCREEN_UTILS_H + + // Screen stuff ------------------------------------------------- // typedef volatile unsigned int vu32; typedef unsigned short u16; @@ -14,6 +21,7 @@ typedef volatile unsigned char vu8; // COLOR uses numbers from (0-31) for each of the RGB components #define COLOR(r,g,b) ((r) | (g)<<5 | (b)<<10) +#define RGB(r,g,b) ((r / 8) | (g / 8)<<5 | (b / 8)<<10) #define HSL(h,s,l) (COLOR(0,0,0) | (h)<<10 | (s)<<5 | (l)) #define OFFSET(r,c,w) ((r)*(w)+(c)) @@ -21,7 +29,96 @@ typedef volatile unsigned char vu8; #define SCREENHEIGHT (192) -void waitForVblank() { - while (SCANLINECOUNTER > SCREENHEIGHT); - while (SCANLINECOUNTER < SCREENHEIGHT); +// void waitForVblank() { +// while (SCANLINECOUNTER > SCREENHEIGHT); +// while (SCANLINECOUNTER < SCREENHEIGHT); +// } + + + +// Drawing functions -------------------------------------------- +static void setPixel(int row, int col, u16 color) { + VRAM_A[OFFSET(row, col, SCREENWIDTH)] = color; +} + + +static void rect(int row, int col, int width, int height, u16 color) { + int r, c; + for (c=col; c= 0 && b >= 0 && c >= 0) || (a <= 0 && b <= 0 && c <= 0)) { + setPixel(x, y, color); + } + } + } + } +} + +static void drawCircleFilled(int center_y, int center_x, int radius, u16 color) { + int x = 0; + int y = radius; + int d = 1 - radius; + + while (x <= y) { + for (int i = center_x - x; i <= center_x + x; i++) { + setPixel(i, center_y + y, color); // Upper half + setPixel(i, center_y - y, color); // Lower half + } + + for (int i = center_x - y; i <= center_x + y; i++) { + setPixel(i, center_y + x, color); // Right half + setPixel(i, center_y - x, color); // Left half + } + + x++; + + if (d < 0) { + d += 2 * x + 1; + } else { + y--; + d += 2 * (x - y) + 1; + } + } +} + +#endif