254 lines
8.2 KiB
C++
254 lines
8.2 KiB
C++
// Copyright (c) 2014 Robert Kooima
|
|
//
|
|
// 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.
|
|
|
|
#ifndef GLDEMONSTRATION_HPP
|
|
#define GLDEMONSTRATION_HPP
|
|
|
|
#include <SDL.h>
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace gl
|
|
{
|
|
class demonstration
|
|
{
|
|
public:
|
|
|
|
/// Initialize an SDL OpenGL window with the given title and size.
|
|
|
|
demonstration(const char *title, int w, int h) :
|
|
width(w),
|
|
height(h),
|
|
running(false),
|
|
sun_rotation(-90, 0),
|
|
drag_sun_rotation(false),
|
|
drag_cam_rotation(false)
|
|
{
|
|
if (SDL_Init(SDL_INIT_VIDEO) == 0)
|
|
{
|
|
int x = SDL_WINDOWPOS_CENTERED;
|
|
int y = SDL_WINDOWPOS_CENTERED;
|
|
int f = SDL_WINDOW_OPENGL;
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
|
|
SDL_GL_CONTEXT_PROFILE_CORE);
|
|
|
|
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, 24);
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
|
|
if ((window = SDL_CreateWindow(title, x, y, w, h, f)))
|
|
{
|
|
context = SDL_GL_CreateContext(window);
|
|
running = true;
|
|
#ifdef GLEW_VERSION
|
|
glewExperimental = GL_TRUE;
|
|
glewInit();
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Dispatch SDL events.
|
|
|
|
void run()
|
|
{
|
|
SDL_Event e;
|
|
|
|
while (running)
|
|
{
|
|
while (SDL_PollEvent(&e))
|
|
switch (e.type)
|
|
{
|
|
case SDL_MOUSEBUTTONDOWN: button(e.button.button, true); break;
|
|
case SDL_MOUSEBUTTONUP: button(e.button.button, false); break;
|
|
case SDL_MOUSEMOTION: motion(e.motion.x, e.motion.y); break;
|
|
case SDL_KEYDOWN: if (e.key.repeat == 0) key(e.key.keysym.scancode, true); break;
|
|
case SDL_KEYUP: if (e.key.repeat == 0) key(e.key.keysym.scancode, false); break;
|
|
case SDL_QUIT: running = false; break;
|
|
}
|
|
|
|
step();
|
|
draw();
|
|
SDL_GL_SwapWindow(window);
|
|
}
|
|
}
|
|
|
|
/// Finalize the SDL OpenGL window.
|
|
|
|
virtual ~demonstration()
|
|
{
|
|
if (context) SDL_GL_DeleteContext(context);
|
|
if (window) SDL_DestroyWindow(window);
|
|
}
|
|
|
|
protected:
|
|
|
|
/// Draw the scene.
|
|
|
|
virtual void draw()
|
|
{
|
|
}
|
|
|
|
/// Animate.
|
|
|
|
virtual void step()
|
|
{
|
|
mat3 N = normal(inverse(view()));
|
|
cam_position = cam_position + N * cam_velocity / 30.0;
|
|
}
|
|
|
|
/// Handle a mouse button press or release.
|
|
|
|
virtual void button(int button, bool down)
|
|
{
|
|
switch (button)
|
|
{
|
|
case SDL_BUTTON_LEFT:
|
|
drag_cam_rotation = down;
|
|
prev_cam_rotation = cam_rotation;
|
|
break;
|
|
|
|
case SDL_BUTTON_RIGHT:
|
|
drag_sun_rotation = down;
|
|
prev_sun_rotation = sun_rotation;
|
|
break;
|
|
}
|
|
prev_x = curr_x;
|
|
prev_y = curr_y;
|
|
}
|
|
|
|
/// Handle mouse pointer motion.
|
|
|
|
virtual void motion(int x, int y)
|
|
{
|
|
GLfloat dy = GLfloat(y - prev_y) / height;
|
|
GLfloat dx = GLfloat(x - prev_x) / height;
|
|
|
|
if (drag_cam_rotation)
|
|
{
|
|
cam_rotation[0] = prev_cam_rotation[0] + 90.0 * dy;
|
|
cam_rotation[1] = prev_cam_rotation[1] + 180.0 * dx;
|
|
|
|
if (cam_rotation[0] > 90) cam_rotation[0] = 90;
|
|
if (cam_rotation[0] < -90) cam_rotation[0] = -90;
|
|
if (cam_rotation[1] > 180) cam_rotation[1] -= 360;
|
|
if (cam_rotation[1] < -180) cam_rotation[1] += 360;
|
|
}
|
|
if (drag_sun_rotation)
|
|
{
|
|
sun_rotation[0] = prev_sun_rotation[0] + 90.0 * dy;
|
|
sun_rotation[1] = prev_sun_rotation[1] + 180.0 * dx;
|
|
|
|
if (sun_rotation[0] > 90) sun_rotation[0] = 90;
|
|
if (sun_rotation[0] < -90) sun_rotation[0] = -90;
|
|
if (sun_rotation[1] > 180) sun_rotation[1] -= 360;
|
|
if (sun_rotation[1] < -180) sun_rotation[1] += 360;
|
|
}
|
|
curr_x = x;
|
|
curr_y = y;
|
|
}
|
|
|
|
/// Handle a key press or release.
|
|
|
|
virtual void key(int key, bool down)
|
|
{
|
|
if (down)
|
|
switch (key)
|
|
{
|
|
case SDL_SCANCODE_A: cam_velocity[0] -= 1.0; break;
|
|
case SDL_SCANCODE_D: cam_velocity[0] += 1.0; break;
|
|
case SDL_SCANCODE_C: cam_velocity[1] -= 1.0; break;
|
|
case SDL_SCANCODE_SPACE: cam_velocity[1] += 1.0; break;
|
|
case SDL_SCANCODE_W: cam_velocity[2] -= 1.0; break;
|
|
case SDL_SCANCODE_S: cam_velocity[2] += 1.0; break;
|
|
}
|
|
else
|
|
switch (key)
|
|
{
|
|
case SDL_SCANCODE_A: cam_velocity[0] += 1.0; break;
|
|
case SDL_SCANCODE_D: cam_velocity[0] -= 1.0; break;
|
|
case SDL_SCANCODE_C: cam_velocity[1] += 1.0; break;
|
|
case SDL_SCANCODE_SPACE: cam_velocity[1] -= 1.0; break;
|
|
case SDL_SCANCODE_W: cam_velocity[2] += 1.0; break;
|
|
case SDL_SCANCODE_S: cam_velocity[2] -= 1.0; break;
|
|
}
|
|
}
|
|
|
|
/// Return the current projection matrix.
|
|
|
|
mat4 projection(GLfloat n=0.10f, GLfloat f=100.f) const
|
|
{
|
|
const GLfloat a = GLfloat(width) / GLfloat(height);
|
|
return perspective(to_radians(60.f), a, n, f);
|
|
}
|
|
|
|
/// Return the current view matrix.
|
|
|
|
mat4 view() const
|
|
{
|
|
return xrotation(to_radians(cam_rotation[0]))
|
|
* yrotation(to_radians(cam_rotation[1]))
|
|
* translation(-cam_position);
|
|
}
|
|
|
|
/// Return the current light vector.
|
|
|
|
vec4 light() const
|
|
{
|
|
return xrotation(to_radians(sun_rotation[0]))
|
|
* yrotation(to_radians(sun_rotation[1])) * vec4(0, 0, 1, 0);
|
|
}
|
|
|
|
protected:
|
|
|
|
int width;
|
|
int height;
|
|
bool running;
|
|
|
|
vec3 cam_position;
|
|
vec3 cam_velocity;
|
|
vec2 cam_rotation;
|
|
vec2 sun_rotation;
|
|
|
|
private:
|
|
|
|
bool drag_sun_rotation;
|
|
bool drag_cam_rotation;
|
|
vec2 prev_sun_rotation;
|
|
vec2 prev_cam_rotation;
|
|
int prev_x;
|
|
int prev_y;
|
|
int curr_x;
|
|
int curr_y;
|
|
|
|
SDL_Window *window;
|
|
SDL_GLContext context;
|
|
};
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
#endif
|