From f439ae911923ee70937592b1ee535e8e8e133808 Mon Sep 17 00:00:00 2001 From: Jonas Gunz Date: Wed, 6 Mar 2019 15:04:57 +0100 Subject: Directory updates Moved source files to ./src and exmaple and test to ./example Updated Makefile and .doxygen to use those directorys --- .doxygen | 2 +- Makefile | 39 ++--- cInput.cpp | 73 ---------- cInput.h | 58 -------- cObject.cpp | 82 ----------- cObject.h | 95 ------------- cObjectHandler.cpp | 368 ----------------------------------------------- cObjectHandler.h | 118 --------------- cRender.cpp | 380 ------------------------------------------------- cRender.h | 177 ----------------------- cWiremesh.cpp | 132 ----------------- cWiremesh.h | 104 -------------- example/test.cpp | 142 ++++++++++++++++++ example/test_old.cpp | 165 +++++++++++++++++++++ src/cInput.cpp | 73 ++++++++++ src/cInput.h | 58 ++++++++ src/cObject.cpp | 82 +++++++++++ src/cObject.h | 95 +++++++++++++ src/cObjectHandler.cpp | 368 +++++++++++++++++++++++++++++++++++++++++++++++ src/cObjectHandler.h | 118 +++++++++++++++ src/cRender.cpp | 380 +++++++++++++++++++++++++++++++++++++++++++++++++ src/cRender.h | 177 +++++++++++++++++++++++ src/cWiremesh.cpp | 132 +++++++++++++++++ src/cWiremesh.h | 104 ++++++++++++++ test.cpp | 142 ------------------ test_old.cpp | 165 --------------------- 26 files changed, 1918 insertions(+), 1911 deletions(-) delete mode 100644 cInput.cpp delete mode 100644 cInput.h delete mode 100644 cObject.cpp delete mode 100644 cObject.h delete mode 100644 cObjectHandler.cpp delete mode 100644 cObjectHandler.h delete mode 100644 cRender.cpp delete mode 100644 cRender.h delete mode 100644 cWiremesh.cpp delete mode 100644 cWiremesh.h create mode 100644 example/test.cpp create mode 100644 example/test_old.cpp create mode 100644 src/cInput.cpp create mode 100644 src/cInput.h create mode 100644 src/cObject.cpp create mode 100644 src/cObject.h create mode 100644 src/cObjectHandler.cpp create mode 100644 src/cObjectHandler.h create mode 100644 src/cRender.cpp create mode 100644 src/cRender.h create mode 100644 src/cWiremesh.cpp create mode 100644 src/cWiremesh.h delete mode 100644 test.cpp delete mode 100644 test_old.cpp diff --git a/.doxygen b/.doxygen index 529e3fa..64bccfe 100644 --- a/.doxygen +++ b/.doxygen @@ -112,7 +112,7 @@ WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- -INPUT = . +INPUT = ./src INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c \ *.cc \ diff --git a/Makefile b/Makefile index ee0f6d2..0fec7c2 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ DEBUGFLAGS = -Wall -g -std=c++11 LDFLAGS = SONAME = engine BUILDDIR = build +SOURCEDIR = src #VERSION VERSION = 0 PATCHLEVEL = 4 @@ -11,22 +12,28 @@ OUTPUT = lib$(SONAME).so.$(VERSION).$(PATCHLEVEL) OBJ = cObject.o cObjectHandler.o cRender.o cInput.o cWiremesh.o -build: genversion $(OBJ) - mkdir -p $(BUILDDIR) - mkdir -p $(BUILDDIR)/lib - mkdir -p $(BUILDDIR)/inc +build: dir genversion $(OBJ) $(CC) $(CFLAGS) -o $(BUILDDIR)/lib/$(OUTPUT) $(OBJ) $(LDFLAGS) -Wl,-soname=lib$(SONAME).so.$(VERSION) ln -sf $(OUTPUT) $(BUILDDIR)/lib/lib$(SONAME).so.$(VERSION) ln -sf $(OUTPUT) $(BUILDDIR)/lib/lib$(SONAME).so - cp c*.h $(BUILDDIR)/inc - cp version.h $(BUILDDIR)/inc + cp src/c*.h $(BUILDDIR)/inc + cp src/version.h $(BUILDDIR)/inc + +dir: + mkdir -p $(BUILDDIR) + mkdir -p $(BUILDDIR)/lib + mkdir -p $(BUILDDIR)/inc + -%.o: %.cpp +%.o: $(SOURCEDIR)/%.cpp @echo @echo Building $< @echo ============== @echo $(CC) $(CFLAGS) -c $< + +%.o: example/%.cpp + $(CC) $(CFLAGS) -I$(SOURCEDIR) -c $< all: clean build @@ -34,7 +41,7 @@ all: clean build .PHONY: clean clean: - rm -df $(OBJ) test.o version.h + rm -df $(OBJ) test.o src/version.h rm -Rdf $(BUILDDIR)/lib $(BUILDDIR)/inc $(BUILDDIR)/test doc/ run: gentest @@ -45,15 +52,15 @@ memleak: gentest genversion: @echo Building Version - @echo "//Generated by MAKEFILE. DO NOT Edit." > version.h - @echo "#pragma once" >> version.h - @echo "#define VERSION $(VERSION)" >> version.h - @echo "#define PATCHLEVEL $(PATCHLEVEL)" >> version.h - @echo "#define VERSTRING \"`git describe`\"" >> version.h - @echo "#define DATE \"`date +'%d.%m.20%y'`\"" >> version.h - @echo "#define TIME \"`date +'%H:%M:%S'`\"" >> version.h + @echo "//Generated by MAKEFILE. DO NOT Edit." > src/version.h + @echo "#pragma once" >> src/version.h + @echo "#define VERSION $(VERSION)" >> src/version.h + @echo "#define PATCHLEVEL $(PATCHLEVEL)" >> src/version.h + @echo "#define VERSTRING \"`git describe`\"" >> src/version.h + @echo "#define DATE \"`date +'%d.%m.20%y'`\"" >> src/version.h + @echo "#define TIME \"`date +'%H:%M:%S'`\"" >> src/version.h -gentest: genversion test.o $(OBJ) +gentest: build test.o mkdir -p $(BUILDDIR)/test $(CC) $(DEBUGFLAGS) -o $(BUILDDIR)/test/test test.o $(OBJ) $(LDFLAGS) diff --git a/cInput.cpp b/cInput.cpp deleted file mode 100644 index 6384c91..0000000 --- a/cInput.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "cInput.h" - -cInput::cInput() -{ - // Save original serial communication configuration for stdin - tcgetattr( STDIN_FILENO, &original); - - // Put stdin in raw mode so keys get through directly without - // requiring pressing enter. - cfmakeraw (&raw); - tcsetattr (STDIN_FILENO, TCSANOW, &raw); - - // Enable mouse tracking - write (STDOUT_FILENO, "\e[?1000h", 8); -} - -cInput::~cInput() -{ - //revert changes to console - write (STDOUT_FILENO, "\e[?1000l", 8); - tcsetattr (STDIN_FILENO, TCSANOW, &original); -} - -sInputEvent cInput::poll() -{ - sInputEvent ret; - unsigned char buff [6]; - - //setup for select - fd_set rfds; - struct timeval tv; - FD_ZERO(&rfds); - FD_SET(STDIN_FILENO, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - - ret.type = _EVENT_NULL; - - //Check for Input. return of none - if(!select(1, &rfds, NULL, NULL, &tv)) - return ret; - - read (STDIN_FILENO, &buff, 1); - if (buff[0] == 3) { - // User pressd Ctr+C - ret.type = _EVENT_TERM; - } - else if (buff[0] == '\x1B') //Escape sequence - { - read (STDIN_FILENO, &buff, 5); - if(buff[0] == '[') - { - if(buff[1] == 'M') //Mouse Event - { - ret.b = buff[2] - 32; - ret.x = buff[3] - 32 - 1; //Console sees origin at 1,1 - ret.y = buff[4] - 32 - 1; //Program at 0,0 - ret.type = _EVENT_MOUSE; - } - else //e.g. Arrow Keys - { - ret.c = buff[1]; - ret.type = _EVENT_KEY; - } - } - } - else - { - ret.type = _EVENT_CHAR; - ret.c = buff[0]; - } - return ret; -} diff --git a/cInput.h b/cInput.h deleted file mode 100644 index 00ddb7d..0000000 --- a/cInput.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef CINPUT_H_ -#define CINPUT_H_ - -#include -#include -#include -#include - -#ifdef __linux__ -#elif _WIN32 - #error "Platforn not supported" -#else - #error "Platforn not supported" -#endif - -#define _EVENT_NULL 0 -#define _EVENT_CHAR 1 -#define _EVENT_KEY 2 -#define _EVENT_MOUSE 3 -#define _EVENT_TERM 4 - -struct sInputEvent -{ - unsigned int type; - unsigned char c; - unsigned int b; - int x, y; -}; -/** -* ##cInput -* * puts STDIN in raw mode -* * activates mouse tracking -* * reverts console back to normal operation on destruction. -* Compatible with xterm compatible terminal emulators -*/ -class cInput -{ -public: - cInput(); - - ~cInput(); - - /** Reads inputevents - * returns event struct - * ### sInputEvent.type - * * _EVENT_NULL: No input recorded - * * _EVENT_CHAR: A Key was pressed, stored in .c - * * _EVENT_KEY: Escape sequence recorded, stored in .c without escape char - * * _EVENT_MOUSE: Console registered click at (.x, .y) with origin at (0,0) (top left). Mouse button stored in b. - * * _EVENT_TERM: Console registered Ctrl+C - */ - sInputEvent poll(); - -private: - struct termios original, raw; -}; - -#endif /* end of include guard: */ diff --git a/cObject.cpp b/cObject.cpp deleted file mode 100644 index 7dc194c..0000000 --- a/cObject.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "cObject.h" - -cObject::cObject(int _sx, int _sy) : pos({0,0}) , bSizeSet(false) -{ - setSize(_sx, _sy); -} - -cObject::~cObject() -{ - destruct(); -} - -sPos cObject::getPosition() -{ - return pos; -} - -void cObject::setPosition(sPos _pos) -{ - pos = _pos; -} - - -void cObject::setPosition(int _x, int _y) -{ - pos.x = _x; - pos.y = _y; -} - - -sObject cObject::getObject() -{ - return sObject{pos, wColor, cScreen, sizeX, sizeY}; -} - -//protected -cObject::cObject() : pos({0,0}) , bSizeSet(false){} - -void cObject::setSize(int _sx, int _sy) -{ - if(bSizeSet) - return; - - bBlockRender = true; //Block inherited render capabilities of parent - - sizeX = _sx; - sizeY = _sy; - - //Initialize 2D array - cScreen = (char**) malloc(sizeof *cScreen * _sx); - for (int i = 0; i < _sx; i++) - cScreen[i] = (char*)malloc(sizeof *cScreen[i] * _sy); - - wColor = (WORD**)malloc(sizeof *wColor * _sx); - for (int i = 0; i < _sx; i++) - wColor[i] = (WORD*)malloc(sizeof *wColor[i] * _sy); - - for (int i = 0; i < sizeY; i++) { - for (int o = 0; o < sizeX; o++) { - cScreen[o][i] = NULL; - wColor[o][i] = _COL_DEFAULT; - } - } - - bSizeSet = true; -} - -void cObject::destruct() -{ - if(!bSizeSet) - return; - - for (int i = 0; i < sizeX; i++) { - free(cScreen[i]); - free(wColor[i]); - } - - free(cScreen); - free(wColor); - - bSizeSet = false; -} diff --git a/cObject.h b/cObject.h deleted file mode 100644 index 50b9d18..0000000 --- a/cObject.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once -#include - -#include "cRender.h" - -#define _HIT_TOP 1 -#define _HIT_BOTTOM 2 -#define _HIT_LEFT 3 -#define _HIT_RIGHT 4 - -struct sObject -{ - sPos pos; - WORD **wColor; - char **cScreen; - int sizeX; - int sizeY; -}; - -/** cObject can be used standalone as well as inherited -* every cObject has its own framebuffer as well as position viariables to be moveable. -* cObject is used by cObjectHandler to manage all objects to be displayed. -* -* Minimal example for inheriting class -* -* -* class example : cObject -* { -* public: -* example() { setSize(10,5); } -* ~example() { destruct(); } -* }; -* -*/ -class cObject : public cRender -{ -public: - /** Sets the size to _sx x _sy - */ - cObject(int _sx, int _sy); - - virtual ~cObject(); - - /** Returns current position - */ - sPos getPosition(); - - /** Sets position to _pos - */ - void setPosition(sPos _pos); - /** Sets position by coordinates - */ - void setPosition(int _x, int _y); - - /** Returns sObject with framebuffer and current position - */ - sObject getObject(); - - /** Called by cObjecthandler if cObject is clicked - */ - virtual void onClick(sPos _pos, unsigned int _button){} - /** Called by cObjecthandler if cObject is active on keyboard input - * _pos decribes the relative position of mousepointer to origin of object - */ - virtual void onChar(unsigned char _c){} - - - /** Called by cObjectHandler if Object hits another during move operation - * return true to abort move, false to continue and allow overlap - */ - virtual bool onCollisionActive(unsigned int _hit, int _passiveObject) { return false; } - - /** Called by cObjectHandler if Object is hit by another object - * return any integer value to be identified by hitting object - */ - virtual int onCollisionPassive(unsigned int _hit) { return 0; } - - - - -protected: //For child classes - cObject(); - /** For inheriting classes: sets size of framebuffer - */ - void setSize(int _sx, int _sy); - - /** For inheriting classes: frees the framebuffer - */ - void destruct(); - -private: - //wColor, cScreen, sizeX and sizeY are inherited from cRender - sPos pos; - bool bSizeSet; -}; diff --git a/cObjectHandler.cpp b/cObjectHandler.cpp deleted file mode 100644 index 11c02e6..0000000 --- a/cObjectHandler.cpp +++ /dev/null @@ -1,368 +0,0 @@ -#include "cObjectHandler.h" - -cObjectHandler::cObjectHandler(cRender *_render, bool _enableInputMapping, bool _enableCollision) : cameraPosition ({0,0}), iActiveObject(0) -{ - render = _render; - - enableInputMapping = _enableInputMapping; - enableCollision = enableInputMapping ? _enableCollision : false; // Collision requires input mapping - - objects.push_back(NULL); //Create first Object as Catcher for Events - - buildHitmap(); -} - -int cObjectHandler::createObject(cObject *_object) -{ - objects.push_back(_object); - - buildHitmap(); - return objects.size() - 1; -} - -int cObjectHandler::moveObject(int _object, sPos _pos, int _mode) -{ - if (_object >= objects.size()) //prevent segmentation faults - return 1; - - if (!objects[_object]) - return 1; - - sPos objPosition = objects[_object]->getPosition(); - sPos newPosition; - - if (_mode == _MOVE_RELATIVE) - newPosition = { objPosition.x + _pos.x, objPosition.y + _pos.y }; - else if (_mode == _MOVE_ABSOLUTE) - newPosition = _pos; - else if (_mode == _MOVE_FORCE_ABSOLUTE) - { - objects[_object]->setPosition(_pos); - return 0; - } - - sCollision coll; - - coll = checkCollision(newPosition, objects[_object]->getSize()); - - bool abort = false; - - if(coll.idc) - { - for(int i = 0; i < coll.idc; i++) - { - if(coll.idv[i] != _object) - abort += objects[_object]->onCollisionActive(0, objects[coll.idv[0]]->onCollisionPassive(0)); - } - } - - if(!abort) - objects[_object]->setPosition(newPosition); - - if(coll.idv) - free (coll.idv); - if(coll.hitv) - free (coll.hitv); - - buildHitmap(); - return 0; -} - -int cObjectHandler::destroyObject(int _object) -{ - if(!objects[_object]) - return 1; - - delete objects[_object]; - objects[_object] = NULL; - - buildHitmap(); - return 0; -} - -int cObjectHandler::write() -{ - render->clear(); - - for (unsigned long int i = 0; i < meshes.size(); i++) - { - if(meshes[i]) - { - moveWiremesh(i,{-cameraPosition.x, -cameraPosition.y, 0} ,_MOVE_RELATIVE); - meshes[i]->write(render); - moveWiremesh(i,{cameraPosition.x, cameraPosition.y, 0},_MOVE_RELATIVE); - } - } - - for (unsigned long int i = 0; i < objects.size(); i++) - { - if (objects[i]) // Check if objects[i] is existent - { - //Draw every Object - sObject obj = objects[i]->getObject(); //get Object #i - - for (int o = 0; o < obj.sizeY; o++) { //y axis - for (int p = 0; p < obj.sizeX; p++) { //x axis - if (obj.cScreen[p][o]) { //Dont overwrite empty pixels - sPos pos{ obj.pos.x + p - cameraPosition.x, - obj.pos.y + o - cameraPosition.y }; - render->drawPoint(obj.cScreen[p][o], pos, true, obj.wColor[p][o]); - } - } - } - } - } - - return 0; -} - -int cObjectHandler::clickEvent(sPos _pos, unsigned int _button) -{ - if(_pos.x >= iHitMap.size()) - return 1; - if(_pos.y >= iHitMap[_pos.x].size()) - return 1; - - - if(objects[ iHitMap[_pos.x][_pos.y] ]) - { - sPos rel_pos; - sPos obj_pos = objects[ iHitMap[_pos.x][_pos.y] ]->getPosition(); - rel_pos.x = _pos.x - obj_pos.x + cameraPosition.x; - rel_pos.y = _pos.y - obj_pos.y + cameraPosition.y; - - iActiveObject = iHitMap[_pos.x][_pos.y]; //Set active object - objects[ iHitMap[_pos.x][_pos.y] ]->onClick(rel_pos, _button); - } - else - return 1; - - return 0; -} - -int cObjectHandler::charEvent(unsigned char _c) -{ - if(objects.size() > iActiveObject) - { - if(objects[iActiveObject]) - { - objects[iActiveObject]->onChar(_c); - } - else - return 1; - } - - return 0; -} - -void cObjectHandler::buildHitmap() -{ - if(!enableInputMapping) - return; - - //Rebuild 2D vector - sPos size = render->getSize(); - - vector cp; - - while(size.y > cp.size()) - { - cp.push_back(0); - } - - while (size.x > iHitMap.size()) - { - iHitMap.push_back(cp); - } - - while (size.x <= iHitMap.size()) - { - iHitMap.pop_back(); - } - for(unsigned int x = 0; x < iHitMap.size(); x++) - { - for(unsigned int y = 0; y < iHitMap[x].size(); y++) - { - iHitMap[x][y] = 0; - } - } - //Write object IDs to iHitMap - for(unsigned int i = 0; i < objects.size(); i++) - { - if(objects[i]) - { - sPos oPos = objects[i]->getPosition(); - sPos oSize = objects[i]->getSize(); - - oPos.x -= cameraPosition.x; - oPos.y -= cameraPosition.y; - - for(int x = oPos.x; x < oPos.x + oSize.x; x++) - { - for(int y = oPos.y; y < oPos.y + oSize.y; y++) - { - if((x < size.x && y < size.y) && (x >= 0 && y >= 0)) //Objects can be outside the screen. - iHitMap[x][y] = i; - }//for - }//for - }//if - }//for -}//buildHitmap - -void cObjectHandler::focusNext() -{ - iActiveObject++; - - if(iActiveObject >= objects.size()) - iActiveObject = 0; -} - -void cObjectHandler::focus(unsigned int _id) -{ - if(_id >= objects.size()) - iActiveObject = objects.size(); - else - iActiveObject = _id; -} - -int cObjectHandler::createWiremesh(cWiremesh *_mesh) -{ - meshes.push_back(_mesh); - - return meshes.size() - 1; -} - -int cObjectHandler::moveWiremesh(int _mesh, sCoord3d _pos, int _mode) -{ - if (_mesh >= meshes.size()) //prevent segmentation faults - return 1; - - if (!meshes[_mesh]) - return 1; - - sCoord3d meshPosition = meshes[_mesh]->getPosition(); - - if (_mode == _MOVE_RELATIVE) - meshes[_mesh]->setPosition(meshPosition + _pos); - else if (_mode == _MOVE_ABSOLUTE) - meshes[_mesh]->setPosition(_pos); - - return 0; -} - -int cObjectHandler::destroyWiremesh(int _mesh) -{ - if(!meshes[_mesh]) - return 1; - - delete meshes[_mesh]; - meshes[_mesh] = NULL; - - return 0; -} - -int cObjectHandler::rotateWiremesh(int _mesh, sCoord3d _angle) -{ - if (_mesh >= meshes.size()) //prevent segmentation faults - return 1; - - if (!meshes[_mesh]) - return 1; - - meshes[_mesh]->rotate(_angle); - - return 0; -} - -void cObjectHandler::setCameraPosition(sPos _pos, int _mode) -{ - if(_mode == _MOVE_ABSOLUTE) - cameraPosition = _pos; - else if(_mode == _MOVE_RELATIVE) - { - cameraPosition.x += _pos.x; - cameraPosition.y += _pos.y; - } - - buildHitmap(); -} - -sPos cObjectHandler::getCameraPosition() -{ - return cameraPosition; -} - -sCollision cObjectHandler::checkCollision(sPos _pos, sPos _size) -{ - sCollision ret; - vector collisions; - vector hitTypes; - ret.idc = 0; - ret.idv = NULL; - ret.hitv = NULL; - - if(!enableCollision) - return ret; - - int sizeX, sizeY; - - sizeX = render->getSize().x; - sizeY = render->getSize().y; - - //The mother of if-statements - //No collision for offscreen objects - if( (_pos.x < cameraPosition.x && _pos.x + _size.x + cameraPosition.x < 0) || - (_pos.x - cameraPosition.x >= iHitMap.size() && _pos.x + _size.x - cameraPosition.x >= iHitMap.size()) || - (_pos.y < cameraPosition.y && _pos.y + _size.y + cameraPosition.y < 0) || - (_pos.y - cameraPosition.y >= iHitMap[0].size() && _pos.y + _size.y - cameraPosition.y >= iHitMap[0].size()) ) - return ret; - - for(int x = _pos.x - cameraPosition.x; x < _pos.x + _size.x - cameraPosition.x; x++) - { - for(int y = _pos.y - cameraPosition.y; y < _pos.y + _size.y - cameraPosition.y; y++) - { - if(!(x >= sizeX || x < 0 || y >= sizeY || y < 0)) - { - if(iHitMap[x][y]) - collisions.push_back(iHitMap[x][y]); - } - } - } - - //Since Object can hit on multiple Pixels, duplications can occur. - //Sort and set duplicates to zero - //-> zeros are at front of vector - for(unsigned int swaps = 1; swaps > 0;) - { - swaps = 0; - - for(unsigned int i = 0; i < collisions.size() - 1; i++) - { - if(collisions[i] > collisions[i + 1]) - { - swaps ++; - unsigned int tmp = 0; - - tmp = collisions[i]; - collisions[i] = collisions[i + 1]; - collisions[i + 1] = tmp; - } - if(collisions[i] == collisions[i + 1]) - collisions[i] = 0; - } - } - - //Since every empty entry is in front, pop them - while(!collisions.front()) - collisions.erase(collisions.begin()); - - ret.idc = collisions.size(); - ret.idv = (unsigned int*) malloc( sizeof(*ret.idv) * ret.idc ); - - for(unsigned int i = 0; i < ret.idc; i++) - { - ret.idv[i] = collisions[i]; - } - - return ret; -} diff --git a/cObjectHandler.h b/cObjectHandler.h deleted file mode 100644 index 4a0306b..0000000 --- a/cObjectHandler.h +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once - -#include - -#include "cObject.h" -#include "cWiremesh.h" - -//movemodes -#define _MOVE_RELATIVE 0 -#define _MOVE_ABSOLUTE 1 -#define _MOVE_FORCE_ABSOLUTE 2 - -using namespace std; - -struct sCollision -{ - unsigned int *idv; - int *hitv; - unsigned int idc; -}; - -/** -* Manages cObject and cWiremesh and writes them to a cRender framebuffer (Also works on cObject, since it inherits from cRender!). -* forwards input events to corresponding cObject. -* Runs collision checking for every move operation. This is very expensive, so deactivate if not needed (eg. for background animations etc)! -*/ -class cObjectHandler -{ -public: - /** - * *_render: pointer to instance of cRender all objects will be written to - * _enableCollision: activate collision checking globally. CAUTION: Collision requires InputMapping. If InputMapping is disabled, Collision will NOT WORK! - * _enableInputMapping: activate Input mapping for mouse and keyboard events - */ - explicit cObjectHandler(cRender *_render, bool _enableInputMapping = true, bool _enableCollision = true); - - /** - * Adds _object to managed objects vector - * returns Identifier for newly created vector - */ - int createObject(cObject *_object); - - /** - * Alters position of _object by _pos either relative to old position or Absolute - * Depending on selected _mode (_MOVE_RELATIVE / _MOVE_ABSOLUTE / _MOVE_ABSOLUTE). - * _MOVE_ABSOLUTE not recommended: Collision is only checked at destination. To ensure initialisation, use _MOVE_FORCE_ABSOLUTE! - */ - int moveObject(int _object, sPos _pos, int _mode); - - /** - * removes _object from vector after deleting it - */ - int destroyObject(int _object); - - /** - * Analog to createObject() - */ - int createWiremesh(cWiremesh *_mesh); - - int moveWiremesh(int _mesh, sCoord3d _pos, int _mode); - - int rotateWiremesh(int _mesh, sCoord3d _angle); - - int destroyWiremesh(int _mesh); - - - void setCameraPosition(sPos _pos, int _mode); - - sPos getCameraPosition(); - - - /** - * writes all objects in objects[] to render buffer - */ - int write(); - - - /** - * Calls onClick of cObject at _pos, focuses Object - * returns 0 if successfull, 1 if no Object is at _pos - */ - int clickEvent(sPos _pos, unsigned int _button); - - /** - * Calls onChar of active cObject, default 0 - * returns 0 if successfull, 1 if no Object or destroyed Object is empty - */ - int charEvent(unsigned char _c); - - /** - * Focuses next Object - */ - void focusNext(); - - /** - * Focuses Object by id. - * 0 is empty by default and can be used to unfocus - */ - void focus(unsigned int _id); - - -private: - /** - * This function is very expensive! Only use when needed! - */ - sCollision checkCollision(sPos _pos, sPos _size); - - void buildHitmap(); - - vector objects; - vector meshes; - vector< vector > iHitMap; - cRender *render; - unsigned long int iActiveObject; - sPos cameraPosition; - bool enableCollision; - bool enableInputMapping; -}; diff --git a/cRender.cpp b/cRender.cpp deleted file mode 100644 index 9fbdc8f..0000000 --- a/cRender.cpp +++ /dev/null @@ -1,380 +0,0 @@ -#include "cRender.h" - - -cRender::cRender(char _backound, WORD _color, int _sx, int _sy) -{ - bBlockRender = false; //If this Constructor is used, this instance is not inherited, thus render() doesn't need to be blocked - iLastError = _OK_; - sizeX = 0; - sizeY = 0; - - cBackound = _backound; - wBackColor = _color; - -#ifdef __linux__ //In Linux, setting Console size is not supported, so it gets Size of Console (Window) instead. - - wDefColor = _COL_DEFAULT; - - //Set up console - setAlternateBufferScreen(true); - setConsoleCursor(false); - - setBufferSize( getConsoleWindowSize() ); - - if(sizeX < _sx || sizeY < _sy) //Notify Program tha screen is too small for desired Size - iLastError = _ERR_SCREEN_TOO_SMALL_; - -#elif _WIN32 //Windows Specific Code - hstdout = GetStdHandle(STD_OUTPUT_HANDLE); //get handle - - GetConsoleScreenBufferInfo(hstdout, &csbi); //get current console settings - wDefColor = csbi.wAttributes; //Get default console color - - SetConsoleWindowSize(_sx + 1, _sy + 1); //set the windows size to _sx * _sy (+1 so no scrolling accurs) - - setBufferSize({_sx,_sy}); -#endif //_WIN32 - - setConsoleEcho(false); - clear(true); //Init backround array - -}//render() - - -cRender::cRender() {} - -cRender::~cRender() -{ - if(bBlockRender) //Don't run destructor if inherited - return; - - for (int i = 0; i < sizeX; i++) { - free(cScreen[i]); - free(wColor[i]); - free(bChanged[i]); - } - - free(cScreen); - free(wColor); - free(bChanged); - - setConsoleEcho(true); - - #ifdef __linux__ - setConsoleCursor(true); - setAlternateBufferScreen(false); - #endif //__linux__ -} - -int cRender::drawPoint(char _c, sPos _pos, bool _overrideCollision, WORD _color) -{ - if (_pos.x >= sizeX || _pos.y >= sizeY || _pos.x < 0 || _pos.y < 0) - return _ERR_COORDINATES_INVALID_; - - if (cScreen[_pos.x][_pos.y] != cBackound && _overrideCollision != true) //detect Collsision - return _COLLISION_; - - cScreen[_pos.x][_pos.y] = _c; - if (_color == _COL_DEFAULT) //_COL_DEFAULT is NOT a proper colorcode! - wColor[_pos.x][_pos.y] = wDefColor; - else - wColor[_pos.x][_pos.y] = _color; - - if(!bBlockRender) //Changemap is not allocated in inherited Classes - bChanged[_pos.x][_pos.y] = true; - - return 0; -} - -int cRender::drawLine(char _c, sPos _pos1, sPos _pos2, bool _overrideCollision, WORD _color) -{ - if(_pos1.x > _pos2.x) - { - //Shit WILL go wrong - return drawLine(_c, _pos2, _pos1, _overrideCollision, _color); - } - - if (_pos1.x == _pos2.x) { //Horizontal line - for (int i = _pos1.y; i <= _pos2.y; i++) - { - drawPoint(_c, sPos{_pos1.x, i}, _overrideCollision, _color); - } - } - else if (_pos1.y == _pos2.y) { //Vertical line - for (int i = _pos1.x; i <= _pos2.x; i++) - { - drawPoint(_c, sPos{ i, _pos1.y }, _overrideCollision, _color); - } - } - else { //Diagonal Line - int dX = _pos1.x - _pos2.x; - int dY = _pos1.y - _pos2.y; - float fGradient = (float)dY / (float)dX; - - for (int i = 0; i <= abs(dX); i++) - { - drawPoint(_c, sPos{i + _pos1.x, (int)(i * fGradient + _pos1.y + 0.5)}, _overrideCollision, _color); //+0.5 for rounding error - - if(std::abs(fGradient) > 1.0) - { - int dy = (int)(((i + 1) * fGradient + _pos1.y + 0.5) - (i * fGradient + _pos1.y + 0.5)); - - if(dy > 0 && ((int)(i * fGradient + _pos1.y + 0.5) + dy) <= _pos2.y) - { - drawLine(_c, - sPos{i + _pos1.x, (int)(i * fGradient + _pos1.y + 0.5)}, - sPos{i + _pos1.x, (int)(i * fGradient + _pos1.y + 0.5) + dy }, - _overrideCollision, _color); - }//if - else if(dy < 0 && ((int)(i * fGradient + _pos1.y + 0.5) + dy) >= (_pos2.y) ) - { - drawLine(_c, - sPos{i + _pos1.x, (int)(i * fGradient + _pos1.y + 0.5) + dy }, - sPos{i + _pos1.x, (int)(i * fGradient + _pos1.y + 0.5)}, - _overrideCollision, _color); - }//else if - }//if - }//for - }//else - - return 0; -}//drawLine - -int cRender::drawText(string _s, sPos _pos, WORD _color) -{ - for (int i = 0; i < _s.length(); i++) - { - drawPoint(_s[i], sPos{ i + _pos.x,_pos.y }, true, _color); - } - return 0; -} - -int cRender::drawRectangle(char _border, char _fill, sPos _pos1, sPos _pos2, WORD _borderColor, WORD _fillColor) -{ - //Draw the four outside lines - drawLine(_border, _pos1, sPos{ _pos1.x, _pos2.y }, true, _borderColor); - drawLine(_border, _pos1, sPos{ _pos2.x, _pos1.y }, true, _borderColor); - drawLine(_border, sPos{ _pos1.x, _pos2.y }, _pos2, true, _borderColor); - drawLine(_border, sPos{ _pos2.x, _pos1.y }, _pos2, true, _borderColor); - - //Fill rectangle if _fill isn't NULL - if (_fill) { - for (int i = _pos1.y + 1; i < _pos2.y; i++) { - for (int o = _pos1.x + 1; o < _pos2.x; o++) { - drawPoint(_fill, sPos{ o,i }, true, _fillColor); - } - } - } - - return 0; -} - -int cRender::render(void) -{ - if (bBlockRender) - return _ERR_RENDER_BLOCKED_BY_CHILD_; - - //Resize screenbuffer if needed - setBufferSize( getConsoleWindowSize( ) ); - - for (int i = 0; i < sizeY; i++) { - for (int o = 0; o < sizeX; o++) { - if(bChanged[o][i]) - { - #ifdef _WIN32 - - gotoxy(o,i); - SetConsoleTextAttribute(hstdout, wColor[o][i] | _COL_INTENSITY); - //cout << cScreen[o][i]; - printf("%c", cScreen[o][i]); - - #elif __linux__ - //gotoxy(x,y) now included!! - char buffer[20]; - int cbuf = sprintf(buffer,"\e[%i;%iH\e[%im%c", i + 1, o + 1, wColor[o][i], cScreen[o][i]); - // Position Color Origin is at 1,1 - write (STDOUT_FILENO, buffer, cbuf); - - #endif //__linux__ - } - bChanged[o][i] = false; - } - } - return 0; -} - -int cRender::clear(bool _forceReRender) -{ - for (int i = 0; i < sizeY; i++) { - for (int o = 0; o < sizeX; o++) { - if(((cScreen[o][i] == cBackound) && (wColor[o][i] == wBackColor)) && !_forceReRender) - bChanged[o][i] = false; - else - { - cScreen[o][i] = cBackound; - wColor[o][i] = wBackColor; - bChanged[o][i] = true; - } - } - } - return 0; -} - -int cRender::clear() -{ - return clear(false); -} - - -#ifdef _WIN32 -//Source: http://www.cplusplus.com/forum/windows/121444/ -int cRender::SetConsoleWindowSize(int x, int y) -{ - HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); - - if (h == INVALID_HANDLE_VALUE) - return 1; - - CONSOLE_SCREEN_BUFFER_INFO bufferInfo; - if (!GetConsoleScreenBufferInfo(h, &bufferInfo)) - return 1; - - SMALL_RECT& winInfo = bufferInfo.srWindow; - COORD windowSize = { winInfo.Right - winInfo.Left + 1, winInfo.Bottom - winInfo.Top + 1 }; - - if (windowSize.X > x || windowSize.Y > y) - { - // window size needs to be adjusted before the buffer size can be reduced. - SMALL_RECT info = - { - 0, 0, - x < windowSize.X ? x - 1 : windowSize.X - 1, - y < windowSize.Y ? y - 1 : windowSize.Y - 1 - }; - - if (!SetConsoleWindowInfo(h, TRUE, &info)) - return 1; - } - - COORD size = { x, y }; - if (!SetConsoleScreenBufferSize(h, size)) - return 1; - - SMALL_RECT info = { 0, 0, x - 1, y - 1 }; - if (!SetConsoleWindowInfo(h, TRUE, &info)) - return 1; -} -#endif //_WIN32 - -int cRender::getLastError() -{ - return iLastError; -} - -#ifdef _WIN32 -void cRender::gotoxy( int x, int y ) -{ - COORD p = { x, y }; - SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), p ); -} - -#elif __linux__ - -sPos cRender::getConsoleWindowSize() -{ - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - - return {w.ws_col, w.ws_row}; -} - -void cRender::setAlternateBufferScreen(bool _enable) -{ - _enable ? write (STDOUT_FILENO, "\e[?47h", 6):write (STDOUT_FILENO, "\e[?47l", 6); -} - -void cRender::setConsoleCursor(bool _enable) -{ - _enable ? write (STDOUT_FILENO, "\e[?25h", 6) : write (STDOUT_FILENO, "\e[?25l", 6); -} - -#endif // __linux__ - -void cRender::setBufferSize(sPos _size) -{ - if(_size.x == sizeX && _size.y == sizeY) - return; - - if(sizeX!=0 && sizeY!=0) //resize. delete first - { - for (int i = 0; i < sizeX; i++) { - free(cScreen[i]); - free(wColor[i]); - free(bChanged[i]); - } - - free(cScreen); - free(wColor); - free(bChanged); - } - - sizeX = _size.x; - sizeY = _size.y; - - //Initialize 2D array - cScreen = (char**)malloc(sizeof *cScreen * sizeX); - for (int i = 0; i < sizeX; i++) - cScreen[i] = (char*)malloc(sizeof *cScreen[i] * sizeY); - - wColor = (WORD**)malloc(sizeof *wColor * sizeX); - for (int i = 0; i < sizeX; i++) - wColor[i] = (WORD*)malloc(sizeof *wColor[i] * sizeY); - - bChanged = (bool**)malloc(sizeof *bChanged * sizeX); - for (int i = 0; i < sizeX; i++) - bChanged[i] = (bool*)malloc(sizeof *bChanged[i] * sizeY); - - clear(true); -} - -sPos cRender::getSize() -{ - return {sizeX, sizeY}; -} - -void cRender::forceReRender() -{ - for (int i = 0; i < sizeY; i++) { - for (int o = 0; o < sizeX; o++) { - bChanged[o][i] = true; - } - } -} - -void cRender::setConsoleEcho(bool _enable) -{ -#ifdef WIN32 - HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); - DWORD mode; - GetConsoleMode(hStdin, &mode); - - if( !_enable ) - mode &= ~ENABLE_ECHO_INPUT; - else - mode |= ENABLE_ECHO_INPUT; - - SetConsoleMode(hStdin, mode ); - -#elif __linux__ - /*struct termios tty; - tcgetattr(STDIN_FILENO, &tty); - if( !_enable ) - tty.c_lflag &= ~ECHO; - else - tty.c_lflag |= ECHO; - - (void) tcsetattr(STDIN_FILENO, TCSANOW, &tty);*/ - - _enable ? write (STDOUT_FILENO, "\e[?8h", 5) : write (STDOUT_FILENO, "\e[?8l", 5); -#endif //__linux__ -} diff --git a/cRender.h b/cRender.h deleted file mode 100644 index 415db6e..0000000 --- a/cRender.h +++ /dev/null @@ -1,177 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#ifdef __linux__ - #include - #include - - typedef int WORD; -#elif _WIN32 - #include -#else - #error "Platforn not supported" -#endif - -//errors -#define _OK_ 0 -#define _ERR_ 1 -#define _ERR_COORDINATES_INVALID_ 2 -#define _ERR_RENDER_BLOCKED_BY_CHILD_ 3 -#define _ERR_SCREEN_TOO_SMALL_ 4 - -#define _COLLISION_ 255 - -//Colors -#ifdef _WIN32 - #define _COL_BLACK 0x00 - #define _COL_BLUE 0x01 - #define _COL_GREEN 0x02 - #define _COL_YELLOW 0x0E - #define _COL_RED 0x04 - #define _COL_WHITE 0x0F - #define _COL_DARK_WHITE 0x07 - #define _COL_INTENSITY 0x08 - #define _COL_DEFAULT 0xFF -#elif __linux__ - #define _COL_BLACK 30 - #define _COL_BLUE 34 - #define _COL_GREEN 32 - #define _COL_YELLOW 33 - #define _COL_RED 31 - #define _COL_WHITE 37 - #define _COL_DEFAULT 0 - - //Linux Specific - #define _COL_BOLD 1 - #define _COL_BOLD_OFF 21 - #define _COL_UNDERLINE 4 - #define _COL_UNDERLINE_OFF 24 - #define _COL_INVERSE 7 - #define _COL_INVERSE_OFF 27 -#endif - -using namespace std; - -struct sPos -{ - int x; - int y; -}; -/** cRender manages a framebuffer the size of the console (window) it is run in. -* -* puts console in alternate screen mode -*/ -class cRender -{ -public: - /** Constructor - * sets cBackround[][] to _backround & wColor[][] to _color - * Resizes console window for Windows - * Sets Size to Console Window Size for Linux. Writes Error for _sx or _sy smaller than Screen. Get by getLastError() - */ - cRender(char _backound, WORD _color, int _sx, int _sy); - - virtual ~cRender(); - - /** Draws _c @ _pos in screenbuffer - * Returns _COLLOSION_ if _pos is already set to !cBackround && _overrideCollision isnt set - */ - int drawPoint(char _c, sPos _pos, bool _overrideCollision, WORD _color); - - /** draws Line from _pos1 to _pos2 in screenbuffer - * x Value of pos1 MUSTNT exceed the x value of pos2! - */ - int drawLine(char _c, sPos _pos1, sPos _pos2, bool _overrideCollision, WORD _color); - - /** Draws Text _s @ _pos in screenbuffer - * First char is @ _pos - */ - int drawText(string _s, sPos _pos, WORD _color); - - /** writes rectangle to screenbuffer - * x Value of pos1 MUSTNT exceed the x value of pos2! - */ - int drawRectangle(char _border, char _fill, sPos _pos1, sPos _pos2, WORD _borderColor, WORD _fillColor); - - /** Dumps screenbuffer to stdout - * prints changed pixels - */ - int render(void); - - /** clears cScreen + wColor - * for _forceReRender == true, the bChanged[][] is set to true to force Re-Render of whole Screen - * clear(void) calls clear(_forceReRender = false) - */ - int clear(); - int clear(bool _forceReRender); - - /** Returns last Error that was not returnable - */ - int getLastError(); - - /** Returns size of screenbuffer - */ - sPos getSize(); - - -protected: - /** Empty Constructor for being inheritable - */ - cRender(); - - /** Sets screenbuffer size - * Uses sizeX, sizeY to determine previous screenbuffer size. Do NOT change sizeX, sizeY manually!! - */ - void setBufferSize(sPos _size); - - bool bBlockRender; - //* Used by children to block render function - - char **cScreen; - //* Pixel Map - WORD **wColor; - //* Color Map - bool **bChanged; - //* Pixel Change Map - - char cBackound; - //* Default backround - WORD wBackColor; - //* Default backround color - int sizeX, sizeY; - //* Size of screen array - -#ifdef _WIN32 - HANDLE hstdout; - CONSOLE_SCREEN_BUFFER_INFO csbi; -#endif - - WORD wDefColor; - //* Default Color - - int iLastError; - -private: -#ifdef _WIN32 - int SetConsoleWindowSize(int x, int y); - //Slightly adapted from: http://www.cplusplus.com/forum/windows/121444/ - - void gotoxy( int x, int y ); -#endif - - void forceReRender(); - - void setConsoleEcho(bool _enable); -#ifdef __linux__ - sPos getConsoleWindowSize(); - - void setConsoleCursor(bool _enable); - - void setAlternateBufferScreen(bool _enable); -#endif -}; diff --git a/cWiremesh.cpp b/cWiremesh.cpp deleted file mode 100644 index 62fee0d..0000000 --- a/cWiremesh.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "cWiremesh.h" - -cWiremesh::cWiremesh() : position({0,0,0}), angle({0,0,0}) { } - -cWiremesh::~cWiremesh() { } - -void cWiremesh::addVector(sCoord3d _origin, sCoord3d _vector, char _char, WORD _color) -{ - vectors.push_back(sVector{_origin, _vector, _char, _color}); -} - -void cWiremesh::rotate(sCoord3d _val) -{ - angle = angle + _val; -} - -void cWiremesh::reset() -{ - vectors.clear(); -} - -void cWiremesh::write(cRender *_render) -{ - if(!_render) - return; - - sPos porigin = _render->getSize(); - sCoord3d origin = {porigin.x / 2, porigin.y / 2, 0}; - - for(long unsigned int i = 0; i < vectors.size(); i++) - { - sCoord3d vorigin = applyRotation(vectors[i].origin, angle); - sCoord3d vdirection = applyRotation(vectors[i].direction, angle); - - _render->drawLine(vectors[i].c, - translate(vorigin + position, origin), - translate(vorigin + vdirection + position, origin), - true, vectors[i].color); - } -} - -sPos cWiremesh::translate(sCoord3d _coord, sCoord3d _origin) -{ - sPos ret; - - ret.x = (int)((float)_coord.x - ((float)_coord.z / (float)_DEPTH * (float)(_coord.x - _origin.x))); - ret.y = (int)((float)_coord.y - ((float)_coord.z / (float)_DEPTH * (float)(_coord.y - _origin.y))); - - return ret; -} - -sCoord3d cWiremesh::getPosition() -{ - return position; -} - -void cWiremesh::setPosition(int _x, int _y, int _z) -{ - position = {_x, _y, _z}; -} - -void cWiremesh::setPosition(sCoord3d _pos) -{ - position = _pos; -} - -void cWiremesh::scale(float _scalar) -{ - for(unsigned long int i = 0; i < vectors.size(); i++) - { - vectors[i].origin.x = (int)((float)vectors[i].origin.x * _scalar); - vectors[i].origin.y = (int)((float)vectors[i].origin.y * _scalar); - vectors[i].origin.z = (int)((float)vectors[i].origin.z * _scalar); - - vectors[i].direction.x = (int)((float)vectors[i].direction.x * _scalar); - vectors[i].direction.y = (int)((float)vectors[i].direction.y * _scalar); - vectors[i].direction.z = (int)((float)vectors[i].direction.z * _scalar); - } -} - -sCoord3d cWiremesh::applyRotation(sCoord3d _vector, sCoord3d _angle) -{ - sCoord3d ret = _vector; - - //Perform some algebra-magic - //couldn't be bothered to implement or use a matrix class - - if(_angle.x) - { - float rads = (float)_angle.x * PI / 180.0; - - ret.y = (int)( - (float)_vector.y * cos(rads) - - (float)_vector.z * sin(rads) - ); - ret.z = (int)( - (float)_vector.y * sin(rads) + - (float)_vector.z * cos(rads) - ); - } - if(_angle.y) - { - float rads = (float)_angle.y * PI / 180.0; - sCoord3d tmp = ret; - - ret.x = (int)( - (float)tmp.x * cos(rads) + - (float)tmp.z * sin(rads) - ); - - ret.z = (int)( - - (float)tmp.x * sin(rads) - + (float)tmp.z * cos(rads) - ); - } - if(_angle.z) - { - float rads = (float)_angle.z * PI / 180.0; - sCoord3d tmp = ret; - - ret.x = (int) ( - (float)tmp.x * cos(rads) - - (float)tmp.y * sin(rads) - ); - ret.y = (int) ( - (float)tmp.x * sin(rads) + - (float)tmp.y * cos(rads) - ); - } - - return ret; -} diff --git a/cWiremesh.h b/cWiremesh.h deleted file mode 100644 index 82d3bd6..0000000 --- a/cWiremesh.h +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include -#include - -#include "cRender.h" - -#define _DEPTH 99 -#define PI 3.14159265 - -struct sCoord3d -{ - int x; - int y; - int z; - - sCoord3d operator+(sCoord3d p) - { - sCoord3d ret; - ret.x = x + p.x; - ret.y = y + p.y; - ret.z = z + p.z; - return ret; - } - - sCoord3d operator-(sCoord3d p) - { - sCoord3d ret; - ret.x = x - p.x; - ret.y = y - p.y; - ret.z = z - p.z; - return ret; - } -}; - -struct sVector -{ - sCoord3d origin; - sCoord3d direction; - - char c; - WORD color; -}; - -/** -* cWiremesh stores 3D objects as multiple vectors. it can write itself on a cRender framebuffer. -*/ -class cWiremesh -{ -public: - - cWiremesh(); - - virtual ~cWiremesh(); - - /** - * Add a line from _origin to (_origin + _vector) in 3D space. - */ - void addVector(sCoord3d _origin, sCoord3d _vector, char _char, WORD _color); - - /** - * Rotates by (x,y,z) degrees around the corresponding axis. - * Rotation is stored seperatately from original vectors while they stay untouched to prevent growing rounding errors by repeated rotation. - * - * Rotation is applied relative to the origin of this wiremsh. - */ - void rotate(sCoord3d _val); - - /** - * Scales by _scalar. The scalar is directly applied to all vectors. Be wary of growing rounding errors! - */ - void scale(float _scalar); - - sCoord3d getPosition(); - - void setPosition(int _x, int _y, int _z); - - void setPosition(sCoord3d _pos); - - /** - * clear this wiremesh - */ - void reset(); - - /** - * Translates wiremesh into 2D space after applying rotation to each vector. - * The vanishing point is set to the center of _render with depth _DEPTH. Alter _DEPTH to achieve optimal resultst. - */ - void write(cRender *_render); - -protected: - -private: - - sPos translate(sCoord3d _coord, sCoord3d _origin); - - sCoord3d applyRotation(sCoord3d _vector, sCoord3d _angle); - - sCoord3d position; - - sCoord3d angle; - - std::vector vectors; -}; diff --git a/example/test.cpp b/example/test.cpp new file mode 100644 index 0000000..b09e6ec --- /dev/null +++ b/example/test.cpp @@ -0,0 +1,142 @@ +#include +#include + +#include "version.h" + +#include "cRender.h" +#include "cObject.h" +#include "cObjectHandler.h" +#include "cInput.h" +#include "cWiremesh.h" + +//#include "testobject.h" + +class testobject : cObject +{ +public: + testobject() + { + setSize(10,5); + cc = 0; + kc = 0; + + drawRectangle('#', NULL, {0,0}, {9,4}, _COL_GREEN, _COL_DEFAULT); + } + + ~testobject() { destruct(); } + + virtual void onClick(sPos _pos, unsigned int _button) + { + cc++; + drawText(std::to_string(cc), {2,2}, _COL_RED); + + drawPoint('Q', _pos, true, _COL_YELLOW); + } + + virtual bool onCollisionActive(unsigned int _hit, int _passiveObject){ + kc++; + drawText(std::to_string(kc), {0,0}, _COL_RED); + return true; + } + + virtual void onChar(unsigned char _c) { drawPoint(_c, {1,1},true, _COL_BLUE); } +private: + int cc; + int kc; +}; + +int main(int argc, char* argv[]) +{ + cRender render(' ', _COL_DEFAULT, 30,30); + cObjectHandler handler(&render); + cObject ver(45,1); + testobject obj2; + + cInput input; + + unsigned int framecounter = 0; + bool loop = true; + + if(argc > 1) + { + loop = false; + } + + render.render(); + + ver.drawText(DATE, {20,0}, _COL_WHITE); + ver.drawText(VERSTRING, {0,0}, _COL_WHITE); + int iver = handler.createObject(&ver); + handler.moveObject(iver, {0,0}, _MOVE_FORCE_ABSOLUTE); + + int iobj2 = handler.createObject((cObject*)&obj2); + handler.moveObject(iobj2, {3,3}, _MOVE_FORCE_ABSOLUTE); + + sPos middle = render.getSize(); + middle.x /= 2; + middle.y /= 2; + + while( loop ) + { + sInputEvent ie = input.poll(); + + if(ie.type != _EVENT_NULL) + { + if(ie.type == _EVENT_KEY) + { + switch (ie.c) + { + case 'A'://up + handler.setCameraPosition({0,-1}, _MOVE_RELATIVE); + break; + case 'B'://down + handler.setCameraPosition({0,1}, _MOVE_RELATIVE); + break; + case 'C'://right + handler.setCameraPosition({1,0}, _MOVE_RELATIVE); + break; + case 'D'://left + handler.setCameraPosition({-1,0}, _MOVE_RELATIVE); + break; + }; + } + else if (ie.type == _EVENT_MOUSE) + { + if(ie.b == 0) + handler.clickEvent({ie.x, ie.y}, 0); + } + else if (ie.type == _EVENT_CHAR) + { + //handler.charEvent(ie.c); + switch(ie.c) + { + case 'w': + handler.moveObject(iobj2, {0,-1}, _MOVE_RELATIVE); + break; + case 's': + handler.moveObject(iobj2, {0,1}, _MOVE_RELATIVE); + break; + case 'a': + handler.moveObject(iobj2, {-1,0}, _MOVE_RELATIVE); + break; + case 'd': + handler.moveObject(iobj2, {1,0}, _MOVE_RELATIVE); + break; + }; + } + else if (ie.type == _EVENT_TERM) + { + return 0; + } + } + + handler.write(); + render.render(); + framecounter++; + + if(loop) + usleep(10*1000); + } + + return 0; +} diff --git a/example/test_old.cpp b/example/test_old.cpp new file mode 100644 index 0000000..313b632 --- /dev/null +++ b/example/test_old.cpp @@ -0,0 +1,165 @@ +#include +#include + +#include "version.h" + +#include "cRender.h" +#include "cObject.h" +#include "cObjectHandler.h" +#include "cInput.h" +#include "cWiremesh.h" + +//#include "testobject.h" + +class testobject : cObject +{ +public: + testobject() + { + setSize(10,5); + cc = 0; + + drawRectangle('#', NULL, {0,0}, {9,4}, _COL_GREEN, _COL_DEFAULT); + } + + ~testobject() { destruct(); } + + virtual void onClick(sPos _pos, unsigned int _button) + { + cc++; + drawText(std::to_string(cc), {2,2}, _COL_RED); + + drawPoint('Q', _pos, true, _COL_YELLOW); + } + + virtual void onChar(unsigned char _c) { drawPoint(_c, {1,1},true, _COL_BLUE); } +private: + int cc; +}; + +int main(int argc, char* argv[]) +{ + cRender render(' ', _COL_DEFAULT, 30,30); + cObjectHandler handler(&render); + cObject ver(45,1); + cWiremesh obj; + testobject obj2; + + cInput input; + + unsigned int framecounter = 0; + bool loop = true; + + if(argc > 1) + { + loop = false; + } + + render.render(); + + ver.drawText(DATE, {20,0}, _COL_WHITE); + ver.drawText(VERSTRING, {0,0}, _COL_WHITE); + int iver = handler.createObject(&ver); + handler.moveObject(iver, {0,0}, _MOVE_ABSOLUTE); + + int x = 15; + int y = 15; + int z = 30; + + obj.addVector({-x,-y,z}, {2*x,0,0}, '+', _COL_RED); + obj.addVector({-x,-y,z}, {0,2*y,0}, '+', _COL_RED); + obj.addVector({-x,y,z}, {2*x,0,0}, '+', _COL_RED); + obj.addVector({x,-y,z}, {0,2*y,0}, '+', _COL_RED); + + obj.addVector({-x,-y,0}, {0,0,z}, ':', _COL_RED); + obj.addVector({x,-y,0}, {0,0,z}, ':', _COL_RED); + obj.addVector({-x,y,0}, {0,0,z}, ':', _COL_RED); + obj.addVector({x,y,0}, {0,0,z}, ':', _COL_RED); + + obj.addVector({-x,-y,0}, {2*x,0,0}, ',', _COL_RED); + obj.addVector({-x,-y,0}, {0,2*y,0}, ',', _COL_RED); + obj.addVector({-x,y,0}, {2*x,0,0}, ',', _COL_RED); + obj.addVector({x,-x,0}, {0,2*y,0}, ',', _COL_RED); + int imesh = handler.createWiremesh(&obj); + + int iobj2 = handler.createObject((cObject*)&obj2); + handler.moveObject(iobj2, {3,3}, _MOVE_ABSOLUTE); + + sPos middle = render.getSize(); + middle.x /= 2; + middle.y /= 2; + + handler.moveWiremesh(imesh,{middle.x,middle.y,0}, _MOVE_ABSOLUTE); + + while( loop ) + { + sInputEvent ie = input.poll(); + + if(ie.type != _EVENT_NULL) + { + if(ie.type == _EVENT_KEY) + { + switch (ie.c) + { + case 'A'://up + handler.setCameraPosition({0,-1}, _MOVE_RELATIVE); + break; + case 'B'://down + handler.setCameraPosition({0,1}, _MOVE_RELATIVE); + break; + case 'C'://right + handler.setCameraPosition({1,0}, _MOVE_RELATIVE); + break; + case 'D'://left + handler.setCameraPosition({-1,0}, _MOVE_RELATIVE); + break; + }; + } + else if (ie.type == _EVENT_MOUSE) + { + if(ie.b == 0) + handler.clickEvent({ie.x, ie.y}, 0); + } + else if (ie.type == _EVENT_CHAR) + { + //handler.charEvent(ie.c); + switch(ie.c) + { + case 'w': + handler.rotateWiremesh(imesh,{-10,0,0}); + break; + case 's': + handler.rotateWiremesh(imesh,{10,0,0}); + break; + case 'a': + handler.rotateWiremesh(imesh,{0,-10,0}); + break; + case 'd': + handler.rotateWiremesh(imesh,{0,10,0}); + break; + case 'q': + handler.rotateWiremesh(imesh,{0,0,-10}); + break; + case 'e': + handler.rotateWiremesh(imesh,{0,0,10}); + break; + }; + } + else if (ie.type == _EVENT_TERM) + { + return 0; + } + } + + handler.rotateWiremesh(imesh,{1,1,1}); + + handler.write(); + render.render(); + framecounter++; + + if(loop) + usleep(10*1000); + } + + return 0; +} diff --git a/src/cInput.cpp b/src/cInput.cpp new file mode 100644 index 0000000..6384c91 --- /dev/null +++ b/src/cInput.cpp @@ -0,0 +1,73 @@ +#include "cInput.h" + +cInput::cInput() +{ + // Save original serial communication configuration for stdin + tcgetattr( STDIN_FILENO, &original); + + // Put stdin in raw mode so keys get through directly without + // requiring pressing enter. + cfmakeraw (&raw); + tcsetattr (STDIN_FILENO, TCSANOW, &raw); + + // Enable mouse tracking + write (STDOUT_FILENO, "\e[?1000h", 8); +} + +cInput::~cInput() +{ + //revert changes to console + write (STDOUT_FILENO, "\e[?1000l", 8); + tcsetattr (STDIN_FILENO, TCSANOW, &original); +} + +sInputEvent cInput::poll() +{ + sInputEvent ret; + unsigned char buff [6]; + + //setup for select + fd_set rfds; + struct timeval tv; + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + ret.type = _EVENT_NULL; + + //Check for Input. return of none + if(!select(1, &rfds, NULL, NULL, &tv)) + return ret; + + read (STDIN_FILENO, &buff, 1); + if (buff[0] == 3) { + // User pressd Ctr+C + ret.type = _EVENT_TERM; + } + else if (buff[0] == '\x1B') //Escape sequence + { + read (STDIN_FILENO, &buff, 5); + if(buff[0] == '[') + { + if(buff[1] == 'M') //Mouse Event + { + ret.b = buff[2] - 32; + ret.x = buff[3] - 32 - 1; //Console sees origin at 1,1 + ret.y = buff[4] - 32 - 1; //Program at 0,0 + ret.type = _EVENT_MOUSE; + } + else //e.g. Arrow Keys + { + ret.c = buff[1]; + ret.type = _EVENT_KEY; + } + } + } + else + { + ret.type = _EVENT_CHAR; + ret.c = buff[0]; + } + return ret; +} diff --git a/src/cInput.h b/src/cInput.h new file mode 100644 index 0000000..00ddb7d --- /dev/null +++ b/src/cInput.h @@ -0,0 +1,58 @@ +#ifndef CINPUT_H_ +#define CINPUT_H_ + +#include +#include +#include +#include + +#ifdef __linux__ +#elif _WIN32 + #error "Platforn not supported" +#else + #error "Platforn not supported" +#endif + +#define _EVENT_NULL 0 +#define _EVENT_CHAR 1 +#define _EVENT_KEY 2 +#define _EVENT_MOUSE 3 +#define _EVENT_TERM 4 + +struct sInputEvent +{ + unsigned int type; + unsigned char c; + unsigned int b; + int x, y; +}; +/** +* ##cInput +* * puts STDIN in raw mode +* * activates mouse tracking +* * reverts console back to normal operation on destruction. +* Compatible with xterm compatible terminal emulators +*/ +class cInput +{ +public: + cInput(); + + ~cInput(); + + /** Reads inputevents + * returns event struct + * ### sInputEvent.type + * * _EVENT_NULL: No input recorded + * * _EVENT_CHAR: A Key was pressed, stored in .c + * * _EVENT_KEY: Escape sequence recorded, stored in .c without escape char + * * _EVENT_MOUSE: Console registered click at (.x, .y) with origin at (0,0) (top left). Mouse button stored in b. + * * _EVENT_TERM: Console registered Ctrl+C + */ + sInputEvent poll(); + +private: + struct termios original, raw; +}; + +#endif /* end of include guard: */ diff --git a/src/cObject.cpp b/src/cObject.cpp new file mode 100644 index 0000000..7dc194c --- /dev/null +++ b/src/cObject.cpp @@ -0,0 +1,82 @@ +#include "cObject.h" + +cObject::cObject(int _sx, int _sy) : pos({0,0}) , bSizeSet(false) +{ + setSize(_sx, _sy); +} + +cObject::~cObject() +{ + destruct(); +} + +sPos cObject::getPosition() +{ + return pos; +} + +void cObject::setPosition(sPos _pos) +{ + pos = _pos; +} + + +void cObject::setPosition(int _x, int _y) +{ + pos.x = _x; + pos.y = _y; +} + + +sObject cObject::getObject() +{ + return sObject{pos, wColor, cScreen, sizeX, sizeY}; +} + +//protected +cObject::cObject() : pos({0,0}) , bSizeSet(false){} + +void cObject::setSize(int _sx, int _sy) +{ + if(bSizeSet) + return; + + bBlockRender = true; //Block inherited render capabilities of parent + + sizeX = _sx; + sizeY = _sy; + + //Initialize 2D array + cScreen = (char**) malloc(sizeof *cScreen * _sx); + for (int i = 0; i < _sx; i++) + cScreen[i] = (char*)malloc(sizeof *cScreen[i] * _sy); + + wColor = (WORD**)malloc(sizeof *wColor * _sx); + for (int i = 0; i < _sx; i++) + wColor[i] = (WORD*)malloc(sizeof *wColor[i] * _sy); + + for (int i = 0; i < sizeY; i++) { + for (int o = 0; o < sizeX; o++) { + cScreen[o][i] = NULL; + wColor[o][i] = _COL_DEFAULT; + } + } + + bSizeSet = true; +} + +void cObject::destruct() +{ + if(!bSizeSet) + return; + + for (int i = 0; i < sizeX; i++) { + free(cScreen[i]); + free(wColor[i]); + } + + free(cScreen); + free(wColor); + + bSizeSet = false; +} diff --git a/src/cObject.h b/src/cObject.h new file mode 100644 index 0000000..50b9d18 --- /dev/null +++ b/src/cObject.h @@ -0,0 +1,95 @@ +#pragma once +#include + +#include "cRender.h" + +#define _HIT_TOP 1 +#define _HIT_BOTTOM 2 +#define _HIT_LEFT 3 +#define _HIT_RIGHT 4 + +struct sObject +{ + sPos pos; + WORD **wColor; + char **cScreen; + int sizeX; + int sizeY; +}; + +/** cObject can be used standalone as well as inherited +* every cObject has its own framebuffer as well as position viariables to be moveable. +* cObject is used by cObjectHandler to manage all objects to be displayed. +* +* Minimal example for inheriting class +* +* +* class example : cObject +* { +* public: +* example() { setSize(10,5); } +* ~example() { destruct(); } +* }; +* +*/ +class cObject : public cRender +{ +public: + /** Sets the size to _sx x _sy + */ + cObject(int _sx, int _sy); + + virtual ~cObject(); + + /** Returns current position + */ + sPos getPosition(); + + /** Sets position to _pos + */ + void setPosition(sPos _pos); + /** Sets position by coordinates + */ + void setPosition(int _x, int _y); + + /** Returns sObject with framebuffer and current position + */ + sObject getObject(); + + /** Called by cObjecthandler if cObject is clicked + */ + virtual void onClick(sPos _pos, unsigned int _button){} + /** Called by cObjecthandler if cObject is active on keyboard input + * _pos decribes the relative position of mousepointer to origin of object + */ + virtual void onChar(unsigned char _c){} + + + /** Called by cObjectHandler if Object hits another during move operation + * return true to abort move, false to continue and allow overlap + */ + virtual bool onCollisionActive(unsigned int _hit, int _passiveObject) { return false; } + + /** Called by cObjectHandler if Object is hit by another object + * return any integer value to be identified by hitting object + */ + virtual int onCollisionPassive(unsigned int _hit) { return 0; } + + + + +protected: //For child classes + cObject(); + /** For inheriting classes: sets size of framebuffer + */ + void setSize(int _sx, int _sy); + + /** For inheriting classes: frees the framebuffer + */ + void destruct(); + +private: + //wColor, cScreen, sizeX and sizeY are inherited from cRender + sPos pos; + bool bSizeSet; +}; diff --git a/src/cObjectHandler.cpp b/src/cObjectHandler.cpp new file mode 100644 index 0000000..11c02e6 --- /dev/null +++ b/src/cObjectHandler.cpp @@ -0,0 +1,368 @@ +#include "cObjectHandler.h" + +cObjectHandler::cObjectHandler(cRender *_render, bool _enableInputMapping, bool _enableCollision) : cameraPosition ({0,0}), iActiveObject(0) +{ + render = _render; + + enableInputMapping = _enableInputMapping; + enableCollision = enableInputMapping ? _enableCollision : false; // Collision requires input mapping + + objects.push_back(NULL); //Create first Object as Catcher for Events + + buildHitmap(); +} + +int cObjectHandler::createObject(cObject *_object) +{ + objects.push_back(_object); + + buildHitmap(); + return objects.size() - 1; +} + +int cObjectHandler::moveObject(int _object, sPos _pos, int _mode) +{ + if (_object >= objects.size()) //prevent segmentation faults + return 1; + + if (!objects[_object]) + return 1; + + sPos objPosition = objects[_object]->getPosition(); + sPos newPosition; + + if (_mode == _MOVE_RELATIVE) + newPosition = { objPosition.x + _pos.x, objPosition.y + _pos.y }; + else if (_mode == _MOVE_ABSOLUTE) + newPosition = _pos; + else if (_mode == _MOVE_FORCE_ABSOLUTE) + { + objects[_object]->setPosition(_pos); + return 0; + } + + sCollision coll; + + coll = checkCollision(newPosition, objects[_object]->getSize()); + + bool abort = false; + + if(coll.idc) + { + for(int i = 0; i < coll.idc; i++) + { + if(coll.idv[i] != _object) + abort += objects[_object]->onCollisionActive(0, objects[coll.idv[0]]->onCollisionPassive(0)); + } + } + + if(!abort) + objects[_object]->setPosition(newPosition); + + if(coll.idv) + free (coll.idv); + if(coll.hitv) + free (coll.hitv); + + buildHitmap(); + return 0; +} + +int cObjectHandler::destroyObject(int _object) +{ + if(!objects[_object]) + return 1; + + delete objects[_object]; + objects[_object] = NULL; + + buildHitmap(); + return 0; +} + +int cObjectHandler::write() +{ + render->clear(); + + for (unsigned long int i = 0; i < meshes.size(); i++) + { + if(meshes[i]) + { + moveWiremesh(i,{-cameraPosition.x, -cameraPosition.y, 0} ,_MOVE_RELATIVE); + meshes[i]->write(render); + moveWiremesh(i,{cameraPosition.x, cameraPosition.y, 0},_MOVE_RELATIVE); + } + } + + for (unsigned long int i = 0; i < objects.size(); i++) + { + if (objects[i]) // Check if objects[i] is existent + { + //Draw every Object + sObject obj = objects[i]->getObject(); //get Object #i + + for (int o = 0; o < obj.sizeY; o++) { //y axis + for (int p = 0; p < obj.sizeX; p++) { //x axis + if (obj.cScreen[p][o]) { //Dont overwrite empty pixels + sPos pos{ obj.pos.x + p - cameraPosition.x, + obj.pos.y + o - cameraPosition.y }; + render->drawPoint(obj.cScreen[p][o], pos, true, obj.wColor[p][o]); + } + } + } + } + } + + return 0; +} + +int cObjectHandler::clickEvent(sPos _pos, unsigned int _button) +{ + if(_pos.x >= iHitMap.size()) + return 1; + if(_pos.y >= iHitMap[_pos.x].size()) + return 1; + + + if(objects[ iHitMap[_pos.x][_pos.y] ]) + { + sPos rel_pos; + sPos obj_pos = objects[ iHitMap[_pos.x][_pos.y] ]->getPosition(); + rel_pos.x = _pos.x - obj_pos.x + cameraPosition.x; + rel_pos.y = _pos.y - obj_pos.y + cameraPosition.y; + + iActiveObject = iHitMap[_pos.x][_pos.y]; //Set active object + objects[ iHitMap[_pos.x][_pos.y] ]->onClick(rel_pos, _button); + } + else + return 1; + + return 0; +} + +int cObjectHandler::charEvent(unsigned char _c) +{ + if(objects.size() > iActiveObject) + { + if(objects[iActiveObject]) + { + objects[iActiveObject]->onChar(_c); + } + else + return 1; + } + + return 0; +} + +void cObjectHandler::buildHitmap() +{ + if(!enableInputMapping) + return; + + //Rebuild 2D vector + sPos size = render->getSize(); + + vector cp; + + while(size.y > cp.size()) + { + cp.push_back(0); + } + + while (size.x > iHitMap.size()) + { + iHitMap.push_back(cp); + } + + while (size.x <= iHitMap.size()) + { + iHitMap.pop_back(); + } + for(unsigned int x = 0; x < iHitMap.size(); x++) + { + for(unsigned int y = 0; y < iHitMap[x].size(); y++) + { + iHitMap[x][y] = 0; + } + } + //Write object IDs to iHitMap + for(unsigned int i = 0; i < objects.size(); i++) + { + if(objects[i]) + { + sPos oPos = objects[i]->getPosition(); + sPos oSize = objects[i]->getSize(); + + oPos.x -= cameraPosition.x; + oPos.y -= cameraPosition.y; + + for(int x = oPos.x; x < oPos.x + oSize.x; x++) + { + for(int y = oPos.y; y < oPos.y + oSize.y; y++) + { + if((x < size.x && y < size.y) && (x >= 0 && y >= 0)) //Objects can be outside the screen. + iHitMap[x][y] = i; + }//for + }//for + }//if + }//for +}//buildHitmap + +void cObjectHandler::focusNext() +{ + iActiveObject++; + + if(iActiveObject >= objects.size()) + iActiveObject = 0; +} + +void cObjectHandler::focus(unsigned int _id) +{ + if(_id >= objects.size()) + iActiveObject = objects.size(); + else + iActiveObject = _id; +} + +int cObjectHandler::createWiremesh(cWiremesh *_mesh) +{ + meshes.push_back(_mesh); + + return meshes.size() - 1; +} + +int cObjectHandler::moveWiremesh(int _mesh, sCoord3d _pos, int _mode) +{ + if (_mesh >= meshes.size()) //prevent segmentation faults + return 1; + + if (!meshes[_mesh]) + return 1; + + sCoord3d meshPosition = meshes[_mesh]->getPosition(); + + if (_mode == _MOVE_RELATIVE) + meshes[_mesh]->setPosition(meshPosition + _pos); + else if (_mode == _MOVE_ABSOLUTE) + meshes[_mesh]->setPosition(_pos); + + return 0; +} + +int cObjectHandler::destroyWiremesh(int _mesh) +{ + if(!meshes[_mesh]) + return 1; + + delete meshes[_mesh]; + meshes[_mesh] = NULL; + + return 0; +} + +int cObjectHandler::rotateWiremesh(int _mesh, sCoord3d _angle) +{ + if (_mesh >= meshes.size()) //prevent segmentation faults + return 1; + + if (!meshes[_mesh]) + return 1; + + meshes[_mesh]->rotate(_angle); + + return 0; +} + +void cObjectHandler::setCameraPosition(sPos _pos, int _mode) +{ + if(_mode == _MOVE_ABSOLUTE) + cameraPosition = _pos; + else if(_mode == _MOVE_RELATIVE) + { + cameraPosition.x += _pos.x; + cameraPosition.y += _pos.y; + } + + buildHitmap(); +} + +sPos cObjectHandler::getCameraPosition() +{ + return cameraPosition; +} + +sCollision cObjectHandler::checkCollision(sPos _pos, sPos _size) +{ + sCollision ret; + vector collisions; + vector hitTypes; + ret.idc = 0; + ret.idv = NULL; + ret.hitv = NULL; + + if(!enableCollision) + return ret; + + int sizeX, sizeY; + + sizeX = render->getSize().x; + sizeY = render->getSize().y; + + //The mother of if-statements + //No collision for offscreen objects + if( (_pos.x < cameraPosition.x && _pos.x + _size.x + cameraPosition.x < 0) || + (_pos.x - cameraPosition.x >= iHitMap.size() && _pos.x + _size.x - cameraPosition.x >= iHitMap.size()) || + (_pos.y < cameraPosition.y && _pos.y + _size.y + cameraPosition.y < 0) || + (_pos.y - cameraPosition.y >= iHitMap[0].size() && _pos.y + _size.y - cameraPosition.y >= iHitMap[0].size()) ) + return ret; + + for(int x = _pos.x - cameraPosition.x; x < _pos.x + _size.x - cameraPosition.x; x++) + { + for(int y = _pos.y - cameraPosition.y; y < _pos.y + _size.y - cameraPosition.y; y++) + { + if(!(x >= sizeX || x < 0 || y >= sizeY || y < 0)) + { + if(iHitMap[x][y]) + collisions.push_back(iHitMap[x][y]); + } + } + } + + //Since Object can hit on multiple Pixels, duplications can occur. + //Sort and set duplicates to zero + //-> zeros are at front of vector + for(unsigned int swaps = 1; swaps > 0;) + { + swaps = 0; + + for(unsigned int i = 0; i < collisions.size() - 1; i++) + { + if(collisions[i] > collisions[i + 1]) + { + swaps ++; + unsigned int tmp = 0; + + tmp = collisions[i]; + collisions[i] = collisions[i + 1]; + collisions[i + 1] = tmp; + } + if(collisions[i] == collisions[i + 1]) + collisions[i] = 0; + } + } + + //Since every empty entry is in front, pop them + while(!collisions.front()) + collisions.erase(collisions.begin()); + + ret.idc = collisions.size(); + ret.idv = (unsigned int*) malloc( sizeof(*ret.idv) * ret.idc ); + + for(unsigned int i = 0; i < ret.idc; i++) + { + ret.idv[i] = collisions[i]; + } + + return ret; +} diff --git a/src/cObjectHandler.h b/src/cObjectHandler.h new file mode 100644 index 0000000..4a0306b --- /dev/null +++ b/src/cObjectHandler.h @@ -0,0 +1,118 @@ +#pragma once + +#include + +#include "cObject.h" +#include "cWiremesh.h" + +//movemodes +#define _MOVE_RELATIVE 0 +#define _MOVE_ABSOLUTE 1 +#define _MOVE_FORCE_ABSOLUTE 2 + +using namespace std; + +struct sCollision +{ + unsigned int *idv; + int *hitv; + unsigned int idc; +}; + +/** +* Manages cObject and cWiremesh and writes them to a cRender framebuffer (Also works on cObject, since it inherits from cRender!). +* forwards input events to corresponding cObject. +* Runs collision checking for every move operation. This is very expensive, so deactivate if not needed (eg. for background animations etc)! +*/ +class cObjectHandler +{ +public: + /** + * *_render: pointer to instance of cRender all objects will be written to + * _enableCollision: activate collision checking globally. CAUTION: Collision requires InputMapping. If InputMapping is disabled, Collision will NOT WORK! + * _enableInputMapping: activate Input mapping for mouse and keyboard events + */ + explicit cObjectHandler(cRender *_render, bool _enableInputMapping = true, bool _enableCollision = true); + + /** + * Adds _object to managed objects vector + * returns Identifier for newly created vector + */ + int createObject(cObject *_object); + + /** + * Alters position of _object by _pos either relative to old position or Absolute + * Depending on selected _mode (_MOVE_RELATIVE / _MOVE_ABSOLUTE / _MOVE_ABSOLUTE). + * _MOVE_ABSOLUTE not recommended: Collision is only checked at destination. To ensure initialisation, use _MOVE_FORCE_ABSOLUTE! + */ + int moveObject(int _object, sPos _pos, int _mode); + + /** + * removes _object from vector after deleting it + */ + int destroyObject(int _object); + + /** + * Analog to createObject() + */ + int createWiremesh(cWiremesh *_mesh); + + int moveWiremesh(int _mesh, sCoord3d _pos, int _mode); + + int rotateWiremesh(int _mesh, sCoord3d _angle); + + int destroyWiremesh(int _mesh); + + + void setCameraPosition(sPos _pos, int _mode); + + sPos getCameraPosition(); + + + /** + * writes all objects in objects[] to render buffer + */ + int write(); + + + /** + * Calls onClick of cObject at _pos, focuses Object + * returns 0 if successfull, 1 if no Object is at _pos + */ + int clickEvent(sPos _pos, unsigned int _button); + + /** + * Calls onChar of active cObject, default 0 + * returns 0 if successfull, 1 if no Object or destroyed Object is empty + */ + int charEvent(unsigned char _c); + + /** + * Focuses next Object + */ + void focusNext(); + + /** + * Focuses Object by id. + * 0 is empty by default and can be used to unfocus + */ + void focus(unsigned int _id); + + +private: + /** + * This function is very expensive! Only use when needed! + */ + sCollision checkCollision(sPos _pos, sPos _size); + + void buildHitmap(); + + vector objects; + vector meshes; + vector< vector > iHitMap; + cRender *render; + unsigned long int iActiveObject; + sPos cameraPosition; + bool enableCollision; + bool enableInputMapping; +}; diff --git a/src/cRender.cpp b/src/cRender.cpp new file mode 100644 index 0000000..9fbdc8f --- /dev/null +++ b/src/cRender.cpp @@ -0,0 +1,380 @@ +#include "cRender.h" + + +cRender::cRender(char _backound, WORD _color, int _sx, int _sy) +{ + bBlockRender = false; //If this Constructor is used, this instance is not inherited, thus render() doesn't need to be blocked + iLastError = _OK_; + sizeX = 0; + sizeY = 0; + + cBackound = _backound; + wBackColor = _color; + +#ifdef __linux__ //In Linux, setting Console size is not supported, so it gets Size of Console (Window) instead. + + wDefColor = _COL_DEFAULT; + + //Set up console + setAlternateBufferScreen(true); + setConsoleCursor(false); + + setBufferSize( getConsoleWindowSize() ); + + if(sizeX < _sx || sizeY < _sy) //Notify Program tha screen is too small for desired Size + iLastError = _ERR_SCREEN_TOO_SMALL_; + +#elif _WIN32 //Windows Specific Code + hstdout = GetStdHandle(STD_OUTPUT_HANDLE); //get handle + + GetConsoleScreenBufferInfo(hstdout, &csbi); //get current console settings + wDefColor = csbi.wAttributes; //Get default console color + + SetConsoleWindowSize(_sx + 1, _sy + 1); //set the windows size to _sx * _sy (+1 so no scrolling accurs) + + setBufferSize({_sx,_sy}); +#endif //_WIN32 + + setConsoleEcho(false); + clear(true); //Init backround array + +}//render() + + +cRender::cRender() {} + +cRender::~cRender() +{ + if(bBlockRender) //Don't run destructor if inherited + return; + + for (int i = 0; i < sizeX; i++) { + free(cScreen[i]); + free(wColor[i]); + free(bChanged[i]); + } + + free(cScreen); + free(wColor); + free(bChanged); + + setConsoleEcho(true); + + #ifdef __linux__ + setConsoleCursor(true); + setAlternateBufferScreen(false); + #endif //__linux__ +} + +int cRender::drawPoint(char _c, sPos _pos, bool _overrideCollision, WORD _color) +{ + if (_pos.x >= sizeX || _pos.y >= sizeY || _pos.x < 0 || _pos.y < 0) + return _ERR_COORDINATES_INVALID_; + + if (cScreen[_pos.x][_pos.y] != cBackound && _overrideCollision != true) //detect Collsision + return _COLLISION_; + + cScreen[_pos.x][_pos.y] = _c; + if (_color == _COL_DEFAULT) //_COL_DEFAULT is NOT a proper colorcode! + wColor[_pos.x][_pos.y] = wDefColor; + else + wColor[_pos.x][_pos.y] = _color; + + if(!bBlockRender) //Changemap is not allocated in inherited Classes + bChanged[_pos.x][_pos.y] = true; + + return 0; +} + +int cRender::drawLine(char _c, sPos _pos1, sPos _pos2, bool _overrideCollision, WORD _color) +{ + if(_pos1.x > _pos2.x) + { + //Shit WILL go wrong + return drawLine(_c, _pos2, _pos1, _overrideCollision, _color); + } + + if (_pos1.x == _pos2.x) { //Horizontal line + for (int i = _pos1.y; i <= _pos2.y; i++) + { + drawPoint(_c, sPos{_pos1.x, i}, _overrideCollision, _color); + } + } + else if (_pos1.y == _pos2.y) { //Vertical line + for (int i = _pos1.x; i <= _pos2.x; i++) + { + drawPoint(_c, sPos{ i, _pos1.y }, _overrideCollision, _color); + } + } + else { //Diagonal Line + int dX = _pos1.x - _pos2.x; + int dY = _pos1.y - _pos2.y; + float fGradient = (float)dY / (float)dX; + + for (int i = 0; i <= abs(dX); i++) + { + drawPoint(_c, sPos{i + _pos1.x, (int)(i * fGradient + _pos1.y + 0.5)}, _overrideCollision, _color); //+0.5 for rounding error + + if(std::abs(fGradient) > 1.0) + { + int dy = (int)(((i + 1) * fGradient + _pos1.y + 0.5) - (i * fGradient + _pos1.y + 0.5)); + + if(dy > 0 && ((int)(i * fGradient + _pos1.y + 0.5) + dy) <= _pos2.y) + { + drawLine(_c, + sPos{i + _pos1.x, (int)(i * fGradient + _pos1.y + 0.5)}, + sPos{i + _pos1.x, (int)(i * fGradient + _pos1.y + 0.5) + dy }, + _overrideCollision, _color); + }//if + else if(dy < 0 && ((int)(i * fGradient + _pos1.y + 0.5) + dy) >= (_pos2.y) ) + { + drawLine(_c, + sPos{i + _pos1.x, (int)(i * fGradient + _pos1.y + 0.5) + dy }, + sPos{i + _pos1.x, (int)(i * fGradient + _pos1.y + 0.5)}, + _overrideCollision, _color); + }//else if + }//if + }//for + }//else + + return 0; +}//drawLine + +int cRender::drawText(string _s, sPos _pos, WORD _color) +{ + for (int i = 0; i < _s.length(); i++) + { + drawPoint(_s[i], sPos{ i + _pos.x,_pos.y }, true, _color); + } + return 0; +} + +int cRender::drawRectangle(char _border, char _fill, sPos _pos1, sPos _pos2, WORD _borderColor, WORD _fillColor) +{ + //Draw the four outside lines + drawLine(_border, _pos1, sPos{ _pos1.x, _pos2.y }, true, _borderColor); + drawLine(_border, _pos1, sPos{ _pos2.x, _pos1.y }, true, _borderColor); + drawLine(_border, sPos{ _pos1.x, _pos2.y }, _pos2, true, _borderColor); + drawLine(_border, sPos{ _pos2.x, _pos1.y }, _pos2, true, _borderColor); + + //Fill rectangle if _fill isn't NULL + if (_fill) { + for (int i = _pos1.y + 1; i < _pos2.y; i++) { + for (int o = _pos1.x + 1; o < _pos2.x; o++) { + drawPoint(_fill, sPos{ o,i }, true, _fillColor); + } + } + } + + return 0; +} + +int cRender::render(void) +{ + if (bBlockRender) + return _ERR_RENDER_BLOCKED_BY_CHILD_; + + //Resize screenbuffer if needed + setBufferSize( getConsoleWindowSize( ) ); + + for (int i = 0; i < sizeY; i++) { + for (int o = 0; o < sizeX; o++) { + if(bChanged[o][i]) + { + #ifdef _WIN32 + + gotoxy(o,i); + SetConsoleTextAttribute(hstdout, wColor[o][i] | _COL_INTENSITY); + //cout << cScreen[o][i]; + printf("%c", cScreen[o][i]); + + #elif __linux__ + //gotoxy(x,y) now included!! + char buffer[20]; + int cbuf = sprintf(buffer,"\e[%i;%iH\e[%im%c", i + 1, o + 1, wColor[o][i], cScreen[o][i]); + // Position Color Origin is at 1,1 + write (STDOUT_FILENO, buffer, cbuf); + + #endif //__linux__ + } + bChanged[o][i] = false; + } + } + return 0; +} + +int cRender::clear(bool _forceReRender) +{ + for (int i = 0; i < sizeY; i++) { + for (int o = 0; o < sizeX; o++) { + if(((cScreen[o][i] == cBackound) && (wColor[o][i] == wBackColor)) && !_forceReRender) + bChanged[o][i] = false; + else + { + cScreen[o][i] = cBackound; + wColor[o][i] = wBackColor; + bChanged[o][i] = true; + } + } + } + return 0; +} + +int cRender::clear() +{ + return clear(false); +} + + +#ifdef _WIN32 +//Source: http://www.cplusplus.com/forum/windows/121444/ +int cRender::SetConsoleWindowSize(int x, int y) +{ + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + + if (h == INVALID_HANDLE_VALUE) + return 1; + + CONSOLE_SCREEN_BUFFER_INFO bufferInfo; + if (!GetConsoleScreenBufferInfo(h, &bufferInfo)) + return 1; + + SMALL_RECT& winInfo = bufferInfo.srWindow; + COORD windowSize = { winInfo.Right - winInfo.Left + 1, winInfo.Bottom - winInfo.Top + 1 }; + + if (windowSize.X > x || windowSize.Y > y) + { + // window size needs to be adjusted before the buffer size can be reduced. + SMALL_RECT info = + { + 0, 0, + x < windowSize.X ? x - 1 : windowSize.X - 1, + y < windowSize.Y ? y - 1 : windowSize.Y - 1 + }; + + if (!SetConsoleWindowInfo(h, TRUE, &info)) + return 1; + } + + COORD size = { x, y }; + if (!SetConsoleScreenBufferSize(h, size)) + return 1; + + SMALL_RECT info = { 0, 0, x - 1, y - 1 }; + if (!SetConsoleWindowInfo(h, TRUE, &info)) + return 1; +} +#endif //_WIN32 + +int cRender::getLastError() +{ + return iLastError; +} + +#ifdef _WIN32 +void cRender::gotoxy( int x, int y ) +{ + COORD p = { x, y }; + SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), p ); +} + +#elif __linux__ + +sPos cRender::getConsoleWindowSize() +{ + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + + return {w.ws_col, w.ws_row}; +} + +void cRender::setAlternateBufferScreen(bool _enable) +{ + _enable ? write (STDOUT_FILENO, "\e[?47h", 6):write (STDOUT_FILENO, "\e[?47l", 6); +} + +void cRender::setConsoleCursor(bool _enable) +{ + _enable ? write (STDOUT_FILENO, "\e[?25h", 6) : write (STDOUT_FILENO, "\e[?25l", 6); +} + +#endif // __linux__ + +void cRender::setBufferSize(sPos _size) +{ + if(_size.x == sizeX && _size.y == sizeY) + return; + + if(sizeX!=0 && sizeY!=0) //resize. delete first + { + for (int i = 0; i < sizeX; i++) { + free(cScreen[i]); + free(wColor[i]); + free(bChanged[i]); + } + + free(cScreen); + free(wColor); + free(bChanged); + } + + sizeX = _size.x; + sizeY = _size.y; + + //Initialize 2D array + cScreen = (char**)malloc(sizeof *cScreen * sizeX); + for (int i = 0; i < sizeX; i++) + cScreen[i] = (char*)malloc(sizeof *cScreen[i] * sizeY); + + wColor = (WORD**)malloc(sizeof *wColor * sizeX); + for (int i = 0; i < sizeX; i++) + wColor[i] = (WORD*)malloc(sizeof *wColor[i] * sizeY); + + bChanged = (bool**)malloc(sizeof *bChanged * sizeX); + for (int i = 0; i < sizeX; i++) + bChanged[i] = (bool*)malloc(sizeof *bChanged[i] * sizeY); + + clear(true); +} + +sPos cRender::getSize() +{ + return {sizeX, sizeY}; +} + +void cRender::forceReRender() +{ + for (int i = 0; i < sizeY; i++) { + for (int o = 0; o < sizeX; o++) { + bChanged[o][i] = true; + } + } +} + +void cRender::setConsoleEcho(bool _enable) +{ +#ifdef WIN32 + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + DWORD mode; + GetConsoleMode(hStdin, &mode); + + if( !_enable ) + mode &= ~ENABLE_ECHO_INPUT; + else + mode |= ENABLE_ECHO_INPUT; + + SetConsoleMode(hStdin, mode ); + +#elif __linux__ + /*struct termios tty; + tcgetattr(STDIN_FILENO, &tty); + if( !_enable ) + tty.c_lflag &= ~ECHO; + else + tty.c_lflag |= ECHO; + + (void) tcsetattr(STDIN_FILENO, TCSANOW, &tty);*/ + + _enable ? write (STDOUT_FILENO, "\e[?8h", 5) : write (STDOUT_FILENO, "\e[?8l", 5); +#endif //__linux__ +} diff --git a/src/cRender.h b/src/cRender.h new file mode 100644 index 0000000..415db6e --- /dev/null +++ b/src/cRender.h @@ -0,0 +1,177 @@ +#pragma once + +#include +#include +#include +#include +#include + +#ifdef __linux__ + #include + #include + + typedef int WORD; +#elif _WIN32 + #include +#else + #error "Platforn not supported" +#endif + +//errors +#define _OK_ 0 +#define _ERR_ 1 +#define _ERR_COORDINATES_INVALID_ 2 +#define _ERR_RENDER_BLOCKED_BY_CHILD_ 3 +#define _ERR_SCREEN_TOO_SMALL_ 4 + +#define _COLLISION_ 255 + +//Colors +#ifdef _WIN32 + #define _COL_BLACK 0x00 + #define _COL_BLUE 0x01 + #define _COL_GREEN 0x02 + #define _COL_YELLOW 0x0E + #define _COL_RED 0x04 + #define _COL_WHITE 0x0F + #define _COL_DARK_WHITE 0x07 + #define _COL_INTENSITY 0x08 + #define _COL_DEFAULT 0xFF +#elif __linux__ + #define _COL_BLACK 30 + #define _COL_BLUE 34 + #define _COL_GREEN 32 + #define _COL_YELLOW 33 + #define _COL_RED 31 + #define _COL_WHITE 37 + #define _COL_DEFAULT 0 + + //Linux Specific + #define _COL_BOLD 1 + #define _COL_BOLD_OFF 21 + #define _COL_UNDERLINE 4 + #define _COL_UNDERLINE_OFF 24 + #define _COL_INVERSE 7 + #define _COL_INVERSE_OFF 27 +#endif + +using namespace std; + +struct sPos +{ + int x; + int y; +}; +/** cRender manages a framebuffer the size of the console (window) it is run in. +* +* puts console in alternate screen mode +*/ +class cRender +{ +public: + /** Constructor + * sets cBackround[][] to _backround & wColor[][] to _color + * Resizes console window for Windows + * Sets Size to Console Window Size for Linux. Writes Error for _sx or _sy smaller than Screen. Get by getLastError() + */ + cRender(char _backound, WORD _color, int _sx, int _sy); + + virtual ~cRender(); + + /** Draws _c @ _pos in screenbuffer + * Returns _COLLOSION_ if _pos is already set to !cBackround && _overrideCollision isnt set + */ + int drawPoint(char _c, sPos _pos, bool _overrideCollision, WORD _color); + + /** draws Line from _pos1 to _pos2 in screenbuffer + * x Value of pos1 MUSTNT exceed the x value of pos2! + */ + int drawLine(char _c, sPos _pos1, sPos _pos2, bool _overrideCollision, WORD _color); + + /** Draws Text _s @ _pos in screenbuffer + * First char is @ _pos + */ + int drawText(string _s, sPos _pos, WORD _color); + + /** writes rectangle to screenbuffer + * x Value of pos1 MUSTNT exceed the x value of pos2! + */ + int drawRectangle(char _border, char _fill, sPos _pos1, sPos _pos2, WORD _borderColor, WORD _fillColor); + + /** Dumps screenbuffer to stdout + * prints changed pixels + */ + int render(void); + + /** clears cScreen + wColor + * for _forceReRender == true, the bChanged[][] is set to true to force Re-Render of whole Screen + * clear(void) calls clear(_forceReRender = false) + */ + int clear(); + int clear(bool _forceReRender); + + /** Returns last Error that was not returnable + */ + int getLastError(); + + /** Returns size of screenbuffer + */ + sPos getSize(); + + +protected: + /** Empty Constructor for being inheritable + */ + cRender(); + + /** Sets screenbuffer size + * Uses sizeX, sizeY to determine previous screenbuffer size. Do NOT change sizeX, sizeY manually!! + */ + void setBufferSize(sPos _size); + + bool bBlockRender; + //* Used by children to block render function + + char **cScreen; + //* Pixel Map + WORD **wColor; + //* Color Map + bool **bChanged; + //* Pixel Change Map + + char cBackound; + //* Default backround + WORD wBackColor; + //* Default backround color + int sizeX, sizeY; + //* Size of screen array + +#ifdef _WIN32 + HANDLE hstdout; + CONSOLE_SCREEN_BUFFER_INFO csbi; +#endif + + WORD wDefColor; + //* Default Color + + int iLastError; + +private: +#ifdef _WIN32 + int SetConsoleWindowSize(int x, int y); + //Slightly adapted from: http://www.cplusplus.com/forum/windows/121444/ + + void gotoxy( int x, int y ); +#endif + + void forceReRender(); + + void setConsoleEcho(bool _enable); +#ifdef __linux__ + sPos getConsoleWindowSize(); + + void setConsoleCursor(bool _enable); + + void setAlternateBufferScreen(bool _enable); +#endif +}; diff --git a/src/cWiremesh.cpp b/src/cWiremesh.cpp new file mode 100644 index 0000000..62fee0d --- /dev/null +++ b/src/cWiremesh.cpp @@ -0,0 +1,132 @@ +#include "cWiremesh.h" + +cWiremesh::cWiremesh() : position({0,0,0}), angle({0,0,0}) { } + +cWiremesh::~cWiremesh() { } + +void cWiremesh::addVector(sCoord3d _origin, sCoord3d _vector, char _char, WORD _color) +{ + vectors.push_back(sVector{_origin, _vector, _char, _color}); +} + +void cWiremesh::rotate(sCoord3d _val) +{ + angle = angle + _val; +} + +void cWiremesh::reset() +{ + vectors.clear(); +} + +void cWiremesh::write(cRender *_render) +{ + if(!_render) + return; + + sPos porigin = _render->getSize(); + sCoord3d origin = {porigin.x / 2, porigin.y / 2, 0}; + + for(long unsigned int i = 0; i < vectors.size(); i++) + { + sCoord3d vorigin = applyRotation(vectors[i].origin, angle); + sCoord3d vdirection = applyRotation(vectors[i].direction, angle); + + _render->drawLine(vectors[i].c, + translate(vorigin + position, origin), + translate(vorigin + vdirection + position, origin), + true, vectors[i].color); + } +} + +sPos cWiremesh::translate(sCoord3d _coord, sCoord3d _origin) +{ + sPos ret; + + ret.x = (int)((float)_coord.x - ((float)_coord.z / (float)_DEPTH * (float)(_coord.x - _origin.x))); + ret.y = (int)((float)_coord.y - ((float)_coord.z / (float)_DEPTH * (float)(_coord.y - _origin.y))); + + return ret; +} + +sCoord3d cWiremesh::getPosition() +{ + return position; +} + +void cWiremesh::setPosition(int _x, int _y, int _z) +{ + position = {_x, _y, _z}; +} + +void cWiremesh::setPosition(sCoord3d _pos) +{ + position = _pos; +} + +void cWiremesh::scale(float _scalar) +{ + for(unsigned long int i = 0; i < vectors.size(); i++) + { + vectors[i].origin.x = (int)((float)vectors[i].origin.x * _scalar); + vectors[i].origin.y = (int)((float)vectors[i].origin.y * _scalar); + vectors[i].origin.z = (int)((float)vectors[i].origin.z * _scalar); + + vectors[i].direction.x = (int)((float)vectors[i].direction.x * _scalar); + vectors[i].direction.y = (int)((float)vectors[i].direction.y * _scalar); + vectors[i].direction.z = (int)((float)vectors[i].direction.z * _scalar); + } +} + +sCoord3d cWiremesh::applyRotation(sCoord3d _vector, sCoord3d _angle) +{ + sCoord3d ret = _vector; + + //Perform some algebra-magic + //couldn't be bothered to implement or use a matrix class + + if(_angle.x) + { + float rads = (float)_angle.x * PI / 180.0; + + ret.y = (int)( + (float)_vector.y * cos(rads) - + (float)_vector.z * sin(rads) + ); + ret.z = (int)( + (float)_vector.y * sin(rads) + + (float)_vector.z * cos(rads) + ); + } + if(_angle.y) + { + float rads = (float)_angle.y * PI / 180.0; + sCoord3d tmp = ret; + + ret.x = (int)( + (float)tmp.x * cos(rads) + + (float)tmp.z * sin(rads) + ); + + ret.z = (int)( + - (float)tmp.x * sin(rads) + + (float)tmp.z * cos(rads) + ); + } + if(_angle.z) + { + float rads = (float)_angle.z * PI / 180.0; + sCoord3d tmp = ret; + + ret.x = (int) ( + (float)tmp.x * cos(rads) - + (float)tmp.y * sin(rads) + ); + ret.y = (int) ( + (float)tmp.x * sin(rads) + + (float)tmp.y * cos(rads) + ); + } + + return ret; +} diff --git a/src/cWiremesh.h b/src/cWiremesh.h new file mode 100644 index 0000000..82d3bd6 --- /dev/null +++ b/src/cWiremesh.h @@ -0,0 +1,104 @@ +#pragma once + +#include +#include + +#include "cRender.h" + +#define _DEPTH 99 +#define PI 3.14159265 + +struct sCoord3d +{ + int x; + int y; + int z; + + sCoord3d operator+(sCoord3d p) + { + sCoord3d ret; + ret.x = x + p.x; + ret.y = y + p.y; + ret.z = z + p.z; + return ret; + } + + sCoord3d operator-(sCoord3d p) + { + sCoord3d ret; + ret.x = x - p.x; + ret.y = y - p.y; + ret.z = z - p.z; + return ret; + } +}; + +struct sVector +{ + sCoord3d origin; + sCoord3d direction; + + char c; + WORD color; +}; + +/** +* cWiremesh stores 3D objects as multiple vectors. it can write itself on a cRender framebuffer. +*/ +class cWiremesh +{ +public: + + cWiremesh(); + + virtual ~cWiremesh(); + + /** + * Add a line from _origin to (_origin + _vector) in 3D space. + */ + void addVector(sCoord3d _origin, sCoord3d _vector, char _char, WORD _color); + + /** + * Rotates by (x,y,z) degrees around the corresponding axis. + * Rotation is stored seperatately from original vectors while they stay untouched to prevent growing rounding errors by repeated rotation. + * + * Rotation is applied relative to the origin of this wiremsh. + */ + void rotate(sCoord3d _val); + + /** + * Scales by _scalar. The scalar is directly applied to all vectors. Be wary of growing rounding errors! + */ + void scale(float _scalar); + + sCoord3d getPosition(); + + void setPosition(int _x, int _y, int _z); + + void setPosition(sCoord3d _pos); + + /** + * clear this wiremesh + */ + void reset(); + + /** + * Translates wiremesh into 2D space after applying rotation to each vector. + * The vanishing point is set to the center of _render with depth _DEPTH. Alter _DEPTH to achieve optimal resultst. + */ + void write(cRender *_render); + +protected: + +private: + + sPos translate(sCoord3d _coord, sCoord3d _origin); + + sCoord3d applyRotation(sCoord3d _vector, sCoord3d _angle); + + sCoord3d position; + + sCoord3d angle; + + std::vector vectors; +}; diff --git a/test.cpp b/test.cpp deleted file mode 100644 index b09e6ec..0000000 --- a/test.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include - -#include "version.h" - -#include "cRender.h" -#include "cObject.h" -#include "cObjectHandler.h" -#include "cInput.h" -#include "cWiremesh.h" - -//#include "testobject.h" - -class testobject : cObject -{ -public: - testobject() - { - setSize(10,5); - cc = 0; - kc = 0; - - drawRectangle('#', NULL, {0,0}, {9,4}, _COL_GREEN, _COL_DEFAULT); - } - - ~testobject() { destruct(); } - - virtual void onClick(sPos _pos, unsigned int _button) - { - cc++; - drawText(std::to_string(cc), {2,2}, _COL_RED); - - drawPoint('Q', _pos, true, _COL_YELLOW); - } - - virtual bool onCollisionActive(unsigned int _hit, int _passiveObject){ - kc++; - drawText(std::to_string(kc), {0,0}, _COL_RED); - return true; - } - - virtual void onChar(unsigned char _c) { drawPoint(_c, {1,1},true, _COL_BLUE); } -private: - int cc; - int kc; -}; - -int main(int argc, char* argv[]) -{ - cRender render(' ', _COL_DEFAULT, 30,30); - cObjectHandler handler(&render); - cObject ver(45,1); - testobject obj2; - - cInput input; - - unsigned int framecounter = 0; - bool loop = true; - - if(argc > 1) - { - loop = false; - } - - render.render(); - - ver.drawText(DATE, {20,0}, _COL_WHITE); - ver.drawText(VERSTRING, {0,0}, _COL_WHITE); - int iver = handler.createObject(&ver); - handler.moveObject(iver, {0,0}, _MOVE_FORCE_ABSOLUTE); - - int iobj2 = handler.createObject((cObject*)&obj2); - handler.moveObject(iobj2, {3,3}, _MOVE_FORCE_ABSOLUTE); - - sPos middle = render.getSize(); - middle.x /= 2; - middle.y /= 2; - - while( loop ) - { - sInputEvent ie = input.poll(); - - if(ie.type != _EVENT_NULL) - { - if(ie.type == _EVENT_KEY) - { - switch (ie.c) - { - case 'A'://up - handler.setCameraPosition({0,-1}, _MOVE_RELATIVE); - break; - case 'B'://down - handler.setCameraPosition({0,1}, _MOVE_RELATIVE); - break; - case 'C'://right - handler.setCameraPosition({1,0}, _MOVE_RELATIVE); - break; - case 'D'://left - handler.setCameraPosition({-1,0}, _MOVE_RELATIVE); - break; - }; - } - else if (ie.type == _EVENT_MOUSE) - { - if(ie.b == 0) - handler.clickEvent({ie.x, ie.y}, 0); - } - else if (ie.type == _EVENT_CHAR) - { - //handler.charEvent(ie.c); - switch(ie.c) - { - case 'w': - handler.moveObject(iobj2, {0,-1}, _MOVE_RELATIVE); - break; - case 's': - handler.moveObject(iobj2, {0,1}, _MOVE_RELATIVE); - break; - case 'a': - handler.moveObject(iobj2, {-1,0}, _MOVE_RELATIVE); - break; - case 'd': - handler.moveObject(iobj2, {1,0}, _MOVE_RELATIVE); - break; - }; - } - else if (ie.type == _EVENT_TERM) - { - return 0; - } - } - - handler.write(); - render.render(); - framecounter++; - - if(loop) - usleep(10*1000); - } - - return 0; -} diff --git a/test_old.cpp b/test_old.cpp deleted file mode 100644 index 313b632..0000000 --- a/test_old.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include - -#include "version.h" - -#include "cRender.h" -#include "cObject.h" -#include "cObjectHandler.h" -#include "cInput.h" -#include "cWiremesh.h" - -//#include "testobject.h" - -class testobject : cObject -{ -public: - testobject() - { - setSize(10,5); - cc = 0; - - drawRectangle('#', NULL, {0,0}, {9,4}, _COL_GREEN, _COL_DEFAULT); - } - - ~testobject() { destruct(); } - - virtual void onClick(sPos _pos, unsigned int _button) - { - cc++; - drawText(std::to_string(cc), {2,2}, _COL_RED); - - drawPoint('Q', _pos, true, _COL_YELLOW); - } - - virtual void onChar(unsigned char _c) { drawPoint(_c, {1,1},true, _COL_BLUE); } -private: - int cc; -}; - -int main(int argc, char* argv[]) -{ - cRender render(' ', _COL_DEFAULT, 30,30); - cObjectHandler handler(&render); - cObject ver(45,1); - cWiremesh obj; - testobject obj2; - - cInput input; - - unsigned int framecounter = 0; - bool loop = true; - - if(argc > 1) - { - loop = false; - } - - render.render(); - - ver.drawText(DATE, {20,0}, _COL_WHITE); - ver.drawText(VERSTRING, {0,0}, _COL_WHITE); - int iver = handler.createObject(&ver); - handler.moveObject(iver, {0,0}, _MOVE_ABSOLUTE); - - int x = 15; - int y = 15; - int z = 30; - - obj.addVector({-x,-y,z}, {2*x,0,0}, '+', _COL_RED); - obj.addVector({-x,-y,z}, {0,2*y,0}, '+', _COL_RED); - obj.addVector({-x,y,z}, {2*x,0,0}, '+', _COL_RED); - obj.addVector({x,-y,z}, {0,2*y,0}, '+', _COL_RED); - - obj.addVector({-x,-y,0}, {0,0,z}, ':', _COL_RED); - obj.addVector({x,-y,0}, {0,0,z}, ':', _COL_RED); - obj.addVector({-x,y,0}, {0,0,z}, ':', _COL_RED); - obj.addVector({x,y,0}, {0,0,z}, ':', _COL_RED); - - obj.addVector({-x,-y,0}, {2*x,0,0}, ',', _COL_RED); - obj.addVector({-x,-y,0}, {0,2*y,0}, ',', _COL_RED); - obj.addVector({-x,y,0}, {2*x,0,0}, ',', _COL_RED); - obj.addVector({x,-x,0}, {0,2*y,0}, ',', _COL_RED); - int imesh = handler.createWiremesh(&obj); - - int iobj2 = handler.createObject((cObject*)&obj2); - handler.moveObject(iobj2, {3,3}, _MOVE_ABSOLUTE); - - sPos middle = render.getSize(); - middle.x /= 2; - middle.y /= 2; - - handler.moveWiremesh(imesh,{middle.x,middle.y,0}, _MOVE_ABSOLUTE); - - while( loop ) - { - sInputEvent ie = input.poll(); - - if(ie.type != _EVENT_NULL) - { - if(ie.type == _EVENT_KEY) - { - switch (ie.c) - { - case 'A'://up - handler.setCameraPosition({0,-1}, _MOVE_RELATIVE); - break; - case 'B'://down - handler.setCameraPosition({0,1}, _MOVE_RELATIVE); - break; - case 'C'://right - handler.setCameraPosition({1,0}, _MOVE_RELATIVE); - break; - case 'D'://left - handler.setCameraPosition({-1,0}, _MOVE_RELATIVE); - break; - }; - } - else if (ie.type == _EVENT_MOUSE) - { - if(ie.b == 0) - handler.clickEvent({ie.x, ie.y}, 0); - } - else if (ie.type == _EVENT_CHAR) - { - //handler.charEvent(ie.c); - switch(ie.c) - { - case 'w': - handler.rotateWiremesh(imesh,{-10,0,0}); - break; - case 's': - handler.rotateWiremesh(imesh,{10,0,0}); - break; - case 'a': - handler.rotateWiremesh(imesh,{0,-10,0}); - break; - case 'd': - handler.rotateWiremesh(imesh,{0,10,0}); - break; - case 'q': - handler.rotateWiremesh(imesh,{0,0,-10}); - break; - case 'e': - handler.rotateWiremesh(imesh,{0,0,10}); - break; - }; - } - else if (ie.type == _EVENT_TERM) - { - return 0; - } - } - - handler.rotateWiremesh(imesh,{1,1,1}); - - handler.write(); - render.render(); - framecounter++; - - if(loop) - usleep(10*1000); - } - - return 0; -} -- cgit v1.2.3