fixed much stuff with bad usage of constructor mixed with virtual functions in gl stuff. added model loading with assimp.

This commit is contained in:
Andreas Ortmann 2016-09-28 13:00:40 +02:00
parent aedda9d48e
commit 0105bfe430
17 changed files with 402 additions and 175 deletions

View file

@ -0,0 +1,45 @@
$fn = 12;
offset = 1.0;
r_inner = 0.2;
r_outer = 0.5;
rotate([0,0,180]) {
hull() {
// hull around the small base
translate([offset, 0, 0]) sphere(r_inner);
// and the thick head
sphere(r_outer);
}
pipe_len=0.3;
translate([offset, 0, 0]) {
rotate([0,90,0]) cylinder(r=r_inner, pipe_len);
}
// fins
w = 0.5;
h = 0.8 * r_outer;
difference() {
// fin
for (i=[0:4]) {
rotate([i*90,0,0]) {
translate([offset-w/2+pipe_len,0,-h/2]) {
hull() {
cube([w,0.05,0.01], center=true);
rotate([0,-5,0]) {
cube([w-0.2,0.05,h+0.15], center=true);
}
}
}
}
}
// cutout part near end of pipe
//translate([pipe_len+offset,0,0]) sphere(0.25);
}
}

View file

@ -3,6 +3,7 @@ set(CMAKE_INCLUDE_CURRENT_DIRS ON)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
find_package(epoxy REQUIRED) find_package(epoxy REQUIRED)
find_package(X11 REQUIRED) find_package(X11 REQUIRED)
find_package(assimp REQUIRED)
set(GAME_SRC set(GAME_SRC
main.cpp main.cpp
@ -34,7 +35,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${OPENGL_INCLUDE_DIR}) include_directories(${OPENGL_INCLUDE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/libs/glm/) include_directories(${CMAKE_SOURCE_DIR}/libs/glm/)
include_directories(${CMAKE_SOURCE_DIR}/libs/asio/asio/include/) include_directories(${CMAKE_SOURCE_DIR}/libs/asio/asio/include/)
include_directories(${assimp_INCLUDE_DIRS})
add_executable(game ${GAME_SRC}) add_executable(game ${GAME_SRC})
setup_target(game) setup_target(game)
target_link_libraries(game X11 epoxy pthread)
target_link_libraries(game X11 epoxy pthread ${assimp_LIBRARIES} assimp)

View file

@ -20,16 +20,20 @@
class GameWindow : public endofthejedi::GLWindow { class GameWindow : public endofthejedi::GLWindow {
private: private:
Game* m_game; Game* m_game;
//endofthejedi::RendererPolygon2d m_renderer; endofthejedi::RendererPolygon2d m_renderer;
//endofthejedi::RendererPolygon3d m_renderer; //endofthejedi::RendererPolygon3d m_renderer;
endofthejedi::RendererRayTracer m_renderer; //endofthejedi::RendererRayTracer m_renderer;
protected: protected:
void init() override { void init() override {
std::cout<<"init" << std::endl;
glClearColor(0.5f, 0.6f, 0.7f, 1.0f); glClearColor(0.5f, 0.6f, 0.7f, 1.0f);
resize(); resize();
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
m_renderer.setup();
} }
void render(double time) override { void render(double time) override {

View file

@ -3,75 +3,87 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
endofthejedi::VAO::VAO() { glGenVertexArrays(1, &m_name); } namespace endofthejedi {
VAO::VAO() { glGenVertexArrays(1, &m_name); }
endofthejedi::VAO::~VAO() { glDeleteVertexArrays(1, &m_name); } VAO::~VAO() { glDeleteVertexArrays(1, &m_name); }
void endofthejedi::VAO::bind() { glBindVertexArray(m_name); } void VAO::bind() { glBindVertexArray(m_name); }
void endofthejedi::VAO::fill(GLuint index, GLint size, GLenum type, void VAO::fill(GLuint index, GLint size, GLenum type,
GLboolean normalized, GLsizei stride, GLboolean normalized, GLsizei stride,
const GLvoid *pointer) { const GLvoid *pointer)
glEnableVertexAttribArray(index); {
glVertexAttribPointer(index, size, GL_FLOAT, normalized, stride, pointer); (void) type;
}
endofthejedi::Shader::Shader() { m_program = glCreateProgram(); } glEnableVertexAttribArray(index);
glVertexAttribPointer(index, size, GL_FLOAT, normalized, stride, pointer);
endofthejedi::Shader::~Shader() {}
bool endofthejedi::Shader::check() {
GLint len = 0;
GLint result = 0;
glGetProgramiv(m_program, GL_LINK_STATUS, &result);
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &len);
if (len > 1) {
char *error = (char *)malloc(len);
glGetProgramInfoLog(m_program, len, NULL, error);
std::string str(error);
std::cout << str << "\n";
} }
std::cout << "checked program"
<< "\n";
return (bool)result; Shader::Shader() : m_program(0) { }
}
bool endofthejedi::Shader::checkShader(GLuint shader) { Shader::~Shader() {}
GLint len = 0;
GLint result = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &result); void Shader::init() { m_program = glCreateProgram(); }
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
if (len > 1) { bool Shader::check() {
char *error = (char *)malloc(len+1); GLint len = 0;
glGetShaderInfoLog(shader, 0, &len, error); GLint result = 0;
std::string str(error, error + len);
std::cout << str << "\n"; glGetProgramiv(m_program, GL_LINK_STATUS, &result);
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &len);
if (len > 1) {
char *error = (char *)malloc(len);
glGetProgramInfoLog(m_program, len, NULL, error);
std::string str(error);
std::cout << str << std::endl;
}
std::cout << "checked program" << std::endl;
return (bool)result;
} }
std::cout << "checked shader"
<< "\n";
return (bool)result; bool Shader::checkShader(GLuint shader) {
} GLint len = 0;
GLint result = 0;
void endofthejedi::Shader::bind() { glUseProgram(m_program); }
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
void endofthejedi::Shader::unbind() { glUseProgram(0); } glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
if (len > 1) {
void endofthejedi::Shader::load(std::string path, GLenum shadertype) { char *error = (char *)malloc(len+1);
GLuint cheddar = glCreateShader(shadertype); glGetShaderInfoLog(shader, 0, &len, error);
const char *cheddardata = path.c_str(); std::string str(error, error + len);
glShaderSource(cheddar, 1, &cheddardata, NULL); std::cout << str << std::endl;
glCompileShader(cheddar); }
checkShader(cheddar);
glAttachShader(m_program, cheddar); std::cout << "checked shader" << std::endl;
glLinkProgram(m_program);
check(); return (bool)result;
glDeleteShader(cheddar); }
}
void Shader::bind() { glUseProgram(m_program); }
GLuint endofthejedi::Shader::location(std::string name) {
return glGetUniformLocation(m_program, name.c_str()); void Shader::unbind() { glUseProgram(0); }
void Shader::load(const std::string &path, GLenum shadertype) {
if (m_program == 0) {
std::cout<<"[shader] error: shader program is invalid (0)!" << std::endl;
exit(-1);
return;
}
GLuint cheddar = glCreateShader(shadertype);
const char *cheddardata = path.c_str();
glShaderSource(cheddar, 1, &cheddardata, NULL);
glCompileShader(cheddar);
checkShader(cheddar);
glAttachShader(m_program, cheddar);
glLinkProgram(m_program);
check();
glDeleteShader(cheddar);
}
GLuint Shader::location(const std::string &name) {
return glGetUniformLocation(m_program, name.c_str());
}
} }

View file

@ -43,6 +43,7 @@ class VAO {
class Shader { class Shader {
private: private:
GLuint m_program; GLuint m_program;
bool check(); bool check();
bool checkShader(GLuint shader); bool checkShader(GLuint shader);
@ -50,10 +51,12 @@ class Shader {
public: public:
Shader(); Shader();
~Shader(); ~Shader();
void init(); // call to init when opengl context exists
void bind(); void bind();
void unbind(); void unbind();
void load(std::string data, GLenum shadertype); void load(const std::string &data, GLenum shadertype);
GLuint location(std::string name); GLuint location(const std::string &name);
}; };
} }

View file

@ -71,6 +71,7 @@ int main(int argc, char *argv[]) {
GameWindow window(500, 500, &game); GameWindow window(500, 500, &game);
window.set_maxfps(60.0); window.set_maxfps(60.0);
window.open();
while(window.running()){ while(window.running()){
window.poll(); window.poll();

View file

@ -19,117 +19,126 @@ timespec diff(timespec start, timespec end) {
return result; return result;
} }
endofthejedi::GLWindow::GLWindow(unsigned int width, unsigned int height) namespace endofthejedi {
: m_width(width), m_height(height) {
m_display = XOpenDisplay(NULL);
if (m_display == NULL) { GLWindow::GLWindow(unsigned int width, unsigned int height) : m_width(width), m_height(height)
throw std::runtime_error("XOpenDisplay NULL"); {
} }
m_rootwnd = DefaultRootWindow(m_display); void GLWindow::open()
{
m_display = XOpenDisplay(NULL);
m_visualinfo = glXChooseVisual(m_display, 0, m_attributes); if (m_display == NULL) {
throw std::runtime_error("XOpenDisplay NULL");
}
if (m_visualinfo == NULL) { m_rootwnd = DefaultRootWindow(m_display);
throw std::runtime_error("glXChooseVisual NULL");
m_visualinfo = glXChooseVisual(m_display, 0, m_attributes);
if (m_visualinfo == NULL) {
throw std::runtime_error("glXChooseVisual NULL");
}
m_colormap =
XCreateColormap(m_display, m_rootwnd, m_visualinfo->visual, AllocNone);
m_swa.colormap = m_colormap;
m_swa.event_mask = ExposureMask | KeyPressMask;
m_window = XCreateWindow(
m_display, m_rootwnd, 0, 0, m_width, m_height, 0, m_visualinfo->depth,
InputOutput, m_visualinfo->visual, CWColormap | CWEventMask, &m_swa);
m_atomWmDeleteWindow = XInternAtom(m_display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(m_display, m_window, &m_atomWmDeleteWindow, 1);
XMapWindow(m_display, m_window);
XStoreName(m_display, m_window, "NAME");
m_glcontext = glXCreateContext(m_display, m_visualinfo, NULL, GL_TRUE);
XSync(m_display, False);
glXMakeCurrent(m_display, m_window, m_glcontext);
std::cout << "GL Renderer: " << glGetString(GL_RENDERER) << "\n";
std::cout << "GL Version: " << glGetString(GL_VERSION) << "\n";
std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION)
<< "\n";
m_running = true;
init();
XClearWindow(m_display, m_window);
XMapRaised(m_display, m_window);
} }
m_colormap = GLWindow::~GLWindow() {
XCreateColormap(m_display, m_rootwnd, m_visualinfo->visual, AllocNone); glXMakeCurrent(m_display, None, NULL);
glXDestroyContext(m_display, m_glcontext);
m_swa.colormap = m_colormap; XFree(m_visualinfo);
m_swa.event_mask = ExposureMask | KeyPressMask; XDestroyWindow(m_display, m_window);
XCloseDisplay(m_display);
m_window = XCreateWindow(
m_display, m_rootwnd, 0, 0, width, height, 0, m_visualinfo->depth,
InputOutput, m_visualinfo->visual, CWColormap | CWEventMask, &m_swa);
m_atomWmDeleteWindow = XInternAtom(m_display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(m_display, m_window, &m_atomWmDeleteWindow, 1);
XMapWindow(m_display, m_window);
XStoreName(m_display, m_window, "NAME");
m_glcontext = glXCreateContext(m_display, m_visualinfo, NULL, GL_TRUE);
XSync(m_display, False);
glXMakeCurrent(m_display, m_window, m_glcontext);
std::cout << "GL Renderer: " << glGetString(GL_RENDERER) << "\n";
std::cout << "GL Version: " << glGetString(GL_VERSION) << "\n";
std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION)
<< "\n";
init();
XClearWindow(m_display, m_window);
XMapRaised(m_display, m_window);
}
endofthejedi::GLWindow::~GLWindow() {
glXMakeCurrent(m_display, None, NULL);
glXDestroyContext(m_display, m_glcontext);
XFree(m_visualinfo);
XDestroyWindow(m_display, m_window);
XCloseDisplay(m_display);
}
void endofthejedi::GLWindow::handleevents() {
if (XPending(m_display) > 0) {
XEvent xev;
XNextEvent(m_display, &xev);
handle(xev);
} }
}
void endofthejedi::GLWindow::handle(XEvent event) { void GLWindow::handleevents() {
if (event.type == Expose) { if (XPending(m_display) > 0) {
XWindowAttributes attribs; XEvent xev;
XGetWindowAttributes(m_display, m_window, &attribs); XNextEvent(m_display, &xev);
m_width = attribs.width; handle(xev);
m_height = attribs.height; }
resize(); }
} else if (event.type == ClientMessage) {
if (event.xclient.data.l[0] == m_atomWmDeleteWindow) { void GLWindow::handle(XEvent event) {
if (event.type == Expose) {
XWindowAttributes attribs;
XGetWindowAttributes(m_display, m_window, &attribs);
m_width = attribs.width;
m_height = attribs.height;
resize();
} else if (event.type == ClientMessage) {
if (event.xclient.data.l[0] == m_atomWmDeleteWindow) {
stop();
}
} else if (event.type == DestroyNotify) {
stop(); stop();
} }
} else if (event.type == DestroyNotify) {
stop();
} }
void GLWindow::swap() { glXSwapBuffers(m_display, m_window); }
void GLWindow::poll() {
clock_gettime(CLOCK_MONOTONIC_RAW, &prev);
clock_gettime(CLOCK_MONOTONIC_RAW, &current);
handleevents();
render(delta);
swap();
if (m_maxfps > 0) {
sleeptime = ((1000000000.0/m_maxfps) - delta) + sleeptime;
if (sleeptime > 0.0) {
usleep((unsigned int)(sleeptime/1000.0));
sleeptime = sleeptime - (unsigned int)(sleeptime/1000.0);
}
}
clock_gettime(CLOCK_MONOTONIC_RAW, &current);
delta = diff(prev, current).tv_nsec;
prev = current;
if(delta > 0.0) {
m_fps = (1000000000.0/delta);
//std::cout << m_fps << "\n";
}
}
void GLWindow::stop() { m_running = false; }
bool GLWindow::running() { return m_running; }
void GLWindow::init() { }
void GLWindow::render(double time) { UNUSED(time) }
void GLWindow::resize() {}
} }
void endofthejedi::GLWindow::swap() { glXSwapBuffers(m_display, m_window); }
void endofthejedi::GLWindow::poll() {
clock_gettime(CLOCK_MONOTONIC_RAW, &prev);
clock_gettime(CLOCK_MONOTONIC_RAW, &current);
handleevents();
render(delta);
swap();
if (m_maxfps > 0) {
sleeptime = ((1000000000.0/m_maxfps) - delta) + sleeptime;
if (sleeptime > 0.0) {
usleep((unsigned int)(sleeptime/1000.0));
sleeptime = sleeptime - (unsigned int)(sleeptime/1000.0);
}
}
clock_gettime(CLOCK_MONOTONIC_RAW, &current);
delta = diff(prev, current).tv_nsec;
prev = current;
if(delta > 0.0) {
m_fps = (1000000000.0/delta);
//std::cout << m_fps << "\n";
}
}
void endofthejedi::GLWindow::stop() { m_running = false; }
bool endofthejedi::GLWindow::running() { return m_running; }
void endofthejedi::GLWindow::init() { m_running = true; }
void endofthejedi::GLWindow::render(double time) { UNUSED(time) }
void endofthejedi::GLWindow::resize() {}

View file

@ -67,10 +67,14 @@ namespace endofthejedi {
virtual void handleevents(); virtual void handleevents();
public: public:
//initializes the X Window & creates an OpenGL context // create the class. call open() afterwards
GLWindow(unsigned int width, unsigned int height); GLWindow(unsigned int width, unsigned int height);
~GLWindow(); ~GLWindow();
//initializes the X Window & creates an OpenGL context
void open();
//mainloop does event handling & calls render/swap //mainloop does event handling & calls render/swap
void poll(); void poll();
void swap(); void swap();

View file

@ -1,6 +1,15 @@
#include "renderer_polygon_2d.hpp" #include "renderer_polygon_2d.hpp"
namespace endofthejedi { namespace endofthejedi {
void RendererPolygon2d::setup()
{
// (dark grey) bg
float r = 0.1;
float g = 0.1;
float b = 0.1;
glClearColor(r, g, b, 1.0);
}
void RendererPolygon2d::drawCircle(float x, float y, float radius, void RendererPolygon2d::drawCircle(float x, float y, float radius,
float r, float g, float b, float r, float g, float b,
int numSides) { int numSides) {

View file

@ -15,7 +15,7 @@
namespace endofthejedi { namespace endofthejedi {
class RendererPolygon2d : Renderer { class RendererPolygon2d : public Renderer {
private: private:
void drawCircle(float x, float y, float radius, float r, float g, void drawCircle(float x, float y, float radius, float r, float g,
float b, int numSides = 12); float b, int numSides = 12);
@ -27,7 +27,9 @@ namespace endofthejedi {
void drawExplosion(const game::Explosion *explosion); void drawExplosion(const game::Explosion *explosion);
protected: protected:
public: public:
void setup() override;
void render(const game::State *state) override; void render(const game::State *state) override;
}; };

View file

@ -0,0 +1,116 @@
#pragma once
#include <string>
#include <iostream>
#include <assimp/Importer.hpp> // C++ importer interface
#include <assimp/scene.h> // Output data structure
#include <assimp/postprocess.h> // Post processing flags
#include <epoxy/gl.h>
#include <epoxy/glx.h>
class PolygonModel {
public:
PolygonModel(const std::string &filename) : m_filename(filename)
{
if (!import()) {
m_loaded = false;
} else {
m_loaded = true;
}
}
bool import()
{
// Create an instance of the Importer class
Assimp::Importer importer;
// And have it read the given file with some example postprocessing
// Usually - if speed is not the most important aspect for you - you'll
// propably to request more postprocessing than we do in this example.
const aiScene* scene = importer.ReadFile(m_filename,
aiProcess_CalcTangentSpace |
aiProcess_Triangulate |
aiProcess_JoinIdenticalVertices |
aiProcess_SortByPType);
// If the import failed, report it
if (!scene) {
std::cout<<"[polygonmodel] loading file "
<< m_filename << " failed with: "
<< importer.GetErrorString() << std::endl;
return false;
}
// Now we can access the file's contents.
copyVertices(scene);
// We're done. Everything will be cleaned up by the importer destructor
return true;
}
private:
bool copyVertices(const aiScene *scene)
{
if (scene->mMeshes == 0) {
std::cout << "[polygonmodel : no meshes loaded for " << m_filename << std::endl;
return false;
}
aiNode *node = scene->mRootNode;
const aiMesh* mesh = scene->mMeshes[node->mMeshes[0]];
// 3 vertices per face, 3 floats per vertex
m_numVertices = mesh->mNumFaces*3;
m_data_position.reserve(m_numVertices);
m_data_normal.reserve(m_numVertices);
size_t t, i;
for (t=0; t<mesh->mNumFaces; ++t) {
const aiFace* face = &mesh->mFaces[t];
if (face->mNumIndices != 3) {
std::cout << "[polygonmodel] need triangles, got something different with: "
<< face->mNumIndices << " vertices" << std::endl;
return false;
}
for (i=0; i<face->mNumIndices; i++) {
const size_t index = face->mIndices[i];
m_data_position.push_back(mesh->mVertices[index].x);
m_data_position.push_back(mesh->mVertices[index].y);
m_data_position.push_back(mesh->mVertices[index].z);
m_data_normal.push_back(mesh->mNormals[index].x);
m_data_normal.push_back(mesh->mNormals[index].y);
m_data_normal.push_back(mesh->mNormals[index].z);
}
}
size_t totalBytes = 3*m_numVertices*sizeof(float);
std::cout<<"[polygonmodel] loaded " << m_numVertices << " vertices ("
<< totalBytes << " bytes)" << std::endl;
return true;
}
const std::string &filename() const { return m_filename; }
bool ready() const { return m_loaded; }
private:
std::string m_filename;
bool m_loaded;
size_t m_numVertices;
// both will hold 3 * numVertices floats
std::vector<float> m_data_position;
std::vector<float> m_data_normal;
GLuint m_vbo_id_position;
GLuint m_vbo_id_normal;
};

View file

@ -2,16 +2,21 @@
#include <iostream> #include <iostream>
#include "polygon_model.hpp"
namespace endofthejedi { namespace endofthejedi {
void RendererPolygon3d::setup() void RendererPolygon3d::setup()
{ {
std::cout<<"setup 3d" << std::endl; std::cout<<"setup 3d" << std::endl;
PolygonModel atomicBomb("../data/mesh/small_atomic_bomb.stl");
exit(-1);
} }
void RendererPolygon3d::render(const game::State *state) void RendererPolygon3d::render(const game::State *state)
{ {
(void) state; (void) state;
//std::cout<<"render 3d" << std::endl; std::cout<<"render 3d" << std::endl;
} }
} }

View file

@ -12,14 +12,18 @@
#include "state/ship.hpp" #include "state/ship.hpp"
#include "state/explosion.hpp" #include "state/explosion.hpp"
class PolygonModel;
namespace endofthejedi { namespace endofthejedi {
class RendererPolygon3d : Renderer { class RendererPolygon3d : public Renderer {
private: private:
protected: protected:
public: public:
void setup(); void setup();
void render(const game::State *state) override; void render(const game::State *state) override;
};
private:
std::vector<PolygonModel*> m_models;
};
} }

View file

@ -16,7 +16,13 @@ static const char *fss =
namespace endofthejedi { namespace endofthejedi {
RendererRayTracer::RendererRayTracer() { RendererRayTracer::RendererRayTracer()
{
}
void RendererRayTracer::setup()
{
m_shader.init();
m_shader.load(vss, GL_VERTEX_SHADER); m_shader.load(vss, GL_VERTEX_SHADER);
m_shader.load(fss, GL_FRAGMENT_SHADER); m_shader.load(fss, GL_FRAGMENT_SHADER);
} }

View file

@ -11,12 +11,14 @@
namespace endofthejedi { namespace endofthejedi {
class RendererRayTracer: Renderer { class RendererRayTracer : public Renderer {
private: private:
Shader m_shader; Shader m_shader;
protected: protected:
public: public:
RendererRayTracer(); RendererRayTracer();
void setup() override;
void render(const game::State *state) override; void render(const game::State *state) override;
}; };

View file

@ -13,7 +13,9 @@ namespace game {
// TODO: idea // TODO: idea
// shoot multiple rockets at once or from different positions after // shoot multiple rockets at once or from different positions after
// level up / upgrade ... // level up / upgrade ...
Missile *missile = new Missile(player, player->ship->position, util::deg2rad(m_angle), player->speed);
// angles are supplied in degrees and are CCW
Missile *missile = new Missile(player, player->ship->position, -util::deg2rad(m_angle), player->speed);
Trace *trace = new Trace(missile); Trace *trace = new Trace(missile);
missile->trace = trace; missile->trace = trace;