From 918b4955c28fad1836a57ab3e9e033448144996c Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Wed, 11 Feb 2015 21:01:35 +0100 Subject: [PATCH] initial testing --- .gitignore | 5 ++ Makefile | 34 +++++++++++ src/init.cpp | 133 +++++++++++++++++++++++++++++++++++++++++ src/init.hpp | 88 +++++++++++++++++++++++++++ src/main.cpp | 157 +++++++++++++++++++++++++++++++++++++++++++++++++ src/shader.cpp | 123 ++++++++++++++++++++++++++++++++++++++ src/shader.hpp | 60 +++++++++++++++++++ 7 files changed, 600 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 src/init.cpp create mode 100644 src/init.hpp create mode 100644 src/main.cpp create mode 100644 src/shader.cpp create mode 100644 src/shader.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0f9ba43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.d +*.o +*.swp +*.swo +blank diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a3855ad --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +CXX = g++ --std=c++11 +LDXX = g++ + +LIBS = sdl2 glew + +PKGFLAGS := $(shell pkg-config --cflags $(LIBS)) +PKGLIBS := $(shell pkg-config --libs $(LIBS)) + +CPPFLAGS ?= +CPPFLAGS += $(PKGFLAGS) +CXXFLAGS ?= +CXXFLAGS += -Wall +LDXXFLAGS ?= +LDXXFLAGS += $(PKGLIBS) + +SRC = $(wildcard src/*.cpp) +OBJ = $(SRC:.cpp=.o) +DEP = $(SRC:.cpp=.d) +BIN = blank + +all: $(BIN) + +clean: + rm -f $(BIN) $(OBJ) $(DEP) + +.PHONY: all clean + +-include $(DEP) + +$(BIN): $(OBJ) + $(LDXX) -o $@ $(CXXFLAGS) $(LDXXFLAGS) $^ + +%.o: %.cpp + $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $@ -MMD -MP -MF"$*".d -MT"$@" $< diff --git a/src/init.cpp b/src/init.cpp new file mode 100644 index 0000000..9010e00 --- /dev/null +++ b/src/init.cpp @@ -0,0 +1,133 @@ +#include "init.hpp" + +#include +#include +#include +#include +#include + + +namespace { + +void sdl_error(std::string msg) { + const char *error = SDL_GetError(); + if (*error != '\0') { + msg += ": "; + msg += error; + SDL_ClearError(); + } + throw std::runtime_error(msg); +} + +} + +namespace blank { + +InitSDL::InitSDL() { + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + sdl_error("SDL_Init(SDL_INIT_VIDEO)"); + } +} + +InitSDL::~InitSDL() { + SDL_Quit(); +} + + +InitGL::InitGL() { + if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3) != 0) { + sdl_error("SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3)"); + } + if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3) != 0) { + sdl_error("SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3)"); + } + if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE) != 0) { + sdl_error("SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE)"); + } + + if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) != 0) { + sdl_error("SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)"); + } +} + +InitGL::~InitGL() { + +} + + +Window::Window() +: handle(SDL_CreateWindow( + "blank", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + 960, 600, + SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE +)) { + if (!handle) { + sdl_error("SDL_CreateWindow"); + } +} + +Window::~Window() { + SDL_DestroyWindow(handle); +} + +GLContext Window::CreateContext() { + return GLContext(handle); +} + +void Window::Flip() { + SDL_GL_SwapWindow(handle); +} + + +GLContext::GLContext(SDL_Window *win) +: handle(SDL_GL_CreateContext(win)) { + if (!handle) { + sdl_error("SDL_GL_CreateContext"); + } +} + +GLContext::~GLContext() { + if (handle) { + SDL_GL_DeleteContext(handle); + } +} + + +GLContext::GLContext(GLContext &&other) +: handle(other.handle) { + other.handle = nullptr; +} + +GLContext &GLContext::operator =(GLContext &&other) { + std::swap(handle, other.handle); + return *this; +} + +void GLContext::EnableVSync() { + if (SDL_GL_SetSwapInterval(1) != 0) { + sdl_error("SDL_GL_SetSwapInterval"); + } +} + + +InitGLEW::InitGLEW() { + glewExperimental = GL_TRUE; + GLenum glew_err = glewInit(); + if (glew_err != GLEW_OK) { + std::string msg("glewInit: "); + const GLubyte *errBegin = glewGetErrorString(glew_err); + const GLubyte *errEnd = errBegin; + while (*errEnd != '\0') { + ++errEnd; + } + msg.append(errBegin, errEnd); + throw std::runtime_error(msg); + } +} + +InitGLEW::~InitGLEW() { + +} + +} diff --git a/src/init.hpp b/src/init.hpp new file mode 100644 index 0000000..0256d40 --- /dev/null +++ b/src/init.hpp @@ -0,0 +1,88 @@ +#ifndef BLANK_INIT_HPP_ +#define BLANK_INIT_HPP_ + +#include + + +namespace blank { + +class GLContext; + + +class InitSDL { + +public: + InitSDL(); + ~InitSDL(); + + InitSDL(const InitSDL &) = delete; + InitSDL &operator =(const InitSDL &) = delete; + +}; + + +class InitGL { + +public: + InitGL(); + ~InitGL(); + + InitGL(const InitGL &) = delete; + InitGL &operator =(const InitGL &) = delete; + +}; + + +class Window { + +public: + Window(); + ~Window(); + + Window(const Window &) = delete; + Window &operator =(const Window &) = delete; + + GLContext CreateContext(); + + void Flip(); + +private: + SDL_Window *handle; + +}; + + +class GLContext { + +public: + explicit GLContext(SDL_Window *); + ~GLContext(); + + GLContext(GLContext &&); + GLContext &operator =(GLContext &&); + + GLContext(const GLContext &) = delete; + GLContext &operator =(const GLContext &) = delete; + + static void EnableVSync(); + +private: + SDL_GLContext handle; + +}; + + +class InitGLEW { + +public: + InitGLEW(); + ~InitGLEW(); + + InitGLEW(const InitGLEW &) = delete; + InitGLEW &operator =(const InitGLEW &) = delete; + +}; + +} + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..33071f1 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include + +#include "init.hpp" +#include "shader.hpp" + +using namespace std; +using namespace blank; + + +constexpr GLfloat vtx_coords[] = { + -1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + 0.0f, 1.0f, -1.0f, +}; + + +int main(int argc, char *argv[]) { + + InitSDL init_sdl; + InitGL init_gl; + Window window; + + GLContext ctx = window.CreateContext(); + InitGLEW init_glew; + GLContext::EnableVSync(); + + + Shader vtx_shader(GL_VERTEX_SHADER); + vtx_shader.Source( + "#version 330 core\n" + "layout(location = 0) in vec3 vertexPosition_modelspace;\n" + "uniform mat4 MVP;\n" + "void main() {\n" + "vec4 v = vec4(vertexPosition_modelspace, 1);\n" + "gl_Position = MVP * v;\n" + "}\n" + ); + vtx_shader.Compile(); + + if (!vtx_shader.Compiled()) { + cerr << "vertex shader compile error" << endl; + vtx_shader.Log(cerr); + return 4; + } + + Shader frag_shader(GL_FRAGMENT_SHADER); + frag_shader.Source( + "#version 330 core\n" + "out vec3 color;\n" + "void main() {\n" + "color = vec3(1, 1, 1);\n" + "}\n" + ); + frag_shader.Compile(); + + if (!frag_shader.Compiled()) { + cerr << "fragment shader compile error" << endl; + frag_shader.Log(cerr); + return 4; + } + + + Program program; + program.Attach(vtx_shader); + program.Attach(frag_shader); + program.Link(); + + if (!program.Linked()) { + cerr << "program link error" << endl; + program.Log(cerr); + return 4; + } + + + GLuint VertexArrayID; + glGenVertexArrays(1, &VertexArrayID); + glBindVertexArray(VertexArrayID); + + + GLuint vtx_buf; + glGenBuffers(1, &vtx_buf); + glBindBuffer(GL_ARRAY_BUFFER, vtx_buf); + glBufferData(GL_ARRAY_BUFFER, sizeof(vtx_coords), vtx_coords, GL_STATIC_DRAW); + + + glm::mat4 projection = glm::perspective( + 45.0f, // FOV in degrees + 1.0f, // aspect ratio + 0.1f, // near clip + 100.0f // far clip + ); + glm::mat4 view = glm::lookAt( + glm::vec3(0, 0, 0), // observer + glm::vec3(0, 0, -1), // target + glm::vec3(0, 1, 0) // up + ); + glm::mat4 model(1.0f); // identity: no transformation + glm::mat4 mvp = projection * view * model; + + GLuint mvp_id = program.UniformLocation("MVP"); + + + glClearColor(0.0, 0.0, 0.0, 1.0); + + + bool running = true; + Uint32 last = SDL_GetTicks(); + while (running) { + Uint32 now = SDL_GetTicks(); + int delta = now - last; + + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + running = false; + break; + default: + break; + } + } + + glClear(GL_COLOR_BUFFER_BIT); + + program.Use(); + + glUniformMatrix4fv(mvp_id, 1, GL_FALSE, &mvp[0][0]); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, vtx_buf); + glVertexAttribPointer( + 0, // attribute 0 (for shader) + 3, // size + GL_FLOAT, // type + GL_FALSE, // normalized + 0, // stride + nullptr // offset + ); + glDrawArrays( + GL_TRIANGLES, // how + 0, // start + 3 // len + ); + glDisableVertexAttribArray(0); + + window.Flip(); + + last = now; + } + + return 0; + +} diff --git a/src/shader.cpp b/src/shader.cpp new file mode 100644 index 0000000..985b96e --- /dev/null +++ b/src/shader.cpp @@ -0,0 +1,123 @@ +#include "shader.hpp" + +#include +#include +#include +#include +#include + + +namespace { + +void gl_error(std::string msg) { + const GLubyte *errBegin = gluErrorString(glGetError()); + if (errBegin && *errBegin != '\0') { + const GLubyte *errEnd = errBegin; + while (*errEnd != '\0') { + ++errEnd; + } + msg += ": "; + msg.append(errBegin, errEnd); + } + throw std::runtime_error(msg); +} + +} + +namespace blank { + +Shader::Shader(GLenum type) +: handle(glCreateShader(type)) { + if (handle == 0) { + gl_error("glCreateShader"); + } +} + +Shader::~Shader() { + if (handle != 0) { + glDeleteShader(handle); + } +} + +Shader::Shader(Shader &&other) +: handle(other.handle) { + other.handle = 0; +} + +Shader &Shader::operator =(Shader &&other) { + std::swap(handle, other.handle); + return *this; +} + + +void Shader::Source(const GLchar *src) { + const GLchar* src_arr[] = { src }; + glShaderSource(handle, 1, src_arr, nullptr); +} + +void Shader::Compile() { + glCompileShader(handle); +} + +bool Shader::Compiled() const { + GLint compiled = GL_FALSE; + glGetShaderiv(handle, GL_COMPILE_STATUS, &compiled); + return compiled == GL_TRUE; +} + +void Shader::Log(std::ostream &out) const { + int log_len = 0, max_len = 0; + glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &max_len); + std::unique_ptr log(new char[max_len]); + glGetShaderInfoLog(handle, max_len, &log_len, log.get()); + out.write(log.get(), log_len); +} + + +void Shader::AttachToProgram(GLuint id) const { + glAttachShader(id, handle); +} + + +Program::Program() +: handle(glCreateProgram()) { + if (handle == 0) { + gl_error("glCreateProgram"); + } +} + +Program::~Program() { + if (handle != 0) { + glDeleteProgram(handle); + } +} + + +void Program::Attach(Shader &shader) { + shader.AttachToProgram(handle); +} + +void Program::Link() { + glLinkProgram(handle); +} + +bool Program::Linked() const { + GLint linked = GL_FALSE; + glGetProgramiv(handle, GL_LINK_STATUS, &linked); + return linked == GL_TRUE; +} + +void Program::Log(std::ostream &out) const { + int log_len = 0, max_len = 0; + glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &max_len); + std::unique_ptr log(new char[max_len]); + glGetProgramInfoLog(handle, max_len, &log_len, log.get()); + out.write(log.get(), log_len); +} + + +GLint Program::UniformLocation(const GLchar *name) const { + return glGetUniformLocation(handle, name); +} + +} diff --git a/src/shader.hpp b/src/shader.hpp new file mode 100644 index 0000000..c112c53 --- /dev/null +++ b/src/shader.hpp @@ -0,0 +1,60 @@ +#ifndef BLANK_SHADER_HPP_ +#define BLANK_SHADER_HPP_ + +#include +#include + + +namespace blank { + +class Shader { + +public: + explicit Shader(GLenum type); + ~Shader(); + + Shader(Shader &&); + Shader &operator =(Shader &&); + + Shader(const Shader &) = delete; + Shader &operator =(const Shader &) = delete; + + void Source(const GLchar *src); + void Compile(); + bool Compiled() const; + void Log(std::ostream &) const; + + void AttachToProgram(GLuint id) const; + +private: + GLuint handle; + +}; + + +class Program { + +public: + Program(); + ~Program(); + + Program(const Program &) = delete; + Program &operator =(const Program &) = delete; + + void Attach(Shader &); + void Link(); + bool Linked() const; + void Log(std::ostream &) const; + + GLint UniformLocation(const GLchar *name) const; + + void Use() const { glUseProgram(handle); } + +private: + GLuint handle; + +}; + +} + +#endif -- 2.39.2