/* -*-c++-*- */ /* osgEarth - Geospatial SDK for OpenSceneGraph * Copyright 2018 Pelican Mapping * http://osgearth.org * * osgEarth is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ #pragma once #include #include #include namespace osgEarth { struct PickerGUI : public ImGuiPanel { PickerGUI() : ImGuiPanel("Picker") { } const char* highlight_shader = R"( #pragma vp_function check_for_highlight, vertex_clip uniform uint objectid_to_highlight; uint oe_index_objectid; // Stage global containing object id flat out int selected; void check_for_highlight(inout vec4 vertex) { selected = (objectid_to_highlight > 1u && objectid_to_highlight == oe_index_objectid) ? 1 : 0; } [break] #pragma vp_function highlight_fragment, fragment flat in int selected; void highlight_fragment(inout vec4 color) { if ( selected == 1 ) color.rgb = mix(color.rgb, clamp(vec3(0.5,2.0,2.0)*(1.0-color.rgb), 0.0, 1.0), 0.5); } )"; void installHighlighter() { osg::StateSet* stateSet = _mapNode->getOrCreateStateSet(); int attrLocation = Registry::objectIndex()->getObjectIDAttribLocation(); // This shader program will highlight the selected object. VirtualProgram* vp = VirtualProgram::getOrCreate(stateSet); ShaderLoader::load(vp, highlight_shader); // Since we're accessing object IDs, we need to load the indexing shader as well: Registry::objectIndex()->loadShaders(vp); // A uniform that will tell the shader which object to highlight: _highlightUniform = new osg::Uniform("objectid_to_highlight", 0u); stateSet->addUniform(_highlightUniform); } void draw(osg::RenderInfo& ri) override { if (!isVisible()) return; if (ImGui::Begin(name(), visible())) { if (!_mapNode.valid()) { _mapNode = findNode(ri); _installedPicker = false; } if (!_installedPicker) { _picker = new ObjectIDPicker(); _picker->setView(view(ri)); // which view to pick? _picker->setGraph(_mapNode.get()); // which graph to pick? _mapNode->addChild(_picker); // put it anywhere in the graph ObjectIDPicker::Function pick = [&](ObjectID id) { if (id > 0) { // Got a pick: FeatureIndex* index = Registry::objectIndex()->get(id).get(); Feature* feature = index ? index->getFeature(id) : 0L; _pickedFeature = feature; _pickedAnnotation = Registry::objectIndex()->get(id).get(); _highlightUniform->set(id); } else { // No pick: _pickedFeature = nullptr; _pickedAnnotation = nullptr; _highlightUniform->set(0u); } }; // Call our handler when hovering over the map _picker->onHover(pick); // Highlight features as we pick'em. installHighlighter(); // To display the contents of the pick camera in the imgui panel setupPreviewCamera(); _installedPicker = true; } if (ImGui::Checkbox("Picker active", &_active)) { _picker->setNodeMask(_active ? ~0 : 0); } if (_active) { if (ImGui::Checkbox("RTT preview", &_preview)) dirtySettings(); if (_preview && _previewTexture) { osg::Texture2D* pickTex = _picker->getOrCreateTexture(); if (pickTex) { if (_previewStateSet->getTextureAttribute(0, osg::StateAttribute::TEXTURE) != pickTex) _previewStateSet->setTextureAttribute(0, pickTex, 1); ImGui::Text("Picker camera preview:"); ImGuiEx::OSGTexture(_previewTexture, ri); } } if (_pickedFeature.valid()) { ImGui::Separator(); ImGui::Text("Picked Feature:"); ImGuiLTable::Begin("picked feature", ImGuiTableFlags_Borders); ImGuiLTable::Text("FID", "%ld", _pickedFeature->getFID()); for (auto& attr : _pickedFeature->getAttrs()) { ImGuiLTable::Text(attr.first.c_str(), "%s", attr.second.getString().c_str()); } ImGuiLTable::End(); } else if (_pickedAnnotation.valid()) { ImGui::Text("Picked Annotation:"); ImGui::Indent(); { ImGui::Text("Object name = %s", _pickedAnnotation->getName().c_str()); ImGui::Text("Object type = %s", typeid(*_pickedAnnotation).name()); } ImGui::Unindent(); } } } ImGui::End(); } // A lot of code just to re-color the picker's rtt camera into visible colors :) // We are just taking the pick texture and re-rendering it to another quad // with a new shader so we can amplify the colors. void setupPreviewCamera() { // simple fragment shader to recolor a texture const char* pick_preview = R"( #pragma vp_function pick_preview_vs, vertex_clip out vec2 uv; void pick_preview_vs(inout vec4 clip) { const vec2 uvs[6] = vec2[6]( vec2(0,0), vec2(1,1), vec2(0,1), vec2(1,1), vec2(0,0), vec2(1,0) ); uv = uvs[gl_VertexID]; clip = vec4(uv*2-1, 0, 1); } [break] #pragma vp_function pick_preview_fs, fragment_output in vec2 uv; out vec4 frag; uniform sampler2D tex; void pick_preview_fs(inout vec4 c) { c = texture(tex, uv); frag = c==vec4(0)? vec4(1) : vec4(vec3((c.r+c.g+c.b+c.a)/4.0),1); } )"; osg::Geometry* geom = new osg::Geometry(); _previewStateSet = geom->getOrCreateStateSet(); geom->setCullingActive(false); geom->setUseVertexBufferObjects(true); geom->setUseDisplayList(false); geom->setVertexArray(new osg::Vec3Array(6)); geom->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, 6)); _previewStateSet->addUniform(new osg::Uniform("tex", 0)); VirtualProgram* vp = VirtualProgram::getOrCreate(_previewStateSet); ShaderLoader::load(vp, pick_preview); _previewTexture = new osg::Texture2D(); _previewTexture->setTextureSize(256, 256); _previewTexture->setSourceFormat(GL_RGBA); _previewTexture->setSourceType(GL_UNSIGNED_BYTE); _previewTexture->setInternalFormat(GL_RGBA8); osg::Camera* cam = new osg::Camera(); cam->addChild(geom); cam->setClearColor(osg::Vec4(1, 0, 0, 1)); cam->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cam->setViewport(0, 0, 256, 256); cam->setRenderOrder(osg::Camera::POST_RENDER); cam->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); cam->setImplicitBufferAttachmentMask(0, 0); cam->attach(osg::Camera::COLOR_BUFFER, _previewTexture); _mapNode->addChild(cam); } bool _active = true; bool _preview = false; osg::observer_ptr _mapNode; bool _installedPicker = false; osgEarth::Util::ObjectIDPicker* _picker; osg::Uniform* _highlightUniform; osg::ref_ptr _pickedFeature; osg::ref_ptr _pickedAnnotation; osg::ref_ptr _previewTexture; osg::ref_ptr _previewStateSet; }; }