diff --git a/Toy b/Toy index 7a15e64..6a08639 160000 --- a/Toy +++ b/Toy @@ -1 +1 @@ -Subproject commit 7a15e645a7bc38889f2ce6a784dccbf510e99859 +Subproject commit 6a086395be0d7824b4a83efddb14d457eaaf299d diff --git a/core/common.c b/core/common.c new file mode 100644 index 0000000..ddef6fc --- /dev/null +++ b/core/common.c @@ -0,0 +1,2 @@ +#include "common.h" + diff --git a/core/common.h b/core/common.h new file mode 100644 index 0000000..e1f9df0 --- /dev/null +++ b/core/common.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include + +//platform exports/imports +#if defined(__linux__) +#define CORE_API extern +#else +#define CORE_API +#endif + diff --git a/core/engine.c b/core/engine.c new file mode 100644 index 0000000..7d4196d --- /dev/null +++ b/core/engine.c @@ -0,0 +1,113 @@ +#include "engine.h" + +#include + +//errors here should be fatal +static void error(Engine* engine, char* message) { + fprintf(stderr, message); + exit(-1); +} + +//exposed functions +void initEngine(Engine* engine) { + //clear + engine->root = NULL; + engine->running = true; + + //init SDL + if (SDL_Init(0) != 0) { + error(engine, "Failed to initialize SDL2"); + } + + //init the window + engine->window = SDL_CreateWindow( + "Caption", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + engine->screenWidth, + engine->screenHeight, + SDL_WINDOW_RESIZABLE + ); + + if (engine->window == NULL) { + error(engine, "Failed to initialize the window"); + } + + //init the renderer + engine->renderer = SDL_CreateRenderer(engine->window, -1, 0); + + if (engine->renderer == NULL) { + error(engine, "Failed to initialize the renderer"); + } + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); + SDL_RenderSetLogicalSize(engine->renderer, engine->screenWidth, engine->screenHeight); +} + +void freeEngine(Engine* engine) { + SDL_DestroyRenderer(engine->renderer); + SDL_DestroyWindow(engine->window); + SDL_Quit(); + + engine->renderer = NULL; + engine->window = NULL; +} + +static void execStep(Engine* engine) { + //DEBUG: for now, just poll events + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch(event.type) { + //quit + case SDL_QUIT: { + engine->running = false; + } + break; + + //window events are handled internally + case SDL_WINDOWEVENT: { + switch(event.window.event) { + case SDL_WINDOWEVENT_RESIZED: + SDL_RenderSetLogicalSize(engine->renderer, event.window.data1, event.window.data2); + break; + } + } + break; + + //TODO: input + } + } +} + +//the heart of the engine +void execEngine(Engine* engine) { + //set up time + gettimeofday(&engine->realTime, NULL); + engine->simTime = engine->realTime; + struct timeval delta = { .tv_sec = 0, .tv_usec = 1000 * 1000 / 60 }; //60 frames per second + + while (engine->running) { + //calc the time passed + gettimeofday(&engine->realTime, NULL); + + //if not enough time has passed + if (engine->simTime.tv_sec < engine->realTime.tv_sec && engine->simTime.tv_usec < engine->realTime.tv_usec) { + //while not enough time has passed + while(engine->simTime.tv_sec < engine->realTime.tv_sec && engine->simTime.tv_usec < engine->realTime.tv_usec) { + //simulate the world + execStep(engine); + + //calc the time simulation + timeradd(&delta, &engine->simTime, &engine->simTime); + } + } + else { + SDL_Delay(10); //let the machine sleep, 10ms + } + + //render the world + SDL_SetRenderDrawColor(engine->renderer, 0, 0, 0, 255); //NOTE: This line can be disabled later + SDL_RenderClear(engine->renderer); //NOTE: This line can be disabled later + SDL_RenderPresent(engine->renderer); + } +} diff --git a/core/engine.h b/core/engine.h new file mode 100644 index 0000000..5ffa14d --- /dev/null +++ b/core/engine.h @@ -0,0 +1,30 @@ +#pragma once + +#include "common.h" +#include "engine_node.h" + +#include + +#include + +//the base engine object, which represents the state of the game +typedef struct _engine { + //engine stuff + EngineNode* root; + struct timeval simTime; + struct timeval realTime; + bool running; + + //SDL stuff + SDL_Window* window; + SDL_Renderer* renderer; + int screenWidth; + int screenHeight; +} Engine; + +//APIs for initializing the engine +CORE_API void initEngine(Engine* engine); +CORE_API void freeEngine(Engine* engine); + +CORE_API void execEngine(Engine* engine); + diff --git a/core/engine_node.c b/core/engine_node.c new file mode 100644 index 0000000..cffb571 --- /dev/null +++ b/core/engine_node.c @@ -0,0 +1,2 @@ +#include "engine_node.h" + diff --git a/core/engine_node.h b/core/engine_node.h new file mode 100644 index 0000000..496c2fb --- /dev/null +++ b/core/engine_node.h @@ -0,0 +1,23 @@ +#pragma once + +#include "common.h" + +//forward declare +typedef struct _engineNode EngineNode; +typedef struct _engine Engine; + +//the interface function +typedef void (*EngineNodeFn)(EngineNode* self, Engine* engine); + +//the node object, which forms a tree +typedef struct _engineNode { + //use Toy's memory model + void* children; + int capacity; + int count; + + EngineNodeFn onInit; + EngineNodeFn onStep; + EngineNodeFn onFree; +} EngineNode; + diff --git a/core/makefile b/core/makefile new file mode 100644 index 0000000..826525c --- /dev/null +++ b/core/makefile @@ -0,0 +1,43 @@ +CC=gcc + +IDIR+=. +CFLAGS+=$(addprefix -I,$(IDIR)) -DSDL_MAIN_HANDLED -g -Wall -W -pedantic -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable +LIBS+=-lSDL2 + +ODIR = obj +SRC = $(wildcard *.c) +OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o)) + +OUTNAME=core + +ifeq ($(findstring CYGWIN, $(shell uname)),CYGWIN) + LIBLINE =-Wl,--out-implib=$(CORE_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive + OUT=$(CORE_OUTDIR)/$(OUTNAME).dll +else ifeq ($(shell uname),Linux) +# No linux for the time being +else ifeq ($(OS),Windows_NT) + LIBLINE =-Wl,--out-implib=$(CORE_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive + OUT=$(CORE_OUTDIR)/$(OUTNAME).dll +else + @echo "Platform test failed - what platform is this?" + exit 1 +endif + +library: $(OBJ) + $(CC) -DCORE_EXPORT $(CFLAGS) -shared -o $(OUT) $(LIBLINE) $(LIBS) + +static: $(OBJ) + ar crs $(CORE_OUTDIR)/lib$(OUTNAME).a $(OBJ) $(LIBS) + +$(OBJ): | $(ODIR) + +$(ODIR): + mkdir $(ODIR) + +$(ODIR)/%.o: %.c + $(CC) -c -o $@ $< $(CFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR) diff --git a/makefile b/makefile index 49a4ac5..b2c44f2 100644 --- a/makefile +++ b/makefile @@ -1,14 +1,18 @@ export OUTDIR = out export LIBDIR = lib export TOY_OUTDIR = ../$(LIBDIR) +export CORE_OUTDIR = ../$(LIBDIR) -all: $(OUTDIR) $(LIBDIR) toy +all: $(OUTDIR) $(LIBDIR) toy core $(MAKE) -C source cp $(LIBDIR)/*.dll $(OUTDIR) toy: $(LIBDIR) $(MAKE) -C Toy/source +core: $(LIBDIR) + $(MAKE) -C core + $(OUTDIR): mkdir $(OUTDIR) diff --git a/source/main.c b/source/main.c index 917f684..e42d183 100644 --- a/source/main.c +++ b/source/main.c @@ -1,79 +1,11 @@ -//This "hello world" was borrowed from the net -//https://gist.github.com/fschr/92958222e35a823e738bb181fe045274 +#include "engine.h" -// SDL2 Hello, World! -// This should display a white screen for 2 seconds -// compile with: clang++ main.cpp -o hello_sdl2 -lSDL2 -// run with: ./hello_sdl2 -#include -#include +int main(int argc, char* argv[]) { + Engine engine = { .screenWidth = 640, .screenHeight = 480 }; -#include "lexer.h" -#include "parser.h" -#include "compiler.h" -#include "interpreter.h" + initEngine(&engine); + execEngine(&engine); + freeEngine(&engine); -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -int main(int argc, char* args[]) { - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - fprintf(stderr, "could not initialize sdl2: %s\n", SDL_GetError()); - return 1; - } - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - screenSurface = SDL_GetWindowSurface(window); - SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0xFF, 0xFF, 0xFF)); - SDL_UpdateWindowSurface(window); - - //hacked in to test linking - { - //source - char* source = "print \"Hello world!\";"; - - //test basic compilation & collation - Lexer lexer; - Parser parser; - Compiler compiler; - Interpreter interpreter; - - initLexer(&lexer, source); - initParser(&parser, &lexer); - initCompiler(&compiler); - initInterpreter(&interpreter); - - Node* node = scanParser(&parser); - - //write - writeCompiler(&compiler, node); - - //collate - int size = 0; - unsigned char* bytecode = collateCompiler(&compiler, &size); - - //run - runInterpreter(&interpreter, bytecode, size); - - //cleanup - freeNode(node); - freeParser(&parser); - freeCompiler(&compiler); - freeInterpreter(&interpreter); - } - - SDL_Delay(2000); - SDL_DestroyWindow(window); - SDL_Quit(); - return 0; + return 0; } \ No newline at end of file diff --git a/source/makefile b/source/makefile index c3746ac..e7fbc96 100644 --- a/source/makefile +++ b/source/makefile @@ -1,8 +1,8 @@ CC=gcc -IDIR+=. ../Toy/source +IDIR+=. ../Toy/source ../core CFLAGS+=$(addprefix -I,$(IDIR)) -DSDL_MAIN_HANDLED -g -Wall -W -pedantic -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable -LIBS+=-lSDL2 -ltoy +LIBS+=-lSDL2 -ltoy -lcore ODIR = obj SRC = $(wildcard *.c)