summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jonas Gunz <himself@jonasgunz.de> 2019-03-06 15:04:57 +0100
committerGravatar Jonas Gunz <himself@jonasgunz.de> 2019-03-06 15:04:57 +0100
commitf439ae911923ee70937592b1ee535e8e8e133808 (patch)
tree7e23e023d0187caf2d81b26217b3a484bd37f799 /src
parent6856fcf08c8c4686ddf9e5cb60862184e15d6f0b (diff)
downloadtermgl-f439ae911923ee70937592b1ee535e8e8e133808.tar.gz
Directory updates
Moved source files to ./src and exmaple and test to ./example Updated Makefile and .doxygen to use those directorys
Diffstat (limited to 'src')
-rw-r--r--src/cInput.cpp73
-rw-r--r--src/cInput.h58
-rw-r--r--src/cObject.cpp82
-rw-r--r--src/cObject.h95
-rw-r--r--src/cObjectHandler.cpp368
-rw-r--r--src/cObjectHandler.h118
-rw-r--r--src/cRender.cpp380
-rw-r--r--src/cRender.h177
-rw-r--r--src/cWiremesh.cpp132
-rw-r--r--src/cWiremesh.h104
10 files changed, 1587 insertions, 0 deletions
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 <stdio.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/select.h>
+
+#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 <stdlib.h>
+
+#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<unsigned int> 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<unsigned int> collisions;
+ vector<int> 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 <vector>
+
+#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<cObject*> objects;
+ vector<cWiremesh*> meshes;
+ vector< vector<unsigned int> > 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 <stdlib.h>
+#include <stdio.h>
+#include <string>
+#include <cmath>
+#include <termios.h>
+
+#ifdef __linux__
+ #include <unistd.h>
+ #include <sys/ioctl.h>
+
+ typedef int WORD;
+#elif _WIN32
+ #include <Windows.h>
+#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 <vector>
+#include <cmath>
+
+#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<sVector> vectors;
+};