diff --git a/CMakeLists.txt b/CMakeLists.txt index 54558f1..ee80151 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,42 +15,5 @@ set(CMAKE_CXX_STANDARD 14) find_package(OpenGL REQUIRED) find_package(GLUT REQUIRED) -if(NOT ${OPENGL_GLU_FOUND}) - message(FATAL_ERROR "Glu not installed!") -endif() - -add_executable(tests_opengl - src/main.cpp - src/displayers.h - src/displayers.cpp - src/DataHandling/Texture.cpp - src/DataHandling/Texture.h - src/DataHandling/Model3D.cpp - src/DataHandling/Model3D.h - src/Vectors.h - src/InputStatus.cpp - src/InputStatus.h - src/Camera.cpp - src/Camera.h - src/Quaternion.cpp - src/Quaternion.h) - -target_link_directories(tests_opengl PRIVATE - src) - -target_include_directories(tests_opengl PRIVATE - src) - -target_link_libraries(tests_opengl - ${OPENGL_LIBRARIES} - ${GLUT_LIBRARIES}) - -target_include_directories(tests_opengl PRIVATE - ${OPENGL_INCLUDE_DIR} - ${GLUT_INCLUDE_DIR}) - -if (CMAKE_COMPILER_IS_GNUCXX) - target_compile_options(tests_opengl PRIVATE -Wall -Wpedantic -Wextra) -elseif(MSVC) - target_compile_options(tests_opengl PRIVATE /W4) -endif() \ No newline at end of file +add_subdirectory(src) +add_subdirectory(example) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..ce63966 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,19 @@ +add_executable(tests_opengl + main.cpp + displayers.h + displayers.cpp) + +target_link_directories(tests_opengl PRIVATE + ${PROJECT_SOURCE_DIR}/src) + +target_include_directories(tests_opengl PRIVATE + ${PROJECT_SOURCE_DIR}/src) + +target_link_libraries(tests_opengl + ${OPENGL_LIBRARIES} + ${GLUT_LIBRARIES} + engine) + +target_include_directories(tests_opengl PRIVATE + ${OPENGL_INCLUDE_DIR} + ${GLUT_INCLUDE_DIR}) \ No newline at end of file diff --git a/src/displayers.cpp b/example/displayers.cpp similarity index 100% rename from src/displayers.cpp rename to example/displayers.cpp diff --git a/src/displayers.h b/example/displayers.h similarity index 100% rename from src/displayers.h rename to example/displayers.h diff --git a/src/main.cpp b/example/main.cpp similarity index 51% rename from src/main.cpp rename to example/main.cpp index 5c7746f..087dfcc 100644 --- a/src/main.cpp +++ b/example/main.cpp @@ -1,6 +1,7 @@ #include #include +#include "Engine.h" #include "displayers.h" #include "DataHandling/Texture.h" #include "DataHandling/Model3D.h" @@ -8,11 +9,9 @@ #include "Camera.h" volatile unsigned long long int timer_ticks = 0; -static double aspect_ratio; static Texture tree_texture; static Model3D raptor; static Texture raptor_texture; -static Camera camera({10,0,10},{-10,0,-10},{0,1,0}); void manage_inputs() { @@ -37,30 +36,30 @@ void manage_inputs() if (InputStatus::is_special_key_pressed(GLUT_KEY_RIGHT)) { timer_ticks += 5; - camera.translate({0,0,0.1}); + OGLE::camera.local_translate({0, 0, 0.1}); } if (InputStatus::is_special_key_pressed(GLUT_KEY_LEFT)) { timer_ticks -= 5; - camera.translate({0,0,-0.1}); + OGLE::camera.local_translate({0, 0, -0.1}); } if (InputStatus::is_key_pressed(' ')) { - camera.translate({0,0.1,0}); + OGLE::camera.local_translate({0, 0.1, 0}); } if (InputStatus::is_special_key_pressed(GLUT_KEY_PAGE_DOWN)) { - camera.translate({0,-0.1,0}); + OGLE::camera.local_translate({0, -0.1, 0}); } if (InputStatus::is_special_key_pressed(GLUT_KEY_UP)) { - camera.translate({0.1,0,0}); + OGLE::camera.local_translate({0.1, 0, 0}); } if (InputStatus::is_special_key_pressed(GLUT_KEY_DOWN)) { - camera.translate({-0.1,0,0}); + OGLE::camera.local_translate({-0.1, 0, 0}); } // Get mouse delta since last frame @@ -68,7 +67,7 @@ void manage_inputs() mouse_delta = InputStatus::get_mouse_delta(true); if (mouse_delta.x != 0 || mouse_delta.y != 0) { - camera.rotate({0, + OGLE::camera.rotate({0, -mouse_delta.x / InputStatus::mouse_sensitivity.x, -mouse_delta.y / InputStatus::mouse_sensitivity.y}); } @@ -79,16 +78,6 @@ void display() manage_inputs(); float angleY = 1*timer_ticks; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_PROJECTION); - // Prepare view - glLoadIdentity(); - gluPerspective(60,aspect_ratio,0.1,30000); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - camera.look(); display_rotating_pyramid(-5,-2,-5,2,4,angleY); display_rotating_pyramid(5,-2,0,1,5,angleY); @@ -100,17 +89,6 @@ void display() glRotatef(angleY,0,-1,0); raptor.draw_model(); glPopMatrix(); - - glutSwapBuffers(); -} - -void reshape(int new_x, int new_y) -{ - glViewport(0,0,new_x,new_y); - - aspect_ratio = (double)new_x/new_y; - InputStatus::window_size.x = new_x; - InputStatus::window_size.y = new_y; } void update_angle(int value) @@ -121,55 +99,26 @@ void update_angle(int value) int main(int argc, char** argv) { - glutInit(&argc,argv); - // Generate window with GLUT - glutInitDisplayMode(GLUT_RGB| GLUT_DEPTH | GLUT_DOUBLE); - glutCreateWindow("OpenGL custom engine tests"); - glutIgnoreKeyRepeat(true); - glutSetCursor(GLUT_CURSOR_NONE); - - // Init OpenGL - glClearColor(0,0,0,1); - glClearDepth(1.0); - glEnable(GL_DEPTH_TEST); - - // Setup OPenGL to use textures - glEnable(GL_TEXTURE_2D); - glAlphaFunc(GL_GREATER, 0.5); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT/GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT/GL_CLAMP); - glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE); + OGLE::setup(argc,argv,display); // Load and generate tree texture tree_texture.load_rgba_tga("resources/arbre.tga","resources/arbre_masque.tga"); - glGenTextures(1,tree_texture.opengl_id); - // TODO : Put in the Texture class - glBindTexture(GL_TEXTURE_2D,tree_texture.opengl_id[0]); - gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA8,tree_texture.width,tree_texture.height,GL_RGBA,GL_UNSIGNED_BYTE,tree_texture.image_data); // Load and generate raptor texture raptor_texture.load_rgb_tga("resources/RAPTOR.tga"); - glGenTextures(1, raptor_texture.opengl_id); - // TODO : Put in the Texture class - glBindTexture(GL_TEXTURE_2D, raptor_texture.opengl_id[0]); - gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, raptor_texture.width, raptor_texture.height, GL_RGB, GL_UNSIGNED_BYTE, raptor_texture.image_data); - + // Load raptor model raptor.load_ascii_off_file("resources/RAPTOR.off"); raptor.assign_texture(raptor_texture); raptor.set_scaling(0.01,0.01,0.01); raptor.set_rotation(-90,1,0,0); + raptor.prepare_displaylist(); - glViewport(0,0,glutGet(GLUT_WINDOW_WIDTH),glutGet(GLUT_WINDOW_HEIGHT)); - glutDisplayFunc(display); - glutIdleFunc(display); - glutReshapeFunc(reshape); glutTimerFunc(50,update_angle,0); - InputStatus::register_glut_callbacks(); + + OGLE::camera.set_position({10,0,10}); + OGLE::camera.rotate({0,1.5*M_PI_4,0}); // Enters main loop, managed by GLUT glutMainLoop(); diff --git a/resources/RAPTOR.off b/example/resources/RAPTOR.off similarity index 100% rename from resources/RAPTOR.off rename to example/resources/RAPTOR.off diff --git a/resources/RAPTOR.tga b/example/resources/RAPTOR.tga similarity index 100% rename from resources/RAPTOR.tga rename to example/resources/RAPTOR.tga diff --git a/resources/arbre.tga b/example/resources/arbre.tga similarity index 100% rename from resources/arbre.tga rename to example/resources/arbre.tga diff --git a/resources/arbre_masque.tga b/example/resources/arbre_masque.tga similarity index 100% rename from resources/arbre_masque.tga rename to example/resources/arbre_masque.tga diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..5e5e5e1 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,33 @@ +add_library(engine + DataHandling/Texture.cpp + DataHandling/Texture.h + DataHandling/Model3D.cpp + DataHandling/Model3D.h + Math/Vectors.h + Math/Quaternion.cpp + Math/Quaternion.h + InputStatus.cpp + InputStatus.h + Camera.cpp + Camera.h + Engine.h) + +target_include_directories(engine PRIVATE + ${PROJECT_SOURCE_DIR}/src) + +target_link_directories(engine PRIVATE + ${PROJECT_SOURCE_DIR}/src) + +target_link_libraries(engine + ${OPENGL_LIBRARIES} + ${GLUT_LIBRARIES}) + +target_include_directories(engine PRIVATE + ${OPENGL_INCLUDE_DIR} + ${GLUT_INCLUDE_DIR}) + +if (CMAKE_COMPILER_IS_GNUCXX) + target_compile_options(engine PRIVATE -Wall -Wpedantic -Wextra) +elseif(MSVC) + target_compile_options(engine PRIVATE /W4) +endif() diff --git a/src/Camera.cpp b/src/Camera.cpp index f1d66b9..7c0aa16 100644 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -17,7 +17,11 @@ Camera::Camera(const Vec3d& eye_pos, const Vec3d& look_direction, const Vec3d& u compute_base_change(); } -void Camera::translate(const Vec3d& translation) +void Camera::translate(const Vec3d &translation) { + eye = eye + translation; +} + +void Camera::local_translate(const Vec3d& translation) { eye = eye + translation * rotation_quaternion; } @@ -35,7 +39,7 @@ void Camera::rotate(const Vec3d& rotation) gaze = z_rotation * gaze; gaze_up = z_rotation * gaze_up; - Quaternion y_rotation{0,sin(rotation.y),0,cos(rotation.y)}; + Quaternion y_rotation{0,sin(rotation.y/2),0,cos(rotation.y/2)}; y_rotation.normalize(); gaze = y_rotation * gaze; gaze_up = y_rotation * gaze_up; @@ -52,7 +56,22 @@ void Camera::look() void Camera::set_position(const Vec3d& eye_pos) { - gaze = eye_pos; + eye = eye_pos; +} + +const Vec3d& Camera::get_eyepos() const +{ + return eye; +} + +const Vec3d& Camera::get_gaze() const +{ + return gaze; +} + +const Vec3d& Camera::get_gazeup() const +{ + return gaze_up; } void Camera::compute_base_change() diff --git a/src/Camera.h b/src/Camera.h index 61c4089..d05cdc1 100644 --- a/src/Camera.h +++ b/src/Camera.h @@ -8,16 +8,19 @@ #include #include -#include "Quaternion.h" -#include "Vectors.h" +#include "Math/Quaternion.h" +#include "Math/Vectors.h" class Camera { public: Camera(const Vec3d& eye_pos,const Vec3d& look_direction,const Vec3d& up_vector); + /// Translates the camera according to the world axises. + /// \param translation Translation in the world coordinates system. + void translate(const Vec3d& translation); /// Translates the camera relative to its current position and look direction. /// \param translation Translation where x is pointing in the direction of vision. - void translate(const Vec3d& translation); + void local_translate(const Vec3d& translation); /// Rotates the gaze around its local x and z but around global y, relatively to the current orientation. /// This is to provide a coherent movement in regards to mouse movement. /// \param rotation Angles are radians to rotate about each axis. @@ -27,6 +30,10 @@ public: void look(); void set_position(const Vec3d& eye_pos); + + const Vec3d& get_eyepos() const; + const Vec3d& get_gaze() const; + const Vec3d& get_gazeup() const; private: Vec3d eye; Vec3d gaze; diff --git a/src/DataHandling/Model3D.cpp b/src/DataHandling/Model3D.cpp index bc9fafd..638a7d5 100644 --- a/src/DataHandling/Model3D.cpp +++ b/src/DataHandling/Model3D.cpp @@ -5,7 +5,7 @@ #include "Model3D.h" -Model3D::Model3D() : vertex_count(0), face_count(0), texture_count(0), is_textured(false) +Model3D::Model3D() :is_textured(false), vertex_count(0), face_count(0), texture_count(0) {} Model3D::Model3D(const std::string& file_name) : Model3D() @@ -30,10 +30,23 @@ Model3D::~Model3D() delete(face_textures); delete(normals); } + + if (has_displaylist) + { + glDeleteLists(display_list_index,1); + } } void Model3D::draw_model() { + if (has_displaylist) + { + glCallList(display_list_index); + return; // Executing the regular draw calls is unnecessary + } + + // If there is no display list available, draw each triangles and texture them if necessary. + if (is_textured) { glEnable(GL_ALPHA_TEST); @@ -84,6 +97,17 @@ void Model3D::draw_model() } } +void Model3D::prepare_displaylist() +{ + display_list_index = glGenLists(1); + + glNewList(display_list_index,GL_COMPILE); + draw_model(); + glEndList(); + + has_displaylist = true; +} + bool Model3D::load_ascii_off_file(const std::string& file_name) { std::fstream file_stream(file_name, std::ios_base::in); diff --git a/src/DataHandling/Model3D.h b/src/DataHandling/Model3D.h index 94474a5..d160a7a 100644 --- a/src/DataHandling/Model3D.h +++ b/src/DataHandling/Model3D.h @@ -10,7 +10,7 @@ #include #include "GL/glut.h" -#include "Vectors.h" +#include "Math/Vectors.h" #include "Texture.h" class Model3D { @@ -26,9 +26,13 @@ public: void set_scaling(float x_scale, float y_scale, float z_scale); void set_rotation(float angle, float x, float y, float z); + /// Draws the model, using a display list if available. void draw_model(); + /// Sets up an OpenGL display list for the model + void prepare_displaylist(); bool is_textured; + bool has_displaylist = false; private: uint32_t vertex_count; uint32_t face_count; @@ -51,6 +55,8 @@ private: Vec3f scaling{}; Vec3f rotation_axis{}; float rotation_angle{}; + + GLuint display_list_index; }; diff --git a/src/DataHandling/Texture.cpp b/src/DataHandling/Texture.cpp index 003d030..4f64c7b 100644 --- a/src/DataHandling/Texture.cpp +++ b/src/DataHandling/Texture.cpp @@ -73,6 +73,7 @@ bool Texture::load_rgb_tga(const std::string& rgb_filename) { bool return_value = load_tga(rgb_filename,image_data); invert_channels(0,2); + generate_texture(); return return_value; } @@ -117,9 +118,25 @@ bool Texture::load_rgba_tga(const std::string& rgb_filename, const std::string& // Now we have an RGBA image, update color_bits color_bits = 32; + invert_channels(0,2); + generate_texture(); return true; } +void Texture::generate_texture() +{ + glGenTextures(1,opengl_id); + glBindTexture(GL_TEXTURE_2D,opengl_id[0]); + if (color_bits == 24) + { + gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGB8,width,height,GL_RGB,GL_UNSIGNED_BYTE,image_data); + } + else if (color_bits == 32) + { + gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA8,width,height,GL_RGBA,GL_UNSIGNED_BYTE,image_data); + } +} + void Texture::invert_channels(uint8_t first_channel, uint8_t second_channel) { uint8_t increment = color_bits/8; diff --git a/src/DataHandling/Texture.h b/src/DataHandling/Texture.h index d0c791e..0eed6d6 100644 --- a/src/DataHandling/Texture.h +++ b/src/DataHandling/Texture.h @@ -33,6 +33,9 @@ private: /// Load and RGB TGA image file to an array bool load_tga(const std::string& filename, uint8_t*& data_array); + /// Initialize the texture for OpenGL + void generate_texture(); + void invert_channels(uint8_t first_channel,uint8_t second_channel); }; diff --git a/src/Engine.h b/src/Engine.h new file mode 100644 index 0000000..13c7d84 --- /dev/null +++ b/src/Engine.h @@ -0,0 +1,85 @@ +// +// Created by trotFunky on 02/11/2019. +// + +#ifndef TESTS_OPENGL_ENGINE_H +#define TESTS_OPENGL_ENGINE_H + +#include +#include + +#include "InputStatus.h" +#include "Camera.h" + +/// OpenGL Engine +namespace OGLE +{ + /// Display function provided at setup. + void (*custom_display)(); + static double aspect_ratio; + static Camera camera({0,0,0},{1,0,0},{0,1,0}); + + void reshape(int new_x, int new_y) + { + glViewport(0,0,new_x,new_y); + + aspect_ratio = (double)new_x/new_y; + InputStatus::window_size.x = new_x; + InputStatus::window_size.y = new_y; + } + + /// Used for glutDisplay. Wraps the custom_display function with the required OpenGL calls. + void display_wrapper() + { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + // Prepare view + glLoadIdentity(); + gluPerspective(60,OGLE::aspect_ratio,0.1,30000); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + OGLE::camera.look(); + + custom_display(); + + glutSwapBuffers(); + } + + void setup(int& argc, char** argv, void (*display_callback)(), const std::string& window_name = "OpenGL custom engine") + { + glutInit(&argc,argv); + // Generate window with GLUT + glutInitDisplayMode(GLUT_RGB| GLUT_DEPTH | GLUT_DOUBLE); + glutCreateWindow(window_name.c_str()); + glutIgnoreKeyRepeat(true); + glutSetCursor(GLUT_CURSOR_NONE); + + // Init OpenGL + glClearColor(0,0,0,1); + glClearDepth(1.0); + glEnable(GL_DEPTH_TEST); + + // Setup OPenGL to use textures + glEnable(GL_TEXTURE_2D); + glAlphaFunc(GL_GREATER, 0.5); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT/GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT/GL_CLAMP); + glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glViewport(0,0,glutGet(GLUT_WINDOW_WIDTH),glutGet(GLUT_WINDOW_HEIGHT)); + + custom_display = display_callback; + + glutDisplayFunc(display_wrapper); + glutIdleFunc(display_wrapper); + glutReshapeFunc(reshape); + InputStatus::register_glut_callbacks(); + } +} + +#endif //TESTS_OPENGL_ENGINE_H diff --git a/src/InputStatus.h b/src/InputStatus.h index f1db851..ca7059e 100644 --- a/src/InputStatus.h +++ b/src/InputStatus.h @@ -9,7 +9,7 @@ #include #include -#include "Vectors.h" +#include "Math/Vectors.h" /// Handles the key and mouse events from glut and keep their status up to date. diff --git a/src/Quaternion.cpp b/src/Math/Quaternion.cpp similarity index 100% rename from src/Quaternion.cpp rename to src/Math/Quaternion.cpp diff --git a/src/Quaternion.h b/src/Math/Quaternion.h similarity index 100% rename from src/Quaternion.h rename to src/Math/Quaternion.h diff --git a/src/Vectors.h b/src/Math/Vectors.h similarity index 100% rename from src/Vectors.h rename to src/Math/Vectors.h