commit 39513a07b83152eed201db8fe009710a63059fe6 Author: iProgramMC Date: Sun May 7 18:36:06 2023 +0300 * Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..99d7e44 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +keep/* \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..91f29a1 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018-2019 iProgramInCpp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e244412 --- /dev/null +++ b/Makefile @@ -0,0 +1,140 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +.SECONDARY: + +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 +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(shell basename $(CURDIR)) +BUILD := build +SOURCES := source +DATA := +INCLUDES := include +GRAPHICS := data + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -mthumb -mthumb-interwork + +CFLAGS := -g -Wall -O2\ + -march=armv5te -mtune=arm946e-s -fomit-frame-pointer\ + -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM9 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=c++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lnds9 + + +#--------------------------------------------------------------------------------- +# 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)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) + +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)/*.*))) +PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(PNGFILES:.png=.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) + +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds $(TARGET).ds.gba + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).nds : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) + +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + + +#--------------------------------------------------------------------------------- +%.s %.h : %.png %.grit +#--------------------------------------------------------------------------------- + grit $< -fts -o$* + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/OLC_Engine3D_NDS.nds b/OLC_Engine3D_NDS.nds new file mode 100644 index 0000000..ac5c71e Binary files /dev/null and b/OLC_Engine3D_NDS.nds differ diff --git a/OLC_PlatformGameNDS.nds b/OLC_PlatformGameNDS.nds new file mode 100644 index 0000000..e11a092 Binary files /dev/null and b/OLC_PlatformGameNDS.nds differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a1bc45 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# DSGameEngine +A DS game engine based off libnds with frame buffer capabilities for the top screen. + +It includes basic image drawing functions with transparency and flipping, and basic rectangle drawing. + +The graphics work is all done in software, only that the CPU will copy the framebuffer data to the GPU of the Nintendo DS. + +It's quite inefficient, but who needs backgrounds and sprites when you can have this? + + +This repo will also have examples of programs written based off it. + +The platform game contains sprites from New Super Mario Bros. for the Nintendo DS. I won't provide them here for legal reasons. +The 3D engine doesn't contain any other things. + +You need devkitPro (namely devkitARM) to build. diff --git a/ds_game_engine.h b/ds_game_engine.h new file mode 100644 index 0000000..f6287cd --- /dev/null +++ b/ds_game_engine.h @@ -0,0 +1,362 @@ +#ifndef DS_GAME_ENGINE_INCL +#define DS_GAME_ENGINE_INCL + +#define WHITE 0xFFFF +#define BLACK 0x0000 +#define SKY 0xEEEF +#define BLUE 0xFC00 +#define MAGENTA 0xFC1F +#define CYAN 0xFFE0 + + +#include + +/* +int round(float f){ + float decpt = f - (int)f; + if(decpt < 0.5f){ + return (int)f; + }else{ + return (int)f+1; + } +}*/ + +short screenbuffer_maindisplay[49152]; +short screen_width = 256; +short screen_height = 192; + +uint32 input_keys = 0; +uint32 input_keysUp = 0; +uint32 input_keysDown = 0; +uint32 input_keysHeld = 0; + +touchPosition touch; +PrintConsole bottomScreen; + +bool get_key_state(uint32 button){ + uint32 s = input_keys & button; + if(s){return true;}else{return false;} +} +bool get_key_down_state(uint32 button){ + uint32 s = input_keysDown & button; + if(s){return true;}else{return false;} +} +bool get_key_up_state(uint32 button){ + uint32 s = input_keysUp & button; + if(s){return true;}else{return false;} +} +bool get_key_held_state(uint32 button){ + uint32 s = input_keysHeld & button; + if(s){return true;}else{return false;} +} + +void push_frame(){ + dmaCopy(&screenbuffer_maindisplay, BG_GFX, 49152*2); +} + +void clear_screenbuffer(short colour){ + for(int x = 0; x < 49152; x+=1){ + screenbuffer_maindisplay[x] = colour; + } +} + +void fill_rectangle(short colour, int w, int h, int dx, int dy){ + for(int y = 0; y < h; y++){ + for(int x = 0; x < w; x++){ + if((x+dx) >= 0 && (x+dx) < 256 && (y+dy) >= 0 && (y+dy) < 192){ + screenbuffer_maindisplay[(dy+y)*screen_width+(x+dx)] = colour; + } + } + } +} + +void plot_pixel (int x, int y, short colour){ + + if((x) >= 0 && (x) < 256 && (y) >= 0 && (y) < 192){ + screenbuffer_maindisplay[y*screen_width+x] = colour; + } +} + +void draw_line (int x1, int y1, int x2, int y2, short col){ + int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i; + dx = x2 - x1; dy = y2 - y1; + dx1 = abs(dx); dy1 = abs(dy); + px = 2 * dy1 - dx1; py = 2 * dx1 - dy1; + if (dy1 <= dx1) + { + if (dx >= 0) + { x = x1; y = y1; xe = x2; } + else + { x = x2; y = y2; xe = x1;} + + plot_pixel(x, y, col); + + for (i = 0; x0 && dy>0)) y = y + 1; else y = y - 1; + px = px + 2 * (dy1 - dx1); + } + plot_pixel(x, y, col); + } + } + else + { + if (dy >= 0) + { x = x1; y = y1; ye = y2; } + else + { x = x2; y = y2; ye = y1; } + + plot_pixel(x, y, col); + + for (i = 0; y0 && dy>0)) x = x + 1; else x = x - 1; + py = py + 2 * (dx1 - dy1); + } + plot_pixel(x, y, col); + } + } +} + +void draw_triangle (int x1, int y1, int x2, int y2, int x3, int y3, short colour){ + draw_line (x1, y1, x2, y2, colour); + draw_line (x1, y1, x3, y3, colour); + draw_line (x3, y3, x2, y2, colour); +} + +void fill_triangle (int x1, int y1, int x2, int y2, int x3, int y3, short col){ + /* Ripped from OneLoneCoder/ConsoleGameEngine */ + int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i; + dx = x2 - x1; dy = y2 - y1; + dx1 = abs(dx); dy1 = abs(dy); + px = 2 * dy1 - dx1; py = 2 * dx1 - dy1; + if (dy1 <= dx1) + { + if (dx >= 0) + { x = x1; y = y1; xe = x2; } + else + { x = x2; y = y2; xe = x1;} + + plot_pixel(x, y, col); + draw_line(x, y, x3, y3, col); + + for (i = 0; x0 && dy>0)) y = y + 1; else y = y - 1; + px = px + 2 * (dy1 - dx1); + } + plot_pixel(x, y, col); + draw_line(x, y, x3, y3, col); + } + } + else + { + if (dy >= 0) + { x = x1; y = y1; ye = y2; } + else + { x = x2; y = y2; ye = y1; } + + plot_pixel(x, y, col); + draw_line(x, y, x3, y3, col); + + for (i = 0; y0 && dy>0)) x = x + 1; else x = x - 1; + py = py + 2 * (dx1 - dy1); + } + plot_pixel(x, y, col); + draw_line(x, y, x3, y3, col); + } + } +} + +void draw_image_sizable(short* image, int w, int h, int dx, int dy, int dw, int dh){ + /*float pixel_width = dw / w; + float pixel_height= dh / h; + + for(int y = 0; y < dh; y++){ + for(int x = 0; x < dw; x++){ + if((x+dx) >= 0 && (x+dx) < 256 && (y+dy) >= 0 && (y+dy) < 192){ + int src_y = round(y * pixel_height); + int src_x = round(x * pixel_width); + screenbuffer_maindisplay[(dy+y)*screen_width+(x+dx)] = image[(src_y*w+src_x)]; + } + } + }*/ + + int w2 = dw, w1 = w, h2 = dh, h1 = h; + + // EDIT: added +1 to account for an early rounding problem + int x_ratio = (int)((w1<<16)/w2) +1; + int y_ratio = (int)((h1<<16)/h2) +1; + + int x2, y2 ; + for (int i=0;i>16) ; + y2 = ((i*y_ratio)>>16) ; + if((j+dx) >= 0 && (j+dx) < 256 && (i+dy) >= 0 && (i+dy) < 192){ + screenbuffer_maindisplay[(i+dy)*screen_width+(j+dx)] = image[(y2*w1)+x2] ; + } + } + } +} + +void draw_image(short* image, int w, int h, int dx, int dy){ + for(int y = 0; y < h; y++){ + for(int x = 0; x < w; x++){ + if((x+dx) >= 0 && (x+dx) < 256 && (y+dy) >= 0 && (y+dy) < 192){ + if(image[y*w+x] == -993){}else{screenbuffer_maindisplay[(dy+y)*screen_width+(x+dx)] = image[y*w+x];} + } + } + } +} + +void draw_image_wsr(short* image, int w, int h, int dx, int dy, int sx, int sy){ + for(int y = 0; y < h; y++){ + for(int x = 0; x < w; x++){ + if((x+dx) >= 0 && (x+dx) < 256 && (y+dy) >= 0 && (y+dy) < 192){ + if(image[(sy+y)*w+(sx+x)] == -993){}else{screenbuffer_maindisplay[(dy+y)*screen_width+(x+dx)] = image[(sy+y)*w+(sx+x)];} + } + } + } +} + +void draw_image_flipped_v(short* image, int w, int h, int dx, int dy){ + for(int y = 0; y < h; y++){ + for(int x = 0; x < w; x++){ + if((x+dx) >= 0 && (x+dx) < 256 && (y+dy) >= 0 && (y+dy) < 192){ + if(image[(h-y-1)*w+x] == -993){}else{screenbuffer_maindisplay[(dy+y)*screen_width+(x+dx)] = image[(h-y-1)*w+x];} + } + } + } +} +void draw_image_flipped_hv(short* image, int w, int h, int dx, int dy){ + for(int y = 0; y < h; y++){ + for(int x = 0; x < w; x++){ + if((x+dx) >= 0 && (x+dx) < 256 && (y+dy) >= 0 && (y+dy) < 192){ + if(image[(h-y)*w+(w-x-1)] == -993){}else{screenbuffer_maindisplay[(dy+y)*screen_width+(x+dx)] = image[(h-y)*w+(w-x-1)];} + } + } + } +} +void draw_image_flipped_h(short* image, int w, int h, int dx, int dy){ + for(int y = 0; y < h; y++){ + for(int x = 0; x < w; x++){ + if((x+dx) >= 0 && (x+dx) < 256 && (y+dy) >= 0 && (y+dy) < 192){ + if(image[y*w+(w-x-1)] == -993){}else{screenbuffer_maindisplay[(dy+y)*screen_width+(x+dx)] = image[y*w+(w-x-1)];} + } + } + } +} + +void OnUserCreate(); +void OnUserUpdate(); + +void make_btm_screen() {consoleSelect(&bottomScreen);} +void printchar(char x, char y, char c) { printf("\x1b[%d;%dH%c", y, x, c); } + +//--------------------------------------------------------------------------------- +int main(void) { +//--------------------------------------------------------------------------------- + + + + videoSetMode(MODE_5_2D); + videoSetModeSub(MODE_0_2D); + + vramSetBankA(VRAM_A_MAIN_BG); + vramSetBankC(VRAM_C_SUB_BG); + + bgInit(2, BgType_Bmp16, BgSize_B16_256x256, 0,0); + + //consoleInit(&topScreen, 3,BgType_Text4bpp, BgSize_T_256x256, 31, 0, true, true); + consoleInit(&bottomScreen, 3,BgType_Text4bpp, BgSize_T_256x256, 31, 0, false, true); + + make_btm_screen(); + + OnUserCreate(); + + clear_screenbuffer(0xEEEE); + + while(1) { + touchRead(&touch); + scanKeys(); + + input_keys = keysCurrent(); + input_keysUp = keysUp(); + input_keysDown = keysDown(); + input_keysHeld = keysHeld(); + + OnUserUpdate(); + swiWaitForVBlank(); + } + + return 0; +} + + + +/*int dx = x2 - x1; + int dy = y2 - y1; + + if (dx >= dy){ + float y = 0.0f; + if(x1 < x2){ + for (int x = x1; x <= x2; x++) { + y = y1 + dy * (x - x1) / dx; + plot_pixel(x, y, colour); + } + }else{ + for (int x = x2; x <= x1; x++) { + y = y1 + dy * (x - x1) / dx; + plot_pixel(x, y, colour); + } + } + }else{ + float x = 0.0f; + if(dx == 0){ + if(y1 < y2){ + for (int y = y1; y <= y2; y++) { + plot_pixel(x1, y, colour); + } + }else{ + for (int y = y2; y <= y1; y++) { + plot_pixel(x2, y, colour); + } + } + }else{ + if(y1 < y2){ + for (int y = y1; y <= y2; y++) { + x = x1 + dx * (y - y1) / dy; + plot_pixel(x, y, colour); + } + }else{ + for (int y = y2; y <= y1; y++) { + x = x1 + dx * (y - y1) / dy; + plot_pixel(x, y, colour); + } + } + } + }*/ +#endif diff --git a/ds_olcEngine3D.cpp b/ds_olcEngine3D.cpp new file mode 100644 index 0000000..b084803 --- /dev/null +++ b/ds_olcEngine3D.cpp @@ -0,0 +1,186 @@ +/*--------------------------------------------------------------------------------- + + Simple console print demo which prints to bottom screen + and also has a frame buffer for the top screen to which + you can draw stuff + -- iProgramMC - Graphics Engine + -- dovoto - Console bottom screen print + +---------------------------------------------------------------------------------*/ +#include +#include +#include + +#include "block.h" +#include "brick.h" +#include "coin.h" +#include "dirt.h" +#include "door.h" +#include "ground.h" +#include "mariojump.h" +#include "mariostill.h" +#include "question.h" +#include "usedblock.h" + +#include +#include + +#include "ds_game_engine.h" + +struct vec3d +{ + float x, y, z; +}; + +struct triangle +{ + vec3d p[3]; +}; + +struct mesh +{ + std::vector tris; +}; + +struct mat4x4 +{ + float m[4][4] = {0}; +}; + +mesh meshCube; +mat4x4 matProj; + +float fTheta; + +void MultiplyMatrixVector (vec3d &i, vec3d &o, mat4x4 &m){ + + o.x = i.x * m.m[0][0] + i.y * m.m[1][0] + i.z * m.m[2][0] + m.m[3][0]; + o.y = i.x * m.m[0][1] + i.y * m.m[1][1] + i.z * m.m[2][1] + m.m[3][1]; + o.z = i.x * m.m[0][2] + i.y * m.m[1][2] + i.z * m.m[2][2] + m.m[3][2]; + float w = i.x * m.m[0][3] + i.y * m.m[1][3] + i.z * m.m[2][3] + m.m[3][3]; + + if (w != 0.0f) + { + o.x /= w; o.y /= w; o.z /= w; + } +} + +int ScreenWidth() {return 256;} +int ScreenHeight(){return 192;} + + +void OnUserCreate() +{ + + meshCube.tris = { + + // SOUTH + { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f }, + + // EAST + { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f }, + + // NORTH + { 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f }, + { 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f }, + + // WEST + { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, + + // TOP + { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }, + { 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f }, + + // BOTTOM + { 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f }, + { 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }, + + }; + + + // Projection Matrix + float fNear = 0.1f; + float fFar = 1000.0f; + float fFov = 90.0f; + float fAspectRatio = (float)ScreenHeight() / (float)ScreenWidth(); + float fFovRad = 1.0f / tanf(fFov * 0.5f / 180.0f * 3.14159f); + + matProj.m[0][0] = fAspectRatio * fFovRad; + matProj.m[1][1] = fFovRad; + matProj.m[2][2] = fFar / (fFar - fNear); + matProj.m[3][2] = (-fFar * fNear) / (fFar - fNear); + matProj.m[2][3] = 1.0f; + matProj.m[3][3] = 0.0f; + //iprintf("\n\n\tGraphics Engine\n\tCoded by iProgramMC\n\tMore modern-like\n\tDo whatever you want!"); +} + +void OnUserUpdate() +{ + clear_screenbuffer(BLACK); + + mat4x4 matRotX, matRotZ; + fTheta += 0.01f; + + + matRotZ.m[0][0] = cosf(fTheta); + matRotZ.m[0][1] = sinf(fTheta); + matRotZ.m[1][0] = -sinf(fTheta); + matRotZ.m[1][1] = cosf(fTheta); + matRotZ.m[2][2] = 1; + matRotZ.m[3][3] = 1; + + // Rotation X + matRotX.m[0][0] = 1; + matRotX.m[1][1] = cosf(fTheta * 0.5f); + matRotX.m[1][2] = sinf(fTheta * 0.5f); + matRotX.m[2][1] = -sinf(fTheta * 0.5f); + matRotX.m[2][2] = cosf(fTheta * 0.5f); + matRotX.m[3][3] = 1; + + for(auto tri : meshCube.tris){ + + triangle triProjected, triTranslated, triRotatedZ, triRotatedZX; + + // Rotate in Z-Axis + MultiplyMatrixVector(tri.p[0], triRotatedZ.p[0], matRotZ); + MultiplyMatrixVector(tri.p[1], triRotatedZ.p[1], matRotZ); + MultiplyMatrixVector(tri.p[2], triRotatedZ.p[2], matRotZ); + + // Rotate in X-Axis + MultiplyMatrixVector(triRotatedZ.p[0], triRotatedZX.p[0], matRotX); + MultiplyMatrixVector(triRotatedZ.p[1], triRotatedZX.p[1], matRotX); + MultiplyMatrixVector(triRotatedZ.p[2], triRotatedZX.p[2], matRotX); + + // Offset into the screen + triTranslated = triRotatedZX; + triTranslated.p[0].z = triRotatedZX.p[0].z + 3.0f; + triTranslated.p[1].z = triRotatedZX.p[1].z + 3.0f; + triTranslated.p[2].z = triRotatedZX.p[2].z + 3.0f; + + // Project triangles from 3D --> 2D + MultiplyMatrixVector(triTranslated.p[0], triProjected.p[0], matProj); + MultiplyMatrixVector(triTranslated.p[1], triProjected.p[1], matProj); + MultiplyMatrixVector(triTranslated.p[2], triProjected.p[2], matProj); + + // Scale into view + triProjected.p[0].x += 1.0f; triProjected.p[0].y += 1.0f; + triProjected.p[1].x += 1.0f; triProjected.p[1].y += 1.0f; + triProjected.p[2].x += 1.0f; triProjected.p[2].y += 1.0f; + triProjected.p[0].x *= 0.5f * (float)ScreenWidth(); + triProjected.p[0].y *= 0.5f * (float)ScreenHeight(); + triProjected.p[1].x *= 0.5f * (float)ScreenWidth(); + triProjected.p[1].y *= 0.5f * (float)ScreenHeight(); + triProjected.p[2].x *= 0.5f * (float)ScreenWidth(); + triProjected.p[2].y *= 0.5f * (float)ScreenHeight(); + + // Rasterize triangle + draw_triangle(triProjected.p[0].x, triProjected.p[0].y, + triProjected.p[1].x, triProjected.p[1].y, + triProjected.p[2].x, triProjected.p[2].y, WHITE); + } + + push_frame(); +} \ No newline at end of file diff --git a/ds_olc_platformer.c b/ds_olc_platformer.c new file mode 100644 index 0000000..bdbb7bc --- /dev/null +++ b/ds_olc_platformer.c @@ -0,0 +1,298 @@ +/*--------------------------------------------------------------------------------- + + Simple console print demo which prints to bottom screen + and also has a frame buffer for the top screen to which + you can draw stuff + -- iProgramInCpp - Graphics Engine + -- dovoto - Console bottom screen print + +---------------------------------------------------------------------------------*/ +#include +#include +#include + +#include "block.h" +#include "brick.h" +#include "coin.h" +#include "dirt.h" +#include "door.h" +#include "ground.h" +#include "mariojump.h" +#include "mariostill.h" +#include "question.h" +#include "usedblock.h" + + +#include "ds_game_engine.h" + + +char sLevel[] = "................................................................" + "................................................................" + ".......ooooo...................................................." + "........ooo....................................................." + ".......................########................................." + ".....BB?BBBB?BB.......###..............#.#......................" + "....................###................#.#......................" + "...................####........................................." + "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG.##############.....########" + "...................................#.#...............###........" + "........................############.#............###..........." + "........................#............#.........###.............." + "........................#.############......###................." + "........................#................###...................." + "........................#################......................." + "................................................................"; +int nLevelWidth; +int nLevelHeight; + +const char TileSize = 8; //8px wide + +short block_image[256]; +short brick_image[256]; +short coin_image[256]; +short dirt_image[256]; +short door_image[256]; +short ground_image[256]; +short question_image[256]; +short mariojump_image[384]; +short mariostill_image[384]; +short usedblock_image[256]; + +bool bPlayerOnGround = false; + +int nDirModX = 0, nDirModY = 0; + +float fCameraPosX = 0.0f, fCameraPosY = 0.0f; +float fPlayerPosX = 0.0f, fPlayerPosY = 0.0f; +float fPlayerVelX = 0.0f, fPlayerVelY = 0.0f; + +unsigned short rng; + +short sky_colour = 0xEEEF; + +uint32 global_timer = 0; + +char ticks = 0; + +unsigned short rng_function(unsigned short input){ + if(input == 0x560A) input=0; + unsigned short S0 = (unsigned char)input<<8; + S0 = S0 ^ input; + input = ((S0 & 0xFF) << 8) | ((S0 & 0xFF00) >> 8); + S0 = ((unsigned char)S0 << 1) ^ input; + short S1 = (S0 >> 1) ^ 0xFF80; + if((S0 & 1) == 0){ + if(S1 == 0xAA55){input = 0;}else{input=S1 ^ 0x1FF4;} + }else{ + input = S1 ^ 0x1FF4; + } + return (unsigned short)input; +} + +void rng_update() { + rng = rng_function(global_timer); +} + +char GetTile(int x, int y){ + if(x >= 0 && x < nLevelWidth && y >= 0 && y < nLevelHeight){ + return sLevel[y*nLevelWidth+x]; + }else{ + return ' '; + } +} + +void SetTile(char c, int x, int y){ + if(x >= 0 && x < nLevelWidth && y >= 0 && y < nLevelHeight){ + sLevel[y*nLevelWidth+x] = c; + } +} + +void make_btm_screen() {consoleSelect(&bottomScreen);} +void printchar(char x, char y, char c) { printf("\x1b[%d;%dH%c", y, x, c); } + +void OnUserCreate() +{ + nLevelWidth = 64; + nLevelHeight = 16; + + decompress(blockBitmap, &block_image, LZ77); + decompress(brickBitmap, &brick_image, LZ77); + decompress(coinBitmap, &coin_image, LZ77); + decompress(dirtBitmap, &dirt_image, LZ77); + decompress(doorBitmap, &door_image, LZ77); + decompress(groundBitmap, &ground_image, LZ77); + decompress(questionBitmap, &question_image, LZ77); + decompress(usedblockBitmap, &usedblock_image, LZ77); + decompress(mariostillBitmap, &mariostill_image, LZ77); + decompress(mariojumpBitmap, &mariojump_image, LZ77); + iprintf("\n\n\tGraphics Engine\n\tCoded by iProgramInCpp\n\tMore modern-like\n\tDo whatever you want!"); +} + +void OnUserUpdate() +{ + clear_screenbuffer(sky_colour); + + + //fPlayerVelX = 0.0f; + //fPlayerVelY = 0.0f; + + //Handle + if(get_key_state(KEY_UP)){ + fPlayerVelY = -6.0f; + } + if(get_key_state(KEY_DOWN)){ + fPlayerVelY = 6.0f; + } + if(get_key_state(KEY_LEFT)){ + nDirModY = 1; + fPlayerVelX += (bPlayerOnGround ?-6.0f :-4.0f) * 0.01664f; + } + if(get_key_state(KEY_RIGHT)){ + nDirModY = 0; + fPlayerVelX += (bPlayerOnGround ? 6.0f : 4.0f) * 0.01664f; + } + if(get_key_down_state(KEY_B)){ + if(bPlayerOnGround){ + fPlayerVelY = -12.0f; + nDirModX = 1; + } + } + + fPlayerVelY += 20.0f * 0.01664f; + + if(bPlayerOnGround){ + fPlayerVelX += -3.0f * fPlayerVelX * 0.01664f; + if(fabs(fPlayerVelX) < 0.01f){ + fPlayerVelX = 0.0f; + } + } + + if(fPlayerVelX > 10.0f) fPlayerVelX = 10.0f; + if(fPlayerVelX < -10.0f) fPlayerVelX = -10.0f; + if(fPlayerVelY > 100.0f) fPlayerVelY = 100.0f; + if(fPlayerVelY < -100.0f) fPlayerVelY = -100.0f; + + float fNewPlayerPosX = fPlayerPosX + fPlayerVelX * 0.01664f; + float fNewPlayerPosY = fPlayerPosY + fPlayerVelY * 0.01664f; + + if(GetTile(fNewPlayerPosX + 0.0f, fNewPlayerPosY + 0.0f) == 'o') + SetTile('.', fNewPlayerPosX + 0.0f, fNewPlayerPosY + 0.0f); + if(GetTile(fNewPlayerPosX + 0.0f, fNewPlayerPosY + 1.0f) == 'o') + SetTile('.', fNewPlayerPosX + 0.0f, fNewPlayerPosY + 1.0f); + if(GetTile(fNewPlayerPosX + 1.0f, fNewPlayerPosY + 0.0f) == 'o') + SetTile('.', fNewPlayerPosX + 1.0f, fNewPlayerPosY + 0.0f); + if(GetTile(fNewPlayerPosX + 1.0f, fNewPlayerPosY + 1.0f) == 'o') + SetTile('.', fNewPlayerPosX + 1.0f, fNewPlayerPosY + 1.0f); + + + //Collision + if(fPlayerVelX <= 0){ + if(GetTile(fNewPlayerPosX + 0.0f, fPlayerPosY + 0.0f) != '.' || + GetTile(fNewPlayerPosX + 0.0f, fPlayerPosY + 0.9f) != '.'){ + fNewPlayerPosX = (int)fNewPlayerPosX + 1; + fPlayerVelX = 0; + } + }else{ + if(GetTile(fNewPlayerPosX + 1.0f, fPlayerPosY + 0.0f) != '.' || + GetTile(fNewPlayerPosX + 1.0f, fPlayerPosY + 0.9f) != '.'){ + fNewPlayerPosX = (int)fNewPlayerPosX; + fPlayerVelX = 0; + } + } + + bPlayerOnGround = false; + if(fPlayerVelY <= 0){ + if(GetTile(fNewPlayerPosX + 0.0f, fNewPlayerPosY) != '.' || + GetTile(fNewPlayerPosX + 0.9f, fNewPlayerPosY) != '.'){ + fNewPlayerPosY = (int)fNewPlayerPosY + 1; + fPlayerVelY = 0; + } + }else{ + if(GetTile(fNewPlayerPosX + 0.0f, fNewPlayerPosY+1) != '.' || + GetTile(fNewPlayerPosX + 0.9f, fNewPlayerPosY+1) != '.'){ + fNewPlayerPosY = (int)fNewPlayerPosY; + fPlayerVelY = 0; + bPlayerOnGround = true; + nDirModX = 0; + } + } + //nDirModX = !bPlayerOnGround; + + fPlayerPosX = fNewPlayerPosX; + fPlayerPosY = fNewPlayerPosY; + + fCameraPosX = fPlayerPosX; + fCameraPosY = fPlayerPosY; + + //Draw Level + int nTileWidth = 16; + int nTileHeight = 16; + int nVisibleTilesX = SCREEN_WIDTH / nTileWidth; + int nVisibleTilesY = SCREEN_HEIGHT/nTileHeight; + + float fOffsetX = fCameraPosX - (float)nVisibleTilesX / 2.0f; + float fOffsetY = fCameraPosY - (float)nVisibleTilesY / 2.0f; + + if(fOffsetX <= 0.0f) fOffsetX = 0.0f; + if(fOffsetY <= 0.0f) fOffsetY = 0.0f; + if(fOffsetX > (float)(nLevelWidth - nVisibleTilesX)) fOffsetX = nLevelWidth - nVisibleTilesX; + if(fOffsetY > (float)(nLevelHeight- nVisibleTilesY)) fOffsetY = nLevelHeight- nVisibleTilesY; + + float fTileOffsetX = (fOffsetX - (int)fOffsetX) * nTileWidth; + float fTileOffsetY = (fOffsetY - (int)fOffsetY) * nTileHeight; + + + for(int x = -1; x < nVisibleTilesX+1; x++){ + for(int y = -1; y < nVisibleTilesY+1; y++){ + char sTileID = GetTile(x + fOffsetX, y+fOffsetY); + + switch(sTileID){ + case '.': + break; + case '#': + draw_image(block_image, nTileWidth, nTileHeight, x*nTileWidth-fTileOffsetX,y*nTileHeight-fTileOffsetY); + break; + case 'o': + draw_image(coin_image, nTileWidth, nTileHeight, x*nTileWidth-fTileOffsetX,y*nTileHeight-fTileOffsetY); + break; + case '?': + draw_image(question_image, nTileWidth, nTileHeight, x*nTileWidth-fTileOffsetX,y*nTileHeight-fTileOffsetY); + break; + case 'B': + draw_image(brick_image, nTileWidth, nTileHeight, x*nTileWidth-fTileOffsetX,y*nTileHeight-fTileOffsetY); + break; + case 'G': + draw_image(ground_image, nTileWidth, nTileHeight, x*nTileWidth-fTileOffsetX,y*nTileHeight-fTileOffsetY); + break; + case 'D': + draw_image(dirt_image, nTileWidth, nTileHeight, x*nTileWidth-fTileOffsetX,y*nTileHeight-fTileOffsetY); + break; + case 'E': + draw_image(door_image, nTileWidth, nTileHeight, x*nTileWidth-fTileOffsetX,y*nTileHeight-fTileOffsetY); + break; + case 'U': + draw_image(usedblock_image, nTileWidth, nTileHeight, x*nTileWidth-fTileOffsetX,y*nTileHeight-fTileOffsetY); + break; + default: + fill_rectangle(0x0000, nTileWidth, nTileHeight, x*nTileWidth-fTileOffsetX,y*nTileHeight-fTileOffsetY); + break; + } + } + } + + if(nDirModX){ + if(nDirModY){ + draw_image_flipped_h(mariojump_image, nTileWidth, 24, (fPlayerPosX - fOffsetX)*nTileWidth, (fPlayerPosY - fOffsetY)*nTileHeight-8); + }else{ + draw_image(mariojump_image, nTileWidth, 24, (fPlayerPosX - fOffsetX)*nTileWidth, (fPlayerPosY - fOffsetY)*nTileHeight-8); + } + }else{ + if(nDirModY){ + draw_image_flipped_h(mariostill_image, nTileWidth, 24, (fPlayerPosX - fOffsetX)*nTileWidth, (fPlayerPosY - fOffsetY)*nTileHeight-8); + }else{ + draw_image(mariostill_image, nTileWidth, 24, (fPlayerPosX - fOffsetX)*nTileWidth, (fPlayerPosY - fOffsetY)*nTileHeight-8); + } + } + + push_frame(); +} diff --git a/keep b/keep new file mode 160000 index 0000000..1295f24 --- /dev/null +++ b/keep @@ -0,0 +1 @@ +Subproject commit 1295f24e03d12a8bf80394ab5933f727ca22097c