void Scene::parse_istream(std::istream& in) { // This is not a fully featured .obj file reader, it just takes some // inspiration from it: // http://www.martinreddy.net/gfx/3d/OBJ.spec std::unordered_map<std::string, SceneNode*> nodes; std::unordered_map<std::string, std::unique_ptr<SceneNode> > unattached_children; std::string name; std::string parent; std::string material = "phong"; glm::vec3 location(0.0f, 0.0f, 0.0f); glm::quat rotation(1.0f, 0.0f, 0.0f, 0.0f); glm::vec3 scale(1.0f, 1.0f, 1.0f); std::vector<glm::vec3> normal; std::vector<glm::vec3> position; std::vector<glm::vec3> texcoord; std::vector<int> index; std::vector<glm::vec4> bone_weight; std::vector<glm::ivec4> bone_index; std::vector<int> bone_count; auto commit_object = [&]{ if (!name.empty()) { ModelPtr model; if (!position.empty()) { // fill in some texcoords if there aren't enough if (texcoord.size() < position.size()) { texcoord.resize(position.size()); for(FaceLst::size_type i = position.size()-1; i < texcoord.size(); ++i) { texcoord[i] = glm::vec3(0.0f, 0.0f, 0.0f); } } { // create Mesh std::unique_ptr<Mesh> mesh(new Mesh(GL_TRIANGLES)); mesh->attach_float_array("position", position); mesh->attach_float_array("texcoord", texcoord); mesh->attach_float_array("normal", normal); mesh->attach_element_array(index); if (!bone_weight.empty() && !bone_index.empty()) { mesh->attach_float_array("bone_weight", bone_weight); mesh->attach_int_array("bone_index", bone_index); } // create Model model = std::make_shared<Model>(); model->add_mesh(std::move(mesh)); if (boost::algorithm::ends_with(material, ".material")) { model->set_material(MaterialFactory::get().from_file(m_directory / boost::filesystem::path(material))); } else { model->set_material(MaterialFactory::get().create(material)); } } } // create SceneNode { std::unique_ptr<SceneNode> node(new SceneNode(name)); node->set_position(location); node->set_orientation(rotation); node->set_scale(scale); if (model) { node->attach_model(model); } if (nodes.find(name) != nodes.end()) { throw std::runtime_error("duplicate object name: " + name); } nodes[name] = node.get(); if (parent.empty()) { m_node->attach_child(std::move(node)); } else { unattached_children[parent] = std::move(node); } } // clear for the next mesh name.clear(); parent.clear(); normal.clear(); texcoord.clear(); position.clear(); index.clear(); location = glm::vec3(0.0f, 0.0f, 0.0f); rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); scale = glm::vec3(1.0f, 1.0f, 1.0f); } }; std::string line; int line_number = 0; while(std::getline(in, line)) { line_number += 1; boost::tokenizer<boost::char_separator<char> > tokens(line, boost::char_separator<char>(" ", "")); auto it = tokens.begin(); if (it != tokens.end()) { #define INCR_AND_CHECK { \ ++it; \ if (it == tokens.end()) \ { \ throw std::runtime_error((boost::format("not enough tokens at line %d") % line_number).str()); \ } \ } try { if (*it == "o") { // object commit_object(); INCR_AND_CHECK; log_debug("object: '%s'", *it); name = *it; } else if (*it == "g") { // group } else if (*it == "parent") { INCR_AND_CHECK; parent = *it; } else if (*it == "mat") { INCR_AND_CHECK; material = *it; } else if (*it == "loc") { INCR_AND_CHECK; location.x = boost::lexical_cast<float>(*it); INCR_AND_CHECK; location.y = boost::lexical_cast<float>(*it); INCR_AND_CHECK; location.z = boost::lexical_cast<float>(*it); } else if (*it == "rot") { INCR_AND_CHECK; rotation.w = boost::lexical_cast<float>(*it); INCR_AND_CHECK; rotation.x = boost::lexical_cast<float>(*it); INCR_AND_CHECK; rotation.y = boost::lexical_cast<float>(*it); INCR_AND_CHECK; rotation.z = boost::lexical_cast<float>(*it); } else if (*it == "scale") { INCR_AND_CHECK; scale.x = boost::lexical_cast<float>(*it); INCR_AND_CHECK; scale.y = boost::lexical_cast<float>(*it); INCR_AND_CHECK; scale.z = boost::lexical_cast<float>(*it); } else if (*it == "v") { glm::vec3 v; INCR_AND_CHECK; v.x = boost::lexical_cast<float>(*it); INCR_AND_CHECK; v.y = boost::lexical_cast<float>(*it); INCR_AND_CHECK; v.z = boost::lexical_cast<float>(*it); position.push_back(v); } else if (*it == "vt") { glm::vec3 vt; INCR_AND_CHECK; vt.s = boost::lexical_cast<float>(*it); INCR_AND_CHECK; vt.t = boost::lexical_cast<float>(*it); texcoord.push_back(vt); } else if (*it == "vn") { glm::vec3 vn; INCR_AND_CHECK; vn.x = boost::lexical_cast<float>(*it); INCR_AND_CHECK; vn.y = boost::lexical_cast<float>(*it); INCR_AND_CHECK; vn.z = boost::lexical_cast<float>(*it); normal.push_back(vn); } else if (*it == "bw") { glm::vec4 bw; INCR_AND_CHECK; bw.x = boost::lexical_cast<float>(*it); INCR_AND_CHECK; bw.y = boost::lexical_cast<float>(*it); INCR_AND_CHECK; bw.z = boost::lexical_cast<float>(*it); INCR_AND_CHECK; bw.w = boost::lexical_cast<float>(*it); bone_weight.push_back(bw); } else if (*it == "bi") { glm::ivec4 bi; INCR_AND_CHECK; bi.x = boost::lexical_cast<int>(*it); INCR_AND_CHECK; bi.y = boost::lexical_cast<int>(*it); INCR_AND_CHECK; bi.z = boost::lexical_cast<int>(*it); INCR_AND_CHECK; bi.w = boost::lexical_cast<int>(*it); bone_index.push_back(bi); } else if (*it == "f") { INCR_AND_CHECK; index.push_back(boost::lexical_cast<int>(*it)); INCR_AND_CHECK; index.push_back(boost::lexical_cast<int>(*it)); INCR_AND_CHECK; index.push_back(boost::lexical_cast<int>(*it)); } else if ((*it)[0] == '#') { // ignore comments } else { throw std::runtime_error((boost::format("unhandled token %s") % *it).str()); } } catch(const std::exception& err) { throw std::runtime_error((boost::format("unknown:%d: %s") % line_number % err.what()).str()); } } } commit_object(); // reconstruct parent/child relationships for(auto& it : unattached_children) { auto p = nodes.find(it.first); if (p == nodes.end()) { throw std::runtime_error("parent not found: " + it.first); } else { p->second->attach_child(std::move(it.second)); } } }
void Compositor::render(Viewer& viewer) { // render the world, twice if stereo is enabled if (true) { OpenGLState state; #ifndef HAVE_OPENGLES2 if (m_render_shadowmap) { g_shadowmap->bind(); render_shadowmap(viewer); g_shadowmap->unbind(); } #endif if (m_stereo_mode == StereoMode::None) { m_renderbuffer1->bind(); render_scene(viewer, Stereo::Center); m_renderbuffer1->unbind(); m_renderbuffer1->blit(*m_framebuffer1); } else { m_renderbuffer1->bind(); render_scene(viewer, Stereo::Left); m_renderbuffer1->unbind(); m_renderbuffer2->bind(); render_scene(viewer, Stereo::Right); m_renderbuffer2->unbind(); m_renderbuffer1->blit(*m_framebuffer1); m_renderbuffer2->blit(*m_framebuffer2); } } // composit the final image if (true) { OpenGLState state; MaterialPtr material = std::make_shared<Material>(); { // setup material material->set_program(m_composition_prog); material->set_uniform("MVP", UniformSymbol::ModelViewProjectionMatrix); material->set_uniform("barrel_power", m_barrel_power); material->set_uniform("left_eye", 0); material->set_uniform("right_eye", 1); if (!viewer.m_cfg.m_show_calibration) { material->set_texture(0, m_framebuffer1->get_color_texture()); material->set_texture(1, m_framebuffer2->get_color_texture()); } else { material->set_texture(0, m_calibration_left_texture); material->set_texture(1, m_calibration_right_texture); } m_viewport_offset = {0, 0}; switch(m_stereo_mode) { case StereoMode::Cybermaxx: m_viewport_offset = {-41, 16}; m_composition_prog = m_cybermaxx_prog; break; case StereoMode::CrossEye: m_composition_prog = m_crosseye_prog; break; case StereoMode::Anaglyph: m_composition_prog = m_anaglyph_prog; break; case StereoMode::Depth: material->set_texture(0, m_framebuffer1->get_depth_texture()); m_composition_prog = m_depth_prog; break; case StereoMode::Newsprint: m_composition_prog = m_newsprint_prog; break; default: m_composition_prog = m_mono_prog; break; } } // setup material ModelPtr model = std::make_shared<Model>(); model->add_mesh(Mesh::create_rect(0.0f, 0.0f, m_screen_w, m_screen_h, -20.0f)); model->set_material(material); Camera camera; camera.ortho(0, m_screen_w, m_screen_h, 0.0f, 0.1f, 10000.0f); SceneManager mgr; mgr.get_world()->attach_model(model); RenderContext ctx(camera, mgr.get_world()); glViewport(m_viewport_offset.x, m_viewport_offset.y, m_screen_w, m_screen_h); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); mgr.render(camera); render_menu(ctx, viewer); } assert_gl("display:exit()"); }