half-edge/src/gl_setup.c

400 lines
8.4 KiB
C

/*
* Copyright 2011-2014 hasufell
*
* This file is part of a hasufell project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gl_setup.c
* Operations for setting up SDL and the OpenGL context.
* @brief set up SDL/OpenGL
*/
#include "err.h"
#include "filereader.h"
#include "gl_draw.h"
#include "gl_setup.h"
#include "half_edge.h"
#include <GL/glut.h>
#include <GL/gl.h>
#include <SDL.h>
/*
* static function declaration
*/
static void init_opengl(void);
static bool process_events(SDL_Window *win, SDL_GLContext glctx);
static void reshape(SDL_Window *win);
static bool process_window_events(SDL_Window *win,
SDL_GLContext glctx,
SDL_WindowEvent *win_event);
static bool process_keypress(SDL_KeyboardEvent *key_event);
static void gl_destroy(SDL_Window *win, SDL_GLContext glctx);
/**
* Sets the initial values to start the program.
*/
static void init_opengl(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glViewport(0, 0, 680, 480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(CAMERA_ANGLE,
(GLfloat) 640 / (GLfloat) 480,
NEAR_CLIPPING_PLANE,
FAR_CLIPPING_PLANE);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -5.0);
}
/**
* Processes all sort of Events the SDL system catches.
*
* @param win the SDL window
* @param glctx the OpenGL context
* @return true if the app is still running, false if it should
* terminate
*/
static bool process_events(SDL_Window *win, SDL_GLContext glctx)
{
SDL_Event e;
bool running = true;
while (SDL_PollEvent(&e))
if (e.type == SDL_QUIT) {
running = false;
} else if (e.type == SDL_WINDOWEVENT) {
running = process_window_events(win, glctx, &(e.window));
} else if (e.type == SDL_KEYDOWN) {
running = process_keypress(&(e.key));
}
return running;
}
/**
* Is called whenever the window size changes, so
* the object is reshaped into the new window size.
*
* @param win the SDL window
*/
static void reshape(SDL_Window *win)
{
int w, h;
SDL_GetWindowSize(win, &w, &h);
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(CAMERA_ANGLE,
(GLfloat) w / (GLfloat) h,
NEAR_CLIPPING_PLANE,
FAR_CLIPPING_PLANE);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -5.0);
}
/**
* Processes all sort of window events the SDL system catches.
*
* @param win the SDL window
* @param glctx the OpenGL context
* @param win_event the window event to process
* @return true if the app is still running, false if it should
* terminate
*/
static bool process_window_events(SDL_Window *win,
SDL_GLContext glctx,
SDL_WindowEvent *win_event)
{
bool running = true;
if (win_event->event == SDL_WINDOWEVENT_RESIZED)
reshape(win);
else if (win_event->event == SDL_WINDOWEVENT_CLOSE)
running = false;
return running;
}
/**
* Processes all sort of keyboard events the SDL system catches.
*
* press t to increase the day
*
* press T to decrease the day
*
* press j to increase the year
*
* press J to decrease the year
*
* press b to toggle GL_CULL_FACE
*
* press D to toggle disco mode
*
* press S to toggle shade model between GL_SMOOTH and GL_FLAT
*
* press n to toggle normals
*
* press k to increase length of normals
*
* press l to decrease length of normals
*
* press x to rotate the middle object in x direction
*
* press X to rotate the middle object in -x direction
*
* press y to rotate the middle object in y direction
*
* press Y to rotate the middle object in -y direction
*
* press c to rotate the middle object in z direction
*
* press C to rotate the middle object in -z direction
*
* press w to translate the whole scene in y direction
*
* press s to translate the whole scene in -y direction
*
* press a to translate the whole scene in -x direction
*
* press d to translate the whole scene in x direction
*
* press q to quit
*
* @param key_event the key event to process
* @return true if the app is still running, false if it should
* terminate
*/
static bool process_keypress(SDL_KeyboardEvent *key_event)
{
SDL_Keycode key = key_event->keysym.sym;
SDL_Keymod mod = key_event->keysym.mod;
bool running = true;
switch (key) {
/* case 'b': */
/* if (glIsEnabled(GL_CULL_FACE)) */
/* glDisable(GL_CULL_FACE); */
/* else */
/* glEnable(GL_CULL_FACE); */
/* break; */
case 't':
if (mod & KMOD_SHIFT) {
dayabs -= 15;
} else {
dayabs += 15;
}
break;
case 'j':
if (mod & KMOD_SHIFT) {
yearabs -= 50;
} else {
yearabs += 50;
}
break;
case 'x':
if (mod & KMOD_SHIFT) {
draw_obj(-2, 0, 0, 0);
} else {
draw_obj(2, 0, 0, 0);
}
break;
case 'y':
if (mod & KMOD_SHIFT) {
draw_obj(0, -2, 0, 0);
} else {
draw_obj(0, 2, 0, 0);
}
break;
case 'c':
if (mod & KMOD_SHIFT) {
draw_obj(0, 0, -2, 0);
} else {
draw_obj(0, 0, 2, 0);
}
break;
case 'd':
if (mod & KMOD_SHIFT) {
draw_vertices(obj, true);
} else {
glTranslatef(1.0f, 0.0f, 0.0f);
}
break;
case 's':
if (mod & KMOD_SHIFT) {
if (shademodel) {
glShadeModel(GL_FLAT);
shademodel = false;
} else {
glShadeModel(GL_SMOOTH);
shademodel = true;
}
} else {
glTranslatef(0.0f, -1.0f, 0.0f);
}
break;
case 'b':
if (mod & KMOD_SHIFT) {
draw_obj(0, 0, 0, -0.02);
} else {
draw_obj(0, 0, 0, 0.02);
}
break;
case 'k':
if (mod & KMOD_SHIFT) {
if (ball_speed - 0.2f > 0)
ball_speed -= 0.2f;
} else {
ball_speed += 0.2f;
}
break;
case 'f':
if (mod & KMOD_SHIFT) {
draw_bezier = !draw_bezier;
} else {
draw_frame = !draw_frame;
}
break;
case 'l':
if (mod & KMOD_SHIFT) {
draw_normals(obj, 0.01f);
} else {
draw_normals(obj, -0.01f);
}
break;
case 'w':
glTranslatef(0.0f, 1.0f, 0.0f);
break;
case 'a':
glTranslatef(-1.0f, 0.0f, 0.0f);
break;
case 'n':
show_normals = !show_normals;
break;
case '+':
glTranslatef(0.0f, 0.0f, 1.0f);
break;
case '-':
glTranslatef(0.0f, 0.0f, -1.0f);
break;
case 'q':
running = false;
break;
}
return running;
}
/**
* Destroy the gl session/window.
*/
static void gl_destroy(SDL_Window *win, SDL_GLContext glctx)
{
delete_object(obj);
free(obj);
SDL_GL_DeleteContext(glctx);
SDL_DestroyWindow(win);
SDL_Quit();
}
/**
* Initialize the global obj object.
*
* @param sun the file to parse and build the object from which
* will construct the sun
* @param object the file to parse and build the object from which
* will float around the sun
* @param bez the file to parse and build the object from which
* will define on which curve the object floats around the sun
*/
void init_object(char const * const sun,
char const * const object,
char const * const bez)
{
obj = read_obj_file(sun);
float_obj = read_obj_file(object);
bez_obj = read_obj_file(bez);
if (!obj) {
ABORT("Failed to read object file \"%s\"!", sun);
} else if (!float_obj) {
ABORT("Failed to read object file \"%s\"!", object);
} else if (!bez_obj) {
ABORT("Failed to read object file \"%s\"!", bez);
}
NORMALIZE_OBJECT(obj);
NORMALIZE_OBJECT(float_obj);
NORMALIZE_OBJECT(bez_obj);
}
/**
* Starts the main SDL loop which runs until the user
* ends the program.
*/
void init_sdl_loop(void)
{
SDL_Window *win;
SDL_GLContext glctx;
const int window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
if (SDL_Init(SDL_INIT_VIDEO)) {
fprintf(stderr, "Failed initalizing SDL!\n");
abort();
}
if (!(win = SDL_CreateWindow("Drow Engine", 100, 100, 640, 480,
window_flags))) {
fprintf(stderr, "Failed creating SDL window!\n");
abort();
}
if (!(glctx = SDL_GL_CreateContext(win))) {
fprintf(stderr, "Failed creating OpenGL context!\n");
abort();
}
SDL_GL_SetSwapInterval(1);
init_opengl();
while (1) {
bool running = process_events(win, glctx);
if (!running)
break;
draw_scene();
SDL_GL_SwapWindow(win);
}
gl_destroy(win, glctx);
}