Spaces:
Sleeping
Sleeping
2c62cd0b0eb2c78fec26a20e2ee85f1e4f8dd6f649125667e3b449817773c6c1
Browse files- third-party/DPVO/Pangolin/components/pango_core/include/pangolin/utils/xml/rapidxml_print.hpp +421 -0
- third-party/DPVO/Pangolin/components/pango_core/include/pangolin/utils/xml/rapidxml_utils.hpp +122 -0
- third-party/DPVO/Pangolin/components/pango_core/include/sigslot/LICENCE +21 -0
- third-party/DPVO/Pangolin/components/pango_core/include/sigslot/README.md +717 -0
- third-party/DPVO/Pangolin/components/pango_core/include/sigslot/signal.hpp +1611 -0
- third-party/DPVO/Pangolin/components/pango_core/src/avx_math.cpp +553 -0
- third-party/DPVO/Pangolin/components/pango_core/src/dummy.cpp +0 -0
- third-party/DPVO/Pangolin/components/pango_core/src/factory/factory_help.cpp +145 -0
- third-party/DPVO/Pangolin/components/pango_core/src/factory/factory_registry.cpp +11 -0
- third-party/DPVO/Pangolin/components/pango_core/src/file_extension.cpp +247 -0
- third-party/DPVO/Pangolin/components/pango_core/src/file_utils.cpp +544 -0
- third-party/DPVO/Pangolin/components/pango_core/src/param_set.cpp +58 -0
- third-party/DPVO/Pangolin/components/pango_core/src/posix/condition_variable.cpp +89 -0
- third-party/DPVO/Pangolin/components/pango_core/src/posix/semaphore.cpp +83 -0
- third-party/DPVO/Pangolin/components/pango_core/src/posix/shared_memory_buffer.cpp +134 -0
- third-party/DPVO/Pangolin/components/pango_core/src/sigstate.cpp +60 -0
- third-party/DPVO/Pangolin/components/pango_core/src/threadedfilebuf.cpp +353 -0
- third-party/DPVO/Pangolin/components/pango_core/src/uri.cpp +105 -0
- third-party/DPVO/Pangolin/components/pango_core/tests/tests_uri.cpp +87 -0
- third-party/DPVO/Pangolin/components/pango_display/CMakeLists.txt +26 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/console/ConsoleView.h +108 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/console/InterpreterInterface.h +80 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/attach.h +86 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/default_font.h +7 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/display.h +147 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/display.hpp +47 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/image_view.h +74 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/process.h +59 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/user_app.h +43 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/view.h +231 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/widgets.h +161 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/handler/handler.h +139 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/handler/handler_glbuffer.h +48 -0
- third-party/DPVO/Pangolin/components/pango_display/include/pangolin/handler/handler_image.h +166 -0
- third-party/DPVO/Pangolin/components/pango_display/src/ConsoleView.cpp +327 -0
- third-party/DPVO/Pangolin/components/pango_display/src/default_font.cpp +19 -0
- third-party/DPVO/Pangolin/components/pango_display/src/display.cpp +347 -0
- third-party/DPVO/Pangolin/components/pango_display/src/handler.cpp +472 -0
- third-party/DPVO/Pangolin/components/pango_display/src/handler_glbuffer.cpp +45 -0
- third-party/DPVO/Pangolin/components/pango_display/src/handler_image.cpp +526 -0
- third-party/DPVO/Pangolin/components/pango_display/src/image_view.cpp +227 -0
- third-party/DPVO/Pangolin/components/pango_display/src/pangolin_gl.cpp +94 -0
- third-party/DPVO/Pangolin/components/pango_display/src/pangolin_gl.h +102 -0
- third-party/DPVO/Pangolin/components/pango_display/src/process.cpp +161 -0
- third-party/DPVO/Pangolin/components/pango_display/src/view.cpp +508 -0
- third-party/DPVO/Pangolin/components/pango_display/src/widgets.cpp +787 -0
- third-party/DPVO/Pangolin/components/pango_geometry/CMakeLists.txt +21 -0
- third-party/DPVO/Pangolin/components/pango_geometry/include/pangolin/geometry/geometry.h +93 -0
- third-party/DPVO/Pangolin/components/pango_geometry/include/pangolin/geometry/geometry_obj.h +34 -0
- third-party/DPVO/Pangolin/components/pango_geometry/include/pangolin/geometry/geometry_ply.h +150 -0
third-party/DPVO/Pangolin/components/pango_core/include/pangolin/utils/xml/rapidxml_print.hpp
ADDED
@@ -0,0 +1,421 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
2 |
+
#define RAPIDXML_PRINT_HPP_INCLUDED
|
3 |
+
|
4 |
+
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
5 |
+
// Version 1.13
|
6 |
+
// Revision $DateTime: 2009/05/13 01:46:17 $
|
7 |
+
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
|
8 |
+
|
9 |
+
#include "rapidxml.hpp"
|
10 |
+
|
11 |
+
// Only include streams if not disabled
|
12 |
+
#ifndef RAPIDXML_NO_STREAMS
|
13 |
+
#include <ostream>
|
14 |
+
#include <iterator>
|
15 |
+
#endif
|
16 |
+
|
17 |
+
namespace rapidxml
|
18 |
+
{
|
19 |
+
|
20 |
+
///////////////////////////////////////////////////////////////////////
|
21 |
+
// Printing flags
|
22 |
+
|
23 |
+
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
24 |
+
|
25 |
+
///////////////////////////////////////////////////////////////////////
|
26 |
+
// Internal
|
27 |
+
|
28 |
+
//! \cond internal
|
29 |
+
namespace internal
|
30 |
+
{
|
31 |
+
|
32 |
+
///////////////////////////////////////////////////////////////////////////
|
33 |
+
// Internal character operations
|
34 |
+
|
35 |
+
// Copy characters from given range to given output iterator
|
36 |
+
template<class OutIt, class Ch>
|
37 |
+
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
38 |
+
{
|
39 |
+
while (begin != end)
|
40 |
+
*out++ = *begin++;
|
41 |
+
return out;
|
42 |
+
}
|
43 |
+
|
44 |
+
// Copy characters from given range to given output iterator and expand
|
45 |
+
// characters into references (< > ' " &)
|
46 |
+
template<class OutIt, class Ch>
|
47 |
+
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
|
48 |
+
{
|
49 |
+
while (begin != end)
|
50 |
+
{
|
51 |
+
if (*begin == noexpand)
|
52 |
+
{
|
53 |
+
*out++ = *begin; // No expansion, copy character
|
54 |
+
}
|
55 |
+
else
|
56 |
+
{
|
57 |
+
switch (*begin)
|
58 |
+
{
|
59 |
+
case Ch('<'):
|
60 |
+
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
|
61 |
+
break;
|
62 |
+
case Ch('>'):
|
63 |
+
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
|
64 |
+
break;
|
65 |
+
case Ch('\''):
|
66 |
+
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
|
67 |
+
break;
|
68 |
+
case Ch('"'):
|
69 |
+
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
|
70 |
+
break;
|
71 |
+
case Ch('&'):
|
72 |
+
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
|
73 |
+
break;
|
74 |
+
default:
|
75 |
+
*out++ = *begin; // No expansion, copy character
|
76 |
+
}
|
77 |
+
}
|
78 |
+
++begin; // Step to next character
|
79 |
+
}
|
80 |
+
return out;
|
81 |
+
}
|
82 |
+
|
83 |
+
// Fill given output iterator with repetitions of the same character
|
84 |
+
template<class OutIt, class Ch>
|
85 |
+
inline OutIt fill_chars(OutIt out, int n, Ch ch)
|
86 |
+
{
|
87 |
+
for (int i = 0; i < n; ++i)
|
88 |
+
*out++ = ch;
|
89 |
+
return out;
|
90 |
+
}
|
91 |
+
|
92 |
+
// Find character
|
93 |
+
template<class Ch, Ch ch>
|
94 |
+
inline bool find_char(const Ch *begin, const Ch *end)
|
95 |
+
{
|
96 |
+
while (begin != end)
|
97 |
+
if (*begin++ == ch)
|
98 |
+
return true;
|
99 |
+
return false;
|
100 |
+
}
|
101 |
+
|
102 |
+
///////////////////////////////////////////////////////////////////////////
|
103 |
+
// Internal printing operations
|
104 |
+
|
105 |
+
// Print node
|
106 |
+
template<class OutIt, class Ch>
|
107 |
+
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
108 |
+
{
|
109 |
+
// Print proper node type
|
110 |
+
switch (node->type())
|
111 |
+
{
|
112 |
+
|
113 |
+
// Document
|
114 |
+
case node_document:
|
115 |
+
out = print_children(out, node, flags, indent);
|
116 |
+
break;
|
117 |
+
|
118 |
+
// Element
|
119 |
+
case node_element:
|
120 |
+
out = print_element_node(out, node, flags, indent);
|
121 |
+
break;
|
122 |
+
|
123 |
+
// Data
|
124 |
+
case node_data:
|
125 |
+
out = print_data_node(out, node, flags, indent);
|
126 |
+
break;
|
127 |
+
|
128 |
+
// CDATA
|
129 |
+
case node_cdata:
|
130 |
+
out = print_cdata_node(out, node, flags, indent);
|
131 |
+
break;
|
132 |
+
|
133 |
+
// Declaration
|
134 |
+
case node_declaration:
|
135 |
+
out = print_declaration_node(out, node, flags, indent);
|
136 |
+
break;
|
137 |
+
|
138 |
+
// Comment
|
139 |
+
case node_comment:
|
140 |
+
out = print_comment_node(out, node, flags, indent);
|
141 |
+
break;
|
142 |
+
|
143 |
+
// Doctype
|
144 |
+
case node_doctype:
|
145 |
+
out = print_doctype_node(out, node, flags, indent);
|
146 |
+
break;
|
147 |
+
|
148 |
+
// Pi
|
149 |
+
case node_pi:
|
150 |
+
out = print_pi_node(out, node, flags, indent);
|
151 |
+
break;
|
152 |
+
|
153 |
+
// Unknown
|
154 |
+
default:
|
155 |
+
assert(0);
|
156 |
+
break;
|
157 |
+
}
|
158 |
+
|
159 |
+
// If indenting not disabled, add line break after node
|
160 |
+
if (!(flags & print_no_indenting))
|
161 |
+
*out = Ch('\n'), ++out;
|
162 |
+
|
163 |
+
// Return modified iterator
|
164 |
+
return out;
|
165 |
+
}
|
166 |
+
|
167 |
+
// Print children of the node
|
168 |
+
template<class OutIt, class Ch>
|
169 |
+
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
170 |
+
{
|
171 |
+
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
|
172 |
+
out = print_node(out, child, flags, indent);
|
173 |
+
return out;
|
174 |
+
}
|
175 |
+
|
176 |
+
// Print attributes of the node
|
177 |
+
template<class OutIt, class Ch>
|
178 |
+
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
|
179 |
+
{
|
180 |
+
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
181 |
+
{
|
182 |
+
if (attribute->name() && attribute->value())
|
183 |
+
{
|
184 |
+
// Print attribute name
|
185 |
+
*out = Ch(' '), ++out;
|
186 |
+
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
|
187 |
+
*out = Ch('='), ++out;
|
188 |
+
// Print attribute value using appropriate quote type
|
189 |
+
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
|
190 |
+
{
|
191 |
+
*out = Ch('\''), ++out;
|
192 |
+
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
|
193 |
+
*out = Ch('\''), ++out;
|
194 |
+
}
|
195 |
+
else
|
196 |
+
{
|
197 |
+
*out = Ch('"'), ++out;
|
198 |
+
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
|
199 |
+
*out = Ch('"'), ++out;
|
200 |
+
}
|
201 |
+
}
|
202 |
+
}
|
203 |
+
return out;
|
204 |
+
}
|
205 |
+
|
206 |
+
// Print data node
|
207 |
+
template<class OutIt, class Ch>
|
208 |
+
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
209 |
+
{
|
210 |
+
assert(node->type() == node_data);
|
211 |
+
if (!(flags & print_no_indenting))
|
212 |
+
out = fill_chars(out, indent, Ch('\t'));
|
213 |
+
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
214 |
+
return out;
|
215 |
+
}
|
216 |
+
|
217 |
+
// Print data node
|
218 |
+
template<class OutIt, class Ch>
|
219 |
+
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
220 |
+
{
|
221 |
+
assert(node->type() == node_cdata);
|
222 |
+
if (!(flags & print_no_indenting))
|
223 |
+
out = fill_chars(out, indent, Ch('\t'));
|
224 |
+
*out = Ch('<'); ++out;
|
225 |
+
*out = Ch('!'); ++out;
|
226 |
+
*out = Ch('['); ++out;
|
227 |
+
*out = Ch('C'); ++out;
|
228 |
+
*out = Ch('D'); ++out;
|
229 |
+
*out = Ch('A'); ++out;
|
230 |
+
*out = Ch('T'); ++out;
|
231 |
+
*out = Ch('A'); ++out;
|
232 |
+
*out = Ch('['); ++out;
|
233 |
+
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
234 |
+
*out = Ch(']'); ++out;
|
235 |
+
*out = Ch(']'); ++out;
|
236 |
+
*out = Ch('>'); ++out;
|
237 |
+
return out;
|
238 |
+
}
|
239 |
+
|
240 |
+
// Print element node
|
241 |
+
template<class OutIt, class Ch>
|
242 |
+
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
243 |
+
{
|
244 |
+
assert(node->type() == node_element);
|
245 |
+
|
246 |
+
// Print element name and attributes, if any
|
247 |
+
if (!(flags & print_no_indenting))
|
248 |
+
out = fill_chars(out, indent, Ch('\t'));
|
249 |
+
*out = Ch('<'), ++out;
|
250 |
+
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
251 |
+
out = print_attributes(out, node, flags);
|
252 |
+
|
253 |
+
// If node is childless
|
254 |
+
if (node->value_size() == 0 && !node->first_node())
|
255 |
+
{
|
256 |
+
// Print childless node tag ending
|
257 |
+
*out = Ch('/'), ++out;
|
258 |
+
*out = Ch('>'), ++out;
|
259 |
+
}
|
260 |
+
else
|
261 |
+
{
|
262 |
+
// Print normal node tag ending
|
263 |
+
*out = Ch('>'), ++out;
|
264 |
+
|
265 |
+
// Test if node contains a single data node only (and no other nodes)
|
266 |
+
xml_node<Ch> *child = node->first_node();
|
267 |
+
if (!child)
|
268 |
+
{
|
269 |
+
// If node has no children, only print its value without indenting
|
270 |
+
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
271 |
+
}
|
272 |
+
else if (child->next_sibling() == 0 && child->type() == node_data)
|
273 |
+
{
|
274 |
+
// If node has a sole data child, only print its value without indenting
|
275 |
+
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
|
276 |
+
}
|
277 |
+
else
|
278 |
+
{
|
279 |
+
// Print all children with full indenting
|
280 |
+
if (!(flags & print_no_indenting))
|
281 |
+
*out = Ch('\n'), ++out;
|
282 |
+
out = print_children(out, node, flags, indent + 1);
|
283 |
+
if (!(flags & print_no_indenting))
|
284 |
+
out = fill_chars(out, indent, Ch('\t'));
|
285 |
+
}
|
286 |
+
|
287 |
+
// Print node end
|
288 |
+
*out = Ch('<'), ++out;
|
289 |
+
*out = Ch('/'), ++out;
|
290 |
+
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
291 |
+
*out = Ch('>'), ++out;
|
292 |
+
}
|
293 |
+
return out;
|
294 |
+
}
|
295 |
+
|
296 |
+
// Print declaration node
|
297 |
+
template<class OutIt, class Ch>
|
298 |
+
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
299 |
+
{
|
300 |
+
// Print declaration start
|
301 |
+
if (!(flags & print_no_indenting))
|
302 |
+
out = fill_chars(out, indent, Ch('\t'));
|
303 |
+
*out = Ch('<'), ++out;
|
304 |
+
*out = Ch('?'), ++out;
|
305 |
+
*out = Ch('x'), ++out;
|
306 |
+
*out = Ch('m'), ++out;
|
307 |
+
*out = Ch('l'), ++out;
|
308 |
+
|
309 |
+
// Print attributes
|
310 |
+
out = print_attributes(out, node, flags);
|
311 |
+
|
312 |
+
// Print declaration end
|
313 |
+
*out = Ch('?'), ++out;
|
314 |
+
*out = Ch('>'), ++out;
|
315 |
+
|
316 |
+
return out;
|
317 |
+
}
|
318 |
+
|
319 |
+
// Print comment node
|
320 |
+
template<class OutIt, class Ch>
|
321 |
+
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
322 |
+
{
|
323 |
+
assert(node->type() == node_comment);
|
324 |
+
if (!(flags & print_no_indenting))
|
325 |
+
out = fill_chars(out, indent, Ch('\t'));
|
326 |
+
*out = Ch('<'), ++out;
|
327 |
+
*out = Ch('!'), ++out;
|
328 |
+
*out = Ch('-'), ++out;
|
329 |
+
*out = Ch('-'), ++out;
|
330 |
+
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
331 |
+
*out = Ch('-'), ++out;
|
332 |
+
*out = Ch('-'), ++out;
|
333 |
+
*out = Ch('>'), ++out;
|
334 |
+
return out;
|
335 |
+
}
|
336 |
+
|
337 |
+
// Print doctype node
|
338 |
+
template<class OutIt, class Ch>
|
339 |
+
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
340 |
+
{
|
341 |
+
assert(node->type() == node_doctype);
|
342 |
+
if (!(flags & print_no_indenting))
|
343 |
+
out = fill_chars(out, indent, Ch('\t'));
|
344 |
+
*out = Ch('<'), ++out;
|
345 |
+
*out = Ch('!'), ++out;
|
346 |
+
*out = Ch('D'), ++out;
|
347 |
+
*out = Ch('O'), ++out;
|
348 |
+
*out = Ch('C'), ++out;
|
349 |
+
*out = Ch('T'), ++out;
|
350 |
+
*out = Ch('Y'), ++out;
|
351 |
+
*out = Ch('P'), ++out;
|
352 |
+
*out = Ch('E'), ++out;
|
353 |
+
*out = Ch(' '), ++out;
|
354 |
+
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
355 |
+
*out = Ch('>'), ++out;
|
356 |
+
return out;
|
357 |
+
}
|
358 |
+
|
359 |
+
// Print pi node
|
360 |
+
template<class OutIt, class Ch>
|
361 |
+
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
362 |
+
{
|
363 |
+
assert(node->type() == node_pi);
|
364 |
+
if (!(flags & print_no_indenting))
|
365 |
+
out = fill_chars(out, indent, Ch('\t'));
|
366 |
+
*out = Ch('<'), ++out;
|
367 |
+
*out = Ch('?'), ++out;
|
368 |
+
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
369 |
+
*out = Ch(' '), ++out;
|
370 |
+
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
371 |
+
*out = Ch('?'), ++out;
|
372 |
+
*out = Ch('>'), ++out;
|
373 |
+
return out;
|
374 |
+
}
|
375 |
+
|
376 |
+
}
|
377 |
+
//! \endcond
|
378 |
+
|
379 |
+
///////////////////////////////////////////////////////////////////////////
|
380 |
+
// Printing
|
381 |
+
|
382 |
+
//! Prints XML to given output iterator.
|
383 |
+
//! \param out Output iterator to print to.
|
384 |
+
//! \param node Node to be printed. Pass xml_document to print entire document.
|
385 |
+
//! \param flags Flags controlling how XML is printed.
|
386 |
+
//! \return Output iterator pointing to position immediately after last character of printed text.
|
387 |
+
template<class OutIt, class Ch>
|
388 |
+
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
|
389 |
+
{
|
390 |
+
return internal::print_node(out, &node, flags, 0);
|
391 |
+
}
|
392 |
+
|
393 |
+
#ifndef RAPIDXML_NO_STREAMS
|
394 |
+
|
395 |
+
//! Prints XML to given output stream.
|
396 |
+
//! \param out Output stream to print to.
|
397 |
+
//! \param node Node to be printed. Pass xml_document to print entire document.
|
398 |
+
//! \param flags Flags controlling how XML is printed.
|
399 |
+
//! \return Output stream.
|
400 |
+
template<class Ch>
|
401 |
+
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
|
402 |
+
{
|
403 |
+
print(std::ostream_iterator<Ch>(out), node, flags);
|
404 |
+
return out;
|
405 |
+
}
|
406 |
+
|
407 |
+
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
|
408 |
+
//! \param out Output stream to print to.
|
409 |
+
//! \param node Node to be printed.
|
410 |
+
//! \return Output stream.
|
411 |
+
template<class Ch>
|
412 |
+
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
|
413 |
+
{
|
414 |
+
return print(out, node);
|
415 |
+
}
|
416 |
+
|
417 |
+
#endif
|
418 |
+
|
419 |
+
}
|
420 |
+
|
421 |
+
#endif
|
third-party/DPVO/Pangolin/components/pango_core/include/pangolin/utils/xml/rapidxml_utils.hpp
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
|
2 |
+
#define RAPIDXML_UTILS_HPP_INCLUDED
|
3 |
+
|
4 |
+
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
5 |
+
// Version 1.13
|
6 |
+
// Revision $DateTime: 2009/05/13 01:46:17 $
|
7 |
+
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
|
8 |
+
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
|
9 |
+
|
10 |
+
#include "rapidxml.hpp"
|
11 |
+
#include <vector>
|
12 |
+
#include <string>
|
13 |
+
#include <fstream>
|
14 |
+
#include <stdexcept>
|
15 |
+
|
16 |
+
namespace rapidxml
|
17 |
+
{
|
18 |
+
|
19 |
+
//! Represents data loaded from a file
|
20 |
+
template<class Ch = char>
|
21 |
+
class file
|
22 |
+
{
|
23 |
+
|
24 |
+
public:
|
25 |
+
|
26 |
+
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
|
27 |
+
//! \param filename Filename to load.
|
28 |
+
file(const char *filename)
|
29 |
+
{
|
30 |
+
using namespace std;
|
31 |
+
|
32 |
+
// Open stream
|
33 |
+
basic_ifstream<Ch> stream(filename, ios::binary);
|
34 |
+
if (!stream)
|
35 |
+
throw runtime_error(string("cannot open file ") + filename);
|
36 |
+
stream.unsetf(ios::skipws);
|
37 |
+
|
38 |
+
// Determine stream size
|
39 |
+
stream.seekg(0, ios::end);
|
40 |
+
size_t size = (size_t)stream.tellg();
|
41 |
+
stream.seekg(0);
|
42 |
+
|
43 |
+
// Load data and add terminating 0
|
44 |
+
m_data.resize(size + 1);
|
45 |
+
stream.read(&m_data.front(), static_cast<streamsize>(size));
|
46 |
+
m_data[size] = 0;
|
47 |
+
}
|
48 |
+
|
49 |
+
//! Loads file into the memory. Data will be automatically destroyed by the destructor
|
50 |
+
//! \param stream Stream to load from
|
51 |
+
file(std::basic_istream<Ch> &stream)
|
52 |
+
{
|
53 |
+
using namespace std;
|
54 |
+
|
55 |
+
// Load data and add terminating 0
|
56 |
+
stream.unsetf(ios::skipws);
|
57 |
+
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
|
58 |
+
if (stream.fail() || stream.bad())
|
59 |
+
throw runtime_error("error reading stream");
|
60 |
+
m_data.push_back(0);
|
61 |
+
}
|
62 |
+
|
63 |
+
//! Gets file data.
|
64 |
+
//! \return Pointer to data of file.
|
65 |
+
Ch *data()
|
66 |
+
{
|
67 |
+
return &m_data.front();
|
68 |
+
}
|
69 |
+
|
70 |
+
//! Gets file data.
|
71 |
+
//! \return Pointer to data of file.
|
72 |
+
const Ch *data() const
|
73 |
+
{
|
74 |
+
return &m_data.front();
|
75 |
+
}
|
76 |
+
|
77 |
+
//! Gets file data size.
|
78 |
+
//! \return Size of file data, in characters.
|
79 |
+
std::size_t size() const
|
80 |
+
{
|
81 |
+
return m_data.size();
|
82 |
+
}
|
83 |
+
|
84 |
+
private:
|
85 |
+
|
86 |
+
std::vector<Ch> m_data; // File data
|
87 |
+
|
88 |
+
};
|
89 |
+
|
90 |
+
//! Counts children of node. Time complexity is O(n).
|
91 |
+
//! \return Number of children of node
|
92 |
+
template<class Ch>
|
93 |
+
inline std::size_t count_children(xml_node<Ch> *node)
|
94 |
+
{
|
95 |
+
xml_node<Ch> *child = node->first_node();
|
96 |
+
std::size_t count = 0;
|
97 |
+
while (child)
|
98 |
+
{
|
99 |
+
++count;
|
100 |
+
child = child->next_sibling();
|
101 |
+
}
|
102 |
+
return count;
|
103 |
+
}
|
104 |
+
|
105 |
+
//! Counts attributes of node. Time complexity is O(n).
|
106 |
+
//! \return Number of attributes of node
|
107 |
+
template<class Ch>
|
108 |
+
inline std::size_t count_attributes(xml_node<Ch> *node)
|
109 |
+
{
|
110 |
+
xml_attribute<Ch> *attr = node->first_attribute();
|
111 |
+
std::size_t count = 0;
|
112 |
+
while (attr)
|
113 |
+
{
|
114 |
+
++count;
|
115 |
+
attr = attr->next_attribute();
|
116 |
+
}
|
117 |
+
return count;
|
118 |
+
}
|
119 |
+
|
120 |
+
}
|
121 |
+
|
122 |
+
#endif
|
third-party/DPVO/Pangolin/components/pango_core/include/sigslot/LICENCE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2017 Pierre-Antoine Lacaze
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
third-party/DPVO/Pangolin/components/pango_core/include/sigslot/README.md
ADDED
@@ -0,0 +1,717 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Sigslot, a signal-slot library
|
2 |
+
|
3 |
+
Sigslot is a header-only, thread safe implementation of signal-slots for C++.
|
4 |
+
|
5 |
+
## Features
|
6 |
+
|
7 |
+
The main goal was to replace Boost.Signals2.
|
8 |
+
|
9 |
+
Apart from the usual features, it offers
|
10 |
+
|
11 |
+
- Thread safety,
|
12 |
+
- Object lifetime tracking for automatic slot disconnection (extensible through ADL),
|
13 |
+
- RAII connection management,
|
14 |
+
- Slot groups to enforce slots execution order,
|
15 |
+
- Reasonable performance. and a simple and straightforward implementation.
|
16 |
+
|
17 |
+
Sigslot is unit-tested and should be reliable and stable enough to replace Boost Signals2.
|
18 |
+
|
19 |
+
The tests run cleanly under the address, thread and undefined behaviour sanitizers.
|
20 |
+
|
21 |
+
Many implementations allow signal return types, Sigslot does not because I have
|
22 |
+
no use for them. If I can be convinced of otherwise I may change my mind later on.
|
23 |
+
|
24 |
+
## Installation
|
25 |
+
|
26 |
+
No compilation or installation is required, just include `sigslot/signal.hpp`
|
27 |
+
and use it. Sigslot currently depends on a C++14 compliant compiler, but if need
|
28 |
+
arises it may be retrofitted to C++11. It is known to work with Clang 4.0 and GCC
|
29 |
+
5.0+ compilers on GNU Linux, MSVC 2017 and up, Clang-cl and MinGW on Windows.
|
30 |
+
|
31 |
+
However, be aware of a potential gotcha on Windows with MSVC and Clang-Cl compilers,
|
32 |
+
which may need the `/OPT:NOICF` linker flags in exceptional situations. Read The
|
33 |
+
Implementation Details chapter for an explanation.
|
34 |
+
|
35 |
+
A CMake list file is supplied for installation purpose and generating a CMake import
|
36 |
+
module. This is the preferred installation method. The `Pal::Sigslot` imported target
|
37 |
+
is available and already applies the needed linker flags. It is also required for
|
38 |
+
examples and tests, which optionally depend on Qt5 and Boost for adapters unit tests.
|
39 |
+
|
40 |
+
```cmake
|
41 |
+
# Using Sigslot from cmake
|
42 |
+
find_package(PalSigslot)
|
43 |
+
|
44 |
+
add_executable(MyExe main.cpp)
|
45 |
+
target_link_libraries(MyExe PRIVATE Pal::Sigslot)
|
46 |
+
```
|
47 |
+
|
48 |
+
A configuration option `SIGSLOT_REDUCE_COMPILE_TIME` is available at configuration
|
49 |
+
time. When activated, it attempts to reduce code bloat by avoiding heavy template
|
50 |
+
instantiations resulting from calls to `std::make_shared`.
|
51 |
+
This option is off by default, but can be activated for those who wish to favor
|
52 |
+
code size and compilation time at the expanse of slightly less efficient code.
|
53 |
+
|
54 |
+
Installation may be done using the following instructions from the root directory:
|
55 |
+
|
56 |
+
```sh
|
57 |
+
mkdir build && cd build
|
58 |
+
cmake .. -DSIGSLOT_REDUCE_COMPILE_TIME=ON -DCMAKE_INSTALL_PREFIX=~/local
|
59 |
+
cmake --build . --target install
|
60 |
+
|
61 |
+
# If you want to compile examples:
|
62 |
+
cmake --build . --target sigslot-examples
|
63 |
+
|
64 |
+
# And compile/execute unit tests:
|
65 |
+
cmake --build . --target sigslot-tests
|
66 |
+
```
|
67 |
+
|
68 |
+
### CMake FetchContent
|
69 |
+
|
70 |
+
`Pal::Sigslot` can also be integrated using the [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) method.
|
71 |
+
|
72 |
+
```cmake
|
73 |
+
include(FetchContent)
|
74 |
+
|
75 |
+
FetchContent_Declare(
|
76 |
+
sigslot
|
77 |
+
GIT_REPOSITORY https://github.com/palacaze/sigslot
|
78 |
+
GIT_TAG 19a6f0f5ea11fc121fe67f81fd5e491f2d7a4637 # v1.2.0
|
79 |
+
)
|
80 |
+
FetchContent_MakeAvailable(sigslot)
|
81 |
+
|
82 |
+
add_executable(MyExe main.cpp)
|
83 |
+
target_link_libraries(MyExe PRIVATE Pal::Sigslot)
|
84 |
+
```
|
85 |
+
|
86 |
+
## Documentation
|
87 |
+
|
88 |
+
Sigslot implements the signal-slot construct popular in UI frameworks, making it
|
89 |
+
easy to use the observer pattern or event-based programming. The main entry point
|
90 |
+
of the library is the `sigslot::signal<T...>` class template.
|
91 |
+
|
92 |
+
A signal is an object that can emit typed notifications, really values parametrized
|
93 |
+
after the signal class template parameters, and register any number of notification
|
94 |
+
handlers (callables) of compatible argument types to be executed with the values
|
95 |
+
supplied whenever a signal emission happens. In signal-slot parlance this is called
|
96 |
+
connecting a slot to a signal, where a "slot" represents a callable instance and
|
97 |
+
a "connection" can be thought of as a conceptual link from signal to slot.
|
98 |
+
|
99 |
+
All the snippets presented below are available in compilable source code form in
|
100 |
+
the example subdirectory.
|
101 |
+
|
102 |
+
### Basic usage
|
103 |
+
|
104 |
+
Here is a first example that showcases the most basic features of the library.
|
105 |
+
|
106 |
+
We first declare a parameter-free signal `sig`, then we proceed to connect several
|
107 |
+
slots and at last emit a signal which triggers the invocation of every slot callable
|
108 |
+
connected beforehand. Notice how The library handles diverse forms of callables.
|
109 |
+
|
110 |
+
```cpp
|
111 |
+
#include <sigslot/signal.hpp>
|
112 |
+
#include <iostream>
|
113 |
+
|
114 |
+
void f() { std::cout << "free function\n"; }
|
115 |
+
|
116 |
+
struct s {
|
117 |
+
void m() { std::cout << "member function\n"; }
|
118 |
+
static void sm() { std::cout << "static member function\n"; }
|
119 |
+
};
|
120 |
+
|
121 |
+
struct o {
|
122 |
+
void operator()() { std::cout << "function object\n"; }
|
123 |
+
};
|
124 |
+
|
125 |
+
int main() {
|
126 |
+
s d;
|
127 |
+
auto lambda = []() { std::cout << "lambda\n"; };
|
128 |
+
auto gen_lambda = [](auto && ...a) { std::cout << "generic lambda\n"; };
|
129 |
+
|
130 |
+
// declare a signal instance with no arguments
|
131 |
+
sigslot::signal<> sig;
|
132 |
+
|
133 |
+
// connect slots
|
134 |
+
sig.connect(f);
|
135 |
+
sig.connect(&s::m, &d);
|
136 |
+
sig.connect(&s::sm);
|
137 |
+
sig.connect(o());
|
138 |
+
sig.connect(lambda);
|
139 |
+
sig.connect(gen_lambda);
|
140 |
+
|
141 |
+
// emit a signal
|
142 |
+
sig();
|
143 |
+
}
|
144 |
+
```
|
145 |
+
|
146 |
+
By default, the slot invocation order when emitting a signal is unspecified, please
|
147 |
+
do not rely on it being always the same. You may constrain a particular invocation
|
148 |
+
order by using slot groups, which are presented later on.
|
149 |
+
|
150 |
+
### Signal with arguments
|
151 |
+
|
152 |
+
That first example was simple but not so useful, let us move on to a signal that
|
153 |
+
emits values instead. A signal can emit any number of arguments, below.
|
154 |
+
|
155 |
+
```cpp
|
156 |
+
#include <sigslot/signal.hpp>
|
157 |
+
#include <iostream>
|
158 |
+
#include <string>
|
159 |
+
|
160 |
+
struct foo {
|
161 |
+
// Notice how we accept a double as first argument here.
|
162 |
+
// This is fine because float is convertible to double.
|
163 |
+
// 's' is a reference and can thus be modified.
|
164 |
+
void bar(double d, int i, bool b, std::string &s) {
|
165 |
+
s = b ? std::to_string(i) : std::to_string(d);
|
166 |
+
}
|
167 |
+
};
|
168 |
+
|
169 |
+
// Function objects can cope with default arguments and overloading.
|
170 |
+
// It does not work with static and member functions.
|
171 |
+
struct obj {
|
172 |
+
void operator()(float, int, bool, std::string &, int = 0) {
|
173 |
+
std::cout << "I was here\n";
|
174 |
+
}
|
175 |
+
|
176 |
+
void operator()() {}
|
177 |
+
};
|
178 |
+
|
179 |
+
int main() {
|
180 |
+
// declare a signal with float, int, bool and string& arguments
|
181 |
+
sigslot::signal<float, int, bool, std::string&> sig;
|
182 |
+
|
183 |
+
// a generic lambda that prints its arguments to stdout
|
184 |
+
auto printer = [] (auto a, auto && ...args) {
|
185 |
+
std::cout << a;
|
186 |
+
(void)std::initializer_list<int>{
|
187 |
+
((void)(std::cout << " " << args), 1)...
|
188 |
+
};
|
189 |
+
std::cout << "\n";
|
190 |
+
};
|
191 |
+
|
192 |
+
// connect the slots
|
193 |
+
foo ff;
|
194 |
+
sig.connect(printer);
|
195 |
+
sig.connect(&foo::bar, &ff);
|
196 |
+
sig.connect(obj());
|
197 |
+
|
198 |
+
float f = 1.f;
|
199 |
+
short i = 2; // convertible to int
|
200 |
+
std::string s = "0";
|
201 |
+
|
202 |
+
// emit a signal
|
203 |
+
sig(f, i, false, s);
|
204 |
+
sig(f, i, true, s);
|
205 |
+
}
|
206 |
+
```
|
207 |
+
|
208 |
+
As shown, slots arguments types don't need to be strictly identical to the signal
|
209 |
+
template parameters, being convertible-from is fine. Generic arguments are fine too,
|
210 |
+
as shown with the `printer` generic lambda (which could have been written as a
|
211 |
+
function template too).
|
212 |
+
|
213 |
+
Right now there are two limitations that I can think of with respect to callable
|
214 |
+
handling: default arguments and function overloading. Both are working correctly
|
215 |
+
in the case of function objects but will fail to compile with static and member
|
216 |
+
functions, for different but related reasons.
|
217 |
+
|
218 |
+
#### Coping with overloaded functions
|
219 |
+
|
220 |
+
Consider the following piece of code:
|
221 |
+
|
222 |
+
```cpp
|
223 |
+
struct foo {
|
224 |
+
void bar(double d);
|
225 |
+
void bar();
|
226 |
+
};
|
227 |
+
```
|
228 |
+
|
229 |
+
What should `&foo::bar` refer to? As per overloading, this pointer over member
|
230 |
+
function does not map to a unique symbol, so the compiler won't be able to pick
|
231 |
+
the right symbol. One way of resolving the right symbol is to explicitly cast the
|
232 |
+
function pointer to the right function type. Here is an example that does just that
|
233 |
+
using a little helper tool for a lighter syntax (In fact I will probably add this
|
234 |
+
to the library soon).
|
235 |
+
|
236 |
+
```cpp
|
237 |
+
#include <sigslot/signal.hpp>
|
238 |
+
|
239 |
+
template <typename... Args, typename C>
|
240 |
+
constexpr auto overload(void (C::*ptr)(Args...)) {
|
241 |
+
return ptr;
|
242 |
+
}
|
243 |
+
|
244 |
+
template <typename... Args>
|
245 |
+
constexpr auto overload(void (*ptr)(Args...)) {
|
246 |
+
return ptr;
|
247 |
+
}
|
248 |
+
|
249 |
+
struct obj {
|
250 |
+
void operator()(int) const {}
|
251 |
+
void operator()() {}
|
252 |
+
};
|
253 |
+
|
254 |
+
struct foo {
|
255 |
+
void bar(int) {}
|
256 |
+
void bar() {}
|
257 |
+
|
258 |
+
static void baz(int) {}
|
259 |
+
static void baz() {}
|
260 |
+
};
|
261 |
+
|
262 |
+
void moo(int) {}
|
263 |
+
void moo() {}
|
264 |
+
|
265 |
+
int main() {
|
266 |
+
sigslot::signal<int> sig;
|
267 |
+
|
268 |
+
// connect the slots, casting to the right overload if necessary
|
269 |
+
foo ff;
|
270 |
+
sig.connect(overload<int>(&foo::bar), &ff);
|
271 |
+
sig.connect(overload<int>(&foo::baz));
|
272 |
+
sig.connect(overload<int>(&moo));
|
273 |
+
sig.connect(obj());
|
274 |
+
|
275 |
+
sig(0);
|
276 |
+
|
277 |
+
return 0;
|
278 |
+
}
|
279 |
+
```
|
280 |
+
|
281 |
+
#### Coping with function with default arguments
|
282 |
+
|
283 |
+
Default arguments are not part of the function type signature, and can be redefined,
|
284 |
+
so they are really difficult to deal with. When connecting a slot to a signal, the
|
285 |
+
library determines if the supplied callable can be invoked with the signal argument
|
286 |
+
types, but at this point the existence of default function arguments is unknown
|
287 |
+
so there might be a mismatch in the number of arguments.
|
288 |
+
|
289 |
+
A simple work around for this use case would is to create a bind adapter, in fact
|
290 |
+
we can even make it quite generic like so:
|
291 |
+
|
292 |
+
```cpp
|
293 |
+
#include <sigslot/signal.hpp>
|
294 |
+
|
295 |
+
#define ADAPT(func) \
|
296 |
+
[=](auto && ...a) { (func)(std::forward<decltype(a)>(a)...); }
|
297 |
+
|
298 |
+
void foo(int &i, int b = 1) {
|
299 |
+
i += b;
|
300 |
+
}
|
301 |
+
|
302 |
+
int main() {
|
303 |
+
int i = 0;
|
304 |
+
|
305 |
+
// fine, all the arguments are handled
|
306 |
+
sigslot::signal<int&, int> sig1;
|
307 |
+
sig1.connect(foo);
|
308 |
+
sig1(i, 2);
|
309 |
+
|
310 |
+
// must wrap in an adapter
|
311 |
+
i = 0;
|
312 |
+
sigslot::signal<int&> sig2;
|
313 |
+
sig2.connect(ADAPT(foo));
|
314 |
+
sig2(i);
|
315 |
+
|
316 |
+
return 0;
|
317 |
+
}
|
318 |
+
```
|
319 |
+
|
320 |
+
### Connection management
|
321 |
+
|
322 |
+
#### Connection object
|
323 |
+
|
324 |
+
What was not made apparent until now is that `signal::connect()` actually returns
|
325 |
+
a `sigslot::connection` object that may be used to manage the behaviour and lifetime
|
326 |
+
of a signal-slot connection. `sigslot::connection` is a lightweight object (basically
|
327 |
+
a `std::weak_ptr`) that allows interaction with an ongoing signal-slot connection
|
328 |
+
and exposes the following features:
|
329 |
+
|
330 |
+
- Status querying, that is testing whether a connection is valid, ongoing or facing destruction,
|
331 |
+
- Connection (un)blocking, which allows to temporarily disable the invocation of a slot when a signal is emitted,
|
332 |
+
- Disconnection of a slot, the destruction of a connection previously created via `signal::connect()`.
|
333 |
+
|
334 |
+
A `sigslot::connection` does not tie a connection to a scope: this is not a RAII
|
335 |
+
object, which explains why it can be copied. It can be however implicitly converted
|
336 |
+
into a `sigslot::scoped_connection` which destroys the connection when going out
|
337 |
+
of scope.
|
338 |
+
|
339 |
+
Here is an example illustrating some of those features:
|
340 |
+
|
341 |
+
```cpp
|
342 |
+
#include <sigslot/signal.hpp>
|
343 |
+
#include <string>
|
344 |
+
|
345 |
+
int i = 0;
|
346 |
+
|
347 |
+
void f() { i += 1; }
|
348 |
+
|
349 |
+
int main() {
|
350 |
+
sigslot::signal<> sig;
|
351 |
+
|
352 |
+
// keep a sigslot::connection object
|
353 |
+
auto c1 = sig.connect(f);
|
354 |
+
|
355 |
+
// disconnection
|
356 |
+
sig(); // i == 1
|
357 |
+
c1.disconnect();
|
358 |
+
sig(); // i == 1
|
359 |
+
|
360 |
+
// scope based disconnection
|
361 |
+
{
|
362 |
+
sigslot::scoped_connection sc = sig.connect(f);
|
363 |
+
sig(); // i == 2
|
364 |
+
}
|
365 |
+
|
366 |
+
sig(); // i == 2;
|
367 |
+
|
368 |
+
|
369 |
+
// connection blocking
|
370 |
+
auto c2 = sig.connect(f);
|
371 |
+
sig(); // i == 3
|
372 |
+
c2.block();
|
373 |
+
sig(); // i == 3
|
374 |
+
c2.unblock();
|
375 |
+
sig(); // i == 4
|
376 |
+
}
|
377 |
+
```
|
378 |
+
|
379 |
+
#### Extended connection signature
|
380 |
+
|
381 |
+
Sigslot supports an extended slot signature with an additional `sigslot::connection`
|
382 |
+
reference as first argument, which permits connection management from inside the
|
383 |
+
slot. This extended signature is accessible using the `connect_extended()` method.
|
384 |
+
|
385 |
+
```cpp
|
386 |
+
#include <sigslot/signal.hpp>
|
387 |
+
|
388 |
+
int main() {
|
389 |
+
int i = 0;
|
390 |
+
sigslot::signal<> sig;
|
391 |
+
|
392 |
+
// extended connection
|
393 |
+
auto f = [](auto &con) {
|
394 |
+
i += 1; // do work
|
395 |
+
con.disconnect(); // then disconnects
|
396 |
+
};
|
397 |
+
|
398 |
+
sig.connect_extended(f);
|
399 |
+
sig(); // i == 1
|
400 |
+
sig(); // i == 1 because f was disconnected
|
401 |
+
}
|
402 |
+
```
|
403 |
+
|
404 |
+
#### Automatic slot lifetime tracking
|
405 |
+
|
406 |
+
The user must make sure that the lifetime of a slot exceeds the one of a signal,
|
407 |
+
which may get tedious in complex software. To simplify this task, Sigslot can
|
408 |
+
automatically disconnect slot object whose lifetime it is able to track. In order
|
409 |
+
to do that, the slot must be convertible to a weak pointer of some form.
|
410 |
+
|
411 |
+
`std::shared_ptr` and `std::weak_ptr` are supported out of the box, and adapters
|
412 |
+
are provided to support `boost::shared_ptr`, `boost::weak_ptr` and Qt `QSharedPointer`,
|
413 |
+
`QWeakPointer` and any class deriving from `QObject`.
|
414 |
+
|
415 |
+
Other trackable objects can be added by declaring a `to_weak()` adapter function.
|
416 |
+
|
417 |
+
```cpp
|
418 |
+
#include <sigslot/signal.hpp>
|
419 |
+
#include <sigslot/adapter/qt.hpp>
|
420 |
+
|
421 |
+
int sum = 0;
|
422 |
+
|
423 |
+
struct s {
|
424 |
+
void f(int i) { sum += i; }
|
425 |
+
};
|
426 |
+
|
427 |
+
class MyObject : public QObject {
|
428 |
+
Q_OBJECT
|
429 |
+
public:
|
430 |
+
void add(int i) const { sum += i; }
|
431 |
+
};
|
432 |
+
|
433 |
+
int main() {
|
434 |
+
sum = 0;
|
435 |
+
signal<int> sig;
|
436 |
+
|
437 |
+
// track lifetime of object and also connect to a member function
|
438 |
+
auto p = std::make_shared<s>();
|
439 |
+
sig.connect(&s::f, p);
|
440 |
+
|
441 |
+
sig(1); // sum == 1
|
442 |
+
p.reset();
|
443 |
+
sig(1); // sum == 1
|
444 |
+
|
445 |
+
// track an unrelated object lifetime
|
446 |
+
struct dummy;
|
447 |
+
auto l = [&](int i) { sum += i; };
|
448 |
+
|
449 |
+
auto d = std::make_shared<dummy>();
|
450 |
+
sig.connect(l, d);
|
451 |
+
sig(1); // sum == 2
|
452 |
+
d.reset();
|
453 |
+
sig(1); // sum == 2
|
454 |
+
|
455 |
+
// track a QObject
|
456 |
+
{
|
457 |
+
MyObject o;
|
458 |
+
sig.connect(&MyObject::add, &o);
|
459 |
+
|
460 |
+
sig(1); // sum == 3
|
461 |
+
}
|
462 |
+
|
463 |
+
sig(1); // sum == 3
|
464 |
+
}
|
465 |
+
```
|
466 |
+
|
467 |
+
#### Intrusive slot lifetime tracking
|
468 |
+
|
469 |
+
Another way of ensuring automatic disconnection of pointer over member functions
|
470 |
+
slots is by explicitly inheriting from `sigslot::observer` or `sigslot::observer_st`.
|
471 |
+
The former is thread-safe, contrary to the later.
|
472 |
+
|
473 |
+
Here is an example usage.
|
474 |
+
|
475 |
+
```cpp
|
476 |
+
#include <sigslot/signal.hpp>
|
477 |
+
|
478 |
+
int sum = 0;
|
479 |
+
|
480 |
+
struct s : sigslot::observer_st {
|
481 |
+
void f(int i) { sum += i; }
|
482 |
+
};
|
483 |
+
|
484 |
+
struct s_mt : sigslot::observer {
|
485 |
+
~s_mt() {
|
486 |
+
// Needed to ensure proper disconnection prior to object destruction
|
487 |
+
// in multithreaded contexts.
|
488 |
+
this->disconnect_all();
|
489 |
+
}
|
490 |
+
|
491 |
+
void f(int i) { sum += i; }
|
492 |
+
};
|
493 |
+
|
494 |
+
int main() {
|
495 |
+
sum = 0;
|
496 |
+
signal<int> sig;
|
497 |
+
|
498 |
+
{
|
499 |
+
// Lifetime of object instance p is tracked
|
500 |
+
s p;
|
501 |
+
s_mt pm;
|
502 |
+
sig.connect(&s::f, &p);
|
503 |
+
sig.connect(&s_mt::f, &pm);
|
504 |
+
sig(1); // sum == 2
|
505 |
+
}
|
506 |
+
|
507 |
+
// The slots got disconnected at instance destruction
|
508 |
+
sig(1); // sum == 2
|
509 |
+
}
|
510 |
+
```
|
511 |
+
|
512 |
+
The objects that use this intrusive approach may be connected to any number of
|
513 |
+
unrelated signals.
|
514 |
+
|
515 |
+
### Disconnection without a connection object
|
516 |
+
|
517 |
+
Support for slot disconnection by supplying an appropriate function signature,
|
518 |
+
object pointer or tracker has been introduced in version 1.2.0.
|
519 |
+
|
520 |
+
One can disconnect any number of slots using the `signal::disconnect()` method,
|
521 |
+
which proposes 4 overloads to specify the disconnection criterion:
|
522 |
+
|
523 |
+
- The first takes a reference to a callable. Any kind of callable can be passed,
|
524 |
+
even pointers to member functions, function objects and lambdas,
|
525 |
+
- The second takes a pointer to an object, for slots bound to a pointer to member
|
526 |
+
function, or a tracking object,
|
527 |
+
- The third overload takes both kinds of arguments at the same time and can be
|
528 |
+
used to pinpoint a specific pair of object + callable.
|
529 |
+
- The last overload takes a group id and disconnects all the slots in this group.
|
530 |
+
|
531 |
+
Disconnection of lambdas is only possible for lambdas bound to a variable, due
|
532 |
+
to their uniqueness.
|
533 |
+
|
534 |
+
The second overload currently needs RTTI to disconnect from pointers to member
|
535 |
+
functions, function objects and lambdas. This limitation does not apply to free
|
536 |
+
and static member functions. The reasons stems from the fact that in C++, pointers
|
537 |
+
to member functions of unrelated types are not comparable, contrary to pointers to
|
538 |
+
free and static member functions. For instance, the pointer to member functions of
|
539 |
+
virtual methods of different classes can have the same address (they kind of store
|
540 |
+
the offset of the method into the vtable).
|
541 |
+
|
542 |
+
However, Sigslot can be compiled with RTTI disabled and the overload will be
|
543 |
+
deactivated for problematic cases.
|
544 |
+
|
545 |
+
As a side node, this feature admittedly added more code than anticipated at first
|
546 |
+
because it is a tricky and easy to get wrong. It has been designed carefully, with
|
547 |
+
correctness in mind, and does not have any hidden costs unless you actually use it.
|
548 |
+
|
549 |
+
Here is an example demonstrating the feature.
|
550 |
+
|
551 |
+
```cpp
|
552 |
+
#include <sigslot/signal.hpp>
|
553 |
+
#include <string>
|
554 |
+
|
555 |
+
static int i = 0;
|
556 |
+
|
557 |
+
void f1() { i += 1; }
|
558 |
+
void f2() { i += 1; }
|
559 |
+
|
560 |
+
struct s {
|
561 |
+
void m1() { i += 1; }
|
562 |
+
void m2() { i += 1; }
|
563 |
+
void m3() { i += 1; }
|
564 |
+
};
|
565 |
+
|
566 |
+
struct o {
|
567 |
+
void operator()() { i += 1; }
|
568 |
+
};
|
569 |
+
|
570 |
+
int main() {
|
571 |
+
sigslot::signal<> sig;
|
572 |
+
s s1;
|
573 |
+
auto s2 = std::make_shared<s>();
|
574 |
+
|
575 |
+
auto lbd = [&] { i += 1; };
|
576 |
+
|
577 |
+
sig.connect(f1); // #1
|
578 |
+
sig.connect(f2); // #2
|
579 |
+
sig.connect(&s::m1, &s1); // #3
|
580 |
+
sig.connect(&s::m2, &s1); // #4
|
581 |
+
sig.connect(&s::m3, &s1); // #5
|
582 |
+
sig.connect(&s::m1, s2); // #6
|
583 |
+
sig.connect(&s::m2, s2); // #7
|
584 |
+
sig.connect(o{}); // #8
|
585 |
+
sig.connect(lbd); // #9
|
586 |
+
|
587 |
+
sig(); // i == 9
|
588 |
+
|
589 |
+
sig.disconnect(f2); // #2 is removed
|
590 |
+
sig.disconnect(&s::m1); // #3 and #6 are removed
|
591 |
+
sig.disconnect(o{}); // #8 and is removed
|
592 |
+
// sig.disconnect(&o::operator()); // same as the above, more efficient
|
593 |
+
sig.disconnect(lbd); // #9 and is removed
|
594 |
+
sig.disconnect(s2); // #7 is removed
|
595 |
+
sig.disconnect(&s::m3, &s1); // #5 is removed, not #4
|
596 |
+
|
597 |
+
sig(); // i == 11
|
598 |
+
|
599 |
+
sig.disconnect_all(); // remove all remaining slots
|
600 |
+
return 0;
|
601 |
+
}
|
602 |
+
```
|
603 |
+
|
604 |
+
### Enforcing slot invocation order with slot groups
|
605 |
+
|
606 |
+
From version 1.2.0, slots can be assigned a group id in order to control the
|
607 |
+
relative order of invocation of slots.
|
608 |
+
|
609 |
+
The order of invocation of slots in a same group is unspecified and should not be
|
610 |
+
relied upon, however slot groups are invoked in ascending group id order.
|
611 |
+
When the group id of a slot is not set, it is assigned to the group 0.
|
612 |
+
Group ids can have any value in the range of signed 32 bit integers.
|
613 |
+
|
614 |
+
```cpp
|
615 |
+
#include <sigslot/signal.hpp>
|
616 |
+
#include <cstdio>
|
617 |
+
#include <limits>
|
618 |
+
|
619 |
+
int main() {
|
620 |
+
sigslot::signal<> sig;
|
621 |
+
|
622 |
+
// simply assigning a group id as last argument to connect
|
623 |
+
sig.connect([] { std::puts("Second"); }, 1);
|
624 |
+
sig.connect([] { std::puts("Last"); }, std::numeric_limits<sigslot::group_id>::max());
|
625 |
+
sig.connect([] { std::puts("First"); }, -10);
|
626 |
+
sig();
|
627 |
+
|
628 |
+
return 0;
|
629 |
+
}
|
630 |
+
```
|
631 |
+
|
632 |
+
### Thread safety
|
633 |
+
|
634 |
+
Thread safety is unit-tested. In particular, cross-signal emission and recursive
|
635 |
+
emission run fine in a multiple threads scenario.
|
636 |
+
|
637 |
+
`sigslot::signal` is a typedef to the more general `sigslot::signal_base` template
|
638 |
+
class, whose first template argument must be a Lockable type. This type will dictate
|
639 |
+
the locking policy of the class.
|
640 |
+
|
641 |
+
Sigslot offers 2 typedefs,
|
642 |
+
|
643 |
+
- `sigslot::signal` usable from multiple threads and uses std::mutex as a lockable.
|
644 |
+
In particular, connection, disconnection, emission and slot execution are thread
|
645 |
+
safe. It is also safe with recursive signal emission.
|
646 |
+
- `sigslot::signal_st` is a non thread-safe alternative, it trades safety for slightly
|
647 |
+
faster operation.
|
648 |
+
|
649 |
+
|
650 |
+
## Implementation details
|
651 |
+
|
652 |
+
### Using function pointers to disconnect slots
|
653 |
+
|
654 |
+
Comparing function pointers is a nightmare in C++. Here is a table demonstrating
|
655 |
+
the size and address of a variety of cases as a showcase:
|
656 |
+
|
657 |
+
```cpp
|
658 |
+
void fun() {}
|
659 |
+
|
660 |
+
struct b1 {
|
661 |
+
virtual ~b1() = default;
|
662 |
+
static void sm() {}
|
663 |
+
void m() {}
|
664 |
+
virtual void vm() {}
|
665 |
+
};
|
666 |
+
|
667 |
+
struct b2 {
|
668 |
+
virtual ~b2() = default;
|
669 |
+
static void sm() {}
|
670 |
+
void m() {}
|
671 |
+
virtual void vm() {}
|
672 |
+
};
|
673 |
+
|
674 |
+
struct c {
|
675 |
+
virtual ~c() = default;
|
676 |
+
virtual void w() {}
|
677 |
+
};
|
678 |
+
|
679 |
+
struct d : b1 {
|
680 |
+
static void sm() {}
|
681 |
+
void m() {}
|
682 |
+
void vm() override {}
|
683 |
+
};
|
684 |
+
|
685 |
+
struct e : b1, c {
|
686 |
+
static void sm() {}
|
687 |
+
void m() {}
|
688 |
+
void vm() override{}
|
689 |
+
};
|
690 |
+
```
|
691 |
+
|
692 |
+
| Symbol | GCC 9 Linux 64<br>Sizeof | GCC 9 Linux 64<br>Address | MSVC 16.6 32<br>Sizeof | MSVC 16.6 32<br>Address | GCC 8 Mingw 32<br>Sizeof | GCC 8 Mingw 32<br>Address | Clang-cl 9 32<br>Sizeof | Clang-cl 9 32<br>Address |
|
693 |
+
|---------|--------------------------|---------------------------|------------------------|-------------------------|--------------------------|---------------------------|-------------------------|--------------------------|
|
694 |
+
| fun | 8 | 0x802340 | 4 | 0x1311A6 | 4 | 0xF41540 | 4 | 0x0010AE |
|
695 |
+
| &b1::sm | 8 | 0xE03140 | 4 | 0x7612A5 | 4 | 0x308D40 | 4 | 0x0010AE |
|
696 |
+
| &b1::m | 16 | 0xF03240 | 4 | 0x1514A5 | 8 | 0x248D40 | 4 | 0x0010AE |
|
697 |
+
| &b1::vm | 16 | 0x11 | 4 | 0x9F11A5 | 8 | 0x09 | 4 | 0x8023AE |
|
698 |
+
| &b2::sm | 8 | 0x003340 | 4 | 0xA515A5 | 4 | 0x408D40 | 4 | 0x0010AE |
|
699 |
+
| &b2::m | 16 | 0x103440 | 4 | 0xEB10A5 | 8 | 0x348D40 | 4 | 0x0010AE |
|
700 |
+
| &b2::vm | 16 | 0x11 | 4 | 0x6A14A5 | 8 | 0x09 | 4 | 0x8023AE |
|
701 |
+
| &d::sm | 8 | 0x203440 | 4 | 0x2612A5 | 4 | 0x108D40 | 4 | 0x0010AE |
|
702 |
+
| &d::m | 16 | 0x303540 | 4 | 0x9D13A5 | 8 | 0x048D40 | 4 | 0x0010AE |
|
703 |
+
| &d::vm | 16 | 0x11 | 4 | 0x4412A5 | 8 | 0x09 | 4 | 0x8023AE |
|
704 |
+
| &e::sm | 8 | 0x403540 | 4 | 0xF911A5 | 4 | 0x208D40 | 4 | 0x0010AE |
|
705 |
+
| &e::m | 16 | 0x503640 | 8 | 0x8111A5 | 8 | 0x148D40 | 8 | 0x0010AE |
|
706 |
+
| &e::vm | 16 | 0x11 | 8 | 0xA911A5 | 8 | 0x09 | 8 | 0x8023AE |
|
707 |
+
|
708 |
+
MSVC and Clang-cl in Release mode optimize functions with the same definition by
|
709 |
+
merging them. This is a behaviour that can be deactivated with the `/OPT:NOICF`
|
710 |
+
linker option.
|
711 |
+
Sigslot tests and examples rely on a lot a identical callables which trigger this
|
712 |
+
behaviour, which is why it deactivates this particular optimization on the affected
|
713 |
+
compilers.
|
714 |
+
|
715 |
+
### Known bugs
|
716 |
+
|
717 |
+
Using generic lambdas with GCC less than version 7.4 can trigger [Bug #68071](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68071).
|
third-party/DPVO/Pangolin/components/pango_core/include/sigslot/signal.hpp
ADDED
@@ -0,0 +1,1611 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
#include <atomic>
|
3 |
+
#include <memory>
|
4 |
+
#include <mutex>
|
5 |
+
#include <type_traits>
|
6 |
+
#include <utility>
|
7 |
+
#include <thread>
|
8 |
+
#include <vector>
|
9 |
+
|
10 |
+
#if defined __clang__ || (__GNUC__ > 5)
|
11 |
+
#define SIGSLOT_MAY_ALIAS __attribute__((__may_alias__))
|
12 |
+
#else
|
13 |
+
#define SIGSLOT_MAY_ALIAS
|
14 |
+
#endif
|
15 |
+
|
16 |
+
#if defined(__GXX_RTTI) || defined(__cpp_rtti) || defined(_CPPRTTI)
|
17 |
+
#define SIGSLOT_RTTI_ENABLED 1
|
18 |
+
#include <typeinfo>
|
19 |
+
#endif
|
20 |
+
|
21 |
+
namespace sigslot {
|
22 |
+
|
23 |
+
namespace detail {
|
24 |
+
|
25 |
+
// Used to detect an object of observer type
|
26 |
+
struct observer_type {};
|
27 |
+
|
28 |
+
} // namespace detail
|
29 |
+
|
30 |
+
namespace trait {
|
31 |
+
|
32 |
+
/// represent a list of types
|
33 |
+
template <typename...> struct typelist {};
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Pointers that can be converted to a weak pointer concept for tracking
|
37 |
+
* purpose must implement the to_weak() function in order to make use of
|
38 |
+
* ADL to convert that type and make it usable
|
39 |
+
*/
|
40 |
+
|
41 |
+
template <typename T>
|
42 |
+
std::weak_ptr<T> to_weak(std::weak_ptr<T> w) {
|
43 |
+
return w;
|
44 |
+
}
|
45 |
+
|
46 |
+
template <typename T>
|
47 |
+
std::weak_ptr<T> to_weak(std::shared_ptr<T> s) {
|
48 |
+
return s;
|
49 |
+
}
|
50 |
+
|
51 |
+
// tools
|
52 |
+
namespace detail {
|
53 |
+
|
54 |
+
template <typename...>
|
55 |
+
struct voider { using type = void; };
|
56 |
+
|
57 |
+
// void_t from c++17
|
58 |
+
template <typename...T>
|
59 |
+
using void_t = typename detail::voider<T...>::type;
|
60 |
+
|
61 |
+
template <typename, typename = void>
|
62 |
+
struct has_call_operator : std::false_type {};
|
63 |
+
|
64 |
+
template <typename F>
|
65 |
+
struct has_call_operator<F, void_t<decltype(&std::remove_reference<F>::type::operator())>>
|
66 |
+
: std::true_type {};
|
67 |
+
|
68 |
+
template <typename, typename, typename = void, typename = void>
|
69 |
+
struct is_callable : std::false_type {};
|
70 |
+
|
71 |
+
template <typename F, typename P, typename... T>
|
72 |
+
struct is_callable<F, P, typelist<T...>,
|
73 |
+
void_t<decltype(((*std::declval<P>()).*std::declval<F>())(std::declval<T>()...))>>
|
74 |
+
: std::true_type {};
|
75 |
+
|
76 |
+
template <typename F, typename... T>
|
77 |
+
struct is_callable<F, typelist<T...>,
|
78 |
+
void_t<decltype(std::declval<F>()(std::declval<T>()...))>>
|
79 |
+
: std::true_type {};
|
80 |
+
|
81 |
+
|
82 |
+
template <typename T, typename = void>
|
83 |
+
struct is_weak_ptr : std::false_type {};
|
84 |
+
|
85 |
+
template <typename T>
|
86 |
+
struct is_weak_ptr<T, void_t<decltype(std::declval<T>().expired()),
|
87 |
+
decltype(std::declval<T>().lock()),
|
88 |
+
decltype(std::declval<T>().reset())>>
|
89 |
+
: std::true_type {};
|
90 |
+
|
91 |
+
template <typename T, typename = void>
|
92 |
+
struct is_weak_ptr_compatible : std::false_type {};
|
93 |
+
|
94 |
+
template <typename T>
|
95 |
+
struct is_weak_ptr_compatible<T, void_t<decltype(to_weak(std::declval<T>()))>>
|
96 |
+
: is_weak_ptr<decltype(to_weak(std::declval<T>()))> {};
|
97 |
+
|
98 |
+
} // namespace detail
|
99 |
+
|
100 |
+
static constexpr bool with_rtti =
|
101 |
+
#ifdef SIGSLOT_RTTI_ENABLED
|
102 |
+
true;
|
103 |
+
#else
|
104 |
+
false;
|
105 |
+
#endif
|
106 |
+
|
107 |
+
/// determine if a pointer is convertible into a "weak" pointer
|
108 |
+
template <typename P>
|
109 |
+
constexpr bool is_weak_ptr_compatible_v = detail::is_weak_ptr_compatible<std::decay_t<P>>::value;
|
110 |
+
|
111 |
+
/// determine if a type T (Callable or Pmf) is callable with supplied arguments
|
112 |
+
template <typename L, typename... T>
|
113 |
+
constexpr bool is_callable_v = detail::is_callable<T..., L>::value;
|
114 |
+
|
115 |
+
template <typename T>
|
116 |
+
constexpr bool is_weak_ptr_v = detail::is_weak_ptr<T>::value;
|
117 |
+
|
118 |
+
template <typename T>
|
119 |
+
constexpr bool has_call_operator_v = detail::has_call_operator<T>::value;
|
120 |
+
|
121 |
+
template <typename T>
|
122 |
+
constexpr bool is_pointer_v = std::is_pointer<T>::value;
|
123 |
+
|
124 |
+
template <typename T>
|
125 |
+
constexpr bool is_func_v = std::is_function<T>::value;
|
126 |
+
|
127 |
+
template <typename T>
|
128 |
+
constexpr bool is_pmf_v = std::is_member_function_pointer<T>::value;
|
129 |
+
|
130 |
+
template <typename T>
|
131 |
+
constexpr bool is_observer_v = std::is_base_of<::sigslot::detail::observer_type,
|
132 |
+
std::remove_pointer_t<T>>::value;
|
133 |
+
|
134 |
+
} // namespace trait
|
135 |
+
|
136 |
+
template <typename, typename...>
|
137 |
+
class signal_base;
|
138 |
+
|
139 |
+
/**
|
140 |
+
* A group_id is used to identify a group of slots
|
141 |
+
*/
|
142 |
+
using group_id = std::int32_t;
|
143 |
+
|
144 |
+
namespace detail {
|
145 |
+
|
146 |
+
/**
|
147 |
+
* The following function_traits and object_pointer series of templates are
|
148 |
+
* used to circumvent the type-erasing that takes place in the slot_base
|
149 |
+
* implementations. They are used to compare the stored functions and objects
|
150 |
+
* with another one for disconnection purpose.
|
151 |
+
*/
|
152 |
+
|
153 |
+
/*
|
154 |
+
* Function pointers and member function pointers size differ from compiler to
|
155 |
+
* compiler, and for virtual members compared to non virtual members. On some
|
156 |
+
* compilers, multiple inheritance has an impact too. Hence, we form an union
|
157 |
+
* big enough to store any kind of function pointer.
|
158 |
+
*/
|
159 |
+
namespace mock {
|
160 |
+
|
161 |
+
struct a { virtual ~a() = default; void f(); virtual void g(); };
|
162 |
+
struct b { virtual ~b() = default; virtual void h(); };
|
163 |
+
struct c : a, b { void g() override; };
|
164 |
+
|
165 |
+
union fun_types {
|
166 |
+
decltype(&c::g) m;
|
167 |
+
decltype(&a::g) v;
|
168 |
+
decltype(&a::f) d;
|
169 |
+
void (*f)();
|
170 |
+
void *o;
|
171 |
+
};
|
172 |
+
|
173 |
+
} // namespace mock
|
174 |
+
|
175 |
+
/*
|
176 |
+
* This union is used to compare function pointers
|
177 |
+
* Generic callables cannot be compared. Here we compare pointers but there is
|
178 |
+
* no guarantee that this always works.
|
179 |
+
*/
|
180 |
+
union SIGSLOT_MAY_ALIAS func_ptr {
|
181 |
+
void* value() {
|
182 |
+
return &data[0];
|
183 |
+
}
|
184 |
+
|
185 |
+
const void* value() const {
|
186 |
+
return &data[0];
|
187 |
+
}
|
188 |
+
|
189 |
+
template <typename T>
|
190 |
+
T& value() {
|
191 |
+
return *static_cast<T*>(value());
|
192 |
+
}
|
193 |
+
|
194 |
+
template <typename T>
|
195 |
+
const T& value() const {
|
196 |
+
return *static_cast<const T*>(value());
|
197 |
+
}
|
198 |
+
|
199 |
+
inline explicit operator bool() const {
|
200 |
+
return value() != nullptr;
|
201 |
+
}
|
202 |
+
|
203 |
+
inline bool operator==(const func_ptr &o) const {
|
204 |
+
return std::equal(std::begin(data), std::end(data), std::begin(o.data));
|
205 |
+
}
|
206 |
+
|
207 |
+
mock::fun_types _;
|
208 |
+
char data[sizeof(mock::fun_types)];
|
209 |
+
};
|
210 |
+
|
211 |
+
|
212 |
+
template <typename T, typename = void>
|
213 |
+
struct function_traits {
|
214 |
+
static void ptr(const T &/*t*/, func_ptr &d) {
|
215 |
+
d.value<std::nullptr_t>() = nullptr;
|
216 |
+
}
|
217 |
+
|
218 |
+
static constexpr bool is_disconnectable = false;
|
219 |
+
static constexpr bool must_check_object = true;
|
220 |
+
};
|
221 |
+
|
222 |
+
template <typename T>
|
223 |
+
struct function_traits<T, std::enable_if_t<trait::is_func_v<T>>> {
|
224 |
+
static void ptr(T &t, func_ptr &d) {
|
225 |
+
d.value<T*>() = &t;
|
226 |
+
}
|
227 |
+
|
228 |
+
static constexpr bool is_disconnectable = true;
|
229 |
+
static constexpr bool must_check_object = false;
|
230 |
+
};
|
231 |
+
|
232 |
+
template <typename T>
|
233 |
+
struct function_traits<T*, std::enable_if_t<trait::is_func_v<T>>> {
|
234 |
+
static void ptr(T *t, func_ptr &d) {
|
235 |
+
d.value<T*>() = t;
|
236 |
+
}
|
237 |
+
|
238 |
+
static constexpr bool is_disconnectable = true;
|
239 |
+
static constexpr bool must_check_object = false;
|
240 |
+
};
|
241 |
+
|
242 |
+
template <typename T>
|
243 |
+
struct function_traits<T, std::enable_if_t<trait::is_pmf_v<T>>> {
|
244 |
+
static void ptr(const T &t, func_ptr &d) {
|
245 |
+
d.value<T>() = t;
|
246 |
+
}
|
247 |
+
|
248 |
+
static constexpr bool is_disconnectable = trait::with_rtti;
|
249 |
+
static constexpr bool must_check_object = true;
|
250 |
+
};
|
251 |
+
|
252 |
+
// for function objects, the assumption is that we are looking for the call operator
|
253 |
+
template <typename T>
|
254 |
+
struct function_traits<T, std::enable_if_t<trait::has_call_operator_v<T>>> {
|
255 |
+
using call_type = decltype(&std::remove_reference<T>::type::operator());
|
256 |
+
|
257 |
+
static void ptr(const T &/*t*/, func_ptr &d) {
|
258 |
+
function_traits<call_type>::ptr(&T::operator(), d);
|
259 |
+
}
|
260 |
+
|
261 |
+
static constexpr bool is_disconnectable = function_traits<call_type>::is_disconnectable;
|
262 |
+
static constexpr bool must_check_object = function_traits<call_type>::must_check_object;
|
263 |
+
};
|
264 |
+
|
265 |
+
template <typename T>
|
266 |
+
func_ptr get_function_ptr(const T &t) {
|
267 |
+
func_ptr d;
|
268 |
+
std::uninitialized_fill(std::begin(d.data), std::end(d.data), '\0');
|
269 |
+
function_traits<std::decay_t<T>>::ptr(t, d);
|
270 |
+
return d;
|
271 |
+
}
|
272 |
+
|
273 |
+
/*
|
274 |
+
* obj_ptr is used to store a pointer to an object.
|
275 |
+
* The object_pointer traits are needed to handle trackable objects correctly,
|
276 |
+
* as they are likely to not be pointers.
|
277 |
+
*/
|
278 |
+
using obj_ptr = const void*;
|
279 |
+
|
280 |
+
template <typename T>
|
281 |
+
obj_ptr get_object_ptr(const T &t);
|
282 |
+
|
283 |
+
template <typename T, typename = void>
|
284 |
+
struct object_pointer {
|
285 |
+
static obj_ptr get(const T&) {
|
286 |
+
return nullptr;
|
287 |
+
}
|
288 |
+
};
|
289 |
+
|
290 |
+
template <typename T>
|
291 |
+
struct object_pointer<T*, std::enable_if_t<trait::is_pointer_v<T*>>> {
|
292 |
+
static obj_ptr get(const T *t) {
|
293 |
+
return reinterpret_cast<obj_ptr>(t);
|
294 |
+
}
|
295 |
+
};
|
296 |
+
|
297 |
+
template <typename T>
|
298 |
+
struct object_pointer<T, std::enable_if_t<trait::is_weak_ptr_v<T>>> {
|
299 |
+
static obj_ptr get(const T &t) {
|
300 |
+
auto p = t.lock();
|
301 |
+
return get_object_ptr(p);
|
302 |
+
}
|
303 |
+
};
|
304 |
+
|
305 |
+
template <typename T>
|
306 |
+
struct object_pointer<T, std::enable_if_t<!trait::is_pointer_v<T> &&
|
307 |
+
!trait::is_weak_ptr_v<T> &&
|
308 |
+
trait::is_weak_ptr_compatible_v<T>>>
|
309 |
+
{
|
310 |
+
static obj_ptr get(const T &t) {
|
311 |
+
return t ? reinterpret_cast<obj_ptr>(t.get()) : nullptr;
|
312 |
+
}
|
313 |
+
};
|
314 |
+
|
315 |
+
template <typename T>
|
316 |
+
obj_ptr get_object_ptr(const T &t) {
|
317 |
+
return object_pointer<T>::get(t);
|
318 |
+
}
|
319 |
+
|
320 |
+
|
321 |
+
// noop mutex for thread-unsafe use
|
322 |
+
struct null_mutex {
|
323 |
+
null_mutex() noexcept = default;
|
324 |
+
~null_mutex() noexcept = default;
|
325 |
+
null_mutex(const null_mutex &) = delete;
|
326 |
+
null_mutex& operator=(const null_mutex &) = delete;
|
327 |
+
null_mutex(null_mutex &&) = delete;
|
328 |
+
null_mutex& operator=(null_mutex &&) = delete;
|
329 |
+
|
330 |
+
inline bool try_lock() noexcept { return true; }
|
331 |
+
inline void lock() noexcept {}
|
332 |
+
inline void unlock() noexcept {}
|
333 |
+
};
|
334 |
+
|
335 |
+
/**
|
336 |
+
* A spin mutex that yields, mostly for use in benchmarks and scenarii that invoke
|
337 |
+
* slots at a very high pace.
|
338 |
+
* One should almost always prefer a standard mutex over this.
|
339 |
+
*/
|
340 |
+
struct spin_mutex {
|
341 |
+
spin_mutex() noexcept = default;
|
342 |
+
~spin_mutex() noexcept = default;
|
343 |
+
spin_mutex(spin_mutex const&) = delete;
|
344 |
+
spin_mutex& operator=(const spin_mutex &) = delete;
|
345 |
+
spin_mutex(spin_mutex &&) = delete;
|
346 |
+
spin_mutex& operator=(spin_mutex &&) = delete;
|
347 |
+
|
348 |
+
void lock() noexcept {
|
349 |
+
while (true) {
|
350 |
+
while (!state.load(std::memory_order_relaxed)) {
|
351 |
+
std::this_thread::yield();
|
352 |
+
}
|
353 |
+
|
354 |
+
if (try_lock()) {
|
355 |
+
break;
|
356 |
+
}
|
357 |
+
}
|
358 |
+
}
|
359 |
+
|
360 |
+
bool try_lock() noexcept {
|
361 |
+
return state.exchange(false, std::memory_order_acquire);
|
362 |
+
}
|
363 |
+
|
364 |
+
void unlock() noexcept {
|
365 |
+
state.store(true, std::memory_order_release);
|
366 |
+
}
|
367 |
+
|
368 |
+
private:
|
369 |
+
std::atomic<bool> state {true};
|
370 |
+
};
|
371 |
+
|
372 |
+
/**
|
373 |
+
* A simple copy on write container that will be used to improve slot lists
|
374 |
+
* access efficiency in a multithreaded context.
|
375 |
+
*/
|
376 |
+
template <typename T>
|
377 |
+
class copy_on_write {
|
378 |
+
struct payload {
|
379 |
+
payload() = default;
|
380 |
+
|
381 |
+
template <typename... Args>
|
382 |
+
explicit payload(Args && ...args)
|
383 |
+
: value(std::forward<Args>(args)...)
|
384 |
+
{}
|
385 |
+
|
386 |
+
std::atomic<std::size_t> count{1};
|
387 |
+
T value;
|
388 |
+
};
|
389 |
+
|
390 |
+
public:
|
391 |
+
using element_type = T;
|
392 |
+
|
393 |
+
copy_on_write()
|
394 |
+
: m_data(new payload)
|
395 |
+
{}
|
396 |
+
|
397 |
+
template <typename U>
|
398 |
+
explicit copy_on_write(U && x, std::enable_if_t<!std::is_same<std::decay_t<U>,
|
399 |
+
copy_on_write>::value>* = nullptr)
|
400 |
+
: m_data(new payload(std::forward<U>(x)))
|
401 |
+
{}
|
402 |
+
|
403 |
+
copy_on_write(const copy_on_write &x) noexcept
|
404 |
+
: m_data(x.m_data)
|
405 |
+
{
|
406 |
+
++m_data->count;
|
407 |
+
}
|
408 |
+
|
409 |
+
copy_on_write(copy_on_write && x) noexcept
|
410 |
+
: m_data(x.m_data)
|
411 |
+
{
|
412 |
+
x.m_data = nullptr;
|
413 |
+
}
|
414 |
+
|
415 |
+
~copy_on_write() {
|
416 |
+
if (m_data && (--m_data->count == 0)) {
|
417 |
+
delete m_data;
|
418 |
+
}
|
419 |
+
}
|
420 |
+
|
421 |
+
copy_on_write& operator=(const copy_on_write &x) noexcept {
|
422 |
+
if (&x != this) {
|
423 |
+
*this = copy_on_write(x);
|
424 |
+
}
|
425 |
+
return *this;
|
426 |
+
}
|
427 |
+
|
428 |
+
copy_on_write& operator=(copy_on_write && x) noexcept {
|
429 |
+
auto tmp = std::move(x);
|
430 |
+
swap(*this, tmp);
|
431 |
+
return *this;
|
432 |
+
}
|
433 |
+
|
434 |
+
element_type& write() {
|
435 |
+
if (!unique()) {
|
436 |
+
*this = copy_on_write(read());
|
437 |
+
}
|
438 |
+
return m_data->value;
|
439 |
+
}
|
440 |
+
|
441 |
+
const element_type& read() const noexcept {
|
442 |
+
return m_data->value;
|
443 |
+
}
|
444 |
+
|
445 |
+
friend inline void swap(copy_on_write &x, copy_on_write &y) noexcept {
|
446 |
+
using std::swap;
|
447 |
+
swap(x.m_data, y.m_data);
|
448 |
+
}
|
449 |
+
|
450 |
+
private:
|
451 |
+
bool unique() const noexcept {
|
452 |
+
return m_data->count == 1;
|
453 |
+
}
|
454 |
+
|
455 |
+
private:
|
456 |
+
payload *m_data;
|
457 |
+
};
|
458 |
+
|
459 |
+
/**
|
460 |
+
* Specializations for thread-safe code path
|
461 |
+
*/
|
462 |
+
template <typename T>
|
463 |
+
const T& cow_read(const T &v) {
|
464 |
+
return v;
|
465 |
+
}
|
466 |
+
|
467 |
+
template <typename T>
|
468 |
+
const T& cow_read(copy_on_write<T> &v) {
|
469 |
+
return v.read();
|
470 |
+
}
|
471 |
+
|
472 |
+
template <typename T>
|
473 |
+
T& cow_write(T &v) {
|
474 |
+
return v;
|
475 |
+
}
|
476 |
+
|
477 |
+
template <typename T>
|
478 |
+
T& cow_write(copy_on_write<T> &v) {
|
479 |
+
return v.write();
|
480 |
+
}
|
481 |
+
|
482 |
+
/**
|
483 |
+
* std::make_shared instantiates a lot a templates, and makes both compilation time
|
484 |
+
* and executable size far bigger than they need to be. We offer a make_shared
|
485 |
+
* equivalent that will avoid most instantiations with the following tradeoffs:
|
486 |
+
* - Not exception safe,
|
487 |
+
* - Allocates a separate control block, and will thus make the code slower.
|
488 |
+
*/
|
489 |
+
#ifdef SIGSLOT_REDUCE_COMPILE_TIME
|
490 |
+
template <typename B, typename D, typename ...Arg>
|
491 |
+
inline std::shared_ptr<B> make_shared(Arg && ... arg) {
|
492 |
+
return std::shared_ptr<B>(static_cast<B*>(new D(std::forward<Arg>(arg)...)));
|
493 |
+
}
|
494 |
+
#else
|
495 |
+
template <typename B, typename D, typename ...Arg>
|
496 |
+
inline std::shared_ptr<B> make_shared(Arg && ... arg) {
|
497 |
+
return std::static_pointer_cast<B>(std::make_shared<D>(std::forward<Arg>(arg)...));
|
498 |
+
}
|
499 |
+
#endif
|
500 |
+
|
501 |
+
/* slot_state holds slot type independent state, to be used to interact with
|
502 |
+
* slots indirectly through connection and scoped_connection objects.
|
503 |
+
*/
|
504 |
+
class slot_state {
|
505 |
+
public:
|
506 |
+
constexpr slot_state(group_id gid) noexcept
|
507 |
+
: m_index(0)
|
508 |
+
, m_group(gid)
|
509 |
+
, m_connected(true)
|
510 |
+
, m_blocked(false)
|
511 |
+
{}
|
512 |
+
|
513 |
+
virtual ~slot_state() = default;
|
514 |
+
|
515 |
+
virtual bool connected() const noexcept { return m_connected; }
|
516 |
+
|
517 |
+
bool disconnect() noexcept {
|
518 |
+
bool ret = m_connected.exchange(false);
|
519 |
+
if (ret) {
|
520 |
+
do_disconnect();
|
521 |
+
}
|
522 |
+
return ret;
|
523 |
+
}
|
524 |
+
|
525 |
+
bool blocked() const noexcept { return m_blocked.load(); }
|
526 |
+
void block() noexcept { m_blocked.store(true); }
|
527 |
+
void unblock() noexcept { m_blocked.store(false); }
|
528 |
+
|
529 |
+
protected:
|
530 |
+
virtual void do_disconnect() {}
|
531 |
+
|
532 |
+
auto index() const {
|
533 |
+
return m_index;
|
534 |
+
}
|
535 |
+
|
536 |
+
auto& index() {
|
537 |
+
return m_index;
|
538 |
+
}
|
539 |
+
|
540 |
+
group_id group() const {
|
541 |
+
return m_group;
|
542 |
+
}
|
543 |
+
|
544 |
+
private:
|
545 |
+
template <typename, typename...>
|
546 |
+
friend class ::sigslot::signal_base;
|
547 |
+
|
548 |
+
std::size_t m_index; // index into the array of slot pointers inside the signal
|
549 |
+
const group_id m_group; // slot group this slot belongs to
|
550 |
+
std::atomic<bool> m_connected;
|
551 |
+
std::atomic<bool> m_blocked;
|
552 |
+
};
|
553 |
+
|
554 |
+
} // namespace detail
|
555 |
+
|
556 |
+
/**
|
557 |
+
* connection_blocker is a RAII object that blocks a connection until destruction
|
558 |
+
*/
|
559 |
+
class connection_blocker {
|
560 |
+
public:
|
561 |
+
connection_blocker() = default;
|
562 |
+
~connection_blocker() noexcept { release(); }
|
563 |
+
|
564 |
+
connection_blocker(const connection_blocker &) = delete;
|
565 |
+
connection_blocker & operator=(const connection_blocker &) = delete;
|
566 |
+
|
567 |
+
connection_blocker(connection_blocker && o) noexcept
|
568 |
+
: m_state{std::move(o.m_state)}
|
569 |
+
{}
|
570 |
+
|
571 |
+
connection_blocker & operator=(connection_blocker && o) noexcept {
|
572 |
+
release();
|
573 |
+
m_state.swap(o.m_state);
|
574 |
+
return *this;
|
575 |
+
}
|
576 |
+
|
577 |
+
private:
|
578 |
+
friend class connection;
|
579 |
+
explicit connection_blocker(std::weak_ptr<detail::slot_state> s) noexcept
|
580 |
+
: m_state{std::move(s)}
|
581 |
+
{
|
582 |
+
if (auto d = m_state.lock()) {
|
583 |
+
d->block();
|
584 |
+
}
|
585 |
+
}
|
586 |
+
|
587 |
+
void release() noexcept {
|
588 |
+
if (auto d = m_state.lock()) {
|
589 |
+
d->unblock();
|
590 |
+
}
|
591 |
+
}
|
592 |
+
|
593 |
+
private:
|
594 |
+
std::weak_ptr<detail::slot_state> m_state;
|
595 |
+
};
|
596 |
+
|
597 |
+
|
598 |
+
/**
|
599 |
+
* A connection object allows interaction with an ongoing slot connection
|
600 |
+
*
|
601 |
+
* It allows common actions such as connection blocking and disconnection.
|
602 |
+
* Note that connection is not a RAII object, one does not need to hold one
|
603 |
+
* such object to keep the signal-slot connection alive.
|
604 |
+
*/
|
605 |
+
class connection {
|
606 |
+
public:
|
607 |
+
connection() = default;
|
608 |
+
virtual ~connection() = default;
|
609 |
+
|
610 |
+
connection(const connection &) noexcept = default;
|
611 |
+
connection & operator=(const connection &) noexcept = default;
|
612 |
+
connection(connection &&) noexcept = default;
|
613 |
+
connection & operator=(connection &&) noexcept = default;
|
614 |
+
|
615 |
+
bool valid() const noexcept {
|
616 |
+
return !m_state.expired();
|
617 |
+
}
|
618 |
+
|
619 |
+
bool connected() const noexcept {
|
620 |
+
const auto d = m_state.lock();
|
621 |
+
return d && d->connected();
|
622 |
+
}
|
623 |
+
|
624 |
+
bool disconnect() noexcept {
|
625 |
+
auto d = m_state.lock();
|
626 |
+
return d && d->disconnect();
|
627 |
+
}
|
628 |
+
|
629 |
+
bool blocked() const noexcept {
|
630 |
+
const auto d = m_state.lock();
|
631 |
+
return d && d->blocked();
|
632 |
+
}
|
633 |
+
|
634 |
+
void block() noexcept {
|
635 |
+
if (auto d = m_state.lock()) {
|
636 |
+
d->block();
|
637 |
+
}
|
638 |
+
}
|
639 |
+
|
640 |
+
void unblock() noexcept {
|
641 |
+
if (auto d = m_state.lock()) {
|
642 |
+
d->unblock();
|
643 |
+
}
|
644 |
+
}
|
645 |
+
|
646 |
+
connection_blocker blocker() const noexcept {
|
647 |
+
return connection_blocker{m_state};
|
648 |
+
}
|
649 |
+
|
650 |
+
protected:
|
651 |
+
template <typename, typename...> friend class signal_base;
|
652 |
+
explicit connection(std::weak_ptr<detail::slot_state> s) noexcept
|
653 |
+
: m_state{std::move(s)}
|
654 |
+
{}
|
655 |
+
|
656 |
+
protected:
|
657 |
+
std::weak_ptr<detail::slot_state> m_state;
|
658 |
+
};
|
659 |
+
|
660 |
+
/**
|
661 |
+
* scoped_connection is a RAII version of connection
|
662 |
+
* It disconnects the slot from the signal upon destruction.
|
663 |
+
*/
|
664 |
+
class scoped_connection final : public connection {
|
665 |
+
public:
|
666 |
+
scoped_connection() = default;
|
667 |
+
~scoped_connection() override {
|
668 |
+
disconnect();
|
669 |
+
}
|
670 |
+
|
671 |
+
/*implicit*/ scoped_connection(const connection &c) noexcept : connection(c) {}
|
672 |
+
/*implicit*/ scoped_connection(connection &&c) noexcept : connection(std::move(c)) {}
|
673 |
+
|
674 |
+
scoped_connection(const scoped_connection &) noexcept = delete;
|
675 |
+
scoped_connection & operator=(const scoped_connection &) noexcept = delete;
|
676 |
+
|
677 |
+
scoped_connection(scoped_connection && o) noexcept
|
678 |
+
: connection{std::move(o.m_state)}
|
679 |
+
{}
|
680 |
+
|
681 |
+
scoped_connection & operator=(scoped_connection && o) noexcept {
|
682 |
+
disconnect();
|
683 |
+
m_state.swap(o.m_state);
|
684 |
+
return *this;
|
685 |
+
}
|
686 |
+
|
687 |
+
private:
|
688 |
+
template <typename, typename...> friend class signal_base;
|
689 |
+
explicit scoped_connection(std::weak_ptr<detail::slot_state> s) noexcept
|
690 |
+
: connection{std::move(s)}
|
691 |
+
{}
|
692 |
+
};
|
693 |
+
|
694 |
+
/**
|
695 |
+
* Observer is a base class for intrusive lifetime tracking of objects.
|
696 |
+
*
|
697 |
+
* This is an alternative to trackable pointers, such as std::shared_ptr,
|
698 |
+
* and manual connection management by keeping connection objects in scope.
|
699 |
+
* Deriving from this class allows automatic disconnection of all the slots
|
700 |
+
* connected to any signal when an instance is destroyed.
|
701 |
+
*/
|
702 |
+
template <typename Lockable>
|
703 |
+
struct observer_base : private detail::observer_type {
|
704 |
+
virtual ~observer_base() = default;
|
705 |
+
|
706 |
+
protected:
|
707 |
+
/**
|
708 |
+
* Disconnect all signals connected to this object.
|
709 |
+
*
|
710 |
+
* To avoid invocation of slots on a semi-destructed instance, which may happen
|
711 |
+
* in multi-threaded contexts, derived classes should call this method in their
|
712 |
+
* destructor. This will ensure proper disconnection prior to the destruction.
|
713 |
+
*/
|
714 |
+
void disconnect_all() {
|
715 |
+
std::unique_lock<Lockable> _{m_mutex};
|
716 |
+
m_connections.clear();
|
717 |
+
}
|
718 |
+
|
719 |
+
private:
|
720 |
+
template <typename, typename ...>
|
721 |
+
friend class signal_base;
|
722 |
+
|
723 |
+
void add_connection(connection conn) {
|
724 |
+
std::unique_lock<Lockable> _{m_mutex};
|
725 |
+
m_connections.emplace_back(std::move(conn));
|
726 |
+
}
|
727 |
+
|
728 |
+
Lockable m_mutex;
|
729 |
+
std::vector<scoped_connection> m_connections;
|
730 |
+
};
|
731 |
+
|
732 |
+
/**
|
733 |
+
* Specialization of observer_base to be used in single threaded contexts.
|
734 |
+
*/
|
735 |
+
using observer_st = observer_base<detail::null_mutex>;
|
736 |
+
|
737 |
+
/**
|
738 |
+
* Specialization of observer_base to be used in multi-threaded contexts.
|
739 |
+
*/
|
740 |
+
using observer = observer_base<std::mutex>;
|
741 |
+
|
742 |
+
|
743 |
+
namespace detail {
|
744 |
+
|
745 |
+
// interface for cleanable objects, used to cleanup disconnected slots
|
746 |
+
struct cleanable {
|
747 |
+
virtual ~cleanable() = default;
|
748 |
+
virtual void clean(slot_state *) = 0;
|
749 |
+
};
|
750 |
+
|
751 |
+
template <typename...>
|
752 |
+
class slot_base;
|
753 |
+
|
754 |
+
template <typename... T>
|
755 |
+
using slot_ptr = std::shared_ptr<slot_base<T...>>;
|
756 |
+
|
757 |
+
|
758 |
+
/* A base class for slot objects. This base type only depends on slot argument
|
759 |
+
* types, it will be used as an element in an intrusive singly-linked list of
|
760 |
+
* slots, hence the public next member.
|
761 |
+
*/
|
762 |
+
template <typename... Args>
|
763 |
+
class slot_base : public slot_state {
|
764 |
+
public:
|
765 |
+
using base_types = trait::typelist<Args...>;
|
766 |
+
|
767 |
+
explicit slot_base(cleanable &c, group_id gid)
|
768 |
+
: slot_state(gid)
|
769 |
+
, cleaner(c)
|
770 |
+
{}
|
771 |
+
~slot_base() override = default;
|
772 |
+
|
773 |
+
// method effectively responsible for calling the "slot" function with
|
774 |
+
// supplied arguments whenever emission happens.
|
775 |
+
virtual void call_slot(Args...) = 0;
|
776 |
+
|
777 |
+
template <typename... U>
|
778 |
+
void operator()(U && ...u) {
|
779 |
+
if (slot_state::connected() && !slot_state::blocked()) {
|
780 |
+
call_slot(std::forward<U>(u)...);
|
781 |
+
}
|
782 |
+
}
|
783 |
+
|
784 |
+
// check if we are storing callable c
|
785 |
+
template <typename C>
|
786 |
+
bool has_callable(const C &c) const {
|
787 |
+
auto cp = get_function_ptr(c);
|
788 |
+
auto p = get_callable();
|
789 |
+
return cp && p && cp == p;
|
790 |
+
}
|
791 |
+
|
792 |
+
template <typename C>
|
793 |
+
std::enable_if_t<function_traits<C>::must_check_object, bool>
|
794 |
+
has_full_callable(const C &c) const {
|
795 |
+
return has_callable(c) && check_class_type<std::decay_t<C>>();
|
796 |
+
}
|
797 |
+
|
798 |
+
template <typename C>
|
799 |
+
std::enable_if_t<!function_traits<C>::must_check_object, bool>
|
800 |
+
has_full_callable(const C &c) const {
|
801 |
+
return has_callable(c);
|
802 |
+
}
|
803 |
+
|
804 |
+
// check if we are storing object o
|
805 |
+
template <typename O>
|
806 |
+
bool has_object(const O &o) const {
|
807 |
+
return get_object() == get_object_ptr(o);
|
808 |
+
}
|
809 |
+
|
810 |
+
protected:
|
811 |
+
void do_disconnect() final {
|
812 |
+
cleaner.clean(this);
|
813 |
+
}
|
814 |
+
|
815 |
+
// retieve a pointer to the object embedded in the slot
|
816 |
+
virtual obj_ptr get_object() const noexcept {
|
817 |
+
return nullptr;
|
818 |
+
}
|
819 |
+
|
820 |
+
// retieve a pointer to the callable embedded in the slot
|
821 |
+
virtual func_ptr get_callable() const noexcept {
|
822 |
+
return get_function_ptr(nullptr);
|
823 |
+
}
|
824 |
+
|
825 |
+
#ifdef SIGSLOT_RTTI_ENABLED
|
826 |
+
// retieve a pointer to the callable embedded in the slot
|
827 |
+
virtual const std::type_info& get_callable_type() const noexcept {
|
828 |
+
return typeid(nullptr);
|
829 |
+
}
|
830 |
+
|
831 |
+
private:
|
832 |
+
template <typename U>
|
833 |
+
bool check_class_type() const {
|
834 |
+
return typeid(U) == get_callable_type();
|
835 |
+
}
|
836 |
+
|
837 |
+
#else
|
838 |
+
template <typename U>
|
839 |
+
bool check_class_type() const {
|
840 |
+
return false;
|
841 |
+
}
|
842 |
+
#endif
|
843 |
+
|
844 |
+
private:
|
845 |
+
cleanable &cleaner;
|
846 |
+
};
|
847 |
+
|
848 |
+
/*
|
849 |
+
* A slot object holds state information, and a callable to to be called
|
850 |
+
* whenever the function call operator of its slot_base base class is called.
|
851 |
+
*/
|
852 |
+
template <typename Func, typename... Args>
|
853 |
+
class slot final : public slot_base<Args...> {
|
854 |
+
public:
|
855 |
+
template <typename F, typename Gid>
|
856 |
+
constexpr slot(cleanable &c, F && f, Gid gid)
|
857 |
+
: slot_base<Args...>(c, gid)
|
858 |
+
, func{std::forward<F>(f)} {}
|
859 |
+
|
860 |
+
protected:
|
861 |
+
void call_slot(Args ...args) override {
|
862 |
+
func(args...);
|
863 |
+
}
|
864 |
+
|
865 |
+
func_ptr get_callable() const noexcept override {
|
866 |
+
return get_function_ptr(func);
|
867 |
+
}
|
868 |
+
|
869 |
+
#ifdef SIGSLOT_RTTI_ENABLED
|
870 |
+
const std::type_info& get_callable_type() const noexcept override {
|
871 |
+
return typeid(func);
|
872 |
+
}
|
873 |
+
#endif
|
874 |
+
|
875 |
+
private:
|
876 |
+
std::decay_t<Func> func;
|
877 |
+
};
|
878 |
+
|
879 |
+
/*
|
880 |
+
* Variation of slot that prepends a connection object to the callable
|
881 |
+
*/
|
882 |
+
template <typename Func, typename... Args>
|
883 |
+
class slot_extended final : public slot_base<Args...> {
|
884 |
+
public:
|
885 |
+
template <typename F>
|
886 |
+
constexpr slot_extended(cleanable &c, F && f, group_id gid)
|
887 |
+
: slot_base<Args...>(c, gid)
|
888 |
+
, func{std::forward<F>(f)} {}
|
889 |
+
|
890 |
+
connection conn;
|
891 |
+
|
892 |
+
protected:
|
893 |
+
void call_slot(Args ...args) override {
|
894 |
+
func(conn, args...);
|
895 |
+
}
|
896 |
+
|
897 |
+
func_ptr get_callable() const noexcept override {
|
898 |
+
return get_function_ptr(func);
|
899 |
+
}
|
900 |
+
|
901 |
+
#ifdef SIGSLOT_RTTI_ENABLED
|
902 |
+
const std::type_info& get_callable_type() const noexcept override {
|
903 |
+
return typeid(func);
|
904 |
+
}
|
905 |
+
#endif
|
906 |
+
|
907 |
+
private:
|
908 |
+
std::decay_t<Func> func;
|
909 |
+
};
|
910 |
+
|
911 |
+
/*
|
912 |
+
* A slot object holds state information, an object and a pointer over member
|
913 |
+
* function to be called whenever the function call operator of its slot_base
|
914 |
+
* base class is called.
|
915 |
+
*/
|
916 |
+
template <typename Pmf, typename Ptr, typename... Args>
|
917 |
+
class slot_pmf final : public slot_base<Args...> {
|
918 |
+
public:
|
919 |
+
template <typename F, typename P>
|
920 |
+
constexpr slot_pmf(cleanable &c, F && f, P && p, group_id gid)
|
921 |
+
: slot_base<Args...>(c, gid)
|
922 |
+
, pmf{std::forward<F>(f)}
|
923 |
+
, ptr{std::forward<P>(p)} {}
|
924 |
+
|
925 |
+
protected:
|
926 |
+
void call_slot(Args ...args) override {
|
927 |
+
((*ptr).*pmf)(args...);
|
928 |
+
}
|
929 |
+
|
930 |
+
func_ptr get_callable() const noexcept override {
|
931 |
+
return get_function_ptr(pmf);
|
932 |
+
}
|
933 |
+
|
934 |
+
obj_ptr get_object() const noexcept override {
|
935 |
+
return get_object_ptr(ptr);
|
936 |
+
}
|
937 |
+
|
938 |
+
#ifdef SIGSLOT_RTTI_ENABLED
|
939 |
+
const std::type_info& get_callable_type() const noexcept override {
|
940 |
+
return typeid(pmf);
|
941 |
+
}
|
942 |
+
#endif
|
943 |
+
|
944 |
+
private:
|
945 |
+
std::decay_t<Pmf> pmf;
|
946 |
+
std::decay_t<Ptr> ptr;
|
947 |
+
};
|
948 |
+
|
949 |
+
/*
|
950 |
+
* Variation of slot that prepends a connection object to the callable
|
951 |
+
*/
|
952 |
+
template <typename Pmf, typename Ptr, typename... Args>
|
953 |
+
class slot_pmf_extended final : public slot_base<Args...> {
|
954 |
+
public:
|
955 |
+
template <typename F, typename P>
|
956 |
+
constexpr slot_pmf_extended(cleanable &c, F && f, P && p, group_id gid)
|
957 |
+
: slot_base<Args...>(c, gid)
|
958 |
+
, pmf{std::forward<F>(f)}
|
959 |
+
, ptr{std::forward<P>(p)} {}
|
960 |
+
|
961 |
+
connection conn;
|
962 |
+
|
963 |
+
protected:
|
964 |
+
void call_slot(Args ...args) override {
|
965 |
+
((*ptr).*pmf)(conn, args...);
|
966 |
+
}
|
967 |
+
|
968 |
+
func_ptr get_callable() const noexcept override {
|
969 |
+
return get_function_ptr(pmf);
|
970 |
+
}
|
971 |
+
obj_ptr get_object() const noexcept override {
|
972 |
+
return get_object_ptr(ptr);
|
973 |
+
}
|
974 |
+
|
975 |
+
#ifdef SIGSLOT_RTTI_ENABLED
|
976 |
+
const std::type_info& get_callable_type() const noexcept override {
|
977 |
+
return typeid(pmf);
|
978 |
+
}
|
979 |
+
#endif
|
980 |
+
|
981 |
+
private:
|
982 |
+
std::decay_t<Pmf> pmf;
|
983 |
+
std::decay_t<Ptr> ptr;
|
984 |
+
};
|
985 |
+
|
986 |
+
/*
|
987 |
+
* An implementation of a slot that tracks the life of a supplied object
|
988 |
+
* through a weak pointer in order to automatically disconnect the slot
|
989 |
+
* on said object destruction.
|
990 |
+
*/
|
991 |
+
template <typename Func, typename WeakPtr, typename... Args>
|
992 |
+
class slot_tracked final : public slot_base<Args...> {
|
993 |
+
public:
|
994 |
+
template <typename F, typename P>
|
995 |
+
constexpr slot_tracked(cleanable &c, F && f, P && p, group_id gid)
|
996 |
+
: slot_base<Args...>(c, gid)
|
997 |
+
, func{std::forward<F>(f)}
|
998 |
+
, ptr{std::forward<P>(p)}
|
999 |
+
{}
|
1000 |
+
|
1001 |
+
bool connected() const noexcept override {
|
1002 |
+
return !ptr.expired() && slot_state::connected();
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
protected:
|
1006 |
+
void call_slot(Args ...args) override {
|
1007 |
+
auto sp = ptr.lock();
|
1008 |
+
if (!sp) {
|
1009 |
+
slot_state::disconnect();
|
1010 |
+
return;
|
1011 |
+
}
|
1012 |
+
if (slot_state::connected()) {
|
1013 |
+
func(args...);
|
1014 |
+
}
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
func_ptr get_callable() const noexcept override {
|
1018 |
+
return get_function_ptr(func);
|
1019 |
+
}
|
1020 |
+
|
1021 |
+
obj_ptr get_object() const noexcept override {
|
1022 |
+
return get_object_ptr(ptr);
|
1023 |
+
}
|
1024 |
+
|
1025 |
+
#ifdef SIGSLOT_RTTI_ENABLED
|
1026 |
+
const std::type_info& get_callable_type() const noexcept override {
|
1027 |
+
return typeid(func);
|
1028 |
+
}
|
1029 |
+
#endif
|
1030 |
+
|
1031 |
+
private:
|
1032 |
+
std::decay_t<Func> func;
|
1033 |
+
std::decay_t<WeakPtr> ptr;
|
1034 |
+
};
|
1035 |
+
|
1036 |
+
/*
|
1037 |
+
* An implementation of a slot as a pointer over member function, that tracks
|
1038 |
+
* the life of a supplied object through a weak pointer in order to automatically
|
1039 |
+
* disconnect the slot on said object destruction.
|
1040 |
+
*/
|
1041 |
+
template <typename Pmf, typename WeakPtr, typename... Args>
|
1042 |
+
class slot_pmf_tracked final : public slot_base<Args...> {
|
1043 |
+
public:
|
1044 |
+
template <typename F, typename P>
|
1045 |
+
constexpr slot_pmf_tracked(cleanable &c, F && f, P && p, group_id gid)
|
1046 |
+
: slot_base<Args...>(c, gid)
|
1047 |
+
, pmf{std::forward<F>(f)}
|
1048 |
+
, ptr{std::forward<P>(p)}
|
1049 |
+
{}
|
1050 |
+
|
1051 |
+
bool connected() const noexcept override {
|
1052 |
+
return !ptr.expired() && slot_state::connected();
|
1053 |
+
}
|
1054 |
+
|
1055 |
+
protected:
|
1056 |
+
void call_slot(Args ...args) override {
|
1057 |
+
auto sp = ptr.lock();
|
1058 |
+
if (!sp) {
|
1059 |
+
slot_state::disconnect();
|
1060 |
+
return;
|
1061 |
+
}
|
1062 |
+
if (slot_state::connected()) {
|
1063 |
+
((*sp).*pmf)(args...);
|
1064 |
+
}
|
1065 |
+
}
|
1066 |
+
|
1067 |
+
func_ptr get_callable() const noexcept override {
|
1068 |
+
return get_function_ptr(pmf);
|
1069 |
+
}
|
1070 |
+
|
1071 |
+
obj_ptr get_object() const noexcept override {
|
1072 |
+
return get_object_ptr(ptr);
|
1073 |
+
}
|
1074 |
+
|
1075 |
+
#ifdef SIGSLOT_RTTI_ENABLED
|
1076 |
+
const std::type_info& get_callable_type() const noexcept override {
|
1077 |
+
return typeid(pmf);
|
1078 |
+
}
|
1079 |
+
#endif
|
1080 |
+
|
1081 |
+
private:
|
1082 |
+
std::decay_t<Pmf> pmf;
|
1083 |
+
std::decay_t<WeakPtr> ptr;
|
1084 |
+
};
|
1085 |
+
|
1086 |
+
} // namespace detail
|
1087 |
+
|
1088 |
+
|
1089 |
+
/**
|
1090 |
+
* signal_base is an implementation of the observer pattern, through the use
|
1091 |
+
* of an emitting object and slots that are connected to the signal and called
|
1092 |
+
* with supplied arguments when a signal is emitted.
|
1093 |
+
*
|
1094 |
+
* signal_base is the general implementation, whose locking policy must be
|
1095 |
+
* set in order to decide thread safety guarantees. signal and signal_st
|
1096 |
+
* are partial specializations for multi-threaded and single-threaded use.
|
1097 |
+
*
|
1098 |
+
* It does not allow slots to return a value.
|
1099 |
+
*
|
1100 |
+
* Slot execution order can be constrained by assigning group ids to the slots.
|
1101 |
+
* The execution order of slots in a same group is unspecified and should not be
|
1102 |
+
* relied upon, however groups are executed in ascending group ids order. When
|
1103 |
+
* the group id of a slot is not set, it is assigned to the group 0. Group ids
|
1104 |
+
* can have any value in the range of signed 32 bit integers.
|
1105 |
+
*
|
1106 |
+
* @tparam Lockable a lock type to decide the lock policy
|
1107 |
+
* @tparam T... the argument types of the emitting and slots functions.
|
1108 |
+
*/
|
1109 |
+
template <typename Lockable, typename... T>
|
1110 |
+
class signal_base final : public detail::cleanable {
|
1111 |
+
template <typename L>
|
1112 |
+
using is_thread_safe = std::integral_constant<bool, !std::is_same<L, detail::null_mutex>::value>;
|
1113 |
+
|
1114 |
+
template <typename U, typename L>
|
1115 |
+
using cow_type = std::conditional_t<is_thread_safe<L>::value,
|
1116 |
+
detail::copy_on_write<U>, U>;
|
1117 |
+
|
1118 |
+
template <typename U, typename L>
|
1119 |
+
using cow_copy_type = std::conditional_t<is_thread_safe<L>::value,
|
1120 |
+
detail::copy_on_write<U>, const U&>;
|
1121 |
+
|
1122 |
+
using lock_type = std::unique_lock<Lockable>;
|
1123 |
+
using slot_base = detail::slot_base<T...>;
|
1124 |
+
using slot_ptr = detail::slot_ptr<T...>;
|
1125 |
+
using slots_type = std::vector<slot_ptr>;
|
1126 |
+
struct group_type { slots_type slts; group_id gid; };
|
1127 |
+
using list_type = std::vector<group_type>; // kept ordered by ascending gid
|
1128 |
+
|
1129 |
+
public:
|
1130 |
+
using arg_list = trait::typelist<T...>;
|
1131 |
+
using ext_arg_list = trait::typelist<connection&, T...>;
|
1132 |
+
|
1133 |
+
signal_base() noexcept : m_block(false) {}
|
1134 |
+
~signal_base() override {
|
1135 |
+
disconnect_all();
|
1136 |
+
}
|
1137 |
+
|
1138 |
+
signal_base(const signal_base&) = delete;
|
1139 |
+
signal_base & operator=(const signal_base&) = delete;
|
1140 |
+
|
1141 |
+
signal_base(signal_base && o) /* not noexcept */
|
1142 |
+
: m_block{o.m_block.load()}
|
1143 |
+
{
|
1144 |
+
lock_type lock(o.m_mutex);
|
1145 |
+
using std::swap;
|
1146 |
+
swap(m_slots, o.m_slots);
|
1147 |
+
}
|
1148 |
+
|
1149 |
+
signal_base & operator=(signal_base && o) /* not noexcept */ {
|
1150 |
+
lock_type lock1(m_mutex, std::defer_lock);
|
1151 |
+
lock_type lock2(o.m_mutex, std::defer_lock);
|
1152 |
+
std::lock(lock1, lock2);
|
1153 |
+
|
1154 |
+
using std::swap;
|
1155 |
+
swap(m_slots, o.m_slots);
|
1156 |
+
m_block.store(o.m_block.exchange(m_block.load()));
|
1157 |
+
return *this;
|
1158 |
+
}
|
1159 |
+
|
1160 |
+
/**
|
1161 |
+
* Emit a signal
|
1162 |
+
*
|
1163 |
+
* Effect: All non blocked and connected slot functions will be called
|
1164 |
+
* with supplied arguments.
|
1165 |
+
* Safety: With proper locking (see pal::signal), emission can happen from
|
1166 |
+
* multiple threads simultaneously. The guarantees only apply to the
|
1167 |
+
* signal object, it does not cover thread safety of potentially
|
1168 |
+
* shared state used in slot functions.
|
1169 |
+
*
|
1170 |
+
* @param a... arguments to emit
|
1171 |
+
*/
|
1172 |
+
template <typename... U>
|
1173 |
+
void operator()(U && ...a) {
|
1174 |
+
if (m_block) {
|
1175 |
+
return;
|
1176 |
+
}
|
1177 |
+
|
1178 |
+
// Reference to the slots to execute them out of the lock
|
1179 |
+
// a copy may occur if another thread writes to it.
|
1180 |
+
cow_copy_type<list_type, Lockable> ref = slots_reference();
|
1181 |
+
|
1182 |
+
for (const auto &group : detail::cow_read(ref)) {
|
1183 |
+
for (const auto &s : group.slts) {
|
1184 |
+
s->operator()(a...);
|
1185 |
+
}
|
1186 |
+
}
|
1187 |
+
}
|
1188 |
+
|
1189 |
+
/**
|
1190 |
+
* Connect a callable of compatible arguments
|
1191 |
+
*
|
1192 |
+
* Effect: Creates and stores a new slot responsible for executing the
|
1193 |
+
* supplied callable for every subsequent signal emission.
|
1194 |
+
* Safety: Thread-safety depends on locking policy.
|
1195 |
+
*
|
1196 |
+
* @param c a callable
|
1197 |
+
* @param gid an identifier that can be used to order slot execution
|
1198 |
+
* @return a connection object that can be used to interact with the slot
|
1199 |
+
*/
|
1200 |
+
template <typename Callable>
|
1201 |
+
std::enable_if_t<trait::is_callable_v<arg_list, Callable>, connection>
|
1202 |
+
connect(Callable && c, group_id gid = 0) {
|
1203 |
+
using slot_t = detail::slot<Callable, T...>;
|
1204 |
+
auto s = make_slot<slot_t>(std::forward<Callable>(c), gid);
|
1205 |
+
connection conn(s);
|
1206 |
+
add_slot(std::move(s));
|
1207 |
+
return conn;
|
1208 |
+
}
|
1209 |
+
|
1210 |
+
/**
|
1211 |
+
* Connect a callable with an additional connection argument
|
1212 |
+
*
|
1213 |
+
* The callable's first argument must be of type connection. This overload
|
1214 |
+
* the callable to manage it's own connection through this argument.
|
1215 |
+
*
|
1216 |
+
* @param c a callable
|
1217 |
+
* @param gid an identifier that can be used to order slot execution
|
1218 |
+
* @return a connection object that can be used to interact with the slot
|
1219 |
+
*/
|
1220 |
+
template <typename Callable>
|
1221 |
+
std::enable_if_t<trait::is_callable_v<ext_arg_list, Callable>, connection>
|
1222 |
+
connect_extended(Callable && c, group_id gid = 0) {
|
1223 |
+
using slot_t = detail::slot_extended<Callable, T...>;
|
1224 |
+
auto s = make_slot<slot_t>(std::forward<Callable>(c), gid);
|
1225 |
+
connection conn(s);
|
1226 |
+
std::static_pointer_cast<slot_t>(s)->conn = conn;
|
1227 |
+
add_slot(std::move(s));
|
1228 |
+
return conn;
|
1229 |
+
}
|
1230 |
+
|
1231 |
+
/**
|
1232 |
+
* Overload of connect for pointers over member functions derived from
|
1233 |
+
* observer
|
1234 |
+
*
|
1235 |
+
* @param pmf a pointer over member function
|
1236 |
+
* @param ptr an object pointer derived from observer
|
1237 |
+
* @param gid an identifier that can be used to order slot execution
|
1238 |
+
* @return a connection object that can be used to interact with the slot
|
1239 |
+
*/
|
1240 |
+
template <typename Pmf, typename Ptr>
|
1241 |
+
std::enable_if_t<trait::is_callable_v<arg_list, Pmf, Ptr> &&
|
1242 |
+
trait::is_observer_v<Ptr>, connection>
|
1243 |
+
connect(Pmf && pmf, Ptr && ptr, group_id gid = 0) {
|
1244 |
+
using slot_t = detail::slot_pmf<Pmf, Ptr, T...>;
|
1245 |
+
auto s = make_slot<slot_t>(std::forward<Pmf>(pmf), std::forward<Ptr>(ptr), gid);
|
1246 |
+
connection conn(s);
|
1247 |
+
add_slot(std::move(s));
|
1248 |
+
ptr->add_connection(conn);
|
1249 |
+
return conn;
|
1250 |
+
}
|
1251 |
+
|
1252 |
+
/**
|
1253 |
+
* Overload of connect for pointers over member functions
|
1254 |
+
*
|
1255 |
+
* @param pmf a pointer over member function
|
1256 |
+
* @param ptr an object pointer
|
1257 |
+
* @param gid an identifier that can be used to order slot execution
|
1258 |
+
* @return a connection object that can be used to interact with the slot
|
1259 |
+
*/
|
1260 |
+
template <typename Pmf, typename Ptr>
|
1261 |
+
std::enable_if_t<trait::is_callable_v<arg_list, Pmf, Ptr> &&
|
1262 |
+
!trait::is_observer_v<Ptr> &&
|
1263 |
+
!trait::is_weak_ptr_compatible_v<Ptr>, connection>
|
1264 |
+
connect(Pmf && pmf, Ptr && ptr, group_id gid = 0) {
|
1265 |
+
using slot_t = detail::slot_pmf<Pmf, Ptr, T...>;
|
1266 |
+
auto s = make_slot<slot_t>(std::forward<Pmf>(pmf), std::forward<Ptr>(ptr), gid);
|
1267 |
+
connection conn(s);
|
1268 |
+
add_slot(std::move(s));
|
1269 |
+
return conn;
|
1270 |
+
}
|
1271 |
+
|
1272 |
+
/**
|
1273 |
+
* Overload of connect for pointer over member functions and
|
1274 |
+
*
|
1275 |
+
* @param pmf a pointer over member function
|
1276 |
+
* @param ptr an object pointer
|
1277 |
+
* @param gid an identifier that can be used to order slot execution
|
1278 |
+
* @return a connection object that can be used to interact with the slot
|
1279 |
+
*/
|
1280 |
+
template <typename Pmf, typename Ptr>
|
1281 |
+
std::enable_if_t<trait::is_callable_v<ext_arg_list, Pmf, Ptr> &&
|
1282 |
+
!trait::is_weak_ptr_compatible_v<Ptr>, connection>
|
1283 |
+
connect_extended(Pmf && pmf, Ptr && ptr, group_id gid = 0) {
|
1284 |
+
using slot_t = detail::slot_pmf_extended<Pmf, Ptr, T...>;
|
1285 |
+
auto s = make_slot<slot_t>(std::forward<Pmf>(pmf), std::forward<Ptr>(ptr), gid);
|
1286 |
+
connection conn(s);
|
1287 |
+
std::static_pointer_cast<slot_t>(s)->conn = conn;
|
1288 |
+
add_slot(std::move(s));
|
1289 |
+
return conn;
|
1290 |
+
}
|
1291 |
+
|
1292 |
+
/**
|
1293 |
+
* Overload of connect for lifetime object tracking and automatic disconnection
|
1294 |
+
*
|
1295 |
+
* Ptr must be convertible to an object following a loose form of weak pointer
|
1296 |
+
* concept, by implementing the ADL-detected conversion function to_weak().
|
1297 |
+
*
|
1298 |
+
* This overload covers the case of a pointer over member function and a
|
1299 |
+
* trackable pointer of that class.
|
1300 |
+
*
|
1301 |
+
* Note: only weak references are stored, a slot does not extend the lifetime
|
1302 |
+
* of a suppied object.
|
1303 |
+
*
|
1304 |
+
* @param pmf a pointer over member function
|
1305 |
+
* @param ptr a trackable object pointer
|
1306 |
+
* @param gid an identifier that can be used to order slot execution
|
1307 |
+
* @return a connection object that can be used to interact with the slot
|
1308 |
+
*/
|
1309 |
+
template <typename Pmf, typename Ptr>
|
1310 |
+
std::enable_if_t<!trait::is_callable_v<arg_list, Pmf> &&
|
1311 |
+
trait::is_weak_ptr_compatible_v<Ptr>, connection>
|
1312 |
+
connect(Pmf && pmf, Ptr && ptr, group_id gid = 0) {
|
1313 |
+
using trait::to_weak;
|
1314 |
+
auto w = to_weak(std::forward<Ptr>(ptr));
|
1315 |
+
using slot_t = detail::slot_pmf_tracked<Pmf, decltype(w), T...>;
|
1316 |
+
auto s = make_slot<slot_t>(std::forward<Pmf>(pmf), w, gid);
|
1317 |
+
connection conn(s);
|
1318 |
+
add_slot(std::move(s));
|
1319 |
+
return conn;
|
1320 |
+
}
|
1321 |
+
|
1322 |
+
/**
|
1323 |
+
* Overload of connect for lifetime object tracking and automatic disconnection
|
1324 |
+
*
|
1325 |
+
* Trackable must be convertible to an object following a loose form of weak
|
1326 |
+
* pointer concept, by implementing the ADL-detected conversion function to_weak().
|
1327 |
+
*
|
1328 |
+
* This overload covers the case of a standalone callable and unrelated trackable
|
1329 |
+
* object.
|
1330 |
+
*
|
1331 |
+
* Note: only weak references are stored, a slot does not extend the lifetime
|
1332 |
+
* of a suppied object.
|
1333 |
+
*
|
1334 |
+
* @param c a callable
|
1335 |
+
* @param ptr a trackable object pointer
|
1336 |
+
* @param gid an identifier that can be used to order slot execution
|
1337 |
+
* @return a connection object that can be used to interact with the slot
|
1338 |
+
*/
|
1339 |
+
template <typename Callable, typename Trackable>
|
1340 |
+
std::enable_if_t<trait::is_callable_v<arg_list, Callable> &&
|
1341 |
+
trait::is_weak_ptr_compatible_v<Trackable>, connection>
|
1342 |
+
connect(Callable && c, Trackable && ptr, group_id gid = 0) {
|
1343 |
+
using trait::to_weak;
|
1344 |
+
auto w = to_weak(std::forward<Trackable>(ptr));
|
1345 |
+
using slot_t = detail::slot_tracked<Callable, decltype(w), T...>;
|
1346 |
+
auto s = make_slot<slot_t>(std::forward<Callable>(c), w, gid);
|
1347 |
+
connection conn(s);
|
1348 |
+
add_slot(std::move(s));
|
1349 |
+
return conn;
|
1350 |
+
}
|
1351 |
+
|
1352 |
+
/**
|
1353 |
+
* Creates a connection whose duration is tied to the return object
|
1354 |
+
* Use the same semantics as connect
|
1355 |
+
*/
|
1356 |
+
template <typename... CallArgs>
|
1357 |
+
scoped_connection connect_scoped(CallArgs && ...args) {
|
1358 |
+
return connect(std::forward<CallArgs>(args)...);
|
1359 |
+
}
|
1360 |
+
|
1361 |
+
/**
|
1362 |
+
* Disconnect slots bound to a callable
|
1363 |
+
*
|
1364 |
+
* Effect: Disconnects all the slots bound to the callable in argument.
|
1365 |
+
* Safety: Thread-safety depends on locking policy.
|
1366 |
+
*
|
1367 |
+
* If the callable is a free or static member function, this overload is always
|
1368 |
+
* available. However, RTTI is needed for it to work for pointer to member
|
1369 |
+
* functions, function objects or and (references to) lambdas, because the
|
1370 |
+
* C++ spec does not mandate the pointers to member functions to be unique.
|
1371 |
+
*
|
1372 |
+
* @param c a callable
|
1373 |
+
* @return the number of disconnected slots
|
1374 |
+
*/
|
1375 |
+
template <typename Callable>
|
1376 |
+
std::enable_if_t<(trait::is_callable_v<arg_list, Callable> ||
|
1377 |
+
trait::is_callable_v<ext_arg_list, Callable> ||
|
1378 |
+
trait::is_pmf_v<Callable>) &&
|
1379 |
+
detail::function_traits<Callable>::is_disconnectable, size_t>
|
1380 |
+
disconnect(const Callable &c) {
|
1381 |
+
return disconnect_if([&] (const auto &s) {
|
1382 |
+
return s->has_full_callable(c);
|
1383 |
+
});
|
1384 |
+
}
|
1385 |
+
|
1386 |
+
/**
|
1387 |
+
* Disconnect slots bound to this object
|
1388 |
+
*
|
1389 |
+
* Effect: Disconnects all the slots bound to the object or tracked object
|
1390 |
+
* in argument.
|
1391 |
+
* Safety: Thread-safety depends on locking policy.
|
1392 |
+
*
|
1393 |
+
* The object may be a pointer or trackable object.
|
1394 |
+
*
|
1395 |
+
* @param obj an object
|
1396 |
+
* @return the number of disconnected slots
|
1397 |
+
*/
|
1398 |
+
template <typename Obj>
|
1399 |
+
std::enable_if_t<!trait::is_callable_v<arg_list, Obj> &&
|
1400 |
+
!trait::is_callable_v<ext_arg_list, Obj> &&
|
1401 |
+
!trait::is_pmf_v<Obj>, size_t>
|
1402 |
+
disconnect(const Obj &obj) {
|
1403 |
+
return disconnect_if([&] (const auto &s) {
|
1404 |
+
return s->has_object(obj);
|
1405 |
+
});
|
1406 |
+
}
|
1407 |
+
|
1408 |
+
/**
|
1409 |
+
* Disconnect slots bound both to a callable and object
|
1410 |
+
*
|
1411 |
+
* Effect: Disconnects all the slots bound to the callable and object in argument.
|
1412 |
+
* Safety: Thread-safety depends on locking policy.
|
1413 |
+
*
|
1414 |
+
* For naked pointers, the Callable is expected to be a pointer over member
|
1415 |
+
* function. If obj is trackable, any kind of Callable can be used.
|
1416 |
+
*
|
1417 |
+
* @param c a callable
|
1418 |
+
* @param obj an object
|
1419 |
+
* @return the number of disconnected slots
|
1420 |
+
*/
|
1421 |
+
template <typename Callable, typename Obj>
|
1422 |
+
size_t disconnect(const Callable &c, const Obj &obj) {
|
1423 |
+
return disconnect_if([&] (const auto &s) {
|
1424 |
+
return s->has_object(obj) && s->has_callable(c);
|
1425 |
+
});
|
1426 |
+
}
|
1427 |
+
|
1428 |
+
/**
|
1429 |
+
* Disconnect slots in a particular group
|
1430 |
+
*
|
1431 |
+
* Effect: Disconnects all the slots in the group id in argument.
|
1432 |
+
* Safety: Thread-safety depends on locking policy.
|
1433 |
+
*
|
1434 |
+
* @param gid a group id
|
1435 |
+
* @return the number of disconnected slots
|
1436 |
+
*/
|
1437 |
+
size_t disconnect(group_id gid) {
|
1438 |
+
lock_type lock(m_mutex);
|
1439 |
+
for (auto &group : detail::cow_write(m_slots)) {
|
1440 |
+
if (group.gid == gid) {
|
1441 |
+
size_t count = group.slts.size();
|
1442 |
+
group.slts.clear();
|
1443 |
+
return count;
|
1444 |
+
}
|
1445 |
+
}
|
1446 |
+
return 0;
|
1447 |
+
}
|
1448 |
+
|
1449 |
+
/**
|
1450 |
+
* Disconnects all the slots
|
1451 |
+
* Safety: Thread safety depends on locking policy
|
1452 |
+
*/
|
1453 |
+
void disconnect_all() {
|
1454 |
+
lock_type lock(m_mutex);
|
1455 |
+
clear();
|
1456 |
+
}
|
1457 |
+
|
1458 |
+
/**
|
1459 |
+
* Blocks signal emission
|
1460 |
+
* Safety: thread safe
|
1461 |
+
*/
|
1462 |
+
void block() noexcept {
|
1463 |
+
m_block.store(true);
|
1464 |
+
}
|
1465 |
+
|
1466 |
+
/**
|
1467 |
+
* Unblocks signal emission
|
1468 |
+
* Safety: thread safe
|
1469 |
+
*/
|
1470 |
+
void unblock() noexcept {
|
1471 |
+
m_block.store(false);
|
1472 |
+
}
|
1473 |
+
|
1474 |
+
/**
|
1475 |
+
* Tests blocking state of signal emission
|
1476 |
+
*/
|
1477 |
+
bool blocked() const noexcept {
|
1478 |
+
return m_block.load();
|
1479 |
+
}
|
1480 |
+
|
1481 |
+
/**
|
1482 |
+
* Get number of connected slots
|
1483 |
+
* Safety: thread safe
|
1484 |
+
*/
|
1485 |
+
size_t slot_count() noexcept {
|
1486 |
+
cow_copy_type<list_type, Lockable> ref = slots_reference();
|
1487 |
+
size_t count = 0;
|
1488 |
+
for (const auto &g : detail::cow_read(ref)) {
|
1489 |
+
count += g.slts.size();
|
1490 |
+
}
|
1491 |
+
return count;
|
1492 |
+
}
|
1493 |
+
|
1494 |
+
protected:
|
1495 |
+
/**
|
1496 |
+
* remove disconnected slots
|
1497 |
+
*/
|
1498 |
+
void clean(detail::slot_state *state) override {
|
1499 |
+
lock_type lock(m_mutex);
|
1500 |
+
const auto idx = state->index();
|
1501 |
+
const auto gid = state->group();
|
1502 |
+
|
1503 |
+
// find the group
|
1504 |
+
for (auto &group : detail::cow_write(m_slots)) {
|
1505 |
+
if (group.gid == gid) {
|
1506 |
+
auto &slts = group.slts;
|
1507 |
+
|
1508 |
+
// ensure we have the right slot, in case of concurrent cleaning
|
1509 |
+
if (idx < slts.size() && slts[idx] && slts[idx].get() == state) {
|
1510 |
+
std::swap(slts[idx], slts.back());
|
1511 |
+
slts[idx]->index() = idx;
|
1512 |
+
slts.pop_back();
|
1513 |
+
}
|
1514 |
+
|
1515 |
+
return;
|
1516 |
+
}
|
1517 |
+
}
|
1518 |
+
}
|
1519 |
+
|
1520 |
+
private:
|
1521 |
+
// used to get a reference to the slots for reading
|
1522 |
+
inline cow_copy_type<list_type, Lockable> slots_reference() {
|
1523 |
+
lock_type lock(m_mutex);
|
1524 |
+
return m_slots;
|
1525 |
+
}
|
1526 |
+
|
1527 |
+
// create a new slot
|
1528 |
+
template <typename Slot, typename... A>
|
1529 |
+
inline auto make_slot(A && ...a) {
|
1530 |
+
return detail::make_shared<slot_base, Slot>(*this, std::forward<A>(a)...);
|
1531 |
+
}
|
1532 |
+
|
1533 |
+
// add the slot to the list of slots of the right group
|
1534 |
+
void add_slot(slot_ptr &&s) {
|
1535 |
+
const group_id gid = s->group();
|
1536 |
+
|
1537 |
+
lock_type lock(m_mutex);
|
1538 |
+
auto &groups = detail::cow_write(m_slots);
|
1539 |
+
|
1540 |
+
// find the group
|
1541 |
+
auto it = groups.begin();
|
1542 |
+
while (it != groups.end() && it->gid < gid) {
|
1543 |
+
it++;
|
1544 |
+
}
|
1545 |
+
|
1546 |
+
// create a new group if necessary
|
1547 |
+
if (it == groups.end() || it->gid != gid) {
|
1548 |
+
it = groups.insert(it, {{}, gid});
|
1549 |
+
}
|
1550 |
+
|
1551 |
+
// add the slot
|
1552 |
+
s->index() = it->slts.size();
|
1553 |
+
it->slts.push_back(std::move(s));
|
1554 |
+
}
|
1555 |
+
|
1556 |
+
// disconnect a slot if a condition occurs
|
1557 |
+
template <typename Cond>
|
1558 |
+
size_t disconnect_if(Cond && cond) {
|
1559 |
+
lock_type lock(m_mutex);
|
1560 |
+
auto &groups = detail::cow_write(m_slots);
|
1561 |
+
|
1562 |
+
size_t count = 0;
|
1563 |
+
|
1564 |
+
for (auto &group : groups) {
|
1565 |
+
auto &slts = group.slts;
|
1566 |
+
size_t i = 0;
|
1567 |
+
while (i < slts.size()) {
|
1568 |
+
if (cond(slts[i])) {
|
1569 |
+
std::swap(slts[i], slts.back());
|
1570 |
+
slts[i]->index() = i;
|
1571 |
+
slts.pop_back();
|
1572 |
+
++count;
|
1573 |
+
} else {
|
1574 |
+
++i;
|
1575 |
+
}
|
1576 |
+
}
|
1577 |
+
}
|
1578 |
+
|
1579 |
+
return count;
|
1580 |
+
}
|
1581 |
+
|
1582 |
+
// to be called under lock: remove all the slots
|
1583 |
+
void clear() {
|
1584 |
+
detail::cow_write(m_slots).clear();
|
1585 |
+
}
|
1586 |
+
|
1587 |
+
private:
|
1588 |
+
Lockable m_mutex;
|
1589 |
+
cow_type<list_type, Lockable> m_slots;
|
1590 |
+
std::atomic<bool> m_block;
|
1591 |
+
};
|
1592 |
+
|
1593 |
+
/**
|
1594 |
+
* Specialization of signal_base to be used in single threaded contexts.
|
1595 |
+
* Slot connection, disconnection and signal emission are not thread-safe.
|
1596 |
+
* The performance improvement over the thread-safe variant is not impressive,
|
1597 |
+
* so this is not very useful.
|
1598 |
+
*/
|
1599 |
+
template <typename... T>
|
1600 |
+
using signal_st = signal_base<detail::null_mutex, T...>;
|
1601 |
+
|
1602 |
+
/**
|
1603 |
+
* Specialization of signal_base to be used in multi-threaded contexts.
|
1604 |
+
* Slot connection, disconnection and signal emission are thread-safe.
|
1605 |
+
*
|
1606 |
+
* Recursive signal emission and emission cycles are supported too.
|
1607 |
+
*/
|
1608 |
+
template <typename... T>
|
1609 |
+
using signal = signal_base<std::mutex, T...>;
|
1610 |
+
|
1611 |
+
} // namespace sigslot
|
third-party/DPVO/Pangolin/components/pango_core/src/avx_math.cpp
ADDED
@@ -0,0 +1,553 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
AVX implementation of sin, cos, sincos, exp and log
|
3 |
+
|
4 |
+
Based on "sse_mathfun.h", by Julien Pommier
|
5 |
+
http://gruntthepeon.free.fr/ssemath/
|
6 |
+
|
7 |
+
Copyright (C) 2012 Giovanni Garberoglio
|
8 |
+
Interdisciplinary Laboratory for Computational Science (LISC)
|
9 |
+
Fondazione Bruno Kessler and University of Trento
|
10 |
+
via Sommarive, 18
|
11 |
+
I-38123 Trento (Italy)
|
12 |
+
|
13 |
+
This software is provided 'as-is', without any express or implied
|
14 |
+
warranty. In no event will the authors be held liable for any damages
|
15 |
+
arising from the use of this software.
|
16 |
+
|
17 |
+
Permission is granted to anyone to use this software for any purpose,
|
18 |
+
including commercial applications, and to alter it and redistribute it
|
19 |
+
freely, subject to the following restrictions:
|
20 |
+
|
21 |
+
1. The origin of this software must not be misrepresented; you must not
|
22 |
+
claim that you wrote the original software. If you use this software
|
23 |
+
in a product, an acknowledgment in the product documentation would be
|
24 |
+
appreciated but is not required.
|
25 |
+
2. Altered source versions must be plainly marked as such, and must not be
|
26 |
+
misrepresented as being the original software.
|
27 |
+
3. This notice may not be removed or altered from any source distribution.
|
28 |
+
|
29 |
+
(this is the zlib license)
|
30 |
+
*/
|
31 |
+
|
32 |
+
/*
|
33 |
+
From: http://software-lisc.fbk.eu/avx_mathfun/
|
34 |
+
*/
|
35 |
+
|
36 |
+
#include <pangolin/utils/avx_math.h>
|
37 |
+
|
38 |
+
#ifdef __AVX2__
|
39 |
+
namespace pangolin
|
40 |
+
{
|
41 |
+
/* yes I know, the top of this file is quite ugly */
|
42 |
+
#ifdef _MSC_VER
|
43 |
+
# define ALIGN32_BEG __declspec(align(32))
|
44 |
+
# define ALIGN32_END
|
45 |
+
#else
|
46 |
+
# define ALIGN32_BEG
|
47 |
+
# define ALIGN32_END __attribute__((aligned(32)))
|
48 |
+
#endif
|
49 |
+
|
50 |
+
/* declare some AVX constants -- why can't I figure a better way to do that? */
|
51 |
+
#define _PS256_CONST(Name, Val) \
|
52 |
+
static const ALIGN32_BEG float _ps256_##Name[8] ALIGN32_END = { Val, Val, Val, Val, Val, Val, Val, Val }
|
53 |
+
#define _PI32_CONST256(Name, Val) \
|
54 |
+
static const ALIGN32_BEG int _pi32_256_##Name[8] ALIGN32_END = { Val, Val, Val, Val, Val, Val, Val, Val }
|
55 |
+
#define _PS256_CONST_TYPE(Name, Type, Val) \
|
56 |
+
static const ALIGN32_BEG Type _ps256_##Name[8] ALIGN32_END = { Val, Val, Val, Val, Val, Val, Val, Val }
|
57 |
+
|
58 |
+
_PS256_CONST(1 , 1.0f);
|
59 |
+
_PS256_CONST(0p5, 0.5f);
|
60 |
+
/* the smallest non denormalized float number */
|
61 |
+
|
62 |
+
#ifdef __GNUC__
|
63 |
+
#pragma GCC diagnostic push
|
64 |
+
#pragma GCC diagnostic ignored "-Wnarrowing"
|
65 |
+
#endif
|
66 |
+
_PS256_CONST_TYPE(min_norm_pos, int, 0x00800000);
|
67 |
+
_PS256_CONST_TYPE(inv_mant_mask, int, ~0x7f800000);
|
68 |
+
_PS256_CONST_TYPE(sign_mask, int, 0x80000000);
|
69 |
+
_PS256_CONST_TYPE(inv_sign_mask, int, ~0x80000000);
|
70 |
+
#ifdef __GNUC__
|
71 |
+
#pragma GCC diagnostic pop
|
72 |
+
#endif
|
73 |
+
|
74 |
+
_PI32_CONST256(0, 0);
|
75 |
+
_PI32_CONST256(1, 1);
|
76 |
+
_PI32_CONST256(inv1, ~1);
|
77 |
+
_PI32_CONST256(2, 2);
|
78 |
+
_PI32_CONST256(4, 4);
|
79 |
+
_PI32_CONST256(0x7f, 0x7f);
|
80 |
+
_PI32_CONST256(signbit, 0x7FFFFFFF);
|
81 |
+
|
82 |
+
_PS256_CONST(cephes_SQRTHF, 0.707106781186547524);
|
83 |
+
_PS256_CONST(cephes_log_p0, 7.0376836292E-2);
|
84 |
+
_PS256_CONST(cephes_log_p1, - 1.1514610310E-1);
|
85 |
+
_PS256_CONST(cephes_log_p2, 1.1676998740E-1);
|
86 |
+
_PS256_CONST(cephes_log_p3, - 1.2420140846E-1);
|
87 |
+
_PS256_CONST(cephes_log_p4, + 1.4249322787E-1);
|
88 |
+
_PS256_CONST(cephes_log_p5, - 1.6668057665E-1);
|
89 |
+
_PS256_CONST(cephes_log_p6, + 2.0000714765E-1);
|
90 |
+
_PS256_CONST(cephes_log_p7, - 2.4999993993E-1);
|
91 |
+
_PS256_CONST(cephes_log_p8, + 3.3333331174E-1);
|
92 |
+
_PS256_CONST(cephes_log_q1, -2.12194440e-4);
|
93 |
+
_PS256_CONST(cephes_log_q2, 0.693359375);
|
94 |
+
|
95 |
+
/* natural logarithm computed for 8 simultaneous float
|
96 |
+
return NaN for x <= 0
|
97 |
+
*/
|
98 |
+
__m256 log256_ps(__m256 x) {
|
99 |
+
__m256i imm0;
|
100 |
+
__m256 one = *(__m256*)_ps256_1;
|
101 |
+
|
102 |
+
//__m256 invalid_mask = _mm256_cmple_ps(x, _mm256_setzero_ps());
|
103 |
+
__m256 invalid_mask = _mm256_cmp_ps(x, _mm256_setzero_ps(), _CMP_LE_OS);
|
104 |
+
|
105 |
+
x = _mm256_max_ps(x, *(__m256*)_ps256_min_norm_pos); /* cut off denormalized stuff */
|
106 |
+
|
107 |
+
// can be done with AVX2
|
108 |
+
imm0 = _mm256_srli_epi32(_mm256_castps_si256(x), 23);
|
109 |
+
|
110 |
+
/* keep only the fractional part */
|
111 |
+
x = _mm256_and_ps(x, *(__m256*)_ps256_inv_mant_mask);
|
112 |
+
x = _mm256_or_ps(x, *(__m256*)_ps256_0p5);
|
113 |
+
|
114 |
+
// this is again another AVX2 instruction
|
115 |
+
imm0 = _mm256_sub_epi32(imm0, *(__m256i*)_pi32_256_0x7f);
|
116 |
+
__m256 e = _mm256_cvtepi32_ps(imm0);
|
117 |
+
|
118 |
+
e = _mm256_add_ps(e, one);
|
119 |
+
|
120 |
+
/* part2:
|
121 |
+
if( x < SQRTHF ) {
|
122 |
+
e -= 1;
|
123 |
+
x = x + x - 1.0;
|
124 |
+
} else { x = x - 1.0; }
|
125 |
+
*/
|
126 |
+
//__m256 mask = _mm256_cmplt_ps(x, *(__m256*)_ps256_cephes_SQRTHF);
|
127 |
+
__m256 mask = _mm256_cmp_ps(x, *(__m256*)_ps256_cephes_SQRTHF, _CMP_LT_OS);
|
128 |
+
__m256 tmp = _mm256_and_ps(x, mask);
|
129 |
+
x = _mm256_sub_ps(x, one);
|
130 |
+
e = _mm256_sub_ps(e, _mm256_and_ps(one, mask));
|
131 |
+
x = _mm256_add_ps(x, tmp);
|
132 |
+
|
133 |
+
__m256 z = _mm256_mul_ps(x,x);
|
134 |
+
|
135 |
+
__m256 y = *(__m256*)_ps256_cephes_log_p0;
|
136 |
+
y = _mm256_mul_ps(y, x);
|
137 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_log_p1);
|
138 |
+
y = _mm256_mul_ps(y, x);
|
139 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_log_p2);
|
140 |
+
y = _mm256_mul_ps(y, x);
|
141 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_log_p3);
|
142 |
+
y = _mm256_mul_ps(y, x);
|
143 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_log_p4);
|
144 |
+
y = _mm256_mul_ps(y, x);
|
145 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_log_p5);
|
146 |
+
y = _mm256_mul_ps(y, x);
|
147 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_log_p6);
|
148 |
+
y = _mm256_mul_ps(y, x);
|
149 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_log_p7);
|
150 |
+
y = _mm256_mul_ps(y, x);
|
151 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_log_p8);
|
152 |
+
y = _mm256_mul_ps(y, x);
|
153 |
+
|
154 |
+
y = _mm256_mul_ps(y, z);
|
155 |
+
|
156 |
+
tmp = _mm256_mul_ps(e, *(__m256*)_ps256_cephes_log_q1);
|
157 |
+
y = _mm256_add_ps(y, tmp);
|
158 |
+
|
159 |
+
|
160 |
+
tmp = _mm256_mul_ps(z, *(__m256*)_ps256_0p5);
|
161 |
+
y = _mm256_sub_ps(y, tmp);
|
162 |
+
|
163 |
+
tmp = _mm256_mul_ps(e, *(__m256*)_ps256_cephes_log_q2);
|
164 |
+
x = _mm256_add_ps(x, y);
|
165 |
+
x = _mm256_add_ps(x, tmp);
|
166 |
+
x = _mm256_or_ps(x, invalid_mask); // negative arg will be NAN
|
167 |
+
return x;
|
168 |
+
}
|
169 |
+
|
170 |
+
_PS256_CONST(exp_hi, 88.3762626647949f);
|
171 |
+
_PS256_CONST(exp_lo, -88.3762626647949f);
|
172 |
+
|
173 |
+
_PS256_CONST(cephes_LOG2EF, 1.44269504088896341);
|
174 |
+
_PS256_CONST(cephes_exp_C1, 0.693359375);
|
175 |
+
_PS256_CONST(cephes_exp_C2, -2.12194440e-4);
|
176 |
+
|
177 |
+
_PS256_CONST(cephes_exp_p0, 1.9875691500E-4);
|
178 |
+
_PS256_CONST(cephes_exp_p1, 1.3981999507E-3);
|
179 |
+
_PS256_CONST(cephes_exp_p2, 8.3334519073E-3);
|
180 |
+
_PS256_CONST(cephes_exp_p3, 4.1665795894E-2);
|
181 |
+
_PS256_CONST(cephes_exp_p4, 1.6666665459E-1);
|
182 |
+
_PS256_CONST(cephes_exp_p5, 5.0000001201E-1);
|
183 |
+
|
184 |
+
__m256 exp256_ps(__m256 x) {
|
185 |
+
__m256 tmp = _mm256_setzero_ps(), fx;
|
186 |
+
__m256i imm0;
|
187 |
+
__m256 one = *(__m256*)_ps256_1;
|
188 |
+
|
189 |
+
x = _mm256_min_ps(x, *(__m256*)_ps256_exp_hi);
|
190 |
+
x = _mm256_max_ps(x, *(__m256*)_ps256_exp_lo);
|
191 |
+
|
192 |
+
/* express exp(x) as exp(g + n*log(2)) */
|
193 |
+
fx = _mm256_mul_ps(x, *(__m256*)_ps256_cephes_LOG2EF);
|
194 |
+
fx = _mm256_add_ps(fx, *(__m256*)_ps256_0p5);
|
195 |
+
|
196 |
+
/* how to perform a floorf with SSE: just below */
|
197 |
+
//imm0 = _mm256_cvttps_epi32(fx);
|
198 |
+
//tmp = _mm256_cvtepi32_ps(imm0);
|
199 |
+
|
200 |
+
tmp = _mm256_floor_ps(fx);
|
201 |
+
|
202 |
+
/* if greater, substract 1 */
|
203 |
+
//__m256 mask = _mm256_cmpgt_ps(tmp, fx);
|
204 |
+
__m256 mask = _mm256_cmp_ps(tmp, fx, _CMP_GT_OS);
|
205 |
+
mask = _mm256_and_ps(mask, one);
|
206 |
+
fx = _mm256_sub_ps(tmp, mask);
|
207 |
+
|
208 |
+
tmp = _mm256_mul_ps(fx, *(__m256*)_ps256_cephes_exp_C1);
|
209 |
+
__m256 z = _mm256_mul_ps(fx, *(__m256*)_ps256_cephes_exp_C2);
|
210 |
+
x = _mm256_sub_ps(x, tmp);
|
211 |
+
x = _mm256_sub_ps(x, z);
|
212 |
+
|
213 |
+
z = _mm256_mul_ps(x,x);
|
214 |
+
|
215 |
+
__m256 y = *(__m256*)_ps256_cephes_exp_p0;
|
216 |
+
y = _mm256_mul_ps(y, x);
|
217 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_exp_p1);
|
218 |
+
y = _mm256_mul_ps(y, x);
|
219 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_exp_p2);
|
220 |
+
y = _mm256_mul_ps(y, x);
|
221 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_exp_p3);
|
222 |
+
y = _mm256_mul_ps(y, x);
|
223 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_exp_p4);
|
224 |
+
y = _mm256_mul_ps(y, x);
|
225 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_cephes_exp_p5);
|
226 |
+
y = _mm256_mul_ps(y, z);
|
227 |
+
y = _mm256_add_ps(y, x);
|
228 |
+
y = _mm256_add_ps(y, one);
|
229 |
+
|
230 |
+
/* build 2^n */
|
231 |
+
imm0 = _mm256_cvttps_epi32(fx);
|
232 |
+
// another two AVX2 instructions
|
233 |
+
imm0 = _mm256_add_epi32(imm0, *(__m256i*)_pi32_256_0x7f);
|
234 |
+
imm0 = _mm256_slli_epi32(imm0, 23);
|
235 |
+
__m256 pow2n = _mm256_castsi256_ps(imm0);
|
236 |
+
y = _mm256_mul_ps(y, pow2n);
|
237 |
+
return y;
|
238 |
+
}
|
239 |
+
|
240 |
+
_PS256_CONST(minus_cephes_DP1, -0.78515625);
|
241 |
+
_PS256_CONST(minus_cephes_DP2, -2.4187564849853515625e-4);
|
242 |
+
_PS256_CONST(minus_cephes_DP3, -3.77489497744594108e-8);
|
243 |
+
_PS256_CONST(sincof_p0, -1.9515295891E-4);
|
244 |
+
_PS256_CONST(sincof_p1, 8.3321608736E-3);
|
245 |
+
_PS256_CONST(sincof_p2, -1.6666654611E-1);
|
246 |
+
_PS256_CONST(coscof_p0, 2.443315711809948E-005);
|
247 |
+
_PS256_CONST(coscof_p1, -1.388731625493765E-003);
|
248 |
+
_PS256_CONST(coscof_p2, 4.166664568298827E-002);
|
249 |
+
_PS256_CONST(cephes_FOPI, 1.27323954473516); // 4 / M_PI
|
250 |
+
|
251 |
+
|
252 |
+
/* evaluation of 8 sines at onces using AVX intrisics
|
253 |
+
|
254 |
+
The code is the exact rewriting of the cephes sinf function.
|
255 |
+
Precision is excellent as long as x < 8192 (I did not bother to
|
256 |
+
take into account the special handling they have for greater values
|
257 |
+
-- it does not return garbage for arguments over 8192, though, but
|
258 |
+
the extra precision is missing).
|
259 |
+
|
260 |
+
Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the
|
261 |
+
surprising but correct result.
|
262 |
+
|
263 |
+
*/
|
264 |
+
__m256 sin256_ps(__m256 x) { // any x
|
265 |
+
__m256 xmm1, xmm2 = _mm256_setzero_ps(), xmm3, sign_bit, y;
|
266 |
+
__m256i imm0, imm2;
|
267 |
+
|
268 |
+
sign_bit = x;
|
269 |
+
/* take the absolute value */
|
270 |
+
x = _mm256_and_ps(x, *(__m256*)_ps256_inv_sign_mask);
|
271 |
+
/* extract the sign bit (upper one) */
|
272 |
+
sign_bit = _mm256_and_ps(sign_bit, *(__m256*)_ps256_sign_mask);
|
273 |
+
|
274 |
+
/* scale by 4/Pi */
|
275 |
+
y = _mm256_mul_ps(x, *(__m256*)_ps256_cephes_FOPI);
|
276 |
+
|
277 |
+
/*
|
278 |
+
Here we start a series of integer operations, which are in the
|
279 |
+
realm of AVX2.
|
280 |
+
If we don't have AVX, let's perform them using SSE2 directives
|
281 |
+
*/
|
282 |
+
|
283 |
+
/* store the integer part of y in mm0 */
|
284 |
+
imm2 = _mm256_cvttps_epi32(y);
|
285 |
+
/* j=(j+1) & (~1) (see the cephes sources) */
|
286 |
+
// another two AVX2 instruction
|
287 |
+
imm2 = _mm256_add_epi32(imm2, *(__m256i*)_pi32_256_1);
|
288 |
+
imm2 = _mm256_and_si256(imm2, *(__m256i*)_pi32_256_inv1);
|
289 |
+
y = _mm256_cvtepi32_ps(imm2);
|
290 |
+
|
291 |
+
/* get the swap sign flag */
|
292 |
+
imm0 = _mm256_and_si256(imm2, *(__m256i*)_pi32_256_4);
|
293 |
+
imm0 = _mm256_slli_epi32(imm0, 29);
|
294 |
+
/* get the polynom selection mask
|
295 |
+
there is one polynom for 0 <= x <= Pi/4
|
296 |
+
and another one for Pi/4<x<=Pi/2
|
297 |
+
|
298 |
+
Both branches will be computed.
|
299 |
+
*/
|
300 |
+
imm2 = _mm256_and_si256(imm2, *(__m256i*)_pi32_256_2);
|
301 |
+
imm2 = _mm256_cmpeq_epi32(imm2,*(__m256i*)_pi32_256_0);
|
302 |
+
|
303 |
+
__m256 swap_sign_bit = _mm256_castsi256_ps(imm0);
|
304 |
+
__m256 poly_mask = _mm256_castsi256_ps(imm2);
|
305 |
+
sign_bit = _mm256_xor_ps(sign_bit, swap_sign_bit);
|
306 |
+
|
307 |
+
/* The magic pass: "Extended precision modular arithmetic"
|
308 |
+
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
309 |
+
xmm1 = *(__m256*)_ps256_minus_cephes_DP1;
|
310 |
+
xmm2 = *(__m256*)_ps256_minus_cephes_DP2;
|
311 |
+
xmm3 = *(__m256*)_ps256_minus_cephes_DP3;
|
312 |
+
xmm1 = _mm256_mul_ps(y, xmm1);
|
313 |
+
xmm2 = _mm256_mul_ps(y, xmm2);
|
314 |
+
xmm3 = _mm256_mul_ps(y, xmm3);
|
315 |
+
x = _mm256_add_ps(x, xmm1);
|
316 |
+
x = _mm256_add_ps(x, xmm2);
|
317 |
+
x = _mm256_add_ps(x, xmm3);
|
318 |
+
|
319 |
+
/* Evaluate the first polynom (0 <= x <= Pi/4) */
|
320 |
+
y = *(__m256*)_ps256_coscof_p0;
|
321 |
+
__m256 z = _mm256_mul_ps(x,x);
|
322 |
+
|
323 |
+
y = _mm256_mul_ps(y, z);
|
324 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_coscof_p1);
|
325 |
+
y = _mm256_mul_ps(y, z);
|
326 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_coscof_p2);
|
327 |
+
y = _mm256_mul_ps(y, z);
|
328 |
+
y = _mm256_mul_ps(y, z);
|
329 |
+
__m256 tmp = _mm256_mul_ps(z, *(__m256*)_ps256_0p5);
|
330 |
+
y = _mm256_sub_ps(y, tmp);
|
331 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_1);
|
332 |
+
|
333 |
+
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
|
334 |
+
|
335 |
+
__m256 y2 = *(__m256*)_ps256_sincof_p0;
|
336 |
+
y2 = _mm256_mul_ps(y2, z);
|
337 |
+
y2 = _mm256_add_ps(y2, *(__m256*)_ps256_sincof_p1);
|
338 |
+
y2 = _mm256_mul_ps(y2, z);
|
339 |
+
y2 = _mm256_add_ps(y2, *(__m256*)_ps256_sincof_p2);
|
340 |
+
y2 = _mm256_mul_ps(y2, z);
|
341 |
+
y2 = _mm256_mul_ps(y2, x);
|
342 |
+
y2 = _mm256_add_ps(y2, x);
|
343 |
+
|
344 |
+
/* select the correct result from the two polynoms */
|
345 |
+
xmm3 = poly_mask;
|
346 |
+
y2 = _mm256_and_ps(xmm3, y2); //, xmm3);
|
347 |
+
y = _mm256_andnot_ps(xmm3, y);
|
348 |
+
y = _mm256_add_ps(y,y2);
|
349 |
+
/* update the sign */
|
350 |
+
y = _mm256_xor_ps(y, sign_bit);
|
351 |
+
|
352 |
+
return y;
|
353 |
+
}
|
354 |
+
|
355 |
+
/* almost the same as sin_ps */
|
356 |
+
__m256 cos256_ps(__m256 x) { // any x
|
357 |
+
__m256 xmm1, xmm2 = _mm256_setzero_ps(), xmm3, y;
|
358 |
+
__m256i imm0, imm2;
|
359 |
+
|
360 |
+
/* take the absolute value */
|
361 |
+
x = _mm256_and_ps(x, *(__m256*)_ps256_inv_sign_mask);
|
362 |
+
|
363 |
+
/* scale by 4/Pi */
|
364 |
+
y = _mm256_mul_ps(x, *(__m256*)_ps256_cephes_FOPI);
|
365 |
+
|
366 |
+
/* store the integer part of y in mm0 */
|
367 |
+
imm2 = _mm256_cvttps_epi32(y);
|
368 |
+
/* j=(j+1) & (~1) (see the cephes sources) */
|
369 |
+
imm2 = _mm256_add_epi32(imm2, *(__m256i*)_pi32_256_1);
|
370 |
+
imm2 = _mm256_and_si256(imm2, *(__m256i*)_pi32_256_inv1);
|
371 |
+
y = _mm256_cvtepi32_ps(imm2);
|
372 |
+
imm2 = _mm256_sub_epi32(imm2, *(__m256i*)_pi32_256_2);
|
373 |
+
|
374 |
+
/* get the swap sign flag */
|
375 |
+
imm0 = _mm256_andnot_si256(imm2, *(__m256i*)_pi32_256_4);
|
376 |
+
imm0 = _mm256_slli_epi32(imm0, 29);
|
377 |
+
/* get the polynom selection mask */
|
378 |
+
imm2 = _mm256_and_si256(imm2, *(__m256i*)_pi32_256_2);
|
379 |
+
imm2 = _mm256_cmpeq_epi32(imm2, *(__m256i*)_pi32_256_0);
|
380 |
+
|
381 |
+
__m256 sign_bit = _mm256_castsi256_ps(imm0);
|
382 |
+
__m256 poly_mask = _mm256_castsi256_ps(imm2);
|
383 |
+
|
384 |
+
/* The magic pass: "Extended precision modular arithmetic"
|
385 |
+
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
386 |
+
xmm1 = *(__m256*)_ps256_minus_cephes_DP1;
|
387 |
+
xmm2 = *(__m256*)_ps256_minus_cephes_DP2;
|
388 |
+
xmm3 = *(__m256*)_ps256_minus_cephes_DP3;
|
389 |
+
xmm1 = _mm256_mul_ps(y, xmm1);
|
390 |
+
xmm2 = _mm256_mul_ps(y, xmm2);
|
391 |
+
xmm3 = _mm256_mul_ps(y, xmm3);
|
392 |
+
x = _mm256_add_ps(x, xmm1);
|
393 |
+
x = _mm256_add_ps(x, xmm2);
|
394 |
+
x = _mm256_add_ps(x, xmm3);
|
395 |
+
|
396 |
+
/* Evaluate the first polynom (0 <= x <= Pi/4) */
|
397 |
+
y = *(__m256*)_ps256_coscof_p0;
|
398 |
+
__m256 z = _mm256_mul_ps(x,x);
|
399 |
+
|
400 |
+
y = _mm256_mul_ps(y, z);
|
401 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_coscof_p1);
|
402 |
+
y = _mm256_mul_ps(y, z);
|
403 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_coscof_p2);
|
404 |
+
y = _mm256_mul_ps(y, z);
|
405 |
+
y = _mm256_mul_ps(y, z);
|
406 |
+
__m256 tmp = _mm256_mul_ps(z, *(__m256*)_ps256_0p5);
|
407 |
+
y = _mm256_sub_ps(y, tmp);
|
408 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_1);
|
409 |
+
|
410 |
+
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
|
411 |
+
|
412 |
+
__m256 y2 = *(__m256*)_ps256_sincof_p0;
|
413 |
+
y2 = _mm256_mul_ps(y2, z);
|
414 |
+
y2 = _mm256_add_ps(y2, *(__m256*)_ps256_sincof_p1);
|
415 |
+
y2 = _mm256_mul_ps(y2, z);
|
416 |
+
y2 = _mm256_add_ps(y2, *(__m256*)_ps256_sincof_p2);
|
417 |
+
y2 = _mm256_mul_ps(y2, z);
|
418 |
+
y2 = _mm256_mul_ps(y2, x);
|
419 |
+
y2 = _mm256_add_ps(y2, x);
|
420 |
+
|
421 |
+
/* select the correct result from the two polynoms */
|
422 |
+
xmm3 = poly_mask;
|
423 |
+
y2 = _mm256_and_ps(xmm3, y2); //, xmm3);
|
424 |
+
y = _mm256_andnot_ps(xmm3, y);
|
425 |
+
y = _mm256_add_ps(y,y2);
|
426 |
+
/* update the sign */
|
427 |
+
y = _mm256_xor_ps(y, sign_bit);
|
428 |
+
|
429 |
+
return y;
|
430 |
+
}
|
431 |
+
|
432 |
+
/* since sin256_ps and cos256_ps are almost identical, sincos256_ps could replace both of them..
|
433 |
+
it is almost as fast, and gives you a free cosine with your sine */
|
434 |
+
void sincos256_ps(__m256 x, __m256 *s, __m256 *c) {
|
435 |
+
|
436 |
+
__m256 xmm1, xmm2, xmm3 = _mm256_setzero_ps(), sign_bit_sin, y;
|
437 |
+
__m256i imm0, imm2, imm4;
|
438 |
+
|
439 |
+
sign_bit_sin = x;
|
440 |
+
/* take the absolute value */
|
441 |
+
x = _mm256_and_ps(x, *(__m256*)_ps256_inv_sign_mask);
|
442 |
+
/* extract the sign bit (upper one) */
|
443 |
+
sign_bit_sin = _mm256_and_ps(sign_bit_sin, *(__m256*)_ps256_sign_mask);
|
444 |
+
|
445 |
+
/* scale by 4/Pi */
|
446 |
+
y = _mm256_mul_ps(x, *(__m256*)_ps256_cephes_FOPI);
|
447 |
+
|
448 |
+
/* store the integer part of y in imm2 */
|
449 |
+
imm2 = _mm256_cvttps_epi32(y);
|
450 |
+
|
451 |
+
/* j=(j+1) & (~1) (see the cephes sources) */
|
452 |
+
imm2 = _mm256_add_epi32(imm2, *(__m256i*)_pi32_256_1);
|
453 |
+
imm2 = _mm256_and_si256(imm2, *(__m256i*)_pi32_256_inv1);
|
454 |
+
|
455 |
+
y = _mm256_cvtepi32_ps(imm2);
|
456 |
+
imm4 = imm2;
|
457 |
+
|
458 |
+
/* get the swap sign flag for the sine */
|
459 |
+
imm0 = _mm256_and_si256(imm2, *(__m256i*)_pi32_256_4);
|
460 |
+
imm0 = _mm256_slli_epi32(imm0, 29);
|
461 |
+
//__m256 swap_sign_bit_sin = _mm256_castsi256_ps(imm0);
|
462 |
+
|
463 |
+
/* get the polynom selection mask for the sine*/
|
464 |
+
imm2 = _mm256_and_si256(imm2, *(__m256i*)_pi32_256_2);
|
465 |
+
imm2 = _mm256_cmpeq_epi32(imm2, *(__m256i*)_pi32_256_0);
|
466 |
+
//__m256 poly_mask = _mm256_castsi256_ps(imm2);
|
467 |
+
|
468 |
+
__m256 swap_sign_bit_sin = _mm256_castsi256_ps(imm0);
|
469 |
+
__m256 poly_mask = _mm256_castsi256_ps(imm2);
|
470 |
+
|
471 |
+
/* The magic pass: "Extended precision modular arithmetic"
|
472 |
+
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
473 |
+
xmm1 = *(__m256*)_ps256_minus_cephes_DP1;
|
474 |
+
xmm2 = *(__m256*)_ps256_minus_cephes_DP2;
|
475 |
+
xmm3 = *(__m256*)_ps256_minus_cephes_DP3;
|
476 |
+
xmm1 = _mm256_mul_ps(y, xmm1);
|
477 |
+
xmm2 = _mm256_mul_ps(y, xmm2);
|
478 |
+
xmm3 = _mm256_mul_ps(y, xmm3);
|
479 |
+
x = _mm256_add_ps(x, xmm1);
|
480 |
+
x = _mm256_add_ps(x, xmm2);
|
481 |
+
x = _mm256_add_ps(x, xmm3);
|
482 |
+
|
483 |
+
imm4 = _mm256_sub_epi32(imm4, *(__m256i*)_pi32_256_2);
|
484 |
+
imm4 = _mm256_andnot_si256(imm4, *(__m256i*)_pi32_256_4);
|
485 |
+
imm4 = _mm256_slli_epi32(imm4, 29);
|
486 |
+
|
487 |
+
__m256 sign_bit_cos = _mm256_castsi256_ps(imm4);
|
488 |
+
|
489 |
+
sign_bit_sin = _mm256_xor_ps(sign_bit_sin, swap_sign_bit_sin);
|
490 |
+
|
491 |
+
/* Evaluate the first polynom (0 <= x <= Pi/4) */
|
492 |
+
__m256 z = _mm256_mul_ps(x,x);
|
493 |
+
y = *(__m256*)_ps256_coscof_p0;
|
494 |
+
|
495 |
+
y = _mm256_mul_ps(y, z);
|
496 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_coscof_p1);
|
497 |
+
y = _mm256_mul_ps(y, z);
|
498 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_coscof_p2);
|
499 |
+
y = _mm256_mul_ps(y, z);
|
500 |
+
y = _mm256_mul_ps(y, z);
|
501 |
+
__m256 tmp = _mm256_mul_ps(z, *(__m256*)_ps256_0p5);
|
502 |
+
y = _mm256_sub_ps(y, tmp);
|
503 |
+
y = _mm256_add_ps(y, *(__m256*)_ps256_1);
|
504 |
+
|
505 |
+
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
|
506 |
+
|
507 |
+
__m256 y2 = *(__m256*)_ps256_sincof_p0;
|
508 |
+
y2 = _mm256_mul_ps(y2, z);
|
509 |
+
y2 = _mm256_add_ps(y2, *(__m256*)_ps256_sincof_p1);
|
510 |
+
y2 = _mm256_mul_ps(y2, z);
|
511 |
+
y2 = _mm256_add_ps(y2, *(__m256*)_ps256_sincof_p2);
|
512 |
+
y2 = _mm256_mul_ps(y2, z);
|
513 |
+
y2 = _mm256_mul_ps(y2, x);
|
514 |
+
y2 = _mm256_add_ps(y2, x);
|
515 |
+
|
516 |
+
/* select the correct result from the two polynoms */
|
517 |
+
xmm3 = poly_mask;
|
518 |
+
__m256 ysin2 = _mm256_and_ps(xmm3, y2);
|
519 |
+
__m256 ysin1 = _mm256_andnot_ps(xmm3, y);
|
520 |
+
y2 = _mm256_sub_ps(y2,ysin2);
|
521 |
+
y = _mm256_sub_ps(y, ysin1);
|
522 |
+
|
523 |
+
xmm1 = _mm256_add_ps(ysin1,ysin2);
|
524 |
+
xmm2 = _mm256_add_ps(y,y2);
|
525 |
+
|
526 |
+
/* update the sign */
|
527 |
+
*s = _mm256_xor_ps(xmm1, sign_bit_sin);
|
528 |
+
*c = _mm256_xor_ps(xmm2, sign_bit_cos);
|
529 |
+
}
|
530 |
+
|
531 |
+
__m256 fabs256_ps(__m256 x) {
|
532 |
+
return _mm256_and_ps(x, *(__m256*)_pi32_256_signbit);
|
533 |
+
}
|
534 |
+
|
535 |
+
// I did not find any implementation
|
536 |
+
// that is as exact as sequential execution.
|
537 |
+
// Furthermore, there is none under a free
|
538 |
+
// license:
|
539 |
+
//
|
540 |
+
// http://jrfonseca.blogspot.de/2008/09/fast-sse2-pow-tables-or-polynomials.html
|
541 |
+
// http://www.dctsystems.co.uk/Software/power.html
|
542 |
+
//
|
543 |
+
// This implementation is the trivial
|
544 |
+
// reformulation a = x^y -> a = exp(y * ln(x))
|
545 |
+
__m256 pow256_ps(__m256 x, __m256 y)
|
546 |
+
{
|
547 |
+
const __m256 l = log256_ps(x);
|
548 |
+
const __m256 f = _mm256_mul_ps(l, y);
|
549 |
+
return exp256_ps(f);
|
550 |
+
}
|
551 |
+
}
|
552 |
+
|
553 |
+
#endif
|
third-party/DPVO/Pangolin/components/pango_core/src/dummy.cpp
ADDED
File without changes
|
third-party/DPVO/Pangolin/components/pango_core/src/factory/factory_help.cpp
ADDED
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <iomanip>
|
2 |
+
#include <numeric>
|
3 |
+
#include <limits>
|
4 |
+
#include <pangolin/factory/factory_help.h>
|
5 |
+
#include <pangolin/factory/factory_registry.h>
|
6 |
+
|
7 |
+
namespace pangolin {
|
8 |
+
|
9 |
+
void PrintSchemeHelp(std::ostream& out, bool color)
|
10 |
+
{
|
11 |
+
const std::string c_normal = color ? "\033[0m" : "";
|
12 |
+
const std::string c_bold = color ? "\033[1m" : "";
|
13 |
+
const std::string c_scheme = color ? "\033[36m" : "";
|
14 |
+
const std::string c_alias = color ? "\033[32m" : "";
|
15 |
+
const std::string c_params = color ? "\033[34m" : "";
|
16 |
+
const std::string c_param = color ? "\033[31m" : "";
|
17 |
+
|
18 |
+
out << c_bold << "Using Factory Schemes" << c_normal << std::endl << std::endl;
|
19 |
+
|
20 |
+
out << "The factory to use is specified in the 'scheme' portion of the URL. Any parameters the factory takes will be reset to default values." << std::endl;
|
21 |
+
out << " e.g. \"" << c_scheme << "scheme" << c_normal << "://" << c_normal << "\"" << std::endl;
|
22 |
+
out << std::endl;
|
23 |
+
|
24 |
+
out << "When a factory needs to choose a unique resource, it can be specified using the URI portion of the URL." << std::endl;
|
25 |
+
out << " e.g. \"" << c_scheme << "scheme" << c_normal << "://" << c_param << "uri" << c_normal << "\"" << std::endl;
|
26 |
+
out << std::endl;
|
27 |
+
|
28 |
+
out << "Parameters can be specified within square brackets to override defaults." << std::endl;
|
29 |
+
out << " e.g. \"" << c_scheme << "scheme" << c_normal << ":[";
|
30 |
+
out << c_param << "param1" << c_normal << "=" << c_alias << "value1" << c_normal << ",";
|
31 |
+
out << c_param << "param2" << c_normal << "=" << c_alias << "value2" << c_normal << ",...";
|
32 |
+
out << "]//" << c_param << "uri" << c_normal << "\"" << std::endl;
|
33 |
+
out << std::endl;
|
34 |
+
}
|
35 |
+
|
36 |
+
// assumes schemes is not empty
|
37 |
+
std::string HighestPriScheme(const std::map<FactoryInterface::Name,FactoryInterface::Precedence>& schemes)
|
38 |
+
{
|
39 |
+
FactoryInterface::Name best_name;
|
40 |
+
FactoryInterface::Precedence best_pri = std::numeric_limits<FactoryInterface::Precedence>::max();
|
41 |
+
for(const auto& scheme : schemes) {
|
42 |
+
if(scheme.second < best_pri) {
|
43 |
+
best_name = scheme.first;
|
44 |
+
best_pri = scheme.second;
|
45 |
+
}
|
46 |
+
}
|
47 |
+
return best_name;
|
48 |
+
}
|
49 |
+
|
50 |
+
void PrintFactoryDetails(std::ostream& out, const std::string name, const pangolin::FactoryInterface& f, HelpVerbosity level, size_t indent, bool color)
|
51 |
+
{
|
52 |
+
const std::string c_normal = color ? "\033[0m" : "";
|
53 |
+
const std::string c_scheme = color ? "\033[36m" : "";
|
54 |
+
const std::string c_alias = color ? "\033[32m" : "";
|
55 |
+
const std::string c_params = color ? "\033[34m" : "";
|
56 |
+
const std::string c_param = color ? "\033[31m" : "";
|
57 |
+
|
58 |
+
indent = std::max(indent, name.size());
|
59 |
+
|
60 |
+
out << c_scheme;
|
61 |
+
out << std::setw(indent);
|
62 |
+
out << name << c_normal;
|
63 |
+
out << "| " << f.Description() << std::endl;
|
64 |
+
if(level >= HelpVerbosity::SYNOPSIS) {
|
65 |
+
if(f.Schemes().size() > 1) {
|
66 |
+
out << std::setw(indent) << " " << "| ";
|
67 |
+
out << c_alias << "aliases: " << c_normal << "{";
|
68 |
+
for(const auto& s : f.Schemes()) {
|
69 |
+
out << c_scheme << s.first << c_normal << " (" << s.second << "); ";
|
70 |
+
}
|
71 |
+
out << "}" << std::endl;
|
72 |
+
}
|
73 |
+
}
|
74 |
+
if(level >= HelpVerbosity::PARAMS) {
|
75 |
+
if(f.Params().params.size()) {
|
76 |
+
out << std::setw(indent) << " " << "| ";
|
77 |
+
out << c_alias << "params: " << c_normal << std::endl;
|
78 |
+
for(auto& param : f.Params().params) {
|
79 |
+
out << std::setw(indent) << " " << "| ";
|
80 |
+
out << c_param << param.name_regex << c_normal << ":";
|
81 |
+
if(!param.default_value.empty()) {
|
82 |
+
out << " (default='" << param.default_value << "')";
|
83 |
+
}
|
84 |
+
out << std::endl;
|
85 |
+
out << std::setw(indent) << " " << "| ";
|
86 |
+
out << param.description << std::endl;
|
87 |
+
}
|
88 |
+
}
|
89 |
+
}
|
90 |
+
if(level >= HelpVerbosity::SYNOPSIS) {
|
91 |
+
std::cout << std::endl;
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
void PrintFactoryRegistryDetails(
|
96 |
+
std::ostream& out, const pangolin::FactoryRegistry& registry, std::type_index factory_type,
|
97 |
+
const std::string& scheme_filter, HelpVerbosity level, bool color
|
98 |
+
) {
|
99 |
+
const std::string c_normal = color ? "\033[0m" : "";
|
100 |
+
const std::string c_bold = color ? "\033[1m" : "";
|
101 |
+
|
102 |
+
auto& factories = registry.GetFactories(factory_type);
|
103 |
+
std::vector<std::string> high_pri_names;
|
104 |
+
size_t longest_scheme = 0;
|
105 |
+
for(const auto& f : factories) {
|
106 |
+
const std::string scheme = HighestPriScheme(f->Schemes());
|
107 |
+
high_pri_names.push_back(scheme);
|
108 |
+
longest_scheme = std::max(longest_scheme, scheme.size());
|
109 |
+
}
|
110 |
+
|
111 |
+
// Create vector of indices which we will use to store alphabetical order
|
112 |
+
std::vector<size_t> order(factories.size());
|
113 |
+
std::iota(order.begin(), order.end(), 0);
|
114 |
+
|
115 |
+
std::sort(order.begin(), order.end(), [&](size_t lhs, size_t rhs){
|
116 |
+
return high_pri_names[lhs] < high_pri_names[rhs];
|
117 |
+
});
|
118 |
+
|
119 |
+
const std::string post = ":// ";
|
120 |
+
longest_scheme += post.size();
|
121 |
+
|
122 |
+
out << c_bold << "Factory Scheme List" << c_normal << std::endl << std::endl;
|
123 |
+
|
124 |
+
if(level >= HelpVerbosity::SYNOPSIS) {
|
125 |
+
out << "Factory schemes can be accessed through any of their named aliases (shown below). If multiple factories support the same scheme, the factory having the lowest scheme precedence (shown in brackets) will be used." << std::endl;
|
126 |
+
}
|
127 |
+
if(level >= HelpVerbosity::PARAMS) {
|
128 |
+
out << "Available parameters and their default values for the factories are also shown. Regular expressions may be used if the parameter itself can vary (see the examples)."<< std::endl;
|
129 |
+
}
|
130 |
+
out << "The following is a list of factory provided schemes:" << std::endl;
|
131 |
+
|
132 |
+
out << std::endl;
|
133 |
+
|
134 |
+
for(size_t idx : order) {
|
135 |
+
if(scheme_filter.empty() || factories[idx]->Schemes().count(scheme_filter) > 0) {
|
136 |
+
PrintFactoryDetails(out, high_pri_names[idx] + post, *factories[idx], level, longest_scheme, color);
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
if(level == 0) {
|
141 |
+
out << std::endl;
|
142 |
+
}
|
143 |
+
}
|
144 |
+
|
145 |
+
}
|
third-party/DPVO/Pangolin/components/pango_core/src/factory/factory_registry.cpp
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include "pangolin/factory/factory_registry.h"
|
2 |
+
|
3 |
+
namespace pangolin {
|
4 |
+
|
5 |
+
std::shared_ptr<FactoryRegistry> FactoryRegistry::I()
|
6 |
+
{
|
7 |
+
static std::shared_ptr<FactoryRegistry> registry(new FactoryRegistry());
|
8 |
+
return registry;
|
9 |
+
}
|
10 |
+
|
11 |
+
}
|
third-party/DPVO/Pangolin/components/pango_core/src/file_extension.cpp
ADDED
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2013 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <pangolin/utils/file_extension.h>
|
29 |
+
|
30 |
+
#include <algorithm>
|
31 |
+
#include <fstream>
|
32 |
+
#include <string.h>
|
33 |
+
|
34 |
+
namespace pangolin
|
35 |
+
{
|
36 |
+
|
37 |
+
std::string ImageFileTypeToName(ImageFileType t)
|
38 |
+
{
|
39 |
+
switch(t)
|
40 |
+
{
|
41 |
+
case ImageFileTypePpm:
|
42 |
+
return "ppm";
|
43 |
+
case ImageFileTypeTga:
|
44 |
+
return "tga";
|
45 |
+
case ImageFileTypePng:
|
46 |
+
return "png";
|
47 |
+
case ImageFileTypeJpg:
|
48 |
+
return "jpg";
|
49 |
+
case ImageFileTypeTiff:
|
50 |
+
return "tiff";
|
51 |
+
case ImageFileTypeGif:
|
52 |
+
return "gif";
|
53 |
+
case ImageFileTypeExr:
|
54 |
+
return "exr";
|
55 |
+
case ImageFileTypeBmp:
|
56 |
+
return "bmp";
|
57 |
+
case ImageFileTypePango:
|
58 |
+
return "pango";
|
59 |
+
case ImageFileTypePvn:
|
60 |
+
return "pvn";
|
61 |
+
case ImageFileTypeVrs:
|
62 |
+
return "vrs";
|
63 |
+
case ImageFileTypePly:
|
64 |
+
return "ply";
|
65 |
+
case ImageFileTypeObj:
|
66 |
+
return "obj";
|
67 |
+
case ImageFileTypeArw:
|
68 |
+
return "arw";
|
69 |
+
case ImageFileTypeUnknown:
|
70 |
+
default:
|
71 |
+
return "unknown";
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
ImageFileType NameToImageFileType(const std::string& name)
|
76 |
+
{
|
77 |
+
if ("ppm" == name)
|
78 |
+
return ImageFileTypePpm;
|
79 |
+
else if ("pgm" == name)
|
80 |
+
return ImageFileTypePpm;
|
81 |
+
else if ("tga" == name)
|
82 |
+
return ImageFileTypeTga;
|
83 |
+
else if ("png" == name)
|
84 |
+
return ImageFileTypePng;
|
85 |
+
else if ("jpg" == name)
|
86 |
+
return ImageFileTypeJpg;
|
87 |
+
else if ("jpeg" == name)
|
88 |
+
return ImageFileTypeJpg;
|
89 |
+
else if ("tiff" == name)
|
90 |
+
return ImageFileTypeTiff;
|
91 |
+
else if ("gif" == name)
|
92 |
+
return ImageFileTypeGif;
|
93 |
+
else if ("exr" == name)
|
94 |
+
return ImageFileTypeExr;
|
95 |
+
else if ("bmp" == name)
|
96 |
+
return ImageFileTypeBmp;
|
97 |
+
else if ("pango" == name)
|
98 |
+
return ImageFileTypePango;
|
99 |
+
else if ("pvn" == name)
|
100 |
+
return ImageFileTypePvn;
|
101 |
+
else if ("vrs" == name)
|
102 |
+
return ImageFileTypeVrs;
|
103 |
+
else if ("zstd" == name)
|
104 |
+
return ImageFileTypeZstd;
|
105 |
+
else if ("lzf" == name)
|
106 |
+
return ImageFileTypeLz4;
|
107 |
+
else if ("p12b" == name)
|
108 |
+
return ImageFileTypeP12b;
|
109 |
+
else if ("ply" == name)
|
110 |
+
return ImageFileTypePly;
|
111 |
+
else if ("obj" == name)
|
112 |
+
return ImageFileTypeObj;
|
113 |
+
else if ("arw" == name)
|
114 |
+
return ImageFileTypeArw;
|
115 |
+
|
116 |
+
return ImageFileTypeUnknown;
|
117 |
+
}
|
118 |
+
|
119 |
+
ImageFileType FileTypeExtension(const std::string& ext)
|
120 |
+
{
|
121 |
+
if( ext == ".png" ) {
|
122 |
+
return ImageFileTypePng;
|
123 |
+
} else if( ext == ".tga" || ext == ".targa") {
|
124 |
+
return ImageFileTypeTga;
|
125 |
+
} else if( ext == ".jpg" || ext == ".jpeg" ) {
|
126 |
+
return ImageFileTypeJpg;
|
127 |
+
} else if( ext == ".gif" ) {
|
128 |
+
return ImageFileTypeGif;
|
129 |
+
} else if( ext == ".tif" || ext == ".tiff" ) {
|
130 |
+
return ImageFileTypeTiff;
|
131 |
+
} else if( ext == ".exr" ) {
|
132 |
+
return ImageFileTypeExr;
|
133 |
+
} else if( ext == ".bmp" ) {
|
134 |
+
return ImageFileTypeBmp;
|
135 |
+
} else if( ext == ".ppm" || ext == ".pgm" || ext == ".pbm" || ext == ".pxm" || ext == ".pdm" ) {
|
136 |
+
return ImageFileTypePpm;
|
137 |
+
} else if( ext == ".pvn" ) {
|
138 |
+
return ImageFileTypePvn;
|
139 |
+
} else if( ext == ".vrs" ) {
|
140 |
+
return ImageFileTypeVrs;
|
141 |
+
} else if( ext == ".pango" ) {
|
142 |
+
return ImageFileTypePango;
|
143 |
+
} else if( ext == ".zstd" ) {
|
144 |
+
return ImageFileTypeZstd;
|
145 |
+
} else if( ext == ".lzf" ) {
|
146 |
+
return ImageFileTypeLz4;
|
147 |
+
} else if( ext == ".p12b" ) {
|
148 |
+
return ImageFileTypeP12b;
|
149 |
+
} else if( ext == ".ply" ) {
|
150 |
+
return ImageFileTypePly;
|
151 |
+
} else if( ext == ".obj" ) {
|
152 |
+
return ImageFileTypeObj;
|
153 |
+
} else if( ext == ".ARW" ) {
|
154 |
+
return ImageFileTypeArw;
|
155 |
+
} else {
|
156 |
+
return ImageFileTypeUnknown;
|
157 |
+
}
|
158 |
+
}
|
159 |
+
|
160 |
+
std::string FileLowercaseExtention(const std::string& filename)
|
161 |
+
{
|
162 |
+
size_t pos = filename.find_last_of('.');
|
163 |
+
if(pos != std::string::npos) {
|
164 |
+
std::string ext = filename.substr(pos);
|
165 |
+
std::transform( ext.begin(), ext.end(), ext.begin(), tolower );
|
166 |
+
return ext;
|
167 |
+
}else{
|
168 |
+
return "";
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
ImageFileType FileTypeMagic(const unsigned char data[], size_t bytes)
|
173 |
+
{
|
174 |
+
// Check we wont go over bounds when comparing.
|
175 |
+
if(bytes >= 8) {
|
176 |
+
const unsigned char magic_png[] = "\211PNG\r\n\032\n";
|
177 |
+
const unsigned char magic_jpg1[] = "\xFF\xD8";
|
178 |
+
const unsigned char magic_jpg2[] = "\xFF\xD9";
|
179 |
+
const unsigned char magic_gif1[] = "GIF87a";
|
180 |
+
const unsigned char magic_gif2[] = "GIF89a";
|
181 |
+
const unsigned char magic_tiff1[] = "\x49\x49\x2A\x00";
|
182 |
+
const unsigned char magic_tiff2[] = "\x4D\x4D\x00\x2A";
|
183 |
+
const unsigned char magic_exr[] = "\x76\x2F\x31\x01";
|
184 |
+
const unsigned char magic_bmp[] = "BM";
|
185 |
+
const unsigned char magic_pango[] = "PANGO";
|
186 |
+
const unsigned char magic_pango_zstd[] = "ZSTD";
|
187 |
+
const unsigned char magic_pango_lz4[] = "LZ4";
|
188 |
+
const unsigned char magic_pango_p12b[] = "P12B";
|
189 |
+
const unsigned char magic_vrs[] = "VisionR";
|
190 |
+
const unsigned char magic_ply[] = "ply";
|
191 |
+
|
192 |
+
if( !strncmp((char*)data, (char*)magic_png, 8) ) {
|
193 |
+
return ImageFileTypePng;
|
194 |
+
}else if( !strncmp( (char*)data, (char*)magic_jpg1, 2)
|
195 |
+
|| !strncmp( (char*)data, (char*)magic_jpg2, 2) ) {
|
196 |
+
return ImageFileTypeJpg;
|
197 |
+
}else if( !strncmp((char*)data, (char*)magic_gif1,6)
|
198 |
+
|| !strncmp((char*)data, (char*)magic_gif2,6) ) {
|
199 |
+
return ImageFileTypeGif;
|
200 |
+
}else if( !strncmp((char*)data, (char*)magic_tiff1,4)
|
201 |
+
|| !strncmp((char*)data, (char*)magic_tiff2,4) ) {
|
202 |
+
return ImageFileTypeTiff;
|
203 |
+
}else if( !strncmp((char*)data, (char*)magic_exr,4) ) {
|
204 |
+
return ImageFileTypeExr;
|
205 |
+
}else if( !strncmp((char*)data, (char*)magic_bmp,2) ) {
|
206 |
+
return ImageFileTypeBmp;
|
207 |
+
}else if( !strncmp((char*)data, (char*)magic_pango,5) ) {
|
208 |
+
return ImageFileTypePango;
|
209 |
+
}else if( !strncmp((char*)data, (char*)magic_vrs,7) ) {
|
210 |
+
return ImageFileTypeVrs;
|
211 |
+
}else if( !strncmp((char*)data, (char*)magic_pango_zstd,4) ) {
|
212 |
+
return ImageFileTypeZstd;
|
213 |
+
}else if( !strncmp((char*)data, (char*)magic_pango_lz4,3) ) {
|
214 |
+
return ImageFileTypeLz4;
|
215 |
+
}else if( !strncmp((char*)data, (char*)magic_pango_p12b,4) ) {
|
216 |
+
return ImageFileTypeP12b;
|
217 |
+
}else if( !strncmp((char*)data, (char*)magic_ply, 3) ) {
|
218 |
+
return ImageFileTypePly;
|
219 |
+
}else if( data[0] == 'P' && '0' < data[1] && data[1] < '9') {
|
220 |
+
return ImageFileTypePpm;
|
221 |
+
}
|
222 |
+
}
|
223 |
+
return ImageFileTypeUnknown;
|
224 |
+
}
|
225 |
+
|
226 |
+
ImageFileType FileType(const std::string& filename)
|
227 |
+
{
|
228 |
+
// Check magic number of file...
|
229 |
+
std::ifstream f(filename.c_str(), std::ios::binary );
|
230 |
+
if(f.is_open()) {
|
231 |
+
const size_t magic_bytes = 8;
|
232 |
+
unsigned char magic[magic_bytes];
|
233 |
+
f.read((char*)magic, magic_bytes);
|
234 |
+
if(f.good()) {
|
235 |
+
ImageFileType magic_type = FileTypeMagic(magic, magic_bytes);
|
236 |
+
if(magic_type != ImageFileTypeUnknown) {
|
237 |
+
return magic_type;
|
238 |
+
}
|
239 |
+
}
|
240 |
+
}
|
241 |
+
|
242 |
+
// Fallback on using extension...
|
243 |
+
const std::string ext = FileLowercaseExtention(filename);
|
244 |
+
return FileTypeExtension(ext);
|
245 |
+
}
|
246 |
+
|
247 |
+
}
|
third-party/DPVO/Pangolin/components/pango_core/src/file_utils.cpp
ADDED
@@ -0,0 +1,544 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2013 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <pangolin/platform.h>
|
29 |
+
|
30 |
+
#include <pangolin/utils/file_utils.h>
|
31 |
+
|
32 |
+
#ifdef _WIN_
|
33 |
+
# ifndef WIN32_LEAN_AND_MEAN
|
34 |
+
# define WIN32_LEAN_AND_MEAN
|
35 |
+
# endif
|
36 |
+
# include <Windows.h>
|
37 |
+
# include <Shlobj.h>
|
38 |
+
# ifdef UNICODE
|
39 |
+
# include <codecvt>
|
40 |
+
# endif
|
41 |
+
#else
|
42 |
+
# include <dirent.h>
|
43 |
+
# include <sys/types.h>
|
44 |
+
# include <sys/stat.h>
|
45 |
+
# include <sys/signal.h>
|
46 |
+
# include <stdio.h>
|
47 |
+
# include <string.h>
|
48 |
+
# include <unistd.h>
|
49 |
+
# include <fcntl.h>
|
50 |
+
# include <errno.h>
|
51 |
+
# include <poll.h>
|
52 |
+
#endif // _WIN_
|
53 |
+
|
54 |
+
#include <algorithm>
|
55 |
+
#include <sstream>
|
56 |
+
#include <fstream>
|
57 |
+
#include <list>
|
58 |
+
#include <NaturalSort/natural_sort.hpp>
|
59 |
+
|
60 |
+
namespace pangolin
|
61 |
+
{
|
62 |
+
|
63 |
+
std::vector<std::string>& Split(const std::string& s, char delim, std::vector<std::string>& elements) {
|
64 |
+
std::stringstream ss(s);
|
65 |
+
std::string item;
|
66 |
+
while (std::getline(ss, item, delim)) {
|
67 |
+
elements.push_back(item);
|
68 |
+
}
|
69 |
+
return elements;
|
70 |
+
}
|
71 |
+
|
72 |
+
std::vector<std::string> Split(const std::string &s, char delim) {
|
73 |
+
std::vector<std::string> elems;
|
74 |
+
return Split(s, delim, elems);
|
75 |
+
}
|
76 |
+
|
77 |
+
std::vector<std::string> Expand(const std::string &s, char open, char close, char delim)
|
78 |
+
{
|
79 |
+
const size_t no = s.find_first_of(open);
|
80 |
+
if(no != std::string::npos) {
|
81 |
+
const size_t nc = s.find_first_of(close, no);
|
82 |
+
if(no != std::string::npos) {
|
83 |
+
const std::string pre = s.substr(0, no);
|
84 |
+
const std::string mid = s.substr(no+1, nc-no-1);
|
85 |
+
const std::string post = s.substr(nc+1, std::string::npos);
|
86 |
+
const std::vector<std::string> options = Split(mid, delim);
|
87 |
+
std::vector<std::string> expansion;
|
88 |
+
|
89 |
+
for(std::vector<std::string>::const_iterator iop = options.begin(); iop != options.end(); ++iop)
|
90 |
+
{
|
91 |
+
std::string full = pre + *iop + post;
|
92 |
+
expansion.push_back(full);
|
93 |
+
}
|
94 |
+
return expansion;
|
95 |
+
}
|
96 |
+
// Open but no close is unusual. Leave it for caller to see if valid
|
97 |
+
}
|
98 |
+
|
99 |
+
std::vector<std::string> ret;
|
100 |
+
ret.push_back(s);
|
101 |
+
return ret;
|
102 |
+
}
|
103 |
+
|
104 |
+
// Make path seperator consistent for OS.
|
105 |
+
void PathOsNormaliseInplace(std::string& path)
|
106 |
+
{
|
107 |
+
#ifdef _WIN_
|
108 |
+
std::replace(path.begin(), path.end(), '/', '\\');
|
109 |
+
#else
|
110 |
+
std::replace(path.begin(), path.end(), '\\', '/');
|
111 |
+
#endif
|
112 |
+
}
|
113 |
+
|
114 |
+
std::string SanitizePath(const std::string& path)
|
115 |
+
{
|
116 |
+
std::string path_copy(path.length(), '\0');
|
117 |
+
|
118 |
+
int p_slash1 = -1;
|
119 |
+
int p_slash0 = -1;
|
120 |
+
int n_dots = 0;
|
121 |
+
|
122 |
+
int dst = 0;
|
123 |
+
for(int src=0; src < (int)path.length(); ++src) {
|
124 |
+
if(path[src] == '/') {
|
125 |
+
if(n_dots==1 && p_slash0 >=0) {
|
126 |
+
dst = p_slash0;
|
127 |
+
for(p_slash1=p_slash0-1; p_slash1>=0 && path_copy[p_slash1] != '/'; --p_slash1);
|
128 |
+
}else if(n_dots==2) {
|
129 |
+
if(p_slash1 >=0) {
|
130 |
+
dst = p_slash1;
|
131 |
+
p_slash0 = dst;
|
132 |
+
for(p_slash1=p_slash0-1; p_slash1>=0 && path_copy[p_slash1] != '/'; --p_slash1) {
|
133 |
+
if( path_copy[p_slash1] == '.' ) {
|
134 |
+
p_slash1=-1;
|
135 |
+
break;
|
136 |
+
}
|
137 |
+
}
|
138 |
+
}else{
|
139 |
+
p_slash1 = -1;
|
140 |
+
p_slash0 = dst;
|
141 |
+
}
|
142 |
+
}else{
|
143 |
+
p_slash1 = p_slash0;
|
144 |
+
p_slash0 = dst;
|
145 |
+
}
|
146 |
+
n_dots = 0;
|
147 |
+
}else if(path[src] == '.' ){
|
148 |
+
if((dst-p_slash0) == n_dots+1) {
|
149 |
+
++n_dots;
|
150 |
+
}
|
151 |
+
}else{
|
152 |
+
n_dots = 0;
|
153 |
+
}
|
154 |
+
path_copy[dst++] = path[src];
|
155 |
+
}
|
156 |
+
|
157 |
+
return path_copy.substr(0,dst);
|
158 |
+
}
|
159 |
+
|
160 |
+
// Return path 'levels' directories above 'path'
|
161 |
+
std::string PathParent(const std::string& path, int levels)
|
162 |
+
{
|
163 |
+
std::string res = path;
|
164 |
+
|
165 |
+
while (levels > 0) {
|
166 |
+
if (res.length() == 0) {
|
167 |
+
res = std::string();
|
168 |
+
for (int l = 0; l < levels; ++l) {
|
169 |
+
#ifdef _WIN_
|
170 |
+
res += std::string("..\\");
|
171 |
+
#else
|
172 |
+
res += std::string("../");
|
173 |
+
#endif
|
174 |
+
}
|
175 |
+
return res;
|
176 |
+
}else{
|
177 |
+
const size_t nLastSlash = res.find_last_of("/\\");
|
178 |
+
|
179 |
+
if (nLastSlash != std::string::npos) {
|
180 |
+
res = path.substr(0, nLastSlash);
|
181 |
+
} else{
|
182 |
+
res = std::string();
|
183 |
+
}
|
184 |
+
|
185 |
+
--levels;
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
+
return res;
|
190 |
+
}
|
191 |
+
|
192 |
+
std::string FindPath(const std::string& child_path, const std::string& signature_path)
|
193 |
+
{
|
194 |
+
std::string path = PathExpand(child_path);
|
195 |
+
#ifdef _UNIX_
|
196 |
+
char abs_path[PATH_MAX];
|
197 |
+
if (realpath(path.c_str(), abs_path)) {
|
198 |
+
path = abs_path;
|
199 |
+
}
|
200 |
+
#endif
|
201 |
+
std::string signature = signature_path;
|
202 |
+
PathOsNormaliseInplace(path);
|
203 |
+
PathOsNormaliseInplace(signature);
|
204 |
+
|
205 |
+
while(!FileExists(path + signature)) {
|
206 |
+
if (path.empty()) {
|
207 |
+
return std::string();
|
208 |
+
} else {
|
209 |
+
path = PathParent(path);
|
210 |
+
}
|
211 |
+
}
|
212 |
+
|
213 |
+
return path + signature;
|
214 |
+
}
|
215 |
+
|
216 |
+
std::string PathExpand(const std::string& sPath)
|
217 |
+
{
|
218 |
+
if(sPath.length() >0 && sPath[0] == '~') {
|
219 |
+
#ifdef _WIN_
|
220 |
+
std::string sHomeDir;
|
221 |
+
WCHAR path[MAX_PATH];
|
222 |
+
if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path))) {
|
223 |
+
std::wstring ws(path);
|
224 |
+
sHomeDir = std::string(ws.begin(), ws.end());
|
225 |
+
}
|
226 |
+
#else
|
227 |
+
std::string sHomeDir = std::string(getenv("HOME"));
|
228 |
+
#endif
|
229 |
+
return sHomeDir + sPath.substr(1,std::string::npos);
|
230 |
+
}else{
|
231 |
+
return sPath;
|
232 |
+
}
|
233 |
+
}
|
234 |
+
|
235 |
+
// Based on http://www.codeproject.com/Articles/188256/A-Simple-Wildcard-Matching-Function
|
236 |
+
bool MatchesWildcard(const std::string& str, const std::string& wildcard)
|
237 |
+
{
|
238 |
+
const char* psQuery = str.c_str();
|
239 |
+
const char* psWildcard = wildcard.c_str();
|
240 |
+
|
241 |
+
while(*psWildcard)
|
242 |
+
{
|
243 |
+
if(*psWildcard=='?')
|
244 |
+
{
|
245 |
+
if(!*psQuery)
|
246 |
+
return false;
|
247 |
+
|
248 |
+
++psQuery;
|
249 |
+
++psWildcard;
|
250 |
+
}
|
251 |
+
else if(*psWildcard=='*')
|
252 |
+
{
|
253 |
+
if(MatchesWildcard(psQuery,psWildcard+1))
|
254 |
+
return true;
|
255 |
+
|
256 |
+
if(*psQuery && MatchesWildcard(psQuery+1,psWildcard))
|
257 |
+
return true;
|
258 |
+
|
259 |
+
return false;
|
260 |
+
}
|
261 |
+
else
|
262 |
+
{
|
263 |
+
if(*psQuery++ != *psWildcard++ )
|
264 |
+
return false;
|
265 |
+
}
|
266 |
+
}
|
267 |
+
|
268 |
+
return !*psQuery && !*psWildcard;
|
269 |
+
}
|
270 |
+
|
271 |
+
std::string MakeUniqueFilename(const std::string& filename)
|
272 |
+
{
|
273 |
+
if( FileExists(filename) ) {
|
274 |
+
const size_t dot = filename.find_last_of('.');
|
275 |
+
|
276 |
+
std::string fn;
|
277 |
+
std::string ext;
|
278 |
+
|
279 |
+
if(dot == filename.npos) {
|
280 |
+
fn = filename;
|
281 |
+
ext = "";
|
282 |
+
}else{
|
283 |
+
fn = filename.substr(0, dot);
|
284 |
+
ext = filename.substr(dot);
|
285 |
+
}
|
286 |
+
|
287 |
+
int id = 1;
|
288 |
+
std::string new_file;
|
289 |
+
do {
|
290 |
+
id++;
|
291 |
+
std::stringstream ss;
|
292 |
+
ss << fn << "_" << id << ext;
|
293 |
+
new_file = ss.str();
|
294 |
+
}while( FileExists(new_file) );
|
295 |
+
|
296 |
+
return new_file;
|
297 |
+
}else{
|
298 |
+
return filename;
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
// Based on https://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html
|
303 |
+
std::string GetFileContents(const std::string& filename)
|
304 |
+
{
|
305 |
+
std::ifstream in(filename.c_str(), std::ios::in | std::ios::binary);
|
306 |
+
if (in)
|
307 |
+
{
|
308 |
+
std::string contents;
|
309 |
+
in.seekg(0, std::ios::end);
|
310 |
+
contents.resize(in.tellg());
|
311 |
+
in.seekg(0, std::ios::beg);
|
312 |
+
in.read(&contents[0], contents.size());
|
313 |
+
in.close();
|
314 |
+
return(contents);
|
315 |
+
}else{
|
316 |
+
throw std::runtime_error(std::string("Unable to open file: ") + filename);
|
317 |
+
}
|
318 |
+
}
|
319 |
+
|
320 |
+
bool IsPipe(const std::string& file)
|
321 |
+
{
|
322 |
+
#ifdef _WIN_
|
323 |
+
return false;
|
324 |
+
#else
|
325 |
+
struct stat st;
|
326 |
+
int err = stat(file.c_str(), &st);
|
327 |
+
return (err == 0) && ((st.st_mode & S_IFMT) == S_IFIFO);
|
328 |
+
#endif // _WIN_
|
329 |
+
}
|
330 |
+
|
331 |
+
bool IsPipe(int fd)
|
332 |
+
{
|
333 |
+
#ifdef _WIN_
|
334 |
+
return false;
|
335 |
+
#else
|
336 |
+
struct stat st;
|
337 |
+
int err = fstat(fd, &st);
|
338 |
+
return (err == 0) && ((st.st_mode & S_IFMT) == S_IFIFO);
|
339 |
+
#endif
|
340 |
+
}
|
341 |
+
|
342 |
+
int WritablePipeFileDescriptor(const std::string& file)
|
343 |
+
{
|
344 |
+
#ifdef _WIN_
|
345 |
+
return false;
|
346 |
+
#else
|
347 |
+
// open(2) will return ENXIO when there is no reader on the other
|
348 |
+
// side of the pipe, but only if O_WRONLY|O_NONBLOCK is specified.
|
349 |
+
// The file descriptor can be adjusted to be a blocking file
|
350 |
+
// descriptor if it is valid.
|
351 |
+
return open(file.c_str(), O_WRONLY | O_NONBLOCK);
|
352 |
+
#endif // _WIN_
|
353 |
+
}
|
354 |
+
|
355 |
+
int ReadablePipeFileDescriptor(const std::string& file)
|
356 |
+
{
|
357 |
+
#ifdef _WIN_
|
358 |
+
return -1;
|
359 |
+
#else
|
360 |
+
return open(file.c_str(), O_RDONLY | O_NONBLOCK);
|
361 |
+
#endif
|
362 |
+
}
|
363 |
+
|
364 |
+
bool PipeHasDataToRead(int fd)
|
365 |
+
{
|
366 |
+
#ifdef _WIN_
|
367 |
+
return false;
|
368 |
+
#else
|
369 |
+
struct pollfd pfd;
|
370 |
+
memset(&pfd, 0, sizeof(pfd));
|
371 |
+
pfd.fd = fd;
|
372 |
+
pfd.events = POLLIN;
|
373 |
+
|
374 |
+
int err = poll(&pfd, 1, 0);
|
375 |
+
|
376 |
+
// If err is 0, the file has no data. If err is negative, an error
|
377 |
+
// occurred.
|
378 |
+
return err == 1 && pfd.revents & POLLIN;
|
379 |
+
#endif
|
380 |
+
}
|
381 |
+
|
382 |
+
void FlushPipe(const std::string& file)
|
383 |
+
{
|
384 |
+
#ifndef _WIN_
|
385 |
+
int fd = open(file.c_str(), O_RDONLY | O_NONBLOCK);
|
386 |
+
char buf[65535];
|
387 |
+
int n = 0;
|
388 |
+
do
|
389 |
+
{
|
390 |
+
n = read(fd, buf, sizeof(buf));
|
391 |
+
} while(n > 0);
|
392 |
+
close(fd);
|
393 |
+
#endif
|
394 |
+
}
|
395 |
+
|
396 |
+
#ifdef _WIN_
|
397 |
+
|
398 |
+
#ifdef UNICODE
|
399 |
+
typedef std::codecvt_utf8<wchar_t> WinStringConvert;
|
400 |
+
typedef std::wstring WinString;
|
401 |
+
|
402 |
+
WinString s2ws(const std::string& str) {
|
403 |
+
std::wstring_convert<WinStringConvert, wchar_t> converter;
|
404 |
+
return converter.from_bytes(str);
|
405 |
+
}
|
406 |
+
std::string ws2s(const WinString& wstr) {
|
407 |
+
std::wstring_convert<WinStringConvert, wchar_t> converter;
|
408 |
+
return converter.to_bytes(wstr);
|
409 |
+
}
|
410 |
+
#else
|
411 |
+
typedef std::string WinString;
|
412 |
+
// No conversions necessary
|
413 |
+
# define s2ws(X) (X)
|
414 |
+
# define ws2s(X) (X)
|
415 |
+
#endif // UNICODE
|
416 |
+
|
417 |
+
bool FilesMatchingWildcard(const std::string& wildcard, std::vector<std::string>& file_vec,
|
418 |
+
SortMethod sort_method )
|
419 |
+
{
|
420 |
+
size_t nLastSlash = wildcard.find_last_of("/\\");
|
421 |
+
|
422 |
+
std::string sPath;
|
423 |
+
std::string sFileWc;
|
424 |
+
|
425 |
+
if(nLastSlash != std::string::npos) {
|
426 |
+
sPath = wildcard.substr(0, nLastSlash);
|
427 |
+
sFileWc = wildcard.substr(nLastSlash+1, std::string::npos);
|
428 |
+
}else{
|
429 |
+
sPath = ".";
|
430 |
+
sFileWc = wildcard;
|
431 |
+
}
|
432 |
+
|
433 |
+
sPath = PathExpand(sPath);
|
434 |
+
|
435 |
+
WIN32_FIND_DATA wfd;
|
436 |
+
HANDLE fh = FindFirstFile( s2ws(sPath + "\\" + sFileWc).c_str(), &wfd);
|
437 |
+
|
438 |
+
std::vector<std::string> files;
|
439 |
+
|
440 |
+
if (fh != INVALID_HANDLE_VALUE) {
|
441 |
+
do {
|
442 |
+
if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
443 |
+
files.push_back( sPath + "\\" + ws2s(wfd.cFileName) );
|
444 |
+
}
|
445 |
+
} while (FindNextFile (fh, &wfd));
|
446 |
+
FindClose(fh);
|
447 |
+
}
|
448 |
+
|
449 |
+
// TOOD: Use different comparison to achieve better ordering.
|
450 |
+
switch(sort_method) {
|
451 |
+
case SortMethod::NATURAL:
|
452 |
+
SI::natural::sort(files.begin(), files.end());
|
453 |
+
break;
|
454 |
+
case SortMethod::STANDARD:
|
455 |
+
default:
|
456 |
+
std::sort(files.begin(), files.end() );
|
457 |
+
}
|
458 |
+
|
459 |
+
// Put file list at end of file_vec
|
460 |
+
file_vec.insert(file_vec.end(), files.begin(), files.end() );
|
461 |
+
|
462 |
+
return files.size() > 0;
|
463 |
+
}
|
464 |
+
|
465 |
+
bool FileExists(const std::string& filename)
|
466 |
+
{
|
467 |
+
std::string search_filename = filename;
|
468 |
+
if(filename.length() > 0 &&
|
469 |
+
(filename[filename.length()-1] == '\\' || filename[filename.length() - 1] == '/')) {
|
470 |
+
search_filename.resize(filename.length()-1);
|
471 |
+
}
|
472 |
+
WIN32_FIND_DATA wfd;
|
473 |
+
HANDLE fh = FindFirstFile( s2ws(search_filename).c_str(), &wfd);
|
474 |
+
const bool exists = fh != INVALID_HANDLE_VALUE;
|
475 |
+
FindClose(fh);
|
476 |
+
return exists;
|
477 |
+
}
|
478 |
+
|
479 |
+
#else // _WIN_
|
480 |
+
|
481 |
+
bool FilesMatchingWildcard_(const std::string& in_wildcard, std::vector<std::string>& file_vec)
|
482 |
+
{
|
483 |
+
const std::string wildcard = PathExpand(in_wildcard);
|
484 |
+
const size_t first_wildcard = wildcard.find_first_of("?*");
|
485 |
+
if(first_wildcard != std::string::npos) {
|
486 |
+
const std::string root = PathParent(wildcard.substr(0,first_wildcard));
|
487 |
+
struct dirent **namelist;
|
488 |
+
int n = scandir(root.c_str(), &namelist, 0, alphasort);
|
489 |
+
if (n >= 0) {
|
490 |
+
const size_t next_slash = wildcard.find_first_of("/\\",first_wildcard+1);
|
491 |
+
std::string dir_wildcard, rest;
|
492 |
+
if(next_slash != std::string::npos) {
|
493 |
+
dir_wildcard = wildcard.substr(root.size()+1, next_slash-root.size()-1);
|
494 |
+
rest = wildcard.substr(next_slash);
|
495 |
+
}else{
|
496 |
+
dir_wildcard = wildcard.substr(root.size()+1);
|
497 |
+
}
|
498 |
+
|
499 |
+
while(n--) {
|
500 |
+
const std::string file_name(namelist[n]->d_name);
|
501 |
+
if( file_name != "." && file_name != ".." && MatchesWildcard(file_name, dir_wildcard) ) {
|
502 |
+
const std::string sub_wildcard = root + "/" + file_name + rest;
|
503 |
+
FilesMatchingWildcard_(sub_wildcard, file_vec);
|
504 |
+
if(dir_wildcard == "**") {
|
505 |
+
const std::string sub_wildcard2 = root + "/" + file_name + "/**" + rest;
|
506 |
+
FilesMatchingWildcard_(sub_wildcard2, file_vec);
|
507 |
+
}
|
508 |
+
}
|
509 |
+
}
|
510 |
+
}
|
511 |
+
} else if(FileExists(wildcard)) {
|
512 |
+
file_vec.push_back(wildcard);
|
513 |
+
}
|
514 |
+
return file_vec.size() > 0;
|
515 |
+
}
|
516 |
+
|
517 |
+
bool FilesMatchingWildcard(const std::string& in_wildcard, std::vector<std::string>& file_vec, SortMethod sort_method)
|
518 |
+
{
|
519 |
+
if (FilesMatchingWildcard_(in_wildcard, file_vec)) {
|
520 |
+
// sort all file entries in file_vec to make sure anything that was
|
521 |
+
// added is sorted in properly.
|
522 |
+
switch (sort_method) {
|
523 |
+
case SortMethod::NATURAL:
|
524 |
+
SI::natural::sort(file_vec.begin(), file_vec.end());
|
525 |
+
break;
|
526 |
+
case SortMethod::STANDARD:
|
527 |
+
default:
|
528 |
+
std::sort(file_vec.begin(), file_vec.end() );
|
529 |
+
}
|
530 |
+
return true;
|
531 |
+
}
|
532 |
+
return false;
|
533 |
+
}
|
534 |
+
|
535 |
+
|
536 |
+
bool FileExists(const std::string& filename)
|
537 |
+
{
|
538 |
+
struct stat buf;
|
539 |
+
return stat(filename.c_str(), &buf) != -1;
|
540 |
+
}
|
541 |
+
|
542 |
+
#endif //_WIN_
|
543 |
+
|
544 |
+
}
|
third-party/DPVO/Pangolin/components/pango_core/src/param_set.cpp
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pangolin/utils/param_set.h>
|
2 |
+
|
3 |
+
namespace pangolin
|
4 |
+
{
|
5 |
+
|
6 |
+
bool ParamReader::Contains( const std::string& param_name )
|
7 |
+
{
|
8 |
+
const ParamSet::Param* param = GetMatchingParamFromParamSet( param_name );
|
9 |
+
if( param ){
|
10 |
+
return uri_.Contains( param_name );
|
11 |
+
}
|
12 |
+
throw ParamReaderException( param_name );
|
13 |
+
}
|
14 |
+
|
15 |
+
std::unordered_set<std::string> ParamReader::FindUnrecognizedUriParams()
|
16 |
+
{
|
17 |
+
std::unordered_set<std::string> result;
|
18 |
+
for(const auto& param_pair: uri_.params){
|
19 |
+
if(GetMatchingParamFromParamSet( param_pair.first ) == nullptr ){
|
20 |
+
result.insert( param_pair.first );
|
21 |
+
}
|
22 |
+
}
|
23 |
+
return result;
|
24 |
+
}
|
25 |
+
|
26 |
+
const ParamSet::Param* ParamReader::GetMatchingParamFromParamSet( const std::string& param_name ) const
|
27 |
+
{
|
28 |
+
for(const auto& param : param_set_.params){
|
29 |
+
std::regex name_regex( param.name_regex );
|
30 |
+
if (std::regex_match ( param_name, name_regex )){
|
31 |
+
return ¶m;
|
32 |
+
}
|
33 |
+
}
|
34 |
+
return nullptr;
|
35 |
+
}
|
36 |
+
|
37 |
+
std::string ParamSet::str() const
|
38 |
+
{
|
39 |
+
std::stringstream ss;
|
40 |
+
if( params.size() > 0){
|
41 |
+
ss << "[";
|
42 |
+
size_t count = 0;
|
43 |
+
for(const auto& param : params){
|
44 |
+
ss << param.name_regex;
|
45 |
+
if(!param.default_value.empty()){
|
46 |
+
ss << "=" << param.default_value;
|
47 |
+
}
|
48 |
+
if(count < (params.size()-1)){
|
49 |
+
ss << ",";
|
50 |
+
}
|
51 |
+
count++;
|
52 |
+
}
|
53 |
+
ss << "]";
|
54 |
+
}
|
55 |
+
return ss.str();
|
56 |
+
}
|
57 |
+
|
58 |
+
}
|
third-party/DPVO/Pangolin/components/pango_core/src/posix/condition_variable.cpp
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pangolin/utils/posix/condition_variable.h>
|
2 |
+
|
3 |
+
#include <pangolin/utils/posix/shared_memory_buffer.h>
|
4 |
+
|
5 |
+
#include <pthread.h>
|
6 |
+
|
7 |
+
using namespace std;
|
8 |
+
|
9 |
+
namespace pangolin {
|
10 |
+
|
11 |
+
struct PThreadSharedData {
|
12 |
+
pthread_mutex_t lock;
|
13 |
+
pthread_cond_t cond;
|
14 |
+
};
|
15 |
+
|
16 |
+
class PThreadConditionVariable : public ConditionVariableInterface {
|
17 |
+
public:
|
18 |
+
PThreadConditionVariable(std::shared_ptr<SharedMemoryBufferInterface> &shmem)
|
19 |
+
: _shmem(shmem),
|
20 |
+
_pthread_data(reinterpret_cast<PThreadSharedData *>(_shmem->ptr())) {}
|
21 |
+
|
22 |
+
~PThreadConditionVariable() override {}
|
23 |
+
|
24 |
+
void wait() override {
|
25 |
+
_lock();
|
26 |
+
pthread_cond_wait(&_pthread_data->cond, &_pthread_data->lock);
|
27 |
+
_unlock();
|
28 |
+
}
|
29 |
+
|
30 |
+
bool wait(timespec abstime) override {
|
31 |
+
_lock();
|
32 |
+
int err = pthread_cond_timedwait(&_pthread_data->cond, &_pthread_data->lock,
|
33 |
+
&abstime);
|
34 |
+
_unlock();
|
35 |
+
|
36 |
+
return 0 == err;
|
37 |
+
}
|
38 |
+
|
39 |
+
void signal() override { pthread_cond_signal(&_pthread_data->cond); }
|
40 |
+
|
41 |
+
void broadcast() override { pthread_cond_broadcast(&_pthread_data->cond); }
|
42 |
+
|
43 |
+
private:
|
44 |
+
void _lock() { pthread_mutex_lock(&_pthread_data->lock); }
|
45 |
+
|
46 |
+
void _unlock() { pthread_mutex_unlock(&_pthread_data->lock); }
|
47 |
+
|
48 |
+
std::shared_ptr<SharedMemoryBufferInterface> _shmem;
|
49 |
+
PThreadSharedData *_pthread_data;
|
50 |
+
};
|
51 |
+
|
52 |
+
std::shared_ptr<ConditionVariableInterface>
|
53 |
+
create_named_condition_variable(const string &name) {
|
54 |
+
std::shared_ptr<SharedMemoryBufferInterface> shmem =
|
55 |
+
create_named_shared_memory_buffer(name, sizeof(PThreadSharedData));
|
56 |
+
std::shared_ptr<ConditionVariableInterface> ptr;
|
57 |
+
|
58 |
+
PThreadSharedData *pthread_data =
|
59 |
+
reinterpret_cast<PThreadSharedData *>(shmem->ptr());
|
60 |
+
|
61 |
+
pthread_mutexattr_t mattr;
|
62 |
+
pthread_mutexattr_init(&mattr);
|
63 |
+
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
|
64 |
+
|
65 |
+
pthread_condattr_t cattr;
|
66 |
+
pthread_condattr_init(&cattr);
|
67 |
+
pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
|
68 |
+
|
69 |
+
pthread_mutex_init(&pthread_data->lock, &mattr);
|
70 |
+
pthread_cond_init(&pthread_data->cond, &cattr);
|
71 |
+
|
72 |
+
ptr.reset(static_cast<ConditionVariableInterface *>(
|
73 |
+
new PThreadConditionVariable(shmem)));
|
74 |
+
return ptr;
|
75 |
+
}
|
76 |
+
|
77 |
+
std::shared_ptr<ConditionVariableInterface>
|
78 |
+
open_named_condition_variable(const string &name) {
|
79 |
+
std::shared_ptr<SharedMemoryBufferInterface> shmem =
|
80 |
+
open_named_shared_memory_buffer(name, true);
|
81 |
+
std::shared_ptr<ConditionVariableInterface> ptr;
|
82 |
+
|
83 |
+
if(shmem) {
|
84 |
+
ptr.reset(new PThreadConditionVariable(shmem));
|
85 |
+
}
|
86 |
+
return ptr;
|
87 |
+
}
|
88 |
+
|
89 |
+
}
|
third-party/DPVO/Pangolin/components/pango_core/src/posix/semaphore.cpp
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pangolin/utils/posix/semaphore.h>
|
2 |
+
|
3 |
+
#include <fcntl.h>
|
4 |
+
#include <semaphore.h>
|
5 |
+
#include <sys/stat.h>
|
6 |
+
|
7 |
+
#include <string>
|
8 |
+
|
9 |
+
using namespace std;
|
10 |
+
|
11 |
+
namespace pangolin
|
12 |
+
{
|
13 |
+
|
14 |
+
// TODO(shaheen) register a signal handler for SIGTERM and unlink shared
|
15 |
+
// semaphores.
|
16 |
+
class PosixSemaphore : public SemaphoreInterface
|
17 |
+
{
|
18 |
+
public:
|
19 |
+
PosixSemaphore(sem_t *semaphore, bool ownership, const string& name) :
|
20 |
+
_semaphore(semaphore),
|
21 |
+
_ownership(ownership),
|
22 |
+
_name(name)
|
23 |
+
{
|
24 |
+
}
|
25 |
+
|
26 |
+
~PosixSemaphore() override
|
27 |
+
{
|
28 |
+
if (_ownership) {
|
29 |
+
sem_unlink(_name.c_str());
|
30 |
+
} else {
|
31 |
+
sem_close(_semaphore);
|
32 |
+
}
|
33 |
+
}
|
34 |
+
|
35 |
+
bool tryAcquire() override
|
36 |
+
{
|
37 |
+
int err = sem_trywait(_semaphore);
|
38 |
+
return err == 0;
|
39 |
+
}
|
40 |
+
|
41 |
+
void acquire() override
|
42 |
+
{
|
43 |
+
sem_wait(_semaphore);
|
44 |
+
}
|
45 |
+
|
46 |
+
void release() override
|
47 |
+
{
|
48 |
+
sem_post(_semaphore);
|
49 |
+
}
|
50 |
+
|
51 |
+
private:
|
52 |
+
sem_t *_semaphore;
|
53 |
+
bool _ownership;
|
54 |
+
string _name;
|
55 |
+
};
|
56 |
+
|
57 |
+
std::shared_ptr<SemaphoreInterface> create_named_semaphore(const string& name, unsigned int value)
|
58 |
+
{
|
59 |
+
std::shared_ptr<SemaphoreInterface> ptr;
|
60 |
+
sem_t *semaphore = sem_open(name.c_str(), O_CREAT | O_EXCL,
|
61 |
+
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, value);
|
62 |
+
if (NULL == semaphore) {
|
63 |
+
return ptr;
|
64 |
+
}
|
65 |
+
|
66 |
+
ptr.reset(new PosixSemaphore(semaphore, true, name));
|
67 |
+
return ptr;
|
68 |
+
}
|
69 |
+
|
70 |
+
std::shared_ptr<SemaphoreInterface> open_named_semaphore(const string& name)
|
71 |
+
{
|
72 |
+
std::shared_ptr<SemaphoreInterface> ptr;
|
73 |
+
sem_t *semaphore = sem_open(name.c_str(), 0);
|
74 |
+
|
75 |
+
if (NULL == semaphore) {
|
76 |
+
return ptr;
|
77 |
+
}
|
78 |
+
|
79 |
+
ptr.reset(new PosixSemaphore(semaphore, false, name));
|
80 |
+
return ptr;
|
81 |
+
}
|
82 |
+
|
83 |
+
}
|
third-party/DPVO/Pangolin/components/pango_core/src/posix/shared_memory_buffer.cpp
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pangolin/utils/posix/shared_memory_buffer.h>
|
2 |
+
|
3 |
+
#include <fcntl.h>
|
4 |
+
#include <limits.h>
|
5 |
+
#include <sys/file.h>
|
6 |
+
#include <sys/mman.h>
|
7 |
+
#include <sys/stat.h>
|
8 |
+
#include <unistd.h>
|
9 |
+
|
10 |
+
using namespace std;
|
11 |
+
|
12 |
+
namespace pangolin
|
13 |
+
{
|
14 |
+
|
15 |
+
// TODO(shaheen) register a signal handler for SIGTERM and unlink shared memory
|
16 |
+
// objects.
|
17 |
+
class PosixSharedMemoryBuffer : public SharedMemoryBufferInterface
|
18 |
+
{
|
19 |
+
public:
|
20 |
+
PosixSharedMemoryBuffer(int fd, unsigned char *ptr, size_t size, bool ownership, const std::string& name) :
|
21 |
+
_fd(fd),
|
22 |
+
_ptr(ptr),
|
23 |
+
_size(size),
|
24 |
+
_ownership(ownership),
|
25 |
+
_name(name),
|
26 |
+
_lockCount(0)
|
27 |
+
{
|
28 |
+
}
|
29 |
+
|
30 |
+
~PosixSharedMemoryBuffer() override
|
31 |
+
{
|
32 |
+
close(_fd);
|
33 |
+
munmap(_ptr, _size);
|
34 |
+
|
35 |
+
if (_ownership) {
|
36 |
+
shm_unlink(_name.c_str());
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
bool tryLock() override
|
41 |
+
{
|
42 |
+
if (_lockCount == 0) {
|
43 |
+
int err = flock(_fd, LOCK_EX|LOCK_NB);
|
44 |
+
if (0 == err) {
|
45 |
+
_lockCount++;
|
46 |
+
}
|
47 |
+
}
|
48 |
+
return _lockCount != 0;
|
49 |
+
}
|
50 |
+
|
51 |
+
void lock() override
|
52 |
+
{
|
53 |
+
if (_lockCount == 0) {
|
54 |
+
flock(_fd, LOCK_EX);
|
55 |
+
}
|
56 |
+
_lockCount++;
|
57 |
+
}
|
58 |
+
|
59 |
+
void unlock() override
|
60 |
+
{
|
61 |
+
if (_lockCount != 0) {
|
62 |
+
flock(_fd, LOCK_UN);
|
63 |
+
}
|
64 |
+
_lockCount--;
|
65 |
+
}
|
66 |
+
|
67 |
+
unsigned char *ptr() override
|
68 |
+
{
|
69 |
+
return _ptr;
|
70 |
+
}
|
71 |
+
|
72 |
+
std::string name() override
|
73 |
+
{
|
74 |
+
return _name;
|
75 |
+
}
|
76 |
+
|
77 |
+
private:
|
78 |
+
int _fd;
|
79 |
+
unsigned char *_ptr;
|
80 |
+
size_t _size;
|
81 |
+
bool _ownership;
|
82 |
+
string _name;
|
83 |
+
unsigned int _lockCount;
|
84 |
+
};
|
85 |
+
|
86 |
+
std::shared_ptr<SharedMemoryBufferInterface> create_named_shared_memory_buffer(const
|
87 |
+
string& name, size_t size)
|
88 |
+
{
|
89 |
+
std::shared_ptr<SharedMemoryBufferInterface> ptr;
|
90 |
+
|
91 |
+
int fd = shm_open(name.c_str(), O_RDWR | O_RDONLY | O_CREAT,
|
92 |
+
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
|
93 |
+
if (-1 == fd) {
|
94 |
+
return ptr;
|
95 |
+
}
|
96 |
+
|
97 |
+
int err = ftruncate(fd, size);
|
98 |
+
if (-1 == err) {
|
99 |
+
shm_unlink(name.c_str());
|
100 |
+
return ptr;
|
101 |
+
}
|
102 |
+
|
103 |
+
unsigned char *buffer = reinterpret_cast<unsigned char *>(mmap(NULL, size,
|
104 |
+
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0));
|
105 |
+
|
106 |
+
ptr.reset(new PosixSharedMemoryBuffer(fd, buffer, size, true, name));
|
107 |
+
return ptr;
|
108 |
+
}
|
109 |
+
|
110 |
+
std::shared_ptr<SharedMemoryBufferInterface> open_named_shared_memory_buffer(const
|
111 |
+
string& name, bool readwrite)
|
112 |
+
{
|
113 |
+
std::shared_ptr<SharedMemoryBufferInterface> ptr;
|
114 |
+
|
115 |
+
int fd = shm_open(name.c_str(), readwrite ? O_RDWR | O_RDONLY : O_RDONLY, 0);
|
116 |
+
if (-1 == fd) {
|
117 |
+
return ptr;
|
118 |
+
}
|
119 |
+
|
120 |
+
struct stat sbuf;
|
121 |
+
int err = fstat(fd, &sbuf);
|
122 |
+
if (-1 == err) {
|
123 |
+
return ptr;
|
124 |
+
}
|
125 |
+
|
126 |
+
size_t size = sbuf.st_size;
|
127 |
+
unsigned char *buffer = reinterpret_cast<unsigned char *>(mmap(NULL, size,
|
128 |
+
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0));
|
129 |
+
|
130 |
+
ptr.reset(new PosixSharedMemoryBuffer(fd, buffer, size, false, name));
|
131 |
+
return ptr;
|
132 |
+
}
|
133 |
+
|
134 |
+
}
|
third-party/DPVO/Pangolin/components/pango_core/src/sigstate.cpp
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <pangolin/utils/sigstate.h>
|
29 |
+
#include <iostream>
|
30 |
+
#include <fstream>
|
31 |
+
#include <sstream>
|
32 |
+
|
33 |
+
using namespace std;
|
34 |
+
|
35 |
+
namespace pangolin
|
36 |
+
{
|
37 |
+
|
38 |
+
SigState& SigState::I() {
|
39 |
+
static SigState singleton;
|
40 |
+
return singleton;
|
41 |
+
}
|
42 |
+
|
43 |
+
SigState::SigState()
|
44 |
+
{
|
45 |
+
}
|
46 |
+
|
47 |
+
SigState::~SigState() {
|
48 |
+
Clear();
|
49 |
+
}
|
50 |
+
|
51 |
+
void SigState::Clear() {
|
52 |
+
sig_callbacks.clear();
|
53 |
+
}
|
54 |
+
|
55 |
+
void RegisterNewSigCallback(SigCallbackFn callback, void* data, const int signal)
|
56 |
+
{
|
57 |
+
SigState::I().sig_callbacks.insert(std::pair<int, SigCallback>(signal, SigCallback(signal, callback, data)));
|
58 |
+
}
|
59 |
+
|
60 |
+
}
|
third-party/DPVO/Pangolin/components/pango_core/src/threadedfilebuf.cpp
ADDED
@@ -0,0 +1,353 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <pangolin/utils/threadedfilebuf.h>
|
29 |
+
#include <pangolin/utils/file_utils.h>
|
30 |
+
#include <pangolin/utils/sigstate.h>
|
31 |
+
|
32 |
+
#include <cstring>
|
33 |
+
#include <stdexcept>
|
34 |
+
|
35 |
+
#ifdef USE_POSIX_FILE_IO
|
36 |
+
#include <unistd.h>
|
37 |
+
#include <fcntl.h>
|
38 |
+
|
39 |
+
// Optionally use direct file i/o to avoid the cache.
|
40 |
+
#define USE_DIRECT_FILE_IO
|
41 |
+
#define POSIX_BLOCK_SIZE 4096
|
42 |
+
#endif
|
43 |
+
|
44 |
+
using namespace std;
|
45 |
+
|
46 |
+
namespace pangolin
|
47 |
+
{
|
48 |
+
|
49 |
+
namespace
|
50 |
+
{
|
51 |
+
char* allocate_buffer(size_t mem_max_size)
|
52 |
+
{
|
53 |
+
#ifdef USE_DIRECT_FILE_IO
|
54 |
+
void *mem_alloc;
|
55 |
+
int result = posix_memalign(&mem_alloc, POSIX_BLOCK_SIZE, mem_max_size);
|
56 |
+
if(result)
|
57 |
+
{
|
58 |
+
throw std::runtime_error("posix_memalign failed with result: " + std::to_string(result));
|
59 |
+
}
|
60 |
+
return static_cast<char*>(mem_alloc);
|
61 |
+
#else
|
62 |
+
return new char[static_cast<size_t>(mem_max_size)];
|
63 |
+
#endif
|
64 |
+
}
|
65 |
+
|
66 |
+
void free_buffer(char* mem_buffer)
|
67 |
+
{
|
68 |
+
#ifdef USE_DIRECT_FILE_IO
|
69 |
+
free(mem_buffer);
|
70 |
+
#else
|
71 |
+
delete mem_buffer;
|
72 |
+
#endif
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
threadedfilebuf::threadedfilebuf()
|
77 |
+
: mem_buffer(0), mem_size(0), mem_max_size(0), mem_start(0), mem_end(0), should_run(false), is_pipe(false)
|
78 |
+
{
|
79 |
+
}
|
80 |
+
|
81 |
+
threadedfilebuf::threadedfilebuf(const std::string& filename, size_t buffer_size_bytes )
|
82 |
+
: mem_buffer(0), mem_size(0), mem_max_size(0), mem_start(0), mem_end(0), should_run(false), is_pipe(pangolin::IsPipe(filename))
|
83 |
+
{
|
84 |
+
open(filename, buffer_size_bytes);
|
85 |
+
}
|
86 |
+
|
87 |
+
void threadedfilebuf::open(const std::string& filename, size_t buffer_size_bytes)
|
88 |
+
{
|
89 |
+
is_pipe = pangolin::IsPipe(filename);
|
90 |
+
|
91 |
+
#ifdef USE_POSIX_FILE_IO
|
92 |
+
if (filenum != -1) {
|
93 |
+
#else
|
94 |
+
if (file.is_open()) {
|
95 |
+
#endif
|
96 |
+
close();
|
97 |
+
}
|
98 |
+
|
99 |
+
#ifdef USE_POSIX_FILE_IO
|
100 |
+
|
101 |
+
// File is read/write for user and group, read only for other.
|
102 |
+
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
|
103 |
+
#ifdef USE_DIRECT_FILE_IO
|
104 |
+
filenum = ::open(filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_DIRECT | O_SYNC, mode);
|
105 |
+
#else
|
106 |
+
filenum = ::open(filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, mode);
|
107 |
+
#endif
|
108 |
+
|
109 |
+
#else
|
110 |
+
file.open(filename.c_str(), ios::out | ios::binary);
|
111 |
+
#endif
|
112 |
+
|
113 |
+
#ifdef USE_POSIX_FILE_IO
|
114 |
+
if (filenum == -1) {
|
115 |
+
#else
|
116 |
+
if(!file.is_open()) {
|
117 |
+
#endif
|
118 |
+
throw std::runtime_error("Unable to open '" + filename + "' for writing.");
|
119 |
+
}
|
120 |
+
|
121 |
+
mem_buffer = 0;
|
122 |
+
mem_size = 0;
|
123 |
+
mem_start = 0;
|
124 |
+
mem_end = 0;
|
125 |
+
mem_max_size = static_cast<std::streamsize>(buffer_size_bytes);
|
126 |
+
mem_buffer = allocate_buffer(mem_max_size);
|
127 |
+
should_run = true;
|
128 |
+
write_thread = std::thread(std::ref(*this));
|
129 |
+
}
|
130 |
+
|
131 |
+
void threadedfilebuf::close()
|
132 |
+
{
|
133 |
+
should_run = false;
|
134 |
+
|
135 |
+
cond_queued.notify_all();
|
136 |
+
|
137 |
+
if(write_thread.joinable())
|
138 |
+
{
|
139 |
+
write_thread.join();
|
140 |
+
}
|
141 |
+
|
142 |
+
if(mem_buffer)
|
143 |
+
{
|
144 |
+
free_buffer(mem_buffer);
|
145 |
+
mem_buffer = 0;
|
146 |
+
}
|
147 |
+
|
148 |
+
#ifdef USE_POSIX_FILE_IO
|
149 |
+
::close(filenum);
|
150 |
+
filenum = -1;
|
151 |
+
#else
|
152 |
+
file.close();
|
153 |
+
#endif
|
154 |
+
}
|
155 |
+
|
156 |
+
void threadedfilebuf::soft_close()
|
157 |
+
{
|
158 |
+
// Forces sputn to write no bytes and exit early, results in lost data
|
159 |
+
mem_size = 0;
|
160 |
+
}
|
161 |
+
|
162 |
+
void threadedfilebuf::force_close()
|
163 |
+
{
|
164 |
+
soft_close();
|
165 |
+
close();
|
166 |
+
}
|
167 |
+
|
168 |
+
threadedfilebuf::~threadedfilebuf()
|
169 |
+
{
|
170 |
+
close();
|
171 |
+
}
|
172 |
+
|
173 |
+
std::streamsize threadedfilebuf::xsputn(const char* data, std::streamsize num_bytes)
|
174 |
+
{
|
175 |
+
if( num_bytes > mem_max_size ) {
|
176 |
+
std::unique_lock<std::mutex> lock(update_mutex);
|
177 |
+
// Wait until queue is empty
|
178 |
+
while( mem_size > 0 ) {
|
179 |
+
cond_dequeued.wait(lock);
|
180 |
+
}
|
181 |
+
|
182 |
+
// Allocate bigger buffer
|
183 |
+
free_buffer(mem_buffer);
|
184 |
+
mem_start = 0;
|
185 |
+
mem_end = 0;
|
186 |
+
mem_max_size = num_bytes * 4;
|
187 |
+
mem_buffer = allocate_buffer(mem_max_size);
|
188 |
+
}
|
189 |
+
|
190 |
+
{
|
191 |
+
std::unique_lock<std::mutex> lock(update_mutex);
|
192 |
+
|
193 |
+
// wait until there is space to write into buffer
|
194 |
+
while( mem_size + num_bytes > mem_max_size ) {
|
195 |
+
cond_dequeued.wait(lock);
|
196 |
+
}
|
197 |
+
|
198 |
+
// add image to end of mem_buffer
|
199 |
+
const std::streamsize array_a_size =
|
200 |
+
(mem_start <= mem_end) ? (mem_max_size - mem_end) : (mem_start - mem_end);
|
201 |
+
|
202 |
+
if( num_bytes <= array_a_size )
|
203 |
+
{
|
204 |
+
// copy in one
|
205 |
+
memcpy(mem_buffer + mem_end, data, static_cast<size_t>(num_bytes));
|
206 |
+
mem_end += num_bytes;
|
207 |
+
mem_size += num_bytes;
|
208 |
+
}else{
|
209 |
+
const std::streamsize array_b_size = num_bytes - array_a_size;
|
210 |
+
memcpy(mem_buffer + mem_end, data, (size_t)array_a_size);
|
211 |
+
memcpy(mem_buffer, data+array_a_size, (size_t)array_b_size);
|
212 |
+
mem_end = array_b_size;
|
213 |
+
mem_size += num_bytes;
|
214 |
+
}
|
215 |
+
|
216 |
+
if(mem_end == mem_max_size)
|
217 |
+
mem_end = 0;
|
218 |
+
}
|
219 |
+
|
220 |
+
cond_queued.notify_one();
|
221 |
+
|
222 |
+
input_pos += num_bytes;
|
223 |
+
return num_bytes;
|
224 |
+
}
|
225 |
+
|
226 |
+
int threadedfilebuf::overflow(int c)
|
227 |
+
{
|
228 |
+
const std::streamsize num_bytes = 1;
|
229 |
+
|
230 |
+
{
|
231 |
+
std::unique_lock<std::mutex> lock(update_mutex);
|
232 |
+
|
233 |
+
// wait until there is space to write into buffer
|
234 |
+
while( mem_size + num_bytes > mem_max_size ) {
|
235 |
+
cond_dequeued.wait(lock);
|
236 |
+
}
|
237 |
+
|
238 |
+
// add image to end of mem_buffer
|
239 |
+
mem_buffer[mem_end] = c;
|
240 |
+
mem_end += num_bytes;
|
241 |
+
mem_size += num_bytes;
|
242 |
+
|
243 |
+
if(mem_end == mem_max_size)
|
244 |
+
mem_end = 0;
|
245 |
+
}
|
246 |
+
|
247 |
+
cond_queued.notify_one();
|
248 |
+
|
249 |
+
input_pos += num_bytes;
|
250 |
+
return num_bytes;
|
251 |
+
}
|
252 |
+
|
253 |
+
std::streampos threadedfilebuf::seekoff(
|
254 |
+
std::streamoff off, std::ios_base::seekdir way,
|
255 |
+
std::ios_base::openmode /*which*/
|
256 |
+
) {
|
257 |
+
if(off == 0 && way == ios_base::cur) {
|
258 |
+
return input_pos;
|
259 |
+
}else{
|
260 |
+
return -1;
|
261 |
+
}
|
262 |
+
}
|
263 |
+
|
264 |
+
void threadedfilebuf::operator()()
|
265 |
+
{
|
266 |
+
std::streamsize data_to_write = 0;
|
267 |
+
|
268 |
+
while(true)
|
269 |
+
{
|
270 |
+
if(is_pipe)
|
271 |
+
{
|
272 |
+
try
|
273 |
+
{
|
274 |
+
if(SigState::I().sig_callbacks.at(SIGPIPE).value)
|
275 |
+
{
|
276 |
+
soft_close();
|
277 |
+
return;
|
278 |
+
}
|
279 |
+
} catch(std::out_of_range&)
|
280 |
+
{
|
281 |
+
// std::cout << "Please register a SIGPIPE handler for your writer" << std::endl;
|
282 |
+
}
|
283 |
+
}
|
284 |
+
|
285 |
+
{
|
286 |
+
std::unique_lock<std::mutex> lock(update_mutex);
|
287 |
+
|
288 |
+
// Wait until there is data to write or we are stopping the write thread.
|
289 |
+
#ifdef USE_DIRECT_FILE_IO
|
290 |
+
while(mem_size < POSIX_BLOCK_SIZE && should_run) {
|
291 |
+
#else
|
292 |
+
while(mem_size == 0 && should_run) {
|
293 |
+
#endif
|
294 |
+
cond_queued.wait(lock);
|
295 |
+
}
|
296 |
+
|
297 |
+
if (mem_size == 0 && !should_run)
|
298 |
+
{
|
299 |
+
return;
|
300 |
+
}
|
301 |
+
|
302 |
+
data_to_write =
|
303 |
+
(mem_start < mem_end) ?
|
304 |
+
mem_end - mem_start :
|
305 |
+
mem_max_size - mem_start;
|
306 |
+
}
|
307 |
+
|
308 |
+
// Adjust write size if appropriate.
|
309 |
+
#ifdef USE_DIRECT_FILE_IO
|
310 |
+
if (!should_run && data_to_write < POSIX_BLOCK_SIZE)
|
311 |
+
{
|
312 |
+
// Stopping the write thread - allow non-direct write of final block.
|
313 |
+
int fopts = fcntl(filenum, F_GETFL);
|
314 |
+
int result = fcntl(filenum, F_SETFL, fopts & ~O_DIRECT);
|
315 |
+
if (result == -1)
|
316 |
+
{
|
317 |
+
throw std::runtime_error("fcntl failed with result: " + std::to_string(result));
|
318 |
+
}
|
319 |
+
}
|
320 |
+
else
|
321 |
+
{
|
322 |
+
// Direct writes are limited to block size boundaries
|
323 |
+
data_to_write = data_to_write - (data_to_write%POSIX_BLOCK_SIZE);
|
324 |
+
}
|
325 |
+
#endif
|
326 |
+
|
327 |
+
// Write data through to disk.
|
328 |
+
#ifdef USE_POSIX_FILE_IO
|
329 |
+
int bytes_written = ::write(filenum, mem_buffer + mem_start, data_to_write);
|
330 |
+
if(bytes_written == -1)
|
331 |
+
{
|
332 |
+
throw std::runtime_error("Unable to write data.");
|
333 |
+
}
|
334 |
+
#else
|
335 |
+
std::streamsize bytes_written =
|
336 |
+
file.sputn(mem_buffer + mem_start, data_to_write );
|
337 |
+
#endif
|
338 |
+
|
339 |
+
{
|
340 |
+
std::unique_lock<std::mutex> lock(update_mutex);
|
341 |
+
|
342 |
+
mem_size -= bytes_written;
|
343 |
+
mem_start += bytes_written;
|
344 |
+
|
345 |
+
if(mem_start == mem_max_size)
|
346 |
+
mem_start = 0;
|
347 |
+
}
|
348 |
+
|
349 |
+
cond_dequeued.notify_all();
|
350 |
+
}
|
351 |
+
}
|
352 |
+
|
353 |
+
}
|
third-party/DPVO/Pangolin/components/pango_core/src/uri.cpp
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <pangolin/utils/file_utils.h>
|
29 |
+
#include <pangolin/utils/uri.h>
|
30 |
+
|
31 |
+
#include <stdexcept>
|
32 |
+
#include <vector>
|
33 |
+
#include <string>
|
34 |
+
|
35 |
+
namespace pangolin
|
36 |
+
{
|
37 |
+
|
38 |
+
Uri ParseUri(const std::string &str_uri)
|
39 |
+
{
|
40 |
+
Uri uri;
|
41 |
+
uri.full_uri = str_uri;
|
42 |
+
|
43 |
+
// Find Scheme delimiter
|
44 |
+
size_t npos = 0;
|
45 |
+
const size_t ns = str_uri.find(':', npos);
|
46 |
+
if( ns != std::string::npos )
|
47 |
+
{
|
48 |
+
uri.scheme = str_uri.substr(0,ns);
|
49 |
+
npos = ns+1;
|
50 |
+
}else{
|
51 |
+
uri.scheme = "file";
|
52 |
+
uri.url = str_uri;
|
53 |
+
return uri;
|
54 |
+
}
|
55 |
+
|
56 |
+
// Find Options delimiters
|
57 |
+
if( str_uri.size() > npos && str_uri[npos] == '[' )
|
58 |
+
{
|
59 |
+
const size_t nob = npos;
|
60 |
+
const size_t ncb = str_uri.find(']', nob+1);
|
61 |
+
if(ncb != std::string::npos)
|
62 |
+
{
|
63 |
+
const std::string queries = str_uri.substr(nob+1, ncb - (ns+2) );
|
64 |
+
std::vector<std::string> params;
|
65 |
+
Split(queries, ',', params);
|
66 |
+
for(size_t i=0; i< params.size(); ++i)
|
67 |
+
{
|
68 |
+
std::vector<std::string> args;
|
69 |
+
Split(params[i], '=', args );
|
70 |
+
std::string key = Trim(args[0]);
|
71 |
+
std::string val = args.size() > 1 ? Trim(args[1]) : "";
|
72 |
+
uri.Set(key,val);
|
73 |
+
}
|
74 |
+
}else{
|
75 |
+
throw std::runtime_error("Unable to parse URI: '" + str_uri + "'");
|
76 |
+
}
|
77 |
+
npos = ncb + 1;
|
78 |
+
}
|
79 |
+
|
80 |
+
// Find url delimiter
|
81 |
+
size_t nurl = str_uri.find("//", npos);
|
82 |
+
if(nurl != std::string::npos)
|
83 |
+
{
|
84 |
+
uri.url = str_uri.substr(nurl+2);
|
85 |
+
}
|
86 |
+
|
87 |
+
return uri;
|
88 |
+
}
|
89 |
+
|
90 |
+
std::ostream& operator<< (std::ostream &out, Uri &uri)
|
91 |
+
{
|
92 |
+
out << "scheme: " << uri.scheme << std::endl;
|
93 |
+
out << "url: " << uri.url << std::endl;
|
94 |
+
out << "params:" << std::endl;
|
95 |
+
|
96 |
+
for( Uri::ParamMap::const_iterator ip = uri.params.begin();
|
97 |
+
ip != uri.params.end(); ++ip)
|
98 |
+
{
|
99 |
+
out << "\t" << ip->first << " = " << ip->second << std::endl;
|
100 |
+
}
|
101 |
+
|
102 |
+
return out;
|
103 |
+
}
|
104 |
+
|
105 |
+
} // pangolin
|
third-party/DPVO/Pangolin/components/pango_core/tests/tests_uri.cpp
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#define CATCH_CONFIG_MAIN
|
2 |
+
#include <catch2/catch.hpp>
|
3 |
+
|
4 |
+
#include <string>
|
5 |
+
#include <limits>
|
6 |
+
#include <functional>
|
7 |
+
#include <pangolin/factory/factory_registry.h>
|
8 |
+
|
9 |
+
template<typename T>
|
10 |
+
inline void ExpectExceptionWithMessageFromAction(
|
11 |
+
std::function<void()> action,
|
12 |
+
const std::string& exceptionMessageBegin
|
13 |
+
) {
|
14 |
+
try
|
15 |
+
{
|
16 |
+
action();
|
17 |
+
|
18 |
+
FAIL("The action succeeded when it should have failed.");
|
19 |
+
}
|
20 |
+
catch(const T& ex)
|
21 |
+
{
|
22 |
+
std::string exceptionMessage = std::string(ex.what());
|
23 |
+
std::string exceptionMessageRelevantPortion
|
24 |
+
= exceptionMessage.substr(0, exceptionMessageBegin.size());
|
25 |
+
REQUIRE(exceptionMessageRelevantPortion.compare(exceptionMessageBegin) == 0);
|
26 |
+
}
|
27 |
+
catch(...)
|
28 |
+
{
|
29 |
+
FAIL("Another kind of exception was thrown to the one expected");
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
TEST_CASE("Missing Closing Bracket Causes Exception")
|
34 |
+
{
|
35 |
+
const std::string rawUri = "abc:[...";
|
36 |
+
auto testAction = [&](){pangolin::ParseUri(rawUri);};
|
37 |
+
ExpectExceptionWithMessageFromAction<std::runtime_error>(testAction,
|
38 |
+
"Unable to parse URI: '" + rawUri + "'");
|
39 |
+
}
|
40 |
+
|
41 |
+
TEST_CASE("Uri Equals Sign Character In Value Truncates The Rest")
|
42 |
+
{
|
43 |
+
const std::string fullUri = "abc:[key=value=notfound,key2=value2]";
|
44 |
+
const pangolin::Uri pangoUri = pangolin::ParseUri(fullUri);
|
45 |
+
|
46 |
+
// parsing option list should have precendence over parsing individual option
|
47 |
+
REQUIRE(pangoUri.params.size() == 2);
|
48 |
+
|
49 |
+
REQUIRE( pangoUri.params[0].first == std::string("key"));
|
50 |
+
REQUIRE( pangoUri.params[1].first == std::string("key2"));
|
51 |
+
|
52 |
+
const std::string truncated = pangoUri.Get<std::string>("key", "");
|
53 |
+
REQUIRE( truncated == std::string("value"));
|
54 |
+
|
55 |
+
const std::string otherValue = pangoUri.Get<std::string>("key2", "");
|
56 |
+
REQUIRE( otherValue == std::string("value2"));
|
57 |
+
}
|
58 |
+
|
59 |
+
TEST_CASE("Uri Multiple Occurrences Of Option Overrides Previous")
|
60 |
+
{
|
61 |
+
const std::string fullUri = "abc:[key=value,key=value2]";
|
62 |
+
const pangolin::Uri pangoUri = pangolin::ParseUri(fullUri);
|
63 |
+
|
64 |
+
REQUIRE(pangoUri.params.size() == 2);
|
65 |
+
REQUIRE( pangoUri.params[0].first == std::string("key"));
|
66 |
+
REQUIRE( pangoUri.params[1].first == std::string("key"));
|
67 |
+
|
68 |
+
const std::string truncated = pangoUri.Get<std::string>("key", "");
|
69 |
+
REQUIRE( truncated == std::string("value2"));
|
70 |
+
}
|
71 |
+
|
72 |
+
|
73 |
+
TEST_CASE("Uri Url Contains Everything After Separator")
|
74 |
+
{
|
75 |
+
const std::string expectedUrl = "abc:123[],=";
|
76 |
+
const std::string fullUri = "abc:[key=value,key=value2]//" + expectedUrl;
|
77 |
+
const pangolin::Uri pangoUri = pangolin::ParseUri(fullUri);
|
78 |
+
REQUIRE( pangoUri.url == expectedUrl);
|
79 |
+
}
|
80 |
+
|
81 |
+
TEST_CASE("Uri Invalid Characters After Closed Bracket Are Ignored")
|
82 |
+
{
|
83 |
+
const std::string expectedUrl = "abc:123[],=";
|
84 |
+
const std::string fullUri = "abc:[key=value,key=value2]xyz//" + expectedUrl;
|
85 |
+
const pangolin::Uri pangoUri = pangolin::ParseUri(fullUri);
|
86 |
+
REQUIRE( pangoUri.url == expectedUrl);
|
87 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/CMakeLists.txt
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
get_filename_component(COMPONENT ${CMAKE_CURRENT_LIST_DIR} NAME)
|
2 |
+
|
3 |
+
target_sources( ${COMPONENT}
|
4 |
+
PRIVATE
|
5 |
+
${CMAKE_CURRENT_LIST_DIR}/src/display.cpp
|
6 |
+
${CMAKE_CURRENT_LIST_DIR}/src/process.cpp
|
7 |
+
${CMAKE_CURRENT_LIST_DIR}/src/pangolin_gl.cpp
|
8 |
+
${CMAKE_CURRENT_LIST_DIR}/src/handler.cpp
|
9 |
+
${CMAKE_CURRENT_LIST_DIR}/src/handler_image.cpp
|
10 |
+
${CMAKE_CURRENT_LIST_DIR}/src/handler_glbuffer.cpp
|
11 |
+
${CMAKE_CURRENT_LIST_DIR}/src/view.cpp
|
12 |
+
${CMAKE_CURRENT_LIST_DIR}/src/widgets.cpp
|
13 |
+
${CMAKE_CURRENT_LIST_DIR}/src/image_view.cpp
|
14 |
+
${CMAKE_CURRENT_LIST_DIR}/src/ConsoleView.cpp
|
15 |
+
${CMAKE_CURRENT_LIST_DIR}/src/default_font.cpp
|
16 |
+
)
|
17 |
+
|
18 |
+
target_link_libraries(${COMPONENT} PUBLIC pango_core pango_opengl pango_windowing pango_vars )
|
19 |
+
|
20 |
+
target_include_directories(${COMPONENT} PUBLIC
|
21 |
+
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
|
22 |
+
$<INSTALL_INTERFACE:include>
|
23 |
+
)
|
24 |
+
install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include"
|
25 |
+
DESTINATION ${CMAKE_INSTALL_PREFIX}
|
26 |
+
)
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/console/ConsoleView.h
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <deque>
|
31 |
+
|
32 |
+
#include <pangolin/gl/glfont.h>
|
33 |
+
#include <pangolin/gl/colour.h>
|
34 |
+
#include <pangolin/var/var.h>
|
35 |
+
#include <pangolin/display/view.h>
|
36 |
+
#include <pangolin/handler/handler.h>
|
37 |
+
|
38 |
+
#include <pangolin/console/InterpreterInterface.h>
|
39 |
+
|
40 |
+
namespace pangolin
|
41 |
+
{
|
42 |
+
|
43 |
+
class ConsoleView : public pangolin::View, pangolin::Handler
|
44 |
+
{
|
45 |
+
public:
|
46 |
+
struct Line
|
47 |
+
{
|
48 |
+
Line()
|
49 |
+
: linetype(ConsoleLineTypeCmd)
|
50 |
+
{
|
51 |
+
}
|
52 |
+
|
53 |
+
Line(const GlText& text, InterpreterLineType linetype = ConsoleLineTypeCmd )
|
54 |
+
: text(text), linetype(linetype)
|
55 |
+
{
|
56 |
+
}
|
57 |
+
|
58 |
+
GlText text;
|
59 |
+
InterpreterLineType linetype;
|
60 |
+
};
|
61 |
+
|
62 |
+
|
63 |
+
// Construct with interpreter (and take ownership)
|
64 |
+
ConsoleView(const std::shared_ptr<InterpreterInterface>& interpreter);
|
65 |
+
|
66 |
+
~ConsoleView();
|
67 |
+
|
68 |
+
View& ShowWithoutAnimation(bool show=true);
|
69 |
+
|
70 |
+
// Replace implementation in View to account for hiding animation
|
71 |
+
View& Show(bool show=true);
|
72 |
+
|
73 |
+
// Replace implementation in View to account for hiding animation
|
74 |
+
void ToggleShow();
|
75 |
+
|
76 |
+
// Replace implementation in View to account for hiding animation
|
77 |
+
bool IsShown() const;
|
78 |
+
|
79 |
+
void Render() override;
|
80 |
+
|
81 |
+
void Keyboard(View&, unsigned char key, int x, int y, bool pressed) override;
|
82 |
+
|
83 |
+
private:
|
84 |
+
void DrawLine(const ConsoleView::Line& l, int carat);
|
85 |
+
|
86 |
+
void ProcessOutputLines();
|
87 |
+
|
88 |
+
void AddLine(const std::string& text, InterpreterLineType linetype = ConsoleLineTypeCmd);
|
89 |
+
|
90 |
+
Line* GetLine(int id, InterpreterLineType line_type, const std::string& prefix = "");
|
91 |
+
|
92 |
+
std::shared_ptr<InterpreterInterface> interpreter;
|
93 |
+
|
94 |
+
GlFont& font;
|
95 |
+
|
96 |
+
int carat;
|
97 |
+
Line current_line;
|
98 |
+
std::deque<Line> line_buffer;
|
99 |
+
|
100 |
+
bool hiding;
|
101 |
+
GLfloat bottom;
|
102 |
+
|
103 |
+
Colour background_colour;
|
104 |
+
std::map<InterpreterLineType,pangolin::Colour> line_colours;
|
105 |
+
float animation_speed;
|
106 |
+
};
|
107 |
+
|
108 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/console/InterpreterInterface.h
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <vector>
|
31 |
+
#include <string>
|
32 |
+
|
33 |
+
namespace pangolin
|
34 |
+
{
|
35 |
+
|
36 |
+
enum InterpreterLineType
|
37 |
+
{
|
38 |
+
ConsoleLineTypeCmd,
|
39 |
+
ConsoleLineTypeCmdOptions,
|
40 |
+
ConsoleLineTypeStdout,
|
41 |
+
ConsoleLineTypeStderr,
|
42 |
+
ConsoleLineTypeOutput,
|
43 |
+
ConsoleLineTypeHelp,
|
44 |
+
};
|
45 |
+
|
46 |
+
class InterpreterLine
|
47 |
+
{
|
48 |
+
public:
|
49 |
+
inline InterpreterLine()
|
50 |
+
: linetype(ConsoleLineTypeCmd)
|
51 |
+
{
|
52 |
+
}
|
53 |
+
|
54 |
+
inline InterpreterLine(std::string text, InterpreterLineType linetype = ConsoleLineTypeOutput)
|
55 |
+
: text(text), linetype(linetype)
|
56 |
+
{
|
57 |
+
}
|
58 |
+
|
59 |
+
std::string text;
|
60 |
+
InterpreterLineType linetype;
|
61 |
+
};
|
62 |
+
|
63 |
+
class InterpreterInterface
|
64 |
+
{
|
65 |
+
public:
|
66 |
+
inline virtual ~InterpreterInterface()
|
67 |
+
{
|
68 |
+
}
|
69 |
+
|
70 |
+
virtual void PushCommand(const std::string& cmd) = 0;
|
71 |
+
|
72 |
+
virtual bool PullLine(InterpreterLine& line) = 0;
|
73 |
+
|
74 |
+
virtual std::vector<std::string> Complete(
|
75 |
+
const std::string& cmd, int max_options = 20
|
76 |
+
) = 0;
|
77 |
+
|
78 |
+
};
|
79 |
+
|
80 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/attach.h
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2013 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <iostream>
|
31 |
+
#include <string>
|
32 |
+
#include <cmath>
|
33 |
+
|
34 |
+
namespace pangolin
|
35 |
+
{
|
36 |
+
|
37 |
+
/// Units for measuring screen distances.
|
38 |
+
enum Unit {
|
39 |
+
Fraction,
|
40 |
+
Pixel,
|
41 |
+
ReversePixel
|
42 |
+
};
|
43 |
+
|
44 |
+
/// Defines absolute or relative position from parent viewport edge.
|
45 |
+
/// Constructors distinguised by whole pixels, or floating
|
46 |
+
/// fraction in interval [0,1]
|
47 |
+
struct PANGOLIN_EXPORT Attach {
|
48 |
+
/// Attach to Left/Bottom edge
|
49 |
+
Attach() : unit(Fraction), p(0) {}
|
50 |
+
|
51 |
+
/// General constructor
|
52 |
+
Attach(Unit unit, GLfloat p) : unit(unit), p(p) {}
|
53 |
+
|
54 |
+
/// Specify relative position in range [0,1].
|
55 |
+
/// 0 represents leftmost / bottom-most edge,
|
56 |
+
/// 1 represents rightmost / topmost edge
|
57 |
+
Attach(GLfloat p) : unit(Fraction), p(p) {
|
58 |
+
// Allow for numerical imprecision when checking usage.
|
59 |
+
if( p < -1E-3 || 1.001 < p ) {
|
60 |
+
std::cerr << "Pangolin API Change: Display::SetBounds must be used with Attach::Pix or Attach::ReversePix to specify pixel bounds relative to an edge. See the code samples for details." << std::endl;
|
61 |
+
throw std::exception();
|
62 |
+
}
|
63 |
+
}
|
64 |
+
|
65 |
+
/// Specify absolute position from leftmost / bottom-most edge.
|
66 |
+
static Attach Pix(int p) {
|
67 |
+
return Attach(p >=0 ? Pixel : ReversePixel, std::abs((float)p));
|
68 |
+
}
|
69 |
+
|
70 |
+
/// Specify absolute position from rightmost / topmost edge.
|
71 |
+
static Attach ReversePix(int p) {
|
72 |
+
return Attach(ReversePixel, (GLfloat)p);
|
73 |
+
}
|
74 |
+
|
75 |
+
/// Specify relative position in range [0,1].
|
76 |
+
/// 0 represents leftmost / bottom-most edge,
|
77 |
+
/// 1 represents rightmost / topmost edge
|
78 |
+
static Attach Frac(float frac) {
|
79 |
+
return Attach(frac);
|
80 |
+
}
|
81 |
+
|
82 |
+
Unit unit;
|
83 |
+
GLfloat p;
|
84 |
+
};
|
85 |
+
|
86 |
+
} // namespace pangolin
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/default_font.h
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
|
3 |
+
#include <pangolin/gl/glfont.h>
|
4 |
+
|
5 |
+
namespace pangolin {
|
6 |
+
GlFont& default_font();
|
7 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/display.h
ADDED
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove, Richard Newcombe
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <pangolin/platform.h>
|
31 |
+
#include <pangolin/gl/glinclude.h>
|
32 |
+
#include <pangolin/gl/viewport.h>
|
33 |
+
#include <pangolin/utils/params.h>
|
34 |
+
#include <pangolin/windowing/window.h>
|
35 |
+
|
36 |
+
#include <functional>
|
37 |
+
#include <string>
|
38 |
+
#include <memory>
|
39 |
+
|
40 |
+
/*! \file display.h
|
41 |
+
* This file contains a number of global methods for creating and
|
42 |
+
* querying window state as well as handling user input.
|
43 |
+
*/
|
44 |
+
|
45 |
+
namespace pangolin
|
46 |
+
{
|
47 |
+
|
48 |
+
// Forward Declarations
|
49 |
+
struct View;
|
50 |
+
class UserApp;
|
51 |
+
|
52 |
+
/// Give this OpenGL context a name or switch contexts.
|
53 |
+
/// This is required to initialise Pangolin for use with an
|
54 |
+
/// externally defined OpenGL context. You needn't call it
|
55 |
+
/// if you have used CreateWindowAndBind() to create a window
|
56 |
+
/// or launched a pangolin::UserApp
|
57 |
+
PANGOLIN_EXPORT
|
58 |
+
void BindToContext(std::string name);
|
59 |
+
|
60 |
+
/// Initialise OpenGL window (determined by platform) and bind context.
|
61 |
+
/// This method will choose an available windowing system if one is present.
|
62 |
+
PANGOLIN_EXPORT
|
63 |
+
WindowInterface& CreateWindowAndBind(std::string window_title, int w = 640, int h = 480, const Params& params = Params());
|
64 |
+
|
65 |
+
/// Return pointer to current Pangolin Window context, or nullptr if none bound.
|
66 |
+
PANGOLIN_EXPORT
|
67 |
+
WindowInterface* GetBoundWindow();
|
68 |
+
|
69 |
+
PANGOLIN_EXPORT
|
70 |
+
void DestroyWindow(const std::string& window_title);
|
71 |
+
|
72 |
+
/// Launch users derived UserApp, controlling OpenGL event loop.
|
73 |
+
/// This method will block until the application exits, calling app's
|
74 |
+
/// Init() method to start and Render() method subsequently to draw each frame.
|
75 |
+
/// @return exit code for use when returning from main. Currently always 0.
|
76 |
+
PANGOLIN_EXPORT
|
77 |
+
int LaunchUserApp(UserApp& app);
|
78 |
+
|
79 |
+
/// Perform any post rendering, event processing and frame swapping.
|
80 |
+
PANGOLIN_EXPORT
|
81 |
+
void FinishFrame();
|
82 |
+
|
83 |
+
/// Request that the window close.
|
84 |
+
PANGOLIN_EXPORT
|
85 |
+
void Quit();
|
86 |
+
|
87 |
+
/// Request that all windows close.
|
88 |
+
PANGOLIN_EXPORT
|
89 |
+
void QuitAll();
|
90 |
+
|
91 |
+
/// Returns true if user has requested to close OpenGL window.
|
92 |
+
PANGOLIN_EXPORT
|
93 |
+
bool ShouldQuit();
|
94 |
+
|
95 |
+
/// Renders any views with default draw methods.
|
96 |
+
PANGOLIN_EXPORT
|
97 |
+
void RenderViews();
|
98 |
+
|
99 |
+
/// Perform any post render events, such as screen recording.
|
100 |
+
PANGOLIN_EXPORT
|
101 |
+
void PostRender();
|
102 |
+
|
103 |
+
/// Request to be notified via functor when key is pressed.
|
104 |
+
PANGOLIN_EXPORT
|
105 |
+
void RegisterKeyPressCallback(int key, std::function<void(void)> func);
|
106 |
+
|
107 |
+
/// Request to be notified via functor when key is pressed.
|
108 |
+
/// Functor may take one parameter which will equal the key pressed
|
109 |
+
PANGOLIN_EXPORT
|
110 |
+
void RegisterKeyPressCallback(int key, std::function<void(int)> func);
|
111 |
+
|
112 |
+
/// Save the contents of current window within the specified viewport (whole window by default).
|
113 |
+
/// This will be called during pangolin::FinishFrame().
|
114 |
+
/// \param filename_hint can be a complete filename (absolute or relative to working directory).
|
115 |
+
/// \param the portion of the window to save. Default construction will save entire window.
|
116 |
+
PANGOLIN_EXPORT
|
117 |
+
void SaveWindowOnRender(const std::string& filename_hint, const Viewport& v = Viewport());
|
118 |
+
|
119 |
+
/// Save the contents of current window within the specified viewport (whole window by default).
|
120 |
+
/// This will block whilst waiting for pending draw calls to complete and then save the current contents.
|
121 |
+
/// \param filename_hint can be a complete filename (absolute or relative to working directory).
|
122 |
+
/// \param the portion of the window to save. Default construction will save entire window.
|
123 |
+
PANGOLIN_EXPORT
|
124 |
+
void SaveWindowNow(const std::string& filename_hint, const Viewport& v = Viewport());
|
125 |
+
|
126 |
+
/// Retrieve 'base' display, corresponding to entire window.
|
127 |
+
PANGOLIN_EXPORT
|
128 |
+
View& DisplayBase();
|
129 |
+
|
130 |
+
/// Create or retrieve named display managed by pangolin (automatically deleted).
|
131 |
+
PANGOLIN_EXPORT
|
132 |
+
View& Display(const std::string& name);
|
133 |
+
|
134 |
+
/// Create unnamed display managed by pangolin (automatically deleted).
|
135 |
+
PANGOLIN_EXPORT
|
136 |
+
View& CreateDisplay();
|
137 |
+
|
138 |
+
/// Switch windows/fullscreenmode = fullscreen.
|
139 |
+
PANGOLIN_EXPORT
|
140 |
+
void ShowFullscreen(TrueFalseToggle on_off);
|
141 |
+
|
142 |
+
/// Toggle display of Pangolin console
|
143 |
+
PANGOLIN_EXPORT
|
144 |
+
void ShowConsole(TrueFalseToggle on_off);
|
145 |
+
}
|
146 |
+
|
147 |
+
#include <pangolin/display/display.hpp>
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/display.hpp
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove, Richard Newcombe
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
namespace pangolin
|
31 |
+
{
|
32 |
+
|
33 |
+
PANGOLIN_DEPRECATED("Use ShowFullscreen(...) instead")
|
34 |
+
inline void ToggleFullscreen() {
|
35 |
+
ShowFullscreen(TrueFalseToggle::Toggle);
|
36 |
+
}
|
37 |
+
PANGOLIN_DEPRECATED("Use ShowFullscreen(...) instead")
|
38 |
+
inline void SetFullscreen(bool fullscreen = true) {
|
39 |
+
ShowFullscreen( (TrueFalseToggle)fullscreen);
|
40 |
+
}
|
41 |
+
PANGOLIN_DEPRECATED("Use ShowConsole(...) instead")
|
42 |
+
inline void ToggleConsole()
|
43 |
+
{
|
44 |
+
ShowConsole(TrueFalseToggle::Toggle);
|
45 |
+
}
|
46 |
+
|
47 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/image_view.h
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
|
3 |
+
#include <pangolin/display/display.h>
|
4 |
+
#include <pangolin/gl/glpixformat.h>
|
5 |
+
#include <pangolin/gl/glformattraits.h>
|
6 |
+
#include <pangolin/gl/glsl.h>
|
7 |
+
#include <pangolin/handler/handler_image.h>
|
8 |
+
#include <pangolin/image/image_utils.h>
|
9 |
+
|
10 |
+
#include <mutex>
|
11 |
+
|
12 |
+
namespace pangolin
|
13 |
+
{
|
14 |
+
|
15 |
+
class PANGOLIN_EXPORT ImageView : public pangolin::View, public pangolin::ImageViewHandler
|
16 |
+
{
|
17 |
+
public:
|
18 |
+
ImageView(const std::string & title ="");
|
19 |
+
|
20 |
+
~ImageView();
|
21 |
+
|
22 |
+
void Render() override;
|
23 |
+
|
24 |
+
void Mouse(View& view, pangolin::MouseButton button, int x, int y, bool pressed, int button_state) override;
|
25 |
+
|
26 |
+
void Keyboard(View& view, unsigned char key, int x, int y, bool pressed) override;
|
27 |
+
|
28 |
+
pangolin::GlTexture& Tex();
|
29 |
+
|
30 |
+
ImageView& SetImage(void* ptr, size_t w, size_t h, size_t pitch, pangolin::GlPixFormat img_fmt, bool delayed_upload = false);
|
31 |
+
|
32 |
+
ImageView& SetImage(const pangolin::Image<unsigned char>& img, const pangolin::GlPixFormat& glfmt, bool delayed_upload = false);
|
33 |
+
|
34 |
+
template<typename T> inline
|
35 |
+
ImageView& SetImage(const pangolin::Image<T>& img, bool delayed_upload = false)
|
36 |
+
{
|
37 |
+
return SetImage(img.template UnsafeReinterpret<unsigned char>(), GlPixFormat::FromType<T>(), delayed_upload);
|
38 |
+
}
|
39 |
+
|
40 |
+
ImageView& SetImage(const pangolin::TypedImage& img, bool delayed_upload = false);
|
41 |
+
|
42 |
+
ImageView& SetImage(const pangolin::GlTexture& texture);
|
43 |
+
|
44 |
+
void LoadPending();
|
45 |
+
|
46 |
+
ImageView& Clear();
|
47 |
+
|
48 |
+
std::pair<float, float>& GetOffsetScale();
|
49 |
+
|
50 |
+
bool MouseReleased() const;
|
51 |
+
|
52 |
+
bool MousePressed() const;
|
53 |
+
|
54 |
+
void SetRenderOverlay(const bool& val);
|
55 |
+
|
56 |
+
// private:
|
57 |
+
// img_to_load contains image data that should be uploaded to the texture on
|
58 |
+
// the next render cycle. The data is owned by this object and should be
|
59 |
+
// freed after use.
|
60 |
+
pangolin::ManagedImage<unsigned char> img_to_load;
|
61 |
+
pangolin::GlPixFormat img_fmt_to_load;
|
62 |
+
|
63 |
+
std::pair<float, float> offset_scale;
|
64 |
+
pangolin::GlPixFormat fmt;
|
65 |
+
pangolin::GlTexture tex;
|
66 |
+
bool lastPressed;
|
67 |
+
bool mouseReleased;
|
68 |
+
bool mousePressed;
|
69 |
+
bool overlayRender;
|
70 |
+
|
71 |
+
std::mutex texlock;
|
72 |
+
};
|
73 |
+
|
74 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/process.h
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove, Richard Newcombe
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <pangolin/platform.h>
|
31 |
+
#include <pangolin/windowing/handler_bitsets.h>
|
32 |
+
|
33 |
+
namespace pangolin
|
34 |
+
{
|
35 |
+
|
36 |
+
/// You can use these methods to drive Pangolin events when it
|
37 |
+
/// doesn't own the OpenGL Context. You can probably ignore these.
|
38 |
+
namespace process
|
39 |
+
{
|
40 |
+
PANGOLIN_EXPORT
|
41 |
+
void Resize(int width, int height);
|
42 |
+
|
43 |
+
PANGOLIN_EXPORT
|
44 |
+
void Keyboard(unsigned char key, int x, int y, bool pressed, KeyModifierBitmask key_modifiers);
|
45 |
+
|
46 |
+
PANGOLIN_EXPORT
|
47 |
+
void Mouse(int button, bool pressed, int x, int y, KeyModifierBitmask key_modifiers);
|
48 |
+
|
49 |
+
PANGOLIN_EXPORT
|
50 |
+
void MouseMotion( int x, int y, KeyModifierBitmask key_modifiers);
|
51 |
+
|
52 |
+
PANGOLIN_EXPORT
|
53 |
+
void PassiveMouseMotion(int x, int y, KeyModifierBitmask key_modifiers);
|
54 |
+
|
55 |
+
PANGOLIN_EXPORT
|
56 |
+
void SpecialInput(InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, KeyModifierBitmask key_modifiers);
|
57 |
+
}
|
58 |
+
|
59 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/user_app.h
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2014 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <pangolin/platform.h>
|
31 |
+
|
32 |
+
namespace pangolin
|
33 |
+
{
|
34 |
+
|
35 |
+
class PANGOLIN_EXPORT UserApp
|
36 |
+
{
|
37 |
+
public:
|
38 |
+
virtual ~UserApp() {}
|
39 |
+
virtual void Init() {}
|
40 |
+
virtual void Render() = 0;
|
41 |
+
};
|
42 |
+
|
43 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/view.h
ADDED
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2013 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <functional>
|
31 |
+
#include <vector>
|
32 |
+
|
33 |
+
#include <pangolin/gl/viewport.h>
|
34 |
+
#include <pangolin/display/attach.h>
|
35 |
+
|
36 |
+
namespace pangolin
|
37 |
+
{
|
38 |
+
|
39 |
+
enum Layout
|
40 |
+
{
|
41 |
+
LayoutOverlay,
|
42 |
+
LayoutVertical,
|
43 |
+
LayoutHorizontal,
|
44 |
+
LayoutEqual,
|
45 |
+
LayoutEqualVertical,
|
46 |
+
LayoutEqualHorizontal
|
47 |
+
};
|
48 |
+
|
49 |
+
enum Lock {
|
50 |
+
LockLeft = 0,
|
51 |
+
LockBottom = 0,
|
52 |
+
LockCenter = 1,
|
53 |
+
LockRight = 2,
|
54 |
+
LockTop = 2
|
55 |
+
};
|
56 |
+
|
57 |
+
// Forward declarations
|
58 |
+
struct Handler;
|
59 |
+
|
60 |
+
class OpenGlRenderState;
|
61 |
+
|
62 |
+
/// A Display manages the location and resizing of an OpenGl viewport.
|
63 |
+
struct PANGOLIN_EXPORT View
|
64 |
+
{
|
65 |
+
View(double aspect=0.0)
|
66 |
+
: aspect(aspect), top(1.0),left(0.0),right(1.0),bottom(0.0), hlock(LockCenter),vlock(LockCenter),
|
67 |
+
layout(LayoutOverlay), scroll_offset(0), show(1), zorder(0), handler(0), scroll_show(1) {}
|
68 |
+
|
69 |
+
virtual ~View() {}
|
70 |
+
|
71 |
+
//! Activate Displays viewport for drawing within this area
|
72 |
+
void Activate() const;
|
73 |
+
|
74 |
+
//! Activate Displays and set State Matrices
|
75 |
+
void Activate(const OpenGlRenderState& state ) const;
|
76 |
+
|
77 |
+
//! Activate Displays viewport and Scissor for drawing within this area
|
78 |
+
void ActivateAndScissor() const;
|
79 |
+
|
80 |
+
//! Activate Displays viewport and Scissor for drawing within this area
|
81 |
+
void ActivateScissorAndClear() const;
|
82 |
+
|
83 |
+
//! Activate Display and set State Matrices
|
84 |
+
void ActivateAndScissor(const OpenGlRenderState& state ) const;
|
85 |
+
|
86 |
+
//! Activate Display and set State Matrices
|
87 |
+
void ActivateScissorAndClear(const OpenGlRenderState& state ) const;
|
88 |
+
|
89 |
+
//! Activate Display and setup coordinate system for 2d pixel View coordinates
|
90 |
+
void ActivatePixelOrthographic() const;
|
91 |
+
|
92 |
+
//! Activate Display and reset coordinate system to OpenGL default
|
93 |
+
void ActivateIdentity() const;
|
94 |
+
|
95 |
+
//! Return closest depth buffer value within radius of window (winx,winy)
|
96 |
+
GLfloat GetClosestDepth(int winx, int winy, int radius) const;
|
97 |
+
|
98 |
+
//! Obtain camera space coordinates of scene at pixel (winx, winy, winzdepth)
|
99 |
+
//! winzdepth can be obtained from GetClosestDepth
|
100 |
+
void GetCamCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const;
|
101 |
+
|
102 |
+
//! Obtain object space coordinates of scene at pixel (winx, winy, winzdepth)
|
103 |
+
//! winzdepth can be obtained from GetClosestDepth
|
104 |
+
void GetObjectCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const;
|
105 |
+
|
106 |
+
//! Given the specification of Display, compute viewport
|
107 |
+
virtual void Resize(const Viewport& parent);
|
108 |
+
|
109 |
+
//! Instruct all children to resize
|
110 |
+
virtual void ResizeChildren();
|
111 |
+
|
112 |
+
//! Perform any automatic rendering for this View.
|
113 |
+
//! Default implementation simply instructs children to render themselves.
|
114 |
+
virtual void Render();
|
115 |
+
|
116 |
+
//! Instruct all children to render themselves if appropriate
|
117 |
+
virtual void RenderChildren();
|
118 |
+
|
119 |
+
//! Set this view as the active View to receive input
|
120 |
+
View& SetFocus();
|
121 |
+
|
122 |
+
//! Returns true iff this view currently has focus and will receive user input
|
123 |
+
bool HasFocus() const;
|
124 |
+
|
125 |
+
//! Set bounds for the View using mixed fractional / pixel coordinates (OpenGl view coordinates)
|
126 |
+
View& SetBounds(Attach bottom, Attach top, Attach left, Attach right);
|
127 |
+
|
128 |
+
//! Set bounds for the View using mixed fractional / pixel coordinates (OpenGl view coordinates)
|
129 |
+
View& SetBounds(Attach bottom, Attach top, Attach left, Attach right, bool keep_aspect);
|
130 |
+
|
131 |
+
//! Set bounds for the View using mixed fractional / pixel coordinates (OpenGl view coordinates)
|
132 |
+
View& SetBounds(Attach bottom, Attach top, Attach left, Attach right, double aspect);
|
133 |
+
|
134 |
+
//! Designate handler for accepting mouse / keyboard input.
|
135 |
+
View& SetHandler(Handler* handler);
|
136 |
+
|
137 |
+
//! Set drawFunc as the drawing function for this view
|
138 |
+
View& SetDrawFunction(const std::function<void(View&)>& drawFunc);
|
139 |
+
|
140 |
+
//! Force this view to have the given aspect, whilst fitting snuggly
|
141 |
+
//! within the parent. A negative value with 'over-draw', fitting the
|
142 |
+
//! smaller side of the parent.
|
143 |
+
View& SetAspect(double aspect);
|
144 |
+
|
145 |
+
//! Set how this view should be positioned relative to its parent
|
146 |
+
View& SetLock(Lock horizontal, Lock vertical );
|
147 |
+
|
148 |
+
//! Set layout policy for this view
|
149 |
+
View& SetLayout(Layout layout);
|
150 |
+
|
151 |
+
//! Add view as child
|
152 |
+
View& AddDisplay(View& view);
|
153 |
+
|
154 |
+
//! Show / hide this view
|
155 |
+
View& Show(bool show=true);
|
156 |
+
|
157 |
+
//! Toggle this views visibility
|
158 |
+
void ToggleShow();
|
159 |
+
|
160 |
+
//! Return whether this view should be shown.
|
161 |
+
//! This method should be checked if drawing manually
|
162 |
+
bool IsShown() const;
|
163 |
+
|
164 |
+
//! Returns viewport reflecting space that will actually get drawn
|
165 |
+
//! The minimum of vp and v
|
166 |
+
Viewport GetBounds() const;
|
167 |
+
|
168 |
+
//! Return number of child views attached to this view
|
169 |
+
size_t NumChildren() const;
|
170 |
+
|
171 |
+
//! Return (i)th child of this view
|
172 |
+
View& operator[](size_t i);
|
173 |
+
|
174 |
+
//! Return number of visible child views attached to this view.
|
175 |
+
size_t NumVisibleChildren() const;
|
176 |
+
|
177 |
+
//! Return visible child by index.
|
178 |
+
View& VisibleChild(size_t i);
|
179 |
+
|
180 |
+
//! Return visible child at window coords x,y
|
181 |
+
View* FindChild(int x, int y);
|
182 |
+
|
183 |
+
// Desired width / height aspect (0 if dynamic)
|
184 |
+
double aspect;
|
185 |
+
|
186 |
+
// Bounds to fit display within
|
187 |
+
Attach top, left, right, bottom;
|
188 |
+
Lock hlock;
|
189 |
+
Lock vlock;
|
190 |
+
Layout layout;
|
191 |
+
|
192 |
+
int scroll_offset;
|
193 |
+
|
194 |
+
// Cached client area (space allocated from parent)
|
195 |
+
Viewport vp;
|
196 |
+
|
197 |
+
// Cached absolute viewport (recomputed on resize - respects aspect)
|
198 |
+
Viewport v;
|
199 |
+
|
200 |
+
// Should this view be displayed?
|
201 |
+
bool show;
|
202 |
+
|
203 |
+
// Child views are rendered in order of low to high z-order
|
204 |
+
// Views default to 0 z-order
|
205 |
+
int zorder;
|
206 |
+
|
207 |
+
// Input event handler (if any)
|
208 |
+
Handler* handler;
|
209 |
+
|
210 |
+
// Map for sub-displays (if any)
|
211 |
+
std::vector<View*> views;
|
212 |
+
|
213 |
+
// External draw function
|
214 |
+
std::function<void(View&)> extern_draw_function;
|
215 |
+
|
216 |
+
////////////////////////////////////////////////
|
217 |
+
|
218 |
+
PANGOLIN_DEPRECATED("Use pangolin::SaveWindowOnRender(...) instead.")
|
219 |
+
void SaveOnRender(const std::string& filename_hint);
|
220 |
+
|
221 |
+
PANGOLIN_DEPRECATED("Use pangolin::SaveWindowNow(...) instead.")
|
222 |
+
void SaveRenderNow(const std::string& filename_hint);
|
223 |
+
|
224 |
+
private:
|
225 |
+
// Private copy constructor
|
226 |
+
View(View&) { /* Do Not copy - take reference instead*/ }
|
227 |
+
|
228 |
+
bool scroll_show;
|
229 |
+
};
|
230 |
+
|
231 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/display/widgets.h
ADDED
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <pangolin/display/view.h>
|
31 |
+
#include <pangolin/var/var.h>
|
32 |
+
#include <pangolin/handler/handler.h>
|
33 |
+
#include <pangolin/gl/glfont.h>
|
34 |
+
|
35 |
+
#include <functional>
|
36 |
+
|
37 |
+
namespace pangolin
|
38 |
+
{
|
39 |
+
|
40 |
+
PANGOLIN_EXPORT
|
41 |
+
View& CreatePanel(const std::string& name);
|
42 |
+
|
43 |
+
struct PANGOLIN_EXPORT Panel : public View
|
44 |
+
{
|
45 |
+
Panel();
|
46 |
+
Panel(const std::string& auto_register_var_prefix);
|
47 |
+
void Render();
|
48 |
+
void ResizeChildren();
|
49 |
+
|
50 |
+
private:
|
51 |
+
void NewVarCallback(const VarState::Event& e);
|
52 |
+
void AddVariable(const std::string& name, const std::shared_ptr<VarValueGeneric> &var);
|
53 |
+
void RemoveVariable(const std::string& name);
|
54 |
+
|
55 |
+
sigslot::scoped_connection var_added_connection;
|
56 |
+
std::string auto_register_var_prefix;
|
57 |
+
};
|
58 |
+
|
59 |
+
template<typename T>
|
60 |
+
struct Widget : public View, Handler, Var<T>
|
61 |
+
{
|
62 |
+
Widget(std::string title, const std::shared_ptr<VarValueGeneric>& tv)
|
63 |
+
: Var<T>(tv), title(title)
|
64 |
+
{
|
65 |
+
handler = this;
|
66 |
+
}
|
67 |
+
|
68 |
+
std::string title;
|
69 |
+
};
|
70 |
+
|
71 |
+
struct PANGOLIN_EXPORT Button : public Widget<bool>
|
72 |
+
{
|
73 |
+
Button(std::string title, const std::shared_ptr<VarValueGeneric> &tv);
|
74 |
+
void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state);
|
75 |
+
void Render();
|
76 |
+
|
77 |
+
//Cache params on resize
|
78 |
+
void ResizeChildren();
|
79 |
+
GlText gltext;
|
80 |
+
GLfloat raster[2];
|
81 |
+
bool down;
|
82 |
+
};
|
83 |
+
|
84 |
+
struct PANGOLIN_EXPORT FunctionButton : public Widget<std::function<void(void)> >
|
85 |
+
{
|
86 |
+
FunctionButton(std::string title, const std::shared_ptr<VarValueGeneric> &tv);
|
87 |
+
void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state);
|
88 |
+
void Render();
|
89 |
+
|
90 |
+
//Cache params on resize
|
91 |
+
void ResizeChildren();
|
92 |
+
GlText gltext;
|
93 |
+
GLfloat raster[2];
|
94 |
+
bool down;
|
95 |
+
};
|
96 |
+
|
97 |
+
struct PANGOLIN_EXPORT Checkbox : public Widget<bool>
|
98 |
+
{
|
99 |
+
Checkbox(std::string title, const std::shared_ptr<VarValueGeneric>& tv);
|
100 |
+
void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state);
|
101 |
+
void Render();
|
102 |
+
|
103 |
+
//Cache params on resize
|
104 |
+
void ResizeChildren();
|
105 |
+
GlText gltext;
|
106 |
+
GLfloat raster[2];
|
107 |
+
Viewport vcb;
|
108 |
+
};
|
109 |
+
|
110 |
+
struct PANGOLIN_EXPORT Slider : public Widget<double>
|
111 |
+
{
|
112 |
+
Slider(std::string title, const std::shared_ptr<VarValueGeneric>& tv);
|
113 |
+
void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state);
|
114 |
+
void MouseMotion(View&, int x, int y, int mouse_state);
|
115 |
+
void Keyboard(View&, unsigned char key, int x, int y, bool pressed);
|
116 |
+
void Render();
|
117 |
+
|
118 |
+
//Cache params on resize
|
119 |
+
void ResizeChildren();
|
120 |
+
GlText gltext;
|
121 |
+
GLfloat raster[2];
|
122 |
+
bool lock_bounds;
|
123 |
+
bool logscale;
|
124 |
+
bool is_integral_type;
|
125 |
+
};
|
126 |
+
|
127 |
+
struct PANGOLIN_EXPORT TextInput : public Widget<std::string>
|
128 |
+
{
|
129 |
+
TextInput(std::string title, const std::shared_ptr<VarValueGeneric>& tv);
|
130 |
+
void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state);
|
131 |
+
void MouseMotion(View&, int x, int y, int mouse_state);
|
132 |
+
void Keyboard(View&, unsigned char key, int x, int y, bool pressed);
|
133 |
+
void Render();
|
134 |
+
|
135 |
+
std::string edit;
|
136 |
+
GlText gledit;
|
137 |
+
|
138 |
+
//Cache params on resize
|
139 |
+
void ResizeChildren();
|
140 |
+
void CalcVisibleEditPart();
|
141 |
+
GlText gltext;
|
142 |
+
bool can_edit;
|
143 |
+
bool do_edit;
|
144 |
+
int sel[2];
|
145 |
+
GLfloat vertical_margin;
|
146 |
+
GLfloat horizontal_margin = 2.f;
|
147 |
+
int input_width;
|
148 |
+
int edit_visible_part[2] = {0,1};
|
149 |
+
};
|
150 |
+
|
151 |
+
|
152 |
+
inline bool GuiVarHasChanged() {
|
153 |
+
Var<bool> changed("pango.widgets.gui_changed");
|
154 |
+
return bool(changed) && !(changed = false);
|
155 |
+
}
|
156 |
+
|
157 |
+
inline void FlagVarChanged() {
|
158 |
+
Var<bool>("pango.widgets.gui_changed") = true;
|
159 |
+
}
|
160 |
+
|
161 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/handler/handler.h
ADDED
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2013 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <pangolin/gl/opengl_render_state.h>
|
31 |
+
#include <pangolin/gl/gl.h>
|
32 |
+
#include <pangolin/windowing/handler_enums.h>
|
33 |
+
|
34 |
+
#if defined(HAVE_EIGEN) && !defined(__CUDACC__) //prevent including Eigen in cuda files
|
35 |
+
#define USE_EIGEN
|
36 |
+
#endif
|
37 |
+
|
38 |
+
#ifdef USE_EIGEN
|
39 |
+
#include <Eigen/Core>
|
40 |
+
#endif
|
41 |
+
|
42 |
+
#ifdef _OSX_
|
43 |
+
#define PANGO_DFLT_HANDLER3D_ZF (1.0f/50.0f)
|
44 |
+
#else
|
45 |
+
#define PANGO_DFLT_HANDLER3D_ZF (1.0f/10.0f)
|
46 |
+
#endif
|
47 |
+
|
48 |
+
namespace pangolin
|
49 |
+
{
|
50 |
+
|
51 |
+
// Forward declarations
|
52 |
+
struct View;
|
53 |
+
|
54 |
+
/// Input Handler base class.
|
55 |
+
/// Virtual methods which recurse into sub-displays.
|
56 |
+
struct PANGOLIN_EXPORT Handler
|
57 |
+
{
|
58 |
+
virtual ~Handler() {}
|
59 |
+
virtual void Keyboard(View&, unsigned char key, int x, int y, bool pressed);
|
60 |
+
virtual void Mouse(View&, MouseButton button, int x, int y, bool pressed, int button_state);
|
61 |
+
virtual void MouseMotion(View&, int x, int y, int button_state);
|
62 |
+
virtual void PassiveMouseMotion(View&, int x, int y, int button_state);
|
63 |
+
virtual void Special(View&, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state);
|
64 |
+
};
|
65 |
+
|
66 |
+
struct PANGOLIN_EXPORT HandlerScroll : Handler
|
67 |
+
{
|
68 |
+
void Mouse(View&, MouseButton button, int x, int y, bool pressed, int button_state);
|
69 |
+
void Special(View&, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state);
|
70 |
+
};
|
71 |
+
|
72 |
+
struct PANGOLIN_EXPORT HandlerBase3D : Handler
|
73 |
+
{
|
74 |
+
HandlerBase3D(OpenGlRenderState& cam_state, AxisDirection enforce_up=AxisNone, float trans_scale=0.01f, float zoom_fraction= PANGO_DFLT_HANDLER3D_ZF);
|
75 |
+
|
76 |
+
virtual bool ValidWinDepth(GLprecision depth);
|
77 |
+
virtual void PixelUnproject( View& view, GLprecision winx, GLprecision winy, GLprecision winz, GLprecision Pc[3]);
|
78 |
+
virtual void GetPosNormal(View& view, int x, int y, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision nw[3], GLprecision default_z = 1.0);
|
79 |
+
virtual void GetPosNormalImpl(View& view, int x, int y, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision nw[3], GLprecision default_z, float *zs);
|
80 |
+
|
81 |
+
void Keyboard(View&, unsigned char key, int x, int y, bool pressed);
|
82 |
+
void Mouse(View&, MouseButton button, int x, int y, bool pressed, int button_state);
|
83 |
+
void MouseMotion(View&, int x, int y, int button_state);
|
84 |
+
void Special(View&, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state);
|
85 |
+
|
86 |
+
#ifdef USE_EIGEN
|
87 |
+
// Return selected point in world coordinates
|
88 |
+
inline Eigen::Vector3d Selected_P_w() const {
|
89 |
+
return Eigen::Map<const Eigen::Matrix<GLprecision,3,1>>(Pw).cast<double>();
|
90 |
+
}
|
91 |
+
#endif
|
92 |
+
inline int KeyState() const{
|
93 |
+
return funcKeyState;
|
94 |
+
}
|
95 |
+
|
96 |
+
protected:
|
97 |
+
OpenGlRenderState* cam_state;
|
98 |
+
const static int hwin = 8;
|
99 |
+
AxisDirection enforce_up;
|
100 |
+
float tf; // translation factor
|
101 |
+
float zf; // zoom fraction
|
102 |
+
CameraSpec cameraspec;
|
103 |
+
GLprecision last_z;
|
104 |
+
float last_pos[2];
|
105 |
+
GLprecision rot_center[3];
|
106 |
+
|
107 |
+
GLprecision p[3];
|
108 |
+
GLprecision Pw[3];
|
109 |
+
GLprecision Pc[3];
|
110 |
+
GLprecision n[3];
|
111 |
+
|
112 |
+
int funcKeyState;
|
113 |
+
};
|
114 |
+
|
115 |
+
#ifndef HAVE_GLES
|
116 |
+
using Handler3D = HandlerBase3D;
|
117 |
+
#else
|
118 |
+
struct PANGOLIN_EXPORT Handler3DBlitCopy : public pangolin::HandlerBase3D
|
119 |
+
{
|
120 |
+
Handler3DBlitCopy(pangolin::OpenGlRenderState& cam_state, pangolin::AxisDirection enforce_up=pangolin::AxisNone, float trans_scale=0.01f);
|
121 |
+
void GetPosNormal(pangolin::View& view, int x, int y, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision /*n*/[3], GLprecision default_z = 1.0);
|
122 |
+
|
123 |
+
protected:
|
124 |
+
GlTexture rgb_blit;
|
125 |
+
GlTexture depth_blit;
|
126 |
+
GlFramebuffer fb_blit;
|
127 |
+
|
128 |
+
GlTexture rgb;
|
129 |
+
GlTexture depth;
|
130 |
+
GlFramebuffer fb;
|
131 |
+
};
|
132 |
+
using Handler3D = Handler3DBlitCopy;
|
133 |
+
#endif
|
134 |
+
|
135 |
+
|
136 |
+
static Handler StaticHandler;
|
137 |
+
static HandlerScroll StaticHandlerScroll;
|
138 |
+
|
139 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/handler/handler_glbuffer.h
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2014 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#ifndef HANDLER_GLBUFFER_H
|
29 |
+
#define HANDLER_GLBUFFER_H
|
30 |
+
|
31 |
+
#include <pangolin/handler/handler.h>
|
32 |
+
#include <pangolin/gl/gl.h>
|
33 |
+
|
34 |
+
namespace pangolin
|
35 |
+
{
|
36 |
+
|
37 |
+
struct PANGOLIN_EXPORT Handler3DFramebuffer : public pangolin::HandlerBase3D
|
38 |
+
{
|
39 |
+
Handler3DFramebuffer(GlFramebuffer& fb, pangolin::OpenGlRenderState& cam_state, pangolin::AxisDirection enforce_up=pangolin::AxisNone, float trans_scale=0.01f);
|
40 |
+
void GetPosNormal(pangolin::View& view, int x, int y, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision /*n*/[3], GLprecision default_z);
|
41 |
+
|
42 |
+
protected:
|
43 |
+
GlFramebuffer& fb;
|
44 |
+
};
|
45 |
+
|
46 |
+
}
|
47 |
+
|
48 |
+
#endif // HANDLER_GLBUFFER_H
|
third-party/DPVO/Pangolin/components/pango_display/include/pangolin/handler/handler_image.h
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2013 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <pangolin/image/image_utils.h>
|
31 |
+
#include <pangolin/display/view.h>
|
32 |
+
#include <pangolin/handler/handler.h>
|
33 |
+
#include <pangolin/gl/viewport.h>
|
34 |
+
#include <pangolin/gl/gl.h>
|
35 |
+
#include <pangolin/utils/range.h>
|
36 |
+
|
37 |
+
#include <functional>
|
38 |
+
|
39 |
+
namespace pangolin
|
40 |
+
{
|
41 |
+
|
42 |
+
class PANGOLIN_EXPORT ImageViewHandler : public Handler
|
43 |
+
{
|
44 |
+
public:
|
45 |
+
struct EventData {
|
46 |
+
EventData(View& v, ImageViewHandler& h) : view(v), handler(h) {}
|
47 |
+
View& view;
|
48 |
+
ImageViewHandler& handler;
|
49 |
+
};
|
50 |
+
|
51 |
+
struct OnSelectionEventData : public EventData {
|
52 |
+
OnSelectionEventData(View& v, ImageViewHandler& h, bool dragging)
|
53 |
+
: EventData(v,h), dragging(dragging) {}
|
54 |
+
bool dragging;
|
55 |
+
};
|
56 |
+
|
57 |
+
typedef std::function<void(OnSelectionEventData)> OnSelectionCallbackFn;
|
58 |
+
|
59 |
+
// Default constructor: User must call SetDimensions() once image dimensions are known.
|
60 |
+
// Default range is [0,1] in x and y.
|
61 |
+
ImageViewHandler(const std::string & title = "");
|
62 |
+
|
63 |
+
// View ranges store extremes of image (boundary of pixels)
|
64 |
+
// in 'discrete' coords, where 0,0 is center of top-left pixel.
|
65 |
+
ImageViewHandler(size_t w, size_t h);
|
66 |
+
|
67 |
+
void SetDimensions(size_t w, size_t h);
|
68 |
+
|
69 |
+
void UpdateView();
|
70 |
+
|
71 |
+
void glSetViewOrtho();
|
72 |
+
|
73 |
+
void glRenderTexture(pangolin::GlTexture& tex);
|
74 |
+
void glRenderTexture(GLuint tex, GLint width, GLint height);
|
75 |
+
void glRenderTexture(GLuint tex, GLint width, GLint height, XYRangef tex_region);
|
76 |
+
|
77 |
+
|
78 |
+
void glRenderOverlay();
|
79 |
+
|
80 |
+
void ScreenToImage(Viewport& v, float xpix, float ypix, float& ximg, float& yimg);
|
81 |
+
|
82 |
+
void ImageToScreen(Viewport& v, float ximg, float yimg, float& xpix, float& ypix);
|
83 |
+
|
84 |
+
bool UseNN() const;
|
85 |
+
|
86 |
+
bool& UseNN();
|
87 |
+
|
88 |
+
bool& FlipTextureX();
|
89 |
+
|
90 |
+
bool& FlipTextureY();
|
91 |
+
|
92 |
+
pangolin::XYRangef& GetViewToRender();
|
93 |
+
|
94 |
+
float GetViewScale();
|
95 |
+
|
96 |
+
pangolin::XYRangef& GetView();
|
97 |
+
|
98 |
+
pangolin::XYRangef& GetDefaultView();
|
99 |
+
|
100 |
+
pangolin::XYRangef& GetSelection();
|
101 |
+
|
102 |
+
void GetHover(float& x, float& y);
|
103 |
+
|
104 |
+
void SetView(const pangolin::XYRangef& range);
|
105 |
+
|
106 |
+
void SetViewSmooth(const pangolin::XYRangef& range);
|
107 |
+
|
108 |
+
void ScrollView(float x, float y);
|
109 |
+
|
110 |
+
void ScrollViewSmooth(float x, float y);
|
111 |
+
|
112 |
+
void ScaleView(float x, float y, float cx, float cy);
|
113 |
+
|
114 |
+
void ScaleViewSmooth(float x, float y, float cx, float cy);
|
115 |
+
|
116 |
+
void ResetView();
|
117 |
+
|
118 |
+
///////////////////////////////////////////////////////
|
119 |
+
/// pangolin::Handler
|
120 |
+
///////////////////////////////////////////////////////
|
121 |
+
|
122 |
+
void Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed) override;
|
123 |
+
|
124 |
+
void Mouse(View& view, pangolin::MouseButton button, int x, int y, bool pressed, int button_state) override;
|
125 |
+
|
126 |
+
void MouseMotion(View& view, int x, int y, int button_state) override;
|
127 |
+
|
128 |
+
void PassiveMouseMotion(View&, int /*x*/, int /*y*/, int /*button_state*/) override;
|
129 |
+
|
130 |
+
void Special(View& view, pangolin::InputSpecial inType, float x, float y, float p1, float p2, float /*p3*/, float /*p4*/, int /*button_state*/) override;
|
131 |
+
|
132 |
+
///////////////////////////////////////////////////////
|
133 |
+
/// Callbacks
|
134 |
+
///////////////////////////////////////////////////////
|
135 |
+
|
136 |
+
OnSelectionCallbackFn OnSelectionCallback;
|
137 |
+
|
138 |
+
protected:
|
139 |
+
void FixSelection(XYRangef& sel);
|
140 |
+
|
141 |
+
void AdjustScale();
|
142 |
+
|
143 |
+
void AdjustTranslation();
|
144 |
+
|
145 |
+
static ImageViewHandler* to_link;
|
146 |
+
static float animate_factor;
|
147 |
+
|
148 |
+
ImageViewHandler* linked_view_handler;
|
149 |
+
|
150 |
+
pangolin::XYRangef rview_default;
|
151 |
+
pangolin::XYRangef rview_max;
|
152 |
+
pangolin::XYRangef rview;
|
153 |
+
pangolin::XYRangef target;
|
154 |
+
pangolin::XYRangef selection;
|
155 |
+
|
156 |
+
float hover_img[2];
|
157 |
+
int last_mouse_pos[2];
|
158 |
+
|
159 |
+
bool use_nn;
|
160 |
+
bool flipTextureX;
|
161 |
+
bool flipTextureY;
|
162 |
+
std::string title;
|
163 |
+
|
164 |
+
};
|
165 |
+
|
166 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/ConsoleView.cpp
ADDED
@@ -0,0 +1,327 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <iterator>
|
2 |
+
#include <pangolin/console/ConsoleView.h>
|
3 |
+
#include <pangolin/utils/picojson.h>
|
4 |
+
#include <pangolin/gl/gldraw.h>
|
5 |
+
#include <pangolin/display/default_font.h>
|
6 |
+
|
7 |
+
namespace pangolin
|
8 |
+
{
|
9 |
+
|
10 |
+
inline Colour ParseJson(const picojson::value& val)
|
11 |
+
{
|
12 |
+
return Colour(
|
13 |
+
val.contains("r") ? val["r"].get<double>() : 0.0,
|
14 |
+
val.contains("g") ? val["g"].get<double>() : 0.0,
|
15 |
+
val.contains("b") ? val["b"].get<double>() : 0.0,
|
16 |
+
val.contains("a") ? val["a"].get<double>() : 1.0
|
17 |
+
);
|
18 |
+
}
|
19 |
+
|
20 |
+
inline picojson::value toJson(const Colour& colour)
|
21 |
+
{
|
22 |
+
picojson::value ret(picojson::object_type,true);
|
23 |
+
ret["r"] = colour.r;
|
24 |
+
ret["g"] = colour.g;
|
25 |
+
ret["b"] = colour.b;
|
26 |
+
ret["a"] = colour.a;
|
27 |
+
return ret;
|
28 |
+
}
|
29 |
+
|
30 |
+
inline std::ostream& operator<<(std::ostream& os, const Colour& colour)
|
31 |
+
{
|
32 |
+
os << toJson(colour).serialize();
|
33 |
+
return os;
|
34 |
+
}
|
35 |
+
|
36 |
+
inline std::istream& operator>>(std::istream& is, Colour& colour)
|
37 |
+
{
|
38 |
+
picojson::value val;
|
39 |
+
picojson::parse(val,is);
|
40 |
+
colour = ParseJson(val);
|
41 |
+
return is;
|
42 |
+
}
|
43 |
+
|
44 |
+
inline void glColour(const Colour& c)
|
45 |
+
{
|
46 |
+
glColor4f(c.r,c.g,c.b,c.a);
|
47 |
+
}
|
48 |
+
|
49 |
+
ConsoleView::ConsoleView(const std::shared_ptr<InterpreterInterface> &interpreter)
|
50 |
+
: interpreter(interpreter),
|
51 |
+
font(default_font()),
|
52 |
+
carat(0),
|
53 |
+
hiding(false),
|
54 |
+
bottom(1.0f),
|
55 |
+
background_colour(0.2f, 0.0f, 0.0f, 0.6f),
|
56 |
+
animation_speed(0.2)
|
57 |
+
{
|
58 |
+
SetHandler(this);
|
59 |
+
|
60 |
+
line_colours[ConsoleLineTypeCmd] = Colour(1.0f,1.0f,1.0f,1.0f);
|
61 |
+
line_colours[ConsoleLineTypeCmdOptions] = Colour(0.9f,0.9f,0.9f,1.0f);
|
62 |
+
line_colours[ConsoleLineTypeOutput] = Colour(0.0f,1.0f,1.0f,1.0f);
|
63 |
+
line_colours[ConsoleLineTypeHelp] = Colour(1.0f,0.8f,1.0f,1.0f);
|
64 |
+
line_colours[ConsoleLineTypeStdout] = Colour(0.0f,0.0f,1.0f,1.0f);
|
65 |
+
line_colours[ConsoleLineTypeStderr] = Colour(1.0f,0.8f,0.8f,1.0f);
|
66 |
+
|
67 |
+
Var<Colour>::Attach("pango.console.colours.Background", background_colour);
|
68 |
+
Var<Colour>::Attach("pango.console.colours.Cmd", line_colours[ConsoleLineTypeCmd]);
|
69 |
+
Var<Colour>::Attach("pango.console.colours.CmdOptions", line_colours[ConsoleLineTypeCmdOptions]);
|
70 |
+
Var<Colour>::Attach("pango.console.colours.Stdout", line_colours[ConsoleLineTypeStdout]);
|
71 |
+
Var<Colour>::Attach("pango.console.colours.Stderr", line_colours[ConsoleLineTypeStderr]);
|
72 |
+
Var<Colour>::Attach("pango.console.colours.Output", line_colours[ConsoleLineTypeOutput]);
|
73 |
+
Var<Colour>::Attach("pango.console.colours.Help", line_colours[ConsoleLineTypeHelp]);
|
74 |
+
|
75 |
+
Var<float>::Attach("pango.console.animation_speed", animation_speed);
|
76 |
+
|
77 |
+
AddLine("Pangolin Console:", ConsoleLineTypeHelp);
|
78 |
+
AddLine("===============================", ConsoleLineTypeHelp);
|
79 |
+
}
|
80 |
+
|
81 |
+
ConsoleView::~ConsoleView() {
|
82 |
+
}
|
83 |
+
|
84 |
+
void ConsoleView::ProcessOutputLines()
|
85 |
+
{
|
86 |
+
// empty output queue
|
87 |
+
InterpreterLine line_in;
|
88 |
+
while(interpreter->PullLine(line_in))
|
89 |
+
{
|
90 |
+
AddLine(line_in.text, line_in.linetype);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
View& ConsoleView::ShowWithoutAnimation(bool should_show){
|
95 |
+
Show(should_show);
|
96 |
+
bottom = show ? 1.0 : 0.0;
|
97 |
+
return *this;
|
98 |
+
}
|
99 |
+
|
100 |
+
View& ConsoleView::Show(bool should_show)
|
101 |
+
{
|
102 |
+
if(should_show) {
|
103 |
+
hiding = false;
|
104 |
+
show = true;
|
105 |
+
}else{
|
106 |
+
hiding = true;
|
107 |
+
}
|
108 |
+
return *this;
|
109 |
+
}
|
110 |
+
|
111 |
+
void ConsoleView::ToggleShow()
|
112 |
+
{
|
113 |
+
Show(!IsShown());
|
114 |
+
}
|
115 |
+
|
116 |
+
bool ConsoleView::IsShown() const
|
117 |
+
{
|
118 |
+
return show && !hiding;
|
119 |
+
}
|
120 |
+
|
121 |
+
void ConsoleView::DrawLine(const ConsoleView::Line& l, int carat=-1)
|
122 |
+
{
|
123 |
+
glColour(line_colours[l.linetype]);
|
124 |
+
l.text.Draw();
|
125 |
+
if(carat >= 0) {
|
126 |
+
const double w = font.Text(l.text.str.substr(0,carat)).Width();
|
127 |
+
glDrawLine(w,-2,w,font.Height()-4);
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
void ConsoleView::Render()
|
132 |
+
{
|
133 |
+
if(hiding) {
|
134 |
+
bottom += (1.0f - bottom) * animation_speed;
|
135 |
+
if(1.0 - bottom < 0.01) {
|
136 |
+
bottom = 1.0;
|
137 |
+
show = false;
|
138 |
+
hiding = false;
|
139 |
+
return;
|
140 |
+
}
|
141 |
+
}else{
|
142 |
+
if(bottom > 0.01f) {
|
143 |
+
bottom -= bottom*animation_speed;
|
144 |
+
}else{
|
145 |
+
bottom = 0.0f;
|
146 |
+
}
|
147 |
+
}
|
148 |
+
|
149 |
+
ProcessOutputLines();
|
150 |
+
|
151 |
+
#ifndef HAVE_GLES
|
152 |
+
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT | GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
|
153 |
+
#endif
|
154 |
+
|
155 |
+
this->ActivatePixelOrthographic();
|
156 |
+
glDisable(GL_DEPTH_TEST );
|
157 |
+
glDisable(GL_LIGHTING);
|
158 |
+
glDisable(GL_SCISSOR_TEST);
|
159 |
+
glDisable(GL_LINE_SMOOTH);
|
160 |
+
glDisable( GL_COLOR_MATERIAL );
|
161 |
+
glLineWidth(1.0);
|
162 |
+
|
163 |
+
glEnable(GL_BLEND);
|
164 |
+
glBlendFunc( GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA );
|
165 |
+
|
166 |
+
glColour(background_colour);
|
167 |
+
|
168 |
+
GLfloat verts[] = { 0.0f, (GLfloat)v.h,
|
169 |
+
(GLfloat)v.w, (GLfloat)v.h,
|
170 |
+
(GLfloat)v.w, bottom*v.h,
|
171 |
+
0.0f, bottom*v.h };
|
172 |
+
glEnableClientState(GL_VERTEX_ARRAY);
|
173 |
+
glVertexPointer(2, GL_FLOAT, 0, verts);
|
174 |
+
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
175 |
+
glDisableClientState(GL_VERTEX_ARRAY);
|
176 |
+
|
177 |
+
|
178 |
+
const GLfloat line_space = font.Height();
|
179 |
+
glTranslatef(10.0f, 10.0f + bottom*v.h, 0.0f );
|
180 |
+
DrawLine(current_line, carat);
|
181 |
+
glTranslatef(0.0f, line_space, 0.0f);
|
182 |
+
for(size_t l=0; l < line_buffer.size(); ++l) {
|
183 |
+
DrawLine(line_buffer[l]);
|
184 |
+
glTranslatef(0.0f, line_space, 0.0f);
|
185 |
+
}
|
186 |
+
|
187 |
+
#ifndef HAVE_GLES
|
188 |
+
glPopAttrib();
|
189 |
+
#endif
|
190 |
+
}
|
191 |
+
|
192 |
+
inline std::string CommonPrefix(const std::vector<std::string>& vec)
|
193 |
+
{
|
194 |
+
if(!vec.size()) return "";
|
195 |
+
|
196 |
+
size_t cmn = vec[0].size();
|
197 |
+
for(size_t i=1; i<vec.size(); ++i) {
|
198 |
+
cmn = std::min(vec[i].size(), cmn);
|
199 |
+
for(size_t p=0; p < cmn; ++p) {
|
200 |
+
if(vec[i][p] != vec[0][p]) {
|
201 |
+
cmn = p;
|
202 |
+
break;
|
203 |
+
}
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
return vec[0].substr(0,cmn);
|
208 |
+
}
|
209 |
+
|
210 |
+
void ConsoleView::Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed)
|
211 |
+
{
|
212 |
+
static int hist_id = -1;
|
213 |
+
static std::string prefix;
|
214 |
+
static bool edited = true;
|
215 |
+
|
216 |
+
if(pressed) {
|
217 |
+
if(key=='\r') key = '\n';
|
218 |
+
|
219 |
+
GlText& txt = current_line.text;
|
220 |
+
const std::string cmd = txt.Text();
|
221 |
+
|
222 |
+
if(key=='`') {
|
223 |
+
ToggleShow();
|
224 |
+
} else if(key=='\n') {
|
225 |
+
interpreter->PushCommand(cmd);
|
226 |
+
line_buffer.push_front(current_line);
|
227 |
+
hist_id = -1;
|
228 |
+
prefix = "";
|
229 |
+
edited = true;
|
230 |
+
carat = 0;
|
231 |
+
txt.Clear();
|
232 |
+
}else if(key=='\t') {
|
233 |
+
std::vector<std::string> options = interpreter->Complete(cmd,100);
|
234 |
+
if(options.size()) {
|
235 |
+
const std::string common = CommonPrefix(options);
|
236 |
+
if(common.size() > cmd.size()) {
|
237 |
+
current_line = font.Text("%s", common.c_str());
|
238 |
+
carat = common.size();
|
239 |
+
}else{
|
240 |
+
std::stringstream s;
|
241 |
+
std::copy(options.begin(), options.end(), std::ostream_iterator<std::string>(s,", "));
|
242 |
+
AddLine(s.str(), ConsoleLineTypeCmdOptions);
|
243 |
+
}
|
244 |
+
}
|
245 |
+
}else if(key==PANGO_SPECIAL + PANGO_KEY_UP) {
|
246 |
+
if(edited) {
|
247 |
+
prefix = cmd;
|
248 |
+
edited = false;
|
249 |
+
}
|
250 |
+
Line* hist_line = GetLine(hist_id+1, ConsoleLineTypeCmd, prefix);
|
251 |
+
if(hist_line) {
|
252 |
+
current_line = *hist_line;
|
253 |
+
hist_id++;
|
254 |
+
}
|
255 |
+
}else if(key==PANGO_SPECIAL + PANGO_KEY_DOWN) {
|
256 |
+
if(edited) {
|
257 |
+
prefix = cmd;
|
258 |
+
edited = false;
|
259 |
+
}
|
260 |
+
Line* hist_line = GetLine(hist_id-1, ConsoleLineTypeCmd, prefix);
|
261 |
+
if(hist_line) {
|
262 |
+
current_line = *hist_line;
|
263 |
+
hist_id--;
|
264 |
+
}
|
265 |
+
}else if(key==PANGO_SPECIAL + PANGO_KEY_LEFT) {
|
266 |
+
if(carat > 0) carat--;
|
267 |
+
}else if(key==PANGO_SPECIAL + PANGO_KEY_RIGHT) {
|
268 |
+
if(carat < (int)txt.str.size()) carat++;
|
269 |
+
}else if(key==PANGO_SPECIAL + PANGO_KEY_HOME) {
|
270 |
+
carat = 0;
|
271 |
+
}else if(key==PANGO_SPECIAL + PANGO_KEY_END) {
|
272 |
+
carat = txt.Text().size();
|
273 |
+
}else if(key=='\b') {
|
274 |
+
if(carat > 0) {
|
275 |
+
std::string newstr = txt.Text();
|
276 |
+
newstr.erase(newstr.begin()+carat-1);
|
277 |
+
txt = font.Text("%s", newstr.c_str() );
|
278 |
+
carat--;
|
279 |
+
edited = true;
|
280 |
+
}
|
281 |
+
}else if(key==127) { // delete
|
282 |
+
if(carat < (int)txt.Text().size() ) {
|
283 |
+
std::string newstr = txt.Text();
|
284 |
+
newstr.erase(newstr.begin()+carat);
|
285 |
+
txt = font.Text("%s", newstr.c_str() );
|
286 |
+
edited = true;
|
287 |
+
}
|
288 |
+
}else if(key==PANGO_CTRL + 'c') {
|
289 |
+
txt = font.Text("");
|
290 |
+
carat = 0;
|
291 |
+
edited = true;
|
292 |
+
}else if(key < PANGO_SPECIAL){
|
293 |
+
std::string newstr = txt.Text();
|
294 |
+
newstr.insert(carat, 1, key);
|
295 |
+
txt = font.Text("%s", newstr.c_str());
|
296 |
+
++carat;
|
297 |
+
edited = true;
|
298 |
+
}
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
void ConsoleView::AddLine(const std::string& text, InterpreterLineType linetype )
|
303 |
+
{
|
304 |
+
line_buffer.push_front( Line( font.Text("%s",text.c_str()), linetype) );
|
305 |
+
}
|
306 |
+
|
307 |
+
ConsoleView::Line* ConsoleView::GetLine(int id, InterpreterLineType line_type, const std::string& prefix )
|
308 |
+
{
|
309 |
+
int match = 0;
|
310 |
+
for(Line& l : line_buffer)
|
311 |
+
{
|
312 |
+
if(l.linetype == line_type) {
|
313 |
+
const std::string substr = l.text.Text().substr(0,prefix.size());
|
314 |
+
if(substr == prefix ) {
|
315 |
+
if(id == match) {
|
316 |
+
return &l;
|
317 |
+
}else{
|
318 |
+
++match;
|
319 |
+
}
|
320 |
+
}
|
321 |
+
}
|
322 |
+
}
|
323 |
+
|
324 |
+
return nullptr;
|
325 |
+
}
|
326 |
+
|
327 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/default_font.cpp
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pangolin/display/default_font.h>
|
2 |
+
|
3 |
+
#include "pangolin_gl.h"
|
4 |
+
|
5 |
+
extern const unsigned char AnonymousPro_ttf[];
|
6 |
+
|
7 |
+
namespace pangolin {
|
8 |
+
|
9 |
+
GlFont& default_font()
|
10 |
+
{
|
11 |
+
PangolinGl* context = GetCurrentContext();
|
12 |
+
PANGO_ASSERT(context);
|
13 |
+
if(!context->font) {
|
14 |
+
context->font = std::make_shared<GlFont>(AnonymousPro_ttf, 18);
|
15 |
+
}
|
16 |
+
return *(context->font.get());
|
17 |
+
}
|
18 |
+
|
19 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/display.cpp
ADDED
@@ -0,0 +1,347 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove, Richard Newcombe
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <pangolin/platform.h>
|
29 |
+
|
30 |
+
|
31 |
+
#include <iostream>
|
32 |
+
#include <sstream>
|
33 |
+
#include <string>
|
34 |
+
#include <map>
|
35 |
+
#include <mutex>
|
36 |
+
#include <cstdlib>
|
37 |
+
#include <memory>
|
38 |
+
|
39 |
+
#include <pangolin/gl/gl.h>
|
40 |
+
#include <pangolin/gl/gldraw.h>
|
41 |
+
#include <pangolin/factory/factory_registry.h>
|
42 |
+
#include <pangolin/display/display.h>
|
43 |
+
#include <pangolin/display/process.h>
|
44 |
+
#include <pangolin/console/ConsoleView.h>
|
45 |
+
#include <pangolin/utils/simple_math.h>
|
46 |
+
#include <pangolin/utils/timer.h>
|
47 |
+
#include <pangolin/utils/type_convert.h>
|
48 |
+
#include <pangolin/image/image_io.h>
|
49 |
+
#include <pangolin/var/var.h>
|
50 |
+
|
51 |
+
#include "pangolin_gl.h"
|
52 |
+
|
53 |
+
extern const unsigned char AnonymousPro_ttf[];
|
54 |
+
|
55 |
+
namespace pangolin
|
56 |
+
{
|
57 |
+
|
58 |
+
typedef std::map<std::string,std::shared_ptr<PangolinGl> > ContextMap;
|
59 |
+
|
60 |
+
// Map of active contexts
|
61 |
+
ContextMap contexts;
|
62 |
+
std::recursive_mutex contexts_mutex;
|
63 |
+
|
64 |
+
// Context active for current thread
|
65 |
+
__thread PangolinGl* context = 0;
|
66 |
+
|
67 |
+
void SetCurrentContext(PangolinGl* newcontext) {
|
68 |
+
context = newcontext;
|
69 |
+
}
|
70 |
+
|
71 |
+
PangolinGl* GetCurrentContext()
|
72 |
+
{
|
73 |
+
return context;
|
74 |
+
}
|
75 |
+
|
76 |
+
PangolinGl *FindContext(const std::string& name)
|
77 |
+
{
|
78 |
+
contexts_mutex.lock();
|
79 |
+
ContextMap::iterator ic = contexts.find(name);
|
80 |
+
PangolinGl* context = (ic == contexts.end()) ? 0 : ic->second.get();
|
81 |
+
contexts_mutex.unlock();
|
82 |
+
return context;
|
83 |
+
}
|
84 |
+
|
85 |
+
WindowInterface& CreateWindowAndBind(std::string window_title, int w, int h, const Params& params)
|
86 |
+
{
|
87 |
+
std::unique_lock<std::recursive_mutex> l(contexts_mutex);
|
88 |
+
|
89 |
+
pangolin::Uri win_uri;
|
90 |
+
|
91 |
+
if(const char* extra_params = std::getenv("PANGOLIN_WINDOW_URI"))
|
92 |
+
{
|
93 |
+
// Take any defaults from the environment
|
94 |
+
win_uri = pangolin::ParseUri(extra_params);
|
95 |
+
}else{
|
96 |
+
// Otherwise revert to 'default' scheme.
|
97 |
+
win_uri.scheme = "default";
|
98 |
+
}
|
99 |
+
|
100 |
+
// Override with anything the program specified
|
101 |
+
for(const auto& param : params.params) {
|
102 |
+
if(param.first != "scheme") win_uri.params.push_back(param);
|
103 |
+
}
|
104 |
+
|
105 |
+
// Special params that shouldn't get passed to window factory
|
106 |
+
win_uri.scheme = win_uri.Get("scheme", win_uri.scheme);
|
107 |
+
const std::string default_font = win_uri.Get<std::string>("default_font","");
|
108 |
+
const int default_font_size = win_uri.Get("default_font_size", 18);
|
109 |
+
win_uri.Remove("scheme");
|
110 |
+
win_uri.Remove("default_font");
|
111 |
+
win_uri.Remove("default_font_size");
|
112 |
+
|
113 |
+
// Additional arguments we will send to factory
|
114 |
+
win_uri.Set("w", w);
|
115 |
+
win_uri.Set("h", h);
|
116 |
+
win_uri.Set("window_title", window_title);
|
117 |
+
|
118 |
+
auto context = std::make_shared<PangolinGl>();
|
119 |
+
context->window = ConstructWindow(win_uri);
|
120 |
+
assert(context->window);
|
121 |
+
|
122 |
+
RegisterNewContext(window_title, context);
|
123 |
+
|
124 |
+
context->window->CloseSignal.connect( [](){
|
125 |
+
pangolin::Quit();
|
126 |
+
});
|
127 |
+
context->window->ResizeSignal.connect( [](WindowResizeEvent event){
|
128 |
+
process::Resize(event.width, event.height);
|
129 |
+
});
|
130 |
+
context->window->KeyboardSignal.connect( [](KeyboardEvent event) {
|
131 |
+
process::Keyboard(event.key, event.x, event.y, event.pressed, event.key_modifiers);
|
132 |
+
});
|
133 |
+
context->window->MouseSignal.connect( [](MouseEvent event){
|
134 |
+
process::Mouse(event.button, event.pressed, event.x, event.y, event.key_modifiers);
|
135 |
+
});
|
136 |
+
context->window->MouseMotionSignal.connect( [](MouseMotionEvent event){
|
137 |
+
process::MouseMotion(event.x, event.y, event.key_modifiers);
|
138 |
+
});
|
139 |
+
context->window->PassiveMouseMotionSignal.connect( [](MouseMotionEvent event){
|
140 |
+
process::PassiveMouseMotion(event.x, event.y, event.key_modifiers);
|
141 |
+
});
|
142 |
+
context->window->SpecialInputSignal.connect( [](SpecialInputEvent event){
|
143 |
+
process::SpecialInput(event.inType, event.x, event.y, event.p[0], event.p[1], event.p[2], event.p[3], event.key_modifiers);
|
144 |
+
});
|
145 |
+
|
146 |
+
// If there is a special font request
|
147 |
+
if( !default_font.empty() ) {
|
148 |
+
const std::string font_filename = PathExpand(default_font);
|
149 |
+
context->font = std::make_shared<GlFont>(font_filename, default_font_size);
|
150 |
+
}else{
|
151 |
+
context->font = std::make_shared<GlFont>(AnonymousPro_ttf, default_font_size);
|
152 |
+
}
|
153 |
+
|
154 |
+
context->MakeCurrent();
|
155 |
+
glewInit();
|
156 |
+
|
157 |
+
// And finally process pending window events (such as resize) now that we've setup our callbacks.
|
158 |
+
context->window->ProcessEvents();
|
159 |
+
|
160 |
+
return *context->window;
|
161 |
+
}
|
162 |
+
|
163 |
+
// Assumption: unique lock is held on contexts_mutex for multi-threaded operation
|
164 |
+
void RegisterNewContext(const std::string& name, std::shared_ptr<PangolinGl> newcontext)
|
165 |
+
{
|
166 |
+
// Set defaults
|
167 |
+
newcontext->base.left = 0.0;
|
168 |
+
newcontext->base.bottom = 0.0;
|
169 |
+
newcontext->base.top = 1.0;
|
170 |
+
newcontext->base.right = 1.0;
|
171 |
+
newcontext->base.aspect = 0;
|
172 |
+
newcontext->base.handler = &StaticHandler;
|
173 |
+
|
174 |
+
// Create and add
|
175 |
+
if( contexts.find(name) != contexts.end() ) {
|
176 |
+
throw std::runtime_error("Context already exists.");
|
177 |
+
}
|
178 |
+
contexts[name] = newcontext;
|
179 |
+
|
180 |
+
// Process the following as if this context is now current.
|
181 |
+
PangolinGl *oldContext = context;
|
182 |
+
context = newcontext.get();
|
183 |
+
|
184 |
+
// Default key bindings can be overridden
|
185 |
+
RegisterKeyPressCallback(PANGO_KEY_ESCAPE, Quit );
|
186 |
+
RegisterKeyPressCallback('\t', [](){ShowFullscreen(TrueFalseToggle::Toggle);} );
|
187 |
+
RegisterKeyPressCallback('`', [](){ShowConsole(TrueFalseToggle::Toggle);} );
|
188 |
+
|
189 |
+
context = oldContext;
|
190 |
+
}
|
191 |
+
|
192 |
+
WindowInterface* GetBoundWindow()
|
193 |
+
{
|
194 |
+
return context->window.get();
|
195 |
+
}
|
196 |
+
|
197 |
+
void DestroyWindow(const std::string& name)
|
198 |
+
{
|
199 |
+
contexts_mutex.lock();
|
200 |
+
ContextMap::iterator ic = contexts.find(name);
|
201 |
+
PangolinGl *context_to_destroy = (ic == contexts.end()) ? 0 : ic->second.get();
|
202 |
+
if (context_to_destroy == context) {
|
203 |
+
context = nullptr;
|
204 |
+
}
|
205 |
+
size_t erased = contexts.erase(name);
|
206 |
+
if(erased == 0) {
|
207 |
+
pango_print_warn("Context '%s' doesn't exist for deletion.\n", name.c_str());
|
208 |
+
}
|
209 |
+
contexts_mutex.unlock();
|
210 |
+
}
|
211 |
+
|
212 |
+
void BindToContext(std::string name)
|
213 |
+
{
|
214 |
+
std::unique_lock<std::recursive_mutex> l(contexts_mutex);
|
215 |
+
|
216 |
+
// N.B. context is modified prior to invoking MakeCurrent so that
|
217 |
+
// state management callbacks (such as Resize()) can be correctly
|
218 |
+
// processed.
|
219 |
+
PangolinGl *context_to_bind = FindContext(name);
|
220 |
+
if( !context_to_bind )
|
221 |
+
{
|
222 |
+
std::shared_ptr<PangolinGl> newcontext(new PangolinGl());
|
223 |
+
RegisterNewContext(name, newcontext);
|
224 |
+
}else{
|
225 |
+
context_to_bind->MakeCurrent();
|
226 |
+
}
|
227 |
+
}
|
228 |
+
|
229 |
+
void Quit()
|
230 |
+
{
|
231 |
+
context->quit = true;
|
232 |
+
}
|
233 |
+
|
234 |
+
void QuitAll()
|
235 |
+
{
|
236 |
+
for(auto& nc : contexts) {
|
237 |
+
nc.second->quit = true;
|
238 |
+
}
|
239 |
+
}
|
240 |
+
|
241 |
+
bool ShouldQuit()
|
242 |
+
{
|
243 |
+
return !context || context->quit;
|
244 |
+
}
|
245 |
+
|
246 |
+
void ShowFullscreen(TrueFalseToggle on_off)
|
247 |
+
{
|
248 |
+
if(context && context->window)
|
249 |
+
context->window->ShowFullscreen(on_off);
|
250 |
+
}
|
251 |
+
|
252 |
+
|
253 |
+
void FinishFrame()
|
254 |
+
{
|
255 |
+
if(context) context->FinishFrame();
|
256 |
+
}
|
257 |
+
|
258 |
+
View& DisplayBase()
|
259 |
+
{
|
260 |
+
return context->base;
|
261 |
+
}
|
262 |
+
|
263 |
+
View& CreateDisplay()
|
264 |
+
{
|
265 |
+
int iguid = rand();
|
266 |
+
std::stringstream ssguid;
|
267 |
+
ssguid << iguid;
|
268 |
+
return Display(ssguid.str());
|
269 |
+
}
|
270 |
+
|
271 |
+
void ShowConsole(TrueFalseToggle on_off)
|
272 |
+
{
|
273 |
+
if( !context->console_view) {
|
274 |
+
Uri interpreter_uri = ParseUri("python://");
|
275 |
+
|
276 |
+
try {
|
277 |
+
// Instantiate interpreter
|
278 |
+
std::shared_ptr<InterpreterInterface> interpreter
|
279 |
+
= FactoryRegistry::I()->Construct<InterpreterInterface>(interpreter_uri);
|
280 |
+
assert(interpreter);
|
281 |
+
|
282 |
+
// Create console and let the pangolin context take ownership
|
283 |
+
context->console_view = std::make_unique<ConsoleView>(interpreter);
|
284 |
+
context->console_view->zorder = std::numeric_limits<int>::max();
|
285 |
+
DisplayBase().AddDisplay(*context->console_view);
|
286 |
+
context->console_view->SetFocus();
|
287 |
+
} catch (std::exception&) {
|
288 |
+
}
|
289 |
+
}else{
|
290 |
+
context->console_view->Show(
|
291 |
+
to_bool(on_off, context->console_view->IsShown())
|
292 |
+
);
|
293 |
+
|
294 |
+
if(context->console_view->IsShown()) {
|
295 |
+
context->console_view->SetFocus();
|
296 |
+
}
|
297 |
+
}
|
298 |
+
|
299 |
+
}
|
300 |
+
|
301 |
+
View& Display(const std::string& name)
|
302 |
+
{
|
303 |
+
// Get / Create View
|
304 |
+
ViewMap::iterator vi = context->named_managed_views.find(name);
|
305 |
+
if( vi != context->named_managed_views.end() )
|
306 |
+
{
|
307 |
+
return *(vi->second);
|
308 |
+
}else{
|
309 |
+
View * v = new View();
|
310 |
+
context->named_managed_views[name] = v;
|
311 |
+
v->handler = &StaticHandler;
|
312 |
+
context->base.views.push_back(v);
|
313 |
+
return *v;
|
314 |
+
}
|
315 |
+
}
|
316 |
+
|
317 |
+
void RegisterKeyPressCallback(int key, std::function<void(int)> func)
|
318 |
+
{
|
319 |
+
context->keypress_hooks[key] = func;
|
320 |
+
}
|
321 |
+
|
322 |
+
void RegisterKeyPressCallback(int key, std::function<void(void)> func)
|
323 |
+
{
|
324 |
+
context->keypress_hooks[key] = [=](int){func();};
|
325 |
+
}
|
326 |
+
|
327 |
+
void SaveWindowOnRender(const std::string& filename, const Viewport& v)
|
328 |
+
{
|
329 |
+
context->screen_capture.push(std::pair<std::string,Viewport>(filename, v) );
|
330 |
+
}
|
331 |
+
|
332 |
+
void SaveWindowNow(const std::string& filename_hint, const Viewport& v)
|
333 |
+
{
|
334 |
+
const Viewport to_save = v.area() ? v.Intersect(DisplayBase().v) : DisplayBase().v;
|
335 |
+
std::string filename = filename_hint;
|
336 |
+
if(FileLowercaseExtention(filename) == "") filename += ".png";
|
337 |
+
|
338 |
+
try {
|
339 |
+
glFlush();
|
340 |
+
TypedImage buffer = ReadFramebuffer(to_save, "RGBA32");
|
341 |
+
SaveImage(buffer, filename, false);
|
342 |
+
} catch (std::exception& e) {
|
343 |
+
std::cerr << e.what() << std::endl;
|
344 |
+
}
|
345 |
+
}
|
346 |
+
|
347 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/handler.cpp
ADDED
@@ -0,0 +1,472 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2013 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <pangolin/display/view.h>
|
29 |
+
#include <pangolin/handler/handler.h>
|
30 |
+
#include <pangolin/display/display.h>
|
31 |
+
|
32 |
+
#include "pangolin_gl.h"
|
33 |
+
|
34 |
+
namespace pangolin
|
35 |
+
{
|
36 |
+
|
37 |
+
void Handler::Keyboard(View& d, unsigned char key, int x, int y, bool pressed)
|
38 |
+
{
|
39 |
+
View* child = d.FindChild(x,y);
|
40 |
+
if( child)
|
41 |
+
{
|
42 |
+
GetCurrentContext()->activeDisplay = child;
|
43 |
+
if( child->handler)
|
44 |
+
child->handler->Keyboard(*child,key,x,y,pressed);
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
void Handler::Mouse(View& d, MouseButton button, int x, int y, bool pressed, int button_state)
|
49 |
+
{
|
50 |
+
View* child = d.FindChild(x,y);
|
51 |
+
if( child )
|
52 |
+
{
|
53 |
+
GetCurrentContext()->activeDisplay = child;
|
54 |
+
if( child->handler)
|
55 |
+
child->handler->Mouse(*child,button,x,y,pressed,button_state);
|
56 |
+
}
|
57 |
+
}
|
58 |
+
|
59 |
+
void Handler::MouseMotion(View& d, int x, int y, int button_state)
|
60 |
+
{
|
61 |
+
View* child = d.FindChild(x,y);
|
62 |
+
if( child )
|
63 |
+
{
|
64 |
+
GetCurrentContext()->activeDisplay = child;
|
65 |
+
if( child->handler)
|
66 |
+
child->handler->MouseMotion(*child,x,y,button_state);
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
void Handler::PassiveMouseMotion(View& d, int x, int y, int button_state)
|
71 |
+
{
|
72 |
+
View* child = d.FindChild(x,y);
|
73 |
+
if( child )
|
74 |
+
{
|
75 |
+
if( child->handler)
|
76 |
+
child->handler->PassiveMouseMotion(*child,x,y,button_state);
|
77 |
+
}
|
78 |
+
}
|
79 |
+
|
80 |
+
void Handler::Special(View& d, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state)
|
81 |
+
{
|
82 |
+
View* child = d.FindChild( (int)x, (int)y);
|
83 |
+
if( child )
|
84 |
+
{
|
85 |
+
GetCurrentContext()->activeDisplay = child;
|
86 |
+
if( child->handler)
|
87 |
+
child->handler->Special(*child,inType, x,y, p1, p2, p3, p4, button_state);
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
void HandlerScroll::Mouse(View& d, MouseButton button, int x, int y, bool pressed, int button_state)
|
92 |
+
{
|
93 |
+
if( pressed && (button == MouseWheelUp || button == MouseWheelDown) )
|
94 |
+
{
|
95 |
+
if( button == MouseWheelUp) d.scroll_offset -= 1;
|
96 |
+
if( button == MouseWheelDown) d.scroll_offset += 1;
|
97 |
+
d.scroll_offset = std::max(0, std::min(d.scroll_offset, (int)d.NumVisibleChildren()-1) );
|
98 |
+
d.ResizeChildren();
|
99 |
+
}else{
|
100 |
+
Handler::Mouse(d,button,x,y,pressed,button_state);
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
void HandlerScroll::Special(View& d, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state)
|
105 |
+
{
|
106 |
+
if( inType == InputSpecialScroll )
|
107 |
+
{
|
108 |
+
d.scroll_offset -= (int)(p2 / fabs(p2));
|
109 |
+
d.scroll_offset = std::max(0, std::min(d.scroll_offset, (int)d.NumVisibleChildren()-1) );
|
110 |
+
d.ResizeChildren();
|
111 |
+
}else{
|
112 |
+
Handler::Special(d,inType,x,y,p1,p2,p3,p4,button_state);
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
HandlerBase3D::HandlerBase3D(OpenGlRenderState& cam_state, AxisDirection enforce_up, float trans_scale, float zoom_fraction)
|
117 |
+
: cam_state(&cam_state), enforce_up(enforce_up), tf(trans_scale), zf(zoom_fraction), cameraspec(CameraSpecOpenGl), last_z(0.8)
|
118 |
+
{
|
119 |
+
SetZero<3,1>(rot_center);
|
120 |
+
}
|
121 |
+
|
122 |
+
void HandlerBase3D::Keyboard(View&, unsigned char /*key*/, int /*x*/, int /*y*/, bool /*pressed*/)
|
123 |
+
{
|
124 |
+
// TODO: hooks for reset / changing mode (perspective / ortho etc)
|
125 |
+
}
|
126 |
+
|
127 |
+
bool HandlerBase3D::ValidWinDepth(GLprecision depth)
|
128 |
+
{
|
129 |
+
return depth != 1;
|
130 |
+
}
|
131 |
+
|
132 |
+
void HandlerBase3D::PixelUnproject( View& view, GLprecision winx, GLprecision winy, GLprecision winz, GLprecision Pc[3])
|
133 |
+
{
|
134 |
+
const GLint viewport[4] = {view.v.l,view.v.b,view.v.w,view.v.h};
|
135 |
+
const pangolin::OpenGlMatrix proj = cam_state->GetProjectionMatrix();
|
136 |
+
glUnProject(winx, winy, winz, IdentityMatrix().m, proj.m, viewport, &Pc[0], &Pc[1], &Pc[2]);
|
137 |
+
}
|
138 |
+
|
139 |
+
void HandlerBase3D::GetPosNormalImpl(pangolin::View& view, int winx, int winy, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision nw[3], GLprecision default_z, float* zs)
|
140 |
+
{
|
141 |
+
const int zl = (hwin*2+1);
|
142 |
+
const int zsize = zl*zl;
|
143 |
+
|
144 |
+
GLfloat mindepth = *(std::min_element(zs,zs+zsize));
|
145 |
+
if(mindepth == 1) mindepth = (GLfloat)default_z;
|
146 |
+
|
147 |
+
p[0] = winx; p[1] = winy; p[2] = mindepth;
|
148 |
+
PixelUnproject(view, winx, winy, mindepth, Pc);
|
149 |
+
|
150 |
+
const pangolin::OpenGlMatrix mv = cam_state->GetModelViewMatrix();
|
151 |
+
|
152 |
+
GLprecision T_wc[3*4];
|
153 |
+
LieSE3from4x4(T_wc, mv.Inverse().m );
|
154 |
+
LieApplySE3vec(Pw, T_wc, Pc);
|
155 |
+
|
156 |
+
// Neighboring points in camera coordinates
|
157 |
+
GLprecision Pl[3]; GLprecision Pr[3]; GLprecision Pb[3]; GLprecision Pt[3];
|
158 |
+
PixelUnproject(view, winx-hwin, winy, zs[hwin*zl + 0], Pl );
|
159 |
+
PixelUnproject(view, winx+hwin, winy, zs[hwin*zl + zl-1], Pr );
|
160 |
+
PixelUnproject(view, winx, winy-hwin, zs[hwin+1], Pb );
|
161 |
+
PixelUnproject(view, winx, winy+hwin, zs[zsize-(hwin+1)], Pt );
|
162 |
+
|
163 |
+
// n = ((Pr-Pl).cross(Pt-Pb)).normalized();
|
164 |
+
GLprecision PrmPl[3]; GLprecision PtmPb[3];
|
165 |
+
MatSub<3,1>(PrmPl,Pr,Pl);
|
166 |
+
MatSub<3,1>(PtmPb,Pt,Pb);
|
167 |
+
|
168 |
+
GLprecision nc[3];
|
169 |
+
CrossProduct(nc, PrmPl, PtmPb);
|
170 |
+
Normalise<3>(nc);
|
171 |
+
|
172 |
+
// T_wc is col major, so the rotation component is first.
|
173 |
+
LieApplySO3(nw,T_wc,nc);
|
174 |
+
}
|
175 |
+
|
176 |
+
void HandlerBase3D::GetPosNormal(pangolin::View& view, int winx, int winy, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision nw[3], GLprecision default_z)
|
177 |
+
{
|
178 |
+
const int zl = (hwin*2+1);
|
179 |
+
const int zsize = zl*zl;
|
180 |
+
GLfloat zs[zsize];
|
181 |
+
|
182 |
+
GLint readid = 0;
|
183 |
+
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readid);
|
184 |
+
// Choose attachment based on the bound framebuffer since GL_FRONT doesn't exist for FBOs
|
185 |
+
glReadBuffer(readid == 0 ? GL_FRONT : GL_COLOR_ATTACHMENT0);
|
186 |
+
glReadPixels(winx-hwin,winy-hwin,zl,zl,GL_DEPTH_COMPONENT,GL_FLOAT,zs);
|
187 |
+
GetPosNormalImpl(view, winx, winy, p, Pw, Pc, nw, default_z, zs);
|
188 |
+
}
|
189 |
+
|
190 |
+
void HandlerBase3D::Mouse(View& display, MouseButton button, int x, int y, bool pressed, int button_state)
|
191 |
+
{
|
192 |
+
// mouse down
|
193 |
+
last_pos[0] = (float)x;
|
194 |
+
last_pos[1] = (float)y;
|
195 |
+
|
196 |
+
GLprecision T_nc[3*4];
|
197 |
+
LieSetIdentity(T_nc);
|
198 |
+
|
199 |
+
funcKeyState = 0;
|
200 |
+
if( pressed )
|
201 |
+
{
|
202 |
+
GetPosNormal(display,x,y,p,Pw,Pc,n,last_z);
|
203 |
+
if( ValidWinDepth(p[2]) )
|
204 |
+
{
|
205 |
+
last_z = p[2];
|
206 |
+
std::copy(Pc,Pc+3,rot_center);
|
207 |
+
}
|
208 |
+
|
209 |
+
if( button == MouseWheelUp || button == MouseWheelDown)
|
210 |
+
{
|
211 |
+
LieSetIdentity(T_nc);
|
212 |
+
const GLprecision t[3] = { 0,0,(button==MouseWheelUp?1:-1)*100*tf};
|
213 |
+
LieSetTranslation<>(T_nc,t);
|
214 |
+
if( !(button_state & MouseButtonRight) && !(rot_center[0]==0 && rot_center[1]==0 && rot_center[2]==0) )
|
215 |
+
{
|
216 |
+
LieSetTranslation<>(T_nc,rot_center);
|
217 |
+
const GLprecision s = (button==MouseWheelUp?-1.0:1.0) * zf;
|
218 |
+
MatMul<3,1>(T_nc+(3*3), s);
|
219 |
+
}
|
220 |
+
OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
|
221 |
+
LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
|
222 |
+
}
|
223 |
+
|
224 |
+
funcKeyState = button_state;
|
225 |
+
}
|
226 |
+
}
|
227 |
+
|
228 |
+
void HandlerBase3D::MouseMotion(View& display, int x, int y, int button_state)
|
229 |
+
{
|
230 |
+
const GLprecision rf = 0.01;
|
231 |
+
const float delta[2] = { (float)x - last_pos[0], (float)y - last_pos[1] };
|
232 |
+
const float mag = delta[0]*delta[0] + delta[1]*delta[1];
|
233 |
+
|
234 |
+
if((button_state & KeyModifierCtrl) && (button_state & KeyModifierShift))
|
235 |
+
{
|
236 |
+
GLprecision T_nc[3 * 4];
|
237 |
+
LieSetIdentity(T_nc);
|
238 |
+
|
239 |
+
GetPosNormal(display, x, y, p, Pw, Pc, n, last_z);
|
240 |
+
if(ValidWinDepth(p[2]))
|
241 |
+
{
|
242 |
+
last_z = p[2];
|
243 |
+
std::copy(Pc, Pc + 3, rot_center);
|
244 |
+
}
|
245 |
+
|
246 |
+
funcKeyState = button_state;
|
247 |
+
}
|
248 |
+
else
|
249 |
+
{
|
250 |
+
funcKeyState = 0;
|
251 |
+
}
|
252 |
+
|
253 |
+
// TODO: convert delta to degrees based of fov
|
254 |
+
// TODO: make transformation with respect to cam spec
|
255 |
+
if( mag < 50.0f*50.0f )
|
256 |
+
{
|
257 |
+
OpenGlMatrix& mv = cam_state->GetModelViewMatrix();
|
258 |
+
const GLprecision* up = AxisDirectionVector[enforce_up];
|
259 |
+
GLprecision T_nc[3*4];
|
260 |
+
LieSetIdentity(T_nc);
|
261 |
+
bool rotation_changed = false;
|
262 |
+
|
263 |
+
if( button_state == MouseButtonMiddle )
|
264 |
+
{
|
265 |
+
// Middle Drag: Rotate around view
|
266 |
+
|
267 |
+
// Try to correct for different coordinate conventions.
|
268 |
+
GLprecision aboutx = -rf * delta[1];
|
269 |
+
GLprecision abouty = rf * delta[0];
|
270 |
+
OpenGlMatrix& pm = cam_state->GetProjectionMatrix();
|
271 |
+
abouty *= -pm.m[2 * 4 + 3];
|
272 |
+
|
273 |
+
Rotation<>(T_nc, aboutx, abouty, (GLprecision)0.0);
|
274 |
+
}else if( button_state == MouseButtonLeft )
|
275 |
+
{
|
276 |
+
// Left Drag: in plane translate
|
277 |
+
if( ValidWinDepth(last_z) )
|
278 |
+
{
|
279 |
+
GLprecision np[3];
|
280 |
+
PixelUnproject(display, x, y, last_z, np);
|
281 |
+
const GLprecision t[] = { np[0] - rot_center[0], np[1] - rot_center[1], 0};
|
282 |
+
LieSetTranslation<>(T_nc,t);
|
283 |
+
std::copy(np,np+3,rot_center);
|
284 |
+
}else{
|
285 |
+
const GLprecision t[] = { -10*delta[0]*tf, 10*delta[1]*tf, 0};
|
286 |
+
LieSetTranslation<>(T_nc,t);
|
287 |
+
}
|
288 |
+
}else if( button_state == (MouseButtonLeft | MouseButtonRight) )
|
289 |
+
{
|
290 |
+
// Left and Right Drag: in plane rotate about object
|
291 |
+
// Rotation<>(T_nc,0.0,0.0, delta[0]*0.01);
|
292 |
+
|
293 |
+
GLprecision T_2c[3*4];
|
294 |
+
Rotation<>(T_2c, (GLprecision)0.0, (GLprecision)0.0, delta[0]*rf);
|
295 |
+
GLprecision mrotc[3];
|
296 |
+
MatMul<3,1>(mrotc, rot_center, (GLprecision)-1.0);
|
297 |
+
LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
|
298 |
+
GLprecision T_n2[3*4];
|
299 |
+
LieSetIdentity<>(T_n2);
|
300 |
+
LieSetTranslation<>(T_n2,rot_center);
|
301 |
+
LieMulSE3(T_nc, T_n2, T_2c );
|
302 |
+
rotation_changed = true;
|
303 |
+
}else if( button_state == MouseButtonRight)
|
304 |
+
{
|
305 |
+
GLprecision aboutx = -rf * delta[1];
|
306 |
+
GLprecision abouty = -rf * delta[0];
|
307 |
+
|
308 |
+
// Try to correct for different coordinate conventions.
|
309 |
+
if(cam_state->GetProjectionMatrix().m[2*4+3] <= 0) {
|
310 |
+
abouty *= -1;
|
311 |
+
}
|
312 |
+
|
313 |
+
if(enforce_up) {
|
314 |
+
// Special case if view direction is parallel to up vector
|
315 |
+
const GLprecision updotz = mv.m[2]*up[0] + mv.m[6]*up[1] + mv.m[10]*up[2];
|
316 |
+
if(updotz > 0.98) aboutx = std::min(aboutx, (GLprecision)0.0);
|
317 |
+
if(updotz <-0.98) aboutx = std::max(aboutx, (GLprecision)0.0);
|
318 |
+
// Module rotation around y so we don't spin too fast!
|
319 |
+
abouty *= (1-0.6*fabs(updotz));
|
320 |
+
}
|
321 |
+
|
322 |
+
// Right Drag: object centric rotation
|
323 |
+
GLprecision T_2c[3*4];
|
324 |
+
Rotation<>(T_2c, aboutx, abouty, (GLprecision)0.0);
|
325 |
+
GLprecision mrotc[3];
|
326 |
+
MatMul<3,1>(mrotc, rot_center, (GLprecision)-1.0);
|
327 |
+
LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
|
328 |
+
GLprecision T_n2[3*4];
|
329 |
+
LieSetIdentity<>(T_n2);
|
330 |
+
LieSetTranslation<>(T_n2,rot_center);
|
331 |
+
LieMulSE3(T_nc, T_n2, T_2c );
|
332 |
+
rotation_changed = true;
|
333 |
+
}
|
334 |
+
|
335 |
+
LieMul4x4bySE3<>(mv.m,T_nc,mv.m);
|
336 |
+
|
337 |
+
if(enforce_up != AxisNone && rotation_changed) {
|
338 |
+
EnforceUpT_cw(mv.m, up);
|
339 |
+
}
|
340 |
+
}
|
341 |
+
|
342 |
+
last_pos[0] = (float)x;
|
343 |
+
last_pos[1] = (float)y;
|
344 |
+
}
|
345 |
+
|
346 |
+
void HandlerBase3D::Special(View& display, InputSpecial inType, float x, float y, float p1, float p2, float /*p3*/, float /*p4*/, int button_state)
|
347 |
+
{
|
348 |
+
if( !(inType == InputSpecialScroll || inType == InputSpecialRotate) )
|
349 |
+
return;
|
350 |
+
|
351 |
+
// mouse down
|
352 |
+
last_pos[0] = x;
|
353 |
+
last_pos[1] = y;
|
354 |
+
|
355 |
+
GLprecision T_nc[3*4];
|
356 |
+
LieSetIdentity(T_nc);
|
357 |
+
|
358 |
+
GetPosNormal(display, (int)x, (int)y, p, Pw, Pc, n, last_z);
|
359 |
+
if(p[2] < 1.0) {
|
360 |
+
last_z = p[2];
|
361 |
+
std::copy(Pc,Pc+3,rot_center);
|
362 |
+
}
|
363 |
+
|
364 |
+
if( inType == InputSpecialScroll ) {
|
365 |
+
if(button_state & KeyModifierCmd) {
|
366 |
+
const GLprecision rx = -p2 / 1000;
|
367 |
+
const GLprecision ry = -p1 / 1000;
|
368 |
+
|
369 |
+
Rotation<>(T_nc,rx, ry, (GLprecision)0.0);
|
370 |
+
OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
|
371 |
+
LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
|
372 |
+
}else{
|
373 |
+
const GLprecision scrolly = p2/10;
|
374 |
+
|
375 |
+
LieSetIdentity(T_nc);
|
376 |
+
const GLprecision t[] = { 0,0, -scrolly*100*tf};
|
377 |
+
LieSetTranslation<>(T_nc,t);
|
378 |
+
if( !(button_state & MouseButtonRight) && !(rot_center[0]==0 && rot_center[1]==0 && rot_center[2]==0) )
|
379 |
+
{
|
380 |
+
LieSetTranslation<>(T_nc,rot_center);
|
381 |
+
MatMul<3,1>(T_nc+(3*3), -scrolly * zf);
|
382 |
+
}
|
383 |
+
OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
|
384 |
+
LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
|
385 |
+
}
|
386 |
+
}else if(inType == InputSpecialRotate) {
|
387 |
+
const GLprecision r = p1 / 20;
|
388 |
+
|
389 |
+
GLprecision T_2c[3*4];
|
390 |
+
Rotation<>(T_2c, (GLprecision)0.0, (GLprecision)0.0, r);
|
391 |
+
GLprecision mrotc[3];
|
392 |
+
MatMul<3,1>(mrotc, rot_center, (GLprecision)-1.0);
|
393 |
+
LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
|
394 |
+
GLprecision T_n2[3*4];
|
395 |
+
LieSetIdentity<>(T_n2);
|
396 |
+
LieSetTranslation<>(T_n2,rot_center);
|
397 |
+
LieMulSE3(T_nc, T_n2, T_2c );
|
398 |
+
OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
|
399 |
+
LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
|
400 |
+
}
|
401 |
+
|
402 |
+
}
|
403 |
+
|
404 |
+
#ifdef HAVE_GLES
|
405 |
+
Handler3DBlitCopy::Handler3DBlitCopy(pangolin::OpenGlRenderState& cam_state, pangolin::AxisDirection enforce_up, float trans_scale)
|
406 |
+
: pangolin::HandlerBase3D(cam_state,enforce_up, trans_scale)
|
407 |
+
{
|
408 |
+
}
|
409 |
+
|
410 |
+
void Handler3DBlitCopy::GetPosNormal(pangolin::View& view, int winx, int winy, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision n[3], GLprecision default_z)
|
411 |
+
{
|
412 |
+
// Go around the houses so we can get depth data...
|
413 |
+
// With GLES3 / WebGL 2.0, we can't read from the depth buffer or download ROI's of GL textures
|
414 |
+
// The process below is the simplest I could make work that avoids a large GPU -> CPU download.
|
415 |
+
|
416 |
+
const int w = pangolin::DisplayBase().v.w;
|
417 |
+
const int h = pangolin::DisplayBase().v.h;
|
418 |
+
|
419 |
+
GLint num_bits;
|
420 |
+
glGetIntegerv(GL_DEPTH_BITS, &num_bits);
|
421 |
+
|
422 |
+
// Make sure our buffers are the right size for the current screen buffer
|
423 |
+
if(!depth_blit.IsValid() || depth_blit.width != w || depth_blit.height != h)
|
424 |
+
{
|
425 |
+
// Reinitialize all buffers
|
426 |
+
fb_blit.Reinitialise();
|
427 |
+
rgb_blit.Reinitialise(w,h,GL_RGB, true, 0, GL_RGB, GL_UNSIGNED_BYTE);
|
428 |
+
depth_blit.Reinitialise(w,h,GL_DEPTH24_STENCIL8, false, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
|
429 |
+
fb_blit.AttachColour(rgb_blit);
|
430 |
+
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_blit.fbid);
|
431 |
+
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_blit.tid, 0);
|
432 |
+
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
433 |
+
|
434 |
+
fb.Reinitialise();
|
435 |
+
rgb.Reinitialise(w,h,GL_R32F, true, 0, GL_RED, GL_FLOAT);
|
436 |
+
depth.Reinitialise(w,h,GL_DEPTH24_STENCIL8, false, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
|
437 |
+
fb.AttachColour(rgb);
|
438 |
+
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb.fbid);
|
439 |
+
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth.tid, 0);
|
440 |
+
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
441 |
+
}
|
442 |
+
|
443 |
+
// Copy screens depth buffer to our blit framebuffer
|
444 |
+
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
445 |
+
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_blit.fbid);
|
446 |
+
glBlitFramebuffer(0,0,w,h, 0,0,w,h, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
447 |
+
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
448 |
+
|
449 |
+
// Render the depth buffer to our regular buffer (so depth ends up in color buffer)
|
450 |
+
fb.Bind();
|
451 |
+
glViewport(0,0,w,h);
|
452 |
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
453 |
+
glColor4f(1.0,1.0,1.0,1.0);
|
454 |
+
depth_blit.RenderToViewport();
|
455 |
+
depth_blit.Unbind();
|
456 |
+
|
457 |
+
const int zl = (hwin*2+1);
|
458 |
+
const int zsize = zl*zl;
|
459 |
+
GLfloat zs[4*zsize];
|
460 |
+
GLfloat zsr[zsize];
|
461 |
+
|
462 |
+
// GLES3 only supports ReadPixels with GL_RGBA
|
463 |
+
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
464 |
+
glReadPixels(winx-hwin,winy-hwin,zl,zl,GL_RGBA,GL_FLOAT,zs);
|
465 |
+
for(size_t i=0; i < zsize; ++i) zsr[i] = zs[4*i];
|
466 |
+
fb.Unbind();
|
467 |
+
|
468 |
+
HandlerBase3D::GetPosNormalImpl(view,winx,winy,p,Pw,Pc,n,default_z,zsr);
|
469 |
+
}
|
470 |
+
#endif
|
471 |
+
|
472 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/handler_glbuffer.cpp
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2013 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <pangolin/handler/handler_glbuffer.h>
|
29 |
+
#include <pangolin/display/view.h>
|
30 |
+
|
31 |
+
namespace pangolin {
|
32 |
+
|
33 |
+
Handler3DFramebuffer::Handler3DFramebuffer(GlFramebuffer& fb, pangolin::OpenGlRenderState& cam_state, pangolin::AxisDirection enforce_up, float trans_scale)
|
34 |
+
: pangolin::HandlerBase3D(cam_state,enforce_up, trans_scale), fb(fb)
|
35 |
+
{
|
36 |
+
}
|
37 |
+
|
38 |
+
void Handler3DFramebuffer::GetPosNormal(pangolin::View& view, int x, int y, GLprecision p[3], GLprecision Pw[3], GLprecision Pc[3], GLprecision n[3], GLprecision default_z)
|
39 |
+
{
|
40 |
+
fb.Bind();
|
41 |
+
HandlerBase3D::GetPosNormal(view,x,y,p,Pw,Pc,n,default_z);
|
42 |
+
fb.Unbind();
|
43 |
+
}
|
44 |
+
|
45 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/handler_image.cpp
ADDED
@@ -0,0 +1,526 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pangolin/handler/handler_image.h>
|
2 |
+
#include <pangolin/display/default_font.h>
|
3 |
+
|
4 |
+
namespace pangolin
|
5 |
+
{
|
6 |
+
|
7 |
+
ImageViewHandler::ImageViewHandler(const std::string & title)
|
8 |
+
: linked_view_handler(0), use_nn(false), flipTextureX(false), flipTextureY(false), title(title)
|
9 |
+
{
|
10 |
+
SetDimensions(1, 1);
|
11 |
+
}
|
12 |
+
|
13 |
+
ImageViewHandler::ImageViewHandler(size_t w, size_t h)
|
14 |
+
: linked_view_handler(0),
|
15 |
+
use_nn(false), flipTextureX(false), flipTextureY(false)
|
16 |
+
{
|
17 |
+
SetDimensions(w,h);
|
18 |
+
}
|
19 |
+
|
20 |
+
void ImageViewHandler::SetDimensions(size_t w, size_t h)
|
21 |
+
{
|
22 |
+
rview_default = pangolin::XYRangef(-0.5f, w-0.5f, -0.5f, h-0.5f),
|
23 |
+
rview_max = pangolin::XYRangef(-0.5f, w-0.5f, -0.5f, h-0.5f),
|
24 |
+
rview = rview_default;
|
25 |
+
target = rview;
|
26 |
+
}
|
27 |
+
|
28 |
+
void ImageViewHandler::UpdateView()
|
29 |
+
{
|
30 |
+
// TODO: Base this on current framerate.
|
31 |
+
const float animate_factor = 1.0f / 5.0f;
|
32 |
+
|
33 |
+
if( linked_view_handler ) {
|
34 |
+
// Synchronise rview and target with linked plotter
|
35 |
+
rview = linked_view_handler->rview;
|
36 |
+
target = linked_view_handler->target;
|
37 |
+
selection = linked_view_handler->selection;
|
38 |
+
}else{
|
39 |
+
// Clamp target to image dimensions.
|
40 |
+
AdjustScale();
|
41 |
+
AdjustTranslation();
|
42 |
+
|
43 |
+
// Animate view window toward target
|
44 |
+
pangolin::XYRangef d = target - rview;
|
45 |
+
rview += d * animate_factor;
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
void ImageViewHandler::glSetViewOrtho()
|
50 |
+
{
|
51 |
+
const pangolin::XYRangef& xy = GetViewToRender();
|
52 |
+
|
53 |
+
glMatrixMode(GL_PROJECTION);
|
54 |
+
ProjectionMatrixOrthographic(xy.x.min, xy.x.max, xy.y.max, xy.y.min, -1.0f, 1.0f).Load();
|
55 |
+
glMatrixMode(GL_MODELVIEW);
|
56 |
+
glLoadIdentity();
|
57 |
+
}
|
58 |
+
|
59 |
+
void ImageViewHandler::glRenderTexture(pangolin::GlTexture& tex)
|
60 |
+
{
|
61 |
+
glRenderTexture(tex.tid, tex.width, tex.height);
|
62 |
+
}
|
63 |
+
|
64 |
+
void ImageViewHandler::glRenderTexture(GLuint tex, GLint width, GLint height)
|
65 |
+
{
|
66 |
+
if(tex != 0) {
|
67 |
+
const pangolin::XYRangef& xy = GetViewToRender();
|
68 |
+
const float w = (float)width;
|
69 |
+
const float h = (float)height;
|
70 |
+
|
71 |
+
// discrete coords, (-0.5, -0.5) - (w-0.5, h-0.5)
|
72 |
+
const GLfloat l = xy.x.min;
|
73 |
+
const GLfloat r = xy.x.max;
|
74 |
+
const GLfloat b = xy.y.max;
|
75 |
+
const GLfloat t = xy.y.min;
|
76 |
+
|
77 |
+
// continuous coords, (0,0) - (1,1)
|
78 |
+
GLfloat ln = (l + 0.5f) / w;
|
79 |
+
GLfloat rn = (r + 0.5f) / w;
|
80 |
+
GLfloat bn = (b + 0.5f) / h;
|
81 |
+
GLfloat tn = (t + 0.5f) / h;
|
82 |
+
|
83 |
+
if(flipTextureX) {
|
84 |
+
ln = 1-ln;
|
85 |
+
rn = 1-rn;
|
86 |
+
}
|
87 |
+
|
88 |
+
if(flipTextureY) {
|
89 |
+
bn = 1-bn;
|
90 |
+
tn = 1-tn;
|
91 |
+
}
|
92 |
+
|
93 |
+
const GLfloat sq_vert[] = { l,t, r,t, r,b, l,b };
|
94 |
+
const GLfloat sq_tex[] = { ln,tn, rn,tn, rn,bn, ln,bn };
|
95 |
+
|
96 |
+
glBindTexture(GL_TEXTURE_2D, tex);
|
97 |
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, UseNN() ? GL_NEAREST : GL_LINEAR);
|
98 |
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, UseNN() ? GL_NEAREST : GL_LINEAR);
|
99 |
+
|
100 |
+
glEnable(GL_TEXTURE_2D);
|
101 |
+
glEnableClientState(GL_VERTEX_ARRAY);
|
102 |
+
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
103 |
+
glTexCoordPointer(2, GL_FLOAT, 0, sq_tex);
|
104 |
+
glVertexPointer(2, GL_FLOAT, 0, sq_vert);
|
105 |
+
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
106 |
+
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
107 |
+
glDisableClientState(GL_VERTEX_ARRAY);
|
108 |
+
glDisable(GL_TEXTURE_2D);
|
109 |
+
glBindTexture(GL_TEXTURE_2D, 0);
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
void ImageViewHandler::glRenderTexture(GLuint tex, GLint width, GLint height, XYRangef tex_region)
|
114 |
+
{
|
115 |
+
if(tex != 0) {
|
116 |
+
const pangolin::XYRangef& xy = tex_region;
|
117 |
+
const float w = (float)width;
|
118 |
+
const float h = (float)height;
|
119 |
+
|
120 |
+
// discrete coords, (-0.5, -0.5) - (w-0.5, h-0.5)
|
121 |
+
const GLfloat l = xy.x.min;
|
122 |
+
const GLfloat r = xy.x.max;
|
123 |
+
const GLfloat b = xy.y.max;
|
124 |
+
const GLfloat t = xy.y.min;
|
125 |
+
|
126 |
+
// continuous coords, (0,0) - (1,1)
|
127 |
+
GLfloat ln = 0.0;
|
128 |
+
GLfloat rn = 1.0;
|
129 |
+
GLfloat bn = 0.0;
|
130 |
+
GLfloat tn = 1.0;
|
131 |
+
|
132 |
+
if(flipTextureX) {
|
133 |
+
ln = 1-ln;
|
134 |
+
rn = 1-rn;
|
135 |
+
}
|
136 |
+
|
137 |
+
if(flipTextureY) {
|
138 |
+
bn = 1-bn;
|
139 |
+
tn = 1-tn;
|
140 |
+
}
|
141 |
+
|
142 |
+
const GLfloat sq_vert[] = { l,t, r,t, r,b, l,b };
|
143 |
+
const GLfloat sq_tex[] = { ln,tn, rn,tn, rn,bn, ln,bn };
|
144 |
+
|
145 |
+
glBindTexture(GL_TEXTURE_2D, tex);
|
146 |
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, UseNN() ? GL_NEAREST : GL_LINEAR);
|
147 |
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, UseNN() ? GL_NEAREST : GL_LINEAR);
|
148 |
+
|
149 |
+
glEnable(GL_TEXTURE_2D);
|
150 |
+
glEnableClientState(GL_VERTEX_ARRAY);
|
151 |
+
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
152 |
+
glTexCoordPointer(2, GL_FLOAT, 0, sq_tex);
|
153 |
+
glVertexPointer(2, GL_FLOAT, 0, sq_vert);
|
154 |
+
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
155 |
+
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
156 |
+
glDisableClientState(GL_VERTEX_ARRAY);
|
157 |
+
glDisable(GL_TEXTURE_2D);
|
158 |
+
glBindTexture(GL_TEXTURE_2D, 0);
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
void ImageViewHandler::glRenderOverlay()
|
163 |
+
{
|
164 |
+
const pangolin::XYRangef& selxy = GetSelection();
|
165 |
+
const GLfloat sq_select[] = {
|
166 |
+
selxy.x.min, selxy.y.min,
|
167 |
+
selxy.x.max, selxy.y.min,
|
168 |
+
selxy.x.max, selxy.y.max,
|
169 |
+
selxy.x.min, selxy.y.max
|
170 |
+
};
|
171 |
+
glColor4f(1.0,0.0,0.0,1.0);
|
172 |
+
glEnableClientState(GL_VERTEX_ARRAY);
|
173 |
+
glVertexPointer(2, GL_FLOAT, 0, sq_select);
|
174 |
+
glDrawArrays(GL_LINE_LOOP, 0, 4);
|
175 |
+
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
176 |
+
glColor4f(1.0,1.0,1.0,1.0);
|
177 |
+
|
178 |
+
const bool have_text = std::abs(selxy.Area()) > 0 || !title.empty();
|
179 |
+
|
180 |
+
GLboolean gl_blend_enabled;
|
181 |
+
pangolin::Viewport v;
|
182 |
+
|
183 |
+
if( have_text ) {
|
184 |
+
|
185 |
+
glGetIntegerv( GL_VIEWPORT, &v.l );
|
186 |
+
|
187 |
+
// Save previous value
|
188 |
+
glGetBooleanv(GL_BLEND, &gl_blend_enabled);
|
189 |
+
|
190 |
+
// Ensure that blending is enabled for rendering text.
|
191 |
+
glEnable(GL_BLEND);
|
192 |
+
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
193 |
+
|
194 |
+
}
|
195 |
+
|
196 |
+
if( std::abs(selxy.Area()) > 0) {
|
197 |
+
// Render text
|
198 |
+
float xpix, ypix;
|
199 |
+
ImageToScreen(v, selxy.x.max, selxy.y.max, xpix, ypix);
|
200 |
+
|
201 |
+
auto& font = pangolin::default_font();
|
202 |
+
|
203 |
+
font.Text(
|
204 |
+
"%.2f x %.2f",
|
205 |
+
selxy.x.Size(), selxy.y.Size()
|
206 |
+
).DrawWindow(xpix,ypix);
|
207 |
+
|
208 |
+
font.Text(
|
209 |
+
"(%.1f,%.1f)->(%.1f,%.1f)",
|
210 |
+
selxy.x.min, selxy.y.min,
|
211 |
+
selxy.x.max, selxy.y.max
|
212 |
+
).DrawWindow(xpix, ypix - 1.0f * font.Height());
|
213 |
+
}
|
214 |
+
|
215 |
+
if (!title.empty()) {
|
216 |
+
auto& font = pangolin::default_font();
|
217 |
+
font.Text(title).DrawWindow(v.l + 8, v.t() - 4 - font.Height());
|
218 |
+
}
|
219 |
+
|
220 |
+
if (have_text) {
|
221 |
+
// Restore previous value
|
222 |
+
if(!gl_blend_enabled) glDisable(GL_BLEND);
|
223 |
+
}
|
224 |
+
}
|
225 |
+
|
226 |
+
void ImageViewHandler::ScreenToImage(Viewport& v, float xpix, float ypix, float& ximg, float& yimg)
|
227 |
+
{
|
228 |
+
ximg = rview.x.min + rview.x.Size() * (xpix - v.l) / (float)v.w;
|
229 |
+
yimg = rview.y.min + rview.y.Size() * ( 1.0f - (ypix - v.b) / (float)v.h);
|
230 |
+
}
|
231 |
+
|
232 |
+
void ImageViewHandler::ImageToScreen(Viewport& v, float ximg, float yimg, float& xpix, float& ypix)
|
233 |
+
{
|
234 |
+
xpix = (ximg -rview.x.min) * (float)v.w / rview.x.Size() + v.l;
|
235 |
+
ypix = v.b - (float)v.h * ((yimg - rview.y.min) / rview.y.Size() - 1.0f);
|
236 |
+
}
|
237 |
+
|
238 |
+
bool ImageViewHandler::UseNN() const
|
239 |
+
{
|
240 |
+
return use_nn;
|
241 |
+
}
|
242 |
+
|
243 |
+
bool& ImageViewHandler::UseNN()
|
244 |
+
{
|
245 |
+
return use_nn;
|
246 |
+
}
|
247 |
+
|
248 |
+
bool& ImageViewHandler::FlipTextureX()
|
249 |
+
{
|
250 |
+
return flipTextureX;
|
251 |
+
}
|
252 |
+
|
253 |
+
bool& ImageViewHandler::FlipTextureY()
|
254 |
+
{
|
255 |
+
return flipTextureY;
|
256 |
+
}
|
257 |
+
|
258 |
+
pangolin::XYRangef& ImageViewHandler::GetViewToRender()
|
259 |
+
{
|
260 |
+
return rview;
|
261 |
+
}
|
262 |
+
|
263 |
+
float ImageViewHandler::GetViewScale()
|
264 |
+
{
|
265 |
+
return rview_max.x.Size() / rview.x.Size();
|
266 |
+
}
|
267 |
+
|
268 |
+
pangolin::XYRangef& ImageViewHandler::GetView()
|
269 |
+
{
|
270 |
+
return target;
|
271 |
+
}
|
272 |
+
|
273 |
+
pangolin::XYRangef& ImageViewHandler::GetDefaultView()
|
274 |
+
{
|
275 |
+
return rview_default;
|
276 |
+
}
|
277 |
+
|
278 |
+
pangolin::XYRangef& ImageViewHandler::GetSelection()
|
279 |
+
{
|
280 |
+
return selection;
|
281 |
+
}
|
282 |
+
|
283 |
+
void ImageViewHandler::GetHover(float& x, float& y)
|
284 |
+
{
|
285 |
+
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
|
286 |
+
x = tv.hover_img[0];
|
287 |
+
y = tv.hover_img[1];
|
288 |
+
}
|
289 |
+
|
290 |
+
void ImageViewHandler::SetView(const pangolin::XYRangef& range)
|
291 |
+
{
|
292 |
+
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
|
293 |
+
tv.rview = range;
|
294 |
+
tv.target = range;
|
295 |
+
}
|
296 |
+
|
297 |
+
void ImageViewHandler::SetViewSmooth(const pangolin::XYRangef& range)
|
298 |
+
{
|
299 |
+
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
|
300 |
+
tv.target = range;
|
301 |
+
}
|
302 |
+
|
303 |
+
void ImageViewHandler::ScrollView(float x, float y)
|
304 |
+
{
|
305 |
+
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
|
306 |
+
ScrollViewSmooth(x,y);
|
307 |
+
tv.rview.x += x;
|
308 |
+
tv.rview.y += y;
|
309 |
+
}
|
310 |
+
|
311 |
+
void ImageViewHandler::ScrollViewSmooth(float x, float y)
|
312 |
+
{
|
313 |
+
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
|
314 |
+
tv.target.x += x;
|
315 |
+
tv.target.y += y;
|
316 |
+
}
|
317 |
+
|
318 |
+
void ImageViewHandler::ScaleView(float x, float y, float cx, float cy)
|
319 |
+
{
|
320 |
+
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
|
321 |
+
ScaleViewSmooth(x,y,cx,cy);
|
322 |
+
tv.rview.x.Scale(x,cx);
|
323 |
+
tv.rview.y.Scale(y,cy);
|
324 |
+
}
|
325 |
+
|
326 |
+
void ImageViewHandler::ScaleViewSmooth(float x, float y, float cx, float cy)
|
327 |
+
{
|
328 |
+
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
|
329 |
+
tv.target.x.Scale(x,cx);
|
330 |
+
tv.target.y.Scale(y,cy);
|
331 |
+
}
|
332 |
+
|
333 |
+
void ImageViewHandler::ResetView()
|
334 |
+
{
|
335 |
+
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
|
336 |
+
tv.target = tv.rview_default;
|
337 |
+
}
|
338 |
+
|
339 |
+
///////////////////////////////////////////////////////
|
340 |
+
/// pangolin::Handler
|
341 |
+
///////////////////////////////////////////////////////
|
342 |
+
|
343 |
+
void ImageViewHandler::Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed)
|
344 |
+
{
|
345 |
+
XYRangef& sel = linked_view_handler ? linked_view_handler->selection : selection;
|
346 |
+
const float mvfactor = 1.0f / 10.0f;
|
347 |
+
const float c[2] = { rview.x.Mid(), rview.y.Mid() };
|
348 |
+
|
349 |
+
|
350 |
+
if(pressed) {
|
351 |
+
if(key == '\r') {
|
352 |
+
if( sel.Area() != 0.0f && std::isfinite(sel.Area()) ) {
|
353 |
+
// Set view to equal selection
|
354 |
+
SetViewSmooth(sel);
|
355 |
+
|
356 |
+
// Reset selection
|
357 |
+
sel.x.max = sel.x.min;
|
358 |
+
sel.y.max = sel.y.min;
|
359 |
+
}
|
360 |
+
}else if(key == 'n') {
|
361 |
+
use_nn = !use_nn;
|
362 |
+
}else if(key == 'l') {
|
363 |
+
if(to_link) {
|
364 |
+
linked_view_handler = to_link;
|
365 |
+
to_link = 0;
|
366 |
+
}else{
|
367 |
+
to_link = this;
|
368 |
+
}
|
369 |
+
}else if(key == PANGO_SPECIAL + PANGO_KEY_LEFT) {
|
370 |
+
const float w = target.x.Size();
|
371 |
+
const float dx = mvfactor*w;
|
372 |
+
ScrollViewSmooth(-dx, 0);
|
373 |
+
}else if(key == PANGO_SPECIAL + PANGO_KEY_RIGHT) {
|
374 |
+
const float w = target.x.Size();
|
375 |
+
const float dx = mvfactor*w;
|
376 |
+
ScrollViewSmooth(+dx, 0);
|
377 |
+
}else if(key == PANGO_SPECIAL + PANGO_KEY_DOWN) {
|
378 |
+
const float h = target.y.Size();
|
379 |
+
const float dy = mvfactor*h;
|
380 |
+
ScrollViewSmooth(0, -dy);
|
381 |
+
}else if(key == PANGO_SPECIAL + PANGO_KEY_UP) {
|
382 |
+
const float h = target.y.Size();
|
383 |
+
const float dy = mvfactor*h;
|
384 |
+
ScrollViewSmooth(0, +dy);
|
385 |
+
}else if(key == '=') {
|
386 |
+
ScaleViewSmooth(0.5, 0.5, c[0], c[1]);
|
387 |
+
}else if(key == '-') {
|
388 |
+
ScaleViewSmooth(2.0, 2.0, c[0], c[1]);
|
389 |
+
}else if(key == '#') {
|
390 |
+
ResetView();
|
391 |
+
}else if(key == 1) {
|
392 |
+
// ctrl-a: select all.
|
393 |
+
sel = rview;
|
394 |
+
}else{
|
395 |
+
pango_print_debug("Unhandled ImageViewHandler::Keyboard. Key: %u\n", (unsigned int)key);
|
396 |
+
}
|
397 |
+
}
|
398 |
+
}
|
399 |
+
|
400 |
+
void ImageViewHandler::Mouse(View& view, pangolin::MouseButton button, int x, int y, bool pressed, int button_state)
|
401 |
+
{
|
402 |
+
XYRangef& sel = linked_view_handler ? linked_view_handler->selection : selection;
|
403 |
+
ScreenToImage(view.v, (float)x, (float)y, hover_img[0], hover_img[1]);
|
404 |
+
|
405 |
+
const float scinc = 1.05f;
|
406 |
+
const float scdec = 1.0f/scinc;
|
407 |
+
|
408 |
+
if(button_state & KeyModifierCtrl) {
|
409 |
+
const float mvfactor = 1.0f/20.0f;
|
410 |
+
|
411 |
+
if(button == MouseWheelUp) {
|
412 |
+
ScrollViewSmooth(0.0f, +mvfactor*rview.y.Size() );
|
413 |
+
}else if(button == MouseWheelDown) {
|
414 |
+
ScrollViewSmooth(0.0f, -mvfactor*rview.y.Size() );
|
415 |
+
}else if(button == MouseWheelLeft) {
|
416 |
+
ScrollViewSmooth(+mvfactor*rview.x.Size(), 0.0f );
|
417 |
+
}else if(button == MouseWheelRight) {
|
418 |
+
ScrollViewSmooth(-mvfactor*rview.x.Size(), 0.0f );
|
419 |
+
}
|
420 |
+
}else{
|
421 |
+
if(button == MouseButtonLeft) {
|
422 |
+
// Update selected range
|
423 |
+
if(pressed) {
|
424 |
+
sel.x.min = hover_img[0];
|
425 |
+
sel.y.min = hover_img[1];
|
426 |
+
}
|
427 |
+
sel.x.max = hover_img[0];
|
428 |
+
sel.y.max = hover_img[1];
|
429 |
+
}else if(button == MouseWheelUp) {
|
430 |
+
ScaleViewSmooth(scdec, scdec, hover_img[0], hover_img[1]);
|
431 |
+
}else if(button == MouseWheelDown) {
|
432 |
+
ScaleViewSmooth(scinc, scinc, hover_img[0], hover_img[1]);
|
433 |
+
}
|
434 |
+
}
|
435 |
+
|
436 |
+
FixSelection(sel);
|
437 |
+
last_mouse_pos[0] = x;
|
438 |
+
last_mouse_pos[1] = y;
|
439 |
+
|
440 |
+
if(OnSelectionCallback) {
|
441 |
+
OnSelectionCallback( OnSelectionEventData(view,*this,pressed) );
|
442 |
+
}
|
443 |
+
}
|
444 |
+
|
445 |
+
void ImageViewHandler::MouseMotion(View& view, int x, int y, int button_state)
|
446 |
+
{
|
447 |
+
XYRangef& sel = linked_view_handler ? linked_view_handler->selection : selection;
|
448 |
+
const int d[2] = {x-last_mouse_pos[0], y-last_mouse_pos[1]};
|
449 |
+
|
450 |
+
// Update hover status (after potential resizing)
|
451 |
+
ScreenToImage(view.v, (float)x, (float)y, hover_img[0], hover_img[1]);
|
452 |
+
|
453 |
+
if( button_state == MouseButtonLeft )
|
454 |
+
{
|
455 |
+
// Update selected range
|
456 |
+
sel.x.max = hover_img[0];
|
457 |
+
sel.y.max = hover_img[1];
|
458 |
+
}else if(button_state == MouseButtonRight )
|
459 |
+
{
|
460 |
+
Special(view, InputSpecialScroll, (float)x, (float)y, (float)d[0], (float)d[1], 0.0f, 0.0f, button_state);
|
461 |
+
}
|
462 |
+
|
463 |
+
last_mouse_pos[0] = x;
|
464 |
+
last_mouse_pos[1] = y;
|
465 |
+
|
466 |
+
if( button_state == MouseButtonLeft && OnSelectionCallback) {
|
467 |
+
OnSelectionCallback( OnSelectionEventData(view,*this,true) );
|
468 |
+
}
|
469 |
+
}
|
470 |
+
|
471 |
+
void ImageViewHandler::PassiveMouseMotion(View&, int /*x*/, int /*y*/, int /*button_state*/)
|
472 |
+
{
|
473 |
+
}
|
474 |
+
|
475 |
+
void ImageViewHandler::Special(View& view, pangolin::InputSpecial inType, float x, float y, float p1, float p2, float /*p3*/, float /*p4*/, int /*button_state*/)
|
476 |
+
{
|
477 |
+
ScreenToImage(view.v, x, y, hover_img[0], hover_img[1]);
|
478 |
+
|
479 |
+
if(inType == InputSpecialScroll) {
|
480 |
+
const float d[2] = {p1,p2};
|
481 |
+
const float is[2] = {rview.x.Size(),rview.y.Size() };
|
482 |
+
const float df[2] = {is[0]*d[0]/(float)view.v.w, is[1]*d[1]/(float)view.v.h};
|
483 |
+
ScrollView(-df[0], -df[1]);
|
484 |
+
} else if(inType == InputSpecialZoom) {
|
485 |
+
float scale = 1.0f - p1;
|
486 |
+
ScaleView(scale, scale, hover_img[0], hover_img[1]);
|
487 |
+
}
|
488 |
+
|
489 |
+
// Update hover status (after potential resizing)
|
490 |
+
ScreenToImage( view.v, x, y, hover_img[0], hover_img[1]);
|
491 |
+
}
|
492 |
+
|
493 |
+
void ImageViewHandler::FixSelection(XYRangef& sel)
|
494 |
+
{
|
495 |
+
// Make sure selection matches sign of current viewport
|
496 |
+
if( (sel.x.min<sel.x.max) != (rview.x.min<rview.x.max) ) {
|
497 |
+
std::swap(sel.x.min, sel.x.max);
|
498 |
+
}
|
499 |
+
if( (sel.y.min<sel.y.max) != (rview.y.min<rview.y.max) ) {
|
500 |
+
std::swap(sel.y.min, sel.y.max);
|
501 |
+
}
|
502 |
+
}
|
503 |
+
|
504 |
+
void ImageViewHandler::AdjustScale()
|
505 |
+
{
|
506 |
+
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
|
507 |
+
if(tv.target.x.AbsSize() > tv.rview_max.x.AbsSize())
|
508 |
+
tv.target.x.Scale(tv.rview_max.x.AbsSize() / tv.target.x.AbsSize(), tv.target.x.Mid());
|
509 |
+
if(tv.target.y.AbsSize() > tv.rview_max.y.AbsSize())
|
510 |
+
tv.target.y.Scale(tv.rview_max.y.AbsSize() / tv.target.y.AbsSize(), tv.target.y.Mid());
|
511 |
+
}
|
512 |
+
|
513 |
+
void ImageViewHandler::AdjustTranslation()
|
514 |
+
{
|
515 |
+
ImageViewHandler& tv = linked_view_handler ? *linked_view_handler : *this;
|
516 |
+
if( tv.target.x.max > tv.rview_max.x.max) tv.target.x -= tv.target.x.max - tv.rview_max.x.max;
|
517 |
+
if( tv.target.x.min < tv.rview_max.x.min) tv.target.x -= tv.target.x.min - tv.rview_max.x.min;
|
518 |
+
|
519 |
+
if( tv.target.y.max > tv.rview_max.y.max) tv.target.y -= tv.target.y.max - tv.rview_max.y.max;
|
520 |
+
if( tv.target.y.min < tv.rview_max.y.min) tv.target.y -= tv.target.y.min - tv.rview_max.y.min;
|
521 |
+
}
|
522 |
+
|
523 |
+
float ImageViewHandler::animate_factor = 1.0f / 2.0f;
|
524 |
+
ImageViewHandler* ImageViewHandler::to_link = 0;
|
525 |
+
|
526 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/image_view.cpp
ADDED
@@ -0,0 +1,227 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pangolin/display/image_view.h>
|
2 |
+
#include <pangolin/image/image_utils.h>
|
3 |
+
#include <pangolin/image/image_convert.h>
|
4 |
+
|
5 |
+
namespace pangolin
|
6 |
+
{
|
7 |
+
|
8 |
+
ImageView::ImageView(const std::string & title)
|
9 |
+
: pangolin::ImageViewHandler(title), offset_scale(0.0f, 1.0f), lastPressed(false), mouseReleased(false), mousePressed(false), overlayRender(true)
|
10 |
+
{
|
11 |
+
SetHandler(this);
|
12 |
+
}
|
13 |
+
|
14 |
+
ImageView::~ImageView()
|
15 |
+
{
|
16 |
+
}
|
17 |
+
|
18 |
+
void ImageView::Render()
|
19 |
+
{
|
20 |
+
LoadPending();
|
21 |
+
|
22 |
+
#ifndef HAVE_GLES
|
23 |
+
glPushAttrib(GL_DEPTH_BITS);
|
24 |
+
#endif
|
25 |
+
glDisable(GL_DEPTH_TEST);
|
26 |
+
|
27 |
+
Activate();
|
28 |
+
this->UpdateView();
|
29 |
+
this->glSetViewOrtho();
|
30 |
+
|
31 |
+
if(tex.IsValid())
|
32 |
+
{
|
33 |
+
if(offset_scale.first != 0.0 || offset_scale.second != 1.0)
|
34 |
+
{
|
35 |
+
pangolin::GlSlUtilities::OffsetAndScale(offset_scale.first, offset_scale.second);
|
36 |
+
}
|
37 |
+
else
|
38 |
+
{
|
39 |
+
glColor4f(1, 1, 1, 1);
|
40 |
+
}
|
41 |
+
|
42 |
+
this->glRenderTexture(tex);
|
43 |
+
pangolin::GlSlUtilities::UseNone();
|
44 |
+
}
|
45 |
+
|
46 |
+
if(overlayRender)
|
47 |
+
{
|
48 |
+
this->glRenderOverlay();
|
49 |
+
}
|
50 |
+
|
51 |
+
if(extern_draw_function)
|
52 |
+
{
|
53 |
+
extern_draw_function(*this);
|
54 |
+
}
|
55 |
+
|
56 |
+
#ifndef HAVE_GLES
|
57 |
+
glPopAttrib();
|
58 |
+
#endif
|
59 |
+
}
|
60 |
+
|
61 |
+
void ImageView::Mouse(View& view, pangolin::MouseButton button, int x, int y, bool pressed, int button_state)
|
62 |
+
{
|
63 |
+
ImageViewHandler::Mouse(view, button, x, y, pressed, button_state);
|
64 |
+
|
65 |
+
mouseReleased = (!pressed && lastPressed);
|
66 |
+
|
67 |
+
mousePressed = lastPressed = (pressed && button == pangolin::MouseButtonLeft);
|
68 |
+
}
|
69 |
+
|
70 |
+
void ImageView::Keyboard(View& view, unsigned char key, int x, int y, bool pressed)
|
71 |
+
{
|
72 |
+
if(key == 'a')
|
73 |
+
{
|
74 |
+
if(!tex.IsValid())
|
75 |
+
{
|
76 |
+
std::cerr << "ImageViewHandler does not contain valid texture." << std::endl;
|
77 |
+
return;
|
78 |
+
}
|
79 |
+
|
80 |
+
// compute scale
|
81 |
+
const bool have_selection = std::isfinite(GetSelection().Area()) && std::abs(GetSelection().Area()) >= 4;
|
82 |
+
const pangolin::XYRangef froi = have_selection ? GetSelection() : GetViewToRender();
|
83 |
+
|
84 |
+
// Download texture so that we can take min / max
|
85 |
+
pangolin::TypedImage img;
|
86 |
+
tex.Download(img);
|
87 |
+
offset_scale = pangolin::GetOffsetScale(img, pangolin::Round(froi), img.fmt);
|
88 |
+
}
|
89 |
+
else if(key == 'b')
|
90 |
+
{
|
91 |
+
if(!tex.IsValid())
|
92 |
+
{
|
93 |
+
std::cerr << "ImageViewHandler does not contain valid texture." << std::endl;
|
94 |
+
return;
|
95 |
+
}
|
96 |
+
|
97 |
+
// compute scale
|
98 |
+
const bool have_selection = std::isfinite(GetSelection().Area()) && std::abs(GetSelection().Area()) >= 4;
|
99 |
+
const pangolin::XYRangef froi = have_selection ? GetSelection() : GetViewToRender();
|
100 |
+
|
101 |
+
// Download texture so that we can take min / max
|
102 |
+
pangolin::TypedImage img;
|
103 |
+
tex.Download(img);
|
104 |
+
std::pair<float, float> mm = pangolin::GetMinMax(img, pangolin::Round(froi), img.fmt);
|
105 |
+
|
106 |
+
printf("Min / Max in Region: %f / %f\n", mm.first, mm.second);
|
107 |
+
}
|
108 |
+
else
|
109 |
+
{
|
110 |
+
pangolin::ImageViewHandler::Keyboard(view, key, x, y, pressed);
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
pangolin::GlTexture& ImageView::Tex() {
|
115 |
+
return tex;
|
116 |
+
}
|
117 |
+
|
118 |
+
ImageView& ImageView::SetImage(void* ptr, size_t w, size_t h, size_t pitch, pangolin::GlPixFormat img_fmt, bool delayed_upload )
|
119 |
+
{
|
120 |
+
const size_t pix_bytes =
|
121 |
+
pangolin::GlFormatChannels(img_fmt.glformat) * pangolin::GlDataTypeBytes(img_fmt.gltype);
|
122 |
+
|
123 |
+
const bool convert_first = (img_fmt.gltype == GL_DOUBLE);
|
124 |
+
|
125 |
+
if(delayed_upload || !pangolin::GetBoundWindow() || IsDevicePtr(ptr) || convert_first )
|
126 |
+
{
|
127 |
+
texlock.lock();
|
128 |
+
if(!convert_first) {
|
129 |
+
img_to_load = ManagedImage<unsigned char>(w,h,w*pix_bytes);
|
130 |
+
PitchedCopy((char*)img_to_load.ptr, img_to_load.pitch, (char*)ptr, pitch, w * pix_bytes, h);
|
131 |
+
img_fmt_to_load = img_fmt;
|
132 |
+
}else if(img_fmt.gltype == GL_DOUBLE) {
|
133 |
+
Image<double> double_image( (double*)ptr, w, h, pitch);
|
134 |
+
img_to_load.OwnAndReinterpret(ImageConvert<float>(double_image));
|
135 |
+
img_fmt_to_load = GlPixFormat::FromType<float>();
|
136 |
+
}else{
|
137 |
+
pango_print_warn("TextureView: Unable to display image.\n");
|
138 |
+
}
|
139 |
+
texlock.unlock();
|
140 |
+
return *this;
|
141 |
+
}
|
142 |
+
|
143 |
+
PANGO_ASSERT(pitch % pix_bytes == 0);
|
144 |
+
const size_t stride = pitch / pix_bytes;
|
145 |
+
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
146 |
+
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
147 |
+
|
148 |
+
// Initialise if it didn't already exist or the size was too small
|
149 |
+
if(!tex.tid || tex.width != (int)w || tex.height != (int)h ||
|
150 |
+
tex.internal_format != img_fmt.scalable_internal_format)
|
151 |
+
{
|
152 |
+
fmt = img_fmt;
|
153 |
+
SetDimensions(w, h);
|
154 |
+
SetAspect((float)w / (float)h);
|
155 |
+
tex.Reinitialise(w, h, img_fmt.scalable_internal_format, true, 0, img_fmt.glformat, img_fmt.gltype, ptr);
|
156 |
+
}
|
157 |
+
else
|
158 |
+
{
|
159 |
+
tex.Upload(ptr, img_fmt.glformat, img_fmt.gltype);
|
160 |
+
}
|
161 |
+
|
162 |
+
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
163 |
+
return *this;
|
164 |
+
}
|
165 |
+
|
166 |
+
ImageView& ImageView::SetImage(const pangolin::Image<unsigned char>& img, const pangolin::GlPixFormat& glfmt, bool delayed_upload )
|
167 |
+
{
|
168 |
+
return SetImage(img.ptr, img.w, img.h, img.pitch, glfmt, delayed_upload);
|
169 |
+
}
|
170 |
+
|
171 |
+
ImageView& ImageView::SetImage(const pangolin::TypedImage& img, bool delayed_upload )
|
172 |
+
{
|
173 |
+
return SetImage(img.ptr, img.w, img.h, img.pitch, pangolin::GlPixFormat(img.fmt), delayed_upload);
|
174 |
+
}
|
175 |
+
|
176 |
+
ImageView& ImageView::SetImage(const pangolin::GlTexture& texture)
|
177 |
+
{
|
178 |
+
// Initialise if it didn't already exist or the size was too small
|
179 |
+
if(!tex.tid || tex.width != texture.width || tex.height != texture.height ||
|
180 |
+
tex.internal_format != texture.internal_format)
|
181 |
+
{
|
182 |
+
SetDimensions(texture.width, texture.height);
|
183 |
+
SetAspect((float)texture.width / (float)texture.height);
|
184 |
+
tex.Reinitialise(texture.width, texture.height, texture.internal_format, true);
|
185 |
+
}
|
186 |
+
|
187 |
+
glCopyImageSubData(
|
188 |
+
texture.tid, GL_TEXTURE_2D, 0, 0, 0, 0, tex.tid, GL_TEXTURE_2D, 0, 0, 0, 0, tex.width, tex.height, 1);
|
189 |
+
|
190 |
+
return *this;
|
191 |
+
}
|
192 |
+
|
193 |
+
void ImageView::LoadPending()
|
194 |
+
{
|
195 |
+
if(img_to_load.ptr)
|
196 |
+
{
|
197 |
+
// Scoped lock
|
198 |
+
texlock.lock();
|
199 |
+
SetImage(img_to_load, img_fmt_to_load, false);
|
200 |
+
img_to_load.Deallocate();
|
201 |
+
texlock.unlock();
|
202 |
+
}
|
203 |
+
}
|
204 |
+
|
205 |
+
ImageView& ImageView::Clear()
|
206 |
+
{
|
207 |
+
tex.Delete();
|
208 |
+
return *this;
|
209 |
+
}
|
210 |
+
|
211 |
+
std::pair<float, float>& ImageView::GetOffsetScale() {
|
212 |
+
return offset_scale;
|
213 |
+
}
|
214 |
+
|
215 |
+
bool ImageView::MouseReleased() const {
|
216 |
+
return mouseReleased;
|
217 |
+
}
|
218 |
+
|
219 |
+
bool ImageView::MousePressed() const {
|
220 |
+
return mousePressed;
|
221 |
+
}
|
222 |
+
|
223 |
+
void ImageView::SetRenderOverlay(const bool& val) {
|
224 |
+
overlayRender = val;
|
225 |
+
}
|
226 |
+
|
227 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/pangolin_gl.cpp
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove, Richard Newcombe
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include "pangolin_gl.h"
|
29 |
+
#include <pangolin/display/display.h>
|
30 |
+
#include <pangolin/console/ConsoleView.h>
|
31 |
+
|
32 |
+
namespace pangolin
|
33 |
+
{
|
34 |
+
|
35 |
+
PangolinGl::PangolinGl()
|
36 |
+
: user_app(0), quit(false), mouse_state(0),activeDisplay(0)
|
37 |
+
{
|
38 |
+
}
|
39 |
+
|
40 |
+
PangolinGl::~PangolinGl()
|
41 |
+
{
|
42 |
+
// Free displays owned by named_managed_views
|
43 |
+
for(ViewMap::iterator iv = named_managed_views.begin(); iv != named_managed_views.end(); ++iv) {
|
44 |
+
delete iv->second;
|
45 |
+
}
|
46 |
+
named_managed_views.clear();
|
47 |
+
}
|
48 |
+
|
49 |
+
void PangolinGl::MakeCurrent()
|
50 |
+
{
|
51 |
+
SetCurrentContext(this);
|
52 |
+
if(window) {
|
53 |
+
window->MakeCurrent();
|
54 |
+
}
|
55 |
+
}
|
56 |
+
|
57 |
+
void PangolinGl::RenderViews()
|
58 |
+
{
|
59 |
+
Viewport::DisableScissor();
|
60 |
+
base.Render();
|
61 |
+
}
|
62 |
+
|
63 |
+
void PangolinGl::FinishFrame()
|
64 |
+
{
|
65 |
+
RenderViews();
|
66 |
+
|
67 |
+
while(screen_capture.size()) {
|
68 |
+
std::pair<std::string,Viewport> fv = screen_capture.front();
|
69 |
+
screen_capture.pop();
|
70 |
+
SaveWindowNow(fv.first, fv.second);
|
71 |
+
}
|
72 |
+
|
73 |
+
if(window) {
|
74 |
+
window->SwapBuffers();
|
75 |
+
window->ProcessEvents();
|
76 |
+
}
|
77 |
+
|
78 |
+
Viewport::DisableScissor();
|
79 |
+
}
|
80 |
+
|
81 |
+
void PangolinGl::SetOnRender(std::function<void ()> on_render) {
|
82 |
+
this->on_render = on_render;
|
83 |
+
}
|
84 |
+
|
85 |
+
void PangolinGl::Run() {
|
86 |
+
while (!quit) {
|
87 |
+
if (on_render) {
|
88 |
+
on_render();
|
89 |
+
}
|
90 |
+
FinishFrame();
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/pangolin_gl.h
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#pragma once
|
29 |
+
|
30 |
+
#include <pangolin/platform.h>
|
31 |
+
#include <pangolin/windowing/window.h>
|
32 |
+
|
33 |
+
#include <pangolin/display/view.h>
|
34 |
+
#include <pangolin/display/user_app.h>
|
35 |
+
#include <functional>
|
36 |
+
#include <memory>
|
37 |
+
|
38 |
+
#include <map>
|
39 |
+
#include <queue>
|
40 |
+
|
41 |
+
namespace pangolin
|
42 |
+
{
|
43 |
+
|
44 |
+
// Forward Declarations
|
45 |
+
class ConsoleView;
|
46 |
+
class GlFont;
|
47 |
+
|
48 |
+
typedef std::map<const std::string,View*> ViewMap;
|
49 |
+
typedef std::map<int,std::function<void(int)> > KeyhookMap;
|
50 |
+
|
51 |
+
struct PANGOLIN_EXPORT PangolinGl
|
52 |
+
{
|
53 |
+
PangolinGl();
|
54 |
+
~PangolinGl();
|
55 |
+
|
56 |
+
void Run();
|
57 |
+
|
58 |
+
void MakeCurrent();
|
59 |
+
void FinishFrame();
|
60 |
+
|
61 |
+
void RenderViews();
|
62 |
+
void PostRender();
|
63 |
+
|
64 |
+
void SetOnRender(std::function<void()> on_render);
|
65 |
+
|
66 |
+
// Callback for render loop
|
67 |
+
std::function<void()> on_render;
|
68 |
+
|
69 |
+
// Base container for displays
|
70 |
+
View base;
|
71 |
+
|
72 |
+
// Named views which are managed by pangolin (i.e. created / deleted by pangolin)
|
73 |
+
ViewMap named_managed_views;
|
74 |
+
|
75 |
+
// Optional user app
|
76 |
+
UserApp* user_app;
|
77 |
+
|
78 |
+
// Global keypress hooks
|
79 |
+
KeyhookMap keypress_hooks;
|
80 |
+
|
81 |
+
// State relating to interactivity
|
82 |
+
bool quit;
|
83 |
+
int mouse_state;
|
84 |
+
View* activeDisplay;
|
85 |
+
|
86 |
+
std::queue<std::pair<std::string,Viewport> > screen_capture;
|
87 |
+
|
88 |
+
std::shared_ptr<WindowInterface> window;
|
89 |
+
std::shared_ptr<GlFont> font;
|
90 |
+
|
91 |
+
std::unique_ptr<ConsoleView> console_view;
|
92 |
+
};
|
93 |
+
|
94 |
+
PangolinGl* GetCurrentContext();
|
95 |
+
void SetCurrentContext(PangolinGl* context);
|
96 |
+
void RegisterNewContext(const std::string& name, std::shared_ptr<PangolinGl> newcontext);
|
97 |
+
void DeleteContext(const std::string& name);
|
98 |
+
PangolinGl *FindContext(const std::string& name);
|
99 |
+
void SetCurrentContext(PangolinGl* newcontext);
|
100 |
+
|
101 |
+
}
|
102 |
+
|
third-party/DPVO/Pangolin/components/pango_display/src/process.cpp
ADDED
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove, Richard Newcombe
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <pangolin/display/process.h>
|
29 |
+
#include <pangolin/console/ConsoleView.h>
|
30 |
+
#include <pangolin/handler/handler.h>
|
31 |
+
#include "pangolin_gl.h"
|
32 |
+
|
33 |
+
namespace pangolin
|
34 |
+
{
|
35 |
+
namespace process
|
36 |
+
{
|
37 |
+
float last_x = 0;
|
38 |
+
float last_y = 0;
|
39 |
+
|
40 |
+
void Resize( int width, int height )
|
41 |
+
{
|
42 |
+
PangolinGl* context = GetCurrentContext();
|
43 |
+
|
44 |
+
Viewport win(0,0,width,height);
|
45 |
+
context->base.Resize(win);
|
46 |
+
}
|
47 |
+
|
48 |
+
void Keyboard(unsigned char key, int x, int y, bool pressed, KeyModifierBitmask /*key_modifiers*/)
|
49 |
+
{
|
50 |
+
PangolinGl* context = GetCurrentContext();
|
51 |
+
|
52 |
+
// Force coords to match OpenGl Window Coords
|
53 |
+
y = context->base.v.h - y;
|
54 |
+
|
55 |
+
if(pressed) {
|
56 |
+
// Check if global key hook exists
|
57 |
+
const KeyhookMap::iterator hook = context->keypress_hooks.find(key);
|
58 |
+
|
59 |
+
// Console receives all input when it is open
|
60 |
+
if( context->console_view && context->console_view->IsShown() ) {
|
61 |
+
context->console_view->Keyboard(*(context->console_view),key,x,y,true);
|
62 |
+
}else if(hook != context->keypress_hooks.end() ) {
|
63 |
+
hook->second(key);
|
64 |
+
} else if(context->activeDisplay && context->activeDisplay->handler) {
|
65 |
+
context->activeDisplay->handler->Keyboard(*(context->activeDisplay),key,x,y,true);
|
66 |
+
}
|
67 |
+
}else{
|
68 |
+
if(context->activeDisplay && context->activeDisplay->handler)
|
69 |
+
{
|
70 |
+
context->activeDisplay->handler->Keyboard(*(context->activeDisplay),key,x,y,false);
|
71 |
+
}
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
void Mouse( int button_raw, bool pressed, int x, int y, KeyModifierBitmask key_modifiers)
|
76 |
+
{
|
77 |
+
PangolinGl* context = GetCurrentContext();
|
78 |
+
|
79 |
+
// Force coords to match OpenGl Window Coords
|
80 |
+
y = context->base.v.h - y;
|
81 |
+
|
82 |
+
last_x = (float)x;
|
83 |
+
last_y = (float)y;
|
84 |
+
|
85 |
+
const MouseButton button = (MouseButton)(1 << (button_raw & 0xf) );
|
86 |
+
|
87 |
+
const bool fresh_input = ( (context->mouse_state & 7) == 0);
|
88 |
+
|
89 |
+
if( pressed ) {
|
90 |
+
context->mouse_state |= (button&7);
|
91 |
+
}else{
|
92 |
+
context->mouse_state &= ~(button&7);
|
93 |
+
}
|
94 |
+
|
95 |
+
#if defined(_WIN_)
|
96 |
+
context->mouse_state &= 0x0000ffff;
|
97 |
+
context->mouse_state |= (button_raw >> 4) << 16;
|
98 |
+
#endif
|
99 |
+
|
100 |
+
const int button_state = context->mouse_state | key_modifiers.mask();
|
101 |
+
|
102 |
+
if(fresh_input) {
|
103 |
+
context->base.handler->Mouse(context->base,button,x,y,pressed,button_state);
|
104 |
+
}else if(context->activeDisplay && context->activeDisplay->handler) {
|
105 |
+
context->activeDisplay->handler->Mouse(*(context->activeDisplay),button,x,y,pressed,button_state);
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
void MouseMotion( int x, int y, KeyModifierBitmask key_modifiers)
|
110 |
+
{
|
111 |
+
PangolinGl* context = GetCurrentContext();
|
112 |
+
|
113 |
+
// Force coords to match OpenGl Window Coords
|
114 |
+
y = context->base.v.h - y;
|
115 |
+
|
116 |
+
last_x = (float)x;
|
117 |
+
last_y = (float)y;
|
118 |
+
|
119 |
+
const int button_state = context->mouse_state | key_modifiers.mask();
|
120 |
+
|
121 |
+
if( context->activeDisplay)
|
122 |
+
{
|
123 |
+
if( context->activeDisplay->handler )
|
124 |
+
context->activeDisplay->handler->MouseMotion(*(context->activeDisplay),x,y,button_state);
|
125 |
+
}else{
|
126 |
+
context->base.handler->MouseMotion(context->base,x,y,button_state);
|
127 |
+
}
|
128 |
+
}
|
129 |
+
|
130 |
+
void PassiveMouseMotion(int x, int y, KeyModifierBitmask key_modifiers)
|
131 |
+
{
|
132 |
+
PangolinGl* context = GetCurrentContext();
|
133 |
+
|
134 |
+
// Force coords to match OpenGl Window Coords
|
135 |
+
y = context->base.v.h - y;
|
136 |
+
|
137 |
+
const int button_state = context->mouse_state | key_modifiers.mask();
|
138 |
+
context->base.handler->PassiveMouseMotion(context->base,x,y,button_state);
|
139 |
+
|
140 |
+
last_x = (float)x;
|
141 |
+
last_y = (float)y;
|
142 |
+
}
|
143 |
+
|
144 |
+
void SpecialInput(InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, KeyModifierBitmask key_modifiers)
|
145 |
+
{
|
146 |
+
PangolinGl* context = GetCurrentContext();
|
147 |
+
|
148 |
+
// Force coords to match OpenGl Window Coords
|
149 |
+
y = context->base.v.h - y;
|
150 |
+
|
151 |
+
const bool fresh_input = (context->mouse_state == 0);
|
152 |
+
const int button_state = context->mouse_state | key_modifiers.mask();
|
153 |
+
|
154 |
+
if(fresh_input) {
|
155 |
+
context->base.handler->Special(context->base,inType,x,y,p1,p2,p3,p4,button_state);
|
156 |
+
}else if(context->activeDisplay && context->activeDisplay->handler) {
|
157 |
+
context->activeDisplay->handler->Special(*(context->activeDisplay),inType,x,y,p1,p2,p3,p4,button_state);
|
158 |
+
}
|
159 |
+
}
|
160 |
+
}
|
161 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/view.cpp
ADDED
@@ -0,0 +1,508 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <stdexcept>
|
29 |
+
#include <pangolin/display/display.h>
|
30 |
+
#include <pangolin/display/view.h>
|
31 |
+
#include <pangolin/gl/gl.h>
|
32 |
+
#include <pangolin/gl/viewport.h>
|
33 |
+
#include <pangolin/gl/opengl_render_state.h>
|
34 |
+
#include <pangolin/platform.h>
|
35 |
+
|
36 |
+
#include "pangolin_gl.h"
|
37 |
+
|
38 |
+
namespace pangolin
|
39 |
+
{
|
40 |
+
|
41 |
+
const int panal_v_margin = 6;
|
42 |
+
|
43 |
+
int AttachAbs( int low, int high, Attach a)
|
44 |
+
{
|
45 |
+
if( a.unit == Pixel ) return low + (int)a.p;
|
46 |
+
if( a.unit == ReversePixel ) return high - (int)a.p;
|
47 |
+
return (int)(low + a.p * (high - low));
|
48 |
+
}
|
49 |
+
|
50 |
+
double AspectAreaWithinTarget(double target, double test)
|
51 |
+
{
|
52 |
+
if( test < target )
|
53 |
+
return test / target;
|
54 |
+
else
|
55 |
+
return target / test;
|
56 |
+
}
|
57 |
+
|
58 |
+
void View::Resize(const Viewport& p)
|
59 |
+
{
|
60 |
+
// Compute Bounds based on specification
|
61 |
+
v.l = AttachAbs(p.l,p.r(),left);
|
62 |
+
v.b = AttachAbs(p.b,p.t(),bottom);
|
63 |
+
int r = AttachAbs(p.l,p.r(),right);
|
64 |
+
int t = AttachAbs(p.b,p.t(),top);
|
65 |
+
|
66 |
+
// Make sure left and right, top and bottom are correct order
|
67 |
+
if( t < v.b ) std::swap(t,v.b);
|
68 |
+
if( r < v.l ) std::swap(r,v.l);
|
69 |
+
|
70 |
+
v.w = r - v.l;
|
71 |
+
v.h = t - v.b;
|
72 |
+
|
73 |
+
vp = v;
|
74 |
+
|
75 |
+
// Adjust based on aspect requirements
|
76 |
+
if( aspect != 0 )
|
77 |
+
{
|
78 |
+
const float current_aspect = (float)v.w / (float)v.h;
|
79 |
+
if( aspect > 0 )
|
80 |
+
{
|
81 |
+
// Fit to space
|
82 |
+
if( current_aspect < aspect )
|
83 |
+
{
|
84 |
+
//Adjust height
|
85 |
+
const int nh = (int)(v.w / aspect);
|
86 |
+
v.b += vlock == LockBottom ? 0 : (vlock == LockCenter ? (v.h-nh)/2 : (v.h-nh) );
|
87 |
+
v.h = nh;
|
88 |
+
}else if( current_aspect > aspect )
|
89 |
+
{
|
90 |
+
//Adjust width
|
91 |
+
const int nw = (int)(v.h * aspect);
|
92 |
+
v.l += hlock == LockLeft? 0 : (hlock == LockCenter ? (v.w-nw)/2 : (v.w-nw) );
|
93 |
+
v.w = nw;
|
94 |
+
}
|
95 |
+
}else{
|
96 |
+
// Overfit
|
97 |
+
double true_aspect = -aspect;
|
98 |
+
if( current_aspect < true_aspect )
|
99 |
+
{
|
100 |
+
//Adjust width
|
101 |
+
const int nw = (int)(v.h * true_aspect);
|
102 |
+
v.l += hlock == LockLeft? 0 : (hlock == LockCenter ? (v.w-nw)/2 : (v.w-nw) );
|
103 |
+
v.w = nw;
|
104 |
+
}else if( current_aspect > true_aspect )
|
105 |
+
{
|
106 |
+
//Adjust height
|
107 |
+
const int nh = (int)(v.w / true_aspect);
|
108 |
+
v.b += vlock == LockBottom ? 0 : (vlock == LockCenter ? (v.h-nh)/2 : (v.h-nh) );
|
109 |
+
v.h = nh;
|
110 |
+
}
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
ResizeChildren();
|
115 |
+
}
|
116 |
+
|
117 |
+
inline int zcompare(const View* lhs, const View* rhs)
|
118 |
+
{
|
119 |
+
return lhs->zorder < rhs->zorder;
|
120 |
+
}
|
121 |
+
|
122 |
+
void View::ResizeChildren()
|
123 |
+
{
|
124 |
+
if( layout == LayoutOverlay )
|
125 |
+
{
|
126 |
+
// Sort children into z-order
|
127 |
+
std::sort(views.begin(), views.end(), zcompare);
|
128 |
+
|
129 |
+
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv ) {
|
130 |
+
(*iv)->Resize(v);
|
131 |
+
}
|
132 |
+
}else if( layout == LayoutVertical )
|
133 |
+
{
|
134 |
+
// Allocate space incrementally
|
135 |
+
Viewport space = v.Inset(panal_v_margin);
|
136 |
+
int num_children = 0;
|
137 |
+
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv )
|
138 |
+
{
|
139 |
+
if (!(*iv)->show) continue;
|
140 |
+
num_children++;
|
141 |
+
if(scroll_offset >= num_children ) {
|
142 |
+
(*iv)->scroll_show = false;
|
143 |
+
}else{
|
144 |
+
(*iv)->scroll_show = true;
|
145 |
+
(*iv)->Resize(space);
|
146 |
+
space.h = (*iv)->v.b - panal_v_margin - space.b;
|
147 |
+
}
|
148 |
+
}
|
149 |
+
}else if(layout == LayoutHorizontal )
|
150 |
+
{
|
151 |
+
// Allocate space incrementally
|
152 |
+
const int margin = 8;
|
153 |
+
Viewport space = v.Inset(margin);
|
154 |
+
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv )
|
155 |
+
{
|
156 |
+
(*iv)->Resize(space);
|
157 |
+
space.w = (*iv)->v.l + margin + space.l;
|
158 |
+
}
|
159 |
+
}else if(layout == LayoutEqualVertical )
|
160 |
+
{
|
161 |
+
// Allocate vertical space equally
|
162 |
+
const size_t visiblechildren = NumVisibleChildren();
|
163 |
+
const float height = (float)v.h / (float)visiblechildren;
|
164 |
+
|
165 |
+
for( size_t i=0; i < visiblechildren; ++i) {
|
166 |
+
Viewport space(v.l, (GLint)(v.b+(visiblechildren-1-i)*height), v.w, (GLint)(height) );
|
167 |
+
VisibleChild(i).Resize(space);
|
168 |
+
}
|
169 |
+
}else if(layout == LayoutEqualHorizontal )
|
170 |
+
{
|
171 |
+
// Allocate vertical space equally
|
172 |
+
const size_t visiblechildren = NumVisibleChildren();
|
173 |
+
const float width = (float)v.w / (float)visiblechildren;
|
174 |
+
|
175 |
+
for( size_t i=0; i < visiblechildren; ++i) {
|
176 |
+
Viewport space( (GLint)(v.l+i*width), v.b, (GLint)width, v.h);
|
177 |
+
VisibleChild(i).Resize(space);
|
178 |
+
}
|
179 |
+
}else if(layout == LayoutEqual )
|
180 |
+
{
|
181 |
+
const size_t visiblechildren = NumVisibleChildren();
|
182 |
+
// TODO: Make this neater, and make fewer assumptions!
|
183 |
+
if( visiblechildren > 0 )
|
184 |
+
{
|
185 |
+
// This containers aspect
|
186 |
+
const double this_a = std::fabs(v.aspect());
|
187 |
+
|
188 |
+
// Use first child with fixed aspect for all children
|
189 |
+
double child_a = std::fabs(VisibleChild(0).aspect);
|
190 |
+
for(size_t i=1; (child_a==0) && i < visiblechildren; ++i ) {
|
191 |
+
child_a = std::fabs(VisibleChild(i).aspect);
|
192 |
+
}
|
193 |
+
|
194 |
+
if(child_a == 0) {
|
195 |
+
child_a = 1;
|
196 |
+
}
|
197 |
+
|
198 |
+
double a = visiblechildren*child_a;
|
199 |
+
double area = AspectAreaWithinTarget(this_a, a);
|
200 |
+
|
201 |
+
size_t cols = visiblechildren-1;
|
202 |
+
for(; cols > 0; --cols)
|
203 |
+
{
|
204 |
+
const size_t rows = visiblechildren / cols + (visiblechildren % cols == 0 ? 0 : 1);
|
205 |
+
const double na = cols * child_a / rows;
|
206 |
+
const double new_area = visiblechildren*AspectAreaWithinTarget(this_a,na)/(rows*cols);
|
207 |
+
if( new_area <= area )
|
208 |
+
break;
|
209 |
+
area = new_area;
|
210 |
+
a = na;
|
211 |
+
}
|
212 |
+
|
213 |
+
cols++;
|
214 |
+
const size_t rows = visiblechildren / cols + (visiblechildren % cols == 0 ? 0 : 1);
|
215 |
+
size_t cw, ch;
|
216 |
+
if( a > this_a )
|
217 |
+
{
|
218 |
+
cw = v.w / cols;
|
219 |
+
ch = (int)(cw / child_a); //v.h / rows;
|
220 |
+
}else{
|
221 |
+
ch = v.h / rows;
|
222 |
+
cw = (int)(ch * child_a);
|
223 |
+
}
|
224 |
+
|
225 |
+
for(size_t i=0; i< visiblechildren; ++i )
|
226 |
+
{
|
227 |
+
size_t c = i % cols;
|
228 |
+
size_t r = i / cols;
|
229 |
+
Viewport space( GLint(v.l + c*cw), GLint(v.t() - (r+1)*ch), GLint(cw), GLint(ch) );
|
230 |
+
VisibleChild(i).Resize(space);
|
231 |
+
}
|
232 |
+
}
|
233 |
+
}
|
234 |
+
|
235 |
+
}
|
236 |
+
|
237 |
+
void View::Render()
|
238 |
+
{
|
239 |
+
if(extern_draw_function && show && scroll_show) {
|
240 |
+
extern_draw_function(*this);
|
241 |
+
}
|
242 |
+
RenderChildren();
|
243 |
+
}
|
244 |
+
|
245 |
+
void View::RenderChildren()
|
246 |
+
{
|
247 |
+
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv )
|
248 |
+
{
|
249 |
+
if((*iv)->show && (*iv)->scroll_show) (*iv)->Render();
|
250 |
+
}
|
251 |
+
}
|
252 |
+
|
253 |
+
void View::Activate() const
|
254 |
+
{
|
255 |
+
v.Activate();
|
256 |
+
}
|
257 |
+
|
258 |
+
void View::ActivateAndScissor() const
|
259 |
+
{
|
260 |
+
vp.Scissor();
|
261 |
+
v.Activate();
|
262 |
+
}
|
263 |
+
|
264 |
+
void View::ActivateScissorAndClear() const
|
265 |
+
{
|
266 |
+
vp.Scissor();
|
267 |
+
v.Activate();
|
268 |
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
269 |
+
}
|
270 |
+
|
271 |
+
void View::Activate(const OpenGlRenderState& state ) const
|
272 |
+
{
|
273 |
+
v.Activate();
|
274 |
+
state.Apply();
|
275 |
+
}
|
276 |
+
|
277 |
+
void View::ActivateAndScissor(const OpenGlRenderState& state) const
|
278 |
+
{
|
279 |
+
vp.Scissor();
|
280 |
+
v.Activate();
|
281 |
+
state.Apply();
|
282 |
+
}
|
283 |
+
|
284 |
+
void View::ActivateScissorAndClear(const OpenGlRenderState& state ) const
|
285 |
+
{
|
286 |
+
vp.Scissor();
|
287 |
+
v.Activate();
|
288 |
+
state.Apply();
|
289 |
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
290 |
+
}
|
291 |
+
|
292 |
+
void View::ActivatePixelOrthographic() const
|
293 |
+
{
|
294 |
+
v.ActivatePixelOrthographic();
|
295 |
+
}
|
296 |
+
|
297 |
+
void View::ActivateIdentity() const
|
298 |
+
{
|
299 |
+
v.ActivateIdentity();
|
300 |
+
}
|
301 |
+
|
302 |
+
GLfloat View::GetClosestDepth(int x, int y, int radius) const
|
303 |
+
{
|
304 |
+
// TODO: Get to work on android
|
305 |
+
|
306 |
+
#ifdef _MSC_VER
|
307 |
+
// MSVC Requires fixed sized arrays on stack
|
308 |
+
radius = 5;
|
309 |
+
const int zl = (5*2+1);
|
310 |
+
#else
|
311 |
+
const int zl = (radius*2+1);
|
312 |
+
#endif
|
313 |
+
|
314 |
+
const int zsize = zl*zl;
|
315 |
+
GLfloat zs[zsize];
|
316 |
+
|
317 |
+
#ifndef HAVE_GLES
|
318 |
+
glReadBuffer(GL_FRONT);
|
319 |
+
glReadPixels(x-radius,y-radius,zl,zl,GL_DEPTH_COMPONENT,GL_FLOAT,zs);
|
320 |
+
#else
|
321 |
+
std::fill(zs,zs+zsize, 0.8);
|
322 |
+
#endif
|
323 |
+
|
324 |
+
const GLfloat mindepth = *(std::min_element(zs,zs+zsize));
|
325 |
+
return mindepth;
|
326 |
+
}
|
327 |
+
|
328 |
+
void View::GetObjectCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const
|
329 |
+
{
|
330 |
+
const GLint viewport[4] = {v.l,v.b,v.w,v.h};
|
331 |
+
const OpenGlMatrix proj = cam_state.GetProjectionMatrix();
|
332 |
+
const OpenGlMatrix mv = cam_state.GetModelViewMatrix();
|
333 |
+
glUnProject(winx, winy, winzdepth, mv.m, proj.m, viewport, &x, &y, &z);
|
334 |
+
}
|
335 |
+
|
336 |
+
void View::GetCamCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const
|
337 |
+
{
|
338 |
+
const GLint viewport[4] = {v.l, v.b, v.w, v.h};
|
339 |
+
const OpenGlMatrix proj = cam_state.GetProjectionMatrix();
|
340 |
+
#ifndef HAVE_GLES
|
341 |
+
glUnProject(winx, winy, winzdepth, Identity4d, proj.m, viewport, &x, &y, &z);
|
342 |
+
#else
|
343 |
+
glUnProject(winx, winy, winzdepth, Identity4f, proj.m, viewport, &x, &y, &z);
|
344 |
+
#endif
|
345 |
+
}
|
346 |
+
|
347 |
+
View& View::SetFocus()
|
348 |
+
{
|
349 |
+
GetCurrentContext()->activeDisplay = this;
|
350 |
+
return *this;
|
351 |
+
}
|
352 |
+
|
353 |
+
bool View::HasFocus() const
|
354 |
+
{
|
355 |
+
return GetCurrentContext()->activeDisplay == this;
|
356 |
+
}
|
357 |
+
|
358 |
+
View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right)
|
359 |
+
{
|
360 |
+
this->left = left;
|
361 |
+
this->top = top;
|
362 |
+
this->right = right;
|
363 |
+
this->bottom = bottom;
|
364 |
+
GetCurrentContext()->base.ResizeChildren();
|
365 |
+
return *this;
|
366 |
+
}
|
367 |
+
|
368 |
+
View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right, bool keep_aspect)
|
369 |
+
{
|
370 |
+
aspect = keep_aspect ? v.aspect() : 0;
|
371 |
+
SetBounds(top,bottom,left,right);
|
372 |
+
return *this;
|
373 |
+
}
|
374 |
+
|
375 |
+
View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right, double aspect)
|
376 |
+
{
|
377 |
+
this->aspect = aspect;
|
378 |
+
SetBounds(top,bottom,left,right);
|
379 |
+
return *this;
|
380 |
+
}
|
381 |
+
|
382 |
+
View& View::SetAspect(double aspect)
|
383 |
+
{
|
384 |
+
this->aspect = aspect;
|
385 |
+
GetCurrentContext()->base.ResizeChildren();
|
386 |
+
return *this;
|
387 |
+
}
|
388 |
+
|
389 |
+
View& View::SetLock(Lock horizontal, Lock vertical )
|
390 |
+
{
|
391 |
+
vlock = vertical;
|
392 |
+
hlock = horizontal;
|
393 |
+
return *this;
|
394 |
+
}
|
395 |
+
|
396 |
+
View& View::SetLayout(Layout l)
|
397 |
+
{
|
398 |
+
layout = l;
|
399 |
+
return *this;
|
400 |
+
}
|
401 |
+
|
402 |
+
|
403 |
+
View& View::AddDisplay(View& child)
|
404 |
+
{
|
405 |
+
// detach child from any other view, and add to this
|
406 |
+
std::vector<View*>::iterator f = std::find(
|
407 |
+
GetCurrentContext()->base.views.begin(), GetCurrentContext()->base.views.end(), &child
|
408 |
+
);
|
409 |
+
|
410 |
+
if( f != GetCurrentContext()->base.views.end() )
|
411 |
+
GetCurrentContext()->base.views.erase(f);
|
412 |
+
|
413 |
+
views.push_back(&child);
|
414 |
+
GetCurrentContext()->base.ResizeChildren();
|
415 |
+
return *this;
|
416 |
+
}
|
417 |
+
|
418 |
+
View& View::Show(bool show)
|
419 |
+
{
|
420 |
+
this->show = show;
|
421 |
+
GetCurrentContext()->base.ResizeChildren();
|
422 |
+
return *this;
|
423 |
+
}
|
424 |
+
|
425 |
+
void View::ToggleShow()
|
426 |
+
{
|
427 |
+
Show(!show);
|
428 |
+
}
|
429 |
+
|
430 |
+
bool View::IsShown() const
|
431 |
+
{
|
432 |
+
return show;
|
433 |
+
}
|
434 |
+
|
435 |
+
Viewport View::GetBounds() const
|
436 |
+
{
|
437 |
+
return Viewport( std::max(v.l, vp.l), std::max(v.b, vp.b), std::min(v.w, vp.w), std::min(v.h, vp.h) );
|
438 |
+
}
|
439 |
+
|
440 |
+
void View::SaveOnRender(const std::string& filename_hint)
|
441 |
+
{
|
442 |
+
SaveWindowOnRender(filename_hint, this->v.Intersect(this->vp));
|
443 |
+
}
|
444 |
+
|
445 |
+
void View::SaveRenderNow(const std::string& filename_hint)
|
446 |
+
{
|
447 |
+
SaveWindowNow(filename_hint, this->v);
|
448 |
+
}
|
449 |
+
|
450 |
+
View& View::operator[](size_t i)
|
451 |
+
{
|
452 |
+
return *views[i];
|
453 |
+
}
|
454 |
+
|
455 |
+
size_t View::NumChildren() const
|
456 |
+
{
|
457 |
+
return views.size();
|
458 |
+
}
|
459 |
+
|
460 |
+
size_t View::NumVisibleChildren() const
|
461 |
+
{
|
462 |
+
int numvis = 0;
|
463 |
+
for(std::vector<View*>::const_iterator i=views.begin(); i!=views.end(); ++i)
|
464 |
+
{
|
465 |
+
if((*i)->show) {
|
466 |
+
numvis++;
|
467 |
+
}
|
468 |
+
}
|
469 |
+
return numvis;
|
470 |
+
}
|
471 |
+
|
472 |
+
View& View::VisibleChild(size_t i)
|
473 |
+
{
|
474 |
+
size_t numvis = 0;
|
475 |
+
for(size_t v=0; v < views.size(); ++v ) {
|
476 |
+
if(views[v]->show) {
|
477 |
+
if( i == numvis ) {
|
478 |
+
return *views[v];
|
479 |
+
}
|
480 |
+
numvis++;
|
481 |
+
}
|
482 |
+
}
|
483 |
+
// Shouldn't get here
|
484 |
+
throw std::out_of_range("No such child.");
|
485 |
+
}
|
486 |
+
|
487 |
+
View* View::FindChild(int x, int y)
|
488 |
+
{
|
489 |
+
// Find in reverse order to mirror draw order
|
490 |
+
for( std::vector<View*>::const_reverse_iterator i = views.rbegin(); i != views.rend(); ++i )
|
491 |
+
if( (*i)->show && (*i)->GetBounds().Contains(x,y) )
|
492 |
+
return (*i);
|
493 |
+
return 0;
|
494 |
+
}
|
495 |
+
|
496 |
+
View& View::SetHandler(Handler* h)
|
497 |
+
{
|
498 |
+
handler = h;
|
499 |
+
return *this;
|
500 |
+
}
|
501 |
+
|
502 |
+
View& View::SetDrawFunction(const std::function<void(View&)>& drawFunc)
|
503 |
+
{
|
504 |
+
extern_draw_function = drawFunc;
|
505 |
+
return *this;
|
506 |
+
}
|
507 |
+
|
508 |
+
}
|
third-party/DPVO/Pangolin/components/pango_display/src/widgets.cpp
ADDED
@@ -0,0 +1,787 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <thread>
|
29 |
+
#include <mutex>
|
30 |
+
#include <iostream>
|
31 |
+
#include <iomanip>
|
32 |
+
|
33 |
+
#include <pangolin/display/widgets.h>
|
34 |
+
#include <pangolin/display/display.h>
|
35 |
+
#include <pangolin/display/default_font.h>
|
36 |
+
#include <pangolin/gl/gldraw.h>
|
37 |
+
#include <pangolin/var/varextra.h>
|
38 |
+
#include <pangolin/utils/file_utils.h>
|
39 |
+
|
40 |
+
#include "pangolin_gl.h"
|
41 |
+
|
42 |
+
|
43 |
+
using namespace std;
|
44 |
+
|
45 |
+
namespace pangolin
|
46 |
+
{
|
47 |
+
|
48 |
+
const static GLfloat colour_s1[4] = {0.2f, 0.2f, 0.2f, 1.0f};
|
49 |
+
const static GLfloat colour_s2[4] = {0.6f, 0.6f, 0.6f, 1.0f};
|
50 |
+
const static GLfloat colour_bg[4] = {0.9f, 0.9f, 0.9f, 1.0f};
|
51 |
+
const static GLfloat colour_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
52 |
+
const static GLfloat colour_tx[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
53 |
+
const static GLfloat colour_dn[4] = {1.0f, 0.7f, 0.7f, 1.0f};
|
54 |
+
|
55 |
+
// TODO: It doesn't look like this is doing anything meaningful right now...
|
56 |
+
std::mutex display_mutex;
|
57 |
+
|
58 |
+
// Render at (x,y) in window coordinates.
|
59 |
+
inline void DrawWindow(GlText& text, GLfloat x, GLfloat y, GLfloat z = 0.0)
|
60 |
+
{
|
61 |
+
// Backup viewport
|
62 |
+
GLint view[4];
|
63 |
+
glGetIntegerv(GL_VIEWPORT, view );
|
64 |
+
|
65 |
+
glMatrixMode(GL_PROJECTION);
|
66 |
+
glPushMatrix();
|
67 |
+
glMatrixMode(GL_MODELVIEW);
|
68 |
+
glPushMatrix();
|
69 |
+
|
70 |
+
DisplayBase().ActivatePixelOrthographic();
|
71 |
+
|
72 |
+
glTranslatef( std::floor(x), std::floor(y), z);
|
73 |
+
text.Draw();
|
74 |
+
|
75 |
+
// Restore viewport
|
76 |
+
glViewport(view[0],view[1],view[2],view[3]);
|
77 |
+
|
78 |
+
// Restore modelview / project matrices
|
79 |
+
glMatrixMode(GL_PROJECTION);
|
80 |
+
glPopMatrix();
|
81 |
+
glMatrixMode(GL_MODELVIEW);
|
82 |
+
glPopMatrix();
|
83 |
+
}
|
84 |
+
|
85 |
+
static inline int cb_height()
|
86 |
+
{
|
87 |
+
return (int)(default_font().Height() * 1.0);
|
88 |
+
}
|
89 |
+
|
90 |
+
static inline int tab_h()
|
91 |
+
{
|
92 |
+
return (int)(default_font().Height() * 1.4);
|
93 |
+
}
|
94 |
+
|
95 |
+
static inline float x_width()
|
96 |
+
{
|
97 |
+
return default_font().Text("x").Width();
|
98 |
+
}
|
99 |
+
|
100 |
+
template<typename T>
|
101 |
+
inline void MarkVarChangedByGui(VarValueT<T>& var)
|
102 |
+
{
|
103 |
+
var.Meta().gui_changed = true;
|
104 |
+
FlagVarChanged();
|
105 |
+
}
|
106 |
+
|
107 |
+
void glLine(GLfloat vs[4])
|
108 |
+
{
|
109 |
+
glEnableClientState(GL_VERTEX_ARRAY);
|
110 |
+
glVertexPointer(2, GL_FLOAT, 0, vs);
|
111 |
+
glDrawArrays( GL_LINE_STRIP, 0, 2);
|
112 |
+
glDisableClientState(GL_VERTEX_ARRAY);
|
113 |
+
}
|
114 |
+
|
115 |
+
void glRect(Viewport v)
|
116 |
+
{
|
117 |
+
GLfloat vs[] = { (float)v.l,(float)v.b,
|
118 |
+
(float)v.l,(float)v.t(),
|
119 |
+
(float)v.r(),(float)v.t(),
|
120 |
+
(float)v.r(),(float)v.b };
|
121 |
+
|
122 |
+
glEnableClientState(GL_VERTEX_ARRAY);
|
123 |
+
glVertexPointer(2, GL_FLOAT, 0, vs);
|
124 |
+
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
125 |
+
glDisableClientState(GL_VERTEX_ARRAY);
|
126 |
+
}
|
127 |
+
|
128 |
+
void glRect(Viewport v, int inset)
|
129 |
+
{
|
130 |
+
glRect(v.Inset(inset));
|
131 |
+
}
|
132 |
+
|
133 |
+
void DrawShadowRect(Viewport& v)
|
134 |
+
{
|
135 |
+
glColor4fv(colour_s2);
|
136 |
+
glDrawRectPerimeter((GLfloat)v.l, (GLfloat)v.b, (GLfloat)v.r(), (GLfloat)v.t());
|
137 |
+
}
|
138 |
+
|
139 |
+
void DrawShadowRect(Viewport& v, bool pushed)
|
140 |
+
{
|
141 |
+
const GLfloat* c1 = pushed ? colour_s1 : colour_s2;
|
142 |
+
const GLfloat* c2 = pushed ? colour_s2 : colour_s1;
|
143 |
+
|
144 |
+
GLfloat vs[] = { (float)v.l,(float)v.b,
|
145 |
+
(float)v.l,(float)v.t(),
|
146 |
+
(float)v.r(),(float)v.t(),
|
147 |
+
(float)v.r(),(float)v.b,
|
148 |
+
(float)v.l,(float)v.b };
|
149 |
+
|
150 |
+
glEnableClientState(GL_VERTEX_ARRAY);
|
151 |
+
glVertexPointer(2, GL_FLOAT, 0, vs);
|
152 |
+
glColor4fv(c1);
|
153 |
+
glDrawArrays(GL_LINE_STRIP, 0, 3);
|
154 |
+
|
155 |
+
glColor4fv(c2);
|
156 |
+
glDrawArrays(GL_LINE_STRIP, 2, 3);
|
157 |
+
glDisableClientState(GL_VERTEX_ARRAY);
|
158 |
+
|
159 |
+
}
|
160 |
+
|
161 |
+
Panel::Panel()
|
162 |
+
{
|
163 |
+
handler = &StaticHandlerScroll;
|
164 |
+
layout = LayoutVertical;
|
165 |
+
}
|
166 |
+
|
167 |
+
Panel::Panel(const std::string& auto_register_var_prefix)
|
168 |
+
: auto_register_var_prefix(auto_register_var_prefix)
|
169 |
+
{
|
170 |
+
handler = &StaticHandlerScroll;
|
171 |
+
layout = LayoutVertical;
|
172 |
+
|
173 |
+
// Register for notifications on var additions
|
174 |
+
var_added_connection = VarState::I().RegisterForVarEvents(
|
175 |
+
std::bind(&Panel::NewVarCallback,this,std::placeholders::_1),
|
176 |
+
true
|
177 |
+
);
|
178 |
+
}
|
179 |
+
|
180 |
+
void Panel::NewVarCallback(const VarState::Event& e)
|
181 |
+
{
|
182 |
+
const std::string name = e.var->Meta().full_name;
|
183 |
+
if(!StartsWith(name, auto_register_var_prefix))
|
184 |
+
return;
|
185 |
+
|
186 |
+
switch(e.action) {
|
187 |
+
case VarState::Event::Action::Added:
|
188 |
+
AddVariable(name, e.var);
|
189 |
+
break;
|
190 |
+
case VarState::Event::Action::Removed:
|
191 |
+
RemoveVariable(name);
|
192 |
+
break;
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
void Panel::AddVariable(const std::string& name, const std::shared_ptr<VarValueGeneric>& var)
|
197 |
+
{
|
198 |
+
const string& title = var->Meta().friendly;
|
199 |
+
|
200 |
+
display_mutex.lock();
|
201 |
+
|
202 |
+
ViewMap::iterator pnl = GetCurrentContext()->named_managed_views.find(name);
|
203 |
+
|
204 |
+
// Only add if a widget by the same name doesn't already exist
|
205 |
+
if( pnl == GetCurrentContext()->named_managed_views.end() )
|
206 |
+
{
|
207 |
+
View* nv = NULL;
|
208 |
+
if( !strcmp(var->TypeId(), typeid(bool).name()) ) {
|
209 |
+
nv = (var->Meta().flags & META_FLAG_TOGGLE) ? (View*)new Checkbox(title,var) : (View*)new Button(title,var);
|
210 |
+
} else if (!strcmp(var->TypeId(), typeid(double).name()) ||
|
211 |
+
!strcmp(var->TypeId(), typeid(float).name()) ||
|
212 |
+
!strcmp(var->TypeId(), typeid(int8_t).name()) ||
|
213 |
+
!strcmp(var->TypeId(), typeid(uint8_t).name()) ||
|
214 |
+
!strcmp(var->TypeId(), typeid(int16_t).name()) ||
|
215 |
+
!strcmp(var->TypeId(), typeid(uint16_t).name()) ||
|
216 |
+
!strcmp(var->TypeId(), typeid(int32_t).name()) ||
|
217 |
+
!strcmp(var->TypeId(), typeid(uint32_t).name()) ||
|
218 |
+
!strcmp(var->TypeId(), typeid(int64_t).name()) ||
|
219 |
+
!strcmp(var->TypeId(), typeid(uint64_t).name())
|
220 |
+
)
|
221 |
+
{
|
222 |
+
nv = new Slider(title, var);
|
223 |
+
} else if (!strcmp(var->TypeId(), typeid(std::function<void(void)>).name() ) ) {
|
224 |
+
nv = (View*)new FunctionButton(title, var);
|
225 |
+
}else if(var->str){
|
226 |
+
nv = new TextInput(title,var);
|
227 |
+
}
|
228 |
+
if(nv) {
|
229 |
+
GetCurrentContext()->named_managed_views[name] = nv;
|
230 |
+
views.push_back( nv );
|
231 |
+
ResizeChildren();
|
232 |
+
}
|
233 |
+
}
|
234 |
+
|
235 |
+
display_mutex.unlock();
|
236 |
+
}
|
237 |
+
|
238 |
+
void Panel::RemoveVariable(const std::string& name)
|
239 |
+
{
|
240 |
+
display_mutex.lock();
|
241 |
+
|
242 |
+
ViewMap::iterator pnl = GetCurrentContext()->named_managed_views.find(name);
|
243 |
+
|
244 |
+
if( pnl != GetCurrentContext()->named_managed_views.end() ) {
|
245 |
+
views.erase(std::remove(views.begin(), views.end(), pnl->second), views.end());
|
246 |
+
ResizeChildren();
|
247 |
+
|
248 |
+
delete pnl->second;
|
249 |
+
GetCurrentContext()->named_managed_views.erase(pnl);
|
250 |
+
}
|
251 |
+
|
252 |
+
display_mutex.unlock();
|
253 |
+
}
|
254 |
+
|
255 |
+
void Panel::Render()
|
256 |
+
{
|
257 |
+
#ifndef HAVE_GLES
|
258 |
+
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT | GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
|
259 |
+
#endif
|
260 |
+
glEnable (GL_BLEND);
|
261 |
+
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
262 |
+
|
263 |
+
DisplayBase().ActivatePixelOrthographic();
|
264 |
+
glDisable(GL_DEPTH_TEST);
|
265 |
+
glDisable(GL_LIGHTING);
|
266 |
+
glDisable(GL_SCISSOR_TEST);
|
267 |
+
glDisable(GL_LINE_SMOOTH);
|
268 |
+
glDisable( GL_COLOR_MATERIAL );
|
269 |
+
glLineWidth(1.0);
|
270 |
+
|
271 |
+
glColor4fv(colour_bg);
|
272 |
+
glRect(v);
|
273 |
+
DrawShadowRect(v);
|
274 |
+
|
275 |
+
RenderChildren();
|
276 |
+
|
277 |
+
#ifndef HAVE_GLES
|
278 |
+
glPopAttrib();
|
279 |
+
#else
|
280 |
+
glEnable(GL_LINE_SMOOTH);
|
281 |
+
glEnable(GL_DEPTH_TEST);
|
282 |
+
#endif
|
283 |
+
}
|
284 |
+
|
285 |
+
void Panel::ResizeChildren()
|
286 |
+
{
|
287 |
+
View::ResizeChildren();
|
288 |
+
}
|
289 |
+
|
290 |
+
|
291 |
+
View& CreatePanel(const std::string& name)
|
292 |
+
{
|
293 |
+
if(GetCurrentContext()->named_managed_views.find(name) != GetCurrentContext()->named_managed_views.end()) {
|
294 |
+
throw std::runtime_error("Panel already registered with this name.");
|
295 |
+
}
|
296 |
+
Panel * p = new Panel(name);
|
297 |
+
GetCurrentContext()->named_managed_views[name] = p;
|
298 |
+
GetCurrentContext()->base.views.push_back(p);
|
299 |
+
return *p;
|
300 |
+
}
|
301 |
+
|
302 |
+
Button::Button(string title, const std::shared_ptr<VarValueGeneric>& tv)
|
303 |
+
: Widget<bool>(title,tv), down(false)
|
304 |
+
{
|
305 |
+
top = 1.0; bottom = Attach::Pix(-tab_h());
|
306 |
+
left = 0.0; right = 1.0;
|
307 |
+
hlock = LockLeft;
|
308 |
+
vlock = LockBottom;
|
309 |
+
gltext = default_font().Text(title);
|
310 |
+
}
|
311 |
+
|
312 |
+
void Button::Mouse(View&, MouseButton button, int /*x*/, int /*y*/, bool pressed, int /*mouse_state*/)
|
313 |
+
{
|
314 |
+
if(button == MouseButtonLeft )
|
315 |
+
{
|
316 |
+
down = pressed;
|
317 |
+
if( !pressed ) {
|
318 |
+
var->Set(!var->Get());
|
319 |
+
MarkVarChangedByGui(*var);
|
320 |
+
}
|
321 |
+
}
|
322 |
+
}
|
323 |
+
|
324 |
+
void Button::Render()
|
325 |
+
{
|
326 |
+
glColor4fv(colour_fg );
|
327 |
+
glRect(v);
|
328 |
+
glColor4fv(colour_tx);
|
329 |
+
if(gltext.Text() != var->Meta().friendly) {
|
330 |
+
gltext = default_font().Text(var->Meta().friendly);
|
331 |
+
}
|
332 |
+
DrawWindow(gltext, raster[0],raster[1]-down);
|
333 |
+
DrawShadowRect(v, down);
|
334 |
+
}
|
335 |
+
|
336 |
+
void Button::ResizeChildren()
|
337 |
+
{
|
338 |
+
raster[0] = floor(v.l + (v.w-gltext.Width())/2.0f);
|
339 |
+
raster[1] = floor(v.b + (v.h-gltext.Height())/2.0f);
|
340 |
+
}
|
341 |
+
|
342 |
+
FunctionButton::FunctionButton(string title, const std::shared_ptr<VarValueGeneric> &tv)
|
343 |
+
: Widget<std::function<void(void)> >(title, tv), down(false)
|
344 |
+
{
|
345 |
+
top = 1.0; bottom = Attach::Pix(-tab_h());
|
346 |
+
left = 0.0; right = 1.0;
|
347 |
+
hlock = LockLeft;
|
348 |
+
vlock = LockBottom;
|
349 |
+
gltext = default_font().Text(title);
|
350 |
+
}
|
351 |
+
|
352 |
+
void FunctionButton::Mouse(View&, MouseButton button, int /*x*/, int /*y*/, bool pressed, int /*mouse_state*/)
|
353 |
+
{
|
354 |
+
if (button == MouseButtonLeft)
|
355 |
+
{
|
356 |
+
down = pressed;
|
357 |
+
if (!pressed) {
|
358 |
+
var->Get()();
|
359 |
+
MarkVarChangedByGui(*var);
|
360 |
+
}
|
361 |
+
}
|
362 |
+
}
|
363 |
+
|
364 |
+
void FunctionButton::Render()
|
365 |
+
{
|
366 |
+
glColor4fv(colour_fg);
|
367 |
+
glRect(v);
|
368 |
+
glColor4fv(colour_tx);
|
369 |
+
if(gltext.Text() != var->Meta().friendly) {
|
370 |
+
gltext = default_font().Text(var->Meta().friendly);
|
371 |
+
}
|
372 |
+
DrawWindow(gltext, raster[0],raster[1]-down);
|
373 |
+
DrawShadowRect(v, down);
|
374 |
+
}
|
375 |
+
|
376 |
+
void FunctionButton::ResizeChildren()
|
377 |
+
{
|
378 |
+
raster[0] = v.l + (v.w - gltext.Width()) / 2.0f;
|
379 |
+
raster[1] = v.b + (v.h - gltext.Height()) / 2.0f;
|
380 |
+
}
|
381 |
+
|
382 |
+
Checkbox::Checkbox(std::string title, const std::shared_ptr<VarValueGeneric> &tv)
|
383 |
+
: Widget<bool>(title,tv)
|
384 |
+
{
|
385 |
+
top = 1.0; bottom = Attach::Pix(-tab_h());
|
386 |
+
left = 0.0; right = 1.0;
|
387 |
+
hlock = LockLeft;
|
388 |
+
vlock = LockBottom;
|
389 |
+
handler = this;
|
390 |
+
gltext = default_font().Text(title);
|
391 |
+
}
|
392 |
+
|
393 |
+
void Checkbox::Mouse(View&, MouseButton button, int /*x*/, int /*y*/, bool pressed, int /*mouse_state*/)
|
394 |
+
{
|
395 |
+
if( button == MouseButtonLeft && pressed ) {
|
396 |
+
var->Set(!var->Get());
|
397 |
+
MarkVarChangedByGui(*var);
|
398 |
+
}
|
399 |
+
}
|
400 |
+
|
401 |
+
void Checkbox::ResizeChildren()
|
402 |
+
{
|
403 |
+
raster[0] = v.l + cb_height() + 4.0f;
|
404 |
+
raster[1] = v.b + (v.h-gltext.Height())/2.0f;
|
405 |
+
const int h = v.h;
|
406 |
+
const int t = (int)((h-cb_height()) / 2.0f);
|
407 |
+
vcb = Viewport(v.l,v.b+t,cb_height(),cb_height());
|
408 |
+
}
|
409 |
+
|
410 |
+
void Checkbox::Render()
|
411 |
+
{
|
412 |
+
const bool val = var->Get();
|
413 |
+
|
414 |
+
if( val )
|
415 |
+
{
|
416 |
+
glColor4fv(colour_dn);
|
417 |
+
glRect(vcb);
|
418 |
+
}
|
419 |
+
glColor4fv(colour_tx);
|
420 |
+
if(gltext.Text() != var->Meta().friendly) {
|
421 |
+
gltext = default_font().Text(var->Meta().friendly);
|
422 |
+
}
|
423 |
+
DrawWindow(gltext, raster[0], raster[1]);
|
424 |
+
DrawShadowRect(vcb, val);
|
425 |
+
}
|
426 |
+
|
427 |
+
inline bool IsIntegral(const char* typeidname)
|
428 |
+
{
|
429 |
+
// TODO: There must be a better way of doing this...
|
430 |
+
return !strcmp(typeidname, typeid(char).name()) ||
|
431 |
+
!strcmp(typeidname, typeid(short).name()) ||
|
432 |
+
!strcmp(typeidname, typeid(int).name()) ||
|
433 |
+
!strcmp(typeidname, typeid(long).name()) ||
|
434 |
+
!strcmp(typeidname, typeid(unsigned char).name()) ||
|
435 |
+
!strcmp(typeidname, typeid(unsigned short).name()) ||
|
436 |
+
!strcmp(typeidname, typeid(unsigned int).name()) ||
|
437 |
+
!strcmp(typeidname, typeid(unsigned long).name());
|
438 |
+
}
|
439 |
+
|
440 |
+
Slider::Slider(std::string title, const std::shared_ptr<VarValueGeneric> &tv)
|
441 |
+
: Widget<double>(title+":", tv), lock_bounds(true)
|
442 |
+
{
|
443 |
+
top = 1.0; bottom = Attach::Pix(-tab_h());
|
444 |
+
left = 0.0; right = 1.0;
|
445 |
+
hlock = LockLeft;
|
446 |
+
vlock = LockBottom;
|
447 |
+
handler = this;
|
448 |
+
logscale = (int)tv->Meta().logscale;
|
449 |
+
gltext = default_font().Text(title);
|
450 |
+
is_integral_type = IsIntegral(tv->TypeId());
|
451 |
+
}
|
452 |
+
|
453 |
+
void Slider::Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed)
|
454 |
+
{
|
455 |
+
if( pressed && var->Meta().range[0] < var->Meta().range[1] )
|
456 |
+
{
|
457 |
+
double val = !logscale ? var->Get() : log(var->Get());
|
458 |
+
|
459 |
+
if(key=='-' || key=='_' || key=='=' || key=='+') {
|
460 |
+
double inc = var->Meta().increment;
|
461 |
+
if (key == '-') inc *= -1.0;
|
462 |
+
if (key == '_') inc *= -0.1;
|
463 |
+
if (key == '+') inc *= 0.1;
|
464 |
+
const double newval = max(var->Meta().range[0], min(var->Meta().range[1], val + inc));
|
465 |
+
var->Set( logscale ? exp(newval) : newval );
|
466 |
+
MarkVarChangedByGui(*var);
|
467 |
+
}else if(key == 'r'){
|
468 |
+
Reset();
|
469 |
+
MarkVarChangedByGui(*var);
|
470 |
+
}else{
|
471 |
+
return;
|
472 |
+
}
|
473 |
+
}
|
474 |
+
}
|
475 |
+
|
476 |
+
void Slider::Mouse(View& view, MouseButton button, int x, int y, bool pressed, int mouse_state)
|
477 |
+
{
|
478 |
+
if(pressed)
|
479 |
+
{
|
480 |
+
// Wheel
|
481 |
+
if( button == MouseWheelUp || button == MouseWheelDown )
|
482 |
+
{
|
483 |
+
// Change scale around current value
|
484 |
+
const double frac = max(0.0,min(1.0,(double)(x - v.l)/(double)v.w));
|
485 |
+
double val = frac * (var->Meta().range[1] - var->Meta().range[0]) + var->Meta().range[0];
|
486 |
+
|
487 |
+
if (logscale)
|
488 |
+
{
|
489 |
+
if (val<=0)
|
490 |
+
val = std::numeric_limits<double>::min();
|
491 |
+
else
|
492 |
+
val = log(val);
|
493 |
+
}
|
494 |
+
|
495 |
+
const double scale = (button == MouseWheelUp ? 1.2 : 1.0 / 1.2 );
|
496 |
+
var->Meta().range[1] = val + (var->Meta().range[1] - val)*scale;
|
497 |
+
var->Meta().range[0] = val - (val - var->Meta().range[0])*scale;
|
498 |
+
}else{
|
499 |
+
lock_bounds = (button == MouseButtonLeft);
|
500 |
+
MouseMotion(view,x,y,mouse_state);
|
501 |
+
}
|
502 |
+
}else{
|
503 |
+
if(!lock_bounds)
|
504 |
+
{
|
505 |
+
double val = !logscale ? var->Get() : log(var->Get());
|
506 |
+
|
507 |
+
var->Meta().range[0] = min(var->Meta().range[0], val);
|
508 |
+
var->Meta().range[1] = max(var->Meta().range[1], val);
|
509 |
+
}
|
510 |
+
}
|
511 |
+
}
|
512 |
+
|
513 |
+
void Slider::MouseMotion(View&, int x, int /*y*/, int /*mouse_state*/)
|
514 |
+
{
|
515 |
+
if( var->Meta().range[0] != var->Meta().range[1] )
|
516 |
+
{
|
517 |
+
const double range = (var->Meta().range[1] - var->Meta().range[0]);
|
518 |
+
const double frac = (double)(x - v.l)/(double)v.w;
|
519 |
+
double val;
|
520 |
+
|
521 |
+
if( lock_bounds )
|
522 |
+
{
|
523 |
+
const double bfrac = max(0.0,min(1.0,frac));
|
524 |
+
val = bfrac * range + var->Meta().range[0] ;
|
525 |
+
}else{
|
526 |
+
val = frac * range + var->Meta().range[0];
|
527 |
+
}
|
528 |
+
|
529 |
+
if (logscale) {
|
530 |
+
val = exp(val);
|
531 |
+
}
|
532 |
+
|
533 |
+
if( is_integral_type ) {
|
534 |
+
val = std::round(val);
|
535 |
+
}
|
536 |
+
|
537 |
+
var->Set(val);
|
538 |
+
MarkVarChangedByGui(*var);
|
539 |
+
}
|
540 |
+
}
|
541 |
+
|
542 |
+
|
543 |
+
void Slider::ResizeChildren()
|
544 |
+
{
|
545 |
+
raster[0] = v.l + 2.0f;
|
546 |
+
raster[1] = v.b + (v.h-gltext.Height())/2.0f;
|
547 |
+
}
|
548 |
+
|
549 |
+
void Slider::Render()
|
550 |
+
{
|
551 |
+
const double val = var->Get();
|
552 |
+
|
553 |
+
if( var->Meta().range[0] != var->Meta().range[1] )
|
554 |
+
{
|
555 |
+
double rval = val;
|
556 |
+
if (logscale)
|
557 |
+
{
|
558 |
+
rval = log(val);
|
559 |
+
}
|
560 |
+
glColor4fv(colour_fg);
|
561 |
+
glRect(v);
|
562 |
+
glColor4fv(colour_dn);
|
563 |
+
const double norm_val = max(0.0,min(1.0,(rval - var->Meta().range[0]) / (var->Meta().range[1] - var->Meta().range[0])));
|
564 |
+
glRect(Viewport(v.l,v.b, (int)(v.w*norm_val),v.h));
|
565 |
+
DrawShadowRect(v);
|
566 |
+
}
|
567 |
+
|
568 |
+
glColor4fv(colour_tx);
|
569 |
+
if(gltext.Text() != var->Meta().friendly) {
|
570 |
+
gltext = default_font().Text(var->Meta().friendly);
|
571 |
+
}
|
572 |
+
DrawWindow(gltext, raster[0], raster[1]);
|
573 |
+
|
574 |
+
std::ostringstream oss;
|
575 |
+
oss << setprecision(4) << val;
|
576 |
+
string str = oss.str();
|
577 |
+
GlText glval = default_font().Text(str);
|
578 |
+
const float l = glval.Width() + 2.0f;
|
579 |
+
DrawWindow(glval, v.l + v.w - l, raster[1] );
|
580 |
+
}
|
581 |
+
|
582 |
+
|
583 |
+
TextInput::TextInput(std::string title, const std::shared_ptr<VarValueGeneric> &tv)
|
584 |
+
: Widget<std::string>(title+":", tv), can_edit(!(tv->Meta().flags & META_FLAG_READONLY)), do_edit(false)
|
585 |
+
{
|
586 |
+
top = 1.0; bottom = Attach::Pix(-2 * tab_h());
|
587 |
+
left = 0.0; right = 1.0;
|
588 |
+
hlock = LockLeft;
|
589 |
+
vlock = LockBottom;
|
590 |
+
handler = this;
|
591 |
+
sel[0] = -1;
|
592 |
+
sel[1] = -1;
|
593 |
+
gltext = default_font().Text(title);
|
594 |
+
}
|
595 |
+
|
596 |
+
void TextInput::Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed)
|
597 |
+
{
|
598 |
+
if(can_edit && pressed && do_edit)
|
599 |
+
{
|
600 |
+
const bool selection = sel[1] > sel[0] && sel[0] >= 0;
|
601 |
+
|
602 |
+
if(key == 13)
|
603 |
+
{
|
604 |
+
var->Set(edit);
|
605 |
+
MarkVarChangedByGui(*var);
|
606 |
+
|
607 |
+
do_edit = false;
|
608 |
+
sel[0] = sel[1] = -1;
|
609 |
+
}else if(key == 8) {
|
610 |
+
// backspace
|
611 |
+
if(selection)
|
612 |
+
{
|
613 |
+
edit = edit.substr(0,sel[0]) + edit.substr(sel[1],edit.length()-sel[1]);
|
614 |
+
sel[1] = sel[0];
|
615 |
+
}else{
|
616 |
+
if(sel[0] >0)
|
617 |
+
{
|
618 |
+
edit = edit.substr(0,sel[0]-1) + edit.substr(sel[0],edit.length()-sel[0]);
|
619 |
+
sel[0]--;
|
620 |
+
sel[1]--;
|
621 |
+
}
|
622 |
+
}
|
623 |
+
}else if(key == 127){
|
624 |
+
// delete
|
625 |
+
if(selection)
|
626 |
+
{
|
627 |
+
edit = edit.substr(0,sel[0]) + edit.substr(sel[1],edit.length()-sel[1]);
|
628 |
+
sel[1] = sel[0];
|
629 |
+
}else{
|
630 |
+
if(sel[0] < (int)edit.length())
|
631 |
+
{
|
632 |
+
edit = edit.substr(0,sel[0]) + edit.substr(sel[0]+1,edit.length()-sel[0]+1);
|
633 |
+
}
|
634 |
+
}
|
635 |
+
}else if(key == 230){
|
636 |
+
// right
|
637 |
+
sel[0] = min((int)edit.length(),sel[0]+1);
|
638 |
+
sel[1] = sel[0];
|
639 |
+
}else if(key == 228){
|
640 |
+
// left
|
641 |
+
sel[0] = max(0,sel[0]-1);
|
642 |
+
sel[1] = sel[0];
|
643 |
+
}else if(key == 234){
|
644 |
+
// home
|
645 |
+
sel[0] = sel[1] = 0;
|
646 |
+
}else if(key == 235){
|
647 |
+
// end
|
648 |
+
sel[0] = sel[1] = (int)edit.length();
|
649 |
+
}else if(key < PANGO_SPECIAL){
|
650 |
+
edit = edit.substr(0,sel[0]).append(1,key) + edit.substr(sel[1],edit.length()-sel[1]);
|
651 |
+
sel[1] = sel[0];
|
652 |
+
sel[0]++;
|
653 |
+
sel[1]++;
|
654 |
+
}
|
655 |
+
CalcVisibleEditPart();
|
656 |
+
}
|
657 |
+
}
|
658 |
+
|
659 |
+
void TextInput::Mouse(View& /*view*/, MouseButton button, int x, int /*y*/, bool pressed, int /*mouse_state*/)
|
660 |
+
{
|
661 |
+
if(can_edit && button != MouseWheelUp && button != MouseWheelDown )
|
662 |
+
{
|
663 |
+
|
664 |
+
if(do_edit)
|
665 |
+
{
|
666 |
+
const int sl = (int)gledit.Width() + vertical_margin;
|
667 |
+
const int rl = v.l + v.w - sl;
|
668 |
+
std::string edit_visible = edit.substr(edit_visible_part[0], edit_visible_part[1]);
|
669 |
+
int ep = (int)edit_visible.length();
|
670 |
+
|
671 |
+
if( x < rl )
|
672 |
+
{
|
673 |
+
ep = 0;
|
674 |
+
}else{
|
675 |
+
for( unsigned i=0; i<edit_visible.length(); ++i )
|
676 |
+
{
|
677 |
+
const int tl = (int)(rl + default_font().Text(edit_visible.substr(0,i)).Width());
|
678 |
+
if(x < tl+2)
|
679 |
+
{
|
680 |
+
ep = i;
|
681 |
+
break;
|
682 |
+
}
|
683 |
+
}
|
684 |
+
}
|
685 |
+
if(pressed)
|
686 |
+
{
|
687 |
+
sel[0] = sel[1] = ep + edit_visible_part[0];
|
688 |
+
}else{
|
689 |
+
sel[1] = ep + edit_visible_part[0];
|
690 |
+
}
|
691 |
+
|
692 |
+
if(sel[0] > sel[1])
|
693 |
+
std::swap(sel[0],sel[1]);
|
694 |
+
}else{
|
695 |
+
do_edit = !pressed;
|
696 |
+
sel[0] = 0;
|
697 |
+
sel[1] = (int)edit.length();
|
698 |
+
}
|
699 |
+
}
|
700 |
+
}
|
701 |
+
|
702 |
+
void TextInput::MouseMotion(View&, int x, int /*y*/, int /*mouse_state*/)
|
703 |
+
{
|
704 |
+
if(can_edit && do_edit)
|
705 |
+
{
|
706 |
+
const int sl = (int)gledit.Width() + 2;
|
707 |
+
const int rl = v.l + v.w - sl;
|
708 |
+
std::string edit_visible = edit.substr(edit_visible_part[0], edit_visible_part[1]);
|
709 |
+
int ep = (int)edit_visible.length();
|
710 |
+
|
711 |
+
if( x < rl )
|
712 |
+
{
|
713 |
+
ep = 0;
|
714 |
+
}else{
|
715 |
+
for( unsigned i=0; i<edit.length(); ++i )
|
716 |
+
{
|
717 |
+
const int tl = (int)(rl + default_font().Text(edit_visible.substr(0,i)).Width());
|
718 |
+
if(x < tl+2)
|
719 |
+
{
|
720 |
+
ep = i;
|
721 |
+
break;
|
722 |
+
}
|
723 |
+
}
|
724 |
+
}
|
725 |
+
|
726 |
+
sel[1] = ep + edit_visible_part[0];
|
727 |
+
}
|
728 |
+
}
|
729 |
+
|
730 |
+
|
731 |
+
void TextInput::ResizeChildren()
|
732 |
+
{
|
733 |
+
vertical_margin = (v.h-2.f*gltext.Height()) / 4.0f;
|
734 |
+
input_width = v.w - 2 * horizontal_margin;
|
735 |
+
int max_possible_chars = floor(input_width / x_width());
|
736 |
+
edit_visible_part[1] = max_possible_chars;
|
737 |
+
CalcVisibleEditPart();
|
738 |
+
}
|
739 |
+
|
740 |
+
void TextInput::CalcVisibleEditPart()
|
741 |
+
{
|
742 |
+
edit_visible_part[0] = 0;
|
743 |
+
|
744 |
+
if(default_font().Text(edit).Width() > input_width)
|
745 |
+
{
|
746 |
+
if(sel[1] >= 0 )
|
747 |
+
{
|
748 |
+
edit_visible_part[0] = max(0, sel[1] - edit_visible_part[1]);
|
749 |
+
}
|
750 |
+
}
|
751 |
+
};
|
752 |
+
|
753 |
+
void TextInput::Render()
|
754 |
+
{
|
755 |
+
if(!do_edit) edit = var->Get();
|
756 |
+
|
757 |
+
Viewport input_v(v.l,v.b,v.w,v.h / 2);
|
758 |
+
|
759 |
+
glColor4fv(colour_fg);
|
760 |
+
if(can_edit) glRect(input_v);
|
761 |
+
|
762 |
+
std::string edit_visible = edit.substr(edit_visible_part[0], edit_visible_part[1]);
|
763 |
+
gledit = default_font().Text(edit_visible);
|
764 |
+
|
765 |
+
const int sl = (int)gledit.Width() + horizontal_margin;
|
766 |
+
const int rl = v.l + v.w - sl;
|
767 |
+
|
768 |
+
if( do_edit && sel[0] >= 0)
|
769 |
+
{
|
770 |
+
const int tl = (int)(rl + default_font().Text(edit_visible.substr(0,sel[0] - edit_visible_part[0])).Width());
|
771 |
+
const int tr = (int)(rl + default_font().Text(edit_visible.substr(0,sel[1] - edit_visible_part[0])).Width());
|
772 |
+
glColor4fv(colour_dn);
|
773 |
+
glRect(Viewport(tl,input_v.b,tr-tl,input_v.h));
|
774 |
+
|
775 |
+
glColor4fv(colour_tx);
|
776 |
+
GLfloat caret[4] = {(float) tr, (float) input_v.b, (float) tr, (float) input_v.b + input_v.h};
|
777 |
+
glLine(caret);
|
778 |
+
}
|
779 |
+
|
780 |
+
glColor4fv(colour_tx);
|
781 |
+
DrawWindow(gltext, v.l + horizontal_margin, v.b + gltext.Height() + 3.f * vertical_margin);
|
782 |
+
|
783 |
+
DrawWindow(gledit, (GLfloat)(rl), input_v.b + vertical_margin);
|
784 |
+
if(can_edit) DrawShadowRect(input_v);
|
785 |
+
}
|
786 |
+
|
787 |
+
}
|
third-party/DPVO/Pangolin/components/pango_geometry/CMakeLists.txt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
get_filename_component(COMPONENT ${CMAKE_CURRENT_LIST_DIR} NAME)
|
2 |
+
|
3 |
+
find_package (Eigen3 REQUIRED QUIET)
|
4 |
+
message(STATUS "Found Eigen: '${EIGEN3_INCLUDE_DIRS}'")
|
5 |
+
target_compile_definitions(${COMPONENT} PUBLIC HAVE_EIGEN)
|
6 |
+
|
7 |
+
target_sources( ${COMPONENT}
|
8 |
+
PRIVATE
|
9 |
+
${CMAKE_CURRENT_LIST_DIR}/src/geometry.cpp
|
10 |
+
${CMAKE_CURRENT_LIST_DIR}/src/geometry_obj.cpp
|
11 |
+
${CMAKE_CURRENT_LIST_DIR}/src/geometry_ply.cpp
|
12 |
+
)
|
13 |
+
|
14 |
+
target_link_libraries(${COMPONENT} pango_core pango_image tinyobj Eigen3::Eigen)
|
15 |
+
target_include_directories(${COMPONENT} PUBLIC
|
16 |
+
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
|
17 |
+
$<INSTALL_INTERFACE:include>
|
18 |
+
)
|
19 |
+
install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include"
|
20 |
+
DESTINATION ${CMAKE_INSTALL_PREFIX}
|
21 |
+
)
|
third-party/DPVO/Pangolin/components/pango_geometry/include/pangolin/geometry/geometry.h
ADDED
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2014 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#ifndef PANGOLIN_GEOMETRY_H
|
29 |
+
#define PANGOLIN_GEOMETRY_H
|
30 |
+
|
31 |
+
#include <map>
|
32 |
+
#include <unordered_map>
|
33 |
+
#include <vector>
|
34 |
+
#include <variant>
|
35 |
+
#include <pangolin/image/typed_image.h>
|
36 |
+
|
37 |
+
#ifdef HAVE_EIGEN
|
38 |
+
#include <Eigen/Geometry>
|
39 |
+
#endif
|
40 |
+
|
41 |
+
namespace pangolin
|
42 |
+
{
|
43 |
+
|
44 |
+
struct Geometry
|
45 |
+
{
|
46 |
+
struct Element : public ManagedImage<uint8_t> {
|
47 |
+
Element() = default;
|
48 |
+
Element(Element&&) = default;
|
49 |
+
Element& operator=(Element&&) = default;
|
50 |
+
|
51 |
+
Element(size_t stride_bytes, size_t num_elements)
|
52 |
+
: ManagedImage<uint8_t>(stride_bytes, num_elements)
|
53 |
+
{}
|
54 |
+
|
55 |
+
using Attribute = std::variant<Image<float>,Image<uint32_t>,Image<uint16_t>,Image<uint8_t>>;
|
56 |
+
// "vertex", "rgb", "normal", "uv", "tris", "quads", ...
|
57 |
+
std::map<std::string, Attribute> attributes;
|
58 |
+
};
|
59 |
+
|
60 |
+
// Store vertices and attributes
|
61 |
+
std::map<std::string, Element> buffers;
|
62 |
+
// Stores index buffers for each sub-object
|
63 |
+
std::multimap<std::string, Element> objects;
|
64 |
+
// Stores pixmaps
|
65 |
+
std::map<std::string, TypedImage> textures;
|
66 |
+
};
|
67 |
+
|
68 |
+
pangolin::Geometry LoadGeometry(const std::string& filename);
|
69 |
+
|
70 |
+
#ifdef HAVE_EIGEN
|
71 |
+
inline Eigen::AlignedBox3f GetAxisAlignedBox(const Geometry& geom)
|
72 |
+
{
|
73 |
+
Eigen::AlignedBox3f box;
|
74 |
+
box.setEmpty();
|
75 |
+
|
76 |
+
for(const auto& b : geom.buffers) {
|
77 |
+
const auto& it_vert = b.second.attributes.find("vertex");
|
78 |
+
if(it_vert != b.second.attributes.end()) {
|
79 |
+
const Image<float>& vs = std::get<Image<float>>(it_vert->second);
|
80 |
+
for(size_t i=0; i < vs.h; ++i) {
|
81 |
+
const Eigen::Map<const Eigen::Vector3f> v(vs.RowPtr(i));
|
82 |
+
box.extend(v);
|
83 |
+
}
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
return box;
|
88 |
+
}
|
89 |
+
#endif
|
90 |
+
|
91 |
+
}
|
92 |
+
|
93 |
+
#endif // PANGOLIN_GEOMETRY_H
|
third-party/DPVO/Pangolin/components/pango_geometry/include/pangolin/geometry/geometry_obj.h
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2011 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <pangolin/geometry/geometry.h>
|
29 |
+
|
30 |
+
namespace pangolin {
|
31 |
+
|
32 |
+
pangolin::Geometry LoadGeometryObj(const std::string& filename);
|
33 |
+
|
34 |
+
}
|
third-party/DPVO/Pangolin/components/pango_geometry/include/pangolin/geometry/geometry_ply.h
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* This file is part of the Pangolin Project.
|
2 |
+
* http://github.com/stevenlovegrove/Pangolin
|
3 |
+
*
|
4 |
+
* Copyright (c) 2014 Steven Lovegrove
|
5 |
+
*
|
6 |
+
* Permission is hereby granted, free of charge, to any person
|
7 |
+
* obtaining a copy of this software and associated documentation
|
8 |
+
* files (the "Software"), to deal in the Software without
|
9 |
+
* restriction, including without limitation the rights to use,
|
10 |
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
* copies of the Software, and to permit persons to whom the
|
12 |
+
* Software is furnished to do so, subject to the following
|
13 |
+
* conditions:
|
14 |
+
*
|
15 |
+
* The above copyright notice and this permission notice shall be
|
16 |
+
* included in all copies or substantial portions of the Software.
|
17 |
+
*
|
18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20 |
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22 |
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23 |
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25 |
+
* OTHER DEALINGS IN THE SOFTWARE.
|
26 |
+
*/
|
27 |
+
|
28 |
+
#include <variant>
|
29 |
+
#include <pangolin/platform.h>
|
30 |
+
#include <pangolin/geometry/geometry.h>
|
31 |
+
#include <pangolin/geometry/geometry.h>
|
32 |
+
|
33 |
+
#include <fstream>
|
34 |
+
#include <vector>
|
35 |
+
#include <algorithm>
|
36 |
+
|
37 |
+
namespace pangolin
|
38 |
+
{
|
39 |
+
|
40 |
+
#define PLY_GROUP_LIST(m) m(PlyHeader) m(PlyFormat) m(PlyType)
|
41 |
+
#define PLY_HEADER_LIST(m) m(ply) m(format) m(comment) m(property) m(element) m(end_header)
|
42 |
+
#define PLY_FORMAT_LIST(m) m(ascii) m(binary_big_endian) m(binary_little_endian)
|
43 |
+
#define PLY_TYPE_LIST(m) m(char) m(uchar) m(short) m(ushort) m(int) m(uint) m(float) m(double) m(list) m(none)
|
44 |
+
#define PLY_CTYPE_LIST(m) m(int8_t) m(uint8_t) m(int16_t) m(uint16_t) m(int32_t) m(uint32_t) m(float) m(double) m(void*) m(void*)
|
45 |
+
|
46 |
+
// Define Enums / strings
|
47 |
+
enum PlyHeader {
|
48 |
+
#define FORMAT_ENUM(x) PlyHeader_##x,
|
49 |
+
PLY_HEADER_LIST(FORMAT_ENUM)
|
50 |
+
PlyHeaderSize
|
51 |
+
#undef FORMAT_ENUM
|
52 |
+
};
|
53 |
+
|
54 |
+
enum PlyFormat {
|
55 |
+
#define FORMAT_ENUM(x) PlyFormat_##x,
|
56 |
+
PLY_FORMAT_LIST(FORMAT_ENUM)
|
57 |
+
PlyFormatSize
|
58 |
+
#undef FORMAT_ENUM
|
59 |
+
};
|
60 |
+
|
61 |
+
enum PlyType {
|
62 |
+
#define FORMAT_ENUM(x) PlyType_##x,
|
63 |
+
PLY_TYPE_LIST(FORMAT_ENUM)
|
64 |
+
PlyTypeSize
|
65 |
+
#undef FORMAT_ENUM
|
66 |
+
};
|
67 |
+
const size_t PlyTypeSizeBytes[] = {
|
68 |
+
#define FORMAT_ENUM(x) sizeof(x),
|
69 |
+
PLY_CTYPE_LIST(FORMAT_ENUM)
|
70 |
+
#undef FORMAT_ENUM
|
71 |
+
};
|
72 |
+
|
73 |
+
struct PlyPropertyDetails
|
74 |
+
{
|
75 |
+
std::string name;
|
76 |
+
|
77 |
+
// Type of property
|
78 |
+
PlyType type;
|
79 |
+
|
80 |
+
// Type of list index if a list, or 0 otherwise.
|
81 |
+
PlyType list_index_type;
|
82 |
+
|
83 |
+
// Offset from element start
|
84 |
+
size_t offset_bytes;
|
85 |
+
|
86 |
+
// Number of items in the list. 1 if not a list. -1 if unknown.
|
87 |
+
int num_items;
|
88 |
+
|
89 |
+
bool isList() const {
|
90 |
+
return list_index_type > 0;
|
91 |
+
}
|
92 |
+
};
|
93 |
+
|
94 |
+
struct PlyElementDetails
|
95 |
+
{
|
96 |
+
std::string name;
|
97 |
+
int num_items;
|
98 |
+
int stride_bytes;
|
99 |
+
std::vector<PlyPropertyDetails> properties;
|
100 |
+
|
101 |
+
inline std::vector<PlyPropertyDetails>::iterator FindProperty(const std::string& name)
|
102 |
+
{
|
103 |
+
return std::find_if(properties.begin(), properties.end(),
|
104 |
+
[&name](const PlyPropertyDetails& p){ return p.name == name;}
|
105 |
+
);
|
106 |
+
}
|
107 |
+
};
|
108 |
+
|
109 |
+
struct PlyHeaderDetails
|
110 |
+
{
|
111 |
+
PlyFormat format;
|
112 |
+
std::string version;
|
113 |
+
std::vector<PlyElementDetails> elements;
|
114 |
+
|
115 |
+
inline std::vector<PlyElementDetails>::iterator FindElement(const std::string& name)
|
116 |
+
{
|
117 |
+
return std::find_if(elements.begin(), elements.end(),
|
118 |
+
[&name](const PlyElementDetails& el){ return el.name == name;}
|
119 |
+
);
|
120 |
+
}
|
121 |
+
};
|
122 |
+
|
123 |
+
void ParsePlyHeader(PlyHeaderDetails& ply, std::istream& is);
|
124 |
+
|
125 |
+
struct PlyBuffer
|
126 |
+
{
|
127 |
+
size_t index_size_bytes;
|
128 |
+
size_t element_item_size_bytes;
|
129 |
+
std::vector<unsigned char> data;
|
130 |
+
};
|
131 |
+
|
132 |
+
void ParsePlyAscii(pangolin::Geometry& /*geom*/, const PlyHeaderDetails& /*ply*/, std::istream& /*is*/);
|
133 |
+
|
134 |
+
// Convert Seperate "x","y","z" attributes into a single "vertex" attribute
|
135 |
+
void StandardizeXyzToVertex(pangolin::Geometry& geom);
|
136 |
+
|
137 |
+
// The Artec scanner saves with these attributes, for example
|
138 |
+
void StandardizeMultiTextureFaceToXyzuv(pangolin::Geometry& geom);
|
139 |
+
|
140 |
+
void Standardize(pangolin::Geometry& geom);
|
141 |
+
|
142 |
+
void ParsePlyLE(pangolin::Geometry& geom, PlyHeaderDetails& ply, std::istream& is);
|
143 |
+
|
144 |
+
void ParsePlyBE(pangolin::Geometry& /*geom*/, const PlyHeaderDetails& /*ply*/, std::istream& /*is*/);
|
145 |
+
|
146 |
+
void AttachAssociatedTexturesPly(pangolin::Geometry& geom, const std::string& filename);
|
147 |
+
|
148 |
+
pangolin::Geometry LoadGeometryPly(const std::string& filename);
|
149 |
+
|
150 |
+
}
|