osg::Vec3 CameraModel::get_translation() const { osg::Vec4 eye( _eye[0], _eye[1], _eye[2], 1.0); osg::Vec4 t = -(eye*get_rot()); freemovr_assert(t[3]==1.0); osg::Vec3 result(t[0], t[1], t[2]); return result; }
quat & mat4::get_rot(quat& q) const { mat3 m; get_rot(m); q.FromMatrix(m); return q; }
Variant Node2D::edit_get_state() const { Array state; state.push_back(get_pos()); state.push_back(get_rot()); state.push_back(get_scale()); return state; }
void unit_vehicle::update(int dt, world &w) { if (hp <= 0) return; if (m_first_update) { m_first_update = false; if (!m_follow.expired()) { auto f = m_follow.lock(); vec3 diff = get_pos() - f->get_pos(); if (diff.length() < m_params.formation_radius) m_formation_offset = f->get_rot().rotate_inv(diff); else m_formation_offset.set(0, 0, -15.0f); } m_ground = (get_pos().y - w.get_height(get_pos().x, get_pos().z)) < 5.0f; if (m_ground) { //ToDo: gear anim } else { if (m_params.speed_min > 0.01f) m_vel = get_rot().rotate(vec3::forward() * m_params.speed_cruise); m_dpos = vec3(); } return; } float kdt = dt * 0.001f; vec3 target_dir; bool has_target = false; if (m_target.expired()) { if (m_ai > ai_default && m_target_search != search_none) { const bool air = m_ai == ai_air_to_air || m_ai == ai_air_multirole, ground = m_ai == ai_air_to_ground || m_ai == ai_air_multirole; float min_dist = 10000.0f; for (int i = 0; i < w.get_planes_count() + w.get_units_count(); ++i) { object_ptr t; if (i < w.get_planes_count()) { auto p = w.get_plane(i); if (is_ally(p, w)) continue; t = p; } else { if (m_target_search == search_player) continue; auto u = w.get_unit(i - w.get_planes_count()); if (is_ally(u)) continue; t = u; } if (!t->is_targetable(air, ground)) continue; const float dist = (t->get_pos() - get_pos()).length(); if(dist >= min_dist) continue; m_target = t; min_dist = dist; } } } else { if (m_target.lock()->hp <= 0) m_target.reset(); } bool not_path_not_follow = false; if (!m_path.empty()) { has_target = true; target_dir = m_path.front() - get_pos(); if (target_dir.length() < m_vel.length() * kdt * m_params.target_radius) { if (m_path_loop) m_path.push_back(m_path.front()); m_path.pop_front(); if (m_path.empty()) has_target = false; else target_dir = m_path.front() - get_pos(); } } else if (!m_follow.expired()) { has_target = true; auto f = m_follow.lock(); target_dir = f->get_pos() + f->get_rot().rotate(m_formation_offset) - (get_pos() + get_vel() * kdt); //+ f->get_vel() * kdt //player's plane is already updated, ToDo } else not_path_not_follow = true; if (!m_target.expired()) { auto t = m_target.lock(); const auto dir = t->get_pos() + t->get_rot().rotate(vec3(0, 0, -20.0)) - (get_pos() + get_vel() * kdt); if (not_path_not_follow) { target_dir = dir; has_target = true; } for (auto &wp: m_weapons) { if (wp.cooldown > 0) { wp.cooldown -= dt; continue; } if (dir.length() > wp.params.lockon_range) continue; wp.cooldown = wp.params.reload_time; auto m = w.add_missile(wp.params.id.c_str(), wp.mdl); if (!m) continue; m->phys->pos = get_pos(); m->phys->rot = get_rot(); m->phys->vel = get_vel(); m->phys->target_dir = dir; m->target = m_target; } } if (has_target) { const float eps=1.0e-6f; const float target_dist = target_dir.length(); const vec3 v=target_dir / target_dist; const float xz_sqdist=v.x*v.x+v.z*v.z; const auto rot = get_rot(); const auto pyr = rot.get_euler(); const nya_math::angle_rad new_yaw=(xz_sqdist>eps*eps)? (atan2(v.x,v.z)) : pyr.y; nya_math::angle_rad new_pitch=(fabsf(v.y)>eps)? (-atan2(v.y,sqrtf(xz_sqdist))) : 0.0f; nya_math::angle_rad new_roll; if (!m_follow.expired()) new_roll = m_follow.lock()->get_rot().get_euler().z; vec3 pos = get_pos() + m_vel * kdt; const float h = w.get_height(pos.x, pos.z); if ((new_pitch > 0.0f && pos.y <= h + m_params.height_min) || (new_pitch < 0.0f && pos.y >= h + m_params.height_max)) new_pitch = 0.0f; const auto ideal_rot = quat(new_pitch, new_yaw, new_roll); const float angle_diff = rot.rotate(vec3::forward()).angle(target_dir).get_deg(); if (fabsf(angle_diff) > 0.001f) { const float turn_k = nya_math::clamp((180.0f / angle_diff) * m_params.turn_speed * kdt, 0.0, 1.0); m_render->mdl.set_rot(quat::slerp(rot, ideal_rot, turn_k)); } float speed = m_vel.length(); float want_speed = target_dist / kdt; if (!m_follow.expired()) { const float target_speed = m_follow.lock()->get_vel().length(); float decel_time = (speed - target_speed) / m_params.decel; if (target_dist / (speed + m_params.accel * kdt) < decel_time) want_speed = target_speed; } want_speed = nya_math::clamp(want_speed, m_params.speed_min, std::min(m_params.speed_max, m_speed_limit)); speed = tend(speed, want_speed, m_params.accel * kdt, m_params.decel * kdt); m_vel = get_rot().rotate(vec3(0.0, 0.0, speed)); } else if (m_params.speed_min < 0.01f) { float speed = m_vel.length(); if (speed > 0.0f) { speed = tend(speed, 0.0f, m_params.accel * kdt, m_params.decel * kdt); m_vel = get_rot().rotate(vec3(0.0, 0.0, speed)); } } vec3 pos = get_pos() + m_vel * kdt; const float h = w.get_height(pos.x, pos.z); pos.y = nya_math::clamp(pos.y, h + m_params.height_min, h + m_params.height_max); //ToDo set_pos(pos); }
void Node2D::rotate(float p_radians) { set_rot( get_rot() + p_radians); }
float Node2D::_get_rotd() const { return Math::rad2deg(get_rot()); }
int main() { setup_resources(); config::register_var("screen_width", "1000"); config::register_var("screen_height", "562"); config::register_var("master_volume", "10"); config::register_var("music_volume", "5"); platform platform; if (!platform.init(config::get_var_int("screen_width"), config::get_var_int("screen_height"), "Open Horizon 7th demo")) return -1; std::vector<joystick_config> joysticks; for (int i = 0; glfwJoystickPresent(i); ++i) { const char *name = glfwGetJoystickName(i); joystick_config j; j.init(name); joysticks.push_back(j); int axis_count = 0, buttons_count = 0; glfwGetJoystickAxes(i, &axis_count); glfwGetJoystickButtons(i, &buttons_count); printf("joy%d: %s %d axis %d buttons\n", i, name, axis_count, buttons_count); } renderer::scene scene; sound::world sound_world; game::world world(scene, sound_world, scene.hud); game::mission game_mode_ms(world); game::free_flight game_mode_ff(world); game::deathmatch game_mode_dm(world); game::team_deathmatch game_mode_tdm(world); game::hangar hangar(scene); game::game_mode *active_game_mode = 0; game::plane_controls controls; game::network_client client; game::network_server server; gui::menu menu(sound_world); gui::menu_controls menu_controls; platform::key_callback kcb = std::bind(&gui::menu::on_input, &menu, std::placeholders::_1); platform.set_keyboard_callback(kcb); int mx = platform.get_mouse_x(), my = platform.get_mouse_y(); int screen_width = platform.get_width(), screen_height = platform.get_height(); scene.resize(screen_width, screen_height); scene.loading(true); nya_render::clear(true, true); scene.draw(); platform.end_frame(); sound_world.set_volume(config::get_var_int("master_volume") / 10.0f); sound_world.set_music_volume(config::get_var_int("music_volume") / 10.0f); menu.init(); sound_world.set_music("BGM_menu"); bool viewer_mode = false; bool is_client = false, is_server = false; gui::menu::on_action on_menu_action = [&](const std::string &event) { if (event == "start") { sound_world.stop_music(); const char *music_names[] = {"BGM_ms10_08", "BGM_ms06", "BGM_ms08x", "BGM_ms11a", "BGM_ms11b", "BGM_ms12_02"}; sound_world.set_music(music_names[rand() % (sizeof(music_names) / sizeof(music_names[0]))]); auto location = menu.get_var("map"); auto plane = menu.get_var("ac"); const int color = atoi(menu.get_var("color").c_str()); is_client = false, is_server = false; scene.loading(true); nya_render::clear(true, true); scene.draw(); platform.end_frame(); scene.loading(false); auto mode = menu.get_var("mode"); auto mp_var = menu.get_var("multiplayer"); if (mp_var == "server") { world.set_network(&server); auto port = menu.get_var_int("port"); server.open(port, config::get_var("name").c_str(), mode.c_str(), menu.get_var("map").c_str(), menu.get_var_int("max_players")); if (menu.get_var("mp_public") == "true") game::servers_list::register_server(port); is_server = true; } else if (mp_var == "client") { world.set_network(&client); client.start(); is_client = true; } if (mode == "ms") { active_game_mode = &game_mode_ms; game_mode_ms.start(plane.c_str(), color, menu.get_var("mission").c_str()); } else if (mode == "dm") { const int bots_count = (is_client || is_server) ? 0 : 11; active_game_mode = &game_mode_dm; game_mode_dm.start(plane.c_str(), color, 0, location.c_str(), bots_count); } else if (mode == "tdm") { const int bots_count = (is_client || is_server) ? 0 : 7; active_game_mode = &game_mode_tdm; game_mode_tdm.start(plane.c_str(), color, 0, location.c_str(), bots_count); } else if (mode == "ff") { active_game_mode = &game_mode_ff; game_mode_ff.start(plane.c_str(), color, location.c_str()); } } else if (event == "connect") { menu.set_error(""); client.disconnect(); auto port = menu.get_var_int("port"); if (client.connect(menu.get_var("address").c_str(), port)) { menu.send_event("map=" + client.get_server_info().location); menu.send_event("mode=" + client.get_server_info().game_mode); menu.send_event("screen=ac_select"); } else menu.set_error(client.get_error()); } else if (event == "viewer_start") { viewer_mode = true; scene.camera.add_delta_rot(0.2f, 2.5f); } else if (event == "viewer_update_bg") { hangar.set_bkg(menu.get_var("bkg").c_str()); } else if (event == "viewer_update_ac") { const auto dr = scene.camera.get_delta_rot(); hangar.set_plane(menu.get_var("ac").c_str()); scene.camera.add_delta_rot(dr.x, dr.y - 3.14f); } else if (event == "viewer_update_color") { const auto dr = scene.camera.get_delta_rot(); const int color = atoi(menu.get_var("color").c_str()); hangar.set_plane_color(color); scene.camera.add_delta_rot(dr.x, dr.y - 3.14f); } else if (event == "viewer_end") { viewer_mode = false; hangar.end(); } else if (event == "update_volume") { sound_world.set_volume(config::get_var_int("master_volume") / 10.0f); sound_world.set_music_volume(config::get_var_int("music_volume") / 10.0f); } else if (event == "update_joy_config") { if (!joysticks.empty()) joysticks.front().update_config(); } else if (event == "exit") { server.close(); client.disconnect(); platform.terminate(); } else printf("unknown event: %s\n", event.c_str()); }; menu.set_callback(on_menu_action); bool reset_camera = false; unsigned long app_time = nya_system::get_time(); while (!platform.should_terminate()) { unsigned long time = nya_system::get_time(); int dt = int(time - app_time); if (dt > 1000 && !is_client && !is_server) dt = 1000; app_time = time; static bool speed10x = false, last_pause = false, paused = false; if (platform.get_width() != screen_width || platform.get_height() != screen_height) { screen_width = platform.get_width(), screen_height = platform.get_height(); scene.resize(screen_width, screen_height); config::set_var("screen_width", std::to_string(screen_width)); config::set_var("screen_height", std::to_string(screen_height)); } if (!active_game_mode) menu.update(dt, menu_controls); if (active_game_mode) { if (!paused) { active_game_mode->update(speed10x ? dt * 10 : dt, controls); //camera - tracking enemy auto p = world.get_player(); if (p && p->change_target_hold_time >= game::plane::change_target_hold_max_time && !p->targets.empty() && !p->targets.front().target.expired()) { static auto last_target = p->targets.front().target; if (last_target.expired() || last_target.lock() != p->targets.front().target.lock()) { last_target = p->targets.front().target; p->change_target_hold_time = game::plane::change_target_hold_max_time; } auto t = p->targets.front().target.lock(); auto tdir = t->get_pos() - p->get_pos(); // + (t->get_vel() - p->get_vel()) * (dt * 0.001f) nya_math::quat q(nya_math::vec3::forward(), tdir); q = nya_math::quat::invert(p->get_rot()) * q; auto da = q.get_euler(); scene.camera.reset_delta_rot(); const float k = nya_math::min((p->change_target_hold_time - game::plane::change_target_hold_max_time) / 500.0f, 1.0); scene.camera.add_delta_rot(da.x * k, -da.y * k); reset_camera = true; } } scene.draw(); //util debug draw nya_render::clear(false, true); nya_render::set_state(nya_render::state()); nya_render::set_modelview_matrix(nya_scene::get_camera().get_view_matrix()); get_debug_draw().set_line_width(2.0f); get_debug_draw().set_point_size(3.0f); get_debug_draw().draw(); } else { nya_render::clear(true, true); if (viewer_mode) { hangar.update(dt); scene.draw(); } menu.draw(scene.ui_render); } const char *ui_ref = 0; //ui_ref = "ui_ref4.tga"; if (ui_ref) { static nya_scene::texture ui_ref_texture(ui_ref); static std::vector<gui::rect_pair> ui_ref_rects(1); ui_ref_rects[0].r.w = scene.ui_render.get_width(); ui_ref_rects[0].r.y = scene.ui_render.get_height(); ui_ref_rects[0].r.h = -scene.ui_render.get_height(); ui_ref_rects[0].tc.w = ui_ref_texture.get_width(); ui_ref_rects[0].tc.h = ui_ref_texture.get_height(); static int alpha_anim = 0; alpha_anim += dt; alpha_anim = alpha_anim % 4000; //alpha_anim = 1000; scene.ui_render.draw(ui_ref_rects, ui_ref_texture, nya_math::vec4(1.0, 1.0, 1.0, fabsf(alpha_anim / 2000.0f - 1.0))); } platform.end_frame(); //controls controls = game::plane_controls(); menu_controls = gui::menu_controls(); if (platform.get_mouse_lbtn()) scene.camera.add_delta_rot((platform.get_mouse_y() - my) * 0.03, (platform.get_mouse_x() - mx) * 0.03); if (platform.get_mouse_rbtn()) scene.camera.add_delta_pos(0, 0, my - platform.get_mouse_y()); mx = platform.get_mouse_x(), my = platform.get_mouse_y(); bool pause = false; for (int i = 0; i < (int)joysticks.size(); ++i) { int axes_count = 0, buttons_count = 0; const float *axes = glfwGetJoystickAxes(i, &axes_count); const unsigned char *buttons = glfwGetJoystickButtons(i, &buttons_count); joysticks[i].update(axes, axes_count, buttons, buttons_count); joysticks[i].apply_controls(controls, pause); if (!active_game_mode) { if (i == 0 && !menu.joy_update(axes, axes_count, buttons, buttons_count)) joysticks[i].apply_controls(menu_controls); } } if (platform.get_key(GLFW_KEY_W)) controls.throttle = 1.0f; if (platform.get_key(GLFW_KEY_S)) controls.brake = 1.0f; if (platform.get_key(GLFW_KEY_A)) controls.rot.y = -1.0f; if (platform.get_key(GLFW_KEY_D)) controls.rot.y = 1.0f; if (platform.get_key(GLFW_KEY_UP)) controls.rot.x = 1.0f, menu_controls.up = true; if (platform.get_key(GLFW_KEY_DOWN)) controls.rot.x = -1.0f, menu_controls.down = true; if (platform.get_key(GLFW_KEY_LEFT)) controls.rot.z = -1.0f, menu_controls.left = true; if (platform.get_key(GLFW_KEY_RIGHT)) controls.rot.z = 1.0f, menu_controls.right = true; if (platform.get_key(GLFW_KEY_LEFT_CONTROL)) controls.mgun = true; if (platform.get_key(GLFW_KEY_LEFT_SHIFT)) controls.mgun = true; if (platform.get_key(GLFW_KEY_SPACE)) controls.missile = true, menu_controls.next = true; if (platform.get_key(GLFW_KEY_F)) controls.flares = true; if (platform.get_key(GLFW_KEY_Q)) controls.change_weapon = true; if (platform.get_key(GLFW_KEY_E)) controls.change_target = true; if (platform.get_key(GLFW_KEY_R)) controls.change_radar = true; if (platform.get_key(GLFW_KEY_V)) controls.change_camera = true; if (platform.was_pressed(GLFW_KEY_ESCAPE)) menu_controls.prev = true; if (platform.was_pressed(GLFW_KEY_ENTER)) menu_controls.next = true; if (active_game_mode) { if (((pause && pause != last_pause) || platform.was_pressed(GLFW_KEY_P)) && !is_server && !is_client) scene.pause(paused = !paused); last_pause = pause; bool should_stop = platform.was_pressed(GLFW_KEY_ESCAPE); if (is_client && !client.is_up()) should_stop = true; if (is_server && !server.is_up()) should_stop = true; if (should_stop) { if (paused) scene.pause(paused = !paused); active_game_mode->end(); active_game_mode = 0; server.close(); client.disconnect(); world.set_network(0); sound_world.stop_sounds(); menu_controls.prev = false; if (is_client) menu.send_event("screen=mp_connect"); sound_world.set_music("BGM_menu"); } } speed10x = platform.get_key(GLFW_KEY_RIGHT_SHIFT) && !is_client && !is_server; if (controls.change_camera || (reset_camera && !controls.change_target)) { scene.camera.reset_delta_rot(); reset_camera = false; } if (!joysticks.empty() && !platform.get_mouse_lbtn() && !controls.change_target) { scene.camera.reset_delta_rot(); scene.camera.add_delta_rot(-controls.cam_rot.x * nya_math::constants::pi_2, -controls.cam_rot.y * nya_math::constants::pi); } if (platform.was_pressed(GLFW_KEY_COMMA)) debug_variable::set(debug_variable::get() - 1); if (platform.was_pressed(GLFW_KEY_PERIOD)) debug_variable::set(debug_variable::get() + 1); if (!active_game_mode) //force limit 60 fps in menu { int sleep_time = 1000/60 - int(nya_system::get_time() - time); if (sleep_time > 0) std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time)); } } server.close(); client.disconnect(); sound::release_context(); platform.terminate(); return 0; }
void Node2D::rotate(float p_degrees) { set_rot( get_rot() + p_degrees); }
osg::Matrix CameraModel::get_rot_inv() const { osg::Matrix result; // OSG doesn't have a transpose matrix function? result.invert( get_rot() ); return result; }
void model_draw(const shader_t *s, GLuint utrans, GLuint uquats, const GLuint *texture, const uint32_t *mdl, int anim_id, double frame, const float *teamcolor, const float *color, uint16_t tex_over) { /* assumes valid model data */ uint8_t ngeo, teamcolor_end, nbone, nanim; const uint8_t *p, *tr, *qt; const chunkinfo_t *ck; const anim_t *anim; const bone_t *b; vec3 trans, ptrans; vec4 rot, prot; int vis, i, offset, tex; vec3 rtrans[maxbones]; vec4 rotation[maxbones]; /* parse header */ p = (const uint8_t*)mdl; ngeo = p[0]; teamcolor_end = p[1]; nbone = p[2]; nanim = p[3]; anim = (const anim_t*)&p[4]; ck = (const chunkinfo_t*)&anim[nanim]; p = (const uint8_t*)&ck[ngeo]; anim += anim_id; vis = anim->vis; frame = frame * anim->frames; /* calculate transformations for frame */ i = 0; do { b = (const bone_t*)p; tr = (const uint8_t*)&b[1]; qt = tr + nanim; p = qt + nanim; p = align4(p); get_trans(&trans, p, tr, anim_id, frame); p += b->keyframes[0] * sizeof(keyframe_t); get_rot(&rot, p, qt, anim_id, frame); p += b->keyframes[1] * sizeof(keyframe4_t); if(b->parent < 0) { ptrans = vec3(0.0, 0.0, 0.0); prot = vec4(0.0, 0.0, 0.0, 1.0); } else { ptrans = rtrans[b->parent]; prot = rotation[b->parent]; } rotation[i] = mul4(rot, prot); trans = add3(ptrans, qrot3(add3(b->pivot, trans), prot)); rtrans[i] = add3(qrot3(neg3(b->pivot), rotation[i]), trans); } while (++i < nbone); /* load transformations */ glUniform4fv(uquats, nbone, (float*)rotation); glUniform3fv(utrans, nbone, (float*)rtrans); //GLuint test; //glGenBuffers(1, &test); // //glBufferData(GL_ELEMENT_ARRAY_BUFFER, ck[ngeo - 1].index, indices, GL_STATIC_DRAW); /* draw visible vertices */ i = 0; offset = 0; tex = 0xFFFF; glUniform4fv(s->k, 1, teamcolor); glUniform4fv(s->samp, 1, color); do { if(i == teamcolor_end) glUniform4fv(s->k, 1, transparency); if((vis & (1 << i))) { if (tex_over != 0xFFFF) { glBindTexture(GL_TEXTURE_2D, tex_over == 0xFFFE ? 0 : texture[tex_over]); } else if (ck[i].texture != tex) { tex = ck[i].texture; glBindTexture(GL_TEXTURE_2D, texture[tex]); } glDrawElements(GL_TRIANGLES, ck[i].index - offset, GL_UNSIGNED_SHORT, (void*)(size_t)offset); } offset = ck[i].index; } while(++i != ngeo); //glDeleteBuffers(1, &test); }
/* todo: implement this correctly */ vec3 model_gettrans(const uint32_t *mdl, int anim_id, double frame, int bone) { uint8_t ngeo, nbone, nanim; const uint8_t *p, *tr, *qt; const chunkinfo_t *ck; const anim_t *anim; const bone_t *b; vec3 trans, ptrans; vec4 rot, prot; int i; vec3 translation[maxbones]; vec3 rtrans[maxbones]; vec4 rotation[maxbones]; if (bone == 0xFF) return vec3(0.0, 0.0, 0.0); /* parse header */ p = (const uint8_t*)mdl; ngeo = p[0]; nbone = p[2]; nanim = p[3]; anim = (const anim_t*)&p[4]; ck = (const chunkinfo_t*)&anim[nanim]; p = (const uint8_t*)&ck[ngeo]; anim += anim_id; frame = frame * anim->frames; /* calculate transformations for frame */ i = 0; do { b = (const bone_t*)p; tr = (const uint8_t*)&b[1]; qt = tr + nanim; p = qt + nanim; if(nanim & 1) { /* alignment */ p += 2; } get_trans(&trans, p, tr, anim_id, frame); p += b->keyframes[0] * sizeof(keyframe_t); get_rot(&rot, p, qt, anim_id, frame); p += b->keyframes[1] * sizeof(keyframe4_t); if(b->parent < 0) { ptrans = vec3(0.0, 0.0, 0.0); prot = vec4(0.0, 0.0, 0.0, 1.0); } else { ptrans = rtrans[b->parent]; prot = rotation[b->parent]; } rotation[i] = mul4(rot, prot); translation[i] = add3(ptrans, qrot3(add3(b->pivot, trans), prot)); rtrans[i] = add3(qrot3(neg3(b->pivot), rotation[i]), translation[i]); if (i == bone) return translation[i]; } while(++i < nbone); return vec3(0.0, 0.0, 0.0); }