Files
openglplayground/main.cc
2015-03-10 00:48:25 +01:00

438 lines
14 KiB
C++

#include <cstdio>
#include <cmath>
#include <string>
#include <unordered_map>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <glbinding/gl/gl.h>
#include <glbinding/Binding.h>
#include <glbinding/callbacks.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/packing.hpp>
#include "common.hh"
#include "shaders.hh"
#include "texture.hh"
#include "VBOManager.hh"
#include "objectParser.hh"
#include "Object.hh"
#include "font.hh"
#include "Overlay.hh"
#include "TextWidget.hh"
#include "LinearLayout.hh"
#include "GUILoader.hh"
#include "FontProvider.hh"
#include "ImageProvider.hh"
using namespace gl;
void glAfterCallback(glbinding::FunctionCall const& fc)
{
glbinding::setCallbackMask(glbinding::CallbackMask::None);
GLenum error = glGetError();
glbinding::setCallbackMask(glbinding::CallbackMask::After);
if (error != GL_NO_ERROR)
throw GLException(error);
}
int main(int argc, char *argv[])
{
SDL_Window *window;
int retcode = 0;
glbinding::Binding::initialize();
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::printf("Could not init SDL: %s\n", SDL_GetError());
return 1;
}
if (IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG) == 0) {
std::printf("Could not init SDL_image: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
if(TTF_Init() == -1) {
printf("Could not init SDL_ttf: %s\n", TTF_GetError());
IMG_Quit();
SDL_Quit();
return 1;
}
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
window = SDL_CreateWindow("SDL2 Test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
1680,
1050,
/*SDL_WINDOW_FULLSCREEN_DESKTOP |*/ SDL_WINDOW_OPENGL);
if (!window) {
std::printf("Could not create window: %s\n", SDL_GetError());
TTF_Quit();
IMG_Quit();
SDL_Quit();
return 1;
}
SDL_GLContext glcontext = SDL_GL_CreateContext(window);
if (!glcontext) {
std::printf("Could not create GL context: %s\n", SDL_GetError());
SDL_DestroyWindow(window);
TTF_Quit();
IMG_Quit();
SDL_Quit();
return 1;
}
// Clear GL errors
while(glGetError() != GL_NO_ERROR);
try {
glbinding::setCallbackMask(glbinding::CallbackMask::After);
glbinding::setAfterCallback(glAfterCallback);
{
int depth, stencil, aa, major, minor;
SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depth);
SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil);
SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &aa);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
std::printf("Depth: %d, Stencil: %d, AA: %d, GL %d.%d\n",
depth, stencil, aa, major, minor);
}
int width, height;
SDL_GetWindowSize(window, &width, &height);
glm::mat4 proj = glm::perspectiveFov(75.0f, static_cast<float>(width), static_cast<float>(height),
0.1f, 100.0f);
glm::mat4 view = glm::lookAt(glm::vec3(2.0f, 2.0f, 10),
glm::vec3(0.0f, 0.0f, 0),
glm::vec3(0, 1, 0));
//Font font{"DejaVuSans.ttf", 12};
// sf::Font font;
// if (!font.loadFromFile("DejaVuSans.ttf")) {
// std::printf("Error loading font\n");
// return 1;
// }
// sf::Text fpsText{"0", font, 12};
// fpsText.setPosition({200, 200});
// window.setFramerateLimit(60);
// sf::Clock clock;
// sf::Time last = clock.getElapsedTime();
auto last = SDL_GetTicks();
Texture2D cubeTex("textures/Wood_Box_Texture.jpg");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast<int>(GL_LINEAR_MIPMAP_LINEAR));
if (SDL_GL_ExtensionSupported("GL_EXT_texture_filter_anisotropic"))
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4.0f);
else
std::printf("Warning: extension GL_EXT_texture_filter_anisotropic not supported\n");
Texture2D redTex("textures/red.png");
Texture2D whiteTex("textures/white.png");
const unsigned lights = 2;
const unsigned shadowMapSize = 512;
glm::mat4 shadowProj = glm::perspectiveFov(90.0f, static_cast<float>(shadowMapSize),
static_cast<float>(shadowMapSize), 1.0f, 128.0f);
//glm::mat4 shadowProj = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 128.0f);
std::vector<TextureCubeMap> shadowMaps;
for(unsigned i = 0;i < lights;++i) {
shadowMaps.emplace_back(shadowMapSize);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, static_cast<GLint>(GL_LESS));
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, static_cast<GLint>(GL_COMPARE_REF_TO_TEXTURE));
}
const glm::vec3 lightPos[lights] = {glm::vec3(2.0, -2.0, 10.0),
glm::vec3(2.0, 2.0, 10.0)};
// const glm::vec3 lightColor[lights] = {glm::vec3(1.0, 0.9, 0.8),
// glm::vec3(0.0, 1.0, 0.0)};
// const float lightIntensity[lights] = {75.0f, 25.0f};
glm::mat4 ovlProj = glm::ortho(0.0f, static_cast<float>(width), static_cast<float>(height), 0.0f);
Framebuffer shadowFB;
VertexShader vs{fileToString("shaders/textured.vs")};
FragmentShader fs{fileToString("shaders/textured.fs")};
Program prog{vs, fs};
VertexShader shadowVs{fileToString("shaders/shadow.vs")};
FragmentShader shadowFs{fileToString("shaders/shadow.fs")};
Program shadowProg{shadowVs, shadowFs};
VertexShader ovlVs{fileToString("shaders/overlay.vs")};
FragmentShader ovlFs{fileToString("shaders/overlay.fs")};
Program ovlProg{ovlVs, ovlFs};
prog.use();
glUniformMatrix4fv(prog.getUniformLocation("projection_matrix"), 1, GL_FALSE,
glm::value_ptr(proj));
glUniformMatrix4fv(prog.getUniformLocation("view_matrix"), 1, GL_FALSE,
glm::value_ptr(view));
glUniform1i(prog.getUniformLocation("texBase"), 0);
const GLint shadowMapTUs[] = {1, 2};
glUniform1iv(prog.getUniformLocation("texShadowMaps"), 2, shadowMapTUs);
shadowProg.use();
glUniformMatrix4fv(shadowProg.getUniformLocation("projection_matrix"), 1, GL_FALSE,
glm::value_ptr(shadowProj));
ovlProg.use();
glUniformMatrix4fv(ovlProg.getUniformLocation("projection_matrix"), 1, GL_FALSE,
glm::value_ptr(ovlProj));
glUniform1i(ovlProg.getUniformLocation("texBase"), 0);
Object box("objects/woodbox.obj");
Object pyramid("objects/pyramid.obj");
Object plane("objects/plane.obj");
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
bool close = false;
TTF_Font * font = FontProvider::getInstance().getFont("DejaVuSans.ttf", 12);
unsigned fpsTime = 0, fpsCount = 0;
TextWidget fpsText{font, "0 FPS", WRAP_CONTENT, WRAP_CONTENT, "fpsText"};
fpsText.setBackgroundColor(SDL_Color{0, 255, 0, 128});
fpsText.setPadding(8, 8, 8, 8);
auto laber = make_unique<TextWidget>(font, "Dies ist ein längerer\nText, der umgebrochen werden sollte. Bla laber schwafl, laber bullshit bingo",
204, WRAP_CONTENT, "laber");
laber->setBackgroundColor(SDL_Color{255, 0, 0, 128});
SDLSurfaceUPtr buttonImg(IMG_Load("textures/button_100x30.png"));
if (!buttonImg)
throw SDLException();
auto button = make_unique<TextWidget>(font, "Do stuff!", 100, 30, "button");
button->setPadding(6, 6, 6, 6);
button->setBackground(buttonImg.get());
button->setForegroundColor(SDL_Color{0, 0, 0, 255});
button->setAlignment(ALIGN_CENTER, ALIGN_CENTER);
auto button2 = make_unique<TextWidget>(font, "Cancel", 100, 30, "button2");
button2->setPadding(6, 6, 6, 6);
button2->setBackground(buttonImg.get());
button2->setForegroundColor(SDL_Color{0, 0, 0, 255});
button2->setAlignment(ALIGN_CENTER, ALIGN_CENTER);
auto layout2 = make_unique<LinearLayout>(DIR_HORIZONTAL, MATCH_PARENT, WRAP_CONTENT, "layout2");
layout2->setBackgroundColor(SDL_Color{0, 255, 0, 128});
layout2->setChildPadding(4);
layout2->addChild(std::move(button2));
layout2->addChild(std::move(button));
auto layout = make_unique<LinearLayout>(DIR_VERTICAL, WRAP_CONTENT, WRAP_CONTENT, "layout");
layout->setBackgroundColor(SDL_Color{0, 255, 255, 128});
layout->addChild(std::move(laber));
layout->addChild(std::move(layout2));
layout->setChildPadding(4);
layout->setPadding(4, 4, 4, 4);
layout->setGLRenderPos(200, 200);
auto gui = loadGUIFromFile("layouts/test.xml");
if (!gui)
throw Exception{"GUI load failed"};
View& guiRoot = dynamic_cast<View&>(*gui);
gui->setGLRenderPos(200, 500);
TextWidget& xmlButton = dynamic_cast<TextWidget&>(guiRoot.getPath("layout2/button"));
int countdown = 5;
xmlButton.setText(std::to_string(countdown));
while (!close) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_KEYDOWN:
close = true;
break;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_CLOSE)
close = true;
break;
}
}
// Draw shadow maps
GLint origVP[4];
glGetIntegerv(GL_VIEWPORT, origVP);
glViewport(0, 0, shadowMapSize, shadowMapSize);
shadowProg.use();
shadowFB.bind();
glPolygonOffset(1.1f, 4.0f);
glEnable(GL_POLYGON_OFFSET_FILL);
glEnable(GL_POLYGON_OFFSET_LINE);
glEnable(GL_POLYGON_OFFSET_POINT);
for (unsigned light = 0;light < lights;++light) {
for (unsigned i = 0;i < 6;++i) {
GLenum const face[6] = {GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z};
const glm::vec3 dir[6] = {glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(-1.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(0.0f, -1.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f),
glm::vec3(0.0f, 0.0f, -1.0f)};
const glm::vec3 up[6] = {glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(0.0f, -1.0f, 0.0f),
glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(-1.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(0.0f, -1.0f, 0.0f)};
shadowMaps[light].bind();
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
face[i], shadowMaps[light].getID(), 0);
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glm::mat4 view = glm::lookAt(lightPos[light],
lightPos[light]+dir[i],
up[i]);
glUniformMatrix4fv(prog.getUniformLocation("view_matrix"), 1, GL_FALSE,
glm::value_ptr(view));
glm::mat4 model = glm::translate(glm::vec3(0.5f, 0.5f, -0.5f)) *
glm::rotate(SDL_GetTicks()*0.001f, glm::vec3(1.0f, 0.0f, 0.0f)) *
glm::translate(glm::vec3(-0.5f, -0.5f, 0.5f));
glUniformMatrix4fv(shadowProg.getUniformLocation("model_matrix"), 1, GL_FALSE,
glm::value_ptr(model));
box.draw();
model = glm::translate(glm::vec3(2.0f, -2.5f, 0.0f)) *
glm::rotate(0.35f, glm::vec3(0.0f, 1.0f, 0.0f));
glUniformMatrix4fv(shadowProg.getUniformLocation("model_matrix"), 1, GL_FALSE,
glm::value_ptr(model));
plane.draw();
model = glm::translate(glm::vec3(-2.0f, 0.0f, 0.0f));
glUniformMatrix4fv(shadowProg.getUniformLocation("model_matrix"), 1, GL_FALSE,
glm::value_ptr(model));
pyramid.draw();
}
}
GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, UnusedMask());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(origVP[0], origVP[1], origVP[2], origVP[3]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glDisable(GL_POLYGON_OFFSET_POINT);
glActiveTexture(GL_TEXTURE2);
shadowMaps[1].bind();
glActiveTexture(GL_TEXTURE1);
shadowMaps[0].bind();
glActiveTexture(GL_TEXTURE0);
glm::mat4 model = glm::translate(glm::vec3(0.5f, 0.5f, -0.5f)) *
glm::rotate(SDL_GetTicks()*0.001f, glm::vec3(1.0f, 0.0f, 0.0f)) *
glm::translate(glm::vec3(-0.5f, -0.5f, 0.5f));
cubeTex.bind();
prog.use();
glUniformMatrix4fv(prog.getUniformLocation("model_matrix"), 1, GL_FALSE,
glm::value_ptr(model));
// Shadow maps must be rendered before real drawing can begin
glClientWaitSync(fence, SyncObjectMask(), 0xffffffffu);
glDeleteSync(fence);
box.draw();
whiteTex.bind();
model = glm::translate(glm::vec3(2.0f, -2.5f, 0.0f)) *
glm::rotate(0.35f, glm::vec3(0.0f, 1.0f, 0.0f));
glUniformMatrix4fv(prog.getUniformLocation("model_matrix"), 1, GL_FALSE,
glm::value_ptr(model));
plane.draw();
redTex.bind();
model = glm::translate(glm::vec3(-2.0f, 0.0f, 0.0f));
glUniformMatrix4fv(prog.getUniformLocation("model_matrix"), 1, GL_FALSE,
glm::value_ptr(model));
pyramid.draw();
auto now = SDL_GetTicks();
auto elapsed = now - last;
last = now;
if (fpsTime+elapsed > 1000) {
fpsText.setText(std::to_string(fpsCount + 1) + " FPS");
fpsCount = 0;
fpsTime = 0;
if(countdown > 0) {
--countdown;
if (countdown > 0)
xmlButton.setText(std::to_string(countdown));
else
xmlButton.setText("Do stuff!");
}
} else {
++fpsCount;
fpsTime += elapsed;
}
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
ovlProg.use();
fpsText.renderToGL();
layout->renderToGL();
gui->renderToGL();
glDisable(GL_BLEND);
SDL_GL_SwapWindow(window);
}
}catch(Exception &ex) {
std::printf("%s\n", ex.toString().c_str());
retcode = 1;
}
SDL_GL_DeleteContext(glcontext);
SDL_DestroyWindow(window);
FontProvider::getInstance().cleanup();
ImageProvider::getInstance().cleanup();
// Clean up
TTF_Quit();
IMG_Quit();
SDL_Quit();
return retcode;
}