Store in GIT
@@ -0,0 +1,76 @@
|
||||
#include "Button.h"
|
||||
#include <string>
|
||||
#include "Util.h"
|
||||
#include "Vector.h"
|
||||
#include "Cursor.h"
|
||||
|
||||
Button::Button(const std::string & text, Vec2f position, float width, float height) : Text(text,position)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->planePosition = position;
|
||||
|
||||
cursorOnButton = false;
|
||||
alfa = 0.5f;
|
||||
background = Vec3f(10, 10, 10);
|
||||
//foreground = Vec3f(255, 255, 255);
|
||||
this->setColor(Vec3f(255, 255, 255));
|
||||
|
||||
this->position.x += width / 2 - textWidth / 2;
|
||||
this->position.y += height / 2 - textHeight / 2;
|
||||
}
|
||||
|
||||
Button::~Button()
|
||||
{
|
||||
/*if (action != nullptr)
|
||||
delete action;*/
|
||||
}
|
||||
|
||||
void Button::draw(void)
|
||||
{
|
||||
|
||||
glColor4f(background.x/255.0f, background.y / 255.0f, background.z / 255.0f, alfa);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(planePosition.x, planePosition.y);
|
||||
glVertex2f(planePosition.x, planePosition.y + height);
|
||||
glVertex2f(planePosition.x + width, planePosition.y + height);
|
||||
glVertex2f(planePosition.x + width, planePosition.y);
|
||||
glEnd();
|
||||
|
||||
/*glColor4f(foreground.x / 255.0f, foreground.y / 255.0f, foreground.z / 255.0f, 1.0f);
|
||||
Util::glutBitmapString(text, position.x, position.y+height/2+14/2);*/
|
||||
Text::draw();
|
||||
}
|
||||
|
||||
void Button::update(int x, int y)
|
||||
{
|
||||
cursorOnButton =
|
||||
(x > planePosition.x && x < planePosition.x + width) &&
|
||||
y > planePosition.y && y < planePosition.y + height;
|
||||
|
||||
|
||||
if (cursorOnButton)
|
||||
alfa = 1.0f;
|
||||
else
|
||||
alfa = 0.5f;
|
||||
|
||||
if (cursorOnButton && Cursor::getInstance()->clicked)
|
||||
if(action != nullptr)
|
||||
action(this);
|
||||
}
|
||||
|
||||
void Button::addAction(action_function action)
|
||||
{
|
||||
this->action = action;
|
||||
}
|
||||
|
||||
void Button::setForeground(Vec3f color)
|
||||
{
|
||||
this->setColor(color);
|
||||
}
|
||||
|
||||
void Button::setBackground(Vec3f color)
|
||||
{
|
||||
background = color;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include "Text.h"
|
||||
|
||||
|
||||
|
||||
class Button : public Text
|
||||
{
|
||||
private:
|
||||
typedef void(*action_function)(Button* b);
|
||||
float width, height;
|
||||
Vec3f background;
|
||||
Vec2f planePosition;
|
||||
bool cursorOnButton;
|
||||
float alfa;
|
||||
action_function action = nullptr;
|
||||
public:
|
||||
Button(const std::string &text, Vec2f position, float width, float height);
|
||||
~Button();
|
||||
|
||||
|
||||
|
||||
void draw();
|
||||
void update(int x, int y);
|
||||
|
||||
void addAction(action_function action);
|
||||
|
||||
void setForeground(Vec3f color);
|
||||
void setBackground(Vec3f color);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(CrystalPoint)
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
"*.cc"
|
||||
)
|
||||
|
||||
add_executable(CrystalPoint ${SOURCE_FILES})
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GLUT REQUIRED)
|
||||
find_package(OpenAL REQUIRED)
|
||||
include_directories( ${OPENGL_INCLUDE_DIRS} ${GLUT_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIRS} )
|
||||
target_link_libraries(CrystalPoint ${OPENGL_LIBRARIES} ${GLUT_LIBRARY} ${OPENAL_LIBRARY} )
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -lpthread")
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "Cursor.h"
|
||||
#include <GL/freeglut.h>
|
||||
#include <cmath>
|
||||
#include "Racer.h"
|
||||
|
||||
Cursor* Cursor::instance = NULL;
|
||||
|
||||
Cursor::Cursor()
|
||||
{
|
||||
enabled = false;
|
||||
mousePosition = Vec2f(Racer::width / 2, Racer::height / 2);
|
||||
clicked = false;
|
||||
}
|
||||
|
||||
Cursor::~Cursor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Cursor* Cursor::getInstance(void)
|
||||
{
|
||||
if (instance == nullptr)
|
||||
instance = new Cursor();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Cursor::enable(bool enable)
|
||||
{
|
||||
enabled = enable;
|
||||
}
|
||||
|
||||
bool Cursor::isEnabled(void)
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void Cursor::draw(void)
|
||||
{
|
||||
//Draw Cursor
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, Racer::width, Racer::height, 0, -10, 10);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glColor4f(1, cos(glutGet(GLUT_ELAPSED_TIME) / 1000.0f), sin(glutGet(GLUT_ELAPSED_TIME) / 1000.0f), 1);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex2f(mousePosition.x, mousePosition.y);
|
||||
glVertex2f(mousePosition.x + 15, mousePosition.y + 15);
|
||||
glVertex2f(mousePosition.x + 5, mousePosition.y + 20);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void Cursor::update(Vec2f newPosition)
|
||||
{
|
||||
if (newPosition.x < 0)
|
||||
newPosition.x = 0;
|
||||
|
||||
if (newPosition.y < 0)
|
||||
newPosition.y = 0;
|
||||
|
||||
if (newPosition.x > Racer::width)
|
||||
newPosition.x = Racer::width;
|
||||
|
||||
if (newPosition.y > Racer::height)
|
||||
newPosition.y = Racer::height;
|
||||
|
||||
mousePosition = newPosition;
|
||||
|
||||
if (clicked)
|
||||
clicked = !clicked;
|
||||
if (state != prev)
|
||||
if(state == GLUT_UP)
|
||||
clicked = true;
|
||||
prev = state;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "Vector.h"
|
||||
|
||||
class Cursor
|
||||
{
|
||||
private:
|
||||
Cursor();
|
||||
|
||||
static Cursor* instance;
|
||||
bool enabled;
|
||||
|
||||
public:
|
||||
Vec2f mousePosition;
|
||||
~Cursor();
|
||||
|
||||
static Cursor* getInstance(void);
|
||||
|
||||
void enable(bool enable);
|
||||
bool isEnabled(void);
|
||||
|
||||
bool clicked;
|
||||
int state, prev;
|
||||
|
||||
|
||||
void draw(void);
|
||||
void update(Vec2f newPosition);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "Entity.h"
|
||||
#include "cmath"
|
||||
#include <GL/freeglut.h>
|
||||
#include "Model.h"
|
||||
|
||||
|
||||
Entity::Entity()
|
||||
{
|
||||
model = NULL;
|
||||
scale = 1;
|
||||
canCollide = true;
|
||||
}
|
||||
|
||||
|
||||
Entity::~Entity()
|
||||
{
|
||||
if(model)
|
||||
Model::unload(model);
|
||||
}
|
||||
|
||||
|
||||
void Entity::draw()
|
||||
{
|
||||
if (model)
|
||||
{
|
||||
glPushMatrix();
|
||||
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glRotatef(rotation.x, 1, 0, 0);
|
||||
glRotatef(rotation.y, 0, 1, 0);
|
||||
glRotatef(rotation.z, 0, 0, 1);
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
model->draw();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Entity::inObject(const Vec3f & point)
|
||||
{
|
||||
if (!model)
|
||||
return false;
|
||||
Vec3f center = position + model->center;
|
||||
float distance = ((point.x - center.x) * (point.x - center.x) + (point.z - center.z)*(point.z - center.z));
|
||||
if (distance < model->radius*scale*model->radius*scale)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "Vector.h"
|
||||
class Model;
|
||||
|
||||
class Entity
|
||||
{
|
||||
public:
|
||||
Entity();
|
||||
~Entity();
|
||||
|
||||
Model* model;
|
||||
|
||||
virtual void draw();
|
||||
virtual void update(float elapsedTime) {};
|
||||
virtual void collide() {};
|
||||
|
||||
Vec3f position;
|
||||
Vec3f rotation;
|
||||
float scale;
|
||||
|
||||
bool canCollide;
|
||||
bool inObject(const Vec3f &position);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
#include "HeightMap.h"
|
||||
#include "stb_image.h"
|
||||
#include "Vector.h"
|
||||
|
||||
#include "LevelObject.h"
|
||||
|
||||
#include <GL/freeglut.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "World.h"
|
||||
|
||||
#define RED 0
|
||||
#define GREEN 1
|
||||
#define BLUE 2
|
||||
#define ALPHA 3
|
||||
|
||||
HeightMap::HeightMap(const std::string &file, World* world)
|
||||
{
|
||||
int bpp;
|
||||
unsigned char* imgData = stbi_load(file.c_str(), &width, &height, &bpp, 4);
|
||||
|
||||
auto heightAt = [&](int x, int y)
|
||||
{
|
||||
return (imgData[(x + y * width) * 4 ] / 256.0f) * 10.0f;
|
||||
};
|
||||
|
||||
auto valueAt = [&](int x, int y, int offset = 0)
|
||||
{
|
||||
return imgData[(x + y * width) * 4 + offset];
|
||||
};
|
||||
|
||||
std::vector<std::vector<Vec3f>> faceNormals(width-1, std::vector<Vec3f>(height-1, Vec3f(0,1,0)));
|
||||
for (int y = 0; y < height - 1; y++)
|
||||
{
|
||||
for (int x = 0; x < width - 1; x++)
|
||||
{
|
||||
int offsets[4][2] = { { 0, 0 },{ 1, 0 },{ 1, 1 },{ 0, 1 } };
|
||||
Vec3f ca(0, heightAt(x, y + 1) - heightAt(x, y), 1);
|
||||
Vec3f ba(1, heightAt(x + 1, y) - heightAt(x, y), 0);
|
||||
Vec3f normal = ca.cross(ba);
|
||||
normal.Normalize();
|
||||
faceNormals[x][y] = normal;
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < height-1; y++)
|
||||
{
|
||||
for (int x = 0; x < width-1; x++)
|
||||
{
|
||||
int offsets[4][2] = { { 0, 0 },{ 1, 0 },{ 1, 1 },{ 0, 1 } };
|
||||
|
||||
if (valueAt(x, y, GREEN) > 5)
|
||||
{
|
||||
ObjectTemplate obtp = world->getObjectFromValue(valueAt(x, y, GREEN));
|
||||
LevelObject* p = new LevelObject(obtp.file, Vec3f(x, heightAt(x, y), y), obtp.rotation, obtp.scale, obtp.canCollide);
|
||||
|
||||
world->addLevelObject(p);
|
||||
}
|
||||
if (valueAt(x, y, BLUE) > 10)
|
||||
{
|
||||
world->addStar(new Star(Vec3f(x, heightAt(x, y), y)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int xx = x + offsets[i][0];
|
||||
int yy = y + offsets[i][1];
|
||||
|
||||
Vec3f normal(0, 0, 0);
|
||||
if(xx < width-1 && yy < height-1)
|
||||
normal = normal + faceNormals[xx][yy];
|
||||
if(xx > 0 && yy < height-1)
|
||||
normal = normal + faceNormals[xx-1][yy];
|
||||
if (xx > 0 && yy > 0)
|
||||
normal = normal + faceNormals[xx-1][yy-1];
|
||||
if (yy > 0 && xx < width-1)
|
||||
normal = normal + faceNormals[xx][yy-1];
|
||||
normal.Normalize();
|
||||
|
||||
float h = heightAt(xx, yy);
|
||||
vertices.push_back(Vertex{ (float)(xx), h, (float)(yy),
|
||||
normal.x, normal.y, normal.z,
|
||||
(xx) / (float)height, (yy) / (float)width } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glGenTextures(1, &imageIndex);
|
||||
glBindTexture(GL_TEXTURE_2D, imageIndex);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0, //level
|
||||
GL_RGBA, //internal format
|
||||
width, //width
|
||||
height, //height
|
||||
0, //border
|
||||
GL_RGBA, //data format
|
||||
GL_UNSIGNED_BYTE, //data type
|
||||
imgData); //data
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
stbi_image_free(imgData);
|
||||
}
|
||||
|
||||
HeightMap::~HeightMap()
|
||||
{
|
||||
glDeleteTextures(1, &imageIndex);
|
||||
}
|
||||
|
||||
void HeightMap::Draw()
|
||||
{
|
||||
glEnable(GL_LIGHTING);
|
||||
float color[] = { 0.7f, 0.7f, 0.7f, 1 };
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, imageIndex);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
//glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), ((float*)vertices.data()) + 0);
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), ((float*)vertices.data()) + 6);
|
||||
glNormalPointer(GL_FLOAT, sizeof(Vertex), ((float*)vertices.data()) + 3);
|
||||
glDrawArrays(GL_QUADS, 0, vertices.size());
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
//glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
}
|
||||
|
||||
float HeightMap::GetHeight(float x, float y)
|
||||
{
|
||||
int ix = x;
|
||||
int iy = y;
|
||||
|
||||
int index = (ix + (width - 1) * iy) * 4;
|
||||
|
||||
if (index + 3 >= vertices.size())
|
||||
index = vertices.size() - 4;
|
||||
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
|
||||
Vertex& a = vertices[index];
|
||||
Vertex& b = vertices[index+1];
|
||||
Vertex& c = vertices[index+3];
|
||||
|
||||
float lowervalue = ((b.z - c.z)*(a.x - c.x) + (c.x - b.x)*(a.z - c.z));
|
||||
float labda1 = ((b.z - c.z)*(x - c.x) + (c.x - b.x)*(y - c.z)) / lowervalue;
|
||||
float labda2 = ((c.y - a.y)*(x - c.x) + (a.x - c.x)*(y - c.y)) / lowervalue;
|
||||
float labda3 = 1 - labda1 - labda2;
|
||||
|
||||
Vertex z = a * labda1 + b * labda2 + c * labda3;
|
||||
// Vertex z = (a * labda1) + (b * labda2) ;
|
||||
|
||||
return z.y;
|
||||
}
|
||||
|
||||
|
||||
int HeightMap::GetSize()
|
||||
{
|
||||
return height >= width ? height : width;
|
||||
}
|
||||
|
||||
void HeightMap::SetTexture(const std::string &file)
|
||||
{
|
||||
int bpp, width2, height2;
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
unsigned char* imgData = stbi_load(file.c_str(), &width2, &height2, &bpp, 4);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, imageIndex);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0, //level
|
||||
GL_RGBA, //internal format
|
||||
width2, //width
|
||||
height2, //height
|
||||
0, //border
|
||||
GL_RGBA, //data format
|
||||
GL_UNSIGNED_BYTE, //data type
|
||||
imgData); //data
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
stbi_image_free(imgData);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "Vertex.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <GL/freeglut.h>
|
||||
|
||||
class World;
|
||||
|
||||
class HeightMap
|
||||
{
|
||||
private:
|
||||
int height;
|
||||
int width;
|
||||
|
||||
GLuint imageIndex;
|
||||
public:
|
||||
HeightMap(const std::string &file, World* world);
|
||||
~HeightMap();
|
||||
|
||||
void Draw();
|
||||
float GetHeight(float x, float y);
|
||||
int GetSize();
|
||||
void SetTexture(const std::string &file);
|
||||
|
||||
std::vector<Vertex> vertices;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "Interface.h"
|
||||
#include <GL/freeglut.h>
|
||||
#include "Racer.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Player.h"
|
||||
#include "Util.h"
|
||||
|
||||
Interface::Interface()
|
||||
{
|
||||
}
|
||||
|
||||
Interface::Interface(int stars)
|
||||
{
|
||||
this->stars = stars;
|
||||
}
|
||||
|
||||
|
||||
Interface::~Interface()
|
||||
{
|
||||
}
|
||||
|
||||
void Interface::draw()
|
||||
{
|
||||
Player* player = Player::getInstance();
|
||||
|
||||
//Switch view to Ortho
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, 1000, 1000, 0, -10, 10);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
//Draw interface
|
||||
|
||||
//Stars bar
|
||||
glBegin(GL_QUADS);
|
||||
glColor4f(0, 0, 0, 1.0);
|
||||
glVertex2f(250, 980);
|
||||
glVertex2f(250, 965);
|
||||
glVertex2f(750, 965);
|
||||
glVertex2f(750, 980);
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
if(player->speed == 20)
|
||||
glColor4f(1.0f, 0.1f, 0.1f, 1.0);
|
||||
else
|
||||
glColor4f(1.0f, 1.0f, 0.1f, 1.0);
|
||||
glVertex2f(250, 980);
|
||||
glVertex2f(250, 965);
|
||||
|
||||
glColor4f(1.0f, 1.0f, 0.5f, 1.0);
|
||||
glVertex2f(250 + ((player->stars / (float)stars) * 500), 965);
|
||||
glVertex2f(250 + ((player->stars / (float)stars) * 500), 980);
|
||||
glEnd();
|
||||
|
||||
//Text: level
|
||||
glColor4f(1.0f, 1.0f, 0.1f, 1.0);
|
||||
Util::glutBitmapString("Stars: " + std::to_string(player->stars) + " / " + std::to_string(stars), 480, 940);
|
||||
|
||||
//Text: weapons
|
||||
//Util::glutBitmapString(player->leftWeapon->name, 850, 900);
|
||||
//Util::glutBitmapString(player->rightWeapon->name, 10, 900);
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void Interface::update(float deltaTime)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
class Interface
|
||||
{
|
||||
private:
|
||||
int stars;
|
||||
public:
|
||||
Interface();
|
||||
Interface(int);
|
||||
~Interface();
|
||||
|
||||
void draw(void);
|
||||
void update(float deltaTime);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "LevelObject.h"
|
||||
|
||||
#include "Model.h"
|
||||
|
||||
|
||||
LevelObject::LevelObject(const std::string &fileName, const Vec3f &position, const Vec3f &rotation, const float &scale, const bool &hasCollision)
|
||||
{
|
||||
model = Model::load(fileName);
|
||||
this->position = position;
|
||||
this->position.x -= model->center.x;
|
||||
this->position.z -= model->center.z;
|
||||
this->rotation = rotation;
|
||||
this->scale = scale;
|
||||
this->canCollide = hasCollision;
|
||||
}
|
||||
|
||||
|
||||
LevelObject::~LevelObject()
|
||||
{
|
||||
if (model)
|
||||
Model::unload(model);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "Entity.h"
|
||||
#include <string>
|
||||
|
||||
|
||||
class LevelObject : public Entity
|
||||
{
|
||||
public:
|
||||
LevelObject(const std::string &fileName,
|
||||
const Vec3f &position,
|
||||
const Vec3f &rotation,
|
||||
const float &scale,
|
||||
const bool &hasCollision);
|
||||
~LevelObject();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#include <GL/freeglut.h>
|
||||
|
||||
#include "Racer.h"
|
||||
#include <stdio.h>
|
||||
#include "Vector.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "Cursor.h"
|
||||
|
||||
void configureOpenGL(void);
|
||||
|
||||
Racer* app;
|
||||
|
||||
bool justMoved = false;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
app = new Racer();
|
||||
glutInit(&argc, argv);
|
||||
|
||||
std::srand (time(NULL));
|
||||
|
||||
configureOpenGL();
|
||||
|
||||
app->init();
|
||||
|
||||
glutDisplayFunc([]() { app->draw(); } );
|
||||
glutIdleFunc([]() { app->update(); } );
|
||||
glutReshapeFunc([](int w, int h) { Racer::width = w; Racer::height = h; glViewport(0, 0, w, h); });
|
||||
|
||||
//Keyboard
|
||||
glutKeyboardFunc([](unsigned char c, int, int) { app->keyboardState.keys[c] = true; });
|
||||
glutKeyboardUpFunc([](unsigned char c, int, int) { app->keyboardState.keys[c] = false; });
|
||||
glutSpecialFunc([](int c, int, int) { app->keyboardState.special[c] = true; });
|
||||
glutSpecialUpFunc([](int c, int, int) { app->keyboardState.special[c] = false; });
|
||||
|
||||
auto mousemotion = [](int x, int y)
|
||||
{
|
||||
if (justMoved)
|
||||
{
|
||||
justMoved = false;
|
||||
return;
|
||||
}
|
||||
int dx = x - app->width / 2;
|
||||
int dy = y - app->height / 2;
|
||||
if ((dx != 0 || dy != 0) && abs(dx) < 400 && abs(dy) < 400)
|
||||
{
|
||||
app->mouseOffset = app->mouseOffset + Vec2f(dx, dy);
|
||||
glutWarpPointer(app->width / 2, app->height / 2);
|
||||
justMoved = true;
|
||||
}
|
||||
};
|
||||
|
||||
//Mouse
|
||||
glutPassiveMotionFunc(mousemotion);
|
||||
glutMotionFunc(mousemotion);
|
||||
|
||||
auto mouseclick = [](int button, int state,
|
||||
int x, int y)
|
||||
{
|
||||
if (button == GLUT_LEFT_BUTTON)
|
||||
Cursor::getInstance()->state = state;
|
||||
|
||||
|
||||
//std::cout << "Left button is down" << std::endl;
|
||||
};
|
||||
|
||||
glutMouseFunc(mouseclick);
|
||||
|
||||
Racer::height = GLUT_WINDOW_HEIGHT;
|
||||
Racer::width = GLUT_WINDOW_WIDTH;
|
||||
|
||||
glutMainLoop();
|
||||
|
||||
delete app;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void configureOpenGL()
|
||||
{
|
||||
//Init window and glut display mode
|
||||
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
|
||||
glutInitWindowSize(1440, 900);
|
||||
//glutInitWindowPosition(glutGet(GLUT_WINDOW_WIDTH) / 2 - 800/2, glutGet(GLUT_WINDOW_HEIGHT) / 2 - 600/2);
|
||||
glutCreateWindow("Racer");
|
||||
glutFullScreen();
|
||||
|
||||
|
||||
//Depth testing
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
//Alpha blending
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
//Alpha testing
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.01f);
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
|
||||
glutSetCursor(GLUT_CURSOR_NONE);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#include <GL/freeglut.h>
|
||||
#include "Menu.h"
|
||||
#include "Racer.h"
|
||||
|
||||
Menu::Menu()
|
||||
{
|
||||
cursor = Cursor::getInstance();
|
||||
}
|
||||
|
||||
|
||||
Menu::~Menu()
|
||||
{
|
||||
}
|
||||
|
||||
void Menu::draw(void)
|
||||
{
|
||||
//Switch view to Ortho
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, Racer::width, Racer::height, 0, -10, 10);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glColor4f(60/255.0f, 60/255.0f, 60/255.0f, 0.8f);
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(0,0);
|
||||
glVertex2f(0, Racer::height);
|
||||
glVertex2f(Racer::width, Racer::height);
|
||||
glVertex2f(Racer::width, 0);
|
||||
glEnd();
|
||||
|
||||
|
||||
for (MenuElement* e : elements)
|
||||
{
|
||||
e->draw();
|
||||
}
|
||||
|
||||
cursor->draw();
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void Menu::update()
|
||||
{
|
||||
for (MenuElement* e : elements)
|
||||
{
|
||||
e->update(cursor->mousePosition.x, cursor->mousePosition.y);
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::AddMenuElement(MenuElement * e)
|
||||
{
|
||||
elements.push_back(e);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include "MenuElement.h"
|
||||
#include "Cursor.h"
|
||||
|
||||
class Menu
|
||||
{
|
||||
private:
|
||||
std::vector<MenuElement*> elements;
|
||||
Cursor* cursor;
|
||||
public:
|
||||
Menu();
|
||||
~Menu();
|
||||
|
||||
void draw(void);
|
||||
void update(void);
|
||||
|
||||
void AddMenuElement(MenuElement* e);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "MenuElement.h"
|
||||
|
||||
MenuElement::MenuElement(Vec2f position)
|
||||
{
|
||||
hover = false;
|
||||
this->position = position;
|
||||
}
|
||||
|
||||
|
||||
MenuElement::~MenuElement()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "Vector.h"
|
||||
#include <string>
|
||||
|
||||
class MenuElement
|
||||
{
|
||||
protected:
|
||||
bool hover;
|
||||
Vec2f position;
|
||||
public:
|
||||
MenuElement(Vec2f position);
|
||||
~MenuElement();
|
||||
|
||||
virtual void draw(void) {};
|
||||
virtual void update(int x, int y) {};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
#include "Model.h"
|
||||
|
||||
#include "stb_image.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
//Prototypes
|
||||
std::vector<std::string> split(std::string str, std::string sep);
|
||||
std::string replace(std::string str, std::string toReplace, std::string replacement);
|
||||
std::string toLower(std::string data);
|
||||
|
||||
Model::Model(std::string fileName)
|
||||
{
|
||||
std::string dirName = fileName;
|
||||
if (dirName.rfind("/") != std::string::npos)
|
||||
dirName = dirName.substr(0, dirName.rfind("/"));
|
||||
if (dirName.rfind("\\") != std::string::npos)
|
||||
dirName = dirName.substr(0, dirName.rfind("\\"));
|
||||
if (fileName == dirName)
|
||||
dirName = "";
|
||||
|
||||
|
||||
std::ifstream pFile(fileName.c_str());
|
||||
|
||||
if (!pFile.is_open())
|
||||
{
|
||||
std::cout << "Could not open file " << fileName << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ObjGroup* currentGroup = new ObjGroup();
|
||||
currentGroup->materialIndex = -1;
|
||||
|
||||
|
||||
while (!pFile.eof())
|
||||
{
|
||||
std::string line;
|
||||
std::getline(pFile, line);
|
||||
|
||||
line = replace(line, "\t", " ");
|
||||
while (line.find(" ") != std::string::npos)
|
||||
line = replace(line, " ", " ");
|
||||
if (line == "")
|
||||
continue;
|
||||
if (line[0] == ' ')
|
||||
line = line.substr(1);
|
||||
if (line == "")
|
||||
continue;
|
||||
if (line[line.length() - 1] == ' ')
|
||||
line = line.substr(0, line.length() - 1);
|
||||
if (line == "")
|
||||
continue;
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
std::vector<std::string> params = split(line, " ");
|
||||
params[0] = toLower(params[0]);
|
||||
|
||||
if (params[0] == "v")
|
||||
vertices.push_back(Vec3f((float)atof(params[1].c_str()), (float)atof(params[2].c_str()), (float)atof(params[3].c_str())));
|
||||
else if (params[0] == "vn")
|
||||
normals.push_back(Vec3f((float)atof(params[1].c_str()), (float)atof(params[2].c_str()), (float)atof(params[3].c_str())));
|
||||
else if (params[0] == "vt")
|
||||
texcoords.push_back(Vec2f((float)atof(params[1].c_str()), (float)atof(params[2].c_str())));
|
||||
else if (params[0] == "f")
|
||||
{
|
||||
for (size_t ii = 4; ii <= params.size(); ii++)
|
||||
{
|
||||
Face face;
|
||||
|
||||
for (size_t i = ii - 3; i < ii; i++) //magische forlus om van quads triangles te maken ;)
|
||||
{
|
||||
VertexIndex vertex;
|
||||
std::vector<std::string> indices = split(params[i == (ii - 3) ? 1 : i], "/");
|
||||
if (indices.size() >= 1) //er is een positie
|
||||
vertex.position = atoi(indices[0].c_str()) - 1;
|
||||
if (indices.size() == 2) //alleen texture
|
||||
vertex.texcoord = atoi(indices[1].c_str()) - 1;
|
||||
if (indices.size() == 3) //v/t/n of v//n
|
||||
{
|
||||
if (indices[1] != "")
|
||||
vertex.texcoord = atoi(indices[1].c_str()) - 1;
|
||||
vertex.normal = atoi(indices[2].c_str()) - 1;
|
||||
}
|
||||
face.vertices.push_back(vertex);
|
||||
}
|
||||
currentGroup->faces.push_back(face);
|
||||
}
|
||||
}
|
||||
else if (params[0] == "s")
|
||||
{//smoothing
|
||||
}
|
||||
else if (params[0] == "mtllib")
|
||||
{
|
||||
loadMaterialFile(dirName + "/" + params[1], dirName);
|
||||
}
|
||||
else if (params[0] == "usemtl")
|
||||
{
|
||||
if (currentGroup->faces.size() != 0)
|
||||
groups.push_back(currentGroup);
|
||||
currentGroup = new ObjGroup();
|
||||
currentGroup->materialIndex = -1;
|
||||
|
||||
for (size_t i = 0; i < materials.size(); i++)
|
||||
{
|
||||
MaterialInfo* info = materials[i];
|
||||
if (info->name == params[1])
|
||||
{
|
||||
currentGroup->materialIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (currentGroup->materialIndex == -1)
|
||||
std::cout << "Could not find material name " << params[1] << std::endl;
|
||||
}
|
||||
}
|
||||
groups.push_back(currentGroup);
|
||||
|
||||
minVertex = vertices[0];
|
||||
maxVertex = vertices[0];
|
||||
for (auto v : vertices)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
minVertex[i] = fmin(minVertex[i], v[i]);
|
||||
maxVertex[i] = fmax(maxVertex[i], v[i]);
|
||||
}
|
||||
}
|
||||
center = (minVertex + maxVertex) / 2.0f;
|
||||
radius = 0;
|
||||
for (auto v : vertices)
|
||||
radius = fmax(radius, (center.x - v.x) * (center.x - v.x) + (center.z - v.z) * (center.z - v.z));
|
||||
radius = sqrt(radius);
|
||||
|
||||
for (ObjGroup *group : groups)
|
||||
{
|
||||
Optimise(group);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::Optimise(ObjGroup *t)
|
||||
{
|
||||
for (Face &face : t->faces)
|
||||
{
|
||||
for (auto &vertex : face.vertices)
|
||||
{
|
||||
t->VertexArray.push_back(Vertex(vertices[vertex.position].x, vertices[vertex.position].y, vertices[vertex.position].z,
|
||||
normals[vertex.normal].x, normals[vertex.normal].y, normals[vertex.normal].z,
|
||||
texcoords[vertex.texcoord].x, texcoords[vertex.texcoord].y));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::draw()
|
||||
{
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
for (auto &g : groups)
|
||||
{
|
||||
if (materials[g->materialIndex]->hasTexture)
|
||||
{
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
materials[g->materialIndex]->texture->bind();
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
float color[4] = { 1, 0, 0, 1 };
|
||||
|
||||
if (materials[g->materialIndex]->hasDiffuse)
|
||||
{
|
||||
memcpy(color, materials[g->materialIndex]->diffuseColor.v, 3 * sizeof(float));
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
|
||||
}
|
||||
else if (materials[g->materialIndex]->hasAmbient)
|
||||
{
|
||||
memcpy(color, materials[g->materialIndex]->ambientColor.v, 3 * sizeof(float));
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);
|
||||
}
|
||||
else if (materials[g->materialIndex]->hasSpecular)
|
||||
{
|
||||
memcpy(color, materials[g->materialIndex]->specularColor.v, 3 * sizeof(float));
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);
|
||||
}
|
||||
}
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), ((float*)g->VertexArray.data()) + 0);
|
||||
glNormalPointer(GL_FLOAT, sizeof(Vertex), ((float*)g->VertexArray.data()) + 3);
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), ((float*)g->VertexArray.data()) + 6);
|
||||
glDrawArrays(GL_TRIANGLES, 0, g->VertexArray.size());
|
||||
}
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
void Model::loadMaterialFile(std::string fileName, std::string dirName)
|
||||
{
|
||||
std::ifstream pFile(fileName.c_str());
|
||||
if (!pFile.is_open())
|
||||
{
|
||||
std::cout << "Could not open file " << fileName << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
MaterialInfo* currentMaterial = NULL;
|
||||
|
||||
while (!pFile.eof())
|
||||
{
|
||||
std::string line;
|
||||
std::getline(pFile, line);
|
||||
|
||||
line = replace(line, "\t", " ");
|
||||
while (line.find(" ") != std::string::npos)
|
||||
line = replace(line, " ", " ");
|
||||
if (line == "")
|
||||
continue;
|
||||
if (line[0] == ' ')
|
||||
line = line.substr(1);
|
||||
if (line == "")
|
||||
continue;
|
||||
if (line[line.length() - 1] == ' ')
|
||||
line = line.substr(0, line.length() - 1);
|
||||
if (line == "")
|
||||
continue;
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
std::vector<std::string> params = split(line, " ");
|
||||
params[0] = toLower(params[0]);
|
||||
|
||||
if (params[0] == "newmtl")
|
||||
{
|
||||
if (currentMaterial != NULL)
|
||||
{
|
||||
materials.push_back(currentMaterial);
|
||||
}
|
||||
currentMaterial = new MaterialInfo();
|
||||
currentMaterial->name = params[1];
|
||||
}
|
||||
else if (params[0] == "map_kd")
|
||||
{
|
||||
currentMaterial->hasTexture = true;
|
||||
currentMaterial->texture = new Texture(dirName + "/" + params[1]);
|
||||
}
|
||||
else if (params[0] == "kd")
|
||||
{
|
||||
currentMaterial->hasDiffuse = true;
|
||||
currentMaterial->diffuseColor = Vec3f(atof(params[1].c_str()), atof(params[2].c_str()), atof(params[3].c_str()));
|
||||
}
|
||||
else if (params[0] == "ka")
|
||||
{
|
||||
currentMaterial->hasAmbient = true;
|
||||
currentMaterial->ambientColor = Vec3f(atof(params[1].c_str()), atof(params[2].c_str()), atof(params[3].c_str()));
|
||||
}
|
||||
else if (params[0] == "ks")
|
||||
{
|
||||
currentMaterial->hasSpecular = true;
|
||||
currentMaterial->specularColor = Vec3f(atof(params[1].c_str()), atof(params[2].c_str()), atof(params[3].c_str()));
|
||||
}
|
||||
else
|
||||
std::cout << "Didn't parse " << params[0] << " in material file" << std::endl;
|
||||
}
|
||||
if (currentMaterial != NULL)
|
||||
materials.push_back(currentMaterial);
|
||||
|
||||
}
|
||||
|
||||
Model::MaterialInfo::MaterialInfo()
|
||||
{
|
||||
hasTexture = false;
|
||||
}
|
||||
|
||||
Model::Texture::Texture(const std::string & fileName)
|
||||
{
|
||||
int width, height, bpp;
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
unsigned char* imgData = stbi_load(fileName.c_str(), &width, &height, &bpp, 4);
|
||||
|
||||
glGenTextures(1, &index);
|
||||
glBindTexture(GL_TEXTURE_2D, index);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0, //level
|
||||
GL_RGBA, //internal format
|
||||
width, //width
|
||||
height, //height
|
||||
0, //border
|
||||
GL_RGBA, //data format
|
||||
GL_UNSIGNED_BYTE, //data type
|
||||
imgData); //data
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
|
||||
stbi_image_free(imgData);
|
||||
}
|
||||
|
||||
void Model::Texture::bind()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, index);
|
||||
}
|
||||
|
||||
std::string replace(std::string str, std::string toReplace, std::string replacement)
|
||||
{
|
||||
size_t index = 0;
|
||||
while (true)
|
||||
{
|
||||
index = str.find(toReplace, index);
|
||||
if (index == std::string::npos)
|
||||
break;
|
||||
str.replace(index, toReplace.length(), replacement);
|
||||
++index;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string str, std::string sep)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
size_t index;
|
||||
while (true)
|
||||
{
|
||||
index = str.find(sep);
|
||||
if (index == std::string::npos)
|
||||
break;
|
||||
ret.push_back(str.substr(0, index));
|
||||
str = str.substr(index + 1);
|
||||
}
|
||||
ret.push_back(str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline std::string toLower(std::string data)
|
||||
{
|
||||
std::transform(data.begin(), data.end(), data.begin(), ::tolower);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::map<std::string, std::pair<Model*, int>> Model::cache;
|
||||
|
||||
Model* Model::load(const std::string &fileName)
|
||||
{
|
||||
if (cache.find(fileName) == cache.end())
|
||||
cache[fileName] = std::pair<Model*, int>(new Model(fileName), 0);
|
||||
cache[fileName].second++;
|
||||
return cache[fileName].first;
|
||||
}
|
||||
|
||||
void Model::unload(Model* model)
|
||||
{
|
||||
for (auto m : cache)
|
||||
{
|
||||
if (m.second.first == model)
|
||||
{
|
||||
m.second.second--;
|
||||
if (m.second.second == 0)
|
||||
{
|
||||
delete m.second.first;
|
||||
cache.erase(cache.find(m.first));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Model::~Model(void)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include <GL/freeglut.h>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "Vector.h"
|
||||
#include "Vertex.h"
|
||||
|
||||
class Model
|
||||
{
|
||||
private:
|
||||
|
||||
class VertexIndex
|
||||
{
|
||||
public:
|
||||
int position;
|
||||
int normal;
|
||||
int texcoord;
|
||||
};
|
||||
|
||||
class Face
|
||||
{
|
||||
public:
|
||||
std::list<VertexIndex> vertices;
|
||||
};
|
||||
|
||||
class Texture
|
||||
{
|
||||
GLuint index;
|
||||
public:
|
||||
Texture(const std::string &fileName);
|
||||
void bind();
|
||||
};
|
||||
|
||||
class MaterialInfo
|
||||
{
|
||||
public:
|
||||
MaterialInfo();
|
||||
std::string name;
|
||||
Texture* texture;
|
||||
bool hasTexture;
|
||||
|
||||
bool hasDiffuse;
|
||||
Vec3f diffuseColor;
|
||||
bool hasAmbient;
|
||||
Vec3f ambientColor;
|
||||
bool hasSpecular;
|
||||
Vec3f specularColor;
|
||||
|
||||
};
|
||||
|
||||
class ObjGroup
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
int materialIndex;
|
||||
std::list<Face> faces;
|
||||
std::vector<Vertex> VertexArray;
|
||||
};
|
||||
|
||||
std::vector<Vec3f> vertices;
|
||||
std::vector<Vec3f> normals;
|
||||
std::vector<Vec2f> texcoords;
|
||||
std::vector<ObjGroup*> groups;
|
||||
std::vector<MaterialInfo*> materials;
|
||||
|
||||
void loadMaterialFile(std::string fileName, std::string dirName);
|
||||
|
||||
Model(std::string filename);
|
||||
~Model(void);
|
||||
|
||||
public:
|
||||
|
||||
static std::map<std::string, std::pair<Model*, int> > cache;
|
||||
static Model* load(const std::string &fileName);
|
||||
static void unload(Model* model);
|
||||
|
||||
void draw();
|
||||
void Optimise(ObjGroup *t);
|
||||
|
||||
Vec3f minVertex;
|
||||
Vec3f maxVertex;
|
||||
|
||||
Vec3f center;
|
||||
float radius;
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "ObjectTemplate.h"
|
||||
|
||||
ObjectTemplate::ObjectTemplate(std::string file, int color, bool collide, float scale, Vec3f rotation)
|
||||
{
|
||||
this->file = file;
|
||||
this->color = color;
|
||||
this->canCollide = collide;
|
||||
this->scale = scale;
|
||||
this->rotation = rotation;
|
||||
}
|
||||
|
||||
ObjectTemplate::~ObjectTemplate()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "Vector.h"
|
||||
|
||||
class ObjectTemplate
|
||||
{
|
||||
public:
|
||||
ObjectTemplate(std::string file, int color, bool collide, float scale, Vec3f rotation);
|
||||
~ObjectTemplate();
|
||||
|
||||
std::string file;
|
||||
|
||||
int color;
|
||||
bool canCollide;
|
||||
|
||||
float scale;
|
||||
Vec3f rotation;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#include "Player.h"
|
||||
#include <GL/freeglut.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
Player* Player::instance = NULL;
|
||||
|
||||
Player::Player()
|
||||
{
|
||||
speed = 10;
|
||||
stars = 0;
|
||||
}
|
||||
|
||||
Player* Player::getInstance()
|
||||
{
|
||||
if (instance == nullptr)
|
||||
instance = new Player();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Player::init()
|
||||
{
|
||||
instance = new Player();
|
||||
}
|
||||
|
||||
void Player::setObject(LevelObject * obj)
|
||||
{
|
||||
kart = obj;
|
||||
kart->position = position;
|
||||
}
|
||||
|
||||
Player::~Player()
|
||||
{
|
||||
}
|
||||
|
||||
void Player::setCamera()
|
||||
{
|
||||
gluLookAt(0, 4, -6, 0, 0, 1, 0, 0.1f, 0);
|
||||
|
||||
glRotatef(rotation.x, 1, 0, 0);
|
||||
glRotatef(rotation.y, 0, 1, 0);
|
||||
//glTranslatef(-position.x, -position.y, -position.z);
|
||||
}
|
||||
|
||||
void Player::setPosition(float angle, float fac, bool height)
|
||||
{
|
||||
if (height)
|
||||
position.y += angle*fac;
|
||||
else
|
||||
{
|
||||
position.x -= (float)cos((rotation.y + angle) / 180 * M_PI) * fac;
|
||||
position.z -= (float)sin((rotation.y + angle) / 180 * M_PI) * fac;
|
||||
}
|
||||
|
||||
kart->position = position;
|
||||
kart->rotation = Vec3f(0, -rotation.y, 0);
|
||||
}
|
||||
|
||||
void Player::draw() {
|
||||
|
||||
glTranslatef(-position.x, -position.y, -position.z);
|
||||
|
||||
if (kart != nullptr)
|
||||
kart->draw();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include "Vector.h"
|
||||
#include "json.h"
|
||||
#include "LevelObject.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Player
|
||||
{
|
||||
private:
|
||||
static Player* instance;
|
||||
|
||||
LevelObject* kart;
|
||||
|
||||
public:
|
||||
Player();
|
||||
~Player();
|
||||
|
||||
void setCamera();
|
||||
void setPosition(float angle, float fac, bool height);
|
||||
void draw(void);
|
||||
|
||||
static Player* getInstance(void);
|
||||
static void init(void);
|
||||
|
||||
void setObject(LevelObject * obj);
|
||||
|
||||
Vec3f position;
|
||||
Vec2f rotation;
|
||||
|
||||
float speed;
|
||||
int stars;
|
||||
};
|
||||
@@ -0,0 +1,145 @@
|
||||
|
||||
#include "Racer.h"
|
||||
#include <GL/freeglut.h>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include "WorldHandler.h"
|
||||
#include "Player.h"
|
||||
#include "Cursor.h"
|
||||
#include "Menu.h"
|
||||
#include "Text.h"
|
||||
#include "Vector.h"
|
||||
#include "Button.h"
|
||||
|
||||
int Racer::width = 0;
|
||||
int Racer::height = 0;
|
||||
|
||||
SoundSystem Racer::sound_system;
|
||||
bool state = false;
|
||||
|
||||
void Racer::init()
|
||||
{
|
||||
player = Player::getInstance();
|
||||
worldhandler = WorldHandler::getInstance();
|
||||
cursor = Cursor::getInstance();
|
||||
|
||||
menu = new Menu();
|
||||
buildMenu();
|
||||
|
||||
lastFrameTime = 0;
|
||||
state = true;
|
||||
|
||||
glClearColor(0.7f, 0.7f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
void Racer::draw()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
//Draw world
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(70, width / (float)height, 0.1f, 7500);
|
||||
//gluLookAt()
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
worldhandler->draw();
|
||||
|
||||
if(!state)
|
||||
menu->draw();
|
||||
|
||||
glutSwapBuffers();
|
||||
}
|
||||
|
||||
|
||||
void Racer::update()
|
||||
{
|
||||
float frameTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
|
||||
float deltaTime = frameTime - lastFrameTime;
|
||||
lastFrameTime = frameTime;
|
||||
|
||||
if (keyboardState.keys[27] && !prevKeyboardState.keys[27])
|
||||
state = !state;
|
||||
|
||||
if (state)
|
||||
{
|
||||
Player* player = Player::getInstance();
|
||||
|
||||
if (keyboardState.special[GLUT_KEY_LEFT] && !prevKeyboardState.special[GLUT_KEY_LEFT])
|
||||
worldhandler->PreviousWorld();
|
||||
if (keyboardState.special[GLUT_KEY_RIGHT] && !prevKeyboardState.special[GLUT_KEY_RIGHT])
|
||||
worldhandler->NextWorld();
|
||||
if (keyboardState.keys[27])
|
||||
state = false;
|
||||
|
||||
player->rotation.y += mouseOffset.x / 10.0f;
|
||||
player->rotation.x += mouseOffset.y / 10.0f;
|
||||
|
||||
float speed = player->speed;
|
||||
|
||||
Vec3f oldPosition = player->position;
|
||||
|
||||
if (keyboardState.keys['w']) player->setPosition(270, deltaTime*speed, false);
|
||||
if (keyboardState.keys['s']) player->setPosition(90, deltaTime*speed, false);
|
||||
|
||||
|
||||
if (player->rotation.x > 25)
|
||||
player->rotation.x = 25;
|
||||
if (player->rotation.x < -20)
|
||||
player->rotation.x = -20;
|
||||
|
||||
player->position.y = worldhandler->getHeight(player->position.x, player->position.z) + 0.1f;
|
||||
|
||||
if (!worldhandler->isPlayerPositionValid())
|
||||
player->position = oldPosition;
|
||||
|
||||
worldhandler->update(deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu->update();
|
||||
cursor->update(cursor->mousePosition + mouseOffset);
|
||||
}
|
||||
|
||||
|
||||
mouseOffset = Vec2f(0, 0);
|
||||
prevKeyboardState = keyboardState;
|
||||
glutPostRedisplay();
|
||||
|
||||
sound_system.SetListener(player->position, Vec3f(), Vec3f());
|
||||
}
|
||||
|
||||
void Racer::buildMenu()
|
||||
{
|
||||
Button* start = new Button("Resume", Vec2f(1920 / 2 - 50, 1080 / 2 - 30), 100, 50);
|
||||
auto toWorld = [](Button* b)
|
||||
{
|
||||
state = true;
|
||||
};
|
||||
start->addAction(toWorld);
|
||||
menu->AddMenuElement(start);
|
||||
|
||||
|
||||
Button* test = new Button("Exit", Vec2f(1920 / 2 - 50, 1080 / 2 + 30), 100, 50);
|
||||
test->addAction([](Button* b)
|
||||
{
|
||||
exit(0);
|
||||
});
|
||||
menu->AddMenuElement(test);
|
||||
Text* t = new Text("Pause", Vec2f(1920 / 2 - Util::glutTextWidth("Pause") / 2, 1080 / 2 - 75));
|
||||
t->setColor(Vec3f(255, 255, 0));
|
||||
menu->AddMenuElement(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
KeyboardState::KeyboardState()
|
||||
{
|
||||
memset(keys, 0, sizeof(keys));
|
||||
memset(special, 0, sizeof(special));
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
class WorldHandler;
|
||||
class SoundSystem;
|
||||
class Player;
|
||||
class Cursor;
|
||||
class Menu;
|
||||
#include "Vector.h"
|
||||
#include "SoundSystem.h"
|
||||
|
||||
class KeyboardState
|
||||
{
|
||||
public:
|
||||
bool keys[256];
|
||||
bool special[256];
|
||||
bool control, shift, alt;
|
||||
|
||||
KeyboardState();
|
||||
};
|
||||
|
||||
class Racer
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
void draw();
|
||||
void update();
|
||||
|
||||
WorldHandler* worldhandler;
|
||||
Player* player;
|
||||
Cursor* cursor;
|
||||
Menu* menu;
|
||||
|
||||
static int width, height;
|
||||
KeyboardState keyboardState;
|
||||
KeyboardState prevKeyboardState;
|
||||
|
||||
Vec2f mouseOffset;
|
||||
Vec2f mousePosition;
|
||||
|
||||
float lastFrameTime;
|
||||
|
||||
static SoundSystem& GetSoundSystem() { return sound_system; }
|
||||
|
||||
|
||||
private:
|
||||
static SoundSystem sound_system;
|
||||
void buildMenu();
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Racer", "Racer.vcxproj", "{F82158C7-7345-4CB0-9F90-3AB49A071904}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F82158C7-7345-4CB0-9F90-3AB49A071904}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F82158C7-7345-4CB0-9F90-3AB49A071904}.Debug|x64.Build.0 = Debug|x64
|
||||
{F82158C7-7345-4CB0-9F90-3AB49A071904}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{F82158C7-7345-4CB0-9F90-3AB49A071904}.Debug|x86.Build.0 = Debug|Win32
|
||||
{F82158C7-7345-4CB0-9F90-3AB49A071904}.Release|x64.ActiveCfg = Release|x64
|
||||
{F82158C7-7345-4CB0-9F90-3AB49A071904}.Release|x64.Build.0 = Release|x64
|
||||
{F82158C7-7345-4CB0-9F90-3AB49A071904}.Release|x86.ActiveCfg = Release|Win32
|
||||
{F82158C7-7345-4CB0-9F90-3AB49A071904}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,223 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{F82158C7-7345-4CB0-9F90-3AB49A071904}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>Racer</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<ProjectName>Racer</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile />
|
||||
<AdditionalIncludeDirectories>lib/serial;freeglut/include; openAL/include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>freeglut/lib; openAL/libs/Win32</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>setupapi.lib;openal32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile />
|
||||
<AdditionalIncludeDirectories>lib/serial;freeglut/include;C:\Program Files (x86)\OpenAL 1.1 SDK\include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>freeglut/lib;C:\Program Files (x86)\OpenAL 1.1 SDK\libs\Win32</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>setupapi.lib;openal32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile />
|
||||
<AdditionalIncludeDirectories>lib/serial;freeglut/include; openAL/include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>freeglut/lib; openAL/libs/Win32</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>setupapi.lib;openal32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile />
|
||||
<AdditionalIncludeDirectories>lib/serial;freeglut/include;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>freeglut/lib</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>setupapi.lib;openal32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Button.cpp" />
|
||||
<ClCompile Include="ObjectTemplate.cpp" />
|
||||
<ClCompile Include="Racer.cpp" />
|
||||
<ClCompile Include="Cursor.cpp" />
|
||||
<ClCompile Include="Entity.cpp" />
|
||||
<ClCompile Include="HeightMap.cpp" />
|
||||
<ClCompile Include="Interface.cpp" />
|
||||
<ClCompile Include="json.cpp" />
|
||||
<ClCompile Include="LevelObject.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="Menu.cpp" />
|
||||
<ClCompile Include="MenuElement.cpp" />
|
||||
<ClCompile Include="Model.cpp" />
|
||||
<ClCompile Include="Sound.cpp" />
|
||||
<ClCompile Include="SoundSystem.cpp" />
|
||||
<ClCompile Include="Player.cpp" />
|
||||
<ClCompile Include="Skybox.cpp" />
|
||||
<ClCompile Include="Star.cpp" />
|
||||
<ClCompile Include="Text.cpp" />
|
||||
<ClCompile Include="Util.cpp" />
|
||||
<ClCompile Include="Vector.cpp" />
|
||||
<ClCompile Include="Vertex.cpp" />
|
||||
<ClCompile Include="World.cpp" />
|
||||
<ClCompile Include="WorldHandler.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Button.h" />
|
||||
<ClInclude Include="ObjectTemplate.h" />
|
||||
<ClInclude Include="Racer.h" />
|
||||
<ClInclude Include="Cursor.h" />
|
||||
<ClInclude Include="Entity.h" />
|
||||
<ClInclude Include="HeightMap.h" />
|
||||
<ClInclude Include="Interface.h" />
|
||||
<ClInclude Include="json.h" />
|
||||
<ClInclude Include="LevelObject.h" />
|
||||
<ClInclude Include="Main.h" />
|
||||
<ClInclude Include="Menu.h" />
|
||||
<ClInclude Include="MenuElement.h" />
|
||||
<ClInclude Include="Model.h" />
|
||||
<ClInclude Include="Sound.h" />
|
||||
<ClInclude Include="SoundSystem.h" />
|
||||
<ClInclude Include="Player.h" />
|
||||
<ClInclude Include="Skybox.h" />
|
||||
<ClInclude Include="Star.h" />
|
||||
<ClInclude Include="stb_image.h" />
|
||||
<ClInclude Include="Text.h" />
|
||||
<ClInclude Include="Util.h" />
|
||||
<ClInclude Include="vector.h" />
|
||||
<ClInclude Include="Vertex.h" />
|
||||
<ClInclude Include="World.h" />
|
||||
<ClInclude Include="WorldHandler.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\worlds\race.json" />
|
||||
<None Include="resources\worlds\worlds.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Media Include="WAVE\Crystal.wav" />
|
||||
<Media Include="WAVE\ghostEnemy.wav" />
|
||||
<Media Include="WAVE\portal.wav" />
|
||||
<Media Include="WAVE\world1.wav" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Object">
|
||||
<UniqueIdentifier>{1e464995-b141-43fd-9e25-16d6ac47176b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\World">
|
||||
<UniqueIdentifier>{0de1a037-e536-40df-a0d0-0d929f2fe752}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\json">
|
||||
<UniqueIdentifier>{9c655946-3f99-44ea-bc97-2817656954e0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Player.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="json.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WorldHandler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Entity.cpp">
|
||||
<Filter>Source Files\Object</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Model.cpp">
|
||||
<Filter>Source Files\Object</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vertex.cpp">
|
||||
<Filter>Source Files\Object</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vector.cpp">
|
||||
<Filter>Source Files\Object</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="World.cpp">
|
||||
<Filter>Source Files\World</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HeightMap.cpp">
|
||||
<Filter>Source Files\World</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LevelObject.cpp">
|
||||
<Filter>Source Files\World</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Cursor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Interface.cpp">
|
||||
<Filter>Source Files\World</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Skybox.cpp">
|
||||
<Filter>Source Files\World</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SoundSystem.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Sound.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Button.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Menu.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MenuElement.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Text.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Util.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Racer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ObjectTemplate.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Star.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="World.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Entity.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LevelObject.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Model.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stb_image.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Player.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Main.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="json.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HeightMap.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Vertex.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WorldHandler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Interface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Cursor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vector.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SoundSystem.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sound.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Skybox.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Button.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Menu.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MenuElement.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Text.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Util.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Racer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ObjectTemplate.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Star.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\worlds\worlds.json">
|
||||
<Filter>Source Files\json</Filter>
|
||||
</None>
|
||||
<None Include="resources\worlds\race.json">
|
||||
<Filter>Source Files\json</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Media Include="WAVE\Crystal.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="WAVE\portal.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="WAVE\ghostEnemy.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="WAVE\world1.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,29 @@
|
||||
Sanic STAR
|
||||
----------
|
||||
Gemaakt door Kenneth van Ewijk
|
||||
|
||||
Een simpel spel waarbij het de bedoeling is dat je alle sterren oppakt.
|
||||
Als je alle sterren hebt verzamelt, gaat hij naar de volgende wereld.
|
||||
Er zijn momenteel slechts vier werelden.
|
||||
|
||||
Opstarten en afsluiten:
|
||||
Druk op starten in Visual Studio. (Release, x86)
|
||||
Om af te sluiten, druk op ESC en kies Exit in het menu.
|
||||
|
||||
Besturing:
|
||||
- W en S voor vooruit/achteruit
|
||||
- Muis om te sturen en te kijken
|
||||
- Forceren van wereld veranderen (zonder alle sterren te verzamelen) door op de rechter pijltjestoets te drukken.
|
||||
|
||||
Deze game bevat de volgende onderdelen:
|
||||
- Bestuurbare third person camera
|
||||
- In de scene zijn een aantal verschillende ‘objecten’
|
||||
- De sterren draaien automatisch rond
|
||||
- SANIC die je bestuurd en de sterren die je op kan pakken zijn objecten die te beïnvloeden zijn.
|
||||
- De bomen staan stil. Een of meerdere objecten staan stil
|
||||
- De bomen/gras/sanic/sterren worden uit een obj file geladen
|
||||
- Het terrein wordt als heightmap met code gegenereerd.
|
||||
- De rode sterren, bij speciale speed boost sterren, zijn relatieve transformaties
|
||||
- Overal zit OpenGL belichting op
|
||||
- Op alle objecten en op de heightmap zit texture mapping
|
||||
- Toetsenbord wordt gebruikt voor besturing
|
||||
@@ -0,0 +1,148 @@
|
||||
#include "cmath"
|
||||
#include <GL/freeglut.h>
|
||||
|
||||
#include "Util.h"
|
||||
#include "stb_image.h"
|
||||
#include "Skybox.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
enum{SKY_LEFT=0,SKY_BACK,SKY_RIGHT,SKY_FRONT,SKY_TOP,SKY_BOTTOM};
|
||||
GLuint skybox[6];
|
||||
|
||||
Skybox::Skybox(const float &size, const std::string &folder)
|
||||
{
|
||||
this->size = size;
|
||||
this->folder = folder;
|
||||
}
|
||||
|
||||
Skybox::~Skybox()
|
||||
{
|
||||
glDeleteTextures(6, &skybox[0]);
|
||||
}
|
||||
|
||||
void Skybox::init()
|
||||
{
|
||||
skybox[SKY_LEFT] = Util::loadTexture(folder + "left.png");
|
||||
skybox[SKY_BACK] = Util::loadTexture(folder + "back.png");
|
||||
skybox[SKY_RIGHT] = Util::loadTexture(folder + "right.png");
|
||||
skybox[SKY_FRONT] = Util::loadTexture(folder + "front.png");
|
||||
skybox[SKY_TOP] = Util::loadTexture(folder + "top.png");
|
||||
skybox[SKY_BOTTOM] = Util::loadTexture(folder + "bottom.png");
|
||||
}
|
||||
|
||||
void Skybox::draw()
|
||||
{
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1);
|
||||
|
||||
bool b1 = glIsEnabled(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_COLOR_MATERIAL);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, skybox[SKY_BACK]);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(1,1);
|
||||
glVertex3f(size / 2, size / 2, size / 2);
|
||||
glTexCoord2f(0,1);
|
||||
glVertex3f(-size / 2, size / 2, size / 2);
|
||||
glTexCoord2f(0,0);
|
||||
glVertex3f(-size / 2, -size / 2, size / 2);
|
||||
glTexCoord2f(1,0);
|
||||
glVertex3f(size / 2, -size / 2, size / 2);
|
||||
glEnd();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, skybox[SKY_LEFT]);
|
||||
glBegin(GL_QUADS);
|
||||
//left face
|
||||
glTexCoord2f(1,1);
|
||||
glVertex3f(-size / 2, size / 2, size / 2);
|
||||
glTexCoord2f(0,1);
|
||||
glVertex3f(-size / 2, size / 2, -size / 2);
|
||||
glTexCoord2f(0,0);
|
||||
glVertex3f(-size / 2, -size / 2, -size / 2);
|
||||
glTexCoord2f(1,0);
|
||||
glVertex3f(-size / 2, -size / 2, size / 2);
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, skybox[SKY_FRONT]);
|
||||
glBegin(GL_QUADS);
|
||||
//front face
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex3f(size / 2, size / 2, -size / 2);
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex3f(-size / 2, size / 2, -size / 2);
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex3f(-size / 2, -size / 2, -size / 2);
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex3f(size / 2, -size / 2, -size / 2);
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, skybox[SKY_RIGHT]);
|
||||
glBegin(GL_QUADS);
|
||||
//right face
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex3f(size / 2, size / 2, -size / 2);
|
||||
glTexCoord2f(0,1);
|
||||
glVertex3f(size / 2, size / 2, size / 2);
|
||||
glTexCoord2f(0,0);
|
||||
glVertex3f(size / 2, -size / 2, size / 2);
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex3f(size / 2, -size / 2, -size / 2);
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, skybox[SKY_TOP]);
|
||||
glBegin(GL_QUADS); //top face
|
||||
glTexCoord2f(0,0);
|
||||
glVertex3f(size / 2, size / 2, size / 2);
|
||||
glTexCoord2f(0,1);
|
||||
glVertex3f(-size / 2, size / 2, size / 2);
|
||||
glTexCoord2f(1,1);
|
||||
glVertex3f(-size / 2, size / 2, -size / 2);
|
||||
glTexCoord2f(1,0);
|
||||
glVertex3f(size / 2, size / 2, -size / 2);
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, skybox[SKY_BOTTOM]);
|
||||
glBegin(GL_QUADS);
|
||||
//bottom face
|
||||
glTexCoord2f(0,1);
|
||||
glVertex3f(size / 2, -size / 2, size / 2);
|
||||
glTexCoord2f(0,0);
|
||||
glVertex3f(-size / 2, -size / 2, size / 2);
|
||||
glTexCoord2f(1,0);
|
||||
glVertex3f(-size / 2, -size / 2, -size / 2);
|
||||
glTexCoord2f(1,1);
|
||||
glVertex3f(size / 2, -size / 2, -size / 2);
|
||||
glEnd();
|
||||
glEnable(GL_LIGHTING); //turn everything back, which we turned on, and turn everything off, which we have turned on.
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
if (!b1)
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
GLuint Skybox::loadTexture(const std::string & fileName) //load the filename named texture
|
||||
{
|
||||
int width, height, bpp;
|
||||
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
unsigned char* imgData = stbi_load(fileName.c_str(), &width, &height, &bpp, 4);
|
||||
GLuint num;
|
||||
glGenTextures(1, &num);
|
||||
glBindTexture(GL_TEXTURE_2D, num);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0, //level
|
||||
GL_RGBA, //internal format
|
||||
width, //width
|
||||
height, //height
|
||||
0, //border
|
||||
GL_RGBA, //data format
|
||||
GL_UNSIGNED_BYTE, //data type
|
||||
imgData); //data
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
|
||||
stbi_image_free(imgData);
|
||||
return num;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
class Skybox
|
||||
{
|
||||
private:
|
||||
float size;
|
||||
std::string folder;
|
||||
public:
|
||||
Skybox(const float &size, const std::string &folder);
|
||||
~Skybox();
|
||||
|
||||
void init();
|
||||
void draw();
|
||||
|
||||
GLuint loadTexture(const std::string &fileName);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,167 @@
|
||||
#include "Sound.h"
|
||||
|
||||
#include <iostream>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <al.h>
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
typedef unsigned long DWORD;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned int UNINT32;
|
||||
typedef unsigned char BYTE;
|
||||
#endif
|
||||
|
||||
|
||||
Sound::Sound(const char* inWavPath, bool inLooping):
|
||||
buffer_id(0),
|
||||
source_id(0),
|
||||
is_looping(inLooping)
|
||||
{
|
||||
const char* path = inWavPath;
|
||||
|
||||
FILE *fp = fopen(path, "rb"); // Open the WAVE file
|
||||
if (!fp)
|
||||
return; // Could not open file
|
||||
|
||||
// Check that the WAVE file is OK
|
||||
char type[4];
|
||||
fread(type, sizeof(char), 4, fp); // Reads the first bytes in the file
|
||||
if (type[0] != 'R' || type[1] != 'I' || type[2] != 'F' || type[3] != 'F') // Should be "RIFF"
|
||||
return; // Not RIFF
|
||||
|
||||
DWORD size;
|
||||
fread(&size, sizeof(DWORD), 1, fp); // Continue to read the file
|
||||
fread(type, sizeof(char), 4, fp); // Continue to read the file
|
||||
if (type[0] != 'W' || type[1] != 'A' || type[2] != 'V' || type[3] != 'E') // This part should be "WAVE"
|
||||
return; // Not WAVE
|
||||
|
||||
fread(type, sizeof(char), 4, fp); // Continue to read the file
|
||||
if (type[0] != 'f' || type[1] != 'm' || type[2] != 't' || type[3] != ' ') // This part should be "fmt "
|
||||
return; // Not fmt
|
||||
|
||||
// Now we know that the file is a acceptable WAVE file
|
||||
// Info about the WAVE data is now read and stored
|
||||
DWORD chunkSize;
|
||||
fread(&chunkSize, sizeof(DWORD), 1, fp);
|
||||
short formatType;
|
||||
fread(&formatType, sizeof(short), 1, fp);
|
||||
short channels;
|
||||
fread(&channels, sizeof(short), 1, fp);
|
||||
DWORD sampleRate;
|
||||
fread(&sampleRate, sizeof(DWORD), 1, fp);
|
||||
DWORD avgBytesPerSec;
|
||||
fread(&avgBytesPerSec, sizeof(DWORD), 1, fp);
|
||||
short bytesPerSample;
|
||||
fread(&bytesPerSample, sizeof(short), 1, fp);
|
||||
short bitsPerSample;
|
||||
fread(&bitsPerSample, sizeof(short), 1, fp);
|
||||
ALenum format = 0; // The audio format (bits per sample, number of channels)
|
||||
if (bitsPerSample == 8)
|
||||
{
|
||||
if (channels == 1)
|
||||
format = AL_FORMAT_MONO8;
|
||||
else if (channels == 2)
|
||||
format = AL_FORMAT_STEREO8;
|
||||
}
|
||||
else if (bitsPerSample == 16)
|
||||
{
|
||||
if (channels == 1)
|
||||
format = AL_FORMAT_MONO16;
|
||||
else if (channels == 2)
|
||||
format = AL_FORMAT_STEREO16;
|
||||
}
|
||||
if (!format)
|
||||
return; // Not valid format
|
||||
|
||||
fread(type, sizeof(char), 4, fp);
|
||||
if (type[0] != 'd' || type[1] != 'a' || type[2] != 't' || type[3] != 'a') // This part should be "data"
|
||||
return; // not data
|
||||
|
||||
DWORD dataSize;
|
||||
fread(&dataSize, sizeof(DWORD), 1, fp); // The size of the sound data is read
|
||||
|
||||
// Display the info about the WAVE file
|
||||
std::cout << "Chunk Size: " << chunkSize << "\n";
|
||||
std::cout << "Format Type: " << formatType << "\n";
|
||||
std::cout << "Channels: " << channels << "\n";
|
||||
std::cout << "Sample Rate: " << sampleRate << "\n";
|
||||
std::cout << "Average Bytes Per Second: " << avgBytesPerSec << "\n";
|
||||
std::cout << "Bytes Per Sample: " << bytesPerSample << "\n";
|
||||
std::cout << "Bits Per Sample: " << bitsPerSample << "\n";
|
||||
std::cout << "Data Size: " << dataSize << "\n";
|
||||
|
||||
unsigned char* buf = new unsigned char[dataSize]; // Allocate memory for the sound data
|
||||
std::cout << fread(buf, sizeof(BYTE), dataSize, fp) << " bytes loaded\n"; // Read the sound data and display the
|
||||
fclose(fp);
|
||||
|
||||
alGenBuffers(1, &buffer_id); // Generate one OpenAL Buffer and link to "buffer"
|
||||
alGenSources(1, &source_id); // Generate one OpenAL Source and link to "source"
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
return; // Error during buffer/source generation
|
||||
|
||||
alBufferData(buffer_id, format, buf, dataSize, sampleRate); // Store the sound data in the OpenAL Buffer
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
return; // Error during buffer loading
|
||||
|
||||
delete[] buf; // Delete the sound data buffer
|
||||
}
|
||||
|
||||
|
||||
Sound::~Sound()
|
||||
{
|
||||
alSourceStop(source_id);
|
||||
alDeleteSources(1, &source_id); // Delete the OpenAL Source
|
||||
alDeleteBuffers(1, &buffer_id); // Delete the OpenAL Buffer
|
||||
}
|
||||
|
||||
|
||||
void Sound::SetPos(const Vec3f& inPos, const Vec3f& inVel)
|
||||
{
|
||||
alSourcei(source_id, AL_BUFFER, buffer_id); // Link the buffer to the source
|
||||
alSourcef(source_id, AL_PITCH, 1.0f); // Set the pitch of the source
|
||||
alSourcef(source_id, AL_GAIN, 1.0f); // Set the gain of the source
|
||||
alSourcefv(source_id, AL_POSITION, inPos.v); // Set the position of the source
|
||||
alSourcefv(source_id, AL_VELOCITY, inVel.v); // Set the velocity of the source
|
||||
alSourcei(source_id, AL_LOOPING, is_looping ? AL_TRUE : AL_FALSE); // Set if source is looping sound
|
||||
}
|
||||
|
||||
|
||||
void Sound::Play()
|
||||
{
|
||||
alSourcePlay(source_id);
|
||||
int e = alGetError(); // != AL_NO_ERROR) return;
|
||||
}
|
||||
|
||||
|
||||
void Sound::Pause()
|
||||
{
|
||||
alSourcePause(source_id);
|
||||
}
|
||||
|
||||
|
||||
void Sound::Stop()
|
||||
{
|
||||
alSourceStop(source_id);
|
||||
}
|
||||
|
||||
bool Sound::IsPlaying()
|
||||
{
|
||||
ALenum state;
|
||||
|
||||
alGetSourcei(source_id, AL_SOURCE_STATE, &state);
|
||||
|
||||
return (state == AL_PLAYING);
|
||||
}
|
||||
|
||||
bool Sound::IsStopped()
|
||||
{
|
||||
ALenum state;
|
||||
|
||||
alGetSourcei(source_id, AL_SOURCE_STATE, &state);
|
||||
|
||||
std::cout << "MUSIC STATE: " << state << std::endl;
|
||||
|
||||
return (state == AL_STOPPED);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "Vector.h"
|
||||
|
||||
class Sound
|
||||
{
|
||||
public:
|
||||
Sound(const char* inWavPath, bool inLooping);
|
||||
~Sound();
|
||||
|
||||
void SetPos(const Vec3f& inPos, const Vec3f& inVel);
|
||||
|
||||
void Play();
|
||||
void Pause();
|
||||
void Stop();
|
||||
bool IsPlaying();
|
||||
bool IsStopped();
|
||||
|
||||
private:
|
||||
unsigned int buffer_id;
|
||||
unsigned int source_id;
|
||||
|
||||
bool is_looping;
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "SoundSystem.h"
|
||||
|
||||
SoundSystem::SoundSystem():
|
||||
device(nullptr),
|
||||
context(nullptr)
|
||||
{
|
||||
device = alcOpenDevice(nullptr);
|
||||
if (!device)
|
||||
return;
|
||||
context = alcCreateContext(device, nullptr);
|
||||
if (!context)
|
||||
return;
|
||||
alcMakeContextCurrent(context);
|
||||
}
|
||||
|
||||
|
||||
SoundSystem::~SoundSystem()
|
||||
{
|
||||
for (auto sound : sounds)
|
||||
delete sound;
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(context);
|
||||
alcCloseDevice(device);
|
||||
}
|
||||
|
||||
|
||||
void SoundSystem::SetListener(const Vec3f& inPos, const Vec3f& inVel, const Vec3f& inOri)
|
||||
{
|
||||
ALfloat orientation[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 };
|
||||
|
||||
alListenerfv(AL_POSITION, inPos.v);
|
||||
alListenerfv(AL_VELOCITY, inVel.v);
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
|
||||
unsigned int SoundSystem::LoadSound(const char* inWavPath, bool inLooping)
|
||||
{
|
||||
Sound* sound = new Sound(inWavPath, inLooping);
|
||||
sounds.push_back(sound);
|
||||
return sounds.size() - 1;
|
||||
}
|
||||
|
||||
|
||||
Sound* SoundSystem::GetSound(unsigned int inID)
|
||||
{
|
||||
if (inID > sounds.size())
|
||||
return nullptr;
|
||||
return sounds[inID];
|
||||
}
|
||||
|
||||
void SoundSystem::UnloadSound(unsigned int inID)
|
||||
{
|
||||
if (inID > sounds.size())
|
||||
return;
|
||||
delete sounds[inID];
|
||||
//sounds.erase(sounds.begin() + inID);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <al.h>
|
||||
#include <alc.h>
|
||||
|
||||
#include "Vector.h"
|
||||
#include "Sound.h"
|
||||
|
||||
|
||||
class SoundSystem
|
||||
{
|
||||
public:
|
||||
SoundSystem();
|
||||
~SoundSystem();
|
||||
|
||||
void SetListener(const Vec3f& inPos, const Vec3f& inVel, const Vec3f& inOri);
|
||||
|
||||
unsigned int LoadSound(const char* inWavPath, bool inLooping);
|
||||
Sound* GetSound(unsigned int inID);
|
||||
void UnloadSound(unsigned int inID);
|
||||
|
||||
private:
|
||||
ALCdevice* device;
|
||||
ALCcontext* context;
|
||||
std::vector<Sound*> sounds;
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
#include "Star.h"
|
||||
#include "Model.h"
|
||||
|
||||
|
||||
Star::Star(Vec3f position)
|
||||
{
|
||||
scale = 1;
|
||||
|
||||
model = Model::load("resources/models/star/I_star.obj");
|
||||
specialstar = Model::load("resources/models/redstar/I_star.obj");
|
||||
|
||||
scale = 0.2;
|
||||
this->position = position;
|
||||
rotVal = 0;
|
||||
|
||||
int rand = std::rand() % 100;
|
||||
|
||||
special = false;
|
||||
if (rand <= 25)
|
||||
{
|
||||
special = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Star::~Star()
|
||||
{
|
||||
if (model)
|
||||
Model::unload(model);
|
||||
if (specialstar)
|
||||
Model::unload(specialstar);
|
||||
}
|
||||
|
||||
void Star::draw()
|
||||
{
|
||||
if (model)
|
||||
{
|
||||
glPushMatrix();
|
||||
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glRotatef(rotation.x, 1, 0, 0);
|
||||
glRotatef(rotation.y, 0, 1, 0);
|
||||
glRotatef(rotation.z, 0, 0, 1);
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
model->draw();
|
||||
|
||||
if (special)
|
||||
{
|
||||
glRotatef(rotVal, 0, 1, 0);
|
||||
glTranslatef(4.0f, 12.0f, 4.0f);
|
||||
glRotatef(rotVal, 0, 1, 0);
|
||||
glScalef(0.3f, 0.3f, 0.3f);
|
||||
|
||||
specialstar->draw();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Star::update(float deltaTime)
|
||||
{
|
||||
rotation.y += deltaTime * 100.0f;
|
||||
rotVal += deltaTime * 100.0f * 1.5f;
|
||||
}
|
||||
|
||||
bool Star::inObject(const Vec3f & point)
|
||||
{
|
||||
if (!model)
|
||||
return false;
|
||||
Vec3f center = position + model->center;
|
||||
float distance = ((point.x - center.x) * (point.x - center.x) + (point.z - center.z)*(point.z - center.z));
|
||||
if (distance < model->radius*scale*model->radius*scale)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include "Entity.h"
|
||||
#include "Vector.h"
|
||||
#include "Model.h"
|
||||
|
||||
class Star
|
||||
{
|
||||
private:
|
||||
float rotVal;
|
||||
Model * specialstar;
|
||||
Model* model;
|
||||
|
||||
public:
|
||||
Star(Vec3f position);
|
||||
~Star();
|
||||
|
||||
void draw(void);
|
||||
void update(float elapsedTime);
|
||||
|
||||
Vec3f position;
|
||||
Vec3f rotation;
|
||||
float scale;
|
||||
|
||||
bool canCollide;
|
||||
bool inObject(const Vec3f &position);
|
||||
|
||||
bool special;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "Text.h"
|
||||
|
||||
|
||||
Text::Text(const std::string &text, Vec2f position) : MenuElement(position)
|
||||
{
|
||||
this->text = text;
|
||||
color = Vec3f(50, 150, 150);
|
||||
textHeight = 14;
|
||||
textWidth = Util::glutTextWidth(text);
|
||||
}
|
||||
|
||||
|
||||
Text::~Text()
|
||||
{
|
||||
}
|
||||
|
||||
void Text::draw()
|
||||
{
|
||||
glColor4f(color.x/255.0f, color.y/255.0f, color.z/255.0f, 1.0f);
|
||||
Util::glutBitmapString(text, position.x-1, position.y+textHeight);
|
||||
}
|
||||
|
||||
void Text::update(int x, int y)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
void Text::setColor(Vec3f color)
|
||||
{
|
||||
this->color = color;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "MenuElement.h"
|
||||
#include "Vector.h"
|
||||
#include "Util.h"
|
||||
|
||||
class Text : public MenuElement
|
||||
{
|
||||
private:
|
||||
std::string text;
|
||||
Vec3f color;
|
||||
protected:
|
||||
int textWidth;
|
||||
int textHeight;
|
||||
public:
|
||||
Text(const std::string &text, Vec2f position);
|
||||
~Text();
|
||||
|
||||
virtual void draw();
|
||||
virtual void update(int x, int y);
|
||||
|
||||
void setColor(Vec3f color);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "Util.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
Util::Util()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
Util::~Util()
|
||||
{
|
||||
}
|
||||
|
||||
GLuint Util::loadTexture(const std::string &filename)
|
||||
{
|
||||
int width, height, bpp;
|
||||
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
unsigned char* imgData = stbi_load(filename.c_str(), &width, &height, &bpp, 4);
|
||||
GLuint num;
|
||||
glGenTextures(1, &num);
|
||||
glBindTexture(GL_TEXTURE_2D, num);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0, //level
|
||||
GL_RGBA, //internal format
|
||||
width, //width
|
||||
height, //height
|
||||
0, //border
|
||||
GL_RGBA, //data format
|
||||
GL_UNSIGNED_BYTE, //data type
|
||||
imgData); //data
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
|
||||
stbi_image_free(imgData);
|
||||
return num;
|
||||
}
|
||||
|
||||
void Util::glutBitmapString(std::string str, int x, int y)
|
||||
{
|
||||
glRasterPos2f(x, y);
|
||||
for (int i = 0; i < str.size(); i++)
|
||||
{
|
||||
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int Util::glutTextWidth(const std::string str)
|
||||
{
|
||||
int total = 0;
|
||||
for (int i = 0; i < str.size(); i++)
|
||||
{
|
||||
total += glutBitmapWidth(GLUT_BITMAP_HELVETICA_18, str[i]);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
//int Util::glutTextHeight()
|
||||
//{
|
||||
// return glutBitmapHeight(GLUT_BITMAP_HELVETICA_18);
|
||||
//}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <GL/freeglut.h>
|
||||
|
||||
class Util
|
||||
{
|
||||
private:
|
||||
Util();
|
||||
~Util();
|
||||
public:
|
||||
static GLuint loadTexture(const std::string &filename);
|
||||
static void glutBitmapString(std::string str, int x, int y);
|
||||
static int glutTextWidth(const std::string str);
|
||||
//static int glutTextHeight();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#include "Vector.h"
|
||||
|
||||
|
||||
Vec3f::Vec3f(float x, float y, float z)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
}
|
||||
/*The length of the vector*/
|
||||
float Vec3f::Length()
|
||||
{
|
||||
return (float)sqrt(x*x+y*y+z*z);
|
||||
}
|
||||
|
||||
void Vec3f::Normalize()
|
||||
{
|
||||
float length = this->Length();
|
||||
|
||||
if (length != 0)
|
||||
{
|
||||
x = x / length;
|
||||
y = y / length;
|
||||
z = z / length;
|
||||
}
|
||||
}
|
||||
|
||||
float Vec3f::Distance(const Vec3f &other)
|
||||
{
|
||||
return (float)sqrt(pow(other.x - x, 2)+pow(other.y - y, 2)+pow(other.z - z, 2));
|
||||
}
|
||||
|
||||
Vec3f::Vec3f()
|
||||
{
|
||||
this->x = 0;
|
||||
this->y = 0;
|
||||
this->z = 0;
|
||||
}
|
||||
Vec3f::Vec3f(const Vec3f &other)
|
||||
{
|
||||
this->x = other.x;
|
||||
this->y = other.y;
|
||||
this->z = other.z;
|
||||
}
|
||||
|
||||
float& Vec3f::operator [](int index)
|
||||
{
|
||||
return v[index];
|
||||
}
|
||||
|
||||
Vec3f Vec3f::operator+(const Vec3f & other)
|
||||
{
|
||||
return Vec3f(x + other.x, y + other.y, z + other.z);
|
||||
}
|
||||
|
||||
Vec3f Vec3f::operator-(const Vec3f & other)
|
||||
{
|
||||
return Vec3f(x - other.x, y - other.y, z - other.z);
|
||||
}
|
||||
|
||||
Vec3f Vec3f::operator/(float value)
|
||||
{
|
||||
return Vec3f(x / value, y / value, z / value);
|
||||
}
|
||||
|
||||
bool Vec3f::operator==(const Vec3f & other)
|
||||
{
|
||||
/*bool xb, yb,zb;
|
||||
xb = x == other.x;
|
||||
yb = y == other.y;
|
||||
zb = z == other.z;
|
||||
if (xb & yb & zb)
|
||||
return true;*/
|
||||
return x == other.x & y == other.y & z == other.z;
|
||||
}
|
||||
|
||||
bool Vec3f::operator!=(const Vec3f & other)
|
||||
{
|
||||
return x != other.x & y != other.y & z != other.z;
|
||||
}
|
||||
|
||||
Vec3f Vec3f::operator*(const float & other)
|
||||
{
|
||||
return Vec3f(x*other, y*other, z*other);
|
||||
}
|
||||
|
||||
Vec3f Vec3f::cross(const Vec3f & other)
|
||||
{
|
||||
return Vec3f(
|
||||
y*other.z - other.y*z,
|
||||
z*other.x - other.z*x,
|
||||
x*other.y - other.x*y
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vec2f::Vec2f(float x, float y)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
Vec2f::Vec2f()
|
||||
{
|
||||
this->x = 0;
|
||||
this->y = 0;
|
||||
}
|
||||
Vec2f::Vec2f(const Vec2f &other)
|
||||
{
|
||||
this->x = other.x;
|
||||
this->y = other.y;
|
||||
}
|
||||
|
||||
float& Vec2f::operator [](int index)
|
||||
{
|
||||
return v[index];
|
||||
}
|
||||
|
||||
Vec2f Vec2f::operator+(const Vec2f & other)
|
||||
{
|
||||
return Vec2f(x + other.x, y+other.y);
|
||||
}
|
||||
|
||||
float Vec2f::length()
|
||||
{
|
||||
return (float)sqrt(x*x + y*y);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
class Vec3f
|
||||
{
|
||||
public:
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
float x, y, z;
|
||||
};
|
||||
float v[3];
|
||||
};
|
||||
Vec3f();
|
||||
Vec3f(const Vec3f &other);
|
||||
Vec3f(float x, float y, float z);
|
||||
float Length();
|
||||
void Normalize();
|
||||
float Distance(const Vec3f &);
|
||||
float& operator [](int);
|
||||
Vec3f operator + (const Vec3f &other);
|
||||
Vec3f operator -(const Vec3f &other);
|
||||
Vec3f operator / (float value);
|
||||
bool operator ==(const Vec3f &other);
|
||||
bool operator !=(const Vec3f &other);
|
||||
Vec3f operator *(const float &other);
|
||||
|
||||
Vec3f cross(const Vec3f &other);
|
||||
|
||||
};
|
||||
|
||||
class Vec2f
|
||||
{
|
||||
public:
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
float v[2];
|
||||
};
|
||||
Vec2f();
|
||||
Vec2f(float x, float y);
|
||||
Vec2f(const Vec2f &other);
|
||||
float& operator [](int);
|
||||
Vec2f operator + (const Vec2f &other);
|
||||
float length();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "Vertex.h"
|
||||
|
||||
Vertex::Vertex(float x, float y, float z, float nx, float ny, float nz, float tx, float ty)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
|
||||
this->normalX = nx;
|
||||
this->normalY = ny;
|
||||
this->normalZ = nz;
|
||||
|
||||
this->texX = tx;
|
||||
this->texY = ty;
|
||||
}
|
||||
|
||||
Vertex::~Vertex()
|
||||
{
|
||||
}
|
||||
|
||||
Vertex Vertex::operator/(const float &other) const
|
||||
{
|
||||
return Vertex(x / other, y / other, z / other, normalX, normalY, normalZ, texX, texY);
|
||||
}
|
||||
|
||||
Vertex Vertex::operator*(const Vertex & other) const
|
||||
{
|
||||
return Vertex(x*other.x, y*other.y, z*other.z, normalX, normalY, normalZ, texX, texY);
|
||||
}
|
||||
|
||||
Vertex Vertex::operator*(const float & other) const
|
||||
{
|
||||
return Vertex(x*other, y*other, z*other, normalX, normalY, normalZ, texX, texY);
|
||||
}
|
||||
|
||||
Vertex Vertex::operator+(const Vertex & other) const
|
||||
{
|
||||
return Vertex(x+other.x, y+other.y, z+other.z, normalX, normalY, normalZ, texX, texY);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
class Vertex
|
||||
{
|
||||
public:
|
||||
Vertex(float x, float y, float z, float nx, float ny, float nz, float tx, float ty);
|
||||
~Vertex();
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
float normalX;
|
||||
float normalY;
|
||||
float normalZ;
|
||||
|
||||
float texX;
|
||||
float texY;
|
||||
|
||||
Vertex operator/(const float &other) const;
|
||||
Vertex operator*(const Vertex &other) const;
|
||||
Vertex operator*(const float &other) const;
|
||||
Vertex operator+(const Vertex &other) const;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
#include "World.h"
|
||||
#include <GL/freeglut.h>
|
||||
#include "Entity.h"
|
||||
#include "json.h"
|
||||
#include "Model.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
#include "WorldHandler.h"
|
||||
#include "LevelObject.h"
|
||||
|
||||
World::World(const std::string &fileName)
|
||||
{
|
||||
nextworld = false;
|
||||
speedboost = false;
|
||||
seconds = 0;
|
||||
|
||||
//Store player instance
|
||||
player = Player::getInstance();
|
||||
|
||||
//Open world json file
|
||||
std::ifstream file(fileName);
|
||||
if(!file.is_open())
|
||||
std::cout<<"Error, can't open world file - " << fileName << "\n";
|
||||
|
||||
json::Value v = json::readJson(file);
|
||||
file.close();
|
||||
|
||||
//Check file
|
||||
if(v["world"].isNull() || v["world"]["heightmap"].isNull() || v["world"]["skybox"].isNull())
|
||||
std::cout << "Invalid world file: world - " << fileName << "\n";
|
||||
if (v["world"]["object-templates"].isNull())
|
||||
std::cout << "Invalid world file: object templates - " << fileName << "\n";
|
||||
if (v["player"].isNull() || v["player"]["startposition"].isNull() || v["player"]["kart"].isNull())
|
||||
std::cout << "Invalid world file: player - " << fileName << "\n";
|
||||
if (v["objects"].isNull())
|
||||
std::cout << "Invalid world file: objects - " << fileName << "\n";
|
||||
|
||||
//Load object templates
|
||||
for (auto objt : v["world"]["object-templates"])
|
||||
{
|
||||
//collision
|
||||
bool cancollide = true;
|
||||
if (!objt["collision"].isNull())
|
||||
cancollide = objt["collision"].asBool();
|
||||
|
||||
float scaleot = 1;
|
||||
if (!objt["scale"].isNull())
|
||||
scaleot = objt["scale"].asFloat();
|
||||
|
||||
Vec3f rotationot = Vec3f(0,0,0);
|
||||
if (!objt["rot"].isNull())
|
||||
rotationot = Vec3f(objt["rot"][0].asFloat(), objt["rot"][3].asFloat(), objt["rot"][2].asFloat());
|
||||
|
||||
objecttemplates.push_back(ObjectTemplate(objt["file"].asString(), objt["color"].asInt(), cancollide, scaleot, rotationot));
|
||||
}
|
||||
|
||||
//Generate heightmap for this world
|
||||
heightmap = new HeightMap(v["world"]["heightmap"].asString(), this);
|
||||
|
||||
//Load skybox
|
||||
skybox = new Skybox(7500.0f, v["world"]["skybox"].asString());
|
||||
skybox->init();
|
||||
|
||||
//Map different texture to heightmap if available
|
||||
if(!v["world"]["texture"].isNull())
|
||||
heightmap->SetTexture(v["world"]["texture"].asString());
|
||||
|
||||
//Set player starting position
|
||||
player->position.x = v["player"]["startposition"][0].asFloat();
|
||||
player->position.z = v["player"]["startposition"][2].asFloat();
|
||||
player->position.y = heightmap->GetHeight(player->position.x, player->position.z);
|
||||
|
||||
float pscale = 1.0f;
|
||||
if(!v["player"]["kart"]["scale"].isNull())
|
||||
pscale = v["player"]["kart"]["scale"].asFloat();
|
||||
|
||||
|
||||
player->setObject(new LevelObject(v["player"]["kart"]["file"].asString(), Vec3f(), Vec3f(), pscale, false));
|
||||
|
||||
//Create the interface
|
||||
starsCount = stars.size();
|
||||
interface = new Interface(stars.size());
|
||||
|
||||
//Load and place objects into world
|
||||
for (auto object : v["objects"])
|
||||
{
|
||||
//Collision
|
||||
bool hasCollision = true;
|
||||
if (!object["collide"].isNull())
|
||||
hasCollision = object["collide"].asBool();
|
||||
|
||||
//Rotation
|
||||
Vec3f rotation(0, 0, 0);
|
||||
if(!object["rot"].isNull())
|
||||
rotation = Vec3f(object["rot"][0].asFloat(), object["rot"][1].asFloat(), object["rot"][2].asFloat());
|
||||
|
||||
//Scale
|
||||
float scale = 1;
|
||||
if (!object["scale"].isNull())
|
||||
scale = object["scale"].asFloat();
|
||||
|
||||
//Position
|
||||
if (object["pos"].isNull())
|
||||
std::cout << "Invalid world file: objects pos - " << fileName << "\n";
|
||||
|
||||
//File
|
||||
if (object["file"].isNull())
|
||||
std::cout << "Invalid world file: objects file - " << fileName << "\n";
|
||||
|
||||
//Create
|
||||
Vec3f position(object["pos"][0].asFloat(), object["pos"][1].asFloat(), object["pos"][2].asFloat());
|
||||
position.y = getHeight(position.x, position.z);
|
||||
|
||||
entities.push_back(new LevelObject(object["file"].asString(), position, rotation, scale, hasCollision));
|
||||
}
|
||||
|
||||
if (!v["world"]["music"].isNull())
|
||||
{
|
||||
sound_id = Racer::GetSoundSystem().LoadSound(v["world"]["music"].asString().c_str(), true);
|
||||
music = Racer::GetSoundSystem().GetSound(sound_id);
|
||||
}
|
||||
|
||||
star_sound_id = Racer::GetSoundSystem().LoadSound("resources/sounds/Crystal.wav", false);
|
||||
starPickup = Racer::GetSoundSystem().GetSound(star_sound_id);
|
||||
}
|
||||
|
||||
World::~World()
|
||||
{
|
||||
delete heightmap;
|
||||
music->Stop();
|
||||
starPickup->Stop();
|
||||
Racer::GetSoundSystem().UnloadSound(sound_id);
|
||||
Racer::GetSoundSystem().UnloadSound(star_sound_id);
|
||||
delete skybox;
|
||||
}
|
||||
|
||||
ObjectTemplate World::getObjectFromValue(int val)
|
||||
{
|
||||
for (auto i : objecttemplates)
|
||||
{
|
||||
if (i.color == val)
|
||||
return i;
|
||||
}
|
||||
|
||||
return objecttemplates[0];
|
||||
}
|
||||
|
||||
float World::getHeight(float x, float y)
|
||||
{
|
||||
return heightmap->GetHeight(x, y);
|
||||
}
|
||||
|
||||
void World::draw()
|
||||
{
|
||||
player->setCamera();
|
||||
|
||||
float lightPosition[4] = { 0, 2, 1, 0 };
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
|
||||
|
||||
GLfloat lightAmbient[] = { 0.05, 0.05, 0.05, 0 };
|
||||
GLfloat light_diffuse[] = { 0.9, 0.9, 0.9, 0 };
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
|
||||
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
|
||||
|
||||
GLfloat mat_specular[] = { 0.15, 0.15, 0.15, 0 };
|
||||
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
|
||||
|
||||
skybox->draw();
|
||||
player->draw();
|
||||
|
||||
heightmap->Draw();
|
||||
|
||||
for (auto &entity : entities)
|
||||
entity->draw();
|
||||
|
||||
for (auto &star : stars)
|
||||
star->draw();
|
||||
|
||||
interface->draw();
|
||||
}
|
||||
|
||||
void World::update(float elapsedTime)
|
||||
{
|
||||
if (nextworld)
|
||||
{
|
||||
WorldHandler::getInstance()->NextWorld();
|
||||
return;
|
||||
}
|
||||
|
||||
music->SetPos(player->position, Vec3f());
|
||||
|
||||
if (music->IsPlaying() == false)
|
||||
{
|
||||
music->Play();
|
||||
}
|
||||
|
||||
for (auto &entity : entities)
|
||||
entity->update(elapsedTime);
|
||||
|
||||
bool remove = false;
|
||||
int removeindex = 0;
|
||||
|
||||
for (auto &star : stars)
|
||||
{
|
||||
star->update(elapsedTime);
|
||||
|
||||
if (star->inObject(player->position))
|
||||
{
|
||||
remove = true;
|
||||
|
||||
if (star->special)
|
||||
{
|
||||
speedboost = true;
|
||||
seconds = 5.0;
|
||||
player->speed = 20;
|
||||
}
|
||||
|
||||
player->stars++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!remove)
|
||||
removeindex++;
|
||||
}
|
||||
|
||||
if (remove)
|
||||
{
|
||||
delete stars[removeindex];
|
||||
stars.erase(stars.begin() + removeindex);
|
||||
}
|
||||
|
||||
if (player->stars == starsCount)
|
||||
nextworld = true;
|
||||
|
||||
interface->update(elapsedTime);
|
||||
seconds -= elapsedTime;
|
||||
|
||||
if (speedboost && seconds < 0)
|
||||
{
|
||||
speedboost = false;
|
||||
seconds = 0;
|
||||
player->speed = 10;
|
||||
}
|
||||
}
|
||||
|
||||
void World::addLevelObject(LevelObject* obj)
|
||||
{
|
||||
entities.push_back(obj);
|
||||
}
|
||||
|
||||
void World::addStar(Star * star)
|
||||
{
|
||||
stars.push_back(star);
|
||||
}
|
||||
|
||||
bool World::isPlayerPositionValid()
|
||||
{
|
||||
for (auto &e : entities)
|
||||
{
|
||||
if (e->canCollide && e->inObject(player->position))
|
||||
{
|
||||
e->collide();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "HeightMap.h"
|
||||
#include "Player.h"
|
||||
#include "LevelObject.h"
|
||||
#include "Interface.h"
|
||||
#include "Skybox.h"
|
||||
#include "Racer.h"
|
||||
#include "ObjectTemplate.h"
|
||||
#include "Star.h"
|
||||
|
||||
class Entity;
|
||||
|
||||
class World
|
||||
{
|
||||
private:
|
||||
std::vector<ObjectTemplate> objecttemplates;
|
||||
Sound* music;
|
||||
Sound* starPickup;
|
||||
|
||||
Player* player;
|
||||
HeightMap* heightmap;
|
||||
Interface* interface;
|
||||
Skybox* skybox;
|
||||
|
||||
bool nextworld;
|
||||
|
||||
float seconds;
|
||||
bool speedboost;
|
||||
|
||||
int sound_id;
|
||||
int star_sound_id;
|
||||
int starsCount;
|
||||
|
||||
std::vector<Entity*> entities;
|
||||
std::vector<Star*> stars;
|
||||
public:
|
||||
World(const std::string &fileName);
|
||||
~World();
|
||||
|
||||
void draw();
|
||||
void update(float elapsedTime);
|
||||
bool isPlayerPositionValid();
|
||||
float getHeight(float x, float y);
|
||||
void addLevelObject(LevelObject* obj);
|
||||
void addStar(Star* star);
|
||||
ObjectTemplate getObjectFromValue(int i);
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "WorldHandler.h"
|
||||
#include "World.h"
|
||||
|
||||
#include "json.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
WorldHandler* WorldHandler::instance = nullptr;
|
||||
|
||||
void WorldHandler::ChangeWorld(int i)
|
||||
{
|
||||
if (i < 0)
|
||||
i = worldfiles.size() - 1;
|
||||
|
||||
else if (i >= worldfiles.size())
|
||||
i = 0;
|
||||
|
||||
if (i != worldIndex)
|
||||
{
|
||||
loadingWorld = true;
|
||||
|
||||
if(worldIndex != -1)
|
||||
delete world;
|
||||
|
||||
world = new World(worldfiles[i]);
|
||||
worldIndex = i;
|
||||
loadingWorld = false;
|
||||
}
|
||||
}
|
||||
|
||||
WorldHandler::WorldHandler()
|
||||
{
|
||||
loadingWorld = true;
|
||||
worldIndex = -1;
|
||||
|
||||
//Find worlds.json
|
||||
std::ifstream file("resources/worlds/worlds.json");
|
||||
if (!file.is_open())
|
||||
std::cout << "Error, can't open worlds overview file\n";
|
||||
|
||||
json::Value v = json::readJson(file);
|
||||
file.close();
|
||||
|
||||
//Load file names into vector
|
||||
if (v["worlds"].isNull() || !v["worlds"].isArray())
|
||||
std::cout << "Error, no content in worlds overview file\n";
|
||||
|
||||
for (auto line : v["worlds"])
|
||||
{
|
||||
std::cout << "Found world: " << line << "\n";
|
||||
worldfiles.push_back(line);
|
||||
}
|
||||
|
||||
if (worldfiles.size() > 0)
|
||||
{
|
||||
ChangeWorld(0);
|
||||
}
|
||||
}
|
||||
|
||||
WorldHandler::~WorldHandler()
|
||||
{
|
||||
worldIndex = -1;
|
||||
delete world;
|
||||
}
|
||||
|
||||
WorldHandler* WorldHandler::getInstance()
|
||||
{
|
||||
if (instance == nullptr)
|
||||
instance = new WorldHandler();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void WorldHandler::init()
|
||||
{
|
||||
instance = new WorldHandler();
|
||||
}
|
||||
|
||||
void WorldHandler::draw(void)
|
||||
{
|
||||
if(!loadingWorld)
|
||||
world->draw();
|
||||
else
|
||||
{
|
||||
//Draw Loading screen
|
||||
}
|
||||
}
|
||||
|
||||
void WorldHandler::update(float deltaTime)
|
||||
{
|
||||
if(!loadingWorld)
|
||||
world->update(deltaTime);
|
||||
}
|
||||
|
||||
bool WorldHandler::isPlayerPositionValid(void)
|
||||
{
|
||||
if(!loadingWorld)
|
||||
return world->isPlayerPositionValid();
|
||||
return false;
|
||||
}
|
||||
|
||||
float WorldHandler::getHeight(float x, float y)
|
||||
{
|
||||
if (!loadingWorld)
|
||||
return world->getHeight(x, y);
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
void WorldHandler::Navigate(const std::string &fileName)
|
||||
{
|
||||
if (!loadingWorld)
|
||||
{
|
||||
for (int i = 0; i < worldfiles.size(); i++)
|
||||
{
|
||||
if (worldfiles[i] == fileName)
|
||||
ChangeWorld(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldHandler::NextWorld()
|
||||
{
|
||||
if (!loadingWorld)
|
||||
{
|
||||
Player::getInstance()->stars = 0;
|
||||
ChangeWorld(worldIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldHandler::PreviousWorld()
|
||||
{
|
||||
if (!loadingWorld)
|
||||
{
|
||||
Player::getInstance()->stars = 0;
|
||||
ChangeWorld(worldIndex - 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class World;
|
||||
|
||||
class WorldHandler
|
||||
{
|
||||
private:
|
||||
WorldHandler();
|
||||
static WorldHandler* instance;
|
||||
|
||||
bool loadingWorld;
|
||||
World* world;
|
||||
int worldIndex;
|
||||
void ChangeWorld(int i);
|
||||
public:
|
||||
|
||||
~WorldHandler();
|
||||
|
||||
static WorldHandler* getInstance(void);
|
||||
static void init();
|
||||
|
||||
void draw(void);
|
||||
void update(float deltaTime);
|
||||
|
||||
bool isPlayerPositionValid(void);
|
||||
float getHeight(float x, float y);
|
||||
|
||||
void Navigate(const std::string &fileName);
|
||||
void NextWorld();
|
||||
void PreviousWorld();
|
||||
|
||||
std::vector<std::string> worldfiles;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,730 @@
|
||||
#include "json.h"
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <set>
|
||||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace json
|
||||
{
|
||||
|
||||
Value Value::null;
|
||||
//constructors
|
||||
Value::Value()
|
||||
{
|
||||
type = Type::nullValue;
|
||||
value.objectValue = NULL;
|
||||
}
|
||||
|
||||
Value::Value(Type type)
|
||||
{
|
||||
this->type = type;
|
||||
if (type == Type::stringValue)
|
||||
value.stringValue = new std::string();
|
||||
if (type == Type::arrayValue)
|
||||
value.arrayValue = new std::vector<Value>();
|
||||
if (type == Type::objectValue)
|
||||
value.objectValue = new std::map<std::string, Value>();
|
||||
}
|
||||
|
||||
Value::Value(int value)
|
||||
{
|
||||
type = Type::intValue;
|
||||
this->value.intValue = value;
|
||||
}
|
||||
|
||||
Value::Value(float value)
|
||||
{
|
||||
type = Type::floatValue;
|
||||
this->value.floatValue = value;
|
||||
}
|
||||
|
||||
Value::Value(bool value)
|
||||
{
|
||||
type = Type::boolValue;
|
||||
this->value.boolValue = value;
|
||||
}
|
||||
|
||||
Value::Value(const std::string &value)
|
||||
{
|
||||
type = Type::stringValue;
|
||||
this->value.stringValue = new std::string();
|
||||
this->value.stringValue->assign(value);
|
||||
}
|
||||
Value::Value(const char* value)
|
||||
{
|
||||
type = Type::stringValue;
|
||||
this->value.stringValue = new std::string();
|
||||
this->value.stringValue->assign(value);
|
||||
}
|
||||
|
||||
Value::Value(const Value& other) : Value(other.type)
|
||||
{
|
||||
if (type == Type::objectValue)
|
||||
*this->value.objectValue = *other.value.objectValue;
|
||||
else if (type == Type::arrayValue)
|
||||
*this->value.arrayValue = *other.value.arrayValue;
|
||||
else if (type == Type::stringValue)
|
||||
this->value.stringValue->assign(*other.value.stringValue);
|
||||
else
|
||||
this->value = other.value;
|
||||
}
|
||||
|
||||
void Value::operator=(const Value& other)
|
||||
{
|
||||
if (type != other.type)
|
||||
{
|
||||
if (type == Type::stringValue)
|
||||
delete value.stringValue;
|
||||
if (type == Type::arrayValue)
|
||||
delete value.arrayValue;
|
||||
if (type == Type::objectValue)
|
||||
delete value.objectValue;
|
||||
this->type = other.type;
|
||||
if (type == Type::stringValue)
|
||||
value.stringValue = new std::string();
|
||||
if (type == Type::arrayValue)
|
||||
value.arrayValue = new std::vector<Value>();
|
||||
if (type == Type::objectValue)
|
||||
value.objectValue = new std::map<std::string, Value>();
|
||||
}
|
||||
|
||||
if (type == Type::objectValue)
|
||||
*this->value.objectValue = *other.value.objectValue;
|
||||
else if (type == Type::arrayValue)
|
||||
*this->value.arrayValue = *other.value.arrayValue;
|
||||
else if (type == Type::stringValue)
|
||||
this->value.stringValue->assign(*other.value.stringValue);
|
||||
else
|
||||
this->value = other.value;
|
||||
}
|
||||
|
||||
Value::~Value()
|
||||
{
|
||||
if (type == Type::stringValue)
|
||||
delete value.stringValue;
|
||||
else if (type == Type::arrayValue)
|
||||
delete value.arrayValue;
|
||||
else if (type == Type::objectValue)
|
||||
delete value.objectValue;
|
||||
}
|
||||
|
||||
size_t Value::size() const
|
||||
{
|
||||
assert(type == Type::arrayValue || type == Type::objectValue);
|
||||
if (type == Type::arrayValue)
|
||||
return value.arrayValue->size();
|
||||
else if (type == Type::objectValue)
|
||||
return value.objectValue->size();
|
||||
throw "Unsupported";
|
||||
}
|
||||
|
||||
void Value::push_back(const Value& value)
|
||||
{
|
||||
assert(type == Type::arrayValue || type == Type::nullValue);
|
||||
if (type == Type::nullValue)
|
||||
{
|
||||
type = Type::arrayValue;
|
||||
this->value.arrayValue = new std::vector<Value>();
|
||||
}
|
||||
this->value.arrayValue->push_back(value);
|
||||
}
|
||||
|
||||
|
||||
Value& Value::operator[](const std::string &key)
|
||||
{
|
||||
assert(type == Type::objectValue);
|
||||
return (*value.objectValue)[key];
|
||||
}
|
||||
Value& Value::operator[](const std::string &key) const
|
||||
{
|
||||
assert(type == Type::objectValue);
|
||||
return (*value.objectValue)[key];
|
||||
}
|
||||
|
||||
Value& Value::operator[](const char* key)
|
||||
{
|
||||
assert(type == Type::objectValue || type == Type::nullValue);
|
||||
if (type == Type::nullValue)
|
||||
{
|
||||
type = Type::objectValue;
|
||||
value.objectValue = new std::map<std::string, Value>();
|
||||
}
|
||||
return (*value.objectValue)[std::string(key)];
|
||||
}
|
||||
|
||||
Value& Value::operator[](const char* key) const
|
||||
{
|
||||
assert(type == Type::objectValue);
|
||||
return (*value.objectValue)[std::string(key)];
|
||||
}
|
||||
|
||||
Value& Value::operator[](size_t index)
|
||||
{
|
||||
assert(type == Type::arrayValue);
|
||||
return (*value.arrayValue)[index];
|
||||
}
|
||||
Value& Value::operator[](size_t index) const
|
||||
{
|
||||
assert(type == Type::arrayValue);
|
||||
return (*value.arrayValue)[index];
|
||||
}
|
||||
Value& Value::operator[](int index)
|
||||
{
|
||||
assert(type == Type::arrayValue);
|
||||
return (*value.arrayValue)[index];
|
||||
}
|
||||
Value& Value::operator[](int index) const
|
||||
{
|
||||
assert(type == Type::arrayValue);
|
||||
return (*value.arrayValue)[index];
|
||||
}
|
||||
|
||||
void Value::erase(size_t index)
|
||||
{
|
||||
throw "Cannot cast";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Value::Iterator Value::end() const
|
||||
{
|
||||
if (type == Type::objectValue)
|
||||
return Iterator(value.objectValue->end());
|
||||
else if (type == Type::arrayValue)
|
||||
return Iterator(value.arrayValue->end());
|
||||
throw "oops";
|
||||
}
|
||||
|
||||
Value::Iterator Value::begin() const
|
||||
{
|
||||
if (type == Type::objectValue)
|
||||
return Iterator(value.objectValue->begin());
|
||||
else if (type == Type::arrayValue)
|
||||
return Iterator(value.arrayValue->begin());
|
||||
throw "oops";
|
||||
}
|
||||
|
||||
///iterator stuff
|
||||
|
||||
Value Value::Iterator::operator*()
|
||||
{
|
||||
if (type == Type::objectValue)
|
||||
return this->objectIterator->second;
|
||||
else if (type == Type::arrayValue)
|
||||
return *arrayIterator;
|
||||
throw "Oops";
|
||||
}
|
||||
|
||||
bool Value::Iterator::operator!=(const Iterator &other)
|
||||
{
|
||||
if (type == Type::objectValue)
|
||||
return this->objectIterator != other.objectIterator;
|
||||
else if (type == Type::arrayValue)
|
||||
return this->arrayIterator != other.arrayIterator;
|
||||
throw "Oops";
|
||||
}
|
||||
|
||||
void Value::Iterator::operator++()
|
||||
{
|
||||
if (type == Type::objectValue)
|
||||
this->objectIterator++;
|
||||
else if (type == Type::arrayValue)
|
||||
this->arrayIterator++;
|
||||
}
|
||||
void Value::Iterator::operator++(int)
|
||||
{
|
||||
if (type == Type::objectValue)
|
||||
this->objectIterator++;
|
||||
else if (type == Type::arrayValue)
|
||||
this->arrayIterator++;
|
||||
}
|
||||
|
||||
Value::Iterator::Iterator(const std::vector<Value>::iterator& arrayIterator)
|
||||
{
|
||||
type = Type::arrayValue;
|
||||
this->arrayIterator = arrayIterator;
|
||||
}
|
||||
|
||||
Value::Iterator::Iterator(const std::map<std::string, Value>::iterator& objectIterator)
|
||||
{
|
||||
type = Type::objectValue;
|
||||
this->objectIterator = objectIterator;
|
||||
}
|
||||
|
||||
std::string Value::Iterator::key()
|
||||
{
|
||||
assert(type == Type::objectValue);
|
||||
return this->objectIterator->first;
|
||||
}
|
||||
Value& Value::Iterator::value()
|
||||
{
|
||||
assert(type == Type::objectValue);
|
||||
return this->objectIterator->second;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void ltrim(std::istream& stream);
|
||||
static void eatComment(std::istream& stream);
|
||||
static Value eatString(std::istream& stream);
|
||||
static Value eatObject(std::istream& stream);
|
||||
static Value eatArray(std::istream& stream);
|
||||
static Value eatNumeric(std::istream& stream, char firstChar);
|
||||
static Value eatBool(std::istream& stream);
|
||||
static Value eatNull(std::istream& stream);
|
||||
static Value eatValue(std::istream& stream);
|
||||
|
||||
//reading
|
||||
static void ltrim(std::istream& stream)
|
||||
{
|
||||
char c = stream.peek();
|
||||
while (c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
{
|
||||
stream.get();
|
||||
c = stream.peek();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static Value eatString(std::istream& stream)
|
||||
{
|
||||
std::string value = "";
|
||||
bool escaped = false;
|
||||
while (!stream.eof())
|
||||
{
|
||||
char c = stream.get();
|
||||
if (c == '\\' && !escaped)
|
||||
escaped = !escaped;
|
||||
else if (c == '\"' && !escaped)
|
||||
return Value(value);
|
||||
else
|
||||
{
|
||||
value += c;
|
||||
escaped = false;
|
||||
}
|
||||
}
|
||||
return Value(value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
static Value eatObject(std::istream& stream)
|
||||
{
|
||||
Value obj(Type::objectValue);
|
||||
while (!stream.eof())
|
||||
{
|
||||
ltrim(stream);
|
||||
char token = stream.get();
|
||||
if (token == '}')
|
||||
break; //empty object
|
||||
if (token == '/')
|
||||
{
|
||||
eatComment(stream);
|
||||
token = stream.get();
|
||||
}
|
||||
|
||||
assert(token == '"');
|
||||
Value key = eatString(stream);
|
||||
ltrim(stream);
|
||||
token = stream.get();
|
||||
assert(token == ':');
|
||||
ltrim(stream);
|
||||
Value val = eatValue(stream);
|
||||
obj[key.asString()] = val;
|
||||
ltrim(stream);
|
||||
|
||||
token = stream.get();
|
||||
if (token == '}')
|
||||
break;
|
||||
assert(token == ',');
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
static Value eatArray(std::istream& stream)
|
||||
{
|
||||
Value obj(Type::arrayValue);
|
||||
while (!stream.eof())
|
||||
{
|
||||
ltrim(stream);
|
||||
if (stream.peek() == ']')
|
||||
{
|
||||
stream.get();
|
||||
break;
|
||||
}
|
||||
obj.push_back(eatValue(stream));
|
||||
ltrim(stream);
|
||||
char token = stream.get();
|
||||
if (token == '/')
|
||||
{
|
||||
eatComment(stream);
|
||||
token = stream.get();
|
||||
}
|
||||
if (token == ']')
|
||||
break;
|
||||
assert(token == ',');
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
static Value eatNumeric(std::istream& stream, char firstChar)
|
||||
{
|
||||
std::string numeric(1, firstChar);
|
||||
while (!stream.eof())
|
||||
{
|
||||
char token = stream.peek();
|
||||
if ((token >= '0' && token <= '9') || token == '.' || token == '-')
|
||||
numeric += stream.get();
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (numeric.find('.') == std::string::npos)
|
||||
return Value(atoi(numeric.c_str()));
|
||||
else
|
||||
return Value((float)atof(numeric.c_str()));
|
||||
};
|
||||
|
||||
static Value eatBool(std::istream& stream)
|
||||
{
|
||||
char token = stream.get();
|
||||
if (token == 'a') //fAlse
|
||||
{
|
||||
stream.get(); //l
|
||||
stream.get(); //s
|
||||
stream.get(); //e
|
||||
return false;
|
||||
}
|
||||
else if (token == 'r') //tRue
|
||||
{
|
||||
stream.get(); // u
|
||||
stream.get(); // e
|
||||
return true;
|
||||
}
|
||||
return Value(Type::nullValue);
|
||||
};
|
||||
static Value eatNull(std::istream& stream)
|
||||
{
|
||||
return Value(Type::nullValue);
|
||||
};
|
||||
|
||||
//precondition: / is already eaten
|
||||
static void eatComment(std::istream& stream)
|
||||
{
|
||||
char token = stream.get();
|
||||
assert(token == '/' || token == '*');
|
||||
if (token == '*')
|
||||
{
|
||||
char last = token;
|
||||
while ((last != '*' || token != '/') && !stream.eof())
|
||||
{
|
||||
last = token;
|
||||
token = stream.get();
|
||||
}
|
||||
}
|
||||
else if (token == '/')
|
||||
while (token != '\n' && !stream.eof())
|
||||
token = stream.get();
|
||||
ltrim(stream);
|
||||
}
|
||||
|
||||
|
||||
static Value eatValue(std::istream& stream)
|
||||
{
|
||||
ltrim(stream);
|
||||
char token = stream.get();
|
||||
if (token == '{')
|
||||
return eatObject(stream);
|
||||
if (token == '[')
|
||||
return eatArray(stream);
|
||||
if ((token >= '0' && token <= '9') || token == '.' || token == '-')
|
||||
return eatNumeric(stream, token);
|
||||
if (token == '"')
|
||||
return eatString(stream);
|
||||
if (token == 't' || token == 'f')
|
||||
return eatBool(stream);
|
||||
if (token == 'n')
|
||||
return eatNull(stream);
|
||||
if (token == '/')
|
||||
{
|
||||
eatComment(stream);
|
||||
return eatValue(stream);
|
||||
}
|
||||
throw "Unable to parse json";
|
||||
};
|
||||
|
||||
|
||||
Value readJson(const std::string &data)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << data;
|
||||
printf("%s", "test");
|
||||
|
||||
return eatValue(stream);
|
||||
}
|
||||
|
||||
Value readJson(std::istream &stream)
|
||||
{
|
||||
return eatValue(stream);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::ostream& indent(std::ostream& stream, int level)
|
||||
{
|
||||
for (int i = 0; i < level; i++)
|
||||
stream << '\t';
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& Value::prettyPrint(std::ostream& stream, json::Value& printConfig, int level) const
|
||||
{
|
||||
stream << std::fixed << std::setprecision(6);
|
||||
switch (type)
|
||||
{
|
||||
case Type::intValue:
|
||||
stream << value.intValue;
|
||||
break;
|
||||
case Type::floatValue:
|
||||
assert(!isnan(value.floatValue));
|
||||
//assert(isnormal(value.floatValue));
|
||||
if (value.floatValue >= 0)
|
||||
stream << " ";
|
||||
stream << value.floatValue;
|
||||
break;
|
||||
case Type::boolValue:
|
||||
stream << (value.boolValue ? "true" : "false");
|
||||
break;
|
||||
case Type::stringValue:
|
||||
stream << "\"" << *value.stringValue << "\""; //TODO: escape \'s
|
||||
break;
|
||||
case Type::arrayValue:
|
||||
{
|
||||
stream << "[";
|
||||
int wrap = 99999;
|
||||
if (value.arrayValue->size() > 10)
|
||||
wrap = 1;
|
||||
if (value.arrayValue->at(0).isArray() || value.arrayValue->at(0).isObject())
|
||||
wrap = 1;
|
||||
else
|
||||
wrap = 3;
|
||||
|
||||
std::string seperator = " ";
|
||||
|
||||
if (!printConfig.isNull() && printConfig.isMember("wrap"))
|
||||
wrap = printConfig["wrap"];
|
||||
if (!printConfig.isNull() && printConfig.isMember("seperator"))
|
||||
seperator = printConfig["seperator"].asString();
|
||||
|
||||
|
||||
int index = 0;
|
||||
|
||||
if ((long)size() > wrap)
|
||||
{
|
||||
stream << "\n";
|
||||
indent(stream, level + 1);
|
||||
}
|
||||
for (auto v : *this)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
stream << "," << seperator;
|
||||
if (index % wrap == 0)
|
||||
{
|
||||
stream << "\n";
|
||||
indent(stream, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
json::Value childPrintConfig = json::Value::null;
|
||||
if (!printConfig.isNull())
|
||||
{
|
||||
if (printConfig.isMember("elements"))
|
||||
childPrintConfig = printConfig["elements"];
|
||||
else if (printConfig.isMember("recursive") && printConfig["recursive"].asBool() == true)
|
||||
childPrintConfig = printConfig;
|
||||
}
|
||||
|
||||
v.prettyPrint(stream, childPrintConfig, level + 1);
|
||||
index++;
|
||||
}
|
||||
if ((long)size() > wrap)
|
||||
{
|
||||
stream << "\n";
|
||||
indent(stream, level);
|
||||
}
|
||||
stream << "]";
|
||||
break;
|
||||
}
|
||||
case Type::objectValue:
|
||||
{
|
||||
stream << "{\n";
|
||||
int wrap = 99999;
|
||||
if (value.arrayValue->size() > 10)
|
||||
wrap = 1;
|
||||
if (value.arrayValue->at(0).isArray() || value.arrayValue->at(0).isObject())
|
||||
wrap = 1;
|
||||
else
|
||||
wrap = 3;
|
||||
|
||||
std::string seperator = " ";
|
||||
|
||||
if (!printConfig.isNull() && printConfig.isMember("wrap"))
|
||||
wrap = printConfig["wrap"];
|
||||
if (!printConfig.isNull() && printConfig.isMember("seperator"))
|
||||
seperator = printConfig["seperator"].asString();
|
||||
|
||||
|
||||
int index = 0;
|
||||
indent(stream, level + 1);
|
||||
|
||||
|
||||
|
||||
//for (auto v : *value.objectValue)
|
||||
auto printEl = [&](const std::pair<const std::string&, const Value&> v)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
stream << "," << seperator;
|
||||
if (index % wrap == 0)
|
||||
{
|
||||
stream << "\n";
|
||||
indent(stream, level + 1);
|
||||
}
|
||||
}
|
||||
stream << "\"" << v.first << "\" : ";
|
||||
if (
|
||||
(v.second.isArray() || v.second.isObject()) &&
|
||||
(printConfig.isNull() ||
|
||||
(
|
||||
printConfig.isMember(v.first) &&
|
||||
printConfig[v.first].isObject() &&
|
||||
printConfig[v.first].isMember("wrap") &&
|
||||
printConfig[v.first]["wrap"].asInt() < (int)v.second.size())
|
||||
)
|
||||
)
|
||||
{
|
||||
stream << "\n";
|
||||
indent(stream, level + 1);
|
||||
}
|
||||
|
||||
json::Value childPrintConfig = json::Value::null;
|
||||
if (!printConfig.isNull())
|
||||
{
|
||||
if (printConfig.isMember(v.first))
|
||||
childPrintConfig = printConfig[v.first];
|
||||
else if (printConfig.isMember("recursive") && printConfig["recursive"].asBool() == true)
|
||||
childPrintConfig = printConfig;
|
||||
}
|
||||
|
||||
v.second.prettyPrint(stream, childPrintConfig, level + 1);;
|
||||
index++;
|
||||
};
|
||||
|
||||
|
||||
|
||||
std::set<std::string> printed;
|
||||
if (!printConfig.isNull())
|
||||
{
|
||||
if (printConfig.isMember("sort"))
|
||||
{
|
||||
for (std::string el : printConfig["sort"])
|
||||
{
|
||||
if (isMember(el))
|
||||
{
|
||||
printEl(std::pair<const std::string&, const Value&>(el, (*value.objectValue)[el]));
|
||||
printed.insert(el);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto v : *value.objectValue)
|
||||
if (printed.find(v.first) == printed.end())
|
||||
printEl(v);
|
||||
|
||||
stream << "\n";
|
||||
indent(stream, level);
|
||||
stream << "}";
|
||||
break;
|
||||
}
|
||||
case Type::nullValue:
|
||||
stream << "null";
|
||||
break;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
std::ostream & operator<<(std::ostream &stream, const Value& value)
|
||||
{
|
||||
stream << std::fixed<< std::setprecision(6);
|
||||
switch (value.type)
|
||||
{
|
||||
case Type::intValue:
|
||||
stream << value.value.intValue;
|
||||
break;
|
||||
case Type::floatValue:
|
||||
assert(!isnan(value.value.floatValue));
|
||||
//assert(isnormal(value.value.floatValue));
|
||||
stream << value.value.floatValue;
|
||||
break;
|
||||
case Type::boolValue:
|
||||
stream << (value.value.boolValue ? "true" : "false");
|
||||
break;
|
||||
case Type::stringValue:
|
||||
stream << "\"" << *value.value.stringValue << "\""; //TODO: escape \'s
|
||||
break;
|
||||
case Type::arrayValue:
|
||||
{
|
||||
stream << "[";
|
||||
bool first = true;
|
||||
for (auto v : value)
|
||||
{
|
||||
if (!first)
|
||||
stream << ", ";
|
||||
stream << v;
|
||||
first = false;
|
||||
}
|
||||
stream << "]";
|
||||
break;
|
||||
}
|
||||
case Type::objectValue:
|
||||
{
|
||||
stream << "{";
|
||||
bool first = true;
|
||||
for (auto v : *value.value.objectValue)
|
||||
{
|
||||
if (!first)
|
||||
stream << ", ";
|
||||
stream << "\"" << v.first << "\" : " << v.second << std::endl;
|
||||
first = false;
|
||||
}
|
||||
stream << "}";
|
||||
break;
|
||||
}
|
||||
case Type::nullValue:
|
||||
stream << "null";
|
||||
break;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
|
||||
namespace json
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
intValue,
|
||||
floatValue,
|
||||
boolValue,
|
||||
stringValue,
|
||||
arrayValue,
|
||||
objectValue,
|
||||
nullValue
|
||||
};
|
||||
|
||||
class Value
|
||||
{
|
||||
public:
|
||||
Type type;
|
||||
union ValueHolder
|
||||
{
|
||||
int intValue;
|
||||
float floatValue;
|
||||
bool boolValue;
|
||||
std::string* stringValue;
|
||||
std::vector<Value>* arrayValue;
|
||||
std::map<std::string, Value>* objectValue;
|
||||
} value;
|
||||
|
||||
static Value null;
|
||||
|
||||
Value();
|
||||
Value(Type type);
|
||||
Value(int value);
|
||||
Value(float value);
|
||||
Value(bool value);
|
||||
Value(const std::string &value);
|
||||
Value(const char* value);
|
||||
Value(const Value& other);
|
||||
virtual ~Value();
|
||||
|
||||
void operator = (const Value& other);
|
||||
|
||||
|
||||
|
||||
|
||||
inline operator int() const { return asInt(); }
|
||||
inline operator float() const { return asFloat(); }
|
||||
inline operator bool() const { return asBool(); }
|
||||
inline operator const std::string&() const { return asString(); }
|
||||
|
||||
|
||||
inline int asInt() const { assert(type == Type::intValue); return value.intValue; }
|
||||
inline float asFloat() const { assert(type == Type::floatValue || type == Type::intValue); return type == Type::floatValue ? value.floatValue : value.intValue; }
|
||||
inline bool asBool() const { assert(type == Type::boolValue); return value.boolValue; }
|
||||
inline const std::string& asString() const { assert(type == Type::stringValue); return *value.stringValue; }
|
||||
inline bool isNull() const { return type == Type::nullValue; }
|
||||
inline bool isString() const { return type == Type::stringValue; }
|
||||
inline bool isInt() const { return type == Type::intValue; }
|
||||
inline bool isBool() const { return type == Type::boolValue; }
|
||||
inline bool isFloat() const { return type == Type::floatValue; }
|
||||
inline bool isObject() const { return type == Type::objectValue; }
|
||||
inline bool isArray() const { return type == Type::arrayValue; }
|
||||
inline bool isMember(const std::string &name) const { assert(type == Type::objectValue); return value.objectValue->find(name) != value.objectValue->end(); }
|
||||
//array/object
|
||||
virtual size_t size() const;
|
||||
//array
|
||||
virtual void push_back(const Value& value);
|
||||
virtual void erase(size_t index);
|
||||
virtual Value& operator [] (size_t index);
|
||||
virtual Value& operator [] (int index);
|
||||
virtual Value& operator [] (size_t index) const;
|
||||
virtual Value& operator [] (int index) const;
|
||||
|
||||
virtual Value& operator [] (const std::string &key);
|
||||
virtual Value& operator [] (const char* key);
|
||||
virtual Value& operator [] (const std::string &key) const;
|
||||
virtual Value& operator [] (const char* key) const;
|
||||
|
||||
virtual bool operator == (const std::string &other) { return asString() == other; }
|
||||
virtual bool operator == (const int other) { return asInt() == other; }
|
||||
virtual bool operator == (const float other) { return asFloat() == other; }
|
||||
|
||||
|
||||
std::ostream& prettyPrint(std::ostream& stream, json::Value& printConfig = null, int level = 0) const;
|
||||
|
||||
class Iterator;
|
||||
Iterator begin() const;
|
||||
Iterator end() const;
|
||||
};
|
||||
|
||||
class Value::Iterator
|
||||
{
|
||||
private:
|
||||
Type type;
|
||||
std::map<std::string, Value>::iterator objectIterator;
|
||||
std::vector<Value>::iterator arrayIterator;
|
||||
public:
|
||||
Iterator(const std::map<std::string, Value>::iterator& objectIterator);
|
||||
Iterator(const std::vector<Value>::iterator& arrayIterator);
|
||||
|
||||
void operator ++();
|
||||
void operator ++(int);
|
||||
bool operator != (const Iterator &other);
|
||||
Value operator*();
|
||||
|
||||
std::string key();
|
||||
Value& value();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
Value readJson(const std::string &data);
|
||||
Value readJson(std::istream &stream);
|
||||
std::ostream &operator << (std::ostream &stream, const Value& value); //serializes json data
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/*!
|
||||
* \file serial/impl/unix.h
|
||||
* \author William Woodall <wjwwood@gmail.com>
|
||||
* \author John Harrison <ash@greaterthaninfinity.com>
|
||||
* \version 0.1
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 William Woodall, John Harrison
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* \section DESCRIPTION
|
||||
*
|
||||
* This provides a unix based pimpl for the Serial class. This implementation is
|
||||
* based off termios.h and uses select for multiplexing the IO ports.
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
#ifndef SERIAL_IMPL_UNIX_H
|
||||
#define SERIAL_IMPL_UNIX_H
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include "../serial.h"
|
||||
|
||||
namespace serial {
|
||||
|
||||
using std::size_t;
|
||||
using std::string;
|
||||
using std::invalid_argument;
|
||||
|
||||
using serial::SerialException;
|
||||
using serial::IOException;
|
||||
|
||||
class MillisecondTimer {
|
||||
public:
|
||||
MillisecondTimer(const uint32_t millis);
|
||||
int64_t remaining();
|
||||
|
||||
private:
|
||||
static timespec timespec_now();
|
||||
timespec expiry;
|
||||
};
|
||||
|
||||
class serial::Serial::SerialImpl {
|
||||
public:
|
||||
SerialImpl (const string &port,
|
||||
unsigned long baudrate,
|
||||
bytesize_t bytesize,
|
||||
parity_t parity,
|
||||
stopbits_t stopbits,
|
||||
flowcontrol_t flowcontrol);
|
||||
|
||||
virtual ~SerialImpl ();
|
||||
|
||||
void
|
||||
open ();
|
||||
|
||||
void
|
||||
close ();
|
||||
|
||||
bool
|
||||
isOpen () const;
|
||||
|
||||
size_t
|
||||
available ();
|
||||
|
||||
bool
|
||||
waitReadable (uint32_t timeout);
|
||||
|
||||
void
|
||||
waitByteTimes (size_t count);
|
||||
|
||||
size_t
|
||||
read (uint8_t *buf, size_t size = 1);
|
||||
|
||||
size_t
|
||||
write (const uint8_t *data, size_t length);
|
||||
|
||||
void
|
||||
flush ();
|
||||
|
||||
void
|
||||
flushInput ();
|
||||
|
||||
void
|
||||
flushOutput ();
|
||||
|
||||
void
|
||||
sendBreak (int duration);
|
||||
|
||||
void
|
||||
setBreak (bool level);
|
||||
|
||||
void
|
||||
setRTS (bool level);
|
||||
|
||||
void
|
||||
setDTR (bool level);
|
||||
|
||||
bool
|
||||
waitForChange ();
|
||||
|
||||
bool
|
||||
getCTS ();
|
||||
|
||||
bool
|
||||
getDSR ();
|
||||
|
||||
bool
|
||||
getRI ();
|
||||
|
||||
bool
|
||||
getCD ();
|
||||
|
||||
void
|
||||
setPort (const string &port);
|
||||
|
||||
string
|
||||
getPort () const;
|
||||
|
||||
void
|
||||
setTimeout (Timeout &timeout);
|
||||
|
||||
Timeout
|
||||
getTimeout () const;
|
||||
|
||||
void
|
||||
setBaudrate (unsigned long baudrate);
|
||||
|
||||
unsigned long
|
||||
getBaudrate () const;
|
||||
|
||||
void
|
||||
setBytesize (bytesize_t bytesize);
|
||||
|
||||
bytesize_t
|
||||
getBytesize () const;
|
||||
|
||||
void
|
||||
setParity (parity_t parity);
|
||||
|
||||
parity_t
|
||||
getParity () const;
|
||||
|
||||
void
|
||||
setStopbits (stopbits_t stopbits);
|
||||
|
||||
stopbits_t
|
||||
getStopbits () const;
|
||||
|
||||
void
|
||||
setFlowcontrol (flowcontrol_t flowcontrol);
|
||||
|
||||
flowcontrol_t
|
||||
getFlowcontrol () const;
|
||||
|
||||
void
|
||||
readLock ();
|
||||
|
||||
void
|
||||
readUnlock ();
|
||||
|
||||
void
|
||||
writeLock ();
|
||||
|
||||
void
|
||||
writeUnlock ();
|
||||
|
||||
protected:
|
||||
void reconfigurePort ();
|
||||
|
||||
private:
|
||||
string port_; // Path to the file descriptor
|
||||
int fd_; // The current file descriptor
|
||||
|
||||
bool is_open_;
|
||||
bool xonxoff_;
|
||||
bool rtscts_;
|
||||
|
||||
Timeout timeout_; // Timeout for read operations
|
||||
unsigned long baudrate_; // Baudrate
|
||||
uint32_t byte_time_ns_; // Nanoseconds to transmit/receive a single byte
|
||||
|
||||
parity_t parity_; // Parity
|
||||
bytesize_t bytesize_; // Size of the bytes
|
||||
stopbits_t stopbits_; // Stop Bits
|
||||
flowcontrol_t flowcontrol_; // Flow Control
|
||||
|
||||
// Mutex used to lock the read functions
|
||||
pthread_mutex_t read_mutex;
|
||||
// Mutex used to lock the write functions
|
||||
pthread_mutex_t write_mutex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SERIAL_IMPL_UNIX_H
|
||||
|
||||
#endif // !defined(_WIN32)
|
||||
@@ -0,0 +1,207 @@
|
||||
/*!
|
||||
* \file serial/impl/windows.h
|
||||
* \author William Woodall <wjwwood@gmail.com>
|
||||
* \author John Harrison <ash@greaterthaninfinity.com>
|
||||
* \version 0.1
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 William Woodall, John Harrison
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* \section DESCRIPTION
|
||||
*
|
||||
* This provides a windows implementation of the Serial class interface.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#ifndef SERIAL_IMPL_WINDOWS_H
|
||||
#define SERIAL_IMPL_WINDOWS_H
|
||||
|
||||
#include "include/serial.h"
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
namespace serial {
|
||||
|
||||
using std::string;
|
||||
using std::wstring;
|
||||
using std::invalid_argument;
|
||||
|
||||
using serial::SerialException;
|
||||
using serial::IOException;
|
||||
|
||||
class serial::Serial::SerialImpl {
|
||||
public:
|
||||
SerialImpl (const string &port,
|
||||
unsigned long baudrate,
|
||||
bytesize_t bytesize,
|
||||
parity_t parity,
|
||||
stopbits_t stopbits,
|
||||
flowcontrol_t flowcontrol);
|
||||
|
||||
virtual ~SerialImpl ();
|
||||
|
||||
void
|
||||
open ();
|
||||
|
||||
void
|
||||
close ();
|
||||
|
||||
bool
|
||||
isOpen () const;
|
||||
|
||||
size_t
|
||||
available ();
|
||||
|
||||
bool
|
||||
waitReadable (uint32_t timeout);
|
||||
|
||||
void
|
||||
waitByteTimes (size_t count);
|
||||
|
||||
size_t
|
||||
read (uint8_t *buf, size_t size = 1);
|
||||
|
||||
size_t
|
||||
write (const uint8_t *data, size_t length);
|
||||
|
||||
void
|
||||
flush ();
|
||||
|
||||
void
|
||||
flushInput ();
|
||||
|
||||
void
|
||||
flushOutput ();
|
||||
|
||||
void
|
||||
sendBreak (int duration);
|
||||
|
||||
void
|
||||
setBreak (bool level);
|
||||
|
||||
void
|
||||
setRTS (bool level);
|
||||
|
||||
void
|
||||
setDTR (bool level);
|
||||
|
||||
bool
|
||||
waitForChange ();
|
||||
|
||||
bool
|
||||
getCTS ();
|
||||
|
||||
bool
|
||||
getDSR ();
|
||||
|
||||
bool
|
||||
getRI ();
|
||||
|
||||
bool
|
||||
getCD ();
|
||||
|
||||
void
|
||||
setPort (const string &port);
|
||||
|
||||
string
|
||||
getPort () const;
|
||||
|
||||
void
|
||||
setTimeout (Timeout &timeout);
|
||||
|
||||
Timeout
|
||||
getTimeout () const;
|
||||
|
||||
void
|
||||
setBaudrate (unsigned long baudrate);
|
||||
|
||||
unsigned long
|
||||
getBaudrate () const;
|
||||
|
||||
void
|
||||
setBytesize (bytesize_t bytesize);
|
||||
|
||||
bytesize_t
|
||||
getBytesize () const;
|
||||
|
||||
void
|
||||
setParity (parity_t parity);
|
||||
|
||||
parity_t
|
||||
getParity () const;
|
||||
|
||||
void
|
||||
setStopbits (stopbits_t stopbits);
|
||||
|
||||
stopbits_t
|
||||
getStopbits () const;
|
||||
|
||||
void
|
||||
setFlowcontrol (flowcontrol_t flowcontrol);
|
||||
|
||||
flowcontrol_t
|
||||
getFlowcontrol () const;
|
||||
|
||||
void
|
||||
readLock ();
|
||||
|
||||
void
|
||||
readUnlock ();
|
||||
|
||||
void
|
||||
writeLock ();
|
||||
|
||||
void
|
||||
writeUnlock ();
|
||||
|
||||
protected:
|
||||
void reconfigurePort ();
|
||||
|
||||
private:
|
||||
wstring port_; // Path to the file descriptor
|
||||
HANDLE fd_;
|
||||
|
||||
bool is_open_;
|
||||
|
||||
Timeout timeout_; // Timeout for read operations
|
||||
unsigned long baudrate_; // Baudrate
|
||||
|
||||
parity_t parity_; // Parity
|
||||
bytesize_t bytesize_; // Size of the bytes
|
||||
stopbits_t stopbits_; // Stop Bits
|
||||
flowcontrol_t flowcontrol_; // Flow Control
|
||||
|
||||
// Mutex used to lock the read functions
|
||||
HANDLE read_mutex;
|
||||
// Mutex used to lock the write functions
|
||||
HANDLE write_mutex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SERIAL_IMPL_WINDOWS_H
|
||||
|
||||
#endif // if defined(_WIN32)
|
||||
@@ -0,0 +1,772 @@
|
||||
/*!
|
||||
* \file serial/serial.h
|
||||
* \author William Woodall <wjwwood@gmail.com>
|
||||
* \author John Harrison <ash.gti@gmail.com>
|
||||
* \version 0.1
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 William Woodall
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* \section DESCRIPTION
|
||||
*
|
||||
* This provides a cross platform interface for interacting with Serial Ports.
|
||||
*/
|
||||
|
||||
#ifndef SERIAL_H
|
||||
#define SERIAL_H
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
#define THROW(exceptionClass, message) throw exceptionClass(__FILE__, \
|
||||
__LINE__, (message) )
|
||||
|
||||
namespace serial {
|
||||
|
||||
/*!
|
||||
* Enumeration defines the possible bytesizes for the serial port.
|
||||
*/
|
||||
typedef enum {
|
||||
fivebits = 5,
|
||||
sixbits = 6,
|
||||
sevenbits = 7,
|
||||
eightbits = 8
|
||||
} bytesize_t;
|
||||
|
||||
/*!
|
||||
* Enumeration defines the possible parity types for the serial port.
|
||||
*/
|
||||
typedef enum {
|
||||
parity_none = 0,
|
||||
parity_odd = 1,
|
||||
parity_even = 2,
|
||||
parity_mark = 3,
|
||||
parity_space = 4
|
||||
} parity_t;
|
||||
|
||||
/*!
|
||||
* Enumeration defines the possible stopbit types for the serial port.
|
||||
*/
|
||||
typedef enum {
|
||||
stopbits_one = 1,
|
||||
stopbits_two = 2,
|
||||
stopbits_one_point_five
|
||||
} stopbits_t;
|
||||
|
||||
/*!
|
||||
* Enumeration defines the possible flowcontrol types for the serial port.
|
||||
*/
|
||||
typedef enum {
|
||||
flowcontrol_none = 0,
|
||||
flowcontrol_software,
|
||||
flowcontrol_hardware
|
||||
} flowcontrol_t;
|
||||
|
||||
/*!
|
||||
* Structure for setting the timeout of the serial port, times are
|
||||
* in milliseconds.
|
||||
*
|
||||
* In order to disable the interbyte timeout, set it to Timeout::max().
|
||||
*/
|
||||
struct Timeout {
|
||||
#ifdef max
|
||||
# undef max
|
||||
#endif
|
||||
static uint32_t max() {return std::numeric_limits<uint32_t>::max();}
|
||||
/*!
|
||||
* Convenience function to generate Timeout structs using a
|
||||
* single absolute timeout.
|
||||
*
|
||||
* \param timeout A long that defines the time in milliseconds until a
|
||||
* timeout occurs after a call to read or write is made.
|
||||
*
|
||||
* \return Timeout struct that represents this simple timeout provided.
|
||||
*/
|
||||
static Timeout simpleTimeout(uint32_t timeout) {
|
||||
return Timeout(max(), timeout, 0, timeout, 0);
|
||||
}
|
||||
|
||||
/*! Number of milliseconds between bytes received to timeout on. */
|
||||
uint32_t inter_byte_timeout;
|
||||
/*! A constant number of milliseconds to wait after calling read. */
|
||||
uint32_t read_timeout_constant;
|
||||
/*! A multiplier against the number of requested bytes to wait after
|
||||
* calling read.
|
||||
*/
|
||||
uint32_t read_timeout_multiplier;
|
||||
/*! A constant number of milliseconds to wait after calling write. */
|
||||
uint32_t write_timeout_constant;
|
||||
/*! A multiplier against the number of requested bytes to wait after
|
||||
* calling write.
|
||||
*/
|
||||
uint32_t write_timeout_multiplier;
|
||||
|
||||
explicit Timeout (uint32_t inter_byte_timeout_=0,
|
||||
uint32_t read_timeout_constant_=0,
|
||||
uint32_t read_timeout_multiplier_=0,
|
||||
uint32_t write_timeout_constant_=0,
|
||||
uint32_t write_timeout_multiplier_=0)
|
||||
: inter_byte_timeout(inter_byte_timeout_),
|
||||
read_timeout_constant(read_timeout_constant_),
|
||||
read_timeout_multiplier(read_timeout_multiplier_),
|
||||
write_timeout_constant(write_timeout_constant_),
|
||||
write_timeout_multiplier(write_timeout_multiplier_)
|
||||
{}
|
||||
};
|
||||
|
||||
/*!
|
||||
* Class that provides a portable serial port interface.
|
||||
*/
|
||||
class Serial {
|
||||
public:
|
||||
/*!
|
||||
* Creates a Serial object and opens the port if a port is specified,
|
||||
* otherwise it remains closed until serial::Serial::open is called.
|
||||
*
|
||||
* \param port A std::string containing the address of the serial port,
|
||||
* which would be something like 'COM1' on Windows and '/dev/ttyS0'
|
||||
* on Linux.
|
||||
*
|
||||
* \param baudrate An unsigned 32-bit integer that represents the baudrate
|
||||
*
|
||||
* \param timeout A serial::Timeout struct that defines the timeout
|
||||
* conditions for the serial port. \see serial::Timeout
|
||||
*
|
||||
* \param bytesize Size of each byte in the serial transmission of data,
|
||||
* default is eightbits, possible values are: fivebits, sixbits, sevenbits,
|
||||
* eightbits
|
||||
*
|
||||
* \param parity Method of parity, default is parity_none, possible values
|
||||
* are: parity_none, parity_odd, parity_even
|
||||
*
|
||||
* \param stopbits Number of stop bits used, default is stopbits_one,
|
||||
* possible values are: stopbits_one, stopbits_one_point_five, stopbits_two
|
||||
*
|
||||
* \param flowcontrol Type of flowcontrol used, default is
|
||||
* flowcontrol_none, possible values are: flowcontrol_none,
|
||||
* flowcontrol_software, flowcontrol_hardware
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::IOException
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
Serial (const std::string &port = "",
|
||||
uint32_t baudrate = 9600,
|
||||
Timeout timeout = Timeout(),
|
||||
bytesize_t bytesize = eightbits,
|
||||
parity_t parity = parity_none,
|
||||
stopbits_t stopbits = stopbits_one,
|
||||
flowcontrol_t flowcontrol = flowcontrol_none);
|
||||
|
||||
/*! Destructor */
|
||||
virtual ~Serial ();
|
||||
|
||||
/*!
|
||||
* Opens the serial port as long as the port is set and the port isn't
|
||||
* already open.
|
||||
*
|
||||
* If the port is provided to the constructor then an explicit call to open
|
||||
* is not needed.
|
||||
*
|
||||
* \see Serial::Serial
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
* \throw serial::SerialException
|
||||
* \throw serial::IOException
|
||||
*/
|
||||
void
|
||||
open ();
|
||||
|
||||
/*! Gets the open status of the serial port.
|
||||
*
|
||||
* \return Returns true if the port is open, false otherwise.
|
||||
*/
|
||||
bool
|
||||
isOpen () const;
|
||||
|
||||
/*! Closes the serial port. */
|
||||
void
|
||||
close ();
|
||||
|
||||
/*! Return the number of characters in the buffer. */
|
||||
size_t
|
||||
available ();
|
||||
|
||||
/*! Block until there is serial data to read or read_timeout_constant
|
||||
* number of milliseconds have elapsed. The return value is true when
|
||||
* the function exits with the port in a readable state, false otherwise
|
||||
* (due to timeout or select interruption). */
|
||||
bool
|
||||
waitReadable ();
|
||||
|
||||
/*! Block for a period of time corresponding to the transmission time of
|
||||
* count characters at present serial settings. This may be used in con-
|
||||
* junction with waitReadable to read larger blocks of data from the
|
||||
* port. */
|
||||
void
|
||||
waitByteTimes (size_t count);
|
||||
|
||||
/*! Read a given amount of bytes from the serial port into a given buffer.
|
||||
*
|
||||
* The read function will return in one of three cases:
|
||||
* * The number of requested bytes was read.
|
||||
* * In this case the number of bytes requested will match the size_t
|
||||
* returned by read.
|
||||
* * A timeout occurred, in this case the number of bytes read will not
|
||||
* match the amount requested, but no exception will be thrown. One of
|
||||
* two possible timeouts occurred:
|
||||
* * The inter byte timeout expired, this means that number of
|
||||
* milliseconds elapsed between receiving bytes from the serial port
|
||||
* exceeded the inter byte timeout.
|
||||
* * The total timeout expired, which is calculated by multiplying the
|
||||
* read timeout multiplier by the number of requested bytes and then
|
||||
* added to the read timeout constant. If that total number of
|
||||
* milliseconds elapses after the initial call to read a timeout will
|
||||
* occur.
|
||||
* * An exception occurred, in this case an actual exception will be thrown.
|
||||
*
|
||||
* \param buffer An uint8_t array of at least the requested size.
|
||||
* \param size A size_t defining how many bytes to be read.
|
||||
*
|
||||
* \return A size_t representing the number of bytes read as a result of the
|
||||
* call to read.
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::SerialException
|
||||
*/
|
||||
size_t
|
||||
read (uint8_t *buffer, size_t size);
|
||||
|
||||
/*! Read a given amount of bytes from the serial port into a give buffer.
|
||||
*
|
||||
* \param buffer A reference to a std::vector of uint8_t.
|
||||
* \param size A size_t defining how many bytes to be read.
|
||||
*
|
||||
* \return A size_t representing the number of bytes read as a result of the
|
||||
* call to read.
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::SerialException
|
||||
*/
|
||||
size_t
|
||||
read (std::vector<uint8_t> &buffer, size_t size = 1);
|
||||
|
||||
/*! Read a given amount of bytes from the serial port into a give buffer.
|
||||
*
|
||||
* \param buffer A reference to a std::string.
|
||||
* \param size A size_t defining how many bytes to be read.
|
||||
*
|
||||
* \return A size_t representing the number of bytes read as a result of the
|
||||
* call to read.
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::SerialException
|
||||
*/
|
||||
size_t
|
||||
read (std::string &buffer, size_t size = 1);
|
||||
|
||||
/*! Read a given amount of bytes from the serial port and return a string
|
||||
* containing the data.
|
||||
*
|
||||
* \param size A size_t defining how many bytes to be read.
|
||||
*
|
||||
* \return A std::string containing the data read from the port.
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::SerialException
|
||||
*/
|
||||
std::string
|
||||
read (size_t size = 1);
|
||||
|
||||
/*! Reads in a line or until a given delimiter has been processed.
|
||||
*
|
||||
* Reads from the serial port until a single line has been read.
|
||||
*
|
||||
* \param buffer A std::string reference used to store the data.
|
||||
* \param size A maximum length of a line, defaults to 65536 (2^16)
|
||||
* \param eol A string to match against for the EOL.
|
||||
*
|
||||
* \return A size_t representing the number of bytes read.
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::SerialException
|
||||
*/
|
||||
size_t
|
||||
readline (std::string &buffer, size_t size = 65536, std::string eol = "\n");
|
||||
|
||||
/*! Reads in a line or until a given delimiter has been processed.
|
||||
*
|
||||
* Reads from the serial port until a single line has been read.
|
||||
*
|
||||
* \param size A maximum length of a line, defaults to 65536 (2^16)
|
||||
* \param eol A string to match against for the EOL.
|
||||
*
|
||||
* \return A std::string containing the line.
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::SerialException
|
||||
*/
|
||||
std::string
|
||||
readline (size_t size = 65536, std::string eol = "\n");
|
||||
|
||||
/*! Reads in multiple lines until the serial port times out.
|
||||
*
|
||||
* This requires a timeout > 0 before it can be run. It will read until a
|
||||
* timeout occurs and return a list of strings.
|
||||
*
|
||||
* \param size A maximum length of combined lines, defaults to 65536 (2^16)
|
||||
*
|
||||
* \param eol A string to match against for the EOL.
|
||||
*
|
||||
* \return A vector<string> containing the lines.
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::SerialException
|
||||
*/
|
||||
std::vector<std::string>
|
||||
readlines (size_t size = 65536, std::string eol = "\n");
|
||||
|
||||
/*! Write a string to the serial port.
|
||||
*
|
||||
* \param data A const reference containing the data to be written
|
||||
* to the serial port.
|
||||
*
|
||||
* \param size A size_t that indicates how many bytes should be written from
|
||||
* the given data buffer.
|
||||
*
|
||||
* \return A size_t representing the number of bytes actually written to
|
||||
* the serial port.
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::SerialException
|
||||
* \throw serial::IOException
|
||||
*/
|
||||
size_t
|
||||
write (const uint8_t *data, size_t size);
|
||||
|
||||
/*! Write a string to the serial port.
|
||||
*
|
||||
* \param data A const reference containing the data to be written
|
||||
* to the serial port.
|
||||
*
|
||||
* \return A size_t representing the number of bytes actually written to
|
||||
* the serial port.
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::SerialException
|
||||
* \throw serial::IOException
|
||||
*/
|
||||
size_t
|
||||
write (const std::vector<uint8_t> &data);
|
||||
|
||||
/*! Write a string to the serial port.
|
||||
*
|
||||
* \param data A const reference containing the data to be written
|
||||
* to the serial port.
|
||||
*
|
||||
* \return A size_t representing the number of bytes actually written to
|
||||
* the serial port.
|
||||
*
|
||||
* \throw serial::PortNotOpenedException
|
||||
* \throw serial::SerialException
|
||||
* \throw serial::IOException
|
||||
*/
|
||||
size_t
|
||||
write (const std::string &data);
|
||||
|
||||
/*! Sets the serial port identifier.
|
||||
*
|
||||
* \param port A const std::string reference containing the address of the
|
||||
* serial port, which would be something like 'COM1' on Windows and
|
||||
* '/dev/ttyS0' on Linux.
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
void
|
||||
setPort (const std::string &port);
|
||||
|
||||
/*! Gets the serial port identifier.
|
||||
*
|
||||
* \see Serial::setPort
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
std::string
|
||||
getPort () const;
|
||||
|
||||
/*! Sets the timeout for reads and writes using the Timeout struct.
|
||||
*
|
||||
* There are two timeout conditions described here:
|
||||
* * The inter byte timeout:
|
||||
* * The inter_byte_timeout component of serial::Timeout defines the
|
||||
* maximum amount of time, in milliseconds, between receiving bytes on
|
||||
* the serial port that can pass before a timeout occurs. Setting this
|
||||
* to zero will prevent inter byte timeouts from occurring.
|
||||
* * Total time timeout:
|
||||
* * The constant and multiplier component of this timeout condition,
|
||||
* for both read and write, are defined in serial::Timeout. This
|
||||
* timeout occurs if the total time since the read or write call was
|
||||
* made exceeds the specified time in milliseconds.
|
||||
* * The limit is defined by multiplying the multiplier component by the
|
||||
* number of requested bytes and adding that product to the constant
|
||||
* component. In this way if you want a read call, for example, to
|
||||
* timeout after exactly one second regardless of the number of bytes
|
||||
* you asked for then set the read_timeout_constant component of
|
||||
* serial::Timeout to 1000 and the read_timeout_multiplier to zero.
|
||||
* This timeout condition can be used in conjunction with the inter
|
||||
* byte timeout condition with out any problems, timeout will simply
|
||||
* occur when one of the two timeout conditions is met. This allows
|
||||
* users to have maximum control over the trade-off between
|
||||
* responsiveness and efficiency.
|
||||
*
|
||||
* Read and write functions will return in one of three cases. When the
|
||||
* reading or writing is complete, when a timeout occurs, or when an
|
||||
* exception occurs.
|
||||
*
|
||||
* \param timeout A serial::Timeout struct containing the inter byte
|
||||
* timeout, and the read and write timeout constants and multipliers.
|
||||
*
|
||||
* \see serial::Timeout
|
||||
*/
|
||||
void
|
||||
setTimeout (Timeout &timeout);
|
||||
|
||||
/*! Sets the timeout for reads and writes. */
|
||||
void
|
||||
setTimeout (uint32_t inter_byte_timeout, uint32_t read_timeout_constant,
|
||||
uint32_t read_timeout_multiplier, uint32_t write_timeout_constant,
|
||||
uint32_t write_timeout_multiplier)
|
||||
{
|
||||
Timeout timeout(inter_byte_timeout, read_timeout_constant,
|
||||
read_timeout_multiplier, write_timeout_constant,
|
||||
write_timeout_multiplier);
|
||||
return setTimeout(timeout);
|
||||
}
|
||||
|
||||
/*! Gets the timeout for reads in seconds.
|
||||
*
|
||||
* \return A Timeout struct containing the inter_byte_timeout, and read
|
||||
* and write timeout constants and multipliers.
|
||||
*
|
||||
* \see Serial::setTimeout
|
||||
*/
|
||||
Timeout
|
||||
getTimeout () const;
|
||||
|
||||
/*! Sets the baudrate for the serial port.
|
||||
*
|
||||
* Possible baudrates depends on the system but some safe baudrates include:
|
||||
* 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 56000,
|
||||
* 57600, 115200
|
||||
* Some other baudrates that are supported by some comports:
|
||||
* 128000, 153600, 230400, 256000, 460800, 921600
|
||||
*
|
||||
* \param baudrate An integer that sets the baud rate for the serial port.
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
void
|
||||
setBaudrate (uint32_t baudrate);
|
||||
|
||||
/*! Gets the baudrate for the serial port.
|
||||
*
|
||||
* \return An integer that sets the baud rate for the serial port.
|
||||
*
|
||||
* \see Serial::setBaudrate
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
uint32_t
|
||||
getBaudrate () const;
|
||||
|
||||
/*! Sets the bytesize for the serial port.
|
||||
*
|
||||
* \param bytesize Size of each byte in the serial transmission of data,
|
||||
* default is eightbits, possible values are: fivebits, sixbits, sevenbits,
|
||||
* eightbits
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
void
|
||||
setBytesize (bytesize_t bytesize);
|
||||
|
||||
/*! Gets the bytesize for the serial port.
|
||||
*
|
||||
* \see Serial::setBytesize
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
bytesize_t
|
||||
getBytesize () const;
|
||||
|
||||
/*! Sets the parity for the serial port.
|
||||
*
|
||||
* \param parity Method of parity, default is parity_none, possible values
|
||||
* are: parity_none, parity_odd, parity_even
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
void
|
||||
setParity (parity_t parity);
|
||||
|
||||
/*! Gets the parity for the serial port.
|
||||
*
|
||||
* \see Serial::setParity
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
parity_t
|
||||
getParity () const;
|
||||
|
||||
/*! Sets the stopbits for the serial port.
|
||||
*
|
||||
* \param stopbits Number of stop bits used, default is stopbits_one,
|
||||
* possible values are: stopbits_one, stopbits_one_point_five, stopbits_two
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
void
|
||||
setStopbits (stopbits_t stopbits);
|
||||
|
||||
/*! Gets the stopbits for the serial port.
|
||||
*
|
||||
* \see Serial::setStopbits
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
stopbits_t
|
||||
getStopbits () const;
|
||||
|
||||
/*! Sets the flow control for the serial port.
|
||||
*
|
||||
* \param flowcontrol Type of flowcontrol used, default is flowcontrol_none,
|
||||
* possible values are: flowcontrol_none, flowcontrol_software,
|
||||
* flowcontrol_hardware
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
void
|
||||
setFlowcontrol (flowcontrol_t flowcontrol);
|
||||
|
||||
/*! Gets the flow control for the serial port.
|
||||
*
|
||||
* \see Serial::setFlowcontrol
|
||||
*
|
||||
* \throw std::invalid_argument
|
||||
*/
|
||||
flowcontrol_t
|
||||
getFlowcontrol () const;
|
||||
|
||||
/*! Flush the input and output buffers */
|
||||
void
|
||||
flush ();
|
||||
|
||||
/*! Flush only the input buffer */
|
||||
void
|
||||
flushInput ();
|
||||
|
||||
/*! Flush only the output buffer */
|
||||
void
|
||||
flushOutput ();
|
||||
|
||||
/*! Sends the RS-232 break signal. See tcsendbreak(3). */
|
||||
void
|
||||
sendBreak (int duration);
|
||||
|
||||
/*! Set the break condition to a given level. Defaults to true. */
|
||||
void
|
||||
setBreak (bool level = true);
|
||||
|
||||
/*! Set the RTS handshaking line to the given level. Defaults to true. */
|
||||
void
|
||||
setRTS (bool level = true);
|
||||
|
||||
/*! Set the DTR handshaking line to the given level. Defaults to true. */
|
||||
void
|
||||
setDTR (bool level = true);
|
||||
|
||||
/*!
|
||||
* Blocks until CTS, DSR, RI, CD changes or something interrupts it.
|
||||
*
|
||||
* Can throw an exception if an error occurs while waiting.
|
||||
* You can check the status of CTS, DSR, RI, and CD once this returns.
|
||||
* Uses TIOCMIWAIT via ioctl if available (mostly only on Linux) with a
|
||||
* resolution of less than +-1ms and as good as +-0.2ms. Otherwise a
|
||||
* polling method is used which can give +-2ms.
|
||||
*
|
||||
* \return Returns true if one of the lines changed, false if something else
|
||||
* occurred.
|
||||
*
|
||||
* \throw SerialException
|
||||
*/
|
||||
bool
|
||||
waitForChange ();
|
||||
|
||||
/*! Returns the current status of the CTS line. */
|
||||
bool
|
||||
getCTS ();
|
||||
|
||||
/*! Returns the current status of the DSR line. */
|
||||
bool
|
||||
getDSR ();
|
||||
|
||||
/*! Returns the current status of the RI line. */
|
||||
bool
|
||||
getRI ();
|
||||
|
||||
/*! Returns the current status of the CD line. */
|
||||
bool
|
||||
getCD ();
|
||||
|
||||
private:
|
||||
// Disable copy constructors
|
||||
Serial(const Serial&);
|
||||
Serial& operator=(const Serial&);
|
||||
|
||||
// Pimpl idiom, d_pointer
|
||||
class SerialImpl;
|
||||
SerialImpl *pimpl_;
|
||||
|
||||
// Scoped Lock Classes
|
||||
class ScopedReadLock;
|
||||
class ScopedWriteLock;
|
||||
|
||||
// Read common function
|
||||
size_t
|
||||
read_ (uint8_t *buffer, size_t size);
|
||||
// Write common function
|
||||
size_t
|
||||
write_ (const uint8_t *data, size_t length);
|
||||
|
||||
};
|
||||
|
||||
class SerialException : public std::exception
|
||||
{
|
||||
// Disable copy constructors
|
||||
SerialException& operator=(const SerialException&);
|
||||
std::string e_what_;
|
||||
public:
|
||||
SerialException (const char *description) {
|
||||
std::stringstream ss;
|
||||
ss << "SerialException " << description << " failed.";
|
||||
e_what_ = ss.str();
|
||||
}
|
||||
SerialException (const SerialException& other) : e_what_(other.e_what_) {}
|
||||
virtual ~SerialException() throw() {}
|
||||
virtual const char* what () const throw () {
|
||||
return e_what_.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class IOException : public std::exception
|
||||
{
|
||||
// Disable copy constructors
|
||||
IOException& operator=(const IOException&);
|
||||
std::string file_;
|
||||
int line_;
|
||||
std::string e_what_;
|
||||
int errno_;
|
||||
public:
|
||||
explicit IOException (std::string file, int line, int errnum)
|
||||
: file_(file), line_(line), errno_(errnum) {
|
||||
std::stringstream ss;
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
char error_str [1024];
|
||||
strerror_s(error_str, 1024, errnum);
|
||||
#else
|
||||
char * error_str = strerror(errnum);
|
||||
#endif
|
||||
ss << "IO Exception (" << errno_ << "): " << error_str;
|
||||
ss << ", file " << file_ << ", line " << line_ << ".";
|
||||
e_what_ = ss.str();
|
||||
}
|
||||
explicit IOException (std::string file, int line, const char * description)
|
||||
: file_(file), line_(line), errno_(0) {
|
||||
std::stringstream ss;
|
||||
ss << "IO Exception: " << description;
|
||||
ss << ", file " << file_ << ", line " << line_ << ".";
|
||||
e_what_ = ss.str();
|
||||
}
|
||||
virtual ~IOException() throw() {}
|
||||
IOException (const IOException& other) : line_(other.line_), e_what_(other.e_what_), errno_(other.errno_) {}
|
||||
|
||||
int getErrorNumber () { return errno_; }
|
||||
|
||||
virtual const char* what () const throw () {
|
||||
return e_what_.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class PortNotOpenedException : public std::exception
|
||||
{
|
||||
// Disable copy constructors
|
||||
const PortNotOpenedException& operator=(PortNotOpenedException);
|
||||
std::string e_what_;
|
||||
public:
|
||||
PortNotOpenedException (const char * description) {
|
||||
std::stringstream ss;
|
||||
ss << "PortNotOpenedException " << description << " failed.";
|
||||
e_what_ = ss.str();
|
||||
}
|
||||
PortNotOpenedException (const PortNotOpenedException& other) : e_what_(other.e_what_) {}
|
||||
virtual ~PortNotOpenedException() throw() {}
|
||||
virtual const char* what () const throw () {
|
||||
return e_what_.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* Structure that describes a serial device.
|
||||
*/
|
||||
struct PortInfo {
|
||||
|
||||
/*! Address of the serial port (this can be passed to the constructor of Serial). */
|
||||
std::string port;
|
||||
|
||||
/*! Human readable description of serial device if available. */
|
||||
std::string description;
|
||||
|
||||
/*! Hardware ID (e.g. VID:PID of USB serial devices) or "n/a" if not available. */
|
||||
std::string hardware_id;
|
||||
|
||||
};
|
||||
|
||||
/* Lists the serial ports available on the system
|
||||
*
|
||||
* Returns a vector of available serial ports, each represented
|
||||
* by a serial::PortInfo data structure:
|
||||
*
|
||||
* \return vector of serial::PortInfo.
|
||||
*/
|
||||
std::vector<PortInfo>
|
||||
list_ports();
|
||||
|
||||
} // namespace serial
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
// This header is from the v8 google project:
|
||||
// http://code.google.com/p/v8/source/browse/trunk/include/v8stdint.h
|
||||
|
||||
// Copyright 2012 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Load definitions of standard types.
|
||||
|
||||
#ifndef V8STDINT_H_
|
||||
#define V8STDINT_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef short int16_t; // NOLINT
|
||||
typedef unsigned short uint16_t; // NOLINT
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
// intptr_t and friends are defined in crtdefs.h through stdio.h.
|
||||
|
||||
#else
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#endif
|
||||
|
||||
#endif // V8STDINT_H_
|
||||
@@ -0,0 +1,335 @@
|
||||
#if defined(__linux__)
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Craig Lilley <cralilley@gmail.com>
|
||||
* This software is made available under the terms of the MIT licence.
|
||||
* A copy of the licence can be obtained from:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <glob.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include "../../../include/serial.h"
|
||||
|
||||
|
||||
using serial::PortInfo;
|
||||
using std::istringstream;
|
||||
using std::ifstream;
|
||||
using std::getline;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
static vector<string> glob(const vector<string>& patterns);
|
||||
static string basename(const string& path);
|
||||
static string dirname(const string& path);
|
||||
static bool path_exists(const string& path);
|
||||
static string realpath(const string& path);
|
||||
static string usb_sysfs_friendly_name(const string& sys_usb_path);
|
||||
static vector<string> get_sysfs_info(const string& device_path);
|
||||
static string read_line(const string& file);
|
||||
static string usb_sysfs_hw_string(const string& sysfs_path);
|
||||
static string format(const char* format, ...);
|
||||
|
||||
vector<string>
|
||||
glob(const vector<string>& patterns)
|
||||
{
|
||||
vector<string> paths_found;
|
||||
|
||||
if(patterns.size() == 0)
|
||||
return paths_found;
|
||||
|
||||
glob_t glob_results;
|
||||
|
||||
int glob_retval = glob(patterns[0].c_str(), 0, NULL, &glob_results);
|
||||
|
||||
vector<string>::const_iterator iter = patterns.begin();
|
||||
|
||||
while(++iter != patterns.end())
|
||||
{
|
||||
glob_retval = glob(iter->c_str(), GLOB_APPEND, NULL, &glob_results);
|
||||
}
|
||||
|
||||
for(int path_index = 0; path_index < glob_results.gl_pathc; path_index++)
|
||||
{
|
||||
paths_found.push_back(glob_results.gl_pathv[path_index]);
|
||||
}
|
||||
|
||||
globfree(&glob_results);
|
||||
|
||||
return paths_found;
|
||||
}
|
||||
|
||||
string
|
||||
basename(const string& path)
|
||||
{
|
||||
size_t pos = path.rfind("/");
|
||||
|
||||
if(pos == std::string::npos)
|
||||
return path;
|
||||
|
||||
return string(path, pos+1, string::npos);
|
||||
}
|
||||
|
||||
string
|
||||
dirname(const string& path)
|
||||
{
|
||||
size_t pos = path.rfind("/");
|
||||
|
||||
if(pos == std::string::npos)
|
||||
return path;
|
||||
else if(pos == 0)
|
||||
return "/";
|
||||
|
||||
return string(path, 0, pos);
|
||||
}
|
||||
|
||||
bool
|
||||
path_exists(const string& path)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if( stat(path.c_str(), &sb ) == 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string
|
||||
realpath(const string& path)
|
||||
{
|
||||
char* real_path = realpath(path.c_str(), NULL);
|
||||
|
||||
string result;
|
||||
|
||||
if(real_path != NULL)
|
||||
{
|
||||
result = real_path;
|
||||
|
||||
free(real_path);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string
|
||||
usb_sysfs_friendly_name(const string& sys_usb_path)
|
||||
{
|
||||
unsigned int device_number = 0;
|
||||
|
||||
istringstream( read_line(sys_usb_path + "/devnum") ) >> device_number;
|
||||
|
||||
string manufacturer = read_line( sys_usb_path + "/manufacturer" );
|
||||
|
||||
string product = read_line( sys_usb_path + "/product" );
|
||||
|
||||
string serial = read_line( sys_usb_path + "/serial" );
|
||||
|
||||
if( manufacturer.empty() && product.empty() && serial.empty() )
|
||||
return "";
|
||||
|
||||
return format("%s %s %s", manufacturer.c_str(), product.c_str(), serial.c_str() );
|
||||
}
|
||||
|
||||
vector<string>
|
||||
get_sysfs_info(const string& device_path)
|
||||
{
|
||||
string device_name = basename( device_path );
|
||||
|
||||
string friendly_name;
|
||||
|
||||
string hardware_id;
|
||||
|
||||
string sys_device_path = format( "/sys/class/tty/%s/device", device_name.c_str() );
|
||||
|
||||
if( device_name.compare(0,6,"ttyUSB") == 0 )
|
||||
{
|
||||
sys_device_path = dirname( dirname( realpath( sys_device_path ) ) );
|
||||
|
||||
if( path_exists( sys_device_path ) )
|
||||
{
|
||||
friendly_name = usb_sysfs_friendly_name( sys_device_path );
|
||||
|
||||
hardware_id = usb_sysfs_hw_string( sys_device_path );
|
||||
}
|
||||
}
|
||||
else if( device_name.compare(0,6,"ttyACM") == 0 )
|
||||
{
|
||||
sys_device_path = dirname( realpath( sys_device_path ) );
|
||||
|
||||
if( path_exists( sys_device_path ) )
|
||||
{
|
||||
friendly_name = usb_sysfs_friendly_name( sys_device_path );
|
||||
|
||||
hardware_id = usb_sysfs_hw_string( sys_device_path );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to read ID string of PCI device
|
||||
|
||||
string sys_id_path = sys_device_path + "/id";
|
||||
|
||||
if( path_exists( sys_id_path ) )
|
||||
hardware_id = read_line( sys_id_path );
|
||||
}
|
||||
|
||||
if( friendly_name.empty() )
|
||||
friendly_name = device_name;
|
||||
|
||||
if( hardware_id.empty() )
|
||||
hardware_id = "n/a";
|
||||
|
||||
vector<string> result;
|
||||
result.push_back(friendly_name);
|
||||
result.push_back(hardware_id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string
|
||||
read_line(const string& file)
|
||||
{
|
||||
ifstream ifs(file.c_str(), ifstream::in);
|
||||
|
||||
string line;
|
||||
|
||||
if(ifs)
|
||||
{
|
||||
getline(ifs, line);
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
string
|
||||
format(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
size_t buffer_size_bytes = 256;
|
||||
|
||||
string result;
|
||||
|
||||
char* buffer = (char*)malloc(buffer_size_bytes);
|
||||
|
||||
if( buffer == NULL )
|
||||
return result;
|
||||
|
||||
bool done = false;
|
||||
|
||||
unsigned int loop_count = 0;
|
||||
|
||||
while(!done)
|
||||
{
|
||||
va_start(ap, format);
|
||||
|
||||
int return_value = vsnprintf(buffer, buffer_size_bytes, format, ap);
|
||||
|
||||
if( return_value < 0 )
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
else if( return_value >= buffer_size_bytes )
|
||||
{
|
||||
// Realloc and try again.
|
||||
|
||||
buffer_size_bytes = return_value + 1;
|
||||
|
||||
char* new_buffer_ptr = (char*)realloc(buffer, buffer_size_bytes);
|
||||
|
||||
if( new_buffer_ptr == NULL )
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = new_buffer_ptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = buffer;
|
||||
done = true;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if( ++loop_count > 5 )
|
||||
done = true;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string
|
||||
usb_sysfs_hw_string(const string& sysfs_path)
|
||||
{
|
||||
string serial_number = read_line( sysfs_path + "/serial" );
|
||||
|
||||
if( serial_number.length() > 0 )
|
||||
{
|
||||
serial_number = format( "SNR=%s", serial_number.c_str() );
|
||||
}
|
||||
|
||||
string vid = read_line( sysfs_path + "/idVendor" );
|
||||
|
||||
string pid = read_line( sysfs_path + "/idProduct" );
|
||||
|
||||
return format("USB VID:PID=%s:%s %s", vid.c_str(), pid.c_str(), serial_number.c_str() );
|
||||
}
|
||||
|
||||
vector<PortInfo>
|
||||
serial::list_ports()
|
||||
{
|
||||
vector<PortInfo> results;
|
||||
|
||||
vector<string> search_globs;
|
||||
search_globs.push_back("/dev/ttyACM*");
|
||||
search_globs.push_back("/dev/ttyS*");
|
||||
search_globs.push_back("/dev/ttyUSB*");
|
||||
search_globs.push_back("/dev/tty.*");
|
||||
search_globs.push_back("/dev/cu.*");
|
||||
|
||||
vector<string> devices_found = glob( search_globs );
|
||||
|
||||
vector<string>::iterator iter = devices_found.begin();
|
||||
|
||||
while( iter != devices_found.end() )
|
||||
{
|
||||
string device = *iter++;
|
||||
|
||||
vector<string> sysfs_info = get_sysfs_info( device );
|
||||
|
||||
string friendly_name = sysfs_info[0];
|
||||
|
||||
string hardware_id = sysfs_info[1];
|
||||
|
||||
PortInfo device_entry;
|
||||
device_entry.port = device;
|
||||
device_entry.description = friendly_name;
|
||||
device_entry.hardware_id = hardware_id;
|
||||
|
||||
results.push_back( device_entry );
|
||||
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
#endif // defined(__linux__)
|
||||
@@ -0,0 +1,286 @@
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/serial/IOSerialKeys.h>
|
||||
#include <IOKit/IOBSD.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "serial/serial.h"
|
||||
|
||||
using serial::PortInfo;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#define HARDWARE_ID_STRING_LENGTH 128
|
||||
|
||||
string cfstring_to_string( CFStringRef cfstring );
|
||||
string get_device_path( io_object_t& serial_port );
|
||||
string get_class_name( io_object_t& obj );
|
||||
io_registry_entry_t get_parent_iousb_device( io_object_t& serial_port );
|
||||
string get_string_property( io_object_t& device, const char* property );
|
||||
uint16_t get_int_property( io_object_t& device, const char* property );
|
||||
string rtrim(const string& str);
|
||||
|
||||
string
|
||||
cfstring_to_string( CFStringRef cfstring )
|
||||
{
|
||||
char cstring[MAXPATHLEN];
|
||||
string result;
|
||||
|
||||
if( cfstring )
|
||||
{
|
||||
Boolean success = CFStringGetCString( cfstring,
|
||||
cstring,
|
||||
sizeof(cstring),
|
||||
kCFStringEncodingASCII );
|
||||
|
||||
if( success )
|
||||
result = cstring;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string
|
||||
get_device_path( io_object_t& serial_port )
|
||||
{
|
||||
CFTypeRef callout_path;
|
||||
string device_path;
|
||||
|
||||
callout_path = IORegistryEntryCreateCFProperty( serial_port,
|
||||
CFSTR(kIOCalloutDeviceKey),
|
||||
kCFAllocatorDefault,
|
||||
0 );
|
||||
|
||||
if (callout_path)
|
||||
{
|
||||
if( CFGetTypeID(callout_path) == CFStringGetTypeID() )
|
||||
device_path = cfstring_to_string( static_cast<CFStringRef>(callout_path) );
|
||||
|
||||
CFRelease(callout_path);
|
||||
}
|
||||
|
||||
return device_path;
|
||||
}
|
||||
|
||||
string
|
||||
get_class_name( io_object_t& obj )
|
||||
{
|
||||
string result;
|
||||
io_name_t class_name;
|
||||
kern_return_t kern_result;
|
||||
|
||||
kern_result = IOObjectGetClass( obj, class_name );
|
||||
|
||||
if( kern_result == KERN_SUCCESS )
|
||||
result = class_name;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
io_registry_entry_t
|
||||
get_parent_iousb_device( io_object_t& serial_port )
|
||||
{
|
||||
io_object_t device = serial_port;
|
||||
io_registry_entry_t parent = 0;
|
||||
io_registry_entry_t result = 0;
|
||||
kern_return_t kern_result = KERN_FAILURE;
|
||||
string name = get_class_name(device);
|
||||
|
||||
// Walk the IO Registry tree looking for this devices parent IOUSBDevice.
|
||||
while( name != "IOUSBDevice" )
|
||||
{
|
||||
kern_result = IORegistryEntryGetParentEntry( device,
|
||||
kIOServicePlane,
|
||||
&parent );
|
||||
|
||||
if(kern_result != KERN_SUCCESS)
|
||||
{
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
device = parent;
|
||||
|
||||
name = get_class_name(device);
|
||||
}
|
||||
|
||||
if(kern_result == KERN_SUCCESS)
|
||||
result = device;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string
|
||||
get_string_property( io_object_t& device, const char* property )
|
||||
{
|
||||
string property_name;
|
||||
|
||||
if( device )
|
||||
{
|
||||
CFStringRef property_as_cfstring = CFStringCreateWithCString (
|
||||
kCFAllocatorDefault,
|
||||
property,
|
||||
kCFStringEncodingASCII );
|
||||
|
||||
CFTypeRef name_as_cfstring = IORegistryEntryCreateCFProperty(
|
||||
device,
|
||||
property_as_cfstring,
|
||||
kCFAllocatorDefault,
|
||||
0 );
|
||||
|
||||
if( name_as_cfstring )
|
||||
{
|
||||
if( CFGetTypeID(name_as_cfstring) == CFStringGetTypeID() )
|
||||
property_name = cfstring_to_string( static_cast<CFStringRef>(name_as_cfstring) );
|
||||
|
||||
CFRelease(name_as_cfstring);
|
||||
}
|
||||
|
||||
if(property_as_cfstring)
|
||||
CFRelease(property_as_cfstring);
|
||||
}
|
||||
|
||||
return property_name;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
get_int_property( io_object_t& device, const char* property )
|
||||
{
|
||||
uint16_t result = 0;
|
||||
|
||||
if( device )
|
||||
{
|
||||
CFStringRef property_as_cfstring = CFStringCreateWithCString (
|
||||
kCFAllocatorDefault,
|
||||
property,
|
||||
kCFStringEncodingASCII );
|
||||
|
||||
CFTypeRef number = IORegistryEntryCreateCFProperty( device,
|
||||
property_as_cfstring,
|
||||
kCFAllocatorDefault,
|
||||
0 );
|
||||
|
||||
if(property_as_cfstring)
|
||||
CFRelease(property_as_cfstring);
|
||||
|
||||
if( number )
|
||||
{
|
||||
if( CFGetTypeID(number) == CFNumberGetTypeID() )
|
||||
{
|
||||
bool success = CFNumberGetValue( static_cast<CFNumberRef>(number),
|
||||
kCFNumberSInt16Type,
|
||||
&result );
|
||||
|
||||
if( !success )
|
||||
result = 0;
|
||||
}
|
||||
|
||||
CFRelease(number);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string rtrim(const string& str)
|
||||
{
|
||||
string result = str;
|
||||
|
||||
string whitespace = " \t\f\v\n\r";
|
||||
|
||||
std::size_t found = result.find_last_not_of(whitespace);
|
||||
|
||||
if (found != std::string::npos)
|
||||
result.erase(found+1);
|
||||
else
|
||||
result.clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<PortInfo>
|
||||
serial::list_ports(void)
|
||||
{
|
||||
vector<PortInfo> devices_found;
|
||||
CFMutableDictionaryRef classes_to_match;
|
||||
io_iterator_t serial_port_iterator;
|
||||
io_object_t serial_port;
|
||||
mach_port_t master_port;
|
||||
kern_return_t kern_result;
|
||||
|
||||
kern_result = IOMasterPort(MACH_PORT_NULL, &master_port);
|
||||
|
||||
if(kern_result != KERN_SUCCESS)
|
||||
return devices_found;
|
||||
|
||||
classes_to_match = IOServiceMatching(kIOSerialBSDServiceValue);
|
||||
|
||||
if (classes_to_match == NULL)
|
||||
return devices_found;
|
||||
|
||||
CFDictionarySetValue( classes_to_match,
|
||||
CFSTR(kIOSerialBSDTypeKey),
|
||||
CFSTR(kIOSerialBSDAllTypes) );
|
||||
|
||||
kern_result = IOServiceGetMatchingServices(master_port, classes_to_match, &serial_port_iterator);
|
||||
|
||||
if (KERN_SUCCESS != kern_result)
|
||||
return devices_found;
|
||||
|
||||
while ( (serial_port = IOIteratorNext(serial_port_iterator)) )
|
||||
{
|
||||
string device_path = get_device_path( serial_port );
|
||||
io_registry_entry_t parent = get_parent_iousb_device( serial_port );
|
||||
IOObjectRelease(serial_port);
|
||||
|
||||
if( device_path.empty() )
|
||||
continue;
|
||||
|
||||
PortInfo port_info;
|
||||
port_info.port = device_path;
|
||||
port_info.description = "n/a";
|
||||
port_info.hardware_id = "n/a";
|
||||
|
||||
string device_name = rtrim( get_string_property( parent, "USB Product Name" ) );
|
||||
string vendor_name = rtrim( get_string_property( parent, "USB Vendor Name") );
|
||||
string description = rtrim( vendor_name + " " + device_name );
|
||||
if( !description.empty() )
|
||||
port_info.description = description;
|
||||
|
||||
string serial_number = rtrim(get_string_property( parent, "USB Serial Number" ) );
|
||||
uint16_t vendor_id = get_int_property( parent, "idVendor" );
|
||||
uint16_t product_id = get_int_property( parent, "idProduct" );
|
||||
|
||||
if( vendor_id && product_id )
|
||||
{
|
||||
char cstring[HARDWARE_ID_STRING_LENGTH];
|
||||
|
||||
if(serial_number.empty())
|
||||
serial_number = "None";
|
||||
|
||||
int ret = snprintf( cstring, HARDWARE_ID_STRING_LENGTH, "USB VID:PID=%04x:%04x SNR=%s",
|
||||
vendor_id,
|
||||
product_id,
|
||||
serial_number.c_str() );
|
||||
|
||||
if( (ret >= 0) && (ret < HARDWARE_ID_STRING_LENGTH) )
|
||||
port_info.hardware_id = cstring;
|
||||
}
|
||||
|
||||
devices_found.push_back(port_info);
|
||||
}
|
||||
|
||||
IOObjectRelease(serial_port_iterator);
|
||||
return devices_found;
|
||||
}
|
||||
|
||||
#endif // defined(__APPLE__)
|
||||
@@ -0,0 +1,152 @@
|
||||
#if defined(_WIN32)
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Craig Lilley <cralilley@gmail.com>
|
||||
* This software is made available under the terms of the MIT licence.
|
||||
* A copy of the licence can be obtained from:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "include/serial.h"
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
#include <initguid.h>
|
||||
#include <devguid.h>
|
||||
#include <cstring>
|
||||
|
||||
using serial::PortInfo;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
static const DWORD port_name_max_length = 256;
|
||||
static const DWORD friendly_name_max_length = 256;
|
||||
static const DWORD hardware_id_max_length = 256;
|
||||
|
||||
// Convert a wide Unicode string to an UTF8 string
|
||||
std::string utf8_encode(const std::wstring &wstr)
|
||||
{
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
|
||||
std::string strTo( size_needed, 0 );
|
||||
WideCharToMultiByte (CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
|
||||
return strTo;
|
||||
}
|
||||
|
||||
vector<PortInfo>
|
||||
serial::list_ports()
|
||||
{
|
||||
vector<PortInfo> devices_found;
|
||||
|
||||
HDEVINFO device_info_set = SetupDiGetClassDevs(
|
||||
(const GUID *) &GUID_DEVCLASS_PORTS,
|
||||
NULL,
|
||||
NULL,
|
||||
DIGCF_PRESENT);
|
||||
|
||||
unsigned int device_info_set_index = 0;
|
||||
SP_DEVINFO_DATA device_info_data;
|
||||
|
||||
device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
|
||||
while(SetupDiEnumDeviceInfo(device_info_set, device_info_set_index, &device_info_data))
|
||||
{
|
||||
device_info_set_index++;
|
||||
|
||||
// Get port name
|
||||
|
||||
HKEY hkey = SetupDiOpenDevRegKey(
|
||||
device_info_set,
|
||||
&device_info_data,
|
||||
DICS_FLAG_GLOBAL,
|
||||
0,
|
||||
DIREG_DEV,
|
||||
KEY_READ);
|
||||
|
||||
TCHAR port_name[port_name_max_length];
|
||||
DWORD port_name_length = port_name_max_length;
|
||||
|
||||
LONG return_code = RegQueryValueEx(
|
||||
hkey,
|
||||
_T("PortName"),
|
||||
NULL,
|
||||
NULL,
|
||||
(LPBYTE)port_name,
|
||||
&port_name_length);
|
||||
|
||||
RegCloseKey(hkey);
|
||||
|
||||
if(return_code != EXIT_SUCCESS)
|
||||
continue;
|
||||
|
||||
if(port_name_length > 0 && port_name_length <= port_name_max_length)
|
||||
port_name[port_name_length-1] = '\0';
|
||||
else
|
||||
port_name[0] = '\0';
|
||||
|
||||
// Ignore parallel ports
|
||||
|
||||
if(_tcsstr(port_name, _T("LPT")) != NULL)
|
||||
continue;
|
||||
|
||||
// Get port friendly name
|
||||
|
||||
TCHAR friendly_name[friendly_name_max_length];
|
||||
DWORD friendly_name_actual_length = 0;
|
||||
|
||||
BOOL got_friendly_name = SetupDiGetDeviceRegistryProperty(
|
||||
device_info_set,
|
||||
&device_info_data,
|
||||
SPDRP_FRIENDLYNAME,
|
||||
NULL,
|
||||
(PBYTE)friendly_name,
|
||||
friendly_name_max_length,
|
||||
&friendly_name_actual_length);
|
||||
|
||||
if(got_friendly_name == TRUE && friendly_name_actual_length > 0)
|
||||
friendly_name[friendly_name_actual_length-1] = '\0';
|
||||
else
|
||||
friendly_name[0] = '\0';
|
||||
|
||||
// Get hardware ID
|
||||
|
||||
TCHAR hardware_id[hardware_id_max_length];
|
||||
DWORD hardware_id_actual_length = 0;
|
||||
|
||||
BOOL got_hardware_id = SetupDiGetDeviceRegistryProperty(
|
||||
device_info_set,
|
||||
&device_info_data,
|
||||
SPDRP_HARDWAREID,
|
||||
NULL,
|
||||
(PBYTE)hardware_id,
|
||||
hardware_id_max_length,
|
||||
&hardware_id_actual_length);
|
||||
|
||||
if(got_hardware_id == TRUE && hardware_id_actual_length > 0)
|
||||
hardware_id[hardware_id_actual_length-1] = '\0';
|
||||
else
|
||||
hardware_id[0] = '\0';
|
||||
|
||||
#ifdef UNICODE
|
||||
std::string portName = utf8_encode(port_name);
|
||||
std::string friendlyName = utf8_encode(friendly_name);
|
||||
std::string hardwareId = utf8_encode(hardware_id);
|
||||
#else
|
||||
std::string portName = port_name;
|
||||
std::string friendlyName = friendly_name;
|
||||
std::string hardwareId = hardware_id;
|
||||
#endif
|
||||
|
||||
PortInfo port_entry;
|
||||
port_entry.port = portName;
|
||||
port_entry.description = friendlyName;
|
||||
port_entry.hardware_id = hardwareId;
|
||||
|
||||
devices_found.push_back(port_entry);
|
||||
}
|
||||
|
||||
SetupDiDestroyDeviceInfoList(device_info_set);
|
||||
|
||||
return devices_found;
|
||||
}
|
||||
|
||||
#endif // #if defined(_WIN32)
|
||||
@@ -0,0 +1,640 @@
|
||||
#if defined(_WIN32)
|
||||
|
||||
/* Copyright 2012 William Woodall and John Harrison */
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "include/impl/win.h"
|
||||
|
||||
using std::string;
|
||||
using std::wstring;
|
||||
using std::stringstream;
|
||||
using std::invalid_argument;
|
||||
using serial::Serial;
|
||||
using serial::Timeout;
|
||||
using serial::bytesize_t;
|
||||
using serial::parity_t;
|
||||
using serial::stopbits_t;
|
||||
using serial::flowcontrol_t;
|
||||
using serial::SerialException;
|
||||
using serial::PortNotOpenedException;
|
||||
using serial::IOException;
|
||||
|
||||
inline wstring
|
||||
_prefix_port_if_needed(const wstring &input)
|
||||
{
|
||||
static wstring windows_com_port_prefix = L"\\\\.\\";
|
||||
if (input.compare(windows_com_port_prefix) != 0)
|
||||
{
|
||||
return windows_com_port_prefix + input;
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate,
|
||||
bytesize_t bytesize,
|
||||
parity_t parity, stopbits_t stopbits,
|
||||
flowcontrol_t flowcontrol)
|
||||
: port_ (port.begin(), port.end()), fd_ (INVALID_HANDLE_VALUE), is_open_ (false),
|
||||
baudrate_ (baudrate), parity_ (parity),
|
||||
bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol)
|
||||
{
|
||||
read_mutex = CreateMutex(NULL, false, NULL);
|
||||
write_mutex = CreateMutex(NULL, false, NULL);
|
||||
if (port_.empty () == false)
|
||||
open ();
|
||||
}
|
||||
|
||||
Serial::SerialImpl::~SerialImpl ()
|
||||
{
|
||||
this->close();
|
||||
CloseHandle(read_mutex);
|
||||
CloseHandle(write_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::open ()
|
||||
{
|
||||
if (port_.empty ()) {
|
||||
throw invalid_argument ("Empty port is invalid.");
|
||||
}
|
||||
if (is_open_ == true) {
|
||||
throw SerialException ("Serial port already open.");
|
||||
}
|
||||
|
||||
// See: https://github.com/wjwwood/serial/issues/84
|
||||
wstring port_with_prefix = _prefix_port_if_needed(port_);
|
||||
LPCWSTR lp_port = port_with_prefix.c_str();
|
||||
fd_ = CreateFileW(lp_port,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0);
|
||||
|
||||
if (fd_ == INVALID_HANDLE_VALUE) {
|
||||
DWORD errno_ = GetLastError();
|
||||
stringstream ss;
|
||||
switch (errno_) {
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
// Use this->getPort to convert to a std::string
|
||||
ss << "Specified port, " << this->getPort() << ", does not exist.";
|
||||
THROW (IOException, ss.str().c_str());
|
||||
default:
|
||||
ss << "Unknown error opening the serial port: " << errno;
|
||||
THROW (IOException, ss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
reconfigurePort();
|
||||
is_open_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::reconfigurePort ()
|
||||
{
|
||||
if (fd_ == INVALID_HANDLE_VALUE) {
|
||||
// Can only operate on a valid file descriptor
|
||||
THROW (IOException, "Invalid file descriptor, is the serial port open?");
|
||||
}
|
||||
|
||||
DCB dcbSerialParams = {0};
|
||||
|
||||
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
|
||||
|
||||
if (!GetCommState(fd_, &dcbSerialParams)) {
|
||||
//error getting state
|
||||
THROW (IOException, "Error getting the serial port state.");
|
||||
}
|
||||
|
||||
// setup baud rate
|
||||
switch (baudrate_) {
|
||||
#ifdef CBR_0
|
||||
case 0: dcbSerialParams.BaudRate = CBR_0; break;
|
||||
#endif
|
||||
#ifdef CBR_50
|
||||
case 50: dcbSerialParams.BaudRate = CBR_50; break;
|
||||
#endif
|
||||
#ifdef CBR_75
|
||||
case 75: dcbSerialParams.BaudRate = CBR_75; break;
|
||||
#endif
|
||||
#ifdef CBR_110
|
||||
case 110: dcbSerialParams.BaudRate = CBR_110; break;
|
||||
#endif
|
||||
#ifdef CBR_134
|
||||
case 134: dcbSerialParams.BaudRate = CBR_134; break;
|
||||
#endif
|
||||
#ifdef CBR_150
|
||||
case 150: dcbSerialParams.BaudRate = CBR_150; break;
|
||||
#endif
|
||||
#ifdef CBR_200
|
||||
case 200: dcbSerialParams.BaudRate = CBR_200; break;
|
||||
#endif
|
||||
#ifdef CBR_300
|
||||
case 300: dcbSerialParams.BaudRate = CBR_300; break;
|
||||
#endif
|
||||
#ifdef CBR_600
|
||||
case 600: dcbSerialParams.BaudRate = CBR_600; break;
|
||||
#endif
|
||||
#ifdef CBR_1200
|
||||
case 1200: dcbSerialParams.BaudRate = CBR_1200; break;
|
||||
#endif
|
||||
#ifdef CBR_1800
|
||||
case 1800: dcbSerialParams.BaudRate = CBR_1800; break;
|
||||
#endif
|
||||
#ifdef CBR_2400
|
||||
case 2400: dcbSerialParams.BaudRate = CBR_2400; break;
|
||||
#endif
|
||||
#ifdef CBR_4800
|
||||
case 4800: dcbSerialParams.BaudRate = CBR_4800; break;
|
||||
#endif
|
||||
#ifdef CBR_7200
|
||||
case 7200: dcbSerialParams.BaudRate = CBR_7200; break;
|
||||
#endif
|
||||
#ifdef CBR_9600
|
||||
case 9600: dcbSerialParams.BaudRate = CBR_9600; break;
|
||||
#endif
|
||||
#ifdef CBR_14400
|
||||
case 14400: dcbSerialParams.BaudRate = CBR_14400; break;
|
||||
#endif
|
||||
#ifdef CBR_19200
|
||||
case 19200: dcbSerialParams.BaudRate = CBR_19200; break;
|
||||
#endif
|
||||
#ifdef CBR_28800
|
||||
case 28800: dcbSerialParams.BaudRate = CBR_28800; break;
|
||||
#endif
|
||||
#ifdef CBR_57600
|
||||
case 57600: dcbSerialParams.BaudRate = CBR_57600; break;
|
||||
#endif
|
||||
#ifdef CBR_76800
|
||||
case 76800: dcbSerialParams.BaudRate = CBR_76800; break;
|
||||
#endif
|
||||
#ifdef CBR_38400
|
||||
case 38400: dcbSerialParams.BaudRate = CBR_38400; break;
|
||||
#endif
|
||||
#ifdef CBR_115200
|
||||
case 115200: dcbSerialParams.BaudRate = CBR_115200; break;
|
||||
#endif
|
||||
#ifdef CBR_128000
|
||||
case 128000: dcbSerialParams.BaudRate = CBR_128000; break;
|
||||
#endif
|
||||
#ifdef CBR_153600
|
||||
case 153600: dcbSerialParams.BaudRate = CBR_153600; break;
|
||||
#endif
|
||||
#ifdef CBR_230400
|
||||
case 230400: dcbSerialParams.BaudRate = CBR_230400; break;
|
||||
#endif
|
||||
#ifdef CBR_256000
|
||||
case 256000: dcbSerialParams.BaudRate = CBR_256000; break;
|
||||
#endif
|
||||
#ifdef CBR_460800
|
||||
case 460800: dcbSerialParams.BaudRate = CBR_460800; break;
|
||||
#endif
|
||||
#ifdef CBR_921600
|
||||
case 921600: dcbSerialParams.BaudRate = CBR_921600; break;
|
||||
#endif
|
||||
default:
|
||||
// Try to blindly assign it
|
||||
dcbSerialParams.BaudRate = baudrate_;
|
||||
}
|
||||
|
||||
// setup char len
|
||||
if (bytesize_ == eightbits)
|
||||
dcbSerialParams.ByteSize = 8;
|
||||
else if (bytesize_ == sevenbits)
|
||||
dcbSerialParams.ByteSize = 7;
|
||||
else if (bytesize_ == sixbits)
|
||||
dcbSerialParams.ByteSize = 6;
|
||||
else if (bytesize_ == fivebits)
|
||||
dcbSerialParams.ByteSize = 5;
|
||||
else
|
||||
throw invalid_argument ("invalid char len");
|
||||
|
||||
// setup stopbits
|
||||
if (stopbits_ == stopbits_one)
|
||||
dcbSerialParams.StopBits = ONESTOPBIT;
|
||||
else if (stopbits_ == stopbits_one_point_five)
|
||||
dcbSerialParams.StopBits = ONE5STOPBITS;
|
||||
else if (stopbits_ == stopbits_two)
|
||||
dcbSerialParams.StopBits = TWOSTOPBITS;
|
||||
else
|
||||
throw invalid_argument ("invalid stop bit");
|
||||
|
||||
// setup parity
|
||||
if (parity_ == parity_none) {
|
||||
dcbSerialParams.Parity = NOPARITY;
|
||||
} else if (parity_ == parity_even) {
|
||||
dcbSerialParams.Parity = EVENPARITY;
|
||||
} else if (parity_ == parity_odd) {
|
||||
dcbSerialParams.Parity = ODDPARITY;
|
||||
} else if (parity_ == parity_mark) {
|
||||
dcbSerialParams.Parity = MARKPARITY;
|
||||
} else if (parity_ == parity_space) {
|
||||
dcbSerialParams.Parity = SPACEPARITY;
|
||||
} else {
|
||||
throw invalid_argument ("invalid parity");
|
||||
}
|
||||
|
||||
// setup flowcontrol
|
||||
if (flowcontrol_ == flowcontrol_none) {
|
||||
dcbSerialParams.fOutxCtsFlow = false;
|
||||
dcbSerialParams.fRtsControl = 0x00;
|
||||
dcbSerialParams.fOutX = false;
|
||||
dcbSerialParams.fInX = false;
|
||||
}
|
||||
if (flowcontrol_ == flowcontrol_software) {
|
||||
dcbSerialParams.fOutxCtsFlow = false;
|
||||
dcbSerialParams.fRtsControl = 0x00;
|
||||
dcbSerialParams.fOutX = true;
|
||||
dcbSerialParams.fInX = true;
|
||||
}
|
||||
if (flowcontrol_ == flowcontrol_hardware) {
|
||||
dcbSerialParams.fOutxCtsFlow = true;
|
||||
dcbSerialParams.fRtsControl = 0x03;
|
||||
dcbSerialParams.fOutX = false;
|
||||
dcbSerialParams.fInX = false;
|
||||
}
|
||||
|
||||
// activate settings
|
||||
if (!SetCommState(fd_, &dcbSerialParams)){
|
||||
CloseHandle(fd_);
|
||||
THROW (IOException, "Error setting serial port settings.");
|
||||
}
|
||||
|
||||
// Setup timeouts
|
||||
COMMTIMEOUTS timeouts = {0};
|
||||
timeouts.ReadIntervalTimeout = timeout_.inter_byte_timeout;
|
||||
timeouts.ReadTotalTimeoutConstant = timeout_.read_timeout_constant;
|
||||
timeouts.ReadTotalTimeoutMultiplier = timeout_.read_timeout_multiplier;
|
||||
timeouts.WriteTotalTimeoutConstant = timeout_.write_timeout_constant;
|
||||
timeouts.WriteTotalTimeoutMultiplier = timeout_.write_timeout_multiplier;
|
||||
if (!SetCommTimeouts(fd_, &timeouts)) {
|
||||
THROW (IOException, "Error setting timeouts.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::close ()
|
||||
{
|
||||
if (is_open_ == true) {
|
||||
if (fd_ != INVALID_HANDLE_VALUE) {
|
||||
int ret;
|
||||
ret = CloseHandle(fd_);
|
||||
if (ret == 0) {
|
||||
stringstream ss;
|
||||
ss << "Error while closing serial port: " << GetLastError();
|
||||
THROW (IOException, ss.str().c_str());
|
||||
} else {
|
||||
fd_ = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
is_open_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::SerialImpl::isOpen () const
|
||||
{
|
||||
return is_open_;
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::SerialImpl::available ()
|
||||
{
|
||||
if (!is_open_) {
|
||||
return 0;
|
||||
}
|
||||
COMSTAT cs;
|
||||
if (!ClearCommError(fd_, NULL, &cs)) {
|
||||
stringstream ss;
|
||||
ss << "Error while checking status of the serial port: " << GetLastError();
|
||||
THROW (IOException, ss.str().c_str());
|
||||
}
|
||||
return static_cast<size_t>(cs.cbInQue);
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::SerialImpl::waitReadable (uint32_t /*timeout*/)
|
||||
{
|
||||
THROW (IOException, "waitReadable is not implemented on Windows.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::waitByteTimes (size_t /*count*/)
|
||||
{
|
||||
THROW (IOException, "waitByteTimes is not implemented on Windows.");
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::SerialImpl::read (uint8_t *buf, size_t size)
|
||||
{
|
||||
if (!is_open_) {
|
||||
throw PortNotOpenedException ("Serial::read");
|
||||
}
|
||||
DWORD bytes_read;
|
||||
if (!ReadFile(fd_, buf, static_cast<DWORD>(size), &bytes_read, NULL)) {
|
||||
stringstream ss;
|
||||
ss << "Error while reading from the serial port: " << GetLastError();
|
||||
THROW (IOException, ss.str().c_str());
|
||||
}
|
||||
return (size_t) (bytes_read);
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::SerialImpl::write (const uint8_t *data, size_t length)
|
||||
{
|
||||
if (is_open_ == false) {
|
||||
throw PortNotOpenedException ("Serial::write");
|
||||
}
|
||||
DWORD bytes_written;
|
||||
if (!WriteFile(fd_, data, static_cast<DWORD>(length), &bytes_written, NULL)) {
|
||||
stringstream ss;
|
||||
ss << "Error while writing to the serial port: " << GetLastError();
|
||||
THROW (IOException, ss.str().c_str());
|
||||
}
|
||||
return (size_t) (bytes_written);
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::setPort (const string &port)
|
||||
{
|
||||
port_ = wstring(port.begin(), port.end());
|
||||
}
|
||||
|
||||
string
|
||||
Serial::SerialImpl::getPort () const
|
||||
{
|
||||
return string(port_.begin(), port_.end());
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::setTimeout (serial::Timeout &timeout)
|
||||
{
|
||||
timeout_ = timeout;
|
||||
if (is_open_) {
|
||||
reconfigurePort ();
|
||||
}
|
||||
}
|
||||
|
||||
serial::Timeout
|
||||
Serial::SerialImpl::getTimeout () const
|
||||
{
|
||||
return timeout_;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::setBaudrate (unsigned long baudrate)
|
||||
{
|
||||
baudrate_ = baudrate;
|
||||
if (is_open_) {
|
||||
reconfigurePort ();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long
|
||||
Serial::SerialImpl::getBaudrate () const
|
||||
{
|
||||
return baudrate_;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize)
|
||||
{
|
||||
bytesize_ = bytesize;
|
||||
if (is_open_) {
|
||||
reconfigurePort ();
|
||||
}
|
||||
}
|
||||
|
||||
serial::bytesize_t
|
||||
Serial::SerialImpl::getBytesize () const
|
||||
{
|
||||
return bytesize_;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::setParity (serial::parity_t parity)
|
||||
{
|
||||
parity_ = parity;
|
||||
if (is_open_) {
|
||||
reconfigurePort ();
|
||||
}
|
||||
}
|
||||
|
||||
serial::parity_t
|
||||
Serial::SerialImpl::getParity () const
|
||||
{
|
||||
return parity_;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits)
|
||||
{
|
||||
stopbits_ = stopbits;
|
||||
if (is_open_) {
|
||||
reconfigurePort ();
|
||||
}
|
||||
}
|
||||
|
||||
serial::stopbits_t
|
||||
Serial::SerialImpl::getStopbits () const
|
||||
{
|
||||
return stopbits_;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol)
|
||||
{
|
||||
flowcontrol_ = flowcontrol;
|
||||
if (is_open_) {
|
||||
reconfigurePort ();
|
||||
}
|
||||
}
|
||||
|
||||
serial::flowcontrol_t
|
||||
Serial::SerialImpl::getFlowcontrol () const
|
||||
{
|
||||
return flowcontrol_;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::flush ()
|
||||
{
|
||||
if (is_open_ == false) {
|
||||
throw PortNotOpenedException ("Serial::flush");
|
||||
}
|
||||
FlushFileBuffers (fd_);
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::flushInput ()
|
||||
{
|
||||
THROW (IOException, "flushInput is not supported on Windows.");
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::flushOutput ()
|
||||
{
|
||||
THROW (IOException, "flushOutput is not supported on Windows.");
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::sendBreak (int /*duration*/)
|
||||
{
|
||||
THROW (IOException, "sendBreak is not supported on Windows.");
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::setBreak (bool level)
|
||||
{
|
||||
if (is_open_ == false) {
|
||||
throw PortNotOpenedException ("Serial::setBreak");
|
||||
}
|
||||
if (level) {
|
||||
EscapeCommFunction (fd_, SETBREAK);
|
||||
} else {
|
||||
EscapeCommFunction (fd_, CLRBREAK);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::setRTS (bool level)
|
||||
{
|
||||
if (is_open_ == false) {
|
||||
throw PortNotOpenedException ("Serial::setRTS");
|
||||
}
|
||||
if (level) {
|
||||
EscapeCommFunction (fd_, SETRTS);
|
||||
} else {
|
||||
EscapeCommFunction (fd_, CLRRTS);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::setDTR (bool level)
|
||||
{
|
||||
if (is_open_ == false) {
|
||||
throw PortNotOpenedException ("Serial::setDTR");
|
||||
}
|
||||
if (level) {
|
||||
EscapeCommFunction (fd_, SETDTR);
|
||||
} else {
|
||||
EscapeCommFunction (fd_, CLRDTR);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::SerialImpl::waitForChange ()
|
||||
{
|
||||
if (is_open_ == false) {
|
||||
throw PortNotOpenedException ("Serial::waitForChange");
|
||||
}
|
||||
DWORD dwCommEvent;
|
||||
|
||||
if (!SetCommMask(fd_, EV_CTS | EV_DSR | EV_RING | EV_RLSD)) {
|
||||
// Error setting communications mask
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WaitCommEvent(fd_, &dwCommEvent, NULL)) {
|
||||
// An error occurred waiting for the event.
|
||||
return false;
|
||||
} else {
|
||||
// Event has occurred.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::SerialImpl::getCTS ()
|
||||
{
|
||||
if (is_open_ == false) {
|
||||
throw PortNotOpenedException ("Serial::getCTS");
|
||||
}
|
||||
DWORD dwModemStatus;
|
||||
if (!GetCommModemStatus(fd_, &dwModemStatus)) {
|
||||
THROW (IOException, "Error getting the status of the CTS line.");
|
||||
}
|
||||
|
||||
return (MS_CTS_ON & dwModemStatus) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::SerialImpl::getDSR ()
|
||||
{
|
||||
if (is_open_ == false) {
|
||||
throw PortNotOpenedException ("Serial::getDSR");
|
||||
}
|
||||
DWORD dwModemStatus;
|
||||
if (!GetCommModemStatus(fd_, &dwModemStatus)) {
|
||||
THROW (IOException, "Error getting the status of the DSR line.");
|
||||
}
|
||||
|
||||
return (MS_DSR_ON & dwModemStatus) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::SerialImpl::getRI()
|
||||
{
|
||||
if (is_open_ == false) {
|
||||
throw PortNotOpenedException ("Serial::getRI");
|
||||
}
|
||||
DWORD dwModemStatus;
|
||||
if (!GetCommModemStatus(fd_, &dwModemStatus)) {
|
||||
THROW (IOException, "Error getting the status of the RI line.");
|
||||
}
|
||||
|
||||
return (MS_RING_ON & dwModemStatus) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::SerialImpl::getCD()
|
||||
{
|
||||
if (is_open_ == false) {
|
||||
throw PortNotOpenedException ("Serial::getCD");
|
||||
}
|
||||
DWORD dwModemStatus;
|
||||
if (!GetCommModemStatus(fd_, &dwModemStatus)) {
|
||||
// Error in GetCommModemStatus;
|
||||
THROW (IOException, "Error getting the status of the CD line.");
|
||||
}
|
||||
|
||||
return (MS_RLSD_ON & dwModemStatus) != 0;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::readLock()
|
||||
{
|
||||
if (WaitForSingleObject(read_mutex, INFINITE) != WAIT_OBJECT_0) {
|
||||
THROW (IOException, "Error claiming read mutex.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::readUnlock()
|
||||
{
|
||||
if (!ReleaseMutex(read_mutex)) {
|
||||
THROW (IOException, "Error releasing read mutex.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::writeLock()
|
||||
{
|
||||
if (WaitForSingleObject(write_mutex, INFINITE) != WAIT_OBJECT_0) {
|
||||
THROW (IOException, "Error claiming write mutex.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Serial::SerialImpl::writeUnlock()
|
||||
{
|
||||
if (!ReleaseMutex(write_mutex)) {
|
||||
THROW (IOException, "Error releasing write mutex.");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #if defined(_WIN32)
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
/* Copyright 2012 William Woodall and John Harrison */
|
||||
#include <algorithm>
|
||||
|
||||
#if !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
|
||||
# include <alloca.h>
|
||||
#endif
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
# define alloca __builtin_alloca
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "include/serial.h"
|
||||
#include "include/impl/win.h"
|
||||
#else
|
||||
#include "../include/serial.h"
|
||||
#include "../include/impl/unix.h"
|
||||
#endif
|
||||
|
||||
using std::invalid_argument;
|
||||
using std::min;
|
||||
using std::numeric_limits;
|
||||
using std::vector;
|
||||
using std::size_t;
|
||||
using std::string;
|
||||
|
||||
using serial::Serial;
|
||||
using serial::SerialException;
|
||||
using serial::IOException;
|
||||
using serial::bytesize_t;
|
||||
using serial::parity_t;
|
||||
using serial::stopbits_t;
|
||||
using serial::flowcontrol_t;
|
||||
|
||||
class Serial::ScopedReadLock {
|
||||
public:
|
||||
ScopedReadLock(SerialImpl *pimpl) : pimpl_(pimpl) {
|
||||
this->pimpl_->readLock();
|
||||
}
|
||||
~ScopedReadLock() {
|
||||
this->pimpl_->readUnlock();
|
||||
}
|
||||
private:
|
||||
// Disable copy constructors
|
||||
ScopedReadLock(const ScopedReadLock&);
|
||||
const ScopedReadLock& operator=(ScopedReadLock);
|
||||
|
||||
SerialImpl *pimpl_;
|
||||
};
|
||||
|
||||
class Serial::ScopedWriteLock {
|
||||
public:
|
||||
ScopedWriteLock(SerialImpl *pimpl) : pimpl_(pimpl) {
|
||||
this->pimpl_->writeLock();
|
||||
}
|
||||
~ScopedWriteLock() {
|
||||
this->pimpl_->writeUnlock();
|
||||
}
|
||||
private:
|
||||
// Disable copy constructors
|
||||
ScopedWriteLock(const ScopedWriteLock&);
|
||||
const ScopedWriteLock& operator=(ScopedWriteLock);
|
||||
SerialImpl *pimpl_;
|
||||
};
|
||||
|
||||
Serial::Serial (const string &port, uint32_t baudrate, serial::Timeout timeout,
|
||||
bytesize_t bytesize, parity_t parity, stopbits_t stopbits,
|
||||
flowcontrol_t flowcontrol)
|
||||
: pimpl_(new SerialImpl (port, baudrate, bytesize, parity,
|
||||
stopbits, flowcontrol))
|
||||
{
|
||||
pimpl_->setTimeout(timeout);
|
||||
}
|
||||
|
||||
Serial::~Serial ()
|
||||
{
|
||||
delete pimpl_;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::open ()
|
||||
{
|
||||
pimpl_->open ();
|
||||
}
|
||||
|
||||
void
|
||||
Serial::close ()
|
||||
{
|
||||
pimpl_->close ();
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::isOpen () const
|
||||
{
|
||||
return pimpl_->isOpen ();
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::available ()
|
||||
{
|
||||
return pimpl_->available ();
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::waitReadable ()
|
||||
{
|
||||
serial::Timeout timeout(pimpl_->getTimeout ());
|
||||
return pimpl_->waitReadable(timeout.read_timeout_constant);
|
||||
}
|
||||
|
||||
void
|
||||
Serial::waitByteTimes (size_t count)
|
||||
{
|
||||
pimpl_->waitByteTimes(count);
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::read_ (uint8_t *buffer, size_t size)
|
||||
{
|
||||
return this->pimpl_->read (buffer, size);
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::read (uint8_t *buffer, size_t size)
|
||||
{
|
||||
ScopedReadLock lock(this->pimpl_);
|
||||
return this->pimpl_->read (buffer, size);
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::read (std::vector<uint8_t> &buffer, size_t size)
|
||||
{
|
||||
ScopedReadLock lock(this->pimpl_);
|
||||
uint8_t *buffer_ = new uint8_t[size];
|
||||
size_t bytes_read = this->pimpl_->read (buffer_, size);
|
||||
buffer.insert (buffer.end (), buffer_, buffer_+bytes_read);
|
||||
delete[] buffer_;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::read (std::string &buffer, size_t size)
|
||||
{
|
||||
ScopedReadLock lock(this->pimpl_);
|
||||
uint8_t *buffer_ = new uint8_t[size];
|
||||
size_t bytes_read = this->pimpl_->read (buffer_, size);
|
||||
buffer.append (reinterpret_cast<const char*>(buffer_), bytes_read);
|
||||
delete[] buffer_;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
string
|
||||
Serial::read (size_t size)
|
||||
{
|
||||
std::string buffer;
|
||||
this->read (buffer, size);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::readline (string &buffer, size_t size, string eol)
|
||||
{
|
||||
ScopedReadLock lock(this->pimpl_);
|
||||
size_t eol_len = eol.length ();
|
||||
uint8_t *buffer_ = static_cast<uint8_t*>
|
||||
(alloca (size * sizeof (uint8_t)));
|
||||
size_t read_so_far = 0;
|
||||
while (true)
|
||||
{
|
||||
size_t bytes_read = this->read_ (buffer_ + read_so_far, 1);
|
||||
read_so_far += bytes_read;
|
||||
if (bytes_read == 0) {
|
||||
break; // Timeout occured on reading 1 byte
|
||||
}
|
||||
if (string (reinterpret_cast<const char*>
|
||||
(buffer_ + read_so_far - eol_len), eol_len) == eol) {
|
||||
break; // EOL found
|
||||
}
|
||||
if (read_so_far == size) {
|
||||
break; // Reached the maximum read length
|
||||
}
|
||||
}
|
||||
buffer.append(reinterpret_cast<const char*> (buffer_), read_so_far);
|
||||
return read_so_far;
|
||||
}
|
||||
|
||||
string
|
||||
Serial::readline (size_t size, string eol)
|
||||
{
|
||||
std::string buffer;
|
||||
this->readline (buffer, size, eol);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
vector<string>
|
||||
Serial::readlines (size_t size, string eol)
|
||||
{
|
||||
ScopedReadLock lock(this->pimpl_);
|
||||
std::vector<std::string> lines;
|
||||
size_t eol_len = eol.length ();
|
||||
uint8_t *buffer_ = static_cast<uint8_t*>
|
||||
(alloca (size * sizeof (uint8_t)));
|
||||
size_t read_so_far = 0;
|
||||
size_t start_of_line = 0;
|
||||
while (read_so_far < size) {
|
||||
size_t bytes_read = this->read_ (buffer_+read_so_far, 1);
|
||||
read_so_far += bytes_read;
|
||||
if (bytes_read == 0) {
|
||||
if (start_of_line != read_so_far) {
|
||||
lines.push_back (
|
||||
string (reinterpret_cast<const char*> (buffer_ + start_of_line),
|
||||
read_so_far - start_of_line));
|
||||
}
|
||||
break; // Timeout occured on reading 1 byte
|
||||
}
|
||||
if (string (reinterpret_cast<const char*>
|
||||
(buffer_ + read_so_far - eol_len), eol_len) == eol) {
|
||||
// EOL found
|
||||
lines.push_back(
|
||||
string(reinterpret_cast<const char*> (buffer_ + start_of_line),
|
||||
read_so_far - start_of_line));
|
||||
start_of_line = read_so_far;
|
||||
}
|
||||
if (read_so_far == size) {
|
||||
if (start_of_line != read_so_far) {
|
||||
lines.push_back(
|
||||
string(reinterpret_cast<const char*> (buffer_ + start_of_line),
|
||||
read_so_far - start_of_line));
|
||||
}
|
||||
break; // Reached the maximum read length
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::write (const string &data)
|
||||
{
|
||||
ScopedWriteLock lock(this->pimpl_);
|
||||
return this->write_ (reinterpret_cast<const uint8_t*>(data.c_str()),
|
||||
data.length());
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::write (const std::vector<uint8_t> &data)
|
||||
{
|
||||
ScopedWriteLock lock(this->pimpl_);
|
||||
return this->write_ (&data[0], data.size());
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::write (const uint8_t *data, size_t size)
|
||||
{
|
||||
ScopedWriteLock lock(this->pimpl_);
|
||||
return this->write_(data, size);
|
||||
}
|
||||
|
||||
size_t
|
||||
Serial::write_ (const uint8_t *data, size_t length)
|
||||
{
|
||||
return pimpl_->write (data, length);
|
||||
}
|
||||
|
||||
void
|
||||
Serial::setPort (const string &port)
|
||||
{
|
||||
ScopedReadLock rlock(this->pimpl_);
|
||||
ScopedWriteLock wlock(this->pimpl_);
|
||||
bool was_open = pimpl_->isOpen ();
|
||||
if (was_open) close();
|
||||
pimpl_->setPort (port);
|
||||
if (was_open) open ();
|
||||
}
|
||||
|
||||
string
|
||||
Serial::getPort () const
|
||||
{
|
||||
return pimpl_->getPort ();
|
||||
}
|
||||
|
||||
void
|
||||
Serial::setTimeout (serial::Timeout &timeout)
|
||||
{
|
||||
pimpl_->setTimeout (timeout);
|
||||
}
|
||||
|
||||
serial::Timeout
|
||||
Serial::getTimeout () const {
|
||||
return pimpl_->getTimeout ();
|
||||
}
|
||||
|
||||
void
|
||||
Serial::setBaudrate (uint32_t baudrate)
|
||||
{
|
||||
pimpl_->setBaudrate (baudrate);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Serial::getBaudrate () const
|
||||
{
|
||||
return uint32_t(pimpl_->getBaudrate ());
|
||||
}
|
||||
|
||||
void
|
||||
Serial::setBytesize (bytesize_t bytesize)
|
||||
{
|
||||
pimpl_->setBytesize (bytesize);
|
||||
}
|
||||
|
||||
bytesize_t
|
||||
Serial::getBytesize () const
|
||||
{
|
||||
return pimpl_->getBytesize ();
|
||||
}
|
||||
|
||||
void
|
||||
Serial::setParity (parity_t parity)
|
||||
{
|
||||
pimpl_->setParity (parity);
|
||||
}
|
||||
|
||||
parity_t
|
||||
Serial::getParity () const
|
||||
{
|
||||
return pimpl_->getParity ();
|
||||
}
|
||||
|
||||
void
|
||||
Serial::setStopbits (stopbits_t stopbits)
|
||||
{
|
||||
pimpl_->setStopbits (stopbits);
|
||||
}
|
||||
|
||||
stopbits_t
|
||||
Serial::getStopbits () const
|
||||
{
|
||||
return pimpl_->getStopbits ();
|
||||
}
|
||||
|
||||
void
|
||||
Serial::setFlowcontrol (flowcontrol_t flowcontrol)
|
||||
{
|
||||
pimpl_->setFlowcontrol (flowcontrol);
|
||||
}
|
||||
|
||||
flowcontrol_t
|
||||
Serial::getFlowcontrol () const
|
||||
{
|
||||
return pimpl_->getFlowcontrol ();
|
||||
}
|
||||
|
||||
void Serial::flush ()
|
||||
{
|
||||
ScopedReadLock rlock(this->pimpl_);
|
||||
ScopedWriteLock wlock(this->pimpl_);
|
||||
pimpl_->flush ();
|
||||
}
|
||||
|
||||
void Serial::flushInput ()
|
||||
{
|
||||
ScopedReadLock lock(this->pimpl_);
|
||||
pimpl_->flushInput ();
|
||||
}
|
||||
|
||||
void Serial::flushOutput ()
|
||||
{
|
||||
ScopedWriteLock lock(this->pimpl_);
|
||||
pimpl_->flushOutput ();
|
||||
}
|
||||
|
||||
void Serial::sendBreak (int duration)
|
||||
{
|
||||
pimpl_->sendBreak (duration);
|
||||
}
|
||||
|
||||
void Serial::setBreak (bool level)
|
||||
{
|
||||
pimpl_->setBreak (level);
|
||||
}
|
||||
|
||||
void Serial::setRTS (bool level)
|
||||
{
|
||||
pimpl_->setRTS (level);
|
||||
}
|
||||
|
||||
void Serial::setDTR (bool level)
|
||||
{
|
||||
pimpl_->setDTR (level);
|
||||
}
|
||||
|
||||
bool Serial::waitForChange()
|
||||
{
|
||||
return pimpl_->waitForChange();
|
||||
}
|
||||
|
||||
bool Serial::getCTS ()
|
||||
{
|
||||
return pimpl_->getCTS ();
|
||||
}
|
||||
|
||||
bool Serial::getDSR ()
|
||||
{
|
||||
return pimpl_->getDSR ();
|
||||
}
|
||||
|
||||
bool Serial::getRI ()
|
||||
{
|
||||
return pimpl_->getRI ();
|
||||
}
|
||||
|
||||
bool Serial::getCD ()
|
||||
{
|
||||
return pimpl_->getCD ();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
Sanic STAR
|
||||
----------
|
||||
Gemaakt door Kenneth van Ewijk
|
||||
|
||||
Een simpel spel waarbij het de bedoeling is dat je alle sterren oppakt.
|
||||
Als je alle sterren hebt verzamelt, gaat hij naar de volgende wereld.
|
||||
Er zijn momenteel slechts vier werelden.
|
||||
|
||||
Opstarten en afsluiten:
|
||||
Druk op starten in Visual Studio. (Release, x86)
|
||||
Om af te sluiten, druk op ESC en kies Exit in het menu.
|
||||
|
||||
Besturing:
|
||||
- W en S voor vooruit/achteruit
|
||||
- Muis om te sturen en te kijken
|
||||
- Forceren van wereld veranderen (zonder alle sterren te verzamelen) door op de rechter pijltjestoets te drukken.
|
||||
|
||||
Deze game bevat de volgende onderdelen:
|
||||
- Bestuurbare third person camera
|
||||
- In de scene zijn een aantal verschillende ‘objecten’
|
||||
- De sterren draaien automatisch rond
|
||||
- SANIC die je bestuurd en de sterren die je op kan pakken zijn objecten die te beïnvloeden zijn.
|
||||
- De bomen staan stil. Een of meerdere objecten staan stil
|
||||
- De bomen/gras/sanic/sterren worden uit een obj file geladen
|
||||
- Het terrein wordt als heightmap met code gegenereerd.
|
||||
- De rode sterren, bij speciale speed boost sterren, zijn relatieve transformaties
|
||||
- Overal zit OpenGL belichting op
|
||||
- Op alle objecten en op de heightmap zit texture mapping
|
||||
- Toetsenbord wordt gebruikt voor besturing
|
||||
@@ -0,0 +1,192 @@
|
||||
newmtl initialShadingGroup
|
||||
illum 4
|
||||
Kd 0.21 0.09 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert2SG
|
||||
illum 4
|
||||
Kd 0.00 1.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert3SG
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert4SG
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert5SG
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert6SG
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert8SG
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert9SG
|
||||
illum 4
|
||||
Kd 1.00 1.00 1.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert10SG
|
||||
illum 4
|
||||
Kd 0.12 0.28 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert11SG
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert2SG
|
||||
illum 4
|
||||
Kd 0.00 1.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert2SG1
|
||||
illum 4
|
||||
Kd 0.00 1.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert2SG2
|
||||
illum 4
|
||||
Kd 0.00 1.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert2SG3
|
||||
illum 4
|
||||
Kd 0.00 1.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert2SG4
|
||||
illum 4
|
||||
Kd 0.00 1.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert3SG
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert3SG1
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert3SG2
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert3SG3
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert3SG4
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert4SG
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert4SG1
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert4SG2
|
||||
illum 4
|
||||
Kd 0.50 0.21 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert5SG
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert5SG1
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert5SG2
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert6SG
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert6SG1
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert6SG2
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert8SG
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert8SG1
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert8SG2
|
||||
illum 4
|
||||
Kd 0.00 0.16 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
|
After Width: | Height: | Size: 336 B |
@@ -0,0 +1,9 @@
|
||||
# WaveFront *.mtl file (generated by CINEMA 4D)
|
||||
|
||||
newmtl Mat
|
||||
Kd 0.80000001192093 0.80000001192093 0.80000001192093
|
||||
map_Kd Blauw.png
|
||||
Ks 1.00000000000000 1.00000000000000 1.00000000000000
|
||||
Ns 100
|
||||
illum 7
|
||||
|
||||
|
After Width: | Height: | Size: 36 KiB |
@@ -0,0 +1,11 @@
|
||||
# Material file for n64tree.obj
|
||||
|
||||
newmtl tree
|
||||
Ns 0
|
||||
d 1
|
||||
illum 2
|
||||
Kd 0.8 0.8 0.8
|
||||
Ks 0.0 0.0 0.0
|
||||
Ka 0.2 0.2 0.2
|
||||
map_Kd m64_tree.png
|
||||
|
||||
|
After Width: | Height: | Size: 335 B |
@@ -0,0 +1,9 @@
|
||||
# WaveFront *.mtl file (generated by CINEMA 4D)
|
||||
|
||||
newmtl Mat
|
||||
Kd 0.80000001192093 0.80000001192093 0.80000001192093
|
||||
map_Kd Blauw.png
|
||||
Ks 1.00000000000000 1.00000000000000 1.00000000000000
|
||||
Ns 100
|
||||
illum 7
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
newmtl bob1:initialShadingGroup
|
||||
illum 4
|
||||
Kd 0.50 0.50 0.50
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl initialShadingGroup
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert2SG
|
||||
illum 4
|
||||
Kd 0.20 0.32 0.50
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert5SG
|
||||
illum 4
|
||||
Kd 1.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert6SG
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert7SG
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
map_Kd Screenshot_1.png
|
||||
Ni 1.00
|
||||
newmtl lambert8SG
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
map_Kd Screenshot_1.png
|
||||
Ni 1.00
|
||||
newmtl lambert10SG
|
||||
illum 4
|
||||
Kd 1.00 1.00 1.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert12SG
|
||||
illum 4
|
||||
Kd 0.58 0.00 1.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert13SG
|
||||
illum 4
|
||||
Kd 0.00 1.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert14SG
|
||||
illum 4
|
||||
Kd 1.00 1.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert15SG
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
map_Kd TheThing2.png
|
||||
Ni 1.00
|
||||
newmtl lambert16SG
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
map_Kd SkateboardwielThing.png
|
||||
Ni 1.00
|
||||
newmtl lambert17SG
|
||||
illum 4
|
||||
Kd 0.25 0.25 0.25
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
Ks 0.50 0.50 0.50
|
||||
newmtl lambert18SG
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
map_Kd BobStoneTexture.png
|
||||
Ni 1.00
|
||||
Ks 0.50 0.50 0.50
|
||||
newmtl lambert19SG
|
||||
illum 4
|
||||
Kd 0.85 0.85 0.85
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert20SG
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 0.64 0.64 0.64
|
||||
Ni 1.00
|
||||
newmtl lambert21SG
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert22SG
|
||||
illum 4
|
||||
Kd 0.50 0.50 0.50
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl lambert23SG
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
map_Kd Kart.png
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert2SG
|
||||
illum 4
|
||||
Kd 0.00 0.00 0.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
map_Kd Screenshot_1.png
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert4SG
|
||||
illum 4
|
||||
Kd 0.50 1.00 1.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
newmtl pasted__lambert5SG
|
||||
illum 4
|
||||
Kd 0.00 1.00 1.00
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
||||
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,11 @@
|
||||
# Material file for n64tree.obj
|
||||
|
||||
newmtl tree
|
||||
Ns 0
|
||||
d 1
|
||||
illum 2
|
||||
Kd 0.8 0.8 0.8
|
||||
Ks 0.0 0.0 0.0
|
||||
Ka 0.2 0.2 0.2
|
||||
map_Kd m64_tree.png
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Blender MTL File: 'yoshi_falls.blend'
|
||||
# Material Count: 1
|
||||
|
||||
newmtl box_mat
|
||||
Ns 96.078431
|
||||
Ka 0.000000 0.000000 0.000000
|
||||
Kd 0.778039 0.778039 0.778039
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 0.000000
|
||||
illum 1
|
||||
map_Kd box_mat.png
|
||||
map_d box_mat.png
|
||||
|
After Width: | Height: | Size: 327 B |
@@ -0,0 +1,9 @@
|
||||
# Created by Every File Explorer
|
||||
|
||||
newmtl mat_star
|
||||
Ka 1 1 1
|
||||
Kd 1 1 1
|
||||
Ks 0.1490196 0.1490196 0
|
||||
d 1
|
||||
map_Kd Tex/I_star.png
|
||||
|
||||
|
After Width: | Height: | Size: 395 B |
@@ -0,0 +1,9 @@
|
||||
# Created by Every File Explorer
|
||||
|
||||
newmtl mat_star
|
||||
Ka 1 1 1
|
||||
Kd 1 1 1
|
||||
Ks 0.1490196 0.1490196 0
|
||||
d 1
|
||||
map_Kd Tex/I_star.png
|
||||
|
||||
|
After Width: | Height: | Size: 401 B |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 68 KiB |
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"world": {
|
||||
"heightmap": "resources/worlds/dark.png",
|
||||
"texture": "resources/worlds/darktexture.png",
|
||||
"skybox": "resources/skyboxes/dark/",
|
||||
"music": "resources/sounds/dark.wav",
|
||||
"object-templates": [
|
||||
{
|
||||
"file": "resources/models/DarkTree/n64tree.obj",
|
||||
"color": 100,
|
||||
"scale": 0.3
|
||||
},
|
||||
{
|
||||
"file": "resources/models/DarkGrass/grass.obj",
|
||||
"color": 110,
|
||||
"scale": 1,
|
||||
"collision": false
|
||||
}]
|
||||
},
|
||||
"player": {
|
||||
"startposition": [ 30, -1, 175],
|
||||
"kart":
|
||||
{
|
||||
"file": "resources/models/Kart/Kart.obj",
|
||||
"scale": 0.5
|
||||
}
|
||||
},
|
||||
"objects": [ ]
|
||||
}
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"world": {
|
||||
"heightmap": "resources/worlds/dark.png",
|
||||
"texture": "resources/worlds/dark2texture.png",
|
||||
"skybox": "resources/skyboxes/dark/",
|
||||
"music": "resources/sounds/dark.wav",
|
||||
"object-templates": [
|
||||
{
|
||||
"file": "resources/models/DarkTree/n64tree.obj",
|
||||
"color": 100,
|
||||
"scale": 0.3
|
||||
},
|
||||
{
|
||||
"file": "resources/models/DarkGrass/grass.obj",
|
||||
"color": 110,
|
||||
"scale": 1,
|
||||
"collision": false
|
||||
}]
|
||||
},
|
||||
"player": {
|
||||
"startposition": [ 30, -1, 175],
|
||||
"kart":
|
||||
{
|
||||
"file": "resources/models/Kart/Kart.obj",
|
||||
"scale": 0.5
|
||||
}
|
||||
},
|
||||
"objects": [ ]
|
||||
}
|
||||