#include "scene.hpp" #include "tree.hpp" #include "interpolation.hpp" #include "ball.hpp" #include "bird.hpp" #include "bat.hpp" #include "dragon.hpp" #include "terrain.hpp" #include "projectile.hpp" #include "sapin.hpp" #include "settings.hpp" using namespace cgp; std::vector<vec3> tree_position; std::vector<vec3> grass_position; void scene_structure::initialize() { //CAMERA camera_control.initialize(inputs, window); // Give access to the inputs and window global state to the camera controler //Orbit camera //camera_control.set_rotation_axis_z(); //camera_control.look_at({ 20.0f,15.0f,15.0f }, {0,0,0}); //First person camera camera_control.camera_model.position_camera = { 0,0,evaluate_terrain_height(0,0)+10}; //camera_control.camera_model.position_camera = { 0,-5,0}; camera_control.camera_model.set_rotation_axis({ 0,0,1 }); global_frame.initialize_data_on_gpu(mesh_primitive_frame()); //SKYBOX //skybox_debug.png for debugging image_structure image_skybox_template = image_load_file("assets/skybox2.jpg"); std::vector<image_structure> image_grid = image_split_grid(image_skybox_template, 4, 3); image_structure image_skybox_template2 = image_load_file("assets/skyboxNight.jpeg"); std::vector<image_structure> image_grid2 = image_split_grid(image_skybox_template2, 4, 3); skybox.initialize_data_on_gpu(); //x neg, x pos, y neg, y pos, z neg, z pos skybox.texture.initialize_cubemap_on_gpu(image_grid[7].rotate_90_degrees_counterclockwise(), image_grid[1].rotate_90_degrees_clockwise(), image_grid[4].rotate_90_degrees_clockwise().rotate_90_degrees_clockwise(), image_grid[10], image_grid[3], image_grid[5].rotate_90_degrees_clockwise().rotate_90_degrees_clockwise()); skybox.texture2.initialize_cubemap_on_gpu(image_grid2[7].rotate_90_degrees_counterclockwise(), image_grid2[1].rotate_90_degrees_clockwise(), image_grid2[4].rotate_90_degrees_clockwise().rotate_90_degrees_clockwise(), image_grid2[10], image_grid2[3], image_grid2[5].rotate_90_degrees_clockwise().rotate_90_degrees_clockwise()); //TERRAIN int N_terrain_samples = 500; mesh const terrain_mesh = create_terrain_mesh(N_terrain_samples); terrain.initialize_data_on_gpu(terrain_mesh); // terrain.material.color = { 0.6f,0.85f,0.5f }; terrain de couleur de base verte terrain.material.color = { 1,1,1 }; terrain.material.phong.specular = 0.0f; // non-specular terrain material terrain.shader.load(project::path + "shaders/mesh_multi_texture/mesh_multi_texture.vert.glsl", project::path + "shaders/mesh_multi_texture/mesh_multi_texture.frag.glsl"); terrain.texture.load_and_initialize_texture_2d_on_gpu(project::path + "assets/grass.jpg", GL_REPEAT, GL_MIRRORED_REPEAT); terrain.supplementary_texture["image_texture_rock"].load_and_initialize_texture_2d_on_gpu(project::path + "assets/rocks3.jpg", GL_REPEAT, GL_MIRRORED_REPEAT); terrain.supplementary_texture["image_texture_snow"].load_and_initialize_texture_2d_on_gpu(project::path + "assets/snow.jpg", GL_REPEAT, GL_MIRRORED_REPEAT); //OBJECTS int r = 1; int h = 5; mesh cyl_mesh = create_cylinder_mesh(r, h); cyl.initialize_data_on_gpu(cyl_mesh); cyl.material.color = { 0.58f,0.294f,0.0f }; cyl.material.phong.specular = 0.0f; r = 3; h = 2; int z = 3; mesh cone_mesh = create_cone_mesh(r, h, z); cone.initialize_data_on_gpu(cone_mesh); cone.material.color = { 0.0f,0.8f,0.0f }; cone.material.phong.specular = 0.0f; mesh tree_mesh = create_tree(); tree.initialize_data_on_gpu(tree_mesh); float x = 1.0; float y = 2.0; tree.model.translation = { x, y, evaluate_terrain_height(x,y) }; tree_position = generate_positions_on_terrain(num_trees()); grass_position = generate_positions_on_terrain(num_grass()); mesh quadrangle_mesh; quadrangle_mesh.position = { {0,0,0},{1, 0, 0}, {1,0,1}, {0, 0,1} }; quadrangle_mesh.uv = { {0,0},{1,0}, {1,1}, {0,1} }; quadrangle_mesh.connectivity = { {0,1,2}, {0,2,3} }; quadrangle_mesh.fill_empty_field(); // (fill with some default values the other buffers (colors, normals) that we didn't filled before) // Convert the mesh structure into a mesh_drawable structure grass.initialize_data_on_gpu(quadrangle_mesh); grass.texture.load_and_initialize_texture_2d_on_gpu(project::path + "assets/grass.png", GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER); chain1.initialize(); bouncing.initialize(20); //10 balls bats.initialize_bats(); dragons.initialize_dragons(); vec3 bat_pos1 = { 0,0,evaluate_terrain_height(0,0) + 20 }; float bat_size1 = 0.2f; numarray<vec3> bat_keypos1 = { {-1,1,0}, {0,1,0}, {1,1,0}, {1,2,0}, {2,2,0}, {2,2,1}, {2,0,1.5}, {1.5,-1,1}, {1.5,-1,0}, {1,-1,0}, {0,-0.5,0}, {-1,1,0} }; numarray<float> bat_keytimes1 = { 0.0f, 1.0f, 2.0f, 2.5f, 3.0f, 3.5f, 3.75f, 4.5f, 5.0f, 6.0f, 7.0f, 8.0f }; bats.add_bat(bat_pos1, bat_size1, bat_keypos1, bat_keytimes1); vec3 bat_pos2 = { 5,5,evaluate_terrain_height(0,0) + 10 }; float bat_size2 = 0.5f; numarray<vec3> bat_keypos2 = { {-1,1,0}, {0,1,0}, {1,1,0}, {1,2,0}, {2,2,0}, {2,2,1}, {2,0,1.5}, {1.5,-1,1}, {1.5,-1,0}, {1,-1,0}, {0,-0.5,0}, {-1,1,0} }; numarray<float> bat_keytimes2 = { 0.0f, 1.0f, 2.0f, 2.5f, 3.0f, 3.5f, 3.75f, 4.5f, 5.0f, 6.0f, 7.0f, 8.0f }; dragons.add_dragon(bat_pos2, bat_size2, bat_keypos2, bat_keytimes2); projectiles.initialize(); sapin1.initialize_sapin(); sapin1.sapin["Trunk"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0 }, Pi / 2); hitbox_sphere.initialize_data_on_gpu(mesh_primitive_sphere(1)); } void scene_structure::display_frame() { // Update the current time timer.update(); // Must be called before drawing the other shapes and without writing in the Depth Buffer glDepthMask(GL_FALSE); // disable depth-buffer writing draw(skybox, timer.t, environment); glDepthMask(GL_TRUE); // re-activate depth-buffer write //Walking on ground if (!gui.fly) { vec3 eye_level = camera_control.camera_model.position_camera; eye_level[2] = evaluate_terrain_height(eye_level[0], eye_level[1]) + 0.75; camera_control.camera_model.position_camera = eye_level; } // Set the light to the current position of the camera environment.light = camera_control.camera_model.position(); if (gui.display_frame) draw(global_frame, environment); draw(terrain, environment); if (gui.display_wireframe) draw_wireframe(terrain, environment); //Draw trees if close enough for (int i = 0; i < num_trees(); i++) { if (norm(tree_position[i]-camera_control.camera_model.position_camera) < 75 ) { sapin1.sapin["Trunk"].transform_local.translation = tree_position[i]; sapin1.sapin.update_local_to_global_coordinates(); draw(sapin1.sapin, environment); } } display_ball(); display_bats(); display_dragons(); display_semiTransparent(); //Important to draw grass before projectiles (otherwise you see them through projectiles) display_projectiles(); if (gui.display_wireframe) draw_wireframe(tree, environment); } void scene_structure::display_bats() { bats.update_mvt(); for (int i = 0; i < bats.N; i++) { if (!bats.bats_prop[i].isdead) { //Wing animation bats.bat_mesh["Bat wing left1"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0 }, 0.5 * cos(5 * bats.bats_prop[i].timer_mvt.t)); bats.bat_mesh["Bat wing right1"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0 }, -0.5 * cos(5 * bats.bats_prop[i].timer_mvt.t)); //Rescale bats.bat_mesh["Bat base"].drawable.model.scaling = bats.bats_prop[i].size; bats.bat_mesh["Bat wing left1"].drawable.model.scaling = bats.bats_prop[i].size; bats.bat_mesh["Bat wing right1"].drawable.model.scaling = bats.bats_prop[i].size; //Make sure wings are at the right distance bats.bat_mesh["Bat wing left1"].transform_local.translation = { -0.25f * bats.bats_prop[i].size, 0, 0 }; bats.bat_mesh["Bat wing right1"].transform_local.translation = { 0.25f * bats.bats_prop[i].size, 0, 0 }; //Orientation and position of the bat along the path rotation_transform rot = rotation_transform::from_vector_transform({ 0,-1,0 }, normalize(bats.bats_prop[i].pos_futur - bats.bats_prop[i].pos)); bats.bat_mesh["Bat base"].transform_local.rotation = rot; bats.bat_mesh["Bat base"].transform_local.translation = bats.bats_prop[i].pos; bats.bat_mesh.update_local_to_global_coordinates(); draw(bats.bat_mesh, environment); if (gui.display_wireframe) { draw_wireframe(bats.bat_mesh, environment); } if (gui.display_hitbox) { display_hitbox(bats.bats_prop[i].bat_hitbox, bats.bats_prop[i].pos, rot); } } } } void scene_structure::display_dragons() { dragons.update_mvt(); for (int i = 0; i < bats.N; i++) { if (!dragons.dragons_prop[i].isdead) { //Wing animation dragons.dragon_mesh["Dragon wing left"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0.5 }, 0.5 * cos(5 * dragons.dragons_prop[i].timer_mvt.t)); dragons.dragon_mesh["Dragon wing right"].transform_local.rotation = rotation_transform::from_axis_angle({ 1,0,0.5 }, -0.5 * cos(5 * dragons.dragons_prop[i].timer_mvt.t)); //Mouth animation dragons.dragon_mesh["Dragon mouth"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0 }, 0.05 * cos(dragons.dragons_prop[i].timer_mvt.t)); //Tail animation dragons.dragon_mesh["Dragon tailmiddle"].transform_local.rotation = rotation_transform::from_axis_angle({ 0,1,0.5 }, 0.05 * cos(2 * dragons.dragons_prop[i].timer_mvt.t)); dragons.dragon_mesh["Dragon tailend"].transform_local.rotation = rotation_transform::from_axis_angle({ 0.5,1,0.5 }, -0.01 * cos(2 * dragons.dragons_prop[i].timer_mvt.t)); //Rescale dragons.dragon_mesh["Dragon base"].drawable.model.scaling = dragons.dragons_prop[i].size; dragons.dragon_mesh["Dragon wing left"].drawable.model.scaling = dragons.dragons_prop[i].size; dragons.dragon_mesh["Dragon wing right"].drawable.model.scaling = dragons.dragons_prop[i].size; dragons.dragon_mesh["Dragon mouth"].drawable.model.scaling = dragons.dragons_prop[i].size; dragons.dragon_mesh["Dragon tailmiddle"].drawable.model.scaling = dragons.dragons_prop[i].size; dragons.dragon_mesh["Dragon tailend"].drawable.model.scaling = dragons.dragons_prop[i].size; //Make sure wings are at the right distance dragons.dragon_mesh["Dragon wing left"].transform_local.translation = { 0, -0.3f * dragons.dragons_prop[i].size, 0 }; dragons.dragon_mesh["Dragon wing right"].transform_local.translation = { 0, 0.3f * dragons.dragons_prop[i].size, 0 }; //Orientation and position of the bat along the path rotation_transform rot = rotation_transform::from_vector_transform({ 1,0,0 }, normalize(dragons.dragons_prop[i].pos_futur - dragons.dragons_prop[i].pos)); dragons.dragon_mesh["Dragon base"].transform_local.rotation = rot; dragons.dragon_mesh["Dragon base"].transform_local.translation = dragons.dragons_prop[i].pos; dragons.dragon_mesh.update_local_to_global_coordinates(); draw(dragons.dragon_mesh, environment); if (gui.display_wireframe) { draw_wireframe(dragons.dragon_mesh, environment); } if (gui.display_hitbox) { display_hitbox(dragons.dragons_prop[i].dragon_hitbox, dragons.dragons_prop[i].pos, rot); } } } } void scene_structure::display_hitbox(hitbox H, vec3 shift, rotation_transform rot) { for (int i = 0; i < H.N; i++) { hitbox_sphere.model.scaling = H.r[i]; hitbox_sphere.model.translation = rot * H.center[i] + shift; draw_wireframe(hitbox_sphere, environment); } } void scene_structure::display_semiTransparent() { // Enable use of alpha component as color blending for transparent elements // alpha = current_color.alpha // new color = previous_color * alpha + current_color * (1-alpha) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Disable depth buffer writing // - Transparent elements cannot use depth buffer // - They are supposed to be display from furest to nearest elements glDepthMask(false); auto const& camera = camera_control.camera_model; // Re-orient the grass shape to always face the camera direction vec3 const right = camera.right(); // Rotation such that the grass follows the right-vector of the camera, while pointing toward the z-direction for (int i = 0; i < num_grass(); i++) { grass.model.translation = grass_position[i]; rotation_transform R = rotation_transform::from_frame_transform({ 1,0,0 }, { 0,0,1}, right, {0,0,1}); grass.model.rotation = R; draw(grass, environment); } // Don't forget to re-activate the depth-buffer write glDepthMask(true); glDisable(GL_BLEND); } void scene_structure::draw_segment(vec3 const& a, vec3 const& b) { chain1.segment.vbo_position.update(numarray<vec3>{ a, b }); draw(chain1.segment, environment); } void scene_structure::display_chain(vec3 bird_pos) { // Update the current time timer_chain.update(); chain1.simulation_step(timer_chain.scale * 0.01f, bird_pos); for (int i = 0; i < chain1.n; i++) { chain1.particle_sphere.model.translation = chain1.p[i]; chain1.particle_sphere.material.color = { (float)i / chain1.n,(float)i / chain1.n,0 }; draw(chain1.particle_sphere, environment); } for (int i = 0; i < chain1.n - 1; i++) { draw_segment(chain1.p[i], chain1.p[i + 1]); } } void scene_structure::display_gui() { ImGui::Checkbox("Frame", &gui.display_frame); ImGui::Checkbox("Wireframe", &gui.display_wireframe); ImGui::Checkbox("Hitbox", &gui.display_hitbox); ImGui::Checkbox("Fly", &gui.fly); //ImGui::SliderFloat("Time", &timer_mvt.t, timer_mvt.t_min, timer_mvt.t_max); //ImGui::SliderFloat("Time scale", &timer_mvt.scale, 0.0f, 2.0f); ImGui::SliderFloat("K", &gui.k, 0.0f, 10.0f); ImGui::SliderFloat("Speed", &gui.speed, 0.0f, 10.0f); // Display the GUI associated to the key position //keyframe.display_gui(); } void scene_structure::display_ball() { bouncing.simulate(timer.scale * 0.01f); for (int i = 0; i < bouncing.N; i++) { bouncing.mesh.model.translation = bouncing.pos[i]; bouncing.mesh.material.color = bouncing.color[i]; draw(bouncing.mesh, environment); } } void scene_structure::display_projectiles() { vec3 const right = camera_control.camera_model.right(); rotation_transform R = rotation_transform::from_frame_transform({ cos(ball_turn_speed * timer.t + 90),sin(ball_turn_speed * timer.t + 90),0 }, { 0,0,1 }, right, { 0,0,1 }); rotation_transform R2 = rotation_transform::from_frame_transform({ cos(ball_turn_speed * timer.t -90), sin(ball_turn_speed * timer.t - 90),0 }, { 0,0,1 }, right, { 0,0,1 }); projectiles.simulate(timer.scale * 0.03f); for (int i = 0; i < projectiles.N; i++) { for (int j = 0; j < bats.N; j++) { if (bats.bats_prop[j].bat_hitbox.is_in_hitbox(projectiles.projectiles_prop[i].pos, bats.bats_prop[j].pos)) bats.bats_prop[j].isdead = true; if (dragons.dragons_prop[j].dragon_hitbox.is_in_hitbox(projectiles.projectiles_prop[i].pos, dragons.dragons_prop[j].pos)) dragons.dragons_prop[j].isdead = true; } projectiles.mesh.model.translation = projectiles.projectiles_prop[i].pos; projectiles.mesh.material.color = projectiles.projectiles_prop[i].color; draw(projectiles.mesh, environment); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); if (projectiles.projectiles_prop[i].elemental_type == projectile::projectile_type::fire) { if (fmod(timer.t, ball_reset_speed) > 0.1) projectiles.projectiles_prop[i].change_animation = true; if (fmod(timer.t, ball_reset_speed) < 0.1 && projectiles.projectiles_prop[i].change_animation) { projectiles.projectiles_prop[i].change_animation = false; projectiles.fireball.texture.update(projectiles.fire_grid[std::rand()%12]); } projectiles.fireball.model.translation = projectiles.projectiles_prop[i].pos; draw(projectiles.fireball, environment); projectiles.fireball.model.rotation = R; draw(projectiles.fireball, environment); projectiles.fireball.model.rotation = R2; draw(projectiles.fireball, environment); } else if (projectiles.projectiles_prop[i].elemental_type == projectile::projectile_type::water) { if (fmod(timer.t, ball_reset_speed) > 0.1) projectiles.projectiles_prop[i].change_animation = true; if (fmod(timer.t, ball_reset_speed) < 0.1 && projectiles.projectiles_prop[i].change_animation) { projectiles.projectiles_prop[i].change_animation = false; projectiles.waterball.texture.update(projectiles.water_grid[std::rand() % 6]); } projectiles.waterball.model.translation = projectiles.projectiles_prop[i].pos; draw(projectiles.waterball, environment); projectiles.waterball.model.rotation = R; draw(projectiles.waterball, environment); projectiles.waterball.model.rotation = R2; draw(projectiles.waterball, environment); } else if (projectiles.projectiles_prop[i].elemental_type == projectile::projectile_type::ice) { if (fmod(timer.t, ball_reset_speed) > 0.1) projectiles.projectiles_prop[i].change_animation = true; if (fmod(timer.t, ball_reset_speed) < 0.1 && projectiles.projectiles_prop[i].change_animation) { projectiles.projectiles_prop[i].change_animation = false; projectiles.iceball.texture.update(projectiles.ice_grid[std::rand() % 6]); } projectiles.iceball.model.translation = projectiles.projectiles_prop[i].pos; draw(projectiles.iceball, environment); projectiles.iceball.model.rotation = R; draw(projectiles.iceball, environment); projectiles.iceball.model.rotation = R2; draw(projectiles.iceball, environment); } else if (projectiles.projectiles_prop[i].elemental_type == projectile::projectile_type::electric) { projectiles.electroball.model.translation = projectiles.projectiles_prop[i].pos; draw(projectiles.electroball, environment); projectiles.electroball.model.rotation = R; draw(projectiles.electroball, environment); projectiles.electroball.model.rotation = R2; draw(projectiles.electroball, environment); } else if (projectiles.projectiles_prop[i].elemental_type == projectile::projectile_type::rock) { projectiles.rockball.model.translation = projectiles.projectiles_prop[i].pos; draw(projectiles.rockball, environment); projectiles.rockball.model.rotation = R; draw(projectiles.rockball, environment); projectiles.rockball.model.rotation = R2; draw(projectiles.rockball, environment); } glDepthMask(true); glDisable(GL_BLEND); } } void scene_structure::mouse_move_event() { if (!inputs.keyboard.shift) camera_control.action_mouse_move(environment.camera_view); } void scene_structure::mouse_click_event() { if (camera_control.inputs->mouse.click.left){ projectiles.add_ball(camera_control.camera_model.position_camera + 2*camera_control.camera_model.front(), 20*camera_control.camera_model.front()); } camera_control.action_mouse_click(environment.camera_view); } void scene_structure::keyboard_event() { camera_control.action_keyboard(environment.camera_view); if(camera_control.inputs->keyboard.shift) { projectiles.reset(); } } void scene_structure::idle_frame() { if (camera_control.inputs->keyboard.ctrl) { camera_control.idle_frame(environment.camera_view, 10); } else { camera_control.idle_frame(environment.camera_view, gui.speed); } }