This repository has been archived by the owner on Jan 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 134
/
README.html
720 lines (630 loc) · 45.5 KB
/
README.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8"/>
<title>Mesh Processing Library</title>
<meta name="description" content="C++ library and demonstration programs for reconstructing, simplifying, and optimizing surface triangle meshes."/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<style>
body { margin-left:10px; margin-bottom:20px; max-width:9in; }
code { font-family:courier; font-size:95%; }
.codeline { margin-left:30px; margin-top:2px; margin-bottom:9px; background-color:rgb(230,230,240); font-family:courier; font-size:95%; padding-left:10px; text-indent:-10px; }
h2 { margin-top:24px; }
h3 { margin-bottom:0px; }
p { margin-left:20px; margin-bottom:5px; margin-top:10px; }
ul { margin-top:7px; margin-left:15px; }
.thumbnail { border: 1px solid #7F7F7F; box-shadow: 0px 0px 6px 1px ThreeDShadow; margin: 0px 7px 2px 0px; }
.lcell { padding-top: 6px; padding-bottom: 6px; padding-left:20px; }
.rcell { padding-bottom: 15px; }
.title { margin-top: 0px; margin-bottom: 1px; font-weight: bold; }
.desc { color: rgb(55,96,146); font-family: verdana,sans-serif; font-size: 78%; }
.bins { padding-top: 4px; font-family:courier; font-size:95%; }
.demos { padding-top: 2px; font-family:courier; color: rgb(100,0,0); font-size:78%; padding-left:10px; text-indent:-10px; }
kbd { padding-left:2px; padding-right:2px; background-color:rgb(250,200,200); font-family:courier; font-size:90%; }
.sprogram { font-family: verdana,sans-serif; font-size: 75%; color: rgb(0,0,0); }
.sdemos { font-family: verdana,sans-serif; font-size: 85%; color: rgb(0,0,0); }
</style>
</head>
<body>
<h1>Mesh Processing Library</h1>
<h2>Overview</h2>
<p>This <a href="https://github.com/Microsoft/Mesh-processing-library">GitHub package</a>
contains a C++ library and several application programs that demonstrate mesh processing technologies
published in research papers at ACM SIGGRAPH in 1992–1998:</p>
<ul>
<li><em>surface reconstruction</em> (from unorganized, unoriented points)</li>
<li><em>mesh optimization</em></li>
<li><em>subdivision surface fitting</em></li>
<li><em>mesh simplification</em></li>
<li><em>progressive meshes</em> (level-of-detail representation)</li>
<li><em>geomorphs</em> (smooth transitions across LOD meshes)</li>
<li><em>view-dependent mesh refinement</em></li>
<li><em>smooth terrain LOD</em></li>
<li><em>progressive simplicial complexes</em></li>
<!--<li><em>optimized mesh traversal</em> (for transparent vertex caching)</li>-->
</ul>
<p>The source code follows modern C++11 style and is designed for cross-platform use.</p>
<h2>Version history</h2>
<p>2016-04-28 — initial release.</p>
<h2>Requirements / dependencies</h2>
<p>The source code can be compiled with Microsoft Visual Studio 2015 from the included solution (<code>*.sln</code>) and project (<code>*.vcxproj</code>) files, using either the Integrated Development Environment (IDE) or the <code>msbuild</code> command.</p>
<p>On Unix-based platforms (including Linux, Mac OS, and Cygwin),
the code can also be compiled using <code>gcc</code> and <code>clang</code> compilers
(and Visual Studio <code>cl</code> compiler)
using <code>Makefiles</code> designed for GNU <code>make</code>.</p>
<p>Reading/writing of images and videos is enabled using several options.
If available, image I/O can use <code>libpng</code>/<code>libjpeg</code> or Windows Imaging Component (WIC).
Video I/O can use Windows Media Foundation (WMF).
Across all platforms, if the command <a href="https://ffmpeg.org/"><code>ffmpeg</code></a>
is present in the <code>PATH</code>,
it is spawned in a piped subprocess for both image and video I/O.</p>
<p>On Mac OS X, it is necessary to install
<a href="https://www.xquartz.org/"><code>XQuartz</code></a> for <code>X11</code> support and
<a href="http://evermeet.cx/ffmpeg/"><code>ffmpeg</code></a> for image/video I/O.</p>
<h2>Code compilation</h2>
<h3>Compiling using the Microsoft Visual Studio IDE</h3>
<p>Open the <code>distrib.sln</code> file and build the solution (typically using the <code>"ReleaseMD - x64"</code> build configuration).
Executables are placed in the <code>bin</code>, <code>bin/debug</code>, <code>bin/Win32</code>, or <code>bin/Win32/debug</code> directory, depending on the build configuration (64-bit versus 32-bit, and release versus debug).</p>
<h3>Compiling using <code>msbuild</code></h3>
<p>Set the appropriate environment variables and run <code>msbuild</code>, e.g.:</p>
<div class="codeline">PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%</div>
<!--<div class="codeline">VisualStudioVersion=14.0</div>-->
<div class="codeline">msbuild -nologo -verbosity:minimal distrib.sln -maxcpucount:4 -p:PlatformToolset=v140 -p:platform=x64 -p:configuration=ReleaseMD</div>
<p>(Some alternatives are to set <code>platform</code> to <code>Win32</code>, or <code>configuration</code> to <code>DebugMD</code>, <code>Release</code>, or <code>Debug</code>; here <code>MD</code> stands for <a href="https://msdn.microsoft.com/en-us/library/aa278396%28v=vs.60%29.aspx">multithreaded DLL</a>.)
Executables are placed in the same target directory as in the IDE.</p>
<h3>Compiling using GNU <code>make</code></h3>
<p>The <code>CONFIG</code> environment variable determines
which <code>make/Makefile_config_*</code> definition file is loaded.
On Windows, <code>CONFIG</code> can be chosen among <code>{win, w32, cygwin, mingw, mingw32, clang}</code>,
defaulting to <code>win</code> if undefined.
On Unix-derived platforms (including Linux and Mac OS), <code>CONFIG=unix</code> is the unique and default setting.</p>
<p>For example, to build using the Microsoft <code>cl</code> compiler (Debug, with 8 parallel processes, placing <code>*.exe</code> into directory <code>bin/win</code>):</p>
<div class="codeline">make -j8</div>
<p>To build all programs (into either <code>bin/unix</code> or <code>bin/win</code>) and run all unit tests:</p>
<div class="codeline">make -j test</div>
<p>To build on Unix, forcing the use of the <code>gcc</code> compiler (the alternative is <code>clang</code>):</p>
<div class="codeline">make CC=gcc -j</div>
<p>To build just the main library using the <code>mingw gcc</code> compiler on Windows:</p>
<div class="codeline">make CONFIG=mingw -j libHh</div>
<p>To build the <code>Filtermesh</code> program (into <code>bin/clang</code>) using the <code>clang</code> compiler on Windows:</p>
<div class="codeline">make CONFIG=clang -j Filtermesh</div>
<p>To build all programs (into <code>bin/cygwin</code>) and run all demos using the <code>gcc</code> compiler under Cygwin:</p>
<div class="codeline">make CONFIG=cygwin -j demos</div>
<p>To clean up all files in all configurations:</p>
<div class="codeline">make CONFIG=all -j deepclean</div>
<p>Note that additional options such as debug/release, 32-bit/64-bit, and
compiler tool paths/parameters are set in the various <code>make/Makefile_*</code> files.
These need to be adjusted depending on the versions and installation paths of the tools.
For instance, the line
<code>"rel ?= 0"</code> in <code>make/Makefile_config_win</code> specifies a debug (non-release) build, and
<code>"$(call prepend_PATH,...)"</code> in <code>make/Makefile_base_vc</code> sets the compiler directory.</p>
<h2>Publications and associated programs/demos</h2>
<table id="publications">
<tr id="pub_recon">
<td class="lcell">
<img class="thumbnail" src="thumbnails/recon.red.jpg" width="240" height="148" alt=""/>
</td>
<td class="rcell">
<div class="title"><a href="http://hhoppe.com/proj/recon/">Surface reconstruction from unorganized points</a>.</div>
<div class="authors">Hugues Hoppe, Tony DeRose, Tom Duchamp, John McDonald, Werner Stuetzle.</div>
<div class="pub"><cite>ACM SIGGRAPH 1992 Proceedings</cite>, 71-78.</div>
<div class="desc">Signed-distance field estimated from a set of unoriented noisy points.</div>
<div class="bins"><span class="sprogram">programs:</span> <a href="#prog_recon">Recon</a></div>
<div class="demos"><span class="sdemos">demos:</span> create_recon_*.{sh,bat}, view_recon_*.{sh,bat}</div>
</td>
</tr>
<tr id="pub_meshopt">
<td class="lcell">
<img class="thumbnail" src="thumbnails/meshopt.red.jpg" width="240" height="125" alt=""/>
</td>
<td class="rcell">
<div class="title"><a href="http://hhoppe.com/proj/meshopt/">Mesh optimization</a>.</div>
<div class="authors">Hugues Hoppe, Tony DeRose, Tom Duchamp, John McDonald, Werner Stuetzle.</div>
<div class="pub"><cite>ACM SIGGRAPH 1993 Proceedings</cite>, 19-26.</div>
<div class="desc">Traversing the space of triangle meshes to optimize model fidelity and conciseness.</div>
<div class="bins"><span class="sprogram">programs:</span> <a href="#prog_Meshfit">Meshfit</a></div>
<div class="demos"><span class="sdemos">demos:</span> create_recon_*, view_recon_*, create_simplified_using_meshopt, view_simplified_using_meshopt</div>
</td>
</tr>
<tr id="pub_psrecon">
<td class="lcell">
<img class="thumbnail" src="thumbnails/psrecon.red.jpg" width="240" height="148" alt=""/>
</td>
<td class="rcell">
<div class="title"><a href="http://hhoppe.com/proj/psrecon/">Piecewise Smooth Surface Reconstruction</a>.</div>
<div class="authors">Hugues Hoppe, Tony DeRose, Tom Duchamp, Michael Halstead, Hubert Jin, John McDonald, Jean Schweitzer, Werner Stuetzle.</div>
<div class="pub"><cite>ACM SIGGRAPH 1994 Proceedings</cite>, 295-302.</div>
<div class="desc">Subdivision surfaces with sharp features, and their automatic creation by data fitting.</div>
<div class="bins"><span class="sprogram">programs:</span> <a href="#prog_Subdivfit">Subdivfit</a></div>
<div class="demos"><span class="sdemos">demos:</span> create_recon_cactus, view_recon_cactus</div>
</td>
</tr>
<tr id="pub_pm">
<td class="lcell">
<img class="thumbnail" src="thumbnails/pm.red.jpg" width="240" height="151" alt=""/>
</td>
<td class="rcell">
<div class="title"><a href="http://hhoppe.com/proj/pm/">Progressive meshes</a>.</div>
<div class="authors">Hugues Hoppe.</div>
<div class="pub"><cite>ACM SIGGRAPH 1996 Proceedings</cite>, 99-108.</div>
<div class="desc">Efficient, lossless, continuous-resolution representation of surface triangulations.</div>
<div class="bins"><span class="sprogram">programs:</span> <a href="#prog_MeshSimplify">MeshSimplify</a>, <a href="#prog_reverselines">reverselines</a>, <a href="#prog_Filterprog">Filterprog</a></div>
<div class="demos"><span class="sdemos">demos:</span> create_geomorphs, view_geomorphs</div>
</td>
</tr>
<tr id="pub_efficientpm">
<td class="lcell">
<img class="thumbnail" src="thumbnails/efficientpm.red.jpg" width="240" height="132" alt=""/>
</td>
<td class="rcell">
<div class="title"><a href="http://hhoppe.com/proj/efficientpm/">Efficient implementation of progressive meshes</a>.</div>
<div class="authors">Hugues Hoppe.</div>
<div class="pub"><cite>Computers & Graphics</cite>, 22(1), 1998, 27-36.</div>
<div class="desc">Progressive mesh data structures compatible with GPU vertex buffers.</div>
<div class="bins"><span class="sprogram">programs:</span> <a href="#prog_FilterPM">FilterPM</a>, <a href="#prog_G3dOGL">G3dOGL</a></div>
<div class="demos"><span class="sdemos">demos:</span> create_pm_club, view_pm_club, determine_approximation_error</div>
</td>
</tr>
<!--<tr id="pub_newqem">
<td class="lcell">
<img class="thumbnail" src="thumbnails/newqem.red.jpg" width="240" height="136" alt=""/>
</td>
<td class="rcell">
<div class="title"><a href="http://hhoppe.com/proj/newqem/">New quadric metric for simplifying meshes with appearance attributes</a>.</div>
<div class="authors">Hugues Hoppe.</div>
<div class="pub"><cite>IEEE Visualization 1999 Conference</cite>, 59-66.</div>
<div class="desc">Efficient simplification metric designed around correspondence in 3D space.</div>
<div class="bins"><span class="sprogram">programs:</span> <a href="#prog_MeshSimplify">MeshSimplify</a></div>
<div class="demos"><span class="sdemos">demos:</span> create_pm_gaudipark, view_pm_gaudipark</div>
</td>
</tr>-->
<tr id="pub_vdrpm">
<td class="lcell">
<img class="thumbnail" src="thumbnails/vdrpm.red.jpg" width="240" height="150" alt=""/>
</td>
<td class="rcell">
<div class="title"><a href="http://hhoppe.com/proj/vdrpm/">View-dependent refinement of progressive meshes</a>.</div>
<div class="authors">Hugues Hoppe.</div>
<div class="pub"><cite>ACM SIGGRAPH 1997 Proceedings</cite>, 189-198.</div>
<div class="desc">Lossless multiresolution structure for incremental local refinement/coarsening.</div>
<div class="bins"><span class="sprogram">programs:</span> <a href="#prog_FilterPM">FilterPM</a>, <a href="#prog_G3dOGL">G3dOGL</a></div>
<div class="demos"><span class="sdemos">demos:</span> create_sr_office, view_sr_office</div>
</td>
</tr>
<tr id="pub_svdlod">
<td class="lcell">
<img class="thumbnail" src="thumbnails/svdlod.red.jpg" width="240" height="149" alt=""/>
</td>
<td class="rcell">
<div class="title"><a href="http://hhoppe.com/proj/svdlod/">Smooth view-dependent level-of-detail control and its application to terrain rendering</a>.</div>
<div class="authors">Hugues Hoppe.</div>
<div class="pub"><cite>IEEE Visualization 1998 Conference</cite>, 35-42.</div>
<div class="desc">Visually smooth adaptation of mesh refinement using cascaded temporal geomorphs.</div>
<div class="bins"><span class="sprogram">programs:</span> <a href="#prog_StitchPM">StitchPM</a>, <a href="#prog_G3dOGL">G3dOGL</a></div>
<div class="demos"><span class="sdemos">demos:</span> create_terrain_hierarchy, view_terrain_hierarchy, create_sr_terrain, view_sr_terrain, view_gcanyon_*</div>
</td>
</tr>
<tr id="pub_psc">
<td class="lcell">
<img class="thumbnail" src="thumbnails/psc.red.jpg" width="240" height="167" alt=""/>
</td>
<td class="rcell">
<div class="title"><a href="http://hhoppe.com/proj/psc/">Progressive simplicial complexes</a>.</div>
<div class="authors">Jovan Popovic, Hugues Hoppe.</div>
<div class="pub"><cite>ACM SIGGRAPH 1997 Proceedings</cite>, 217-224.</div>
<div class="desc">Progressive encoding of both topology and geometry.</div>
<div class="bins"><span class="sprogram">programs:</span> <a href="#prog_G3dOGL">G3dOGL</a></div>
<div class="demos"><span class="sdemos">demos:</span> view_psc_drumset</div>
</td>
</tr>
<!--<tr id="pub_tvc">
<td class="lcell">
<img class="thumbnail" src="thumbnails/tvc.red.jpg" width="240" height="136" alt=""/>
</td>
<td class="rcell">
<div class="title"><a href="http://hhoppe.com/proj/tvc/">Optimization of mesh locality for transparent vertex caching</a>.</div>
<div class="authors">Hugues Hoppe.</div>
<div class="pub"><cite>ACM SIGGRAPH 1999 Proceedings</cite>, 269-276.</div>
<div class="desc">Face reordering for efficient GPU vertex cache, advocating a FIFO policy.</div>
<div class="bins"><span class="sprogram">programs:</span> <a href="#prog_MeshReorder">MeshReorder</a></div>
<div class="demos"><span class="sdemos">demos:</span> create_vertexcache_result, view_vertexcache_result</div>
</td>
</tr>-->
</table>
<h2>Demos</h2>
<p>After the code is compiled, the demos can be run as follows.</p>
<p>In Windows, create, view, and clean up all the results using the <code>batch</code> scripts</p>
<div class="codeline"><b>demos/all_demos_create_results.bat</b></div>
<div class="codeline"><b>demos/all_demos_view_results.bat</b></div>
<div class="codeline"><b>demos/all_demos_clean.bat</b></div>
<p>On Unix-based systems (e.g. Linux, Mac OS, Cygwin), either run the <code>bash</code> scripts</p>
<div class="codeline"><b>demos/all_demos_create_results.sh</b></div>
<div class="codeline"><b>demos/all_demos_view_results.sh</b></div>
<div class="codeline"><b>demos/all_demos_clean.sh</b></div>
<p>or alternatively (and faster), invoke <code>make</code> to create all results in parallel and then view them sequentially:</p>
<div class="codeline"><b>make</b> [CONFIG=<em>config</em>] -j demos # <em>config</em> ∈ {unix, win, w32, cygwin, mingw, mingw32, clang}</div>
<p>Note that pressing the <kbd>Esc</kbd> key closes any open program window.</p>
<h2>Filter programs</h2>
<p>All programs recognize the argument <code>--help</code> (or <code>-?</code>) to show their many options.</p>
<p>The programs <code>Filterimage</code>, <code>Filtermesh</code>, <code>Filtervideo</code>,
<code>FilterPM</code>, and <code>Filterframe</code> are all designed to:</p>
<ul>
<li>read media from <code>std::cin</code> (or from files or procedures specified as initial arguments),</li>
<li>perform operations specified by arguments, and</li>
<li>write media to <code>std::cout</code> (unless <code>-nooutput</code> is specified).</li>
</ul>
<p>For example, the command</p>
<div class="codeline" id="prog_Filterimage"><b>Filterimage</b> demos/data/gaudipark.png -rotate 20 -cropleft 100 -cropright 100 -filter lanczos6 -scaletox 100 -color 0 0 255 255 -boundary border -cropall -20 -setalpha 255 -color 0 0 0 0 -drawrectangle 30% 30% -30% -30% -gdfill -info -to jpg >gaudipark.new.jpg</div>
<ul>
<li>reads the specified image,</li>
<li>rotates it 20 degrees counterclockwise (with the default reflection boundary rule),</li>
<li>crops its left and right sides by 100 pixels,</li>
<li>scales it uniformly to a horizontal resolution of 100 pixels using a 6×6 Lanczos filter,</li>
<li>adds a 20-pixel blue border on all sides,</li>
<li>creates an undefined (<code>alpha=0</code>) rectangular region in the image center,</li>
<li>fills this region using gradient-domain smoothing,</li>
<li>outputs some statistics on pixel colors (to <code>std::cerr</code>), and</li>
<li>writes the result to a file under a different encoding.</li>
</ul>
<p>As another example, the command</p>
<div class="codeline" id="prog_FilterPM"><b>FilterPM</b> demos/data/standingblob.pm -info -nfaces 1000 -outmesh |<br/>
<b>Filtermesh</b> -info -signeddistcontour 60 -genus |<br/>
<b>G3dOGL</b> -key DmDe</div>
<ul>
<li>reads a <em>progressive mesh</em> stream to construct a mesh with 1000 faces,</li>
<li>reports statistics on the mesh geometry,</li>
<li>remeshes the surface as the zero isocontour of its signed-distance function on a 60<sup>3</sup> grid,</li>
<li>reports the new mesh genus, and</li>
<li>shows the result in an interactive viewer using the specified view parameters,</li>
<li>simulating keypresses <kbd>Dm</kbd> to enable flat shading and <kbd>De</kbd> to make mesh edges visible.</li>
</ul>
<p>The command</p>
<div class="codeline" id="prog_Filtermesh"><b>FilterPM</b> demos/data/spheretext.pm -nf 2000 -outmesh | <br/>
<b>Filtermesh</b> -angle 35 -silsubdiv -silsubdiv -mark | <br/>
<b>G3dOGL</b> -key DmDeDbJ---- -st demos/data/spheretext.s3d</div>
<ul>
<li>reads a 2000-face mesh, marks all edges with dihedral angle greater than 35 degrees as sharp,</li>
<li>applies two steps of adaptive subdivision near these sharp edges, and</li>
<li>shows the result flat-shaded (<kbd>Dm</kbd>), with edges (<kbd>De</kbd>), without backface culling (<kbd>Db</kbd>), spinning (<kbd>J</kbd>) somewhat slowly (<kbd>----</kbd>),</li>
<li>starting from the view parameters stored in the <code>spheretext.s3d</code> file.</li>
</ul>
<p>The command</p>
<div class="codeline" id="prog_Filtervideo"><b>Filtervideo</b> demos/data/palmtrees_small.mp4 -filter keys -scaleu 1.5 >palmtrees_small.scale1.5.mp4</div>
<ul>
<li>reads the video (entirely into memory),</li>
<li>uniformly scales the two spatial dimensions by a factor 1.5 using the Keys bicubic filter, and</li>
<li>saves the new video.</li>
</ul>
<p>The command</p>
<div class="codeline"><b>Filtervideo</b> demos/data/palmtrees_small.mp4 -info -trimbeg 4 -boundary clamped -trimend -20% -tscale 1.5 -framerate 150% -croprectangle 50% 50% 400 240 -gamma 1.5 -bitrate 10m |<br/>
<b>VideoViewer</b> demos/data/palmtrees_small.mp4 - -key =an</div>
<ul>
<li>reads the video (entirely into memory),</li>
<li>reports statistics on the color channels,</li>
<li>trims off 4 frames at the beginning,</li>
<li>adds repeated copies of the last frames (with length 20% of the video),</li>
<li>temporally scales the content by a factor of 1.5 and adjusts the framerate accordingly,</li>
<li>spatially crops a centered rectangle with width 400 pixels and height 240 pixels,</li>
<li>adjusts the color gamma,</li>
<li>sets the output bitrate to 10 megabits/sec, and</li>
<li>shows the result (<code>-</code> for <code>std::cin</code>) together with the original video in an interactive viewer,</li>
<li>with keypress <kbd>=</kbd> to scale the window size by 2, <kbd>a</kbd> to loop all (two) videos, and <kbd>n</kbd> to initially select the next (second) video.</li>
</ul>
<h2>Surface reconstruction</h2>
<h3 id="prog_recon">Recon</h3>
<p>This program reads a list of 3D (x, y, z) points assumed to be sampled near some unknown manifold surface,
and reconstructs an approximating triangle mesh. For example,</p>
<div class="codeline"><b>Recon</b> <demos/data/distcap.pts -samplingd 0.02 |<br/>
Filtermesh -genus -rmcomp 100 -fillholes 30 -triangulate -genus | tee distcap.recon.m |<br/>
G3dOGL -st demos/data/distcap.s3d -key DmDe</div>
<ul>
<li>reads the text file of points,</li>
<li>reconstructs a triangle mesh assuming a maximum sample spacing (δ+ρ in paper) of 2% of the bounding volume,</li>
<li>reports the genus of this initial mesh,</li>
<li>removes all connected components with fewer than 100 triangle faces,</li>
<li>fills and triangulates any hole bounded by 30 or fewer mesh edges,</li>
<li>reports the genus of the modified mesh,</li>
<li>saves it to a file, and</li>
<li>displays it interactively starting from a specified viewpoint, with flat-shaded faces (<kbd>Dm</kbd>)
and mesh edges (<kbd>De</kbd>).</li>
</ul>
<p>To show the progression of the Marching Cubes algorithm,</p>
<div class="codeline"><b>Recon</b> <demos/data/distcap.pts -samplingd 0.02 -what c |<br/>
Filtera3d -split 30 | G3dOGL -key DCDb -st demos/data/distcap_backside.s3d -terse</div>
<ul>
<li>selects the 'c' (cubes) output stream,</li>
<li>forces a frame refresh every 30 polygon primitive, and</li>
<li>shows the result without display-list caching (<kbd>DC</kbd>) and without backface culling (<kbd>Db</kbd>).</li>
</ul>
<p>To show a similar streaming reconstruction of the surface mesh,</p>
<div class="codeline"><b>Recon</b> <demos/data/distcap.pts -samplingd 0.02 -what m | Filtermesh -toa3d | <br/>
Filtera3d -split 30 | G3dOGL demos/data/distcap.pts -key DCDb -st demos/data/distcap_backside.s3d -terse -input -key _Jo</div>
<ul>
<li>selects the default 'm' (mesh) output stream,</li>
<li>converts the mesh to a stream of polygons, and</li>
<li>shows the points and streamed reconstruction with a slow (<kbd>_</kbd>) automatic rotation (<kbd>J</kbd>) about the object frame (<kbd>o</kbd>).</li>
</ul>
<p>The same program can also read a list of 2D (y, z) points to reconstruct an approximating curve:</p>
<div class="codeline"><b>Recon</b> <demos/data/curve1.pts -samplingd 0.06 -grid 30 |<br/>
Filtera3d -joinlines | tee curve1.a3d |<br/>
G3dOGL demos/data/curve1.pts -input -st demos/data/curve1.s3d</div>
<h3 id="prog_Meshfit">Meshfit</h3>
<p>Given an initial mesh and a list of 3D points, this program optimizes both the mesh connectivity and
geometry to improve the fit, i.e. minimizing the squared distances from the points to the surface.
For example,</p>
<div class="codeline"><b>Meshfit</b> -mfile distcap.recon.m -file demos/data/distcap.pts -crep 1e-5 -reconstruct |<br/>
tee distcap.opt.m | <b>G3dOGL</b> -st demos/data/distcap.s3d -key DmDe</div>
<ul>
<li>reads the previously reconstructed mesh and the original list of points,</li>
<li>applies an optimized sequence of perturbations to improve both the mesh connectivity and geometry,</li>
<li>using a specified tradeoff between mesh conciseness and fidelity (<var>c<sub>rep</sub></var>=1e-4 yields a coarser mesh),</li>
<li>saves the result to a file, and displays it interactively.</li>
</ul>
<p>The input points can also be sampled from an existing surface, e.g.:</p>
<div class="codeline"><b>Filtermesh</b> demos/data/blob5.orig.m -randpts 10000 -vertexpts |<br/>
<b>Meshfit</b> -mfile demos/data/blob5.orig.m -file - -crep 1e-6 -simplify |<br/>
G3dOGL -st demos/data/blob5.s3d -key DmDe</div>
<p>To view the real-time fitting optimization,</p>
<div class="codeline"><b>Meshfit</b> -mfile distcap.recon.m -file demos/data/distcap.pts -crep 1e-5 -outmesh - -record -reconstruct | G3dOGL -st demos/data/distcap.s3d -key DmDeDC -async -terse</div>
<ul>
<li>writes both the initial mesh and the stream of mesh modifications, and</li>
<li>displays the changing mesh asynchronously with display-list caching disabled (<kbd>DC</kbd>).</li>
</ul>
<h3 id="prog_Polyfit">Polyfit</h3>
<p>This related program performs a similar optimization of a 1D polyline (either open or closed) to fit a set of 2D points. For example,</p>
<div class="codeline"><b>Polyfit</b> -pfile curve1.a3d -file demos/data/curve1.pts -crep 3e-4 -spring 1 -reconstruct |<br/>
G3dOGL demos/data/curve1.pts -input -st demos/data/curve1.s3d</div>
<ul>
<li>reads the previously reconstructed polyline and the original list of points,</li>
<li>optimizes vertex positions and simplifies the number of line segments according to some representation cost, and</li>
<li>displays the result together with the original points.</li>
</ul>
<h3 id="prog_Subdivfit">Subdivfit</h3>
<p>In a subdivision surface representation, a coarse base mesh tagged with <em>sharp</em> edges defines a <em>piecewise smooth</em> surface as the limit of a subdivision process. Such a representation both improves geometric fidelity and leads to a more concise description.</p>
<div class="codeline"><b>Filtermesh</b> distcap.opt.m -angle 52 -mark |<br/>
<b>Subdivfit</b> -mfile - -file demos/data/distcap.pts -crep 1e-5 -csharp .2e-5 -reconstruct >distcap.sub0.m</div>
<ul>
<li>reads the previously optimized mesh and tags all edges with dihedral angle greater than 52 degrees as <em>sharp</em>,</li>
<li>loads this tagged mesh and the original list of points,</li>
<li>optimizes the mesh connectivity, geometry, and assignment of sharp edges to fit a <em>subdivision surface</em> to the points,</li>
<li>with a representation cost of <code>1e-5</code> per vertex and <code>.2e-5</code> per sharp edge, and</li>
<li>saves the resulting optimized base mesh to a file. (The overall process takes a few minutes.)</li>
</ul>
<p>To view the result,</p>
<div class="codeline"><b>G3dOGL</b> distcap.sub0.m <b>"Subdivfit</b> -mf distcap.sub0.m -nsub 2 -outn |<b>"</b> -st demos/data/distcap.s3d -key NDmDe -hwdelay 5 -hwkey N</div>
<ul>
<li>reads the base mesh together with a second mesh obtained by applying two iterations of subdivision,</li>
<li>shows the first mesh (<kbd>N</kbd>) with flat-shaded faces and edges (<kbd>DmDe</kbd>),</li>
<li>waits for 5 seconds, and displays the second mesh (<kbd>N</kbd>) as a smooth surface without edges.</li>
</ul>
<h3 id="prog_MeshDistance">MeshDistance</h3>
<p>This program computes measures of differences between two meshes.
It samples a dense set of points from a first mesh and computes the
projections of each point onto the closest point on a second mesh.</p>
<div class="codeline"><b>MeshDistance</b> -mfile distcap.recon.m -mfile distcap.opt.m -bothdir 1 -maxerror 1 -distance</div>
<ul>
<li><code>MeshDistance</code> loads the earlier results of mesh reconstruction and mesh optimization,</li>
<li>computes correspondences from points sampled on each mesh to the other mesh (in both directions), and</li>
<li>reports differences in geometric distance, color, and surface normals, using both L<sup>2</sup> (rms) and L<sup>∞</sup> (max) norms.</li>
</ul>
<h2>Mesh simplification</h2>
<p>Given a mesh, <code>MeshSimplify</code> applies a sequence of <em>edge collapse</em> operations to simplify it to a coarse <em>base mesh</em> while trying to best preserve the appearance of the original model. It supports many different simplification criteria, as well as face properties, edges tagged as sharp, and vertex and corner attributes
(<var>n<sub>x</sub></var>,<var>n<sub>y</sub></var>,<var>n<sub>z</sub></var> normals, <var>r</var>,<var>g</var>,<var>b</var> colors, and <var>u</var>,<var>v</var> texture coordinates).</p>
<p>For example,</p>
<div class="codeline" id="prog_MeshSimplify"><b>MeshSimplify</b> demos/data/club.orig.m -prog club.prog -simplify >club.base.m</div>
<ul>
<li>reads the original mesh and randomly samples points over its surface,</li>
<li>progressively simplifies it by examining point residual distances, while recording changes to a <code>*.prog</code> file, and</li>
<li>writes the resulting base mesh.</li>
</ul>
<p>The next step is to reverse the sequence of stored edge collapses, i.e. forming a progressive sequence of <em>vertex splits</em>:</p>
<div class="codeline" id="prog_reverselines"><b>reverselines</b> club.prog >club.rprog</div>
<p>We construct a concise <em>progressive mesh</em> by encoding the base mesh together with the sequence of vertex splits that exactly recover the original mesh:</p>
<div class="codeline" id="prog_Filterprog"><b>Filterprog</b> -fbase club.base.m -fprog club.rprog -pm_encode >club.pm</div>
<p>The complete process from the original mesh to the progressive mesh is implemented by the script call</p>
<div class="codeline">demos/bin/<b>meshtopm.</b><i>{sh,bat}</i> demos/data/club.orig.m >club.pm</div>
<p>Given a progressive mesh, we can interactively traverse its continuous levels of detail:</p>
<div class="codeline"><b>G3dOGL</b> -pm_mode club.pm -st demos/data/club.s3d -lightambient .4</div>
<ul>
<li>by dragging the left vertical slider using the left or right mouse button, and</li>
<li>toggling mesh edges using the <kbd>De</kbd> key sequence.</li>
</ul>
<p>We can also define geomorphs between discrete levels of detail, e.g.</p>
<div class="codeline"><b>FilterPM</b> club.pm -nfaces 2000 -geom_nfaces 3300 -geom_nfaces 5000 -geom_nfaces 8000 |<br/>
<b>G3dOGL</b> -st demos/data/club.s3d -key SPDeN -lightambient .5 -thickboundary 1 -video 101 - |
<b>VideoViewer</b> - -key m</div>
<ul>
<li>creates a geomorph between 2000 and 3300 faces, another between 3300 and 5000 faces, and similarly one more,</li>
<li>shows these in a viewer with the level-of-detail slider enabled (<kbd>S</kbd>),</li>
<li>selects all three geomorph meshes (<kbd>P</kbd>), enables mesh edges (<kbd>De</kbd>), selects the first mesh (<kbd>N</kbd>),</li>
<li>records a video of 101 frames while moving the LOD slider, and</li>
<li>shows the resulting video with mirror looping enabled (<kbd>m</kbd>).</li>
</ul>
<p>This example displays a progressive mesh after truncating all detail below 300 faces and above 10000 faces:</p>
<div class="codeline"><b>FilterPM</b> demos/data/standingblob.pm -nf 300 -truncate_prior -nf 10000 -truncate_beyond | <br/>
<b>G3dOGL</b> -pm_mode - -st demos/data/standingblob.s3d</div>
<p>As an example of simplifying meshes with appearance attributes,</p>
<!--<b>MeshSimplify</b> - -nfaces 4000 -minqem -norfac 0. -colfac 1. -neptfac 1e5 -simplify |<br/>-->
<div class="codeline"><b>Filterimage</b> demos/data/gaudipark.png -scaletox 200 -tomesh |<br/>
<b>MeshSimplify</b> - -nfaces 4000 -simplify |<br/>
G3dOGL -st demos/data/imageup.s3d -key De -lightambient 1 -lightsource 0</div>
<ul>
<li>forms a planar grid mesh whose 200×200 vertices have colors sampled from a downsampled image,</li>
<li>simplifies the mesh to 4000 faces while minimizing color differences,</li>
<!--<li>ignoring surface normals and giving high weight to boundary accuracy, and</li>-->
<li>shows the result with mesh edges (<kbd>De</kbd>) and only ambient lighting.</li>
</ul>
<h2>Selective view-dependent mesh refinement</h2>
<p>Within <code>demos/create_sr_office</code>, the script call</p>
<div class="codeline">demos/bin/<b>meshtopm.</b><i>{sh,bat}</i> demos/data/office.nf80000.orig.m -vsgeom >office.sr.pm</div>
<p>creates a progressive mesh
in which the simplified vertices are constrained to lie at their original positions (<code>-vsgeom</code>).
This enables selective refinement, demonstrated by</p>
<div class="codeline">G3dOGL -eyeob demos/data/unit_frustum.a3d -sr_mode office.sr.pm -st demos/data/office_srfig.s3d -key ,DnDeDoDb -lightambient .4 -sr_screen_thresh .002 -frustum_frac 2</div>
<p>The mesh is adaptively refined within the view frustum, shown as the inset rectangle (key <kbd>Do</kbd>) or in the top view (key <kbd>Dr</kbd>). Drag the mouse buttons to rotate, pan, and dolly the object.</p>
<h2>Terrain level-of-detail control</h2>
<p>Within <code>demos/create_sr_terrain.</code><i>{sh,bat}</i>,</p>
<div class="codeline">Filterimage demos/data/gcanyon_elev_crop.bw.png -tobw -elevation -step 6 -scalez 0.000194522 -removekinks -tomesh | <br/>
Filtermesh -assign_normals >gcanyon_sq200.orig.m</div>
<div class="codeline">demos/bin/meshtopm.<i>{sh,bat}</i> gcanyon_sq200.orig.m -vsgeom -terrain >gcanyon_sq200.pm</div>
<ul>
<li>converts an elevation image to a smoothed terrain grid mesh, and</li>
<li>simplifies it to create a selectively refinable mesh.</li>
</ul>
<p>Then, within <code>demos/view_sr_terrain.sh</code>,</p>
<div class="codeline">(common="-eyeob demos/data/unit_frustum.a3d -sr_mode gcanyon_sq200.pm -st demos/data/gcanyon_fly_v98.s3d -texturemap demos/data/gcanyon_color.1024.png -key DeDtDG -sr_screen_thresh .02292 -sr_gtime 64 -lightambient .5"; \<br/>
export G3D_REV_AUTO=1; \<br/>
G3dOGL $common -geom 800x820+100+10 -key "&O" -key ,o----J | <br/>
G3dOGL $common -geom 800x820+920+10 -async -killeof -input -key Dg)</div>
<ul>
<li>opens two synchronized side-by-side windows of the same texture mapped terrain,</li>
<li>in which the first windows shows the temporal pops resulting from instantaneous mesh operations,</li>
<li>whereas the second window shows the smooth appearance provided by runtime geomorphs (<kbd>Dg</kbd>).</li>
</ul>
<p>For large terrain meshes, we form a hierarchical progressive mesh by partitioning the terrain mesh into tiles,
simplifying each tile independently to form a progressive mesh,
stitching the progressive meshes together 2-by-2,
and recursively simplifying and merging at coarser pyramid levels.</p>
<p>An example is presented in <code>demos/create_terrain_hierarchy</code>.
It makes use of</p>
<div class="codeline" id="prog_StitchPM"><b>StitchPM</b> -rootname terrain.level0 -blockx 2 -blocky 2 -blocks 32 -stitch >terrain.level0.stitched.pm</div>
<p>to assemble each 2-by-2 set of progressive mesh tiles <code>terrain.level0.x{0,1}.y{0,1}.pm</code> at the finest level.</p>
<p>The script <code>demos/view_gcanyon_interactive</code> launches an interactive flythrough over a Grand Canyon terrain model,
using a progressive mesh precomputed from an original 4096×2048 height field.</p>
<p>Alternatively, <code>demos/view_gcanyon_frames</code> shows a real-time flythrough using a pre-recorded flight path, whereby keystroke commands embedded within the input stream automatically change viewing modes.</p>
<h2>Topology simplification</h2>
<p>The program <code>MinCycles</code> removes topological noise from a mesh
by iteratively pinching off the smallest nonseparating cycle of edges until a
specified criterion (cycle length, number of cycle edges, number of cycles, or mesh genus) is reached.</p>
<p>For example, within <code>demos/create_topologically_simplified.</code><i>{sh,bat}</i>,</p>
<div class="codeline" id="prog_MinCycles">FilterPM demos/data/office.pm -nf 200000 -outmesh | <br/>
<b>MinCycles</b> - -fraccyclelength 1.2 -maxcyclelen .10 -closecycles | <br/>
G3dOGL -st demos/data/office.s3d -key DeDEJ---- -thickboundary 0 -lightambient .9</div>
<ul>
<li>extracts a mesh of 200000 faces from a progressive mesh,</li>
<li>closes 46 topological handles to reduce the mesh genus from 50 to 4,</li>
<li>where the final remaining handle would require a nonseparating cycle of length greater than <code>.10</code></li>
<li>speeding up the process by identifying approximately shortest nonseparating cycles within a factor 1.2 of optimal, and</li>
<li>shows the resulting closed edge cycles (tagged as sharp) in blue.</li>
</ul>
<!--<h2>Optimized mesh traversal</h2>
<p>The program <code>MeshReorder</code> reorders the triangle faces (and optionally vertices) within a mesh so as to exploit a GPU vertex cache to minimize memory bandwidth and shading cost.</p>
<p>For example, within <code>demos/create_vertexcache_result</code>,</p>
<div class="codeline">Filtermesh demos/data/small_stell_dodecahedron4.nsub4.m -renumber -removeinfo | <br/>
<b>MeshReorder</b> - -fifo -cache_size 16 -analyze -meshify5 -color_corners 1 -analyze >small_stell_dodecahedron4.nsub4.vertexcache.m</div>
<div class="codeline">G3dOGL small_stell_dodecahedron4.nsub4.vertexcache.m -key DmDe -lightambient .70 -lightsource .35</div>
<ul>
<li>simulates traversal using a FIFO cache of 16 vertices and reports cache miss rates,</li>
<li>optimizes the triangle face ordering and re-simulates the cache behavior,</li>
<li>writes the mesh with corner colors that identify cache misses,</li>
<li>and finally views the result.</li>
</ul>-->
<h2 id="prog_G3dOGL">Geometry viewer</h2>
<p>The <code><b>G3dOGL</b></code> program shows interactive rasterized renderings of 3D (and 2D) geometry,
represented as</p>
<ul>
<li>streams of polygons/polylines/points (<code>*.a3d</code> format),</li>
<li>triangle meshes including geomorphs (<code>*.m</code>),</li>
<li>progressive meshes (<code>*.pm</code>),</li>
<li>encoded selectively refinable meshes (<code>*.srm</code>),</li>
<li>progressive simplicial complexes (<code>*.psc</code>), or</li>
<li>simple <code>*.ply</code> files.</li>
</ul>
<p>Please see the many examples presented earlier.
The viewer can also read <code>*.frame</code> elements to position the viewer and the objects in world space.
Elements of <code>*.a3d</code>, <code>*.m</code>, and <code>*.frame</code> streams can all be interleaved in a single input stream.</p>
<p>The viewer can take image snapshots (see <code>demos/create_rendered_mechpart_image</code>) and record videos (see <code>demos/create_rendered_mechpart_video</code>).</p>
<p>The mouse/keyboard UI controls include:</p>
<pre>
Mouse movements:
left mouse: rotate
middle mouse: pan
right mouse: dolly
shift-left: pan
shift-middle mouse: roll
shift-right mouse: zoom
(mouse movements are with respect to current object; see '0-9' below)
Important key strokes:
? : print complete list of keys
D?: print list of keys prefixed by 'D'
De: toggle edges
Ds: toggle shading of faces
Db: toggle backface culling
Dm: toggle Gouraud/flat shading
DP: save current window as an image file
DS: toggle show some sliders
S : toggle show some other sliders
j : jump to a default viewpoint
J : automatically rotate object
D/: edit viewpoint filename
, : read the viewpoint
. : save the viewpoint
0-9: select object (0=eye_frame, 1=first object, 2=second object...)
u : display/hide current object
N : select next object
P : select previous object
-=: decrease/increase the magnitude of all movements
f : toggle flying (usually with '0' eye selected)
</pre>
<p>To record a 6-second (360-frame) video of a rotating mesh and then view the resulting video:</p>
<div class="codeline">G3dOGL demos/data/standingblob.orig.m -st demos/data/standingblob.s3d -key iioJ -video 360 output_video.mp4</div>
<div class="codeline">VideoViewer output_video.mp4</div>
<p>The related program <code><b>G3dVec</b></code> shows wireframe hidden-line-removed renderings of <code>*.a3d</code> streams and <code>*.m</code> meshes.
It can write vector-based Postscript figures (see <code>demos/view_hidden_line_removed</code>).</p>
<p>In both programs, the keys <kbd>?</kbd> and <kbd>D?</kbd> show a list of available keyboard commands.</p>
<h2 id="prog_VideoViewer">Image/video viewer</h2>
<p>The <code><b>VideoViewer</b></code> program enables interactive viewing and simple editing of both images and videos.
Again, the key <kbd>?</kbd> shows a list of available keyboard commands.
Press <kbd>pageup</kbd>/<kbd>pagedown</kbd> to quickly browse through the videos and/or images in a directory.
Audio is not currently supported.</p>
<h2>File formats</h2>
<h3>Mesh (<code>*.m</code>)</h3>
<p>See the documentation at the end of <code>libHh/GMesh.h</code></p>
<p>A mesh is a set of vertices and faces. These in turn also define edges and corners.
Arbitrary string tuples can be associated with vertices, faces, edges, and corners.
Examples of string tuples:
<code>{normal=(.1 .2 .3) rgb=(1 1 1) matid=5 material="string"}</code>.
See the several <code>demos/data/*.m</code> files for examples of the mesh format.
Note that the indices of vertices and faces start at 1 instead of 0;
in hindsight that was a poor choice.</p>
<h3>Geometry stream (<code>*.a3d, *.pts</code>)</h3>
<p>See the documentation at the end of <code>libHh/A3dStream.h</code></p>
<p>The stream contains polygons, polylines, points, and control codes (like end-of-frame, end-of-input, change-of-object). Unlike in a mesh, these primitives do not share vertices. The stream can be either text or binary.</p>
<h3>Frame stream (<code>*.frame, *.s3d</code>)</h3>
<p>See the documentation at the end of <code>libHh/FrameIO.h</code></p>
<p>This text or binary format encodes a 4×3 affine transformation (plus an object id and a scalar field-of-view zoom).
It is used to record default viewing configurations, and sequences of frames for flythroughs.
It usually represents the linear transform from object space (or eye space) to world space. The stream can be either text or binary.</p>
<h3>Progressive mesh (<code>*.pm</code>)</h3>
<p>This is a binary representation that consists of a coarse base mesh and a sequence of vertex split records.</p>
<h3>Edge collapse / vertex split records (<code>*.prog, *.rprog</code>)</h3>
<p>These are temporary text files containing verbose information for a sequence of edge collapse / vertex split records used by MeshSimplify / reverselines / Filterprog to create a progressive mesh.</p>
<h2>Libraries</h2>
<p>The library <a href="./libHh"><code>libHh</code></a> contains the main reusable classes.
All files include <code>Hh.h</code> which sets up a common cross-platform environment.</p>
<p>The libraries <a href="./libHWin"><code>libHWin</code></a> and
<a href="./libHWX"><code>libHWX</code></a> define different implementations
of a simple windowing interface (class <code>HW</code>),
under <code>Win32</code> and <code>X Windows</code>, respectively.
Both implementations support <code>OpenGL</code> rendering.</p>
<h2>Code details</h2>
<p>The include file <code>libHh/<b>RangeOp</b>.h</code> defines many functions that act on <em>ranges</em>,
which are containers or views for which <code>begin()</code> and <code>end()</code> are defined.
For example, the function call <code>hh::fill(ar, 1.f)</code> assigns the value <code>1.f</code> to all
elements in the array named <code>ar</code>,
and the function call <code>hh::mean(matrix)</code> computes the average value of all entries in the
named <code>matrix</code>.</p>
<p>The debugging macro <code><b>SHOW</b>(expr)</code> outputs <code>expr = ...</code> on <code>std::cerr</code>
and also returns <code>expr</code>.
It also accepts multiple arguments in which case it returns <code>void</code>.
For example, <code>SHOW(min(1, 2), "hello", 3*2)</code> outputs the line <code>min(1, 2)=1 hello 3*2=6</code>.
Note the special treatment of literal string values.</p>
<p>Unicode strings are stored using <b>UTF-8</b> encoding into ordinary <code>std::string</code> variables.
The functions <code>hh::widen()</code> and <code>hh::narrow()</code> convert to and from the
<code>std::wstring</code> UTF-16 encodings used in <code>Win32</code> system calls.</p>
<p>All files use end-of-line encodings based on Unix <code>'\n'</code> LF (rather than DOS <code>'\r\n'</code> CR+LF). All streams are opened in binary mode. This allows text and binary to coexist in the same file.</p>
<h2>License</h2>
<p>See the file <a href="./license.txt"><code>./license.txt</code></a>.</p>
<p>This project has adopted the <a href="https://opensource.microsoft.com/codeofconduct/">Microsoft Open Source Code of Conduct</a>. For more information see the <a href="https://opensource.microsoft.com/codeofconduct/faq/">Code of Conduct FAQ</a> or contact <a href="mailto:opencode@microsoft.com">opencode@microsoft.com</a> with any additional questions or comments.</p>
</body>
</html>