Revision: 77313
          http://sourceforge.net/p/brlcad/code/77313
Author:   starseeker
Date:     2020-10-01 21:17:30 +0000 (Thu, 01 Oct 2020)
Log Message:
-----------
Not even Debian is maintaining a vds package anymore.  This one is an easy 
embedding in librt - strip down, clean up and move.

Modified Paths:
--------------
    brlcad/trunk/INSTALL
    brlcad/trunk/configure
    brlcad/trunk/doc/legal/embedded/CMakeLists.txt
    brlcad/trunk/doc/legal/other/CMakeLists.txt
    brlcad/trunk/misc/CMake/CMakeLists.txt
    brlcad/trunk/misc/win32-msvc/Dll/CMakeLists.txt
    brlcad/trunk/src/external/Creo/CMakeLists.txt
    brlcad/trunk/src/external/Cubit/CMakeLists.txt
    brlcad/trunk/src/external/Unigraphics/CMakeLists.txt
    brlcad/trunk/src/librt/CMakeLists.txt
    brlcad/trunk/src/other/CMakeLists.txt

Added Paths:
-----------
    brlcad/trunk/doc/legal/embedded/vds.txt
    brlcad/trunk/src/librt/vds/
    brlcad/trunk/src/librt/vds/COPYING
    brlcad/trunk/src/librt/vds/README
    brlcad/trunk/src/librt/vds/vds.c
    brlcad/trunk/src/librt/vds/vds.h

Removed Paths:
-------------
    brlcad/trunk/doc/legal/other/libvds.txt
    brlcad/trunk/misc/CMake/FindVDS.cmake
    brlcad/trunk/src/other/libvds/
    brlcad/trunk/src/other/libvds.dist

Modified: brlcad/trunk/INSTALL
===================================================================
--- brlcad/trunk/INSTALL        2020-10-01 21:08:02 UTC (rev 77312)
+++ brlcad/trunk/INSTALL        2020-10-01 21:17:30 UTC (rev 77313)
@@ -671,17 +671,6 @@
 Aliases:  ENABLE_SCL, ENABLE_STEP, ENABLE_STEP_CLASS_LIBRARIES
 
 
---- BRLCAD_VDS ---
-
-Option for enabling and disabling compilation of the libvds triangle
-simplification library provided with BRL-CAD's source code.  Default
-is AUTO, responsive to the toplevel BRLCAD_BUNDLED_LIBS option and
-testing first for a system version if BRLCAD_BUNDLED_LIBS is also
-AUTO.
-
-Aliases:  ENABLE_VDS
-
-
 --- BRLCAD_OSG ---
 
 Option for enabling and disabling compilation of the OpenSceneGraph

Modified: brlcad/trunk/configure
===================================================================
--- brlcad/trunk/configure      2020-10-01 21:08:02 UTC (rev 77312)
+++ brlcad/trunk/configure      2020-10-01 21:17:30 UTC (rev 77313)
@@ -174,10 +174,6 @@
                                   shift;;
      --disable-step-class-libraries)                options="$options 
-DBRLCAD_SC=SYSTEM";
                                   shift;;
-     --enable-vds)                options="$options -DBRLCAD_VDS=BUNDLED";
-                                  shift;;
-     --disable-vds)                options="$options -DBRLCAD_VDS=SYSTEM";
-                                  shift;;
      --enable-openscenegraph)                options="$options 
-DBRLCAD_OSG=BUNDLED";
                                   shift;;
      --disable-openscenegraph)                options="$options 
-DBRLCAD_OSG=SYSTEM";

Modified: brlcad/trunk/doc/legal/embedded/CMakeLists.txt
===================================================================
--- brlcad/trunk/doc/legal/embedded/CMakeLists.txt      2020-10-01 21:08:02 UTC 
(rev 77312)
+++ brlcad/trunk/doc/legal/embedded/CMakeLists.txt      2020-10-01 21:17:30 UTC 
(rev 77313)
@@ -70,6 +70,7 @@
   tkcon.txt
   tri_pt.txt
   uce_dirent.txt
+  vds.txt
   whereami.txt
   winmmap.txt
   x24.txt

Copied: brlcad/trunk/doc/legal/embedded/vds.txt (from rev 77312, 
brlcad/trunk/doc/legal/other/libvds.txt)
===================================================================
--- brlcad/trunk/doc/legal/embedded/vds.txt                             (rev 0)
+++ brlcad/trunk/doc/legal/embedded/vds.txt     2020-10-01 21:17:30 UTC (rev 
77313)
@@ -0,0 +1,31 @@
+This package was debianized by Marcelo E. Magallon <[email protected]> on
+Sun, 20 Feb 2000 12:49:36 +0100.
+
+It was downloaded from http://www.cs.virginia.edu/~dwc3q/code/
+
+Upstream Author(s): Dr. David Patrick Luebke <[email protected]>
+
+Copyright:
+
+  Copyright 1999 The University of Virginia.
+  All Rights Reserved.
+
+  Permission to use, copy, modify and distribute this software and its
+  documentation without fee, and without a written agreement, is
+  hereby granted, provided that the above copyright notice and the
+  complete text of this comment appear in all copies, and provided that
+  the University of Virginia and the original authors are credited in
+  any publications arising from the use of this software.
+
+  IN NO EVENT SHALL THE UNIVERSITY OF VIRGINIA
+  OR THE AUTHOR OF THIS SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT,
+  INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+  LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+  DOCUMENTATION, EVEN IF THE UNIVERSITY OF VIRGINIA AND/OR THE
+  AUTHOR OF THIS SOFTWARE HAVE BEEN ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGES.
+
+Note: the polyview example is not included with the BRL-CAD copy of libvds.
+
+file:/src/librt/vds/vds.h
+file:/src/librt/vds/vds.c

Modified: brlcad/trunk/doc/legal/other/CMakeLists.txt
===================================================================
--- brlcad/trunk/doc/legal/other/CMakeLists.txt 2020-10-01 21:08:02 UTC (rev 
77312)
+++ brlcad/trunk/doc/legal/other/CMakeLists.txt 2020-10-01 21:17:30 UTC (rev 
77313)
@@ -9,7 +9,6 @@
   libpng.txt
   libregex.txt
   libutahrle.txt
-  libvds.txt
   libz.txt
   linenoise.txt
   OpenNURBS.txt

Deleted: brlcad/trunk/doc/legal/other/libvds.txt
===================================================================
--- brlcad/trunk/doc/legal/other/libvds.txt     2020-10-01 21:08:02 UTC (rev 
77312)
+++ brlcad/trunk/doc/legal/other/libvds.txt     2020-10-01 21:17:30 UTC (rev 
77313)
@@ -1,28 +0,0 @@
-This package was debianized by Marcelo E. Magallon <[email protected]> on
-Sun, 20 Feb 2000 12:49:36 +0100.
-
-It was downloaded from http://www.cs.virginia.edu/~dwc3q/code/
-
-Upstream Author(s): Dr. David Patrick Luebke <[email protected]>
-
-Copyright:
-
-  Copyright 1999 The University of Virginia.
-  All Rights Reserved.
-
-  Permission to use, copy, modify and distribute this software and its
-  documentation without fee, and without a written agreement, is
-  hereby granted, provided that the above copyright notice and the
-  complete text of this comment appear in all copies, and provided that
-  the University of Virginia and the original authors are credited in
-  any publications arising from the use of this software.
-
-  IN NO EVENT SHALL THE UNIVERSITY OF VIRGINIA
-  OR THE AUTHOR OF THIS SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT,
-  INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
-  LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-  DOCUMENTATION, EVEN IF THE UNIVERSITY OF VIRGINIA AND/OR THE
-  AUTHOR OF THIS SOFTWARE HAVE BEEN ADVISED OF THE POSSIBILITY OF
-  SUCH DAMAGES.
-
-Note: the polyview example is not included with the BRL-CAD copy of libvds.

Modified: brlcad/trunk/misc/CMake/CMakeLists.txt
===================================================================
--- brlcad/trunk/misc/CMake/CMakeLists.txt      2020-10-01 21:08:02 UTC (rev 
77312)
+++ brlcad/trunk/misc/CMake/CMakeLists.txt      2020-10-01 21:17:30 UTC (rev 
77313)
@@ -46,7 +46,6 @@
   FindTCL.cmake
   FindUTAHRLE.cmake
   FindUUID.cmake
-  FindVDS.cmake
   FindWix.cmake
   FindX11.cmake
   FindXMLLINT.cmake

Deleted: brlcad/trunk/misc/CMake/FindVDS.cmake
===================================================================
--- brlcad/trunk/misc/CMake/FindVDS.cmake       2020-10-01 21:08:02 UTC (rev 
77312)
+++ brlcad/trunk/misc/CMake/FindVDS.cmake       2020-10-01 21:17:30 UTC (rev 
77313)
@@ -1,60 +0,0 @@
-#                   F I N D V D S . C M A K E
-# BRL-CAD
-#
-# Copyright (c) 2013-2020 United States Government as represented by
-# the U.S. Army Research Laboratory.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-#
-# 3. The name of the author may not be used to endorse or promote
-# products derived from this software without specific prior written
-# permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
-# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
-# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-###
-# - Find View Dependent Simplification library
-#
-# The following variables are set:
-#
-#  VDS_INCLUDE_DIRS   - where to find vds.h, etc.
-#  VDS_LIBRARIES      - List of libraries when using vds.
-#  VDS_FOUND          - True if vds found.
-
-find_path(VDS_INCLUDE_DIR vds.h)
-find_library(VDS_LIBRARY NAMES vds vdslib)
-
-include(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(VDS DEFAULT_MSG VDS_LIBRARY VDS_INCLUDE_DIR)
-
-IF (VDS_FOUND)
-  set(VDS_INCLUDE_DIRS ${VDS_INCLUDE_DIR})
-  set(VDS_LIBRARIES    ${VDS_LIBRARY})
-endif()
-
-# Local Variables:
-# tab-width: 8
-# mode: cmake
-# indent-tabs-mode: t
-# End:
-# ex: shiftwidth=2 tabstop=8

Modified: brlcad/trunk/misc/win32-msvc/Dll/CMakeLists.txt
===================================================================
--- brlcad/trunk/misc/win32-msvc/Dll/CMakeLists.txt     2020-10-01 21:08:02 UTC 
(rev 77312)
+++ brlcad/trunk/misc/win32-msvc/Dll/CMakeLists.txt     2020-10-01 21:17:30 UTC 
(rev 77313)
@@ -43,7 +43,6 @@
   regex-static
   librt-static
   libbrep-static
-  vds-static
   libwdb-static
   libnmg-static
   poly2tri-static
@@ -124,7 +123,6 @@
   regex-static
   librt-static
   libbrep-static
-  vds-static
   libwdb-static
   libnmg-static
   poly2tri-static

Modified: brlcad/trunk/src/external/Creo/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/external/Creo/CMakeLists.txt       2020-10-01 21:08:02 UTC 
(rev 77312)
+++ brlcad/trunk/src/external/Creo/CMakeLists.txt       2020-10-01 21:17:30 UTC 
(rev 77313)
@@ -38,7 +38,7 @@
   set(CREO_DEFS "-DPRO_MACHINE=36 -DPRO_OS=4 -DPRO_USE_VAR_ARGS 
-D_USING_V100_SDK71_")
 
   # BRL-CAD definitions
-  set(BRLCAD_DEFS "-DHAVE_CONFIG_H -DBRLCAD_DLL -DBRLCADBUILD -DBU_DLL_IMPORTS 
-DBN_DLL_IMPORTS -DNMG_DLL_IMPORTS -DBG_DLL_IMPORTS -DBREP_DLL_IMPORTS 
-DRT_DLL_IMPORTS -DWDB_DLL_IMPORTS -DTIE_DLL_IMPORTS -DDB5_DLL_IMPORTS 
-DVDS_DLL_IMPORTS -DGDIAM_DLL_IMPORTS -DON_DLL_IMPORTS -DLZ4_DLL_IMPORT=1")
+  set(BRLCAD_DEFS "-DHAVE_CONFIG_H -DBRLCAD_DLL -DBRLCADBUILD -DBU_DLL_IMPORTS 
-DBN_DLL_IMPORTS -DNMG_DLL_IMPORTS -DBG_DLL_IMPORTS -DBREP_DLL_IMPORTS 
-DRT_DLL_IMPORTS -DWDB_DLL_IMPORTS -DTIE_DLL_IMPORTS -DDB5_DLL_IMPORTS 
-DGDIAM_DLL_IMPORTS -DON_DLL_IMPORTS")
 
   # These settings are global to all the configs.
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CREO_DEFS} ${BRLCAD_DEFS}" CACHE 
STRING "" FORCE)
@@ -211,7 +211,6 @@
     openNURBS
     poly2tri
     regex_brl
-    vds
     z_brl1
     )
   set(BRLCAD_STATIC_LIBS)
@@ -371,9 +370,7 @@
     set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"WDB_DLL_IMPORTS")
     set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"TIE_DLL_IMPORTS")
     set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"GDIAM_DLL_IMPORTS")
-    set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"VDS_DLL_IMPORTS")
     set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"ON_DLL_IMPORTS")
-    set_property(TARGET creo-brl APPEND PROPERTY COMPILE_DEFINITIONS 
"LZ4_DLL_IMPORT=1")
   endif(HIDE_INTERNAL_SYMBOLS)
 
   # Distcheck file list

