338 lines
9.7 KiB
C++
338 lines
9.7 KiB
C++
/*
|
||
* Copyright <20> 2012-2013 Graham Sellers
|
||
*
|
||
* This code is part of the OpenGL SuperBible, 6th Edition.
|
||
*
|
||
* 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 (including the next
|
||
* paragraph) 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.
|
||
*/
|
||
|
||
#ifndef __SB7_H__
|
||
#define __SB7_H__
|
||
|
||
#ifdef WIN32
|
||
#pragma once
|
||
#define _CRT_SECURE_NO_WARNINGS 1
|
||
|
||
#define WIN32_LEAN_AND_MEAN 1
|
||
#include <Windows.h>
|
||
#else
|
||
#include <unistd.h>
|
||
#define Sleep(t) sleep(t)
|
||
#endif
|
||
|
||
#include "GL/gl3w.h"
|
||
|
||
#define GLFW_NO_GLU 1
|
||
#define GLFW_INCLUDE_GLCOREARB 1
|
||
|
||
#include "GLFW/glfw3.h"
|
||
|
||
#include "sb7ext.h"
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <math.h>
|
||
#include <iostream>
|
||
|
||
namespace sb7
|
||
{
|
||
|
||
class application {
|
||
private:
|
||
static void APIENTRY debug_callback(GLenum source,
|
||
GLenum type,
|
||
GLuint id,
|
||
GLenum severity,
|
||
GLsizei length,
|
||
const GLchar *message,
|
||
GLvoid *userParam);
|
||
|
||
public:
|
||
application() {}
|
||
|
||
virtual ~application() {}
|
||
|
||
virtual void run(sb7::application *the_app) {
|
||
bool running = true;
|
||
app = the_app;
|
||
|
||
if (!glfwInit()) {
|
||
fprintf(stderr, "Failed to initialize GLFW\n");
|
||
return;
|
||
}
|
||
|
||
init();
|
||
|
||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, info.majorVersion);
|
||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, info.minorVersion);
|
||
|
||
|
||
#ifndef _DEBUG
|
||
if (info.flags.debug)
|
||
#endif /* _DEBUG */
|
||
{
|
||
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
|
||
}
|
||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
|
||
if (info.flags.robust) {
|
||
glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS, GLFW_LOSE_CONTEXT_ON_RESET);
|
||
}
|
||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||
glfwWindowHint(GLFW_SAMPLES, info.samples);
|
||
glfwWindowHint(GLFW_STEREO, info.flags.stereo ? GL_TRUE : GL_FALSE);
|
||
// if (info.flags.fullscreen)
|
||
// {
|
||
// if (info.windowWidth == 0 || info.windowHeight == 0)
|
||
// {
|
||
// GLFWvidmode mode;
|
||
// glfwGetDesktopMode(&mode);
|
||
// info.windowWidth = mode.Width;
|
||
// info.windowHeight = mode.Height;
|
||
// }
|
||
//
|
||
// glfwOpenWindow(info.windowWidth, info.windowHeight, 8, 8, 8, 0, 32, 0, GLFW_FULLSCREEN);
|
||
// glfwSwapInterval((int)info.flags.vsync);
|
||
// }
|
||
// else
|
||
{
|
||
window = glfwCreateWindow(info.windowWidth, info.windowHeight, info.title,
|
||
info.flags.fullscreen ? glfwGetPrimaryMonitor() : NULL, NULL);
|
||
if (!window) {
|
||
fprintf(stderr, "Failed to open window\n");
|
||
return;
|
||
}
|
||
}
|
||
|
||
glfwMakeContextCurrent(window);
|
||
|
||
glfwSetWindowSizeCallback(window, glfw_onResize);
|
||
glfwSetKeyCallback(window, glfw_onKey);
|
||
glfwSetMouseButtonCallback(window, glfw_onMouseButton);
|
||
glfwSetCursorPosCallback(window, glfw_onMouseMove);
|
||
glfwSetScrollCallback(window, glfw_onMouseWheel);
|
||
glfwSetErrorCallback(glfw_onError);
|
||
if (!info.flags.cursor) {
|
||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||
}
|
||
|
||
// info.flags.stereo = (glfwGetWindowParam(GLFW_STEREO) ? 1 : 0);
|
||
|
||
gl3wInit();
|
||
|
||
#ifdef _DEBUG
|
||
fprintf(stderr, "VENDOR: %s\n", (char *)glGetString(GL_VENDOR));
|
||
fprintf(stderr, "VERSION: %s\n", (char *)glGetString(GL_VERSION));
|
||
fprintf(stderr, "RENDERER: %s\n", (char *)glGetString(GL_RENDERER));
|
||
#endif
|
||
|
||
if (info.flags.debug) {
|
||
if (gl3wIsSupported(4, 3)) {
|
||
glDebugMessageCallback((GLDEBUGPROC) debug_callback, this);
|
||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||
} else if (sb6IsExtensionSupported("GL_ARB_debug_output")) {
|
||
glDebugMessageCallbackARB((GLDEBUGPROC) debug_callback, this);
|
||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
||
}
|
||
}
|
||
|
||
startup();
|
||
|
||
do {
|
||
render(glfwGetTime());
|
||
|
||
glfwSwapBuffers(window);
|
||
glfwPollEvents();
|
||
|
||
running &= (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_RELEASE);
|
||
running &= (glfwWindowShouldClose(window) != GL_TRUE);
|
||
} while (running);
|
||
|
||
shutdown();
|
||
|
||
glfwDestroyWindow(window);
|
||
glfwTerminate();
|
||
}
|
||
|
||
virtual void init() {
|
||
strcpy(info.title, "OpenGL SuperBible Example");
|
||
info.windowWidth = 800;
|
||
info.windowHeight = 600;
|
||
#ifdef __APPLE__
|
||
info.majorVersion = 3;
|
||
info.minorVersion = 2;
|
||
#else
|
||
info.majorVersion = 4;
|
||
info.minorVersion = 3;
|
||
#endif
|
||
info.samples = 0;
|
||
info.flags.all = 0;
|
||
info.flags.cursor = 1;
|
||
#ifdef _DEBUG
|
||
info.flags.debug = 1;
|
||
#endif
|
||
}
|
||
|
||
virtual void startup() {
|
||
|
||
}
|
||
|
||
virtual void render(double currentTime) {
|
||
|
||
}
|
||
|
||
virtual void shutdown() {
|
||
|
||
}
|
||
|
||
void setWindowTitle(const char *title) {
|
||
glfwSetWindowTitle(window, title);
|
||
}
|
||
|
||
virtual void onResize(int w, int h) {
|
||
info.windowWidth = w;
|
||
info.windowHeight = h;
|
||
}
|
||
|
||
virtual void onKey(int key, int action) {
|
||
|
||
}
|
||
|
||
virtual void onMouseButton(int button, int action) {
|
||
|
||
}
|
||
|
||
virtual void onMouseMove(int x, int y) {
|
||
|
||
}
|
||
|
||
virtual void onMouseWheel(int pos) {
|
||
|
||
}
|
||
|
||
virtual void onDebugMessage(GLenum source,
|
||
GLenum type,
|
||
GLuint id,
|
||
GLenum severity,
|
||
GLsizei length,
|
||
const GLchar *message) {
|
||
#ifdef _WIN32
|
||
OutputDebugStringA(message);
|
||
OutputDebugStringA("\n");
|
||
#endif /* _WIN32 */
|
||
}
|
||
|
||
void getMousePosition(int &x, int &y) {
|
||
double dx, dy;
|
||
glfwGetCursorPos(window, &dx, &dy);
|
||
|
||
x = static_cast<int>(floor(dx));
|
||
y = static_cast<int>(floor(dy));
|
||
}
|
||
|
||
public:
|
||
struct APPINFO {
|
||
char title[128];
|
||
int windowWidth;
|
||
int windowHeight;
|
||
int majorVersion;
|
||
int minorVersion;
|
||
int samples;
|
||
union {
|
||
struct {
|
||
unsigned int fullscreen: 1;
|
||
unsigned int vsync: 1;
|
||
unsigned int cursor: 1;
|
||
unsigned int stereo: 1;
|
||
unsigned int debug: 1;
|
||
unsigned int robust: 1;
|
||
};
|
||
unsigned int all;
|
||
} flags;
|
||
};
|
||
|
||
protected:
|
||
APPINFO info;
|
||
static sb7::application *app;
|
||
GLFWwindow *window;
|
||
|
||
static void glfw_onResize(GLFWwindow *window, int w, int h) {
|
||
app->onResize(w, h);
|
||
}
|
||
|
||
static void glfw_onKey(GLFWwindow *window, int key, int scancode, int action, int mods) {
|
||
app->onKey(key, action);
|
||
}
|
||
|
||
static void glfw_onMouseButton(GLFWwindow *window, int button, int action, int mods) {
|
||
app->onMouseButton(button, action);
|
||
}
|
||
|
||
static void glfw_onMouseMove(GLFWwindow *window, double x, double y) {
|
||
app->onMouseMove(static_cast<int>(x), static_cast<int>(y));
|
||
}
|
||
|
||
static void glfw_onMouseWheel(GLFWwindow *window, double xoffset, double yoffset) {
|
||
app->onMouseWheel(static_cast<int>(yoffset));
|
||
}
|
||
|
||
static void glfw_onError(int code, const char* data)
|
||
{
|
||
std::cout << data << std::endl;
|
||
}
|
||
|
||
void setVsync(bool enable)
|
||
{
|
||
info.flags.vsync = enable ? 1 : 0;
|
||
glfwSwapInterval((int)info.flags.vsync);
|
||
}
|
||
};
|
||
|
||
};
|
||
|
||
#if defined _WIN32
|
||
#define DECLARE_MAIN(a) \
|
||
sb7::application *app = 0; \
|
||
int CALLBACK WinMain(HINSTANCE hInstance, \
|
||
HINSTANCE hPrevInstance, \
|
||
LPSTR lpCmdLine, \
|
||
int nCmdShow) \
|
||
{ \
|
||
a *app = new a; \
|
||
app->run(app); \
|
||
delete app; \
|
||
return 0; \
|
||
}
|
||
#elif defined _LINUX || defined __APPLE__
|
||
#define DECLARE_MAIN(a) \
|
||
int main(int argc, const char ** argv) \
|
||
{ \
|
||
a *app = new a; \
|
||
app->run(app); \
|
||
delete app; \
|
||
return 0; \
|
||
}
|
||
#else
|
||
#error Undefined platform!
|
||
#endif
|
||
|
||
#endif /* __SB7_H__ */
|
||
|