Modified: brlcad/trunk/src/external/Cubit/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/external/Cubit/CMakeLists.txt      2020-10-01 21:08:02 UTC 
(rev 77312)
+++ brlcad/trunk/src/external/Cubit/CMakeLists.txt      2020-10-01 21:17:30 UTC 
(rev 77313)
@@ -36,10 +36,8 @@
     set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"WDB_DLL_IMPORTS")
     set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"TIE_DLL_IMPORTS")
     set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"GDIAM_DLL_IMPORTS")
-    set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"VDS_DLL_IMPORTS")
     set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"ON_DLL_IMPORTS")
     set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"TINYCTHREAD_DLL_IMPORTS")
-    set_property(TARGET g-sat APPEND PROPERTY COMPILE_DEFINITIONS 
"LZ4_DLL_IMPORT=1")
   endif(HIDE_INTERNAL_SYMBOLS)
 
   CMAKEFILES(${g_sat_srcs} shim.h)

Modified: brlcad/trunk/src/external/Unigraphics/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/external/Unigraphics/CMakeLists.txt        2020-10-01 
21:08:02 UTC (rev 77312)
+++ brlcad/trunk/src/external/Unigraphics/CMakeLists.txt        2020-10-01 
21:17:30 UTC (rev 77313)
@@ -41,7 +41,6 @@
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"WDB_DLL_IMPORTS")
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"TIE_DLL_IMPORTS")
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"GDIAM_DLL_IMPORTS")
-      set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"VDS_DLL_IMPORTS")
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"ON_DLL_IMPORTS")
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"TINYCTHREAD_DLL_IMPORTS")
       set_property(TARGET ug-g APPEND PROPERTY COMPILE_DEFINITIONS 
"LZ4_DLL_IMPORT=1")

Modified: brlcad/trunk/src/librt/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/librt/CMakeLists.txt       2020-10-01 21:08:02 UTC (rev 
77312)
+++ brlcad/trunk/src/librt/CMakeLists.txt       2020-10-01 21:17:30 UTC (rev 
77313)
@@ -19,8 +19,8 @@
 # locally used but not needed by users of the library
 set(RT_LOCAL_INCLUDE_DIRS
   ${CMAKE_CURRENT_SOURCE_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}/vds
   ${REGEX_INCLUDE_DIRS}
-  ${VDS_INCLUDE_DIRS}
   ${GDIAM_INCLUDE_DIRS}
   )
 
@@ -219,6 +219,7 @@
   transform.c
   tree.c
   uv.c
+  vds/vds.c
   vers.c
   vlist.c
   vshoot.c
@@ -362,15 +363,12 @@
   set(SPR_LIB libSPR)
 endif(BRLCAD_ENABLE_SPR)
 
-BRLCAD_ADDLIB(librt "${LIBRT_SOURCES}" 
"${OPENCL_LIBS};${GDIAM_LIBRARY};${VDS_LIBRARY};libbrep;libnmg;libbg;libbn;libbu;${OPENNURBS_LIBRARIES};${P2T_LIBRARY};${SPR_LIB};${REGEX_LIBRARIES};${WINSOCK_LIB};${RPCRT_LIB};${STDCXX_LIBRARIES}")
+BRLCAD_ADDLIB(librt "${LIBRT_SOURCES}" 
"${OPENCL_LIBS};${GDIAM_LIBRARY};libbrep;libnmg;libbg;libbn;libbu;${OPENNURBS_LIBRARIES};${REGEX_LIBRARIES};${WINSOCK_LIB};${RPCRT_LIB};${STDCXX_LIBRARIES}")
 
 set_target_properties(librt PROPERTIES VERSION 20.0.1 SOVERSION 20)
 if(HIDE_INTERNAL_SYMBOLS)
   set_property(TARGET librt APPEND PROPERTY COMPILE_DEFINITIONS 
"TIE_DLL_EXPORTS")
   set_property(TARGET librt APPEND PROPERTY COMPILE_DEFINITIONS 
"DB5_DLL_EXPORTS")
-  if(TARGET vds OR HIDE_INTERNAL_SYMBOLS_EXT)
-    set_property(TARGET librt APPEND PROPERTY COMPILE_DEFINITIONS 
"VDS_DLL_IMPORTS")
-  endif(TARGET vds OR HIDE_INTERNAL_SYMBOLS_EXT)
   if(TARGET gdiam OR HIDE_INTERNAL_SYMBOLS_EXT)
     set_property(TARGET librt APPEND PROPERTY COMPILE_DEFINITIONS 
"GDIAM_DLL_IMPORTS")
   endif(TARGET gdiam OR HIDE_INTERNAL_SYMBOLS_EXT)
@@ -377,9 +375,6 @@
   if (TARGET librt-obj)
     set_property(TARGET librt-obj APPEND PROPERTY COMPILE_DEFINITIONS 
"TIE_DLL_EXPORTS")
     set_property(TARGET librt-obj APPEND PROPERTY COMPILE_DEFINITIONS 
"DB5_DLL_EXPORTS")
-    if(TARGET vds OR HIDE_INTERNAL_SYMBOLS_EXT)
-      set_property(TARGET librt-obj APPEND PROPERTY COMPILE_DEFINITIONS 
"VDS_DLL_IMPORTS")
-    endif(TARGET vds OR HIDE_INTERNAL_SYMBOLS_EXT)
     if(TARGET gdiam OR HIDE_INTERNAL_SYMBOLS_EXT)
       set_property(TARGET librt-obj APPEND PROPERTY COMPILE_DEFINITIONS 
"GDIAM_DLL_IMPORTS")
     endif(TARGET gdiam OR HIDE_INTERNAL_SYMBOLS_EXT)
@@ -405,6 +400,9 @@
 CMAKEFILES(
   CMakeLists.txt
   db_fp.cpp
+  vds/README
+  vds/COPYING
+  vds/vds.h
   )
 
 # Local Variables:

Copied: brlcad/trunk/src/librt/vds/COPYING (from rev 77312, 
brlcad/trunk/src/other/libvds/COPYING)
===================================================================
--- brlcad/trunk/src/librt/vds/COPYING                          (rev 0)
+++ brlcad/trunk/src/librt/vds/COPYING  2020-10-01 21:17:30 UTC (rev 77313)
@@ -0,0 +1,28 @@
+This package was debianized by Marcelo E. Magallon <[email protected]> on
+Sun, 20 Feb 2000 12:49:36 +0100.
+
+It was downloaded from http://www.cs.virginia.edu/~dwc3q/code/
+
+Upstream Author(s): Dr. David Patrick Luebke <[email protected]>
+
+Copyright:
+
+  Copyright 1999 The University of Virginia.
+  All Rights Reserved.
+
+  Permission to use, copy, modify and distribute this software and its
+  documentation without fee, and without a written agreement, is
+  hereby granted, provided that the above copyright notice and the
+  complete text of this comment appear in all copies, and provided that
+  the University of Virginia and the original authors are credited in
+  any publications arising from the use of this software.
+
+  IN NO EVENT SHALL THE UNIVERSITY OF VIRGINIA
+  OR THE AUTHOR OF THIS SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT,
+  INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+  LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+  DOCUMENTATION, EVEN IF THE UNIVERSITY OF VIRGINIA AND/OR THE
+  AUTHOR OF THIS SOFTWARE HAVE BEEN ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGES.
+
+Note: the polyview example is not included with the BRL-CAD copy of libvds.

Copied: brlcad/trunk/src/librt/vds/README (from rev 77312, 
brlcad/trunk/src/other/libvds/README)
===================================================================
--- brlcad/trunk/src/librt/vds/README                           (rev 0)
+++ brlcad/trunk/src/librt/vds/README   2020-10-01 21:17:30 UTC (rev 77313)
@@ -0,0 +1,25 @@
+                            VDSlib 0.9
+                     Dr. David Patrick Luebke.
+
+VDSlib is a software package that implements view-dependent simplification, 
+a geometric level-of-detail algorithm for managing the complexity of polygonal 
+scenes for interactive 3-D graphics. Unlike traditional approaches, which 
+compute discreet levels of detail for each object in a preprocess, VDSlib 
+computes a data structure from which the desired level of detail can be 
+dynamically extracted at run-time.
+
+For details of the algorithm, see the SIGGRAPH paper:
+
+View-Dependent Simplification Of Arbitrary Polygonal Environments
+http://www.cs.virginia.edu/~luebke/publications/sig97.html
+
+
+Changes:
+--------------------
+
+-- Marcelo E. Magallon <[email protected]>, Sun, 20 Feb 2000
+
+Modified the example polyview program to get it to compile with FLTk (free,
+available in main as libfltk1 and libfltk-dev) instead of XForms
+(non-free, available as libforms0.89 and libforms-dev).  I have also
+added extern "C" { ... } linkage specifications to vds' headers. 

Copied: brlcad/trunk/src/librt/vds/vds.c (from rev 77312, 
brlcad/trunk/src/other/libvds/vds.c)
===================================================================
--- brlcad/trunk/src/librt/vds/vds.c                            (rev 0)
+++ brlcad/trunk/src/librt/vds/vds.c    2020-10-01 21:17:30 UTC (rev 77313)
@@ -0,0 +1,1741 @@
+/***************************************************************************\
+
+  Copyright 1999 The University of Virginia.
+  All Rights Reserved.
+
+  Permission to use, copy, modify and distribute this software and its
+  documentation without fee, and without a written agreement, is
+  hereby granted, provided that the above copyright notice and the
+  complete text of this comment appear in all copies, and provided that
+  the University of Virginia and the original authors are credited in
+  any publications arising from the use of this software.
+
+  IN NO EVENT SHALL THE UNIVERSITY OF VIRGINIA OR THE AUTHOR OF THIS
+  SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
+  INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
+  OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE
+  UNIVERSITY OF VIRGINIA AND/OR THE AUTHOR OF THIS SOFTWARE HAVE BEEN
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+  The author of the vdslib software library may be contacted at:
+
+  US Mail:             Dr. David Patrick Luebke
+  Department of Computer Science
+  Thornton Hall, University of Virginia
+  Charlottesville, VA 22903
+
+Phone:               (804)924-1021
+
+EMail:               [email protected]
+
+\*****************************************************************************/
+
+/**
+ * @memo       Routines for constructing the VDSlib vertex tree.
+ * @name       Building the vertex tree
+ *
+ * These routines provide a flexible interface for specifying the geometry
+ * of the original model, and for constructing the VDSlib vertex tree upon
+ * the vertices of that underlying high-resolution model.<p>
+ *
+ * Building a vertex tree begins with a call to \Ref{vdsBeginVertexTree}()
+ * and ends with a call to \Ref{vdsEndVertexTree}().  The building process
+ * consists of two stages: specifying geometry and clustering nodes.  All
+ * geometry must be specified before node clustering begins.  <p>
+ *
+ * Use \Ref{vdsBeginGeometry}() to signal the beginning of the first
+ * stage.  Geometry (in VDSlib parlance) consists of a list of
+ * <i>nodes</i>, or vertices in the original model, and a list of
+ * <i>triangles</i>, whose three corners are specified as indices into the
+ * list of nodes.  Nodes are added with the \Ref{vdsAddNode}() call and
+ * triangles are added with \Ref{vdsAddTri}().  The nodes referenced by a
+ * triangle must be added before that triangle can be added.  When all
+ * geometry has been specified, call \Ref{vdsEndGeometry}() to move on to
+ * the next stage.<p>
+ *
+ * The vertex clustering stage simply consists of calls to
+ * \Ref{vdsClusterNodes}().  This function takes several nodes (up to
+ * \Ref{VDS_MAXDEGREE}) and clusters them together, assigning the nodes as
+ * children of a new parent node with coordinates specified by the user
+ * (it is an error to call \Ref{vdsClusterNodes}() on a node which has
+ * already been assigned a parent).  This parent node may then be
+ * clustered with other nodes with further calls to
+ * \Ref{vdsClusterNodes}(), and so on, until all nodes have been clustered
+ * into a single tree.  This is the <i>vertex tree</i>, the fundamental
+ * data structure of VDSlib.  Note that the vertices of the original
+ * (highest-resolution) model, specified by the user in the first stage,
+ * form the leaf nodes of the vertex tree.  Each internal node thus represents
+ * some subset of the original vertices, approximating those vertices with
+ * a single point.  <p>
+ *
+ * Once the vertex tree has been built with successive calls to
+ * \Ref{vdsClusterNodes}(), the user calls \Ref{vdsEndVertexTree}() to
+ * finalize it.  The finished vertex tree is now ready for run-time
+ * maintainance and rendering. <p>
+ *
+ * @see                build.c
+ */
+/*@{*/
+
+#include "common.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vmath.h"
+#include "vds.h"
+
+#define MAJOR 1
+#define MINOR 1
+
+#ifdef INSTRUMENT
+#define STAT(x) x
+#else
+#define STAT(x)
+#endif
+
+#ifdef VDS_DEBUGPRINT
+#define VDS_DEBUG(x) printf x
+#else
+#define VDS_DEBUG(x)
+#endif
+
+/**
+ * @memo       Macros for examining and changing the path to a vdsNode.
+ * @name       Manipulating vdsNodePath structures.
+ *
+ *             These preprocessor macros manipulate vdsNodePath, the bit
+ *             vector that encapsulates the path from the root of a vertex
+ *             tree to a node.<p><dl>
+ *
+ * <dd>Details:        For a binary tree, each bit represents a branch.  For 
an 8-way
+ *             tree, 3 bits represent a branch.  And so on.  The least
+ *             significant bit(s) represent the branch from the root node to
+ *             the level-1 node, the next least significant bit(s) represent
+ *             the next branch, and so on; the most significant meaningful
+ *             bit(s) represent the final branch to the leaf node.  The root
+ *             node has a depth of 0 and none of the bits mean anything (but
+ *             all must be set to zero, see below).<p>
+ * <dd>Note 1: Defining VDS_64_BITS enforces 64-bit paths.  This enables much
+ *             larger vertex trees but may be slower on some architectures.<p>
+ * <dd>Note 2:         For convenience, the depth of the node (and thus the 
node path
+ *             length) is currently stored separately, and all unused bits
+ *             must be set to zero (this eases path comparisons).</dl>
+ *
+ * @see                path.h
+ */
+/*@{*/
+
+/** Copy one vdsNodePath structure into another.
+ *             Copies the vdsNodePath <b>src</b> into <b>dst</b>.
+ */
+#define PATH_COPY(dst,src) ((dst) = (src))
+
+/** Look up a particular branch within a vdsNodePath.
+ *             Given a vdsNodePath P and a depth D, returns a branch number
+ *             indicating which child of the node at depth D is an ancestor
+ *             of the node represented by P.
+ */
+#define PATH_BRANCH(P,D) (((P)>>((D)*VDS_NUMBITS))&VDS_BITMASK)
+
+/** Set a particular branch within a vdsNodePath.
+ *             Takes a vdsNodePath P representing node N, a depth D,
+ *             and a branch number B.  If node A is the ancestor of N at
+ *             depth D, sets P to indicate that A->children[B] is the
+ *             ancestor of N at depth D+1.<p>
+ * Note:       B is assumed to be <= VDS_MAXDEGREE; no checking is done
+ */
+#define PATH_SET_BRANCH(P,D,B) (P |= ((vdsNodePath)(B)<<((D)*VDS_NUMBITS)))
+
+/*@}*/
+
+/* Routines for maintaining the vertex tree (dynamic.c) */
+extern void vdsUnfoldNode(vdsNode *);
+extern void vdsFoldNode(vdsNode *);
+extern void vdsFoldSubtree(vdsNode *);
+/* Routines for rendering the vertex tree (render.c) */
+extern void vdsUpdateTriProxies(vdsTri *t);
+extern void vdsUpdateTriNormal(vdsTri *t);
+/* Routines for building the vertex tree (build.c) */
+extern vdsNode *vdsFindNode(vdsNodeId id, vdsNode *root);
+extern vdsNodeId vdsFindCommonId(vdsNodeId id1, vdsNodeId id2, int maxdepth);
+extern void vdsComputeTriNodes(vdsNode *node, vdsNode *root);
+
+/* Vector macros for the view-dependent simplification package. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VEC3_EQUAL(a,b) (NEAR_EQUAL((a)[0],(b)[0], SMALL_FASTF) && 
NEAR_EQUAL((a)[1],(b)[1], SMALL_FASTF) && NEAR_EQUAL((a)[2],(b)[2],SMALL_FASTF))
+
+#define VEC3_COPY(dst,src) ((dst)[0]=(src)[0], \
+       (dst)[1]=(src)[1], \
+       (dst)[2]=(src)[2])
+
+#define VEC3_ADD(dst,a,b)      {(dst)[0]=(a)[0]+(b)[0];\
+    (dst)[1]=(a)[1]+(b)[1];\
+    (dst)[2]=(a)[2]+(b)[2];}
+
+
+#define VEC3_SUBTRACT(dst,a,b) {(dst)[0]=(a)[0]-(b)[0];\
+    (dst)[1]=(a)[1]-(b)[1];\
+    (dst)[2]=(a)[2]-(b)[2];}
+
+#define VEC3_SCALE(dst,scal,vec) {(dst)[0]=(vec)[0]*(scal);\
+    (dst)[1]=(vec)[1]*(scal);\
+    (dst)[2]=(vec)[2]*(scal);}
+
+#define VEC3_AVERAGE(dst,a,b) {(dst)[0]=((a)[0]+(b)[0])/2.0;\
+    (dst)[1]=((a)[1]+(b)[1])/2.0;\
+    (dst)[2]=((a)[2]+(b)[2])/2.0;}
+
+#define VEC3_DOT(_v0, _v1) ((_v0)[0] * (_v1)[0] +    \
+       (_v0)[1] * (_v1)[1] +    \
+       (_v0)[2] * (_v1)[2])
+
+#define VEC3_CROSS(dst,a,b) {(dst)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1];\
+    (dst)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2];\
+    (dst)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0];}
+
+#define VEC3_LENGTH_SQUARED(v) ((v)[0]*(v)[0] + (v)[1]*(v)[1] + (v)[2]*(v)[2])
+
+#define VEC3_LENGTH(v) (sqrt(VEC3_LENGTH_SQUARED(v)))
+
+#define VEC3_DISTANCE_SQUARED(a,b) (((a)[0]-(b)[0])*((a)[0]-(b)[0]) +  \
+       ((a)[1]-(b)[1])*((a)[1]-(b)[1]) +       \
+       ((a)[2]-(b)[2])*((a)[2]-(b)[2]))
+
+#define VEC3_DISTANCE(a,b) (sqrt(VEC3_DISTANCE_SQUARED((a),(b))))
+
+#define VEC3_NORMALIZE(v) {static vdsFloat _n;                         \
+    _n = 1.0/sqrt((v)[0]*(v)[0] +              \
+           (v)[1]*(v)[1] +             \
+           (v)[2]*(v)[2]);             \
+    (v)[0]*=_n;                                        \
+    (v)[1]*=_n;                                        \
+    (v)[2]*=_n;}
+
+#define VEC3_FIND_MAX(dst,a,b) {(dst)[0]=(a)[0]>(b)[0]?(a)[0]:(b)[0];\
+    (dst)[1]=(a)[1]>(b)[1]?(a)[1]:(b)[1];\
+    (dst)[2]=(a)[2]>(b)[2]?(a)[2]:(b)[2];}
+
+#define VEC3_FIND_MIN(dst,a,b) {(dst)[0]=(a)[0]<(b)[0]?(a)[0]:(b)[0];\
+    (dst)[1]=(a)[1]<(b)[1]?(a)[1]:(b)[1];\
+    (dst)[2]=(a)[2]<(b)[2]?(a)[2]:(b)[2];}
+
+#define BYTE3_EQUAL(a,b) ((a)[0]==(b)[0]&&(a)[1]==(b)[1]&&(a)[2]==(b)[2])
+
+#define BYTE3_COPY(dst,src) ((dst)[0]=(src)[0], \
+       (dst)[1]=(src)[1], \
+       (dst)[2]=(src)[2])
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*
+ * Globals
+ */
+vdsNode *nodearray = NULL;
+int vdsNumnodes;
+static int maxnodes;
+vdsTri *triarray = NULL;
+int vdsNumtris;
+static int maxtris;
+static int curroffset;
+static int openflag = 0;
+
+/** Initializes the builder.
+ * Note:       Currently nothing to do here.
+ */
+void vdsBeginVertexTree()
+{
+    openflag = 1;
+}
+
+/** Initialize the geometry structures.
+ *             Must be called before calling vdsAddNode() and vdsAddTri(),
+ *             and must be followed by vdsEndGeometry().
+ */
+void vdsBeginGeometry()
+{
+    maxnodes = 1024;
+    nodearray = (vdsNode *) calloc(maxnodes, sizeof(vdsNode));
+    vdsNumnodes = 0;
+    maxtris = 1024;
+    triarray = (vdsTri *) calloc(maxtris, sizeof(vdsTri));
+    vdsNumtris = 0;
+    curroffset = 0;
+}
+
+/** When all geometry has been added, prepares VDSlib for node clustering.
+ *             When all geometry (tris & verts) has been added, this
+ *             function prepares the builder for the next phase (merging
+ *             nodes into a tree).  Must be called after vdsBeginGeometry(),
+ *             after all vdsAddNode() and vdsAddTri() calls, and before any
+ *             vdsClusterNodes() calls.
+ * @return     A pointer to an array containing all leaf nodes, in case the
+ *             application wants to use this information during clustering.
+ *             Leaf nodes in the array are in the order they were given.
+ */
+vdsNode *vdsEndGeometry()
+{
+    /* Tighten nodearray and triarray to free up unused memory */
+    nodearray = (vdsNode *) realloc(nodearray, vdsNumnodes * sizeof(vdsNode));
+    triarray = (vdsTri *) realloc(triarray, vdsNumtris * sizeof(vdsTri));
+    return nodearray;
+}
+
+/** Start a new object, with separate vertex and triangle lists.
+ *             Models are often organized into "objects", where each object
+ *             consists of vertex and triangle lists.  An object's triangles
+ *             index corners in that object's vertex list, rather than a
+ *             global vertex list.  VDSlib, however, relies on combining
+ *             object vertices into such a global vertex list.  This utility
+ *             function allows the user to specify triangles without
+ *             renumbering the corner indices.  For example, to load two
+ *             objects into VDSlib, call vdsAddNode() on the vertices of
+ *             object 1, vdsAddTri() on the triangles of object 1, then
+ *             call vdsNewObject().  Finally, add the vertices and triangles
+ *             of object 2.  VDSlib will automatically offset the indices
+ *             of object 2's triangle corners. <p>
+ *
+ * <b>Note:</b>        vdsNewObject() must be called between vdsBeginGeometry()
+ *             and vdsEndGeometry().
+ */
+void vdsNewObject()
+{
+    curroffset = vdsNumnodes;
+}
+
+/** Add a vertex of the original model as a leaf node of the VDS vertex tree.
+ *             Given a vertex coordinate, creates a vdsNode to represent the
+ *             vertex as a leaf node in the vertex tree.
+ * @param      x       The X coordinate of the vertex
+ * @param      y       The Y coordinate of the vertex
+ * @param      z       The Z coordinate of the vertex
+ * @return     A pointer to the created node, in case the user wishes to
+ *             create a vertex->data field. <b>NOTE</b>: This pointer is
+ *             only guaranteed valid until the next call to vdsAddNode()
+ *             or vdsEndGeometry().
+ *
+ * <b>Note:</b>        vdsAddNode() must be called between vdsBeginGeometry()
+ *             and vdsEndGeometry().
+ */
+vdsNode *vdsAddNode(vdsFloat x, vdsFloat y, vdsFloat z)
+{
+    nodearray[vdsNumnodes].coord[0] = x;
+    nodearray[vdsNumnodes].coord[1] = y;
+    nodearray[vdsNumnodes].coord[2] = z;
+    vdsNumnodes++;
+    /* Resize array if necessary */
+    if (vdsNumnodes == maxnodes) {
+       vdsNode *tmparray = (vdsNode *) calloc(maxnodes * 2, sizeof(vdsNode));
+
+       memcpy(tmparray, nodearray, vdsNumnodes * sizeof(vdsNode));
+       free(nodearray);
+       nodearray = tmparray;
+       maxnodes *= 2;
+    }
+    return &nodearray[vdsNumnodes - 1];
+}
+
+/** Add a triangle of the original model.
+ *             Given a triangle (specified as three corner indices into a
+ *             vertex list) creates a vdsTri struct with the given attributes.
+ *             Later, when vdsEndVertexTree() is called, each tri will be
+ *             copied directly into the subtri array of the appropriate node.
+ *             Note that the vertices index by the triangle must already have
+ *             been added via vdsAddNode().
+ * @return     A pointer to the created vdsTri struct, in case the user
+ *             wishes to create a tri->data field. <b>NOTE</b>: This pointer
+ *             is only guaranteed valid until the next call to vdsAddTri()
+ *             or vdsEndGeometry().
+ *
+ * <b>Note:</b>        vdsAddTri() must be called between vdsBeginGeometry()
+ *             and vdsEndGeometry().
+ */
+vdsTri *vdsAddTri(int v0, int v1, int v2,
+       vdsVec3 n0, vdsVec3 n1, vdsVec3 n2,
+       vdsByte3 c0, vdsByte3 c1, vdsByte3 c2)
+{
+    triarray[vdsNumtris].corners[0].index = v0 + curroffset;
+    triarray[vdsNumtris].corners[1].index = v1 + curroffset;
+    triarray[vdsNumtris].corners[2].index = v2 + curroffset;
+    VEC3_COPY(triarray[vdsNumtris].normal[0], n0);
+    VEC3_COPY(triarray[vdsNumtris].normal[1], n1);
+    VEC3_COPY(triarray[vdsNumtris].normal[2], n2);
+    BYTE3_COPY(triarray[vdsNumtris].color[0], c0);
+    BYTE3_COPY(triarray[vdsNumtris].color[1], c1);
+    BYTE3_COPY(triarray[vdsNumtris].color[2], c2);
+    vdsNumtris ++;
+    /* Resize array if necessary */
+    if (vdsNumtris == maxtris) {
+       vdsTri *tmparray = (vdsTri *) calloc(maxtris * 2, sizeof(vdsTri));
+
+       memcpy(tmparray, triarray, vdsNumtris * sizeof(vdsTri));
+       free(triarray);
+       triarray = tmparray;
+       maxtris *= 2;
+    }
+    return &triarray[vdsNumtris - 1];
+}
+
+/** Cluster a set of nodes under a single new node.
+ *             Attaches the given list of nodes to a new parent node, with
+ *             a representative vertex at the specified coordinates.
+ * @param      nnodes  The number of nodes being merged
+ * @param      nodes   Nodes being merged (it is an error if any of these
+ *                     nodes already has a parent node)
+ * @param      XYZ  The coordinates of the new node's repvert
+ * @return     A pointer to the newly created parent node. <b>NOTE</b>:
+ *             This pointer is only valid until the vdsEndVertexTree() call.
+ */
+vdsNode *vdsClusterNodes(int nnodes, vdsNode **nodes,
+       vdsFloat x, vdsFloat y, vdsFloat z)
+{
+    int i;
+    vdsNode *parent = (vdsNode *) calloc(1, sizeof(vdsNode));
+
+    parent->children = nodes[0];
+    parent->children->parent = parent;
+    for (i = 1; i < nnodes; i++) {
+       nodes[i]->parent = parent;
+       nodes[i - 1]->sibling = nodes[i];
+    }
+    nodes[nnodes - 1]->sibling = NULL;
+    parent->coord[0] = x;
+    parent->coord[1] = y;
+    parent->coord[2] = z;
+
+    return parent;
+}
+
+/*
+ * Function:   verifyRootedTree
+ * Description:        Verifies that all the leaf nodes in nodearray belong to 
a
+ *             tree rooted at root.  Must be called after assignNodeIds().
+ */
+static void verifyRootedTree(vdsNode *root)
+{
+    int i;
+    vdsNode *node;
+
+    for (i = 0; i < vdsNumnodes; i++) {
+       node = &nodearray[i];
+       if (node->depth == 0 && node != root) {
+           fprintf(stderr, "\tError: leaf node #%d is not part of the same\n"
+                   "\trooted tree as previous nodes\n", i);
+           exit(1);
+       }
+    }
+}
+
+/*
+ * Function:   computeSubtris
+ * Description:        Processes the tris in triarray and assigns each as the 
subtri
+ *             of the deepest node in the vertex tree to cluster two or more
+ *             corners of the triangle.  Subtris are stored temporarily in
+ *             the node->vistris linked list.
+ */
+static void computeSubtris(vdsNode *root)
+{
+    int i;
+
+    for (i = 0; i < vdsNumtris; i++) {
+       vdsTri *t = &triarray[i];
+       vdsNodeId c0, c1, c2;           /* The 3 corners of the triangle */
+       vdsNodeId com01, com02, com12;  /* Common ancestor of c0c1,c1c2,c0c2*/
+       vdsNode *N = NULL;              /* The node t is a subtri of     */
+
+       c0 = t->corners[0].id;
+       c1 = t->corners[1].id;
+       c2 = t->corners[2].id;
+       com01 = vdsFindCommonId(c0, c1, VDS_MAXDEPTH);
+       com02 = vdsFindCommonId(c0, c2, VDS_MAXDEPTH);
+       com12 = vdsFindCommonId(c1, c2, VDS_MAXDEPTH);
+       /* t is a subtri of the deepest common ancestor of its corner nodes */
+       if (com01.depth >= com02.depth) {
+           if (com01.depth >= com12.depth) {
+               N = vdsFindNode(com01, root);
+           } else {
+               N = vdsFindNode(com12, root);
+           }
+       } else {
+           if (com02.depth >= com12.depth) {
+               N = vdsFindNode(com02, root);
+           } else {
+               N = vdsFindNode(com12, root);
+           }
+       }
+       /* t is a subtri of node N; add it to the N->vistris linked list */
+       t->next = N->vistris;
+       if (t->next != NULL) {
+           t->next->prev = t;
+       }
+       N->vistris = t;
+       N->nsubtris++;
+    }
+
+}
+
+/*
+ * Function:   moveTrisToNodes
+ * Description:        After all subtris have been associated with nodes via 
the
+ *             node->vistris linked list, this function traverses the tree
+ *             and reallocates each node to include room for the subtris
+ *             directly in the node->subtris[] field.  The triangle data
+ *             is then copied into this field, allowing triarray to be freed.
+ *             After reallocating the node, corrects parent/child pointers.
+ * Note:       Since leaf nodes of the vertex tree (the original vertices
+ *             of the model) are reallocated, nodearray can now be freed.
+ */
+static vdsNode *moveTrisToNodes(vdsNode *N)
+{
+    vdsTri *t, *nextt;
+    int whichtri, numchildren;
+    vdsNode *newN, *child;
+
+    /* Reallocate node and adjust child pointers */
+    newN = (vdsNode *) malloc(sizeof(vdsNode) + N->nsubtris * sizeof(vdsTri));
+    memcpy(newN, N, sizeof(vdsNode));
+    child = N->children;
+    numchildren = 0;
+    while (child != NULL) {
+       child->parent = newN;
+       numchildren++;
+       child = child->sibling;
+    }
+    /* Adjust parent's pointer to this node */
+    if (N->parent != NULL) {
+       vdsNode *pp = N->parent->children;
+
+       if (pp == N) {
+           N->parent->children = newN;
+       } else {
+           while (pp->sibling != N) {
+               pp = pp->sibling;
+           }
+           pp->sibling = newN;
+       }
+    }
+    /* Don't try to free leaf nodes, which belong to nodearray */
+    if (numchildren) {
+       free(N);
+    }
+    N = newN;
+    /* Copy node->vistris list into node->subtris[]; clear linked list ptrs */
+    t = N->vistris;
+    N->vistris = NULL;
+    whichtri = 0;
+    while (t != NULL) {
+       N->subtris[whichtri] = *t;
+       whichtri++;
+       nextt = t->next;
+       t->next = t->prev = NULL;
+       t = nextt;
+    }
+    /* Recurse on children nodes */
+    child = N->children;
+    while (child != NULL) {
+       /* since moveTrisToNodes() reallocates nodes, have to reset child */
+       child = moveTrisToNodes(child);
+       child = child->sibling;
+    }
+    return N;
+}
+
+
+/** Finalize the VDS vertex tree.
+ *             After all geometry has been added and all leaf nodes (created
+ *             by vdsAddNode()) merged to form a single hierarchy of vdsNodes,
+ *             call vdsEndVertexTree() to process the hierarchy and produce
+ *             a finished vertex tree, ready for simplification/rendering.<p>
+ *
+ * Tasks:      Performs the following tasks, in order:         <p><ll>
+ *             <li> Computes node paths and ids
+ *             <li> Verifies that node hierarchy forms a single rooted tree
+ *             <li> Computes node bounds for fold & visibility tests
+ *             <li> Computes node subtris, attaching via vistris linked list
+ *             <li> Converts vdsTris to use leaf node ids, rather than indices
+ *             <li> Reallocates each node to store subtris directly
+ *             <li> Nullifies node->vistris list and tri next,prev pointers
+ *             <li> Computes triangle container nodes for tri->node field
+ *             <li> Assigns tri->proxies[] pointers to point at root node
+ *             <li> Deletes triarray
+ *             <li> Labels root node Boundary                  </ll>
+ * @return     Pointer to the root node of the new vertex tree.
+ */
+vdsNode *vdsEndVertexTree()
+{
+    vdsNode *root;
+#ifdef VDS_DEBUGPRINT
+    vdsNodeId rootId = {0, 0};
+#endif
+    vdsNodeId *ids;
+    int i;
+
+    root = &nodearray[0];
+    while (root->parent != NULL) {
+       root = root->parent;
+    }
+    VDS_DEBUG(("Assigning node ids..."));
+    ids = (vdsNodeId *) calloc(vdsNumnodes, sizeof(vdsNodeId));
+#ifdef VDS_DEBUGPRINT
+    int maxdepth = assignNodeIds(root, rootId, ids);
+#endif
+    VDS_DEBUG(("Done.\n"));
+    VDS_DEBUG(("Verifying that all nodes form a single rooted tree..."));
+    verifyRootedTree(root);
+    VDS_DEBUG(("Done.\n"));
+    VDS_DEBUG(("Assigning node->bound for all nodes..."));
+#if 0
+    /* This is a very expensive operation. Only calculate bounds if
+     * you actually intend to use them.
+     */
+    assignNodeBounds(root);
+#endif
+    VDS_DEBUG(("Done.\n"));
+    VDS_DEBUG(("Converting triangles to reference nodes by ID..."));
+    /* Convert tris to reference node IDs, rather than indices */
+    for (i = 0; i < vdsNumtris; i++) {
+       vdsTri *T = &triarray[i];
+       int c0, c1, c2;
+
+       c0 = T->corners[0].index;
+       c1 = T->corners[1].index;
+       c2 = T->corners[2].index;
+
+       T->corners[0].id = ids[c0];
+       T->corners[1].id = ids[c1];
+       T->corners[2].id = ids[c2];
+    }
+    free(ids);
+    VDS_DEBUG(("Done.\n"));
+    VDS_DEBUG(("Computing subtris..."));
+    computeSubtris(root);
+    VDS_DEBUG(("Done.\n"));
+    VDS_DEBUG(("Reallocating nodes and copying triangles into node->subtris "
+               "fields..."));
+    root = moveTrisToNodes(root);      /* Note: reallocates all nodes      */
+    free(nodearray);
+    VDS_DEBUG(("Done.\n"));
+    VDS_DEBUG(("Computing triangle container nodes..."));
+    vdsComputeTriNodes(root, root);
+    free(triarray);                    /* nodearray still holds leaf nodes */
+    root->status = Boundary;           /* root initially on boundary       */
+    root->next = root->prev = root;    /* root always on boundary path     */
+#ifdef VDS_DEBUGPRINT
+    VDS_DEBUG(("Done.\nVertex tree complete! Maximum depth = %d\n", maxdepth));
+#endif
+    openflag = 0;
+    return root;
+}
+
+/*@}*/
+/***************************************************************************\
+
+  Copyright 1999 The University of Virginia.
+  All Rights Reserved.
+
+  Permission to use, copy, modify and distribute this software and its
+  documentation without fee, and without a written agreement, is
+  hereby granted, provided that the above copyright notice and the
+  complete text of this comment appear in all copies, and provided that
+  the University of Virginia and the original authors are credited in
+  any publications arising from the use of this software.
+
+  IN NO EVENT SHALL THE UNIVERSITY OF VIRGINIA
+  OR THE AUTHOR OF THIS SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT,
+  INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+  LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+  DOCUMENTATION, EVEN IF THE UNIVERSITY OF VIRGINIA AND/OR THE
+  AUTHOR OF THIS SOFTWARE HAVE BEEN ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGES.
+
+  The author of the vdslib software library may be contacted at:
+
+  US Mail:             Dr. David Patrick Luebke
+  Department of Computer Science
+  Thornton Hall, University of Virginia
+  Charlottesville, VA 22903
+
+Phone:               (804)924-1021
+
+EMail:               [email protected]
+
+\*****************************************************************************/
+/*
+ * File:       cluster.c
+ * Description:        Routines for building a VDS vertex tree using a VERY 
simple
+ *             octree-based clustering scheme.
+ */
+
+/*
+ * Function:   vdsClusterOctree
+ * Description:        Builds an octree over the given leaf nodes using
+ *             vdsClusterNodes().  Takes an array <nodes> of vdsNode pointers
+ *             that represent vertices in the original model (i.e., leaf nodes
+ *             in the vertex tree to be generated).  This array is partitioned
+ *             into eight subarrays by splitting across the x, y, and z
+ *             midplanes of the tightest-fitting bounding cube, and
+ *             vdsClusterOctree() is called recursively on each subarray.
+ *             Finally, vdsClusterNodes() is called on the 2-8 nodes returned
+ *             by these recursive calls, and vdsClusterOctree returns the newly
+ *             created internal node.
+ */
+vdsNode *vdsClusterOctree(vdsNode **nodes, int nnodes, int depth)
+{
+    vdsNode *thisnode;
+    vdsNode *children[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+    int nchildren = 0;
+    vdsNode **childnodes[8];
+    int nchildnodes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+    int i, j;
+    vdsVec3 min, max, center, average = {0, 0, 0};
+
+    /* Overestimate array size needs for childnodes now; shrink later */
+    for (i = 0; i < 8; i++) {
+       childnodes[i] = (vdsNode **) malloc(sizeof(vdsNode *) * nnodes);
+    }
+    /* Find the min and max bounds of nodes, and accumulate average coord */
+    VEC3_COPY(min, nodes[0]->coord);
+    VEC3_COPY(max, nodes[0]->coord);
+    for (i = 0; i < nnodes; i++) {
+       for (j = 0; j < 3; j++) {
+           if (nodes[i]->coord[j] > max[j]) {
+               max[j] = nodes[i]->coord[j];
+           }
+           if (nodes[i]->coord[j] < min[j]) {
+               min[j] = nodes[i]->coord[j];
+           }
+       }
+       VEC3_ADD(average, average, nodes[i]->coord);
+    }
+    VEC3_SCALE(average, 1.0 / (float) nnodes, average);
+    VEC3_AVERAGE(center, min, max);
+    if (VEC3_EQUAL(min, max)) {
+       /* vertices coincide, just partition evenly among children */
+       for (i = 0; i < nnodes; i++) {
+           int index = i % VDS_MAXDEGREE;
+           childnodes[index][nchildnodes[index]] = nodes[i];
+           nchildnodes[index] ++;
+       }
+    } else {
+       /* Partition the nodes among the 8 octants defined by min and max */
+       for (i = 0; i < nnodes; i++) {
+           int whichchild = 0;
+           if (nodes[i]->coord[0] > center[0]) {
+               whichchild |= 1;
+           }
+           if (nodes[i]->coord[1] > center[1]) {
+               whichchild |= 2;
+           }
+           if (nodes[i]->coord[2] > center[2]) {
+               whichchild |= 4;
+           }
+
+           childnodes[whichchild][nchildnodes[whichchild]] = nodes[i];
+           nchildnodes[whichchild] ++;
+       }
+    }
+    /* Resize childnodes arrays to use only as much space as necessary */
+    for (i = 0; i < 8; i++) {
+       childnodes[i] = (vdsNode **)
+           realloc(childnodes[i], sizeof(vdsNode *) * nchildnodes[i]);
+    }
+    /* Recurse or store non-empty children */
+    for (i = 0; i < 8; i++) {
+       if (nchildnodes[i] > 0) {
+           if (nchildnodes[i] == 1) {  /* 1 node in octant; store directly  */
+               children[nchildren] = childnodes[i][0];
+           } else {            /* 2 or more nodes in octant; recurse*/
+               children[nchildren] =
+                   vdsClusterOctree(childnodes[i], nchildnodes[i], depth + 1);
+           }
+           nchildren++;
+       }
+
+    }
+    /* Finally, cluster nonempty children; this node is the resulting parent */
+    thisnode = vdsClusterNodes(nchildren, children,
+           average[0], average[1], average[2]);
+    for (i = 0; i < 8; i++) {
+       if (nchildnodes[i]) {
+           free(childnodes[i]);
+       }
+    }
+    return thisnode;
+}
+/**
+ * @memo       Routines for controlling simplification at run-time.
+ * @name       Dynamic vertex tree maintenance
+ *
+ * These routines form the heart of the run-time view-dependent
+ * simplification processs.  They maintain the vertex tree dynamically at
+ * render time, as opposed to statically during the tree-building
+ * preprocess.<p>
+ *
+ * The VDS vertex tree spans the entire model, organizing every vertex of
+ * every polygon into one global hierarchy encoding all simplifications VDS
+ * can produce.  Leaf nodes each represent a single vertex of the original
+ * model; internal nodes represent the merging of multiple vertices from
+ * the original model into a single vertex called the <i>proxy</i>.  A
+ * proxy is associated with each node in the vertex tree.<p>
+ *
+ * <i>Folding</i> a node merges the vertices supported by the node into its
+ * proxy, and <i>unfolding</i> a node reverses the process.  Folding and
+ * unfolding a node always affects certain triangles.  One set of triangles
+ * will change in shape as a corner shifts during fold and unfold
+ * operations.  Another set of triangles, called the node's <i>subtris</i>,
+ * will disappear when the node is folded and reappear when the node is
+ * unfolded. Since subtris do not depend on the state of other nodes in the
+ * vertex tree, they can be computed offline and accessed very quickly at
+ * runtime.  This is the key observation behind VDS.<p>
+ *
+ * Unfolded nodes are labeled <i>Active</i>; folded nodes are labeled
+ * <i>Inactive</i>.  During operation the active nodes constitute a cut of
+ * the vertex tree, rooted at the root node, called the <i>active tree</i>.
+ * Folded nodes with active parents are a special case; these nodes form
+ * the boundary of the active tree and are labeled <i>Boundary</i> (Figure
+ * 6).  Since the location of the boundary nodes determines which vertices
+ * in the original model have been collapsed together, the path of the
+ * boundary nodes across the vertex tree completely determines the current
+ * simplification.  <p>
+ *
+ * To fold a node, use \Ref{vdsFoldNode}(); to unfold a node, use
+ * \Ref{vdsUnfoldNode}().  Note that by definition, only Boundary nodes can
+ * be unfolded and only Active nodes whose children are all labeled
+ * boundary can be folded.  For convenience, the \Ref{vdsFoldSubtree}()
+ * function recursively folds a given node after first folding all nodes in
+ * the subtree rooted below that node.<p>
+ *
+ * Usually, the VDSlib user will want to examine all nodes in the vertex
+ * tree, applying some criterion to each node to decide whether the node
+ * should be folded or unfolded.  The \Ref{vdsAdjustTreeTopDown}() call
+ * traverses a vertex tree depth-first, applying a user-specified callback
+ * function to determine whether to fold, unfold, or leave each node.  <p>
+ *
+ * Since all folds and unfolds by definition occur at Boundary nodes, it
+ * is also possible to simply walk across the active boundary, applying
+ * the fold criterion to whether to unfold a Boundary node, fold its
+ * parent, or leave both nodes.  The \Ref{vdsAdjustTreeBoundary}() call
+ * does just this; the boundary path across the vertex tree is maintained
+ * as a doubly-linked list of nodes.  If the active boundary is not
+ * expected to change much from call to call, this function is more
+ * efficient than \Ref{vdsAdjustTreeTopDown}().<p>
+ *
+ * @see dynamic.c */
+/*@{*/
+
+/* Remove a triangle from the scene.
+ *
+ *             Remove a triangle from the vistris list of its containing node.
+ *
+ *             Note that I currently maintain vistris as a doubly-linked list
+ *             for simplicity.  Eventually I should use arrays with garbage
+ *             collection, or a similar scheme, for better memory coherence.
+ *
+ * @param        tri     The triangle to remove.
+ */
+static void removeTri(vdsTri *tri)
+{
+    vdsNode *node = tri->node;
+
+    if (node->vistris == tri) {
+       node->vistris = tri->next;      /* Note that tri->next may be NULL */
+    }
+    if (tri->prev) {
+       tri->prev->next = tri->next;
+    }
+    if (tri->next) {
+       tri->next->prev = tri->prev;
+    }
+}
+
+/* Add a triangle to the scene.
+ *
+ *             Add the specified triangle to its containing node's list
+ *             of visible tris.
+ *
+ * @see        See the note on removeTri().
+ *
+ * @param      tri     the triangle to add
+ */
+static void addTri(vdsTri *tri)
+{
+    vdsNode *node = tri->node;
+
+    if (node->vistris == NULL) {
+       node->vistris = tri;
+       tri->prev = tri->next = NULL;
+    } else {
+       tri->prev = NULL;
+       tri->next = node->vistris;
+       tri->next->prev = tri;
+       node->vistris = tri;
+    }
+}
+
+/** Fold the given node.
+ *
+ * Given a node N, collapses the representative vertices of the children
+ * of N to the representative vertex of N.  This removes some triangles
+ * from the scene (namely, N->subtris).  N is assumed to lie just above the
+ * active boundary before the foldNode() operation, and lies on it
+ * afterwards.<p>
+ *
+ * Requires:  All of N's child nodes must be labeled Boundary.  If this is
+ * not the case, use vdsFoldSubtree().<p>
+ *
+ * Implementation note: The active boundary is maintained as a circular
+ * linked list which always starts at the root, goes to the leftmost node
+ * labeled * Boundary, threads through the active boundary of the vertex
+ * tree to the rightmost Boundary node, and returns to the root.
+ *
+ * @param              node            The node to be folded.
+ */
+void vdsFoldNode(vdsNode *node)
+{
+    vdsNode *child;
+    vdsNode *prev, *next;
+    vdsTri *t;
+    int i;
+
+    /* Activate node and deactivate children */
+    node->status = Boundary;
+    child = node->children;
+    prev = child->prev;                        /* Set prev to first child's 
prev */
+    while (child != NULL) {
+       child->status = Inactive;
+       next = child->next;             /* Set next to last child's next */
+       child = child->sibling;         /* Advance to next child         */
+    }
+    /* Adjust active boundary */
+    node->prev = prev;
+    node->next = next;
+    node->prev->next = node;
+    node->next->prev = node;
+    /* Remove subtris from the scene */
+    for (i = 0; i < node->nsubtris; i++) {
+       t = &node->subtris[i];
+       removeTri(t);
+    }
+}
+
+/** Unfold the given node.
+ *
+ * The dual operation of vdsFoldNode(), expanding the
+ * representative vertex of the given node N to the
+ * representative vertices of N's children.  This adds
+ * some triangles to the scene (N->subtris).  N must lie
+ * on the active boundary, which will be adjusted to follow
+ * N's child nodes.
+ *
+ * @see                See note on vdsFoldNode()
+ *
+ * @param      node    The node to be unfolded.
+ */
+void vdsUnfoldNode(vdsNode *node)
+{
+    vdsNode *child = node->children;
+    vdsNode *prev, *next;
+    vdsTri *t;
+    int i;
+
+    if (child == NULL) {
+       return;    /* Node is a leaf, leave on boundary */
+    }
+
+    /* Activate node children; deactivate node; maintain active boundary */
+    prev = node->prev;
+    next = node->next;
+    while (child != NULL) {
+       child->prev = prev;
+       prev->next = child;
+       prev = child;
+
+       child->status = Boundary;
+       child = child->sibling;                 /* Advance to next child */
+    }
+    prev->next = next;
+    next->prev = prev;
+    node->status = Active;
+    /* Add node->subtris to scene */
+    for (i = 0; i < node->nsubtris; i++) {
+       t = &node->subtris[i];
+       addTri(t);
+    }
+}
+
+/** Fold the entire subtree rooted at the given node.
+ *
+ * Recursively fold the subtree rooted at a given node N.  If
+ * any child C of N is not labeled Boundary, recursively fold
+ * the subtree rooted at C.  After folding all descendents,
+ * fold N.  N must lie above the active boundary; that is, N must
+ * be labeled Active.
+ *
+ * @param      node    Root of the subtree to be folded.
+ * @see        vdsFoldNode(), vdsUnfoldAncestors()
+ */
+void vdsFoldSubtree(vdsNode *node)
+{
+    vdsNode *child = node->children;
+
+    while (child != NULL) {
+       if (child->status == Active) {
+           vdsFoldSubtree(child);
+       }
+       child = child->sibling;                 /* Advance to next child */
+    }
+    /* All children should now be labeled Boundary */
+    vdsFoldNode(node);
+}
+
+/** Unfold the given node, recursively unfolding the node's ancestors first
+ *  if necessary.
+ *
+ * The dual operation of \Ref{vdsFoldSubtree}.  Recursively unfold all
+ * ancestors of the given node N, so that N lies on the active boundary,
+ * then unfold N.  N must lie below the active boundary; that is, N must
+ * be labeled Inactive.
+ *
+ * @param      node    The node to be recursively unfolded.
+ * @see                vdsUnfoldNode(), vdsFoldSubtree()
+ */
+void vdsUnfoldAncestors(vdsNode *node)
+{
+    vdsNode *parent = node->parent;
+
+    if (parent != NULL) {
+       if (parent->status == Boundary) {
+           vdsUnfoldNode(parent);
+       } else {
+           vdsUnfoldAncestors(parent);
+       }
+    }
+    /* We've unfolded the parent, so node should now be on the boundary */
+    vdsUnfoldNode(node);
+}
+
+/** Adjust the active boundary of the vertex tree.
+ *
+ * Walks the boundary of the active tree from left to right,
+ * calling a user-specified function to determine whether to
+ * unfold boundary nodes, lowering the boundary, or fold parents
+ * of boundary nodes, raising the boundary.
+ *
+ * @param      root            root of tree whose boundary is to be adjusted
+ * @param      foldtest        returns 1 if node should be folded, 0 otherwise
+ */
+void vdsAdjustTreeBoundary(vdsNode *root, vdsFoldCriterion foldtest, void 
*udata)
+{
+    vdsNode *current;                  /* node currently being tested  */
+    vdsNode *parent = NULL;            /* parent of current node       */
+    vdsNode *lastparent = NULL;                /* parent node last iteration   
*/
+
+    current = root->next;
+    do {
+       parent = current->parent;
+       /*
+        * If we haven't already, test parent: should it be folded?
+        * Note: if current is root node, parent == lastparent == NULL, so
+        * we won't attempt to fold (or even access) the NULL root->parent.
+        */
+       if (parent != lastparent) {
+           lastparent = parent;
+           /* Test parent: should it be folded? */
+           if (foldtest(parent, udata)) {
+               vdsFoldSubtree(parent);
+               /* Now parent is on the boundary; check it next */
+               current = parent;
+               continue;
+           }
+       }
+       /*
+        * Don't need to fold parent.  If current node can be unfolded,
+        * should we do so, or leave on the boundary?
+        */
+       if (current->children != NULL && foldtest(current, udata) == 0) {
+           vdsUnfoldNode(current);
+           /* Now node->children are on the boundary; check them */
+           current = current->children;
+       } else {
+           /* No folds or unfolds, move on to next node on the boundary */
+           current = current->next;
+       }
+    } while (current != root);
+}
+
+/** Traverse given vertex tree top-down, adjusting the boundary.
+ *
+ * Given the root node of a vertex tree, traverses the tree
+ * in a top-down fashion, using a user-specified function to
+ * determine whether to fold or unfold nodes.
+ *
+ * @param      node            the root of the (sub)tree to be adjusted
+ * @param      foldtest()      returns 1 if node should be folded, 0 otherwise
+ */
+void vdsAdjustTreeTopDown(vdsNode *node, vdsFoldCriterion foldtest, void 
*udata)
+{
+    vdsNode *child = node->children;
+
+    if (node->status == Active) {
+       if (foldtest(node, udata) == 1) {
+           vdsFoldSubtree(node);
+           return;
+       }
+    } else { /* node->status == Boundary */
+       if (foldtest(node, udata) == 0) {
+           vdsUnfoldNode(node);
+       } else {
+           return;
+       }
+    }
+
+    while (child != NULL) {
+       /* Can't fold or unfold leaf nodes */
+       if (child->children != NULL) {
+           vdsAdjustTreeTopDown(child, foldtest, udata);
+       }
+       child = child->sibling;
+    }
+}
+
+/*@}*/
+/***************************************************************************\
+
+  Copyright 1999 The University of Virginia.
+  All Rights Reserved.
+
+  Permission to use, copy, modify and distribute this software and its
+  documentation without fee, and without a written agreement, is
+  hereby granted, provided that the above copyright notice and the
+  complete text of this comment appear in all copies, and provided that
+  the University of Virginia and the original authors are credited in
+  any publications arising from the use of this software.
+
+  IN NO EVENT SHALL THE UNIVERSITY OF VIRGINIA
+  OR THE AUTHOR OF THIS SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT,
+  INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+  LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+  DOCUMENTATION, EVEN IF THE UNIVERSITY OF VIRGINIA AND/OR THE
+  AUTHOR OF THIS SOFTWARE HAVE BEEN ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGES.
+
+  The author of the vdslib software library may be contacted at:
+
+  US Mail:             Dr. David Patrick Luebke
+  Department of Computer Science
+  Thornton Hall, University of Virginia
+  Charlottesville, VA 22903
+
+Phone:               (804)924-1021
+
+EMail:               [email protected]
+
+\*****************************************************************************/
+/**
+ * @memo       Routines for rendering the vertex tree.
+ * @name       Rendering the current simplification
+ *
+ *             These routines traverse a vdsNode tree, using user-specified
+ *             callbacks to cull and render the active triangle list
+ *             associated with each node.<p>
+ *
+ * @see                render.c
+ */
+/*@{*/
+
+/*
+ * Function:   firstActiveAncestor
+ * Description:        Takes a node N representing a vertex in the original 
model,
+ *             specified as a vdsNodeId, and returns the first active
+ *             ancestor of N, i.e., the first ancestor of N on or above
+ *             the active boundary. Note that this need not be a proper
+ *             ancestor; a node may be its own FAA.  To exploit temporal
+ *             coherence, also takes a node "proxy" which was recently N's
+ *             FAA.  The search for the new FAA starts at proxy, moving up
+ *             or down as necessary.
+ */
+static vdsNode *firstActiveAncestor(vdsNodeId id, vdsNode *proxy)
+{
+    if (proxy->status == Inactive) {
+       do {
+           proxy = proxy->parent;
+       } while (proxy->status == Inactive);
+       return proxy;   /* proxy->status is now Boundary */
+    } else {
+       while (proxy->status != Boundary) {
+           /* proxy->status is Active; walk down id->path to find Boundary */
+           register int whichchild = PATH_BRANCH(id.path, proxy->depth);
+
+           proxy = proxy->children;
+           while (whichchild > 0) {
+               proxy = proxy->sibling;
+               whichchild --;
+           }
+       }
+       return proxy;   /* proxy->status is now Boundary */
+    }
+}
+
+/** Update tri->proxies (<b>must</b> be called by rendering callbacks).
+ *             Checks each corner of the given tri to see if the node
+ *             representing the corner has been folded or unfolded, and
+ *             updates the node->proxy field if so.<p>
+ *
+ * Note:       THIS FUNCTION MUST BE CALLED ON EACH TRI BY THE RENDERING
+ *             CALLBACK.  Users writing custom rendering callbacks take note!
+ */
+void vdsUpdateTriProxies(vdsTri *t)
+{
+    if (t->proxies[0]->status != Boundary) {
+       t->proxies[0] = firstActiveAncestor(t->corners[0].id, t->proxies[0]);
+    }
+    if (t->proxies[1]->status != Boundary) {
+       t->proxies[1] = firstActiveAncestor(t->corners[1].id, t->proxies[1]);
+    }
+    if (t->proxies[2]->status != Boundary) {
+       t->proxies[2] = firstActiveAncestor(t->corners[2].id, t->proxies[2]);
+    }
+}
+
+/** Traverses the vertex tree, culling and rendering nodes according to
+ *  user-specified callbacks.
+ *             Traverses the vdsNode tree, calling a user-specified
+ *             function to render the active triangle list stored with
+ *             each node (via the node->vistris linked list).
+ *             Maintaining multiple lists (one per node) allows for
+ *             visibility culling, again via a user-specified callback.
+ *             This callback should take a vdsNode and return 0 (the node
+ *             is completely invisible), 1 (the node may be partially
+ *             visible), or 2 (the node is completely visible).<p>
+ * <b>Note:</b>        Culling is only done down to level VDS_CULLDEPTH of the
+ *             tree, and only nodes at or above VDS_CULLDEPTH have an
+ *             associated vistri list.  There ought to be a more elegant
+ *             way to indicate whether a node is cullable.  A 1-bit flag?
+ * @param      node    The vdsNode being considered for rendering.
+ *             render  The user-specified function for rendering a node.
+ *             cull    The user-specifed function for checking the visibility
+ *                     of a node.  NULL if the node is to be assumed visible.
+ */
+void vdsRenderTree(vdsNode *node, vdsRenderFunction render,
+       vdsVisibilityFunction visible, void *udata)
+{
+    vdsNode *child;
+
+    if (visible != NULL) {
+       int visibility = visible(node);
+       if (visibility == 0) {
+           /* Node invisible, return */
+           return;
+       } else if (visibility == 2) {
+           /* Node completely visible, turn off visibility checking */
+           visible = NULL;
+       }
+    }
+    /* If we got this far, node is visible.  Render it */
+    render(node, udata);
+    /* If node is at VDS_CULLDEPTH, children have no vistris, so can return */
+    if (node->depth == VDS_CULLDEPTH) {
+       return;
+    }
+    child = node->children;
+    while (child != NULL) {
+       vdsRenderTree(child, render, visible, udata);
+       child = child->sibling;
+    }
+}
+
+/*@}*/
+/***************************************************************************\
+
+  Copyright 1999 The University of Virginia.
+  All Rights Reserved.
+
+  Permission to use, copy, modify and distribute this software and its
+  documentation without fee, and without a written agreement, is
+  hereby granted, provided that the above copyright notice and the
+  complete text of this comment appear in all copies, and provided that
+  the University of Virginia and the original authors are credited in
+  any publications arising from the use of this software.
+
+  IN NO EVENT SHALL THE UNIVERSITY OF VIRGINIA
+  OR THE AUTHOR OF THIS SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT,
+  INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+  LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+  DOCUMENTATION, EVEN IF THE UNIVERSITY OF VIRGINIA AND/OR THE
+  AUTHOR OF THIS SOFTWARE HAVE BEEN ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGES.
+
+  The author of the vdslib software library may be contacted at:
+
+  US Mail:             Dr. David Patrick Luebke
+  Department of Computer Science
+  Thornton Hall, University of Virginia
+  Charlottesville, VA 22903
+
+Phone:               (804)924-1021
+
+EMail:               [email protected]
+
+\*****************************************************************************/
+/**
+ * @memo       Debugging and utility routines used throughout VDSlib.
+ * @name       General-purpose utility routines
+ *
+ *             Various debugging and utility functions used throughout the
+ *             view-dependent simplification library.  Basic users of the
+ *             library will probably only care about functions such as
+ *             \Ref{vdsFreeTree}().<p>
+ *
+ * @see util.c */
+/*@{*/
+
+/** Find a node from its vdsNodeId.
+ *             Given a node id and the vertex tree root node, returns a
+ *             pointer to the node
+ */
+vdsNode *vdsFindNode(vdsNodeId id, vdsNode *root)
+{
+    vdsNode *tmp = root;
+    int tmpdepth = 0;
+
+    while (tmpdepth < id.depth) {
+       register int whichchild = PATH_BRANCH(id.path, tmpdepth);
+
+       tmp = tmp->children;
+       while (whichchild > 0) {
+           tmp = tmp->sibling;
+           --whichchild;
+       }
+       ++tmpdepth;
+    }
+    return tmp;
+}
+
+/** Find the common ancestor of two nodes, specified by vdsNodeID.
+ *             Given two node IDs, returns the ID of the first common
+ *             ancestor of the two nodes.  Strictly based on manipulation
+ *             of the IDs; no node structures are actually used, so the
+ *             nodes in question need not be present in memory.
+ * @param      id1             The ID of the first node.
+ * @param      id2             The ID of the second node.
+ * @param      maxdepth        If the nodes share a common ancestor with
+ *                             depth greater than maxdepth, the common
+ *                             ancestor with depth=maxdepth is returned.
+ */
+vdsNodeId vdsFindCommonId(vdsNodeId id1, vdsNodeId id2, int maxdepth)
+{
+    vdsNodeId common = {0, 0};
+    int i, maxcommondepth;
+    vdsNodePath bitmask = VDS_BITMASK;
+
+    maxcommondepth = (id1.depth < id2.depth) ? id1.depth : id2.depth;
+    maxcommondepth = (maxdepth < maxcommondepth) ? maxdepth : maxcommondepth;
+
+    common.depth = 0;
+    for (i = 0; i < maxcommondepth; i++) {
+       if ((id1.path & bitmask) == (id2.path & bitmask)) {
+           /* paths are identical at bits covered by bitmask */
+           common.path |= id1.path & bitmask;
+           common.depth = i + 1;
+           bitmask <<= VDS_NUMBITS;
+       } else {
+           break;
+       }
+    }
+    return common;
+}
+
+/* Assign container nodes for each triangle.
+ *             For each subtri of node, finds the smallest node
+ *             at or above VDS_CULLDEPTH which completely contains the tri.
+ *             When N is unfolded, the subtri is added to the node->vistris
+ *             list of this smallest node for view-frustum culling.  This
+ *             function also assigns all tri->proxies[] to the root node.
+ * @param      node    the node whose subtris are being assigned containers
+ * @param      root    the root of the vertex tree
+ * Note:       Must be called after moveTrisToNodes() !
+ */
+void vdsComputeTriNodes(vdsNode *node, vdsNode *root)
+{
+    int i;
+    vdsTri *t;
+    vdsNodeId c0, c1, c2;              /* The 3 corners of the triangle */
+    vdsNodeId commonId;
+    vdsNode *common;
+    vdsNode *child;
+
+    for (i = 0; i < node->nsubtris; i++) {
+       t = &node->subtris[i];
+       c0 = t->corners[0].id;
+       c1 = t->corners[1].id;
+       c2 = t->corners[2].id;
+       commonId = vdsFindCommonId(c0, c1, VDS_CULLDEPTH);
+       commonId = vdsFindCommonId(c2, commonId, VDS_CULLDEPTH);
+       common = vdsFindNode(commonId, root);
+       t->node = common;
+       t->proxies[0] = t->proxies[1] = t->proxies[2] = root;
+    }
+    child = node->children;
+    while (child != NULL) {
+       vdsComputeTriNodes(child, root);
+       child = child->sibling;
+    }
+}
+
+/** Print a vdsNodeId to stdout.
+ *             Prints the node ID (depth & path down the vertex tree) in
+ *             human-readable form to stdout.
+ *
+ */
+void vdsPrintNodeId(const vdsNodeId *id)
+{
+    int i;
+    vdsNodePath tmppath = id->path;
+
+    if (id->depth == 0) {
+       printf("<root>\n");
+    } else {
+       for (i = 0; i < id->depth; i++) {
+           putchar((char) (tmppath & VDS_BITMASK) + '0');
+           tmppath >>= VDS_NUMBITS;
+       }
+       putchar('\n');
+    }
+}
+
+/** Gather statistics for a vertex tree.
+ *             Recursively counts the number of nodes, the number of
+ *             leaf nodes (i.e., vertices from the original model), and the
+ *             number of subtris (i.e., triangles in the original model)
+ *             in the subtree rooted at <root>.
+ */
+void vdsStatTree(vdsNode *root, int *nodes, int *leaves, int *tris)
+{
+    vdsNode *child;
+    int childnodes, childleaves, childtris;
+
+    child = root->children;
+    *nodes = *leaves = *tris = 0;
+    childnodes = childleaves = childtris = 0;
+    /* If the child is internal, recursivily count its children's nodes */
+    if (child != NULL) {
+       while (child != NULL) {
+           vdsStatTree(child, &childnodes, &childleaves, &childtris);
+           *nodes += childnodes;
+           *leaves += childleaves;
+           *tris += childtris;
+           child = child->sibling;
+       }
+       /* don't forget to count this node: */
+       *nodes += 1;
+       *tris += root->nsubtris;
+    } else {
+       *nodes = 1;
+       *leaves = 1;
+       /* leaf nodes have no subtris */
+    }
+}
+
+/** Calculate a triangle's current normal.
+ *             Calculates a triangle's normal, say for flat-shading, by
+ *             taking the cross product of two of its edges.  Places the
+ *             result in <b>normal</b>. <p>
+ *
+ * <b>Note</b>:        This calculates the normal of the triangle as currently
+ *             simplified!  Triangles that don't exist in the current
+ *             simplification will produce undefined behavior.
+ */
+void vdsCalcTriNormal(vdsTri *t, vdsVec3 normal)
+{
+    vdsVec3 tmp1, tmp2;
+
+    VEC3_SUBTRACT(tmp1, t->proxies[1]->coord, t->proxies[0]->coord);
+    VEC3_SUBTRACT(tmp2, t->proxies[2]->coord, t->proxies[0]->coord);
+    VEC3_CROSS(normal, tmp1, tmp2);
+    VEC3_NORMALIZE(normal);
+}
+
+/** Free all memory used by a vertex tree.
+ *             Recursively frees the given VDS vertex tree and all associated
+ *             vdsTri structs.<p>
+ * <b>Note</b>:        Does NOT free anything pointed at by the node->data 
field;
+ *             this is left to application.
+ */
+void vdsFreeTree(vdsNode *node)
+{
+    vdsNode *child = node->children;
+
+    while (child != NULL) {
+       vdsNode *sibling = child->sibling;
+
+       vdsFreeTree(child);
+       child = sibling;
+    }
+    /* I think just freeing node will free up all its subtris correctly... */
+    free(node);
+}
+
+/*@}*/
+/***************************************************************************\
+
+  Copyright 1999 The University of Virginia.
+  All Rights Reserved.
+
+  Permission to use, copy, modify and distribute this software and its
+  documentation without fee, and without a written agreement, is
+  hereby granted, provided that the above copyright notice and the
+  complete text of this comment appear in all copies, and provided that
+  the University of Virginia and the original authors are credited in
+  any publications arising from the use of this software.
+
+  IN NO EVENT SHALL THE UNIVERSITY OF VIRGINIA
+  OR THE AUTHOR OF THIS SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT,
+  INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+  LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+  DOCUMENTATION, EVEN IF THE UNIVERSITY OF VIRGINIA AND/OR THE
+  AUTHOR OF THIS SOFTWARE HAVE BEEN ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGES.
+
+  The author of the vdslib software library may be contacted at:
+
+  US Mail:             Dr. David Patrick Luebke
+  Department of Computer Science
+  Thornton Hall, University of Virginia
+  Charlottesville, VA 22903
+
+Phone:               (804)924-1021
+
+EMail:               [email protected]
+
+\*****************************************************************************/
+/**
+ * @memo       Routines for reading and writing vertex trees.
+ * @name       Vertex tree file I/O
+ *
+ * These routines provide a mechanism for saving a VDS vertex tree to a
+ * terse binary file format, and reading it back.  This file format is a
+ * bit rough at the moment.  For example, it does not deal with differences
+ * between big-endian and little-endian machines, so files created on one
+ * architecture may not run on another architecture.  Expect file I/O to
+ * change and improve with following versions of the library.<p>
+ *
+ * @see file.c */
+/*@{*/
+
+static void writeNode(FILE *f, vdsNode *node, vdsNodeDataWriter putdata);
+static vdsNode *readNode(FILE *f, vdsNodeDataReader getdata);
+static vdsNode *readChildren(FILE *f, vdsNode *parent, vdsNodeDataReader get);
+static void writeChildren(FILE *f, vdsNode *parent, vdsNodeDataWriter put);
+
+/** Read a vertex tree from a VDS binary file.
+ *             The user may specify a vdsNodeDataReader function
+ *             <b>readdata()</b> if the vertex tree was written with
+ *             custom data in the node->data field.  If <b>readdata()</b>
+ *             is NULL, the node->data field is simply copied
+ *             byte-for-byte into memory.
+ * @param      f               The file to be read.
+ * @param      readdata        A vdsNodeDataReader function callback to read
+ *                             the contents of the node->data field, or NULL
+ *                             to simply read node->data byte-for-byte.
+ * @return     A pointer to the root node of the new tree.
+ */
+vdsNode *vdsReadTree(FILE *f, vdsNodeDataReader readdata)
+{
+    int major, minor;
+    int numnodes, numverts, numtris;
+    vdsNode *root;
+
+    if (fscanf(f, "VDS Vertex Tree file format version %d.%d\n",
+               &major, &minor) != 2) {
+       fprintf(stderr, "Error reading line 1 of input file.\n");
+       exit(1);
+    }
+    if (fscanf(f, "Total nodes: %d\nVertices: %d\nTriangles: %d\n",
+               &numnodes, &numverts, &numtris) != 3) {
+       fprintf(stderr, "Error reading lines 2-4 of input file.\n");
+       exit(1);
+    }
+    /* Read the tree, starting with the root node */
+    root = readNode(f, readdata);
+    root->parent = NULL;
+    root->depth = 0;
+    root->children = readChildren(f, root, readdata);
+    vdsComputeTriNodes(root, root);
+    root->status = Boundary;
+    root->next = root->prev = root;
+    return root;
+}
+
+/*
+ * Function:   readChildren
+ * Description:        Reads a group of nodes, which are sibling children of 
<parent>
+ *             stored adjacently in a VDS binary file.  Then, recursively
+ *             reads THEIR children in depth-first order.
+ * Returns:    The address of the first node in the group of siblings.
+ */
+static vdsNode *readChildren(FILE *f, vdsNode *parent, vdsNodeDataReader get)
+{
+    vdsNode *node, *firstnode;
+
+    firstnode = readNode(f, get);
+    node = firstnode;
+    while (node != NULL) {
+       node->parent = parent;
+       node->depth = parent->depth + 1;
+       /* Unless its NULL, overwrite node->sibling (which is garbage) */
+       if (node->sibling != NULL) {
+           node->sibling = readNode(f, get);
+       }
+       node = node->sibling;
+    }
+    node = firstnode;
+    while (node != NULL) {
+       if (node->children != NULL) {
+           node->children = readChildren(f, node, get);
+       }
+       node = node->sibling;
+    }
+    return firstnode;
+}
+
+/*
+ * Function:   readNode
+ * Description:        Reads a single node from the VDS binary file, leaving
+ *             information like parent and depth to be filled in by the
+ *             caller.
+ */
+static vdsNode *readNode(FILE *f, vdsNodeDataReader getdata)
+{
+    vdsNode *node;
+    int numchildren, numsubtris;
+
+    node = (vdsNode *) calloc(1, sizeof(vdsNode));
+    node->status = Inactive;
+    fread(&node->bound, sizeof(vdsBoundingVolume), 1, f);
+    fread(&node->coord, sizeof(vdsVec3), 1, f);
+    fread(&numchildren, sizeof(numchildren), 1, f);
+    /* if numchildren is 0, set node->children NULL, otherwise to non-NULL */
+    node->children = (numchildren == 0 ? NULL : (vdsNode *) 0x1);
+    /* Read sibling pointer (actually we just care if it's NULL or not) */
+    fread(&node->sibling, sizeof(node->sibling), 1, f);
+    /*
+     * We can read and write the triangles directly to the binary file, at
+     * the expense of re-running vdsComputeTriNodes() afterwards.  Also,
+     * writing the entire structure (versus each field separately) means
+     * that we are locked to a particular architecture/compiler's memory
+     * alignment...not very portable.
+     */
+    fread(&numsubtris, sizeof(numsubtris), 1, f);
+    node->nsubtris = numsubtris;
+    node = (vdsNode *) realloc(node, sizeof(vdsNode) +
+           numsubtris * sizeof(vdsTri));
+    fread(&node->subtris[0], sizeof(vdsTri), numsubtris, f);
+    /* Now get the associated node data if user has provided a function */
+    if (getdata == NULL) {
+       fread(&node->data, sizeof(vdsNodeData), 1, f);
+    } else {
+       node->data = getdata(f);
+    }
+    return node;
+}
+
+/** Writes a vertex tree to a VDS binary file.
+ *             Writes a vertex tree to the specified file.  The user may
+ *             specify a vdsNodeDataWriter function <b>writedata()</b> if the
+ *             vertex tree was written with custom data in the node->data
+ *             field.  If <b>writedata()</b> is NULL, the contents of the
+ *             node->data field are simply copied byte-for-byte into the file.
+ * @param      f       The file to which the tree is written
+ * @param      root            The root of the vertex tree to be written.
+ * @param      writedata       A vdsNodeDataReader function callback to read
+ *                             the contents of the node->data field, or NULL
+ *                             to simply read node->data byte-for-byte.
+ */
+void vdsWriteTree(FILE *f, vdsNode *root, vdsNodeDataWriter writedata)
+{
+    int numnodes, numverts, numtris;
+
+    fprintf(f, "VDS Vertex Tree file format version %d.%d\n", MAJOR, MINOR);
+    vdsStatTree(root, &numnodes, &numverts, &numtris);
+    fprintf(f, "Total nodes: %d\n", numnodes);
+    fprintf(f, "Vertices: %d\n", numverts);
+    fprintf(f, "Triangles: %d\n", numtris);
+    fflush(f);
+    /* Save the root node to disk */
+    writeNode(f, root, writedata);
+    /* Now recursively save its children, grouping siblings together on disk */
+    writeChildren(f, root, writedata);
+}
+
+/*
+ * Function:   writeChildren
+ * Description:        Writes all of the given node's children to disk, then
+ *             recursively writes their children in depth-first order.
+ */
+static void writeChildren(FILE *f, vdsNode *parent, vdsNodeDataWriter put)
+{
+    vdsNode *child;
+
+    child = parent->children;
+    while (child != NULL) {
+       writeNode(f, child, put);
+       child = child->sibling;
+    }
+    child = parent->children;
+    while (child != NULL) {
+       if (child->children != NULL) {
+           writeChildren(f, child, put);
+       }
+       child = child->sibling;
+    }
+}
+
+/*
+ * Function:   writeNode
+ * Description:        Writes the essential fields of a single vdsNode to a
+ * VDS binary file.
+ */
+static void writeNode(FILE *f, vdsNode *node, vdsNodeDataWriter putdata)
+{
+    vdsNode *child;
+    int numchildren = 0, numsubtris = node->nsubtris;
+
+    fwrite(&node->bound, sizeof(vdsBoundingVolume), 1, f);
+    fwrite(&node->coord, sizeof(vdsVec3), 1, f);
+    child = node->children;
+    while (child != NULL) {
+       numchildren ++;
+       child = child->sibling;
+    }
+    fwrite(&numchildren, sizeof(numchildren), 1, f);
+    /* Write the sibling pointer (actually we just care if it's NULL or not) */
+    fwrite(&node->sibling, sizeof(node->sibling), 1, f);
+    /* Write all the subtris (if any) associated with this node */
+    fwrite(&numsubtris, sizeof(numsubtris), 1, f);
+    fwrite(&node->subtris[0], sizeof(vdsTri), numsubtris, f);
+    /* Now write associated node data using user-supplied function (if any) */
+    if (putdata == NULL) {
+       fwrite(&node->data, sizeof(vdsNodeData), 1, f);
+    } else {
+       putdata(f, node);
+    }
+}
+
+/*@}*/
+
+/*
+ * Local Variables:
+ * tab-width: 8
+ * mode: C
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */

Copied: brlcad/trunk/src/librt/vds/vds.h (from rev 77312, 
brlcad/trunk/src/other/libvds/vds.h)
===================================================================
--- brlcad/trunk/src/librt/vds/vds.h                            (rev 0)
+++ brlcad/trunk/src/librt/vds/vds.h    2020-10-01 21:17:30 UTC (rev 77313)
@@ -0,0 +1,336 @@
+/***************************************************************************\
+
+  Copyright 1999 The University of Virginia.
+  All Rights Reserved.
+
+  Permission to use, copy, modify and distribute this software and its
+  documentation without fee, and without a written agreement, is
+  hereby granted, provided that the above copyright notice and the
+  complete text of this comment appear in all copies, and provided that
+  the University of Virginia and the original authors are credited in
+  any publications arising from the use of this software.
+
+  IN NO EVENT SHALL THE UNIVERSITY OF VIRGINIA
+  OR THE AUTHOR OF THIS SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT,
+  INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+  LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+  DOCUMENTATION, EVEN IF THE UNIVERSITY OF VIRGINIA AND/OR THE
+  AUTHOR OF THIS SOFTWARE HAVE BEEN ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGES.
+
+  The author of the vdslib software library may be contacted at:
+
+  US Mail:             Dr. David Patrick Luebke
+  Department of Computer Science
+  Thornton Hall, University of Virginia
+  Charlottesville, VA 22903
+
+Phone:               (804)924-1021
+
+EMail:               [email protected]
+
+\*****************************************************************************/
+
+/**
+ * Note: This is just an unofficial overview of the basics of what libvds
+ * is/does and how to use it. It is not guaranteed to be complete or accurate!
+ *
+ * VDSlib supports view-dependent hierarchical dynamic simplification. The
+ * input vertices are grouped into the cells of a recursive octree spatial
+ * subdivision. The resulting tree is a collection of nodes, each with at most
+ * eight children. The single vertex to which a cell collapses, by default, is
+ * the average of all vertices in the cell (as an example, this could be
+ * changed to be one of the actual vertices based on some notion of
+ * importance).
+ *
+ * 1) Specify the input mesh.
+ *
+ * Call vdsBeginVertexTree() and vdsBeginGeometry(), then create one node per
+ * vertex using vdsAddNode(). Specify triangles as three indices corresponding
+ * to the leaf nodes. VDSlib initially maintains all this information in global
+ * state. You finish by calling vdsEndGeometry(), which returns a list of all
+ * the leaf nodes that were created.
+ *
+ * 2) Build the vertex tree.
+ *
+ * Call clusterOctree() to cluster nodes to form the vertex tree using
+ * vdsClusterNodes(). Then finish by calling vdsEndVertexTree(), which returns
+ * the root node of the tree.
+ *
+ * vdsEndVertexTree() does several things:
+ * - assigns ids to all the nodes
+ * - sets the root as the sole boundary node, and sets all other nodes to 
inactive
+ * - moves the data for each triangle from the global state to the subtris
+ *   array of the deepest node (smallest cell) containing at least two of its
+ *   vertices
+ *
+ * 3) Adjust the tree.
+ *
+ * Use vdsAdjustTreeTopDown() to fold/unfold nodes. When a node is unfolded,
+ * its subtris become visible. Each subtri is added to the vistris list of the
+ * deepest node (smallest cell) at or above VDS_CULLDEPTH which contains all
+ * three of its vertices.
+ *
+ * 4) Draw the tree.
+ *
+ * Use vdsRenderTree to walk the entire tree. The set of triangles in all the
+ * non-NULL vistris lists form the active triangle set. Calling
+ * vdsUpdateTriProxies() on each vdsTri in a node's vistris list calculates the
+ * proxy node corresponding to each corner (the deepest active/unfolded node
+ * that contains the corner).
+ */
+
+/**
+ * @memo       Some important macros used to configure VDSlib.
+ * @name       VDSlib macros
+ *
+ * These macros are defined in the main header file for the view-dependent
+ * simplification library.  \Ref{VDS_MAXDEGREE} sets the maximum degree of
+ * the vertex tree.  For example, a tree built by octree-style clustering
+ * has a maximum degree of 8; a tree built by progressive edge-collapse
+ * operations has a maximum degree of 2.  At the moment VDS_MAXDEGREE only
+ * affects the number of bits used in the vdsNodePath (see
+ * \Ref{VDS_64_BITS}), but eventually VDSlib will include special
+ * optimizations for binary trees (VDS_MAXDEGREE = 2).  Currently VDSlib
+ * only supports setting VDS_MAXDEGREE to 2, 4, or 8.<p>
+ *
+ * Define \Ref{VDS_DOUBLE_PRECISION} to make all floating-point numbers
+ * used by VDSlib (i.e., vdsFloats) double-precision.  This is highly
+ * recommended if you are dealing with complex models; on many modern
+ * architectures double-precision arithmetic is the faster option anyway.
+ *
+ * @see vds.h */
+/*@{*/
+
+#ifndef _VDS_H
+#define _VDS_H
+
+#include <stdio.h>
+
+/** VDS_MAXDEGREE defines the maximum degree of vertex tree nodes      */
+#define VDS_MAXDEGREE 8
+/** VDS_CULLDEPTH defines the depth to which the vertex tree is culled */
+#define VDS_CULLDEPTH 4
+
+/** Define VDS_DOUBLE_PRECISION to make everything double precision */
+#define VDS_DOUBLE_PRECISION
+
+#ifdef VDS_DOUBLE_PRECISION
+typedef double vdsFloat;
+#else
+typedef float vdsFloat;
+#endif
+
+typedef vdsFloat vdsVec2[2];
+typedef vdsFloat vdsVec3[3];
+typedef unsigned char vdsByte3[3];
+
+/** Define VDS_64_BITS for 64-bit node paths.
+ *
+ * A vdsNodePath is a bit vector encapsulating the path from the root of a
+ * vertex tree down to a given node.  For a binary tree, each bit represents
+ * a branch; for an 8-way tree, 3 bits represent a branch, etc.  Defining
+ * VDS_64_BITS enforces 64-bit paths.  This enables much larger vertex trees
+ * but may be slower on some architectures.<p>
+ *
+ * Note: for convenience, the depth of the node (and thus the node path length)
+ * is currently stored separately, and all unused bits must be set to zero.
+ */
+#define VDS_64_BITS            /* don't define for 32-bit node paths   */
+#ifdef VDS_64_BITS
+typedef unsigned long long vdsNodePath;
+#else
+typedef unsigned int vdsNodePath;
+#endif
+
+/* Label node as Active (unfolded), Inactive (folded), or on the Boundary: */
+typedef enum _vdsNodeStatus {
+    Boundary = 0,                      /* Set Boundary to 0 for speed  */
+    Inactive,
+    Active
+} vdsNodeStatus;
+
+/* Bound the triangles supported by a node.
+ *             A bounding volume is associated with each node; the volume
+ *             contains all triangles supported by the node.  Currently I
+ *             use a bounding sphere for simplicity, but this may be less
+ *             than optimal.  Two possible improvements: <ll>
+ *             <li>Following Hoppe's "Efficient Implementation of Progressive
+ *                 Meshes", center the bounding sphere on node->coord.  This
+ *                 saves storing 3 floats per node, at the cost of more
+ *                 conservative visibility and screenspace-extent tests.
+ *             <li>Use a tighter bounding volume (AABBs? OBBs? Ellipsoids?).
+ *                 There is a tradeoff here between storage and accuracy.</ll>
+ */
+typedef struct _vdsBoundingVolume {
+    vdsVec3    center;                 /* center of the sphere         */
+    vdsFloat   radius;                 /* size of the sphere           */
+} vdsBoundingVolume;
+
+typedef void *vdsNodeData;             /* hook for user data           */
+
+typedef struct _vdsNodeId {
+    vdsNodePath        path;                   /* path down tree to node       
*/
+    char       depth;                  /* 1 byte depth info for now    */
+} vdsNodeId;
+
+typedef union {
+    vdsNodeId  id;     /* node depth, path down tree   */
+    int                index;  /* leaf node index; used during vertex tree 
construction */
+} vdsTriCorner;
+
+/*
+ * Note on vdsTri: should use Hoppe's "wedge" structures or something similar
+ * to avoid replicating colors and normals at every triangle corner.  Would
+ * this be hard keep memory-coherent in an out-of-core implementation?
+ */
+typedef struct _vdsTri {
+    vdsTriCorner       corners[3];     /* leaf nodes corresponding to  *
+                                        * 3 original corner vertices   */
+    struct _vdsNode    *proxies[3];    /* nodes representing corners;  *
+                                        * i.e., the FAA of each corner */
+    struct _vdsNode    *node;          /* smallest node containing tri */
+    vdsVec3            normal[3];      /* normal for the tri           */
+    vdsByte3           color[3];       /* RGB for the tri's corners    */
+    struct _vdsTri     *next;          /* next in linked vistri list   */
+    struct _vdsTri     *prev;          /* prev in linked vistri list   */
+} vdsTri;
+
+/*
+ * Note on vdsNode: Should combine depth and status into a single word,
+ * saving 32 bits, and center bounding volume on coord to eliminate
+ * a vdsVec3, saving 96-192 bits (depending on VDS_DOUBLE_PRECISION)
+ */
+typedef struct _vdsNode {
+    /* 3 bitfields (32 bits total): */
+    char               depth;          /* depth of node in vertex tree */
+    int                        nsubtris;       /* size of node->subtris[] 
array*/
+    vdsNodeStatus      status;         /* is node currently active?    */
+
+    vdsBoundingVolume  bound;          /* bounding volume of triangles *
+                                        * supported by the node        */
+    vdsVec3            coord;          /* coordinate of node's proxy   */
+    vdsTri             *vistris;       /* linked list of visible tris  *
+                                        * contained by this node       */
+    vdsNodeData                data;           /* auxiliary node data          
*/
+    struct _vdsNode    *next;          /* next node in boundary path   */
+    struct _vdsNode    *prev;          /* prev node in boundary path   */
+    struct _vdsNode    *parent;        /* the parent node              */
+    struct _vdsNode    *children;      /* first of the node's children */
+    struct _vdsNode    *sibling;       /* node's next sibling          */
+    /* Array of tris created/deleted if node is folded/unfolded.       *
+     * NOTE: Actually a variable-length array!                         */
+    vdsTri             subtris[1];
+} vdsNode;
+
+/*
+ * Callback typedefs
+ *
+ *     vdsRenderFunction:      render the given node
+ *             Note:                   Must call vdsUpdateTriCorners() on tris
+ *     vdsVisibilityFunction:  determine visibility of the given node
+ *             Return codes:           0: node invisible
+ *                                     1: node potentially visible
+ *                                     2: node & subtree *completely* visible
+ *     vdsFoldCriterion:       decide whether a node should be folded
+ *             Return codes:           0: node should be unfolded
+ *                                     1: node should be folded
+ *     vdsNodeDataWriter:      write node->data contents to a file
+ *     vdsNodeDataReader:      read node->data contents from a file
+ *             Returns:                allocated vdsNodeData structure
+ */
+typedef void (*vdsRenderFunction) (const vdsNode *, void *);
+typedef int (*vdsVisibilityFunction) (const vdsNode *);
+typedef int (*vdsFoldCriterion) (const vdsNode *, void *);
+typedef void (*vdsNodeDataWriter) (FILE *f, const vdsNode *);
+typedef vdsNodeData (*vdsNodeDataReader) (FILE *f);
+
+/*
+ * Prototypes
+ */
+
+/* Routines for maintaining the vertex tree (dynamic.c) */
+extern void vdsAdjustTreeBoundary(vdsNode *, vdsFoldCriterion, void *);
+extern void vdsAdjustTreeTopDown(vdsNode *, vdsFoldCriterion, void *);
+/* Low-level vertex tree maintainance routines; not need by most users: */
+extern void vdsFoldNode(vdsNode *);
+extern void vdsUnfoldNode(vdsNode *);
+extern void vdsFoldSubtree(vdsNode *);
+
+/* Routines for rendering the vertex tree (render.c) */
+extern void vdsUpdateTriProxies(vdsTri *t);
+extern void vdsRenderTree(vdsNode *node, vdsRenderFunction render,
+       vdsVisibilityFunction visible, void *udata);
+
+/* Routines for building the vertex tree (build.c) */
+extern void vdsBeginVertexTree();
+extern void vdsBeginGeometry();
+extern vdsNode *vdsAddNode(vdsFloat x, vdsFloat y, vdsFloat z);
+extern vdsTri *vdsAddTri(int v0, int v1, int v2,
+       vdsVec3 n0, vdsVec3 n1, vdsVec3 n2,
+       vdsByte3 c0, vdsByte3 c1, vdsByte3 c2);
+extern void vdsNewObject();
+extern vdsNode *vdsEndGeometry();
+extern vdsNode *vdsClusterNodes(int nnodes, vdsNode **nodes,
+       vdsFloat x, vdsFloat y, vdsFloat z);
+extern vdsNode *vdsEndVertexTree();
+
+/* Routines for reading and writing the vertex tree (file.c) */
+extern vdsNode *vdsReadTree(FILE *f, vdsNodeDataReader readdata);
+extern void vdsWriteTree(FILE *f, vdsNode *root, vdsNodeDataWriter writedata);
+
+/* Assorted useful routines (util.c) */
+extern vdsNode *vdsFindNode(vdsNodeId id, vdsNode *root);
+extern void vdsPrintNodeId(const vdsNodeId *id);
+extern void vdsSprintNodeId(char *str, const vdsNodeId *id);
+extern void vdsStatTree(vdsNode *root, int *nodes, int *leaves, int *tris);
+extern void vdsFreeTree(vdsNode *node);
+
+/* (cluster.c) */
+extern vdsNode *vdsClusterOctree(vdsNode **nodes, int nnodes, int depth);
+
+/*
+ * The following macros relate to the maximum degree of the vertex tree,
+ * which dictates the maximum depth and the number of bits stored per branch.
+ */
+#if VDS_MAXDEGREE == 2
+#    define VDS_NUMBITS 1
+#    define VDS_BITMASK 1
+#    ifdef VDS_64_BITS
+#      define VDS_MAXDEPTH 64
+#    else
+#      define VDS_MAXDEPTH 32
+#    endif
+#elif VDS_MAXDEGREE == 4
+#    define VDS_NUMBITS 2
+#    define VDS_BITMASK 3
+#    ifdef VDS_64_BITS
+#      define VDS_MAXDEPTH 32
+#    else
+#      define VDS_MAXDEPTH 16
+#    endif
+#elif VDS_MAXDEGREE == 8
+#    define VDS_NUMBITS 3
+#    define VDS_BITMASK 7
+#    ifdef VDS_64_BITS
+#      define VDS_MAXDEPTH 21
+#    else
+#      define VDS_MAXDEPTH 10
+#    endif
+#else
+#    error "Only values of 2, 4, and 8 supported for VDS_MAXDEGREE"
+#endif
+
+#endif         /* _VDS_H */
+
+/*@}*/
+
+/*
+ * Local Variables:
+ * tab-width: 8
+ * mode: C
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */

Modified: brlcad/trunk/src/other/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/other/CMakeLists.txt       2020-10-01 21:08:02 UTC (rev 
77312)
+++ brlcad/trunk/src/other/CMakeLists.txt       2020-10-01 21:17:30 UTC (rev 
77313)
@@ -782,25 +782,6 @@
   endif(BRLCAD_GECODE_BUILD)
 endif(BRLCAD_ENABLE_GECODE)
 
-# VDSlib - A View-Dependent Simplification and Rendering Library For
-# the moment, this is marked NOSYS - it's possible that some Debian
-# systems would have 0.9 of vdslib installed, but it's unmaintained
-# and we're likely to be making changes.  If our own copy of VDSlib
-# ever spins back off into its own project, revisit the NOSYS
-set(libvds_DESCRIPTION "
-Option for enabling and disabling compilation of the libvds triangle
-simplification library provided with BRL-CAD's source code.  Default
-is AUTO, responsive to the toplevel BRLCAD_BUNDLED_LIBS option and
-testing first for a system version if BRLCAD_BUNDLED_LIBS is also
-AUTO.
-")
-THIRD_PARTY(libvds VDS vds libvds_DESCRIPTION ALIASES ENABLE_VDS FLAGS NOSYS)
-set(LIBVDS_INCLUDE_DIR "${BRLCAD_SOURCE_DIR}/src/other/libvds" CACHE STRING 
"Directory containing libvds headers." FORCE)
-mark_as_advanced(LIBVDS_INCLUDE_DIR)
-SetTargetFolder(vds "Third Party Libraries")
-SetTargetFolder(vds-static "Third Party Libraries")
-
-
 # OpenSceneGraph Libraries
 set(openscenegraph_DESCRIPTION "
 Option for enabling and disabling compilation of the OpenSceneGraph

Deleted: brlcad/trunk/src/other/libvds.dist
===================================================================
--- brlcad/trunk/src/other/libvds.dist  2020-10-01 21:08:02 UTC (rev 77312)
+++ brlcad/trunk/src/other/libvds.dist  2020-10-01 21:17:30 UTC (rev 77313)
@@ -1,7 +0,0 @@
-set(libvds_ignore_files
-CMakeLists.txt
-COPYING
-README
-vds.c
-vds.h
-)

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to