Initial revision

This commit is contained in:
David Rose
2000-10-04 01:14:41 +00:00
parent 7a78284129
commit 2fd714e52f
2145 changed files with 269592 additions and 0 deletions

49
panda/Config.Irix.pp Normal file
View File

@@ -0,0 +1,49 @@
//
// Config.Irix.pp
//
// This file defines some custom config variables for the SGI/Irix
// platform. It makes some initial guesses about compiler features,
// etc.
//
// Is the platform big-endian (like an SGI workstation) or
// little-endian (like a PC)? Define this to the empty string to
// indicate little-endian, or nonempty to indicate big-endian.
#define WORDS_BIGENDIAN 1
// Does the C++ compiler support namespaces?
#define HAVE_NAMESPACE 1
// Does the C++ compiler support ios::binary?
#define HAVE_IOS_BINARY
// Do we have a gettimeofday() function?
#define HAVE_GETTIMEOFDAY 1
// Does gettimeofday() take only one parameter?
#define GETTIMEOFDAY_ONE_PARAM
// Do we have getopt() and/or getopt_long_only() built into the
// system?
#define HAVE_GETOPT 1
#define HAVE_GETOPT_LONG_ONLY
// Should we include <iostream> or <iostream.h>? Define HAVE_IOSTREAM
// to nonempty if we should use <iostream>, or empty if we should use
// <iostream.h>.
#define HAVE_IOSTREAM
// Do we have a true stringstream class defined in <sstream>?
#define HAVE_SSTREAM
// Do we have <malloc.h>?
#define HAVE_MALLOC_H 1
// Do we have <alloca.h>?
#define HAVE_ALLOCA_H 1
// Do we have <sys/types.h>?
#define HAVE_SYS_TYPES_H 1
// Do we have <unistd.h>?
#define HAVE_UNISTD_H 1

49
panda/Config.Linux.pp Normal file
View File

@@ -0,0 +1,49 @@
//
// Config.Linux.pp
//
// This file defines some custom config variables for the Linux
// platform. It makes some initial guesses about compiler features,
// etc.
//
// Is the platform big-endian (like an SGI workstation) or
// little-endian (like a PC)? Define this to the empty string to
// indicate little-endian, or nonempty to indicate big-endian.
#define WORDS_BIGENDIAN
// Does the C++ compiler support namespaces?
#define HAVE_NAMESPACE 1
// Does the C++ compiler support ios::binary?
#define HAVE_IOS_BINARY 1
// Do we have a gettimeofday() function?
#define HAVE_GETTIMEOFDAY 1
// Does gettimeofday() take only one parameter?
#define GETTIMEOFDAY_ONE_PARAM
// Do we have getopt() and/or getopt_long_only() built into the
// system?
#define HAVE_GETOPT 1
#define HAVE_GETOPT_LONG_ONLY 1
// Should we include <iostream> or <iostream.h>? Define HAVE_IOSTREAM
// to nonempty if we should use <iostream>, or empty if we should use
// <iostream.h>.
#define HAVE_IOSTREAM
// Do we have a true stringstream class defined in <sstream>?
#define HAVE_SSTREAM
// Do we have <malloc.h>?
#define HAVE_MALLOC_H 1
// Do we have <alloca.h>?
#define HAVE_ALLOCA_H 1
// Do we have <sys/types.h>?
#define HAVE_SYS_TYPES_H 1
// Do we have <unistd.h>?
#define HAVE_UNISTD_H 1

49
panda/Config.Win32.pp Normal file
View File

@@ -0,0 +1,49 @@
//
// Config.Win32.pp
//
// This file defines some custom config variables for the Windows
// platform. It makes some initial guesses about compiler features,
// etc.
//
// Is the platform big-endian (like an SGI workstation) or
// little-endian (like a PC)? Define this to the empty string to
// indicate little-endian, or nonempty to indicate big-endian.
#define WORDS_BIGENDIAN
// Does the C++ compiler support namespaces?
#define HAVE_NAMESPACE 1
// Does the C++ compiler support ios::binary?
#define HAVE_IOS_BINARY 1
// Do we have a gettimeofday() function?
#define HAVE_GETTIMEOFDAY
// Does gettimeofday() take only one parameter?
#define GETTIMEOFDAY_ONE_PARAM
// Do we have getopt() and/or getopt_long_only() built into the
// system?
#define HAVE_GETOPT
#define HAVE_GETOPT_LONG_ONLY
// Should we include <iostream> or <iostream.h>? Define HAVE_IOSTREAM
// to nonempty if we should use <iostream>, or empty if we should use
// <iostream.h>.
#define HAVE_IOSTREAM 1
// Do we have a true stringstream class defined in <sstream>?
#define HAVE_SSTREAM 1
// Do we have <malloc.h>?
#define HAVE_MALLOC_H 1
// Do we have <alloca.h>?
#define HAVE_ALLOCA_H
// Do we have <sys/types.h>?
#define HAVE_SYS_TYPES_H 1
// Do we have <unistd.h>?
#define HAVE_UNISTD_H

167
panda/Config.pp Normal file
View File

@@ -0,0 +1,167 @@
//
// Config.pp
//
// This file defines certain configuration variables that are written
// into the various make scripts. It is processed by ppremake (along
// with the Sources.pp files in each of the various directories) to
// generate build scripts appropriate to each environment.
//
// ppremake is capable of generating generic Unix autoconf/automake
// style build scripts, as well as makefiles customized for SGI's
// MipsPRO compiler or for Microsoft's Visual C++. It can also
// generate Microsoft Developer's Studio project files directly. In
// principle, it can be extended to generate suitable build script
// files for any number of different build environments.
//
// All of these build scripts can be tuned for a particular
// environment via this file. This is the place for the user to
// specify which external packages are installed and where, or to
// enable or disable certain optional features. However, it is
// suggested that rather than modify this file directly, you create a
// custom file in your home directory and there redefine whatever
// variables are appropriate, and set the environment variable
// PPREMAKE_CONFIG to refer to it. In this way, you can easily get an
// updated source tree (including a new Config.pp) without risking
// accidentally losing your customizations. This also avoids having
// to redefine the same variables in different packages (for instance,
// in dtool and in panda).
//
// If you *do* decide to make changes directly to this file, you
// should also comment out the line near the bottom that includes the
// file $[TOPDIRPREFIX]Config.$[PLATFORM].pp, to avoid stomping on the
// changes you make.
//
// The syntax in this file resembles some hybrid between C++
// preprocessor declarations and GNU make variables. This is the same
// syntax used in the various ppremake system configure files; it's
// designed to be easy to use as a macro language to generate
// makefiles and their ilk.
//
// What kind of build scripts are we generating? This selects a
// suitable template file from the ppremake system files. The
// allowable choices, at present, are:
//
// autoconf - Generate configure.in and a series of Makefile.am files,
// suitable for using with autoconf/automake. Not quite
// there yet.
// stopgap - Generate original Cary-style Makefile/Makefile.install/etc.
// files, to ease transition to the new system.
//
#define BUILD_TYPE stopgap
// Define the directory in which the system ppremake files are
// installed.
#define PPREMAKE_DIR /usr/local/panda/share
// In which directory should this package be installed when you type
// "make install"? This has no meaning when BUILD_TYPE is "stopgap".
#define INSTALL_DIR /usr/local/panda
// What level of compiler optimization/debug symbols should we build?
// The various optimize levels are defined as follows:
//
// 1 - No compiler optimizations, full debug symbols
// 2 - Full compiler optimizations, full debug symbols
// (if the compiler supports this)
// 3 - Full compiler optimizations, no debug symbols
// 4 - Full optimizations, no debug symbols, and asserts removed
//
// Setting this has no effect when BUILD_TYPE is "stopgap". In this
// case, the compiler optimizations are selected by setting the
// environment variable OPTIMIZE accordingly at compile time.
#define OPTIMIZE 1
////////////////////////////////////////////////////////////////////
// The remaining variables are considered only if BUILD_TYPE is not
// "autoconf". (Autoconf can determine these directly.)
////////////////////////////////////////////////////////////////////
// NOTE: In the following, to indicate "yes" to a yes/no question,
// define the variable to be a nonempty string. To indicate "no",
// define the variable to be an empty string.
// Is Python installed, and should Python interfaces be generated? If
// Python is installed, which directory is it in? (If the directory
// is someplace standard like /usr/include, you may leave it blank.)
#define HAVE_PYTHON 1
#define PYTHON_INCLUDE /usr/local/include/python1.6
#define PYTHON_LIB
// Is NSPR installed, and where?
#define HAVE_NSPR 1
#define NSPR_INCLUDE /usr/local/mozilla/dist/*/include
#define NSPR_LIB
// Is VRPN installed, and where?
#define HAVE_VRPN
#define VRPN_INCLUDE
#define VRPN_LIB
// Is ZLIB installed, and where?
#define HAVE_ZLIB 1
#define ZLIB_INCLUDE
#define ZLIB_LIB
// Is OpenGL installed, and where?
#define HAVE_GL 1
#define GL_INCLUDE
#define GL_LIB
#define GLU_INCLUDE
#define GLU_LIB
// How about GLX?
#define HAVE_GLX 1
#define GLX_INCLUDE
#define GLX_LIB
// Glut?
#define HAVE_GLUT
#define GLUT_INCLUDE
#define GLUT_LIB
// Should we try to build the WGL interface?
#define HAVE_WGL
// Should we try to build the DirectX interface?
#define HAVE_DX
// Do you want to build the Renderman interface?
#define HAVE_RIB
// Is Mikmod installed?
#define HAVE_MIKMOD
#define MIKMOD_CFLAGS
#define MIKMOD_INCLUDE
#define MIKMOD_LIB
//////////////////////////////////////////////////////////////////////
// There are also some additional variables that control specific
// compiler/platform features or characteristics, defined in the
// platform specific file Config.platform.pp. Be sure to inspect
// these variables for correctness too. As above, these are
// unnecessary when BUILD_TYPE is "autoconf".
//////////////////////////////////////////////////////////////////////
#include $[TOPDIRPREFIX]Config.$[PLATFORM].pp
// Also pull in whatever package-specific variables there may be.
#include $[TOPDIRPREFIX]Package.pp
// If the environment variable PPREMAKE_CONFIG is set, it points to a
// user-customized Config.pp file, for instance in the user's home
// directory. This file might redefine any of the variables defined
// above.
#if $[ne $[PPREMAKE_CONFIG],]
#include $[PPREMAKE_CONFIG]
#endif
// Finally, include the system configure file.
#include $[PPREMAKE_DIR]/System.pp

211
panda/LocalSetup.pp Normal file
View File

@@ -0,0 +1,211 @@
//
// LocalSetup.pp
//
// This file contains further instructions to set up the DTOOL package
// when using ppremake. In particular, it creates the dtool_config.h
// file based on the user's selected configure variables. This script
// need not execute when BUILD_TYPE is "autoconf"; in this case, the
// dtool_config.h file will automatically be correctly generated by
// configure.
//
#if $[ne $[BUILD_TYPE],autoconf]
// A couple of variables to output the C #define and #undef
// directives, since we can't type them literally.
#define define #define
#define undef #undef
#output dtool_config.h
#format straight
/* dtool_config.h. Generated automatically by $[PROGRAM] $[PROGVER] from $[SOURCEFILE]. */
/* Define if you have the ANSI C header files. */
$[define] STDC_HEADERS 1
/* Define if your processor stores words with the most significant
byte first (like Motorola and SPARC, unlike Intel and VAX). */
#if $[WORDS_BIGENDIAN]
$[define] WORDS_BIGENDIAN 1
#else
$[undef] WORDS_BIGENDIAN
#endif
/* Define if the X Window System is missing or not being used. */
$[undef] X_DISPLAY_MISSING
/* Define if lex declares yytext as a char * by default, not a char[]. */
$[undef] YYTEXT_POINTER
/* Define if the C++ compiler uses namespaces. */
#if $[HAVE_NAMESPACE]
$[define] HAVE_NAMESPACE 1
#else
$[undef] HAVE_NAMESPACE
#endif
/* Define if the C++ iostream library supports ios::binary. */
#if $[HAVE_IOS_BINARY]
$[define] HAVE_IOS_BINARY 1
#else
$[undef] HAVE_IOS_BINARY
#endif
/* Define if we have Python installed. */
#if $[HAVE_PYTHON]
$[define] HAVE_PYTHON 1
#else
$[undef] HAVE_PYTHON
#endif
/* Define if we have NSPR installed. */
#if $[HAVE_NSPR]
$[define] HAVE_NSPR 1
#else
$[undef] HAVE_NSPR
#endif
/* Define if we have VRPN installed. */
#if $[HAVE_VRPN]
$[define] HAVE_VRPN 1
#else
$[undef] HAVE_VRPN
#endif
/* Define if we have zlib installed. */
#if $[HAVE_ZLIB]
$[define] HAVE_ZLIB 1
#else
$[undef] HAVE_ZLIB
#endif
/* Define if we have OpenGL installed and want to build for GL. */
#if $[HAVE_GL]
$[define] HAVE_GL 1
#else
$[undef] HAVE_GL
#endif
/* Define if we have GLU installed. */
#if $[HAVE_GLU]
$[define] HAVE_GLU 1
#else
$[undef] HAVE_GLU
#endif
/* Define if we have GLX installed and want to build for GLX. */
#if $[HAVE_GLX]
$[define] HAVE_GLX 1
#else
$[undef] HAVE_GLX
#endif
/* Define if we have Glut installed and want to build for Glut. */
#if $[HAVE_GLUT]
$[define] HAVE_GLUT 1
#else
$[undef] HAVE_GLUT
#endif
/* Define if we want to build the Renderman interface. */
#if $[HAVE_RIB]
$[define] HAVE_RIB 1
#else
$[undef] HAVE_RIB
#endif
/* Define if we want to use mikmod for audio. */
#if $[HAVE_MIKMOD]
$[define] HAVE_MIKMOD 1
#else
$[undef] HAVE_MIKMOD
#endif
/* Define if we have a gettimeofday() function. */
#if $[HAVE_GETTIMEOFDAY]
$[define] HAVE_GETTIMEOFDAY 1
#else
$[undef] HAVE_GETTIMEOFDAY
#endif
/* Define if gettimeofday() takes only one parameter. */
#if $[GETTIMEOFDAY_ONE_PARAM]
$[define] GETTIMEOFDAY_ONE_PARAM 1
#else
$[undef] GETTIMEOFDAY_ONE_PARAM
#endif
/* Define if you have the getopt function. */
#if $[HAVE_GETOPT]
$[define] HAVE_GETOPT 1
#else
$[undef] HAVE_GETOPT
#endif
/* Define if you have the getopt_long_only function. */
#if $[HAVE_GETOPT_LONG_ONLY]
$[define] HAVE_GETOPT_LONG_ONLY 1
#else
$[undef] HAVE_GETOPT_LONG_ONLY
#endif
/* Define if you have the <alloca.h> header file. */
$[define] HAVE_ALLOCA_H 1
/* Define if you have the <io.h> header file. */
$[undef] HAVE_IO_H
/* Define if you have the <iostream> header file. */
#if $[HAVE_IOSTREAM]
$[define] HAVE_IOSTREAM 1
#else
$[undef] HAVE_IOSTREAM
#endif
/* Define if you have the <malloc.h> header file. */
#if $[HAVE_MALLOC_H]
$[define] HAVE_MALLOC_H 1
#else
$[undef] HAVE_MALLOC_H
#endif
/* Define if you have the <alloca.h> header file. */
#if $[HAVE_ALLOCA_H]
$[define] HAVE_ALLOCA_H 1
#else
$[undef] HAVE_ALLOCA_H
#endif
/* Define if you have the <minmax.h> header file. */
$[undef] HAVE_MINMAX_H
/* Define if you have the <sstream> header file. */
#if $[HAVE_SSTREAM]
$[define] HAVE_SSTREAM 1
#else
$[undef] HAVE_SSTREAM
#endif
/* Define if you have the <sys/types.h> header file. */
#if $[HAVE_SYS_TYPES]
$[define] HAVE_SYS_TYPES 1
#else
$[undef] HAVE_SYS_TYPES
#endif
/* Define if you have the <unistd.h> header file. */
#if $[HAVE_UNISTD_H]
$[define] HAVE_UNISTD_H 1
#else
$[undef] HAVE_UNISTD_H
#endif
/* Name of package */
$[define] PACKAGE $[PACKAGE]
/* Version number of package */
$[define] VERSION $[VERSION]
#end dtool_config.h
#endif // BUILD_TYPE

11
panda/Package.pp Normal file
View File

@@ -0,0 +1,11 @@
//
// Package.pp
//
// This file defines a few more configuration variables that are
// inconvenient to store in Config.pp, simply because they are more
// specific to a particular package and not likely to be edited by a
// configuring user.
// What is the name and version of this source tree?
#define PACKAGE panda
#define VERSION 0.80

10
panda/Sources.pp Normal file
View File

@@ -0,0 +1,10 @@
// This is the toplevel directory. It contains configure.in and other
// stuff.
#define DIR_TYPE toplevel
#define SAMPLE_SOURCE_FILE src/pandabase/pandabase.cxx
#define REQUIRED_TREES dtool
#define EXTRA_DIST \
Config.Irix.pp Config.Linux.pp Config.Win32.pp LocalSetup.pp Package.pp

933
panda/acinclude.m4 Normal file
View File

@@ -0,0 +1,933 @@
AC_DEFUN(AC_GETTIMEOFDAY,
[AC_CACHE_CHECK([for gettimeofday()],
ac_cv_gettimeofday,
[
AC_TRY_COMPILE([
#include <sys/time.h>
],[
gettimeofday((struct timeval *)NULL, (struct timezone *)NULL);
], ac_cv_gettimeofday="2 params", ac_cv_gettimeofday=no)
if test "$ac_cv_gettimeofday" = no; then
AC_TRY_COMPILE([
#include <sys/time.h>
],[
gettimeofday((struct timeval *)NULL, (struct timezone *)NULL);
], ac_cv_gettimeofday="1 param", ac_cv_gettimeofday=no)
fi
])
if test "$ac_cv_gettimeofday" = "1 param"; then
AC_DEFINE(GETTIMEOFDAY_ONE_PARAM)
AC_DEFINE(HAVE_GETTIMEOFDAY)
elif test "$ac_cv_gettimeofday" = "2 params"; then
AC_DEFINE(HAVE_GETTIMEOFDAY)
fi
])
AC_DEFUN(AC_HEADER_IOSTREAM,
[AC_CHECK_HEADERS(iostream,[have_iostream=yes],[have_iostream=no])])
AC_DEFUN(AC_IOS_BINARY,
[AC_CACHE_CHECK([for ios::binary],
ac_cv_ios_binary,
[
if test $have_iostream = yes; then
AC_TRY_COMPILE([
#include <iostream>
],[
int x; x = ios::binary;
], ac_cv_ios_binary=yes, ac_cv_ios_binary=no)
else
AC_TRY_COMPILE([
#include <iostream.h>
],[
int x; x = ios::binary;
], ac_cv_ios_binary=yes, ac_cv_ios_binary=no)
fi
])
if test $ac_cv_ios_binary = yes; then
AC_DEFINE(HAVE_IOS_BINARY)
fi
])
AC_DEFUN(AC_NAMESPACE,
[AC_CACHE_CHECK([for compiler namespace support],
ac_cv_namespace,
[AC_TRY_COMPILE(
[namespace std { };
using namespace std;],
[],
ac_cv_namespace=yes, ac_cv_namespace=no)])
if test $ac_cv_namespace = yes; then
AC_DEFINE(HAVE_NAMESPACE)
fi
])
dnl A handy function to see if a library is in a particular directory.
dnl AC_CHECK_LIB_LOC(directory, library, function, action-if-found, action-if-not-found, other-libraries)
dnl
AC_DEFUN(AC_CHECK_LIB_LOC,
[AC_MSG_CHECKING([for lib$2 in $1])
ac_lib_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'`
AC_CACHE_VAL(ac_cv_lib_loc_$ac_lib_var,
[ac_save_LIBS="$LIBS"
LIBS="-L$1 -l$2 $6 $LIBS"
AC_TRY_LINK(dnl
ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus
extern "C"
#endif
])dnl
[/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char $3();
],
[$3()],
eval "ac_cv_lib_loc_$ac_lib_var=yes",
eval "ac_cv_lib_loc_$ac_lib_var=no")
LIBS="$ac_save_LIBS"
])dnl
if eval "test \"`echo '$ac_cv_lib_loc_'$ac_lib_var`\" = yes"; then
AC_MSG_RESULT(yes)
ifelse([$4], ,
[LIBS="-L$1 -l$2 $LIBS"
], [$4])
else
AC_MSG_RESULT(no)
ifelse([$5], , , [$5
])dnl
fi
])
dnl A handy function to search a number of possible locations for a library.
dnl AC_SEARCH_LIB(search-dirs, library, function, package, other-libraries)
dnl
dnl Sets $package_LIB to the directory containing the library, or to the
dnl string "no" if the library cannot be found.
AC_DEFUN(AC_SEARCH_LIB, [
ac_found_lib="no"
if test "$1" = ""; then
AC_CHECK_LIB($2, $3, [ ac_found_lib=""; ],, $5)
else
for ac_check_dir in $1; do
if test "$ac_found_lib" = "no"; then
AC_CHECK_LIB_LOC($ac_check_dir, $2, $3, [ ac_found_lib="$ac_check_dir"; ],, $5)
fi
done
fi
$4_LIB="$ac_found_lib"
])
dnl A handy function to see if a header file is in a particular directory.
dnl AC_CHECK_HEADER_LOC(directory, header, action-if-found, action-if-not-found)
dnl
AC_DEFUN(AC_CHECK_HEADER_LOC, [
AC_MSG_CHECKING([for $2 in $1])
ac_include_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'`
AC_CACHE_VAL(ac_cv_include_loc_$ac_include_var, [
ac_save_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="-I$1 $CPPFLAGS"
AC_TRY_CPP([#include <$2>], ac_ch_found_it="yes", ac_ch_found_it="no")
if test "$ac_ch_found_it" = "yes"; then
AC_MSG_RESULT(yes)
ifelse([$3], , :, [$3])
else
AC_MSG_RESULT(no)
ifelse([$4], , , [$4])
fi
CPPFLAGS="$ac_save_CPPFLAGS"
])
])
dnl A handy function to search a number of possible locations for a header
dnl file.
dnl
dnl AC_SEARCH_HEADER(search-dirs, header, package)
dnl
dnl Sets $package_INCLUDE to the directory containing the header, or to
dnl the string "no" if the header cannot be found.
AC_DEFUN(AC_SEARCH_HEADER, [
ac_found_header="no"
if test "$1" = ""; then
AC_CHECK_HEADER($2, [ ac_found_header="";])
else
for ac_check_dir in $1; do
if test "$ac_found_header" = "no"; then
AC_CHECK_HEADER_LOC($ac_check_dir, $2, [ ac_found_header="$ac_check_dir";])
fi
done
fi
$3_INCLUDE="$ac_found_header"
])
dnl A handy function to scan for a third-party package, consisting of at
dnl least a library and an include file. A few assumptions are made about
dnl the relationships between lib and include directories.
dnl
dnl AC_SEARCH_PACKAGE(search-dirs, package-names, header, library, function, package, other-libraries)
dnl
dnl search-dirs is the whitespace-separated list of directory prefixes to
dnl check.
dnl package-names is a whitespace-separated list of possible names the
dnl package may have been installed under.
dnl
dnl For each combination of ${search-dir} and ${package-name}, the following
dnl directories are searched:
dnl
dnl ${search-dir}
dnl ${search-dir}/lib
dnl ${search-dir}/${package-name}
dnl ${search-dir}/${package-name}/lib
dnl ${search-dir}/lib/${package-name}
dnl
dnl And similarly for include.
dnl
dnl Sets the variables $package_INCLUDE and $package_LIB to the directories
dnl containing the header file and library, respectively. If both pieces
dnl are located, also sets the variable $package_PKG to "yes"; otherwise,
dnl sets the variable $package_PKG to "no".
dnl
AC_DEFUN(AC_SEARCH_PACKAGE, [
$6_LIB="no"
$6_INCLUDE="no"
$6_PKG="no"
dnl Look for the library.
AC_SEARCH_LIB("", $4, $5, $6, $7)
for ac_sp_dir in $1; do
if test "[$]$6_LIB" = "no"; then
AC_SEARCH_LIB("$ac_sp_dir" "$ac_sp_dir/lib", $4, $5, $6, $7)
for ac_sp_pkg in $2; do
if test "[$]$6_LIB" = "no"; then
AC_SEARCH_LIB("$ac_sp_dir/$ac_sp_pkg" "$ac_sp_dir/$ac_sp_pkg/lib" \
"$ac_sp_dir/lib/$ac_sp_pkg", $4, $5, $6, $7)
fi
done
fi
done
dnl Now look for the header file. Don't bother looking if the library
dnl wasn't found.
if test "[$]$6_LIB" != "no"; then
dnl First look in the obvious directory corresponding to the lib dir.
ac_sp_testinc=`echo [$]$6_LIB | sed 's:/lib:/include:'`
AC_SEARCH_HEADER("$ac_sp_testinc", $3, $6)
dnl If it wasn't found there, cast about.
if test "[$]$6_INCLUDE" = "no"; then
for ac_sp_dir in $1; do
if test "[$]$6_INCLUDE" = "no"; then
AC_SEARCH_HEADER("$ac_sp_dir" "$ac_sp_dir/include", $3, $6)
for ac_sp_pkg in $2; do
if test "[$]$6_INCLUDE" = "no"; then
AC_SEARCH_HEADER("$ac_sp_dir/$ac_sp_pkg" \
"$ac_sp_dir/$ac_sp_pkg/include" \
"$ac_sp_dir/include/$ac_sp_pkg", $3, $6)
fi
done
fi
done
fi
dnl If we got both a header and a library, set the PKG variable.
if test "[$]$6_INCLUDE" != "no"; then
$6_PKG="yes"
fi
fi
])
dnl A handy function, similar to AC_SEARCH_PACKAGE, above, that looks for a
dnl package that only consists of header files, no libraries.
dnl
dnl AC_SEARCH_HPACKAGE(search-dirs, package-names, header, package)
dnl
dnl search-dirs is the whitespace-separated list of directory prefixes to
dnl check.
dnl package-names is a whitespace-separated list of possible names the
dnl package may have been installed under.
dnl
dnl For each combination of ${search-dir} and ${package-name}, the following
dnl directories are searched:
dnl
dnl ${search-dir}
dnl ${search-dir}/include
dnl ${search-dir}/${package-name}
dnl ${search-dir}/${package-name}/include
dnl ${search-dir}/include/${package-name}
dnl
dnl Sets the variable $package_INCLUDE to the directory containing the
dnl header file, and sets the variable $package_PKG to "yes"; if the
dnl directory is not found, sets the variable $package_PKG to "no".
dnl
AC_DEFUN(AC_SEARCH_HPACKAGE, [
$4_INCLUDE="no"
$4_PKG="no"
dnl Look for the header.
AC_SEARCH_HEADER("", $3, $4)
for ac_sp_dir in $1; do
if test "[$]$4_INCLUDE" = "no"; then
AC_SEARCH_HEADER("$ac_sp_dir" "$ac_sp_dir/include", $3, $4)
for ac_sp_pkg in $2; do
if test "[$]$4_INCLUDE" = "no"; then
AC_SEARCH_HEADER("$ac_sp_dir/$ac_sp_pkg" \
"$ac_sp_dir/$ac_sp_pkg/include" \
"$ac_sp_dir/include/$ac_sp_pkg", $3, $4)
fi
done
fi
done
dnl If we got both a header file, set the PKG variable.
if test "[$]$4_INCLUDE" != "no"; then
$4_PKG="yes"
fi
])
# Define a conditional.
AC_DEFUN(AM_CONDITIONAL,
[AC_SUBST($1_TRUE)
AC_SUBST($1_FALSE)
if $2; then
$1_TRUE=
$1_FALSE='#'
else
$1_TRUE='#'
$1_FALSE=
fi])
# Configure paths for GTK--
# Erik Andersen 30 May 1998
# Modified by Tero Pulkkinen (added the compiler checks... I hope they work..)
dnl Test for GTKMM, and define GTKMM_CFLAGS and GTKMM_LIBS
dnl to be used as follows:
dnl AM_PATH_GTKMM([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
dnl
AC_DEFUN(AM_PATH_GTKMM,
[dnl
dnl Get the cflags and libraries from the gtkmm-config script
dnl
AC_ARG_WITH(gtkmm-prefix,[ --with-gtkmm-prefix=PREFIX
Prefix where GTK-- is installed (optional)],
gtkmm_config_prefix="$withval", gtkmm_config_prefix="")
AC_ARG_WITH(gtkmm-exec-prefix,[ --with-gtkmm-exec-prefix=PREFIX
Exec prefix where GTK-- is installed (optional)],
gtkmm_config_exec_prefix="$withval", gtkmm_config_exec_prefix="")
AC_ARG_ENABLE(gtkmmtest, [ --disable-gtkmmtest Do not try to compile and run a test GTK-- program],
, enable_gtkmmtest=yes)
if test x$gtkmm_config_exec_prefix != x ; then
gtkmm_config_args="$gtkmm_config_args --exec-prefix=$gtkmm_config_exec_prefix"
if test x${GTKMM_CONFIG+set} != xset ; then
GTKMM_CONFIG=$gtkmm_config_exec_prefix/bin/gtkmm-config
fi
fi
if test x$gtkmm_config_prefix != x ; then
gtkmm_config_args="$gtkmm_config_args --prefix=$gtkmm_config_prefix"
if test x${GTKMM_CONFIG+set} != xset ; then
GTKMM_CONFIG=$gtkmm_config_prefix/bin/gtkmm-config
fi
fi
AC_PATH_PROG(GTKMM_CONFIG, gtkmm-config, no)
min_gtkmm_version=ifelse([$1], ,0.10.0,$1)
AC_MSG_CHECKING(for GTK-- - version >= $min_gtkmm_version)
no_gtkmm=""
if test "$GTKMM_CONFIG" = "no" ; then
no_gtkmm=yes
else
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
GTKMM_CFLAGS=`$GTKMM_CONFIG $gtkmm_config_args --cflags`
GTKMM_LIBS=`$GTKMM_CONFIG $gtkmm_config_args --libs`
gtkmm_config_major_version=`$GTKMM_CONFIG $gtkmm_config_args --version | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
gtkmm_config_minor_version=`$GTKMM_CONFIG $gtkmm_config_args --version | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
gtkmm_config_micro_version=`$GTKMM_CONFIG $gtkmm_config_args --version | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
if test "x$enable_gtkmmtest" = "xyes" ; then
ac_save_CXXFLAGS="$CXXFLAGS"
ac_save_LIBS="$LIBS"
CXXFLAGS="$CXXFLAGS $GTKMM_CFLAGS"
LIBS="$LIBS $GTKMM_LIBS"
dnl
dnl Now check if the installed GTK-- is sufficiently new. (Also sanity
dnl checks the results of gtkmm-config to some extent
dnl
rm -f conf.gtkmmtest
AC_TRY_RUN([
#include <gtk--.h>
#include <stdio.h>
#include <stdlib.h>
int
main ()
{
int major, minor, micro;
char *tmp_version;
system ("touch conf.gtkmmtest");
/* HP/UX 0 (%@#!) writes to sscanf strings */
tmp_version = g_strdup("$min_gtkmm_version");
if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
printf("%s, bad version string\n", "$min_gtkmm_version");
exit(1);
}
if ((gtkmm_major_version != $gtkmm_config_major_version) ||
(gtkmm_minor_version != $gtkmm_config_minor_version) ||
(gtkmm_micro_version != $gtkmm_config_micro_version))
{
printf("\n*** 'gtkmm-config --version' returned %d.%d.%d, but GTK-- (%d.%d.%d)\n",
$gtkmm_config_major_version, $gtkmm_config_minor_version, $gtkmm_config_micro_version,
gtkmm_major_version, gtkmm_minor_version, gtkmm_micro_version);
printf ("*** was found! If gtkmm-config was correct, then it is best\n");
printf ("*** to remove the old version of GTK--. You may also be able to fix the error\n");
printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
printf("*** required on your system.\n");
printf("*** If gtkmm-config was wrong, set the environment variable GTKMM_CONFIG\n");
printf("*** to point to the correct copy of gtkmm-config, and remove the file config.cache\n");
printf("*** before re-running configure\n");
}
/* GTK-- does not have the GTKMM_*_VERSION constants */
/*
else if ((gtkmm_major_version != GTKMM_MAJOR_VERSION) ||
(gtkmm_minor_version != GTKMM_MINOR_VERSION) ||
(gtkmm_micro_version != GTKMM_MICRO_VERSION))
{
printf("*** GTK-- header files (version %d.%d.%d) do not match\n",
GTKMM_MAJOR_VERSION, GTKMM_MINOR_VERSION, GTKMM_MICRO_VERSION);
printf("*** library (version %d.%d.%d)\n",
gtkmm_major_version, gtkmm_minor_version, gtkmm_micro_version);
}
*/
else
{
if ((gtkmm_major_version > major) ||
((gtkmm_major_version == major) && (gtkmm_minor_version > minor)) ||
((gtkmm_major_version == major) && (gtkmm_minor_version == minor) && (gtkmm_micro_version >= micro)))
{
return 0;
}
else
{
printf("\n*** An old version of GTK-- (%d.%d.%d) was found.\n",
gtkmm_major_version, gtkmm_minor_version, gtkmm_micro_version);
printf("*** You need a version of GTK-- newer than %d.%d.%d. The latest version of\n",
major, minor, micro);
printf("*** GTK-- is always available from ftp://ftp.gtk.org.\n");
printf("***\n");
printf("*** If you have already installed a sufficiently new version, this error\n");
printf("*** probably means that the wrong copy of the gtkmm-config shell script is\n");
printf("*** being found. The easiest way to fix this is to remove the old version\n");
printf("*** of GTK--, but you can also set the GTKMM_CONFIG environment to point to the\n");
printf("*** correct copy of gtkmm-config. (In this case, you will have to\n");
printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
printf("*** so that the correct libraries are found at run-time))\n");
}
}
return 1;
}
],, no_gtkmm=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
CXXFLAGS="$ac_save_CXXFLAGS"
LIBS="$ac_save_LIBS"
fi
fi
if test "x$no_gtkmm" = x ; then
AC_MSG_RESULT(yes)
ifelse([$2], , :, [$2])
else
AC_MSG_RESULT(no)
if test "$GTKMM_CONFIG" = "no" ; then
echo "*** The gtkmm-config script installed by GTK-- could not be found"
echo "*** If GTK-- was installed in PREFIX, make sure PREFIX/bin is in"
echo "*** your path, or set the GTKMM_CONFIG environment variable to the"
echo "*** full path to gtkmm-config."
echo "*** The gtkmm-config script was not available in GTK-- versions"
echo "*** prior to 0.9.12. Perhaps you need to update your installed"
echo "*** version to 0.9.12 or later"
else
if test -f conf.gtkmmtest ; then
:
else
echo "*** Could not run GTK-- test program, checking why..."
CXXFLAGS="$CFLAGS $GTKMM_CXXFLAGS"
LIBS="$LIBS $GTKMM_LIBS"
AC_TRY_LINK([
#include <gtk--.h>
#include <stdio.h>
], [ return ((gtkmm_major_version) || (gtkmm_minor_version) || (gtkmm_micro_version)); ],
[ echo "*** The test program compiled, but did not run. This usually means"
echo "*** that the run-time linker is not finding GTK-- or finding the wrong"
echo "*** version of GTK--. If it is not finding GTK--, you'll need to set your"
echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
echo "*** to the installed location Also, make sure you have run ldconfig if that"
echo "*** is required on your system"
echo "***"
echo "*** If you have an old version installed, it is best to remove it, although"
echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ],
[ echo "*** The test program failed to compile or link. See the file config.log for the"
echo "*** exact error that occured. This usually means GTK-- was incorrectly installed"
echo "*** or that you have moved GTK-- since it was installed. In the latter case, you"
echo "*** may want to edit the gtkmm-config script: $GTKMM_CONFIG" ])
CXXFLAGS="$ac_save_CXXFLAGS"
LIBS="$ac_save_LIBS"
fi
fi
GTKMM_CFLAGS=""
GTKMM_LIBS=""
ifelse([$3], , :, [$3])
AC_LANG_RESTORE
fi
AC_SUBST(GTKMM_CFLAGS)
AC_SUBST(GTKMM_LIBS)
rm -f conf.gtkmmtest
])
## libtool.m4 - Configure libtool for the target system. -*-Shell-script-*-
## Copyright (C) 1996-1999 Free Software Foundation, Inc.
## Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
##
## As a special exception to the GNU General Public License, if you
## distribute this file as part of a program that contains a
## configuration script generated by Autoconf, you may include it under
## the same distribution terms that you use for the rest of that program.
# serial 40 AC_PROG_LIBTOOL
AC_DEFUN(AC_PROG_LIBTOOL,
[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
# Save cache, so that ltconfig can load it
AC_CACHE_SAVE
# Actually configure libtool. ac_aux_dir is where install-sh is found.
CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \
LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \
DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \
$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \
|| AC_MSG_ERROR([libtool configure failed])
# Reload cache, that may have been modified by ltconfig
AC_CACHE_LOAD
# This can be used to rebuild libtool when needed
LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh"
# Always use our own libtool.
LIBTOOL='$(SHELL) $(top_builddir)/libtool'
AC_SUBST(LIBTOOL)dnl
# Redirect the config.log output again, so that the ltconfig log is not
# clobbered by the next message.
exec 5>>./config.log
])
AC_DEFUN(AC_LIBTOOL_SETUP,
[AC_PREREQ(2.13)dnl
AC_REQUIRE([AC_ENABLE_SHARED])dnl
AC_REQUIRE([AC_ENABLE_STATIC])dnl
AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
AC_REQUIRE([AC_CANONICAL_HOST])dnl
AC_REQUIRE([AC_CANONICAL_BUILD])dnl
AC_REQUIRE([AC_PROG_RANLIB])dnl
AC_REQUIRE([AC_PROG_CC])dnl
AC_REQUIRE([AC_PROG_LD])dnl
AC_REQUIRE([AC_PROG_NM])dnl
AC_REQUIRE([AC_PROG_LN_S])dnl
dnl
# Check for any special flags to pass to ltconfig.
#
# the following will cause an existing older ltconfig to fail, so
# we ignore this at the expense of the cache file... Checking this
# will just take longer ... bummer!
#libtool_flags="--cache-file=$cache_file"
#
test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install"
test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc"
test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN],
[libtool_flags="$libtool_flags --enable-dlopen"])
ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
[libtool_flags="$libtool_flags --enable-win32-dll"])
AC_ARG_ENABLE(libtool-lock,
[ --disable-libtool-lock avoid locking (might break parallel builds)])
test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock"
test x"$silent" = xyes && libtool_flags="$libtool_flags --silent"
# Some flags need to be propagated to the compiler or linker for good
# libtool support.
case "$host" in
*-*-irix6*)
# Find out which ABI we are using.
echo '[#]line __oline__ "configure"' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case "`/usr/bin/file conftest.o`" in
*32-bit*)
LD="${LD-ld} -32"
;;
*N32*)
LD="${LD-ld} -n32"
;;
*64-bit*)
LD="${LD-ld} -64"
;;
esac
fi
rm -rf conftest*
;;
*-*-sco3.2v5*)
# On SCO OpenServer 5, we need -belf to get full-featured binaries.
SAVE_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -belf"
AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
[AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])])
if test x"$lt_cv_cc_needs_belf" != x"yes"; then
# this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
CFLAGS="$SAVE_CFLAGS"
fi
;;
ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
[*-*-cygwin* | *-*-mingw*)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
])
esac
])
# AC_LIBTOOL_DLOPEN - enable checks for dlopen support
AC_DEFUN(AC_LIBTOOL_DLOPEN, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])])
# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's
AC_DEFUN(AC_LIBTOOL_WIN32_DLL, [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])])
# AC_ENABLE_SHARED - implement the --enable-shared flag
# Usage: AC_ENABLE_SHARED[(DEFAULT)]
# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
# `yes'.
AC_DEFUN(AC_ENABLE_SHARED, [dnl
define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
AC_ARG_ENABLE(shared,
changequote(<<, >>)dnl
<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT],
changequote([, ])dnl
[p=${PACKAGE-default}
case "$enableval" in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
for pkg in $enableval; do
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS="$ac_save_ifs"
;;
esac],
enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl
])
# AC_DISABLE_SHARED - set the default shared flag to --disable-shared
AC_DEFUN(AC_DISABLE_SHARED, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
AC_ENABLE_SHARED(no)])
# AC_ENABLE_STATIC - implement the --enable-static flag
# Usage: AC_ENABLE_STATIC[(DEFAULT)]
# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
# `yes'.
AC_DEFUN(AC_ENABLE_STATIC, [dnl
define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
AC_ARG_ENABLE(static,
changequote(<<, >>)dnl
<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT],
changequote([, ])dnl
[p=${PACKAGE-default}
case "$enableval" in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
for pkg in $enableval; do
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS="$ac_save_ifs"
;;
esac],
enable_static=AC_ENABLE_STATIC_DEFAULT)dnl
])
# AC_DISABLE_STATIC - set the default static flag to --disable-static
AC_DEFUN(AC_DISABLE_STATIC, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
AC_ENABLE_STATIC(no)])
# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag
# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)]
# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
# `yes'.
AC_DEFUN(AC_ENABLE_FAST_INSTALL, [dnl
define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
AC_ARG_ENABLE(fast-install,
changequote(<<, >>)dnl
<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT],
changequote([, ])dnl
[p=${PACKAGE-default}
case "$enableval" in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
for pkg in $enableval; do
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS="$ac_save_ifs"
;;
esac],
enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl
])
# AC_ENABLE_FAST_INSTALL - set the default to --disable-fast-install
AC_DEFUN(AC_DISABLE_FAST_INSTALL, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
AC_ENABLE_FAST_INSTALL(no)])
# AC_PROG_LD - find the path to the GNU or non-GNU linker
AC_DEFUN(AC_PROG_LD,
[AC_ARG_WITH(gnu-ld,
[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]],
test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
AC_REQUIRE([AC_PROG_CC])dnl
AC_REQUIRE([AC_CANONICAL_HOST])dnl
AC_REQUIRE([AC_CANONICAL_BUILD])dnl
ac_prog=ld
if test "$ac_cv_prog_gcc" = yes; then
# Check if gcc -print-prog-name=ld gives a path.
AC_MSG_CHECKING([for ld used by GCC])
ac_prog=`($CC -print-prog-name=ld) 2>&5`
case "$ac_prog" in
# Accept absolute paths.
changequote(,)dnl
[\\/]* | [A-Za-z]:[\\/]*)
re_direlt='/[^/][^/]*/\.\./'
changequote([,])dnl
# Canonicalize the path of ld
ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
done
test -z "$LD" && LD="$ac_prog"
;;
"")
# If it fails, then pretend we aren't using GCC.
ac_prog=ld
;;
*)
# If it is relative, then search for the first ld in PATH.
with_gnu_ld=unknown
;;
esac
elif test "$with_gnu_ld" = yes; then
AC_MSG_CHECKING([for GNU ld])
else
AC_MSG_CHECKING([for non-GNU ld])
fi
AC_CACHE_VAL(ac_cv_path_LD,
[if test -z "$LD"; then
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
for ac_dir in $PATH; do
test -z "$ac_dir" && ac_dir=.
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
ac_cv_path_LD="$ac_dir/$ac_prog"
# Check to see if the program is GNU ld. I'd rather use --version,
# but apparently some GNU ld's only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
test "$with_gnu_ld" != no && break
else
test "$with_gnu_ld" != yes && break
fi
fi
done
IFS="$ac_save_ifs"
else
ac_cv_path_LD="$LD" # Let the user override the test with a path.
fi])
LD="$ac_cv_path_LD"
if test -n "$LD"; then
AC_MSG_RESULT($LD)
else
AC_MSG_RESULT(no)
fi
test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
AC_SUBST(LD)
AC_PROG_LD_GNU
])
AC_DEFUN(AC_PROG_LD_GNU,
[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld,
[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
ac_cv_prog_gnu_ld=yes
else
ac_cv_prog_gnu_ld=no
fi])
])
# AC_PROG_NM - find the path to a BSD-compatible name lister
AC_DEFUN(AC_PROG_NM,
[AC_MSG_CHECKING([for BSD-compatible nm])
AC_CACHE_VAL(ac_cv_path_NM,
[if test -n "$NM"; then
# Let the user override the test.
ac_cv_path_NM="$NM"
else
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
test -z "$ac_dir" && ac_dir=.
if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then
# Check to see if the nm accepts a BSD-compat flag.
# Adding the `sed 1q' prevents false positives on HP-UX, which says:
# nm: unknown option "B" ignored
if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
ac_cv_path_NM="$ac_dir/nm -B"
break
elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
ac_cv_path_NM="$ac_dir/nm -p"
break
else
ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but
continue # so that we can try to find one that supports BSD flags
fi
fi
done
IFS="$ac_save_ifs"
test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
fi])
NM="$ac_cv_path_NM"
AC_MSG_RESULT([$NM])
AC_SUBST(NM)
])
# AC_CHECK_LIBM - check for math library
AC_DEFUN(AC_CHECK_LIBM,
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
LIBM=
case "$host" in
*-*-beos* | *-*-cygwin*)
# These system don't have libm
;;
*-ncr-sysv4.3*)
AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
AC_CHECK_LIB(m, main, LIBM="$LIBM -lm")
;;
*)
AC_CHECK_LIB(m, main, LIBM="-lm")
;;
esac
])
# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for
# the libltdl convenience library, adds --enable-ltdl-convenience to
# the configure arguments. Note that LIBLTDL is not AC_SUBSTed, nor
# is AC_CONFIG_SUBDIRS called. If DIR is not provided, it is assumed
# to be `${top_builddir}/libltdl'. Make sure you start DIR with
# '${top_builddir}/' (note the single quotes!) if your package is not
# flat, and, if you're not using automake, define top_builddir as
# appropriate in the Makefiles.
AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
case "$enable_ltdl_convenience" in
no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
"") enable_ltdl_convenience=yes
ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
esac
LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdlc.la
INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl'])
])
# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for
# the libltdl installable library, and adds --enable-ltdl-install to
# the configure arguments. Note that LIBLTDL is not AC_SUBSTed, nor
# is AC_CONFIG_SUBDIRS called. If DIR is not provided, it is assumed
# to be `${top_builddir}/libltdl'. Make sure you start DIR with
# '${top_builddir}/' (note the single quotes!) if your package is not
# flat, and, if you're not using automake, define top_builddir as
# appropriate in the Makefiles.
# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
AC_CHECK_LIB(ltdl, main,
[test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
[if test x"$enable_ltdl_install" = xno; then
AC_MSG_WARN([libltdl not installed, but installation disabled])
else
enable_ltdl_install=yes
fi
])
if test x"$enable_ltdl_install" = x"yes"; then
ac_configure_args="$ac_configure_args --enable-ltdl-install"
LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdl.la
INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl'])
else
ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
LIBLTDL="-lltdl"
INCLTDL=
fi
])
dnl old names
AC_DEFUN(AM_PROG_LIBTOOL, [indir([AC_PROG_LIBTOOL])])dnl
AC_DEFUN(AM_ENABLE_SHARED, [indir([AC_ENABLE_SHARED], $@)])dnl
AC_DEFUN(AM_ENABLE_STATIC, [indir([AC_ENABLE_STATIC], $@)])dnl
AC_DEFUN(AM_DISABLE_SHARED, [indir([AC_DISABLE_SHARED], $@)])dnl
AC_DEFUN(AM_DISABLE_STATIC, [indir([AC_DISABLE_STATIC], $@)])dnl
AC_DEFUN(AM_PROG_LD, [indir([AC_PROG_LD])])dnl
AC_DEFUN(AM_PROG_NM, [indir([AC_PROG_NM])])dnl
dnl This is just to silence aclocal about the macro not being used
ifelse([AC_DISABLE_FAST_INSTALL])dnl

View File

@@ -0,0 +1,7 @@
// This is a group directory: a directory level above a number of
// source subdirectories.
#define DIR_TYPE group
// The metalibs directory always depends on the src directory.
#define DEPENDS src

View File

@@ -0,0 +1,25 @@
// DIR_TYPE "metalib" indicates we are building a shared library that
// consists mostly of references to other shared libraries. Under
// Windows, this directly produces a DLL (as opposed to the regular
// src libraries, which don't produce anything but a pile of OBJ files
// under Windows).
#define DIR_TYPE metalib
#define BUILDING_DLL BUILDING_PANDA
#define LOCAL_LIBS \
pstatclient grutil chan chancfg \
char chat collide cull device \
dgraph display gobj graph gsgbase \
gsgmisc light linmath mathutil net pnm \
pnmimagetypes pnmimage sgattrib sgmanip sgraph sgraphutil \
switchnode text tform lerp loader putil effects \
audio pandabase
#define OTHER_LIBS interrogatedb dconfig dtoolutil dtoolbase
#begin metalib_target
#define TARGET panda
#define SOURCES panda.cxx
#end metalib_target

View File

@@ -0,0 +1,9 @@
// Filename: panda.cxx
// Created by: drose (15May00)
//
////////////////////////////////////////////////////////////////////
// This is a dummy file whose sole purpose is to give the compiler
// something to compile when making libpanda.so in NO_DEFER mode,
// which generates an empty library that itself links with all the
// other shared libraries that make up libpanda.

View File

@@ -0,0 +1,21 @@
#define DIRECTORY_IF_DX yes
// DIR_TYPE "metalib" indicates we are building a shared library that
// consists mostly of references to other shared libraries. Under
// Windows, this directly produces a DLL (as opposed to the regular
// src libraries, which don't produce anything but a pile of OBJ files
// under Windows).
#define DIR_TYPE metalib
#define BUILDING_DLL BUILDING_PANDADX
#define LOCAL_LIBS \
dxgsg wdxdisplay
#define OTHER_LIBS interrogatedb dconfig dtoolutil dtoolbase
#begin metalib_target
#define TARGET pandadx
#define SOURCES pandadx.cxx
#end metalib_target

View File

@@ -0,0 +1,9 @@
// Filename: pandadx.cxx
// Created by: drose (15May00)
//
////////////////////////////////////////////////////////////////////
// This is a dummy file whose sole purpose is to give the compiler
// something to compile when making libpandadx.so in NO_DEFER mode,
// which generates an empty library that itself links with all the
// other shared libraries that make up libpandadx.

View File

@@ -0,0 +1,19 @@
// DIR_TYPE "metalib" indicates we are building a shared library that
// consists mostly of references to other shared libraries. Under
// Windows, this directly produces a DLL (as opposed to the regular
// src libraries, which don't produce anything but a pile of OBJ files
// under Windows).
#define DIR_TYPE metalib
#define BUILDING_DLL BUILDING_PANDAEGG
#define LOCAL_LIBS \
egg2sg egg builder
#define OTHER_LIBS interrogatedb dconfig dtoolutil dtoolbase
#begin metalib_target
#define TARGET pandaegg
#define SOURCES pandaegg.cxx
#end metalib_target

View File

@@ -0,0 +1,9 @@
// Filename: pandaegg.cxx
// Created by: drose (16May00)
//
////////////////////////////////////////////////////////////////////
// This is a dummy file whose sole purpose is to give the compiler
// something to compile when making libpandaegg.so in NO_DEFER mode,
// which generates an empty library that itself links with all the
// other shared libraries that make up libpandaegg.

View File

@@ -0,0 +1,17 @@
// DIR_TYPE "metalib" indicates we are building a shared library that
// consists mostly of references to other shared libraries. Under
// Windows, this directly produces a DLL (as opposed to the regular
// src libraries, which don't produce anything but a pile of OBJ files
// under Windows).
#define DIR_TYPE metalib
#define BUILDING_DLL BUILDING_PANDAEXPRESS
#define LOCAL_LIBS downloader event ipc express pandabase
#define OTHER_LIBS interrogatedb dconfig dtoolutil
#begin metalib_target
#define TARGET pandaexpress
#define SOURCES pandaexpress.cxx
#end metalib_target

View File

@@ -0,0 +1,9 @@
// Filename: pandaexpress.cxx
// Created by: drose (15May00)
//
////////////////////////////////////////////////////////////////////
// This is a dummy file whose sole purpose is to give the compiler
// something to compile when making libpanda.so in NO_DEFER mode,
// which generates an empty library that itself links with all the
// other shared libraries that make up libpanda.

View File

@@ -0,0 +1,21 @@
#define DIRECTORY_IF_GL yes
// DIR_TYPE "metalib" indicates we are building a shared library that
// consists mostly of references to other shared libraries. Under
// Windows, this directly produces a DLL (as opposed to the regular
// src libraries, which don't produce anything but a pile of OBJ files
// under Windows).
#define DIR_TYPE metalib
#define BUILDING_DLL BUILDING_PANDAGL
#define LOCAL_LIBS \
glgsg glxdisplay // sgiglxdisplay
#define OTHER_LIBS interrogatedb dconfig dtoolutil dtoolbase
#begin metalib_target
#define TARGET pandagl
#define SOURCES pandagl.cxx
#end metalib_target

View File

@@ -0,0 +1,9 @@
// Filename: pandagl.cxx
// Created by: drose (15May00)
//
////////////////////////////////////////////////////////////////////
// This is a dummy file whose sole purpose is to give the compiler
// something to compile when making libpandagl.so in NO_DEFER mode,
// which generates an empty library that itself links with all the
// other shared libraries that make up libpandagl.

View File

@@ -0,0 +1,21 @@
#define DIRECTORY_IF_GLUT yes
// DIR_TYPE "metalib" indicates we are building a shared library that
// consists mostly of references to other shared libraries. Under
// Windows, this directly produces a DLL (as opposed to the regular
// src libraries, which don't produce anything but a pile of OBJ files
// under Windows).
#define DIR_TYPE metalib
#define BUILDING_DLL BUILDING_PANDAGLUT
#define LOCAL_LIBS \
glutdisplay // sgiglutdisplay
#define OTHER_LIBS interrogatedb dconfig dtoolutil dtoolbase
#begin metalib_target
#define TARGET pandaglut
#define SOURCES pandaglut.cxx
#end metalib_target

View File

@@ -0,0 +1,9 @@
// Filename: pandaglut.cxx
// Created by: drose (15May00)
//
////////////////////////////////////////////////////////////////////
// This is a dummy file whose sole purpose is to give the compiler
// something to compile when making libpandaglut.so in NO_DEFER mode,
// which generates an empty library that itself links with all the
// other shared libraries that make up libpandaglut.

View File

@@ -0,0 +1,19 @@
// DIR_TYPE "metalib" indicates we are building a shared library that
// consists mostly of references to other shared libraries. Under
// Windows, this directly produces a DLL (as opposed to the regular
// src libraries, which don't produce anything but a pile of OBJ files
// under Windows).
#define DIR_TYPE metalib
#define BUILDING_DLL BUILDING_PANDAPHYSICS
#define LOCAL_LIBS \
physics particlesystem
#define OTHER_LIBS interrogatedb dconfig dtoolutil dtoolbase
#begin metalib_target
#define TARGET pandaphysics
#define SOURCES pandaphysics.cxx
#end metalib_target

View File

@@ -0,0 +1,9 @@
// Filename: pandaphysics.cxx
// Created by: drose (16May00)
//
////////////////////////////////////////////////////////////////////
// This is a dummy file whose sole purpose is to give the compiler
// something to compile when making libpandaphysics.so in NO_DEFER mode,
// which generates an empty library that itself links with all the
// other shared libraries that make up libpandaphysics.

View File

@@ -0,0 +1,21 @@
#define DIRECTORY_IF_RIB yes
// DIR_TYPE "metalib" indicates we are building a shared library that
// consists mostly of references to other shared libraries. Under
// Windows, this directly produces a DLL (as opposed to the regular
// src libraries, which don't produce anything but a pile of OBJ files
// under Windows).
#define DIR_TYPE metalib
#define BUILDING_DLL BUILDING_PANDARIB
#define LOCAL_LIBS \
ribgsg ribdisplay
#define OTHER_LIBS interrogatedb dconfig dtoolutil dtoolbase
#begin metalib_target
#define TARGET pandarib
#define SOURCES pandarib.cxx
#end metalib_target

View File

@@ -0,0 +1,9 @@
// Filename: pandarib.cxx
// Created by: drose (15May00)
//
////////////////////////////////////////////////////////////////////
// This is a dummy file whose sole purpose is to give the compiler
// something to compile when making libpandarib.so in NO_DEFER mode,
// which generates an empty library that itself links with all the
// other shared libraries that make up libpandarib.

212
panda/src/PACKAGE-DESC Normal file
View File

@@ -0,0 +1,212 @@
Quick descriptions of the packages:
audio -
Audio API for panda
builder -
A tool to create Geoms and GeomNodes from a pile of unconnected
triangles or polygons. It separates geometry according to state
(texturing, normals, etc.), discovers connections where they exist
and tries to build nearly-optimal tristrips.
chan -
Animation channels. This defines the various kinds of
AnimChannels that may be defined, as well as the MovingPart class
which binds to the channels and plays the animation. This is a
support library for char, as well as any other libraries that want
to define objects whose values change over time.
chancfg -
This package contains the code for the 'channel configuration' system.
This is responsible for asking for a window to be opened, possibly binding
'pipe video' channels to it, and dividing it up into Display Regions.
chat -
Implementation of a text-entry system along the bottom edge of the
window, along with any other support functions for an online chat
system that might be required.
collide -
This package contains the classes that control and detect collisions
configfiles -
This package contains the housekeeping and configuration files needed by
things like attach, and emacs.
cull -
This package contains the Cull Traverser. The cull traversal collects all
state changes specified, and removes unneccesary state change requests. Also
does all the depth sorting for proper alphaing.
device -
Device drivers, such as mouse and keyboard, trackers, etc... The
base class for using various device APIs is here.
dgraph -
Defines and manages the data graph, which is the hierarchy of
devices, tforms, and any other things which might have an input or
an output and need to execute every frame.
display -
Abstract display classes, including pipes, windows, channels, and
display regions
doc -
Documentation that doesn't fit in any of the packages
downloader -
Tool to allow automatic download of files in the background
dxgsg -
Handles all communication with the DirectX backend, and manages state
to minimize redundant state changes.
effects -
Various graphics effects that aren't shaders. I.E Lens Flares
egg -
A.k.a. the "egg library", this reads, writes, and manipulates egg
files. It knows nothing about the scene graph structure in the
rest of the player; it lives in its own little egg world.
egg2sg -
A.k.a. the "egg loader", this converts the egg structure read from
the egg library, above, to a scene graph structure, suitable for
rendering.
event -
Tools for throwing, handling and receiving events
framework -
A simple, stupid framework around which to write a simple, stupid
demo program. Handy for quickly writing programs that open a
window and display the OmniTriangle.
glgsg -
Handles all communication with the GL backend, and manages state
to minimize redundant state changes.
glidedisplay - (defunct)
This package contains the code to manage pipes/windows/channels on glide
hardware.
glidegsg - (defunct)
This package contains the GSG for the glide backend. All glide calls
should live in here.
glutdisplay -
Glut specific display classes. This uses the Glut library to open
a window and manage keyboard and mouse events. Glut has the
advantage of being widely ported, but unfortunately it needs to
control the main loop and so limits the kind of programs you can
write.
glxdisplay -
X windows display classes that replace Glut functionality.
gobj -
Graphical non-scene-graph objects, such as textures and geometry primitives
graph -
Defines the basic graph operations that are not specific to scene
graphs. This includes nodes, relations, transitions, and
attributes.
gsg -
The base definition for the GraphicsStateGuardian. This is the
abstract base class for all backend specifications.
gsgbase -
Base GSG class defined to avoid cyclical dependency build
gsgmisc -
Some utility functions for gsg that could not live in the same
directory for circular dependency reasons.
ipc -
This package contains the abstraction/adaptation layer for: mutexes,
semiphores, condition variables, threads, and files.
light -
Lights needed to be their own package to avoid multiple inheritance
problems. All concrete light types are both lights and nodes.
linmath -
Linear algebra library.
loader -
Tool for loading various kinds of files into Graph structures.
Can be done asynchronously
mathutil -
Math utility functions, such as frustum and plane
net -
Net connection classes
panda -
Builds the libpanda shared library. This is a single library that
encapsulates most of the packages in Panda, especially those that
are considered essential to Panda's basic functionality. On
Windows platforms, the individual packages are not themselves
built into shared libraries; the single LIBPANDA.DLL is the only
library file. On Unix platforms, the individual packages are each
built into their own shared library files, and a trivial
libpanda.so is built that unifies all of them.
pandadx -
As above, for the DirectX libraries. This includes all of the
packages, in addition to those in libpanda, that are required for
rendering on a DirectX platform. This also includes
Windows-specific libraries.
pandaegg -
As above, for the egg reader. This includes all of the packages,
in addition to those in libpanda, that are required for reading
egg files into the scene graph.
pandagl -
As above, for the OpenGL libraries. This includes all of the
packages, in addition to those in libpanda, that are required for
rendering on an OpenGL platform, with the exception of Glut.
pandaglut -
As above, for the OpenGL Glut libraries.
pandaphysics -
As above, for the physics/particle systems libraries.
pandarib -
As above, for the Renderman non-realtime renderer.
particlesystem -
Tool for doing particle systems. Contains various kinds of particles,
emiters, factories and renderers.
physics -
Base classes for physical objects and forces. Also contains the
physics manager class
pnm -
A more-or-less intact version of the NetPBM package, compiled as a
single library. This is a support library for pnmimage.
pnmimage -
Reads and writes image files in various formats, by using the pnm
and tiff libraries.
pstats -
Package for gathering performance statistics
ps2display - (defunct)
Playstation 2 display classes.
p2gsg - (defunct)
Play station 2 specific rendering backend.
ribdisplay -
RIB-specific "display" classes. These don't actually open
windows, but actually specify filenames.
ribgsg -
The RIB-specific rendering backend. Writing a frame to this
backend causes a RIB file to be produced, which can be used to
render the scene offline.
sgattrib -
Scene graph attributes and transitions (state information)
sgidisplay -
This package contains the code to manage pipes/windows/channels on SGI
hardware.
sgiglutdisplay -
This package contains the code to manage pipes/windows/channels on SGI
hardware for GLUT
sgiglxdisplay -
SGI specific X windows display classes that replace Glut functionality.
sgmanip -
High-level tools for manipulation of scene graphs. This primarily
defines NodePath, the principle interface for high-level scripting
languages into the scene graph.
sgraph -
Graph operations and nodes that are specific to render-type scene
graphs. This includes GeomNode, Camera, etc.
sgraphutil -
Handy utility functions for working with scene graphs.
shader -
Shaders that generate special effects by modifying the render
traversal and computing multiple passes.
stats - (defunct)
Package for gathering performance stats
statsdisplay - (defunct)
Package for remotely displaying the perfomance stats on a running program
switchnode -
Package of nodes that switch out geometry underneath them based on
various conditions.
testbed -
C test programs, that primarily link with framework.
text -
Package for generating renderable text using textured polygons.
tform -
Data transforming objects that live in the data graph and convert
raw data (as read from an input device, for instance) to something
more useful.
tiff -
Another support library for pnmimage.
util -
This package contains all the little fiddley things that are atomic to
just about all the code. Things like: config, ref count, notify, etc.
vrpn -
Defines the specific client code for interfacing to the VRPN API.
wdxdisplay -
Windows DirectX specific display classes
wgldisplay -
Windows OpenGL specific display classes

4
panda/src/Sources.pp Normal file
View File

@@ -0,0 +1,4 @@
// This is a group directory: a directory level above a number of
// source subdirectories.
#define DIR_TYPE group

View File

@@ -0,0 +1,49 @@
#define OTHER_LIBS interrogatedb dconfig dtoolutil dtoolbase
#begin lib_target
#define TARGET audio
#define LOCAL_LIBS putil ipc
#define SOURCES \
audio_manager.I audio_manager.cxx audio_manager.h audio_midi.cxx \
audio_midi.h audio_music.I audio_music.cxx audio_music.h \
audio_pool.I audio_pool.cxx audio_pool.h audio_sample.I \
audio_sample.cxx audio_sample.h audio_trait.cxx audio_trait.h \
config_audio.cxx config_audio.h
#define INSTALL_HEADERS \
audio.h audio_manager.h audio_music.h audio_pool.I audio_pool.h \
audio_sample.I audio_sample.h audio_trait.h
#define IGATESCAN audio.h
#end lib_target
#begin lib_target
#define TARGET audio_load_midi
#define LOCAL_LIBS \
audio
#define SOURCES \
audio_load_midi.cxx
#end lib_target
#begin lib_target
#define TARGET audio_load_wav
#define LOCAL_LIBS \
audio
#define SOURCES \
audio_load_wav.cxx
#end lib_target
#begin test_bin_target
#define TARGET test_audio
#define SOURCES \
test_audio.cxx
#end test_bin_target

15
panda/src/audio/audio.h Normal file
View File

@@ -0,0 +1,15 @@
// Filename: audio.h
// Created by: frang (06Jul00)
//
////////////////////////////////////////////////////////////////////
#ifndef __AUDIO_H__
#define __AUDIO_H__
#include "audio_trait.h"
#include "audio_sample.h"
#include "audio_music.h"
#include "audio_manager.h"
#include "audio_pool.h"
#endif /* __AUDIO_H__ */

View File

@@ -0,0 +1,75 @@
// Filename: audio_load_midi.cxx
// Created by: cary (26Sep00)
//
////////////////////////////////////////////////////////////////////
#include <dconfig.h>
#include "audio_pool.h"
#include "config_audio.h"
Configure(audio_load_midi);
#ifdef USE_MIKMOD
#include "audio_mikmod_traits.h"
void AudioDestroyMidi(AudioTraits::MusicClass* music) {
MikModMidi::destroy(music);
}
void AudioLoadMidi(AudioTraits::MusicClass** music,
AudioTraits::PlayerClass** player,
AudioTraits::DeleteMusicFunc** destroy, Filename filename) {
*music = MikModMidi::load_midi(filename);
if (*music == (AudioTraits::MusicClass*)0L)
return;
*player = MikModMidiPlayer::get_instance();
*destroy = AudioDestroyMidi;
}
#else
#ifdef PENV_WIN32
#include "audio_win_traits.h"
void AudioDestroyMidi(AudioTraits::MusicClass* music) {
WinMusic::destroy(music);
}
void AudioLoadMidi(AudioTraits::MusicClass** music,
AudioTraits::PlayerClass** player,
AudioTraits::DeleteMusicFunc** destroy, Filename filename) {
*music = WinMusic::load_midi(filename);
if (*music == (AudioTraits::MusicClass*)0L)
return;
*player = WinPlayer::get_instance();
*destroy = AudioDestroyMidi;
audio_cat->debug() << "sanity check: music = " << (void*)*music
<< " player = " << (void*)*player << " destroy = "
<< (void*)*destroy << endl;
}
#else
// Null driver
#include "audio_null_traits.h"
void AudioDestroyMidi(AudioTraits::MusicClass* music) {
delete music;
}
void AudioLoadMidi(AudioTraits::MusicClass** music,
AudioTraits::PlayerClass** player,
AudioTraits::DeleteMusicFunc** destroy, Filename) {
*music = new NullMusic();
*player = new NullPlayer();
*destroy = AudioDestroyMidi;
}
#endif /* win32 */
#endif /* mikmod */
ConfigureFn(audio_load_midi) {
AudioPool::register_music_loader("midi", AudioLoadMidi);
AudioPool::register_music_loader("mid", AudioLoadMidi);
}

View File

@@ -0,0 +1,71 @@
// Filename: audio_load_wav.cxx
// Created by: cary (23Sep00)
//
////////////////////////////////////////////////////////////////////
#include <dconfig.h>
#include "audio_pool.h"
Configure(audio_load_wav);
#ifdef USE_MIKMOD
#include "audio_mikmod_traits.h"
void AudioDestroyWav(AudioTraits::SampleClass* sample) {
MikModSample::destroy(sample);
}
void AudioLoadWav(AudioTraits::SampleClass** sample,
AudioTraits::PlayerClass** player,
AudioTraits::DeleteSampleFunc** destroy, Filename filename) {
*sample = MikModSample::load_wav(filename);
if (*sample == (AudioTraits::SampleClass*)0L)
return;
*player = MikModSamplePlayer::get_instance();
*destroy = AudioDestroyWav;
}
#else /* no MikMod */
#ifdef PENV_WIN32
#include "audio_win_traits.h"
void AudioDestroyWav(AudioTraits::SampleClass* sample) {
WinSample::destroy(sample);
}
void AudioLoadWav(AudioTraits::SampleClass** sample,
AudioTraits::PlayerClass** player,
AudioTraits::DeleteSampleFunc** destroy, Filename filename) {
*sample = WinSample::load_wav(filename);
if (*sample == (AudioTraits::SampleClass*)0L)
return;
*player = WinPlayer::get_instance();
*destroy = AudioDestroyWav;
}
#else /* no win32 */
// Null driver
#include "audio_null_traits.h"
void AudioDestroyWav(AudioTraits::SampleClass* sample) {
delete sample;
}
void AudioLoadWav(AudioTraits::SampleClass** sample,
AudioTraits::PlayerClass** player,
AudioTraits::DeleteSampleFunc** destroy, Filename) {
*sample = new NullSample();
*player = new NullPlayer();
*destroy = AudioDestroyWav;
}
#endif /* win32 */
#endif /* MikMod */
ConfigureFn(audio_load_wav) {
AudioPool::register_sample_loader("wav", AudioLoadWav);
}

View File

@@ -0,0 +1,69 @@
// Filename: audio_manager.I
// Created by: cary (24Sep00)
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AudioManager::play (AudioSample)
// Access: Public, Static
// Description: Play an audio sample
////////////////////////////////////////////////////////////////////
INLINE void AudioManager::play(AudioSample* sample) {
get_ptr()->ns_play(sample);
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::play (AudioMusic)
// Access: Public, Static
// Description: Play an audio music instance
////////////////////////////////////////////////////////////////////
INLINE void AudioManager::play(AudioMusic* music) {
get_ptr()->ns_play(music);
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::update
// Access: Public, Static
// Description: make sure buffers are full
////////////////////////////////////////////////////////////////////
INLINE void AudioManager::update(void) {
mutex_lock l(_manager_mutex);
if (_update_func != (UpdateFunc*)0L)
(*_update_func)();
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::spawn_update
// Access: Public, Static
// Description: spawn a thread to call update
////////////////////////////////////////////////////////////////////
INLINE void AudioManager::spawn_update(void) {
get_ptr()->ns_spawn_update();
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::set_volume (sample)
// Access: Public, Static
// Description: set the volume on a sample
////////////////////////////////////////////////////////////////////
INLINE void AudioManager::set_volume(AudioSample* sample, int v) {
get_ptr()->ns_set_volume(sample, v);
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::set_volume (music)
// Access: Public, Static
// Description: set the volume on music
////////////////////////////////////////////////////////////////////
INLINE void AudioManager::set_volume(AudioMusic* music, int v) {
get_ptr()->ns_set_volume(music, v);
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::Constructor
// Access: Private
// Description: The constructor is not intended to be called
// directly; there's only supposed to be one AudioManager
// in the universe and it constructs itself.
////////////////////////////////////////////////////////////////////
INLINE AudioManager::AudioManager(void) : _spawned((thread*)0L) {}

View File

@@ -0,0 +1,95 @@
// Filename: audio_manager.cxx
// Created by: cary (24Sep00)
//
////////////////////////////////////////////////////////////////////
#include "audio_manager.h"
#include "config_audio.h"
AudioManager* AudioManager::_global_ptr = (AudioManager*)0L;
AudioManager::UpdateFunc* AudioManager::_update_func =
(AudioManager::UpdateFunc*)0L;
mutex AudioManager::_manager_mutex;
////////////////////////////////////////////////////////////////////
// Function: AudioManager::set_update_func
// Access: Public, Static
// Description: register a function that will maintain the buffers
// for audio output
////////////////////////////////////////////////////////////////////
void AudioManager::set_update_func(AudioManager::UpdateFunc* func) {
if (_update_func != (AudioManager::UpdateFunc*)0L)
audio_cat->error() << "There maybe be more then one audio driver installed"
<< endl;
_update_func = func;
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::get_ptr
// Access: Private, Static
// Description: Initializes and/or returns the global pointer to the
// one AudioManager object in the system.
////////////////////////////////////////////////////////////////////
AudioManager* AudioManager::get_ptr(void) {
if (_global_ptr == (AudioManager*)0L)
_global_ptr = new AudioManager;
return _global_ptr;
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::ns_play (AudioSample)
// Access: Private
// Description: get the player off the sample, and start it playing
////////////////////////////////////////////////////////////////////
void AudioManager::ns_play(AudioSample* sample) {
sample->get_player()->play_sample(sample->get_sample());
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::ns_play (AudioMusic)
// Access: Private
// Description: get the player off the music, and start it playing
////////////////////////////////////////////////////////////////////
void AudioManager::ns_play(AudioMusic* music) {
music->get_player()->play_music(music->get_music());
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::spawned_update
// Access: static
// Description: the thread function to call update forever.
////////////////////////////////////////////////////////////////////
void AudioManager::spawned_update(void*) {
while (1) {
AudioManager::update();
ipc_traits::sleep(0, 1000000);
}
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::ns_set_volume (AudioSample)
// Access: Private
// Description: get the player off the sample, and set volume on it
////////////////////////////////////////////////////////////////////
void AudioManager::ns_set_volume(AudioSample* sample, int v) {
sample->get_player()->set_volume(sample->get_sample(), v);
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::ns_set_volume (AudioMusic)
// Access: Private
// Description: get the player off the music, and set volume on it
////////////////////////////////////////////////////////////////////
void AudioManager::ns_set_volume(AudioMusic* music, int v) {
music->get_player()->set_volume(music->get_music(), v);
}
////////////////////////////////////////////////////////////////////
// Function: AudioManager::ns_spawn_update
// Access: Private
// Description: spawn a thread that calls update every so often
////////////////////////////////////////////////////////////////////
void AudioManager::ns_spawn_update(void) {
_spawned = thread::create(spawned_update, (void*)0L,
thread::PRIORITY_NORMAL);
}

View File

@@ -0,0 +1,47 @@
// Filename: audio_manager.h
// Created by: cary (22Sep00)
//
////////////////////////////////////////////////////////////////////
#ifndef __AUDIO_MANAGER_H__
#define __AUDIO_MANAGER_H__
#include "audio_trait.h"
#include "audio_sample.h"
#include "audio_music.h"
#include <ipc_mutex.h>
#include <ipc_thread.h>
class EXPCL_PANDA AudioManager {
private:
INLINE AudioManager(void);
void ns_play(AudioSample*);
void ns_play(AudioMusic*);
void ns_spawn_update(void);
void ns_set_volume(AudioSample*, int);
void ns_set_volume(AudioMusic*, int);
static AudioManager* get_ptr(void);
static void spawned_update(void*);
typedef void UpdateFunc(void);
static AudioManager* _global_ptr;
static UpdateFunc* _update_func;
static mutex _manager_mutex;
thread* _spawned;
public:
static void set_update_func(UpdateFunc*);
INLINE static void play(AudioSample*);
INLINE static void play(AudioMusic*);
INLINE static void update(void);
INLINE static void spawn_update(void);
INLINE static void set_volume(AudioSample*, int);
INLINE static void set_volume(AudioMusic*, int);
};
#include "audio_manager.I"
#endif /* __AUDIO_MANAGER_H__ */

View File

@@ -0,0 +1,233 @@
// Filename: audio_midi.cxx
// Created by: cary (26Sep00)
//
////////////////////////////////////////////////////////////////////
#include "audio_midi.h"
#include "config_audio.h"
#include <pandabase.h> // get iostream and fstream
#define SHORT short
#define LONG long
#define RIFF 0x52494646
#define CTMF 0x43544d46
#define MThd 0x4d546864
#define MTrk 0x4d54726b
// take data off the supplimental stream until it's empty
inline static unsigned char read8(istream& is, istream& supp) {
unsigned char b;
if (supp.eof()) {
is >> b;
} else {
supp >> b;
}
return b;
}
inline static unsigned SHORT read16(istream& is, istream& supp) {
unsigned char b1, b2;
b1 = read8(is, supp);
b2 = read8(is, supp);
unsigned SHORT ret = (b1 << 8) | (b2);
return ret;
}
inline static unsigned LONG read32(istream& is, istream& supp) {
unsigned char b1, b2, b3, b4;
b1 = read8(is, supp);
b2 = read8(is, supp);
b3 = read8(is, supp);
b4 = read8(is, supp);
unsigned int LONG ret = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
return ret;
}
inline static void scroll8(unsigned LONG& prev, unsigned LONG& curr,
istream& is, istream& supp) {
unsigned char b1 = ((curr >> 24) & 0xff);
prev = ((prev << 8) & 0xffffff00) | (b1);
b1 = read8(is, supp);
curr = ((curr << 8) & 0xffffff00) | (b1);
}
AudioMidi::AudioMidi(Filename filename, int header_idx) {
filename.set_binary();
ifstream in;
if (!filename.open_read(in)) {
cerr << "ACK, cannot read '" << filename << "'" << endl;
return;
}
istringstream dummy("");
unsigned LONG prev = 0x0;
unsigned LONG curr = read32(in, dummy);
int count = 0;
bool done = false;
do {
if (curr == MThd) {
++count;
if (count == header_idx)
done = true;
else {
scroll8(prev, curr, in, dummy);
scroll8(prev, curr, in, dummy);
scroll8(prev, curr, in, dummy);
scroll8(prev, curr, in, dummy);
}
} else {
scroll8(prev, curr, in, dummy);
}
if (in.eof())
done = true;
} while (!done);
if (in.eof()) {
cerr << "fewer then " << header_idx << " headers in file (" << count
<< ")" << endl;
return;
}
if (prev == RIFF) {
if (audio_cat->is_debug())
audio_cat->debug() << "it's a RIFF file" << endl;
curr = read32(in, dummy);
curr = read32(in, dummy);
curr = read32(in, dummy);
curr = read32(in, dummy);
}
unsigned LONG tracklen;
unsigned SHORT format;
unsigned SHORT numtracks;
unsigned SHORT division;
if (curr == MThd) {
if (audio_cat->is_debug())
audio_cat->debug() << "easy header" << endl;
tracklen = read32(in, dummy);
format = read16(in, dummy);
numtracks = read16(in, dummy);
division = read16(in, dummy);
} else if (curr == CTMF) {
// Creative Labs CMF file. We're not supporting this yet
cerr << "don't support Creative Labs CMF files yet" << endl;
return;
} else {
if (audio_cat->is_debug())
audio_cat->debug() << "hard header" << endl;
done = false;
do {
if (curr == MThd)
done = true;
else
scroll8(prev, curr, in, dummy);
if (in.eof())
done = true;
} while (!done);
if (in.eof()) {
cerr << "truncated file!" << endl;
return;
}
tracklen = read32(in, dummy);
format = read16(in, dummy);
numtracks = read16(in, dummy);
division = read16(in, dummy);
}
if (audio_cat->is_debug())
audio_cat->debug() << "Read header. tracklen = " << tracklen
<< " format = " << format << " numtracks = "
<< numtracks << " division = " << division << endl;
for (int currtrack = 0; currtrack < numtracks; ++currtrack) {
string fudge;
curr = read32(in, dummy);
if (curr != MTrk) {
if (audio_cat->is_debug())
audio_cat->debug() << "having to seach for track #" << currtrack
<< endl;
if (curr == MThd) {
if (audio_cat->is_debug())
audio_cat->debug() << "hit a header instead, skipping track" << endl;
continue;
} else {
done = false;
if (currtrack > 0) {
string stmp = (*(_seq.rbegin()));
int i = stmp.rfind("MTrk");
if (i != string::npos) {
fudge = stmp.substr(i+4, string::npos);
unsigned char b;
b = ((curr >> 24) & 0xff);
fudge += b;
b = ((curr >> 16) & 0xff);
fudge += b;
b = ((curr >> 8) & 0xff);
fudge += b;
b = (curr & 0xff);
fudge += b;
done = true;
}
}
if (!done) {
do {
if (curr == MTrk)
done = true;
else
scroll8(prev, curr, in, dummy);
if (in.eof())
done = true;
} while (!done);
if (in.eof()) {
cerr << "truncated file" << endl;
return;
}
}
}
}
if (audio_cat->is_debug())
audio_cat->debug() << "fudge = '" << fudge << "'" << endl;
istringstream fudges(fudge);
if (fudge.empty()) {
// force EOF
unsigned char b;
fudges >> b;
}
unsigned LONG thislen = read32(in, fudges);
if (audio_cat->is_debug())
audio_cat->debug() << "found track #" << currtrack << " with length = "
<< thislen << endl;
{
ostringstream os;
int i;
for (i=0; i<thislen; ++i) {
unsigned char b;
b = read8(in, fudges);
os << b;
if (in.eof() && ((i+1) < thislen))
break;
}
if (in.eof() && (i != thislen)) {
cerr << "truncated file" << endl;
}
string s = os.str();
_seq.push_back(s);
if (audio_cat->is_debug())
audio_cat->debug() << "track data (" << s.length() << "): '" << s
<< "'" << endl;
}
}
if ((_seq.size() != numtracks) && audio_cat->is_debug())
audio_cat->debug()
<< "actual number of tracks read does not match header. ("
<< _seq.size() << " != " << numtracks << ")" << endl;
}
AudioMidi::AudioMidi(const AudioMidi& c) : _seq(c._seq) {}
AudioMidi::~AudioMidi(void) {
}
AudioMidi& AudioMidi::operator=(const AudioMidi&) {
return *this;
}
bool AudioMidi::operator==(const AudioMidi&) const {
return false;
}

View File

@@ -0,0 +1,26 @@
// Filename: audio_midi.h
// Created by: cary (26Sep00)
//
////////////////////////////////////////////////////////////////////
#ifndef __AUDIO_MIDI_H__
#define __AUDIO_MIDI_H__
#include <filename.h>
#include <list>
// define an internal representation for a midi file
class AudioMidi {
private:
typedef list<string> StrList;
StrList _seq;
public:
AudioMidi(Filename, int = 1);
AudioMidi(const AudioMidi&);
~AudioMidi(void);
AudioMidi& operator=(const AudioMidi&);
bool operator==(const AudioMidi&) const;
};
#endif /* __AUDIO_MIDI_H__ */

View File

@@ -0,0 +1,305 @@
// Filename: audio_mikmod_traits.cxx
// Created by: cary (23Sep00)
//
////////////////////////////////////////////////////////////////////
#include "audio_mikmod_traits.h"
#include "audio_manager.h"
#include "config_audio.h"
#include <list>
#include <serialization.h>
static bool have_initialized = false;
static bool initialization_error = false;
static void update_mikmod(void) {
MikMod_Update();
}
static void initialize(void) {
if (have_initialized)
return;
if (initialization_error)
return;
/* register the drivers */
MikMod_RegisterAllDrivers();
/* initialize the mikmod library */
md_mixfreq = audio_mix_freq;
{
// I think this is defined elsewhere
typedef list<string> StrList;
typedef Serialize::Deserializer<StrList> OptBuster;
StrList opts;
OptBuster buster(*audio_mode_flags, " ");
opts = buster();
for (StrList::iterator i=opts.begin(); i!=opts.end(); ++i) {
if ((*i) == "DMODE_INTERP") {
md_mode |= DMODE_INTERP;
} else if ((*i) == "DMODE_REVERSE") {
md_mode |= DMODE_REVERSE;
} else if ((*i) == "DMODE_SURROUND") {
md_mode |= DMODE_SURROUND;
} else if ((*i) == "DMODE_16BITS") {
md_mode |= DMODE_16BITS;
} else if ((*i) == "DMODE_HQMIXER") {
md_mode |= DMODE_HQMIXER;
} else if ((*i) == "DMODE_SOFT_MUSIC") {
md_mode |= DMODE_SOFT_MUSIC;
} else if ((*i) == "DMODE_SOFT_SNDFX") {
md_mode |= DMODE_SOFT_SNDFX;
} else if ((*i) == "DMODE_STEREO") {
md_mode |= DMODE_STEREO;
} else {
audio_cat->error() << "unknown audio driver flag '" << *i << "'"
<< endl;
}
}
if (audio_cat->is_debug()) {
audio_cat->debug() << "final driver mode is (";
bool any_out = false;
if (md_mode & DMODE_INTERP) {
audio_cat->debug(false) << "DMODE_INTERP";
any_out = true;
}
if (md_mode & DMODE_REVERSE) {
if (any_out)
audio_cat->debug(false) << ", ";
audio_cat->debug(false) << "DMODE_REVERSE";
any_out = true;
}
if (md_mode & DMODE_SURROUND) {
if (any_out)
audio_cat->debug(false) << ", ";
audio_cat->debug(false) << "DMODE_SURROUND";
any_out = true;
}
if (md_mode & DMODE_16BITS) {
if (any_out)
audio_cat->debug(false) << ", ";
audio_cat->debug(false) << "DMODE_16BITS";
any_out = true;
}
if (md_mode & DMODE_HQMIXER) {
if (any_out)
audio_cat->debug(false) << ", ";
audio_cat->debug(false) << "DMODE_HQMIXER";
any_out = true;
}
if (md_mode & DMODE_SOFT_MUSIC) {
if (any_out)
audio_cat->debug(false) << ", ";
audio_cat->debug(false) << "DMODE_SOFT_MUSIC";
any_out = true;
}
if (md_mode & DMODE_SOFT_SNDFX) {
if (any_out)
audio_cat->debug(false) << ", ";
audio_cat->debug(false) << "DMODE_SOFT_SNDFX";
any_out = true;
}
if (md_mode & DMODE_STEREO) {
if (any_out)
audio_cat->debug(false) << ", ";
audio_cat->debug(false) << "DMODE_STEREO";
any_out = true;
}
audio_cat->debug(false) << ")" << endl;
}
}
md_device = audio_driver_select;
if (MikMod_Init((char*)(audio_driver_params->c_str()))) {
audio_cat->error() << "Could not initialize the audio drivers. '"
<< MikMod_strerror(MikMod_errno) << "'" << endl;
initialization_error = true;
return;
}
if (audio_cat->is_debug()) {
audio_cat->debug() << "driver info" << endl << MikMod_InfoDriver() << endl;
}
MikMod_SetNumVoices(-1, audio_sample_voices);
AudioManager::set_update_func(update_mikmod);
have_initialized = true;
}
MikModSample::MikModSample(SAMPLE* sample) : _sample(sample), _voice(-1) {
}
MikModSample::~MikModSample(void) {
Sample_Free(_sample);
}
float MikModSample::length(void) {
float len = _sample->length;
float speed = _sample->speed;
return len / speed;
}
AudioTraits::SampleClass::SampleStatus MikModSample::status(void) {
if (_voice == -1)
return READY;
if (Voice_Stopped(_voice))
return PLAYING;
return READY;
}
MikModSample* MikModSample::load_wav(Filename filename) {
initialize();
SAMPLE* sample = Sample_Load((char*)(filename.c_str()));
if (sample == (SAMPLE*)0L) {
audio_cat->error() << "error loading sample '" << filename << "' because '"
<< MikMod_strerror(MikMod_errno) << "'" << endl;
return (MikModSample*)0L;
}
return new MikModSample(sample);
}
void MikModSample::destroy(AudioTraits::SampleClass* sample) {
delete sample;
}
void MikModSample::set_voice(int v) {
_voice = v;
}
int MikModSample::get_voice(void) {
return _voice;
}
SAMPLE* MikModSample::get_sample(void) {
return _sample;
}
int MikModSample::get_freq(void) {
return _sample->speed;
}
MikModMusic::MikModMusic(void) {
}
MikModMusic::~MikModMusic(void) {
}
AudioTraits::MusicClass::MusicStatus MikModMusic::status(void) {
return READY;
}
MikModMidi::MikModMidi(void) {
}
MikModMidi::~MikModMidi(void) {
}
MikModMidi* MikModMidi::load_midi(Filename) {
initialize();
return new MikModMidi();
}
void MikModMidi::destroy(AudioTraits::MusicClass* music) {
delete music;
}
AudioTraits::MusicClass::MusicStatus MikModMidi::status(void) {
return READY;
}
MikModSamplePlayer* MikModSamplePlayer::_global_instance =
(MikModSamplePlayer*)0L;
MikModSamplePlayer::MikModSamplePlayer(void) : AudioTraits::PlayerClass() {
}
MikModSamplePlayer::~MikModSamplePlayer(void) {
}
void MikModSamplePlayer::play_sample(AudioTraits::SampleClass* sample) {
if (!have_initialized)
initialize();
if (!MikMod_Active()) {
if (MikMod_EnableOutput()) {
audio_cat->error() << "could not enable sample output '"
<< MikMod_strerror(MikMod_errno) << "'" << endl;
}
}
// cast to the correct type
MikModSample* msample = (MikModSample*)sample;
// fire it off
msample->set_voice(Sample_Play(msample->get_sample(), 0, 0));
Voice_SetFrequency(msample->get_voice(), msample->get_freq());
if (Voice_GetFrequency(msample->get_voice()) != msample->get_freq())
audio_cat->error() << "setting freq did not stick!" << endl;
Voice_SetPanning(msample->get_voice(), 127);
}
void MikModSamplePlayer::play_music(AudioTraits::MusicClass*) {
audio_cat->error() << "trying to play music with a MikModSamplePlayer"
<< endl;
}
void MikModSamplePlayer::set_volume(AudioTraits::SampleClass* sample, int v) {
initialize();
MikModSample* msample = (MikModSample*)sample;
Voice_SetVolume(msample->get_voice(), v);
}
void MikModSamplePlayer::set_volume(AudioTraits::MusicClass*, int) {
audio_cat->error()
<< "trying to set volume on music withe a MikModSamplePlayer" << endl;
}
MikModSamplePlayer* MikModSamplePlayer::get_instance(void) {
if (_global_instance == (MikModSamplePlayer*)0L)
_global_instance = new MikModSamplePlayer();
return _global_instance;
}
MikModFmsynthPlayer::MikModFmsynthPlayer(void) {
}
MikModFmsynthPlayer::~MikModFmsynthPlayer(void) {
}
void MikModFmsynthPlayer::play_sample(AudioTraits::SampleClass*) {
audio_cat->error() << "trying to play a sample with a MikModFmsynthPlayer"
<< endl;
}
void MikModFmsynthPlayer::play_music(AudioTraits::MusicClass* music) {
}
void MikModFmsynthPlayer::set_volume(AudioTraits::SampleClass*, int) {
audio_cat->error()
<< "trying to set volume on a sample with a MikModFmsynthPlayer" << endl;
}
void MikModFmsynthPlayer::set_volume(AudioTraits::MusicClass*, int) {
}
MikModMidiPlayer* MikModMidiPlayer::_global_instance = (MikModMidiPlayer*)0L;
MikModMidiPlayer::MikModMidiPlayer(void) {
}
MikModMidiPlayer::~MikModMidiPlayer(void) {
}
void MikModMidiPlayer::play_sample(AudioTraits::SampleClass*) {
audio_cat->error() << "trying to play a sample with a MikModMidiPlayer"
<< endl;
}
void MikModMidiPlayer::play_music(AudioTraits::MusicClass* music) {
}
void MikModMidiPlayer::set_volume(AudioTraits::SampleClass*, int) {
audio_cat->error()
<< "trying to set volume on a sample with a MikModMidiPlayer" << endl;
}
void MikModMidiPlayer::set_volume(AudioTraits::MusicClass*, int) {
}
MikModMidiPlayer* MikModMidiPlayer::get_instance(void) {
if (_global_instance == (MikModMidiPlayer*)0L)
_global_instance = new MikModMidiPlayer();
return _global_instance;
}

View File

@@ -0,0 +1,102 @@
// Filename: audio_mikmod_traits.h
// Created by: frang (06Jul00)
//
////////////////////////////////////////////////////////////////////
#ifndef __AUDIO_MIKMOD_TRAITS_H__
#define __AUDIO_MIKMOD_TRAITS_H__
#include "audio_trait.h"
#include <pandabase.h>
#include <filename.h>
#include <mikmod.h>
class EXPCL_PANDA MikModSample : public AudioTraits::SampleClass {
private:
SAMPLE* _sample;
int _voice;
MikModSample(SAMPLE*);
public:
virtual ~MikModSample(void);
virtual float length(void);
virtual AudioTraits::SampleClass::SampleStatus status(void);
public:
// used by the readers
static MikModSample* load_wav(Filename);
static void destroy(AudioTraits::SampleClass*);
// used by the players
virtual void set_voice(int);
virtual int get_voice(void);
virtual SAMPLE* get_sample(void);
virtual int get_freq(void);
};
class EXPCL_PANDA MikModMusic : public AudioTraits::MusicClass {
private:
MODULE* _music;
public:
MikModMusic(void);
virtual ~MikModMusic(void);
virtual AudioTraits::MusicClass::MusicStatus status(void);
};
class EXPCL_PANDA MikModMidi : public AudioTraits::MusicClass {
private:
public:
MikModMidi(void);
virtual ~MikModMidi(void);
virtual AudioTraits::MusicClass::MusicStatus status(void);
public:
// used by the readers
static MikModMidi* load_midi(Filename);
static void destroy(AudioTraits::MusicClass*);
};
class EXPCL_PANDA MikModSamplePlayer : public AudioTraits::PlayerClass {
public:
MikModSamplePlayer(void);
virtual ~MikModSamplePlayer(void);
virtual void play_sample(AudioTraits::SampleClass*);
virtual void play_music(AudioTraits::MusicClass*);
virtual void set_volume(AudioTraits::SampleClass*, int);
virtual void set_volume(AudioTraits::MusicClass*, int);
public:
// used by the readers
static MikModSamplePlayer* get_instance(void);
private:
static MikModSamplePlayer* _global_instance;
};
class EXPCL_PANDA MikModFmsynthPlayer : public AudioTraits::PlayerClass {
public:
MikModFmsynthPlayer(void);
virtual ~MikModFmsynthPlayer(void);
virtual void play_sample(AudioTraits::SampleClass*);
virtual void play_music(AudioTraits::MusicClass*);
virtual void set_volume(AudioTraits::SampleClass*, int);
virtual void set_volume(AudioTraits::MusicClass*, int);
};
class EXPCL_PANDA MikModMidiPlayer : public AudioTraits::PlayerClass {
public:
MikModMidiPlayer(void);
virtual ~MikModMidiPlayer(void);
virtual void play_sample(AudioTraits::SampleClass*);
virtual void play_music(AudioTraits::MusicClass*);
virtual void set_volume(AudioTraits::SampleClass*, int);
virtual void set_volume(AudioTraits::MusicClass*, int);
public:
// used by the readers
static MikModMidiPlayer* get_instance(void);
private:
static MikModMidiPlayer* _global_instance;
};
#endif /* __AUDIO_MIKMOD_TRAITS_H__ */

View File

@@ -0,0 +1,67 @@
// Filename: audio_music.I
// Created by: cary (26Sep00)
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AudioMusic::constructor
// Access: Protected
// Description: initialize a new music
////////////////////////////////////////////////////////////////////
INLINE AudioMusic::AudioMusic(AudioTraits::MusicClass* music,
AudioTraits::PlayerClass* player,
AudioTraits::DeleteMusicFunc* destroy,
const string& filename) : Namable(filename),
_music(music),
_player(player),
_destroy(destroy) {}
////////////////////////////////////////////////////////////////////
// Function: AudioMusic::copy constructor
// Access: Protected
// Description: copy a music, but we don't really want to allow this
////////////////////////////////////////////////////////////////////
INLINE AudioMusic::AudioMusic(const AudioMusic& c) : Namable(c.get_name()),
_music(c._music),
_player(c._player),
_destroy(c._destroy) {}
////////////////////////////////////////////////////////////////////
// Function: AudioMusic::assignment operator
// Access: Protected
// Description: copy a music, but we don't really want to allow this
////////////////////////////////////////////////////////////////////
INLINE AudioMusic& AudioMusic::operator=(const AudioMusic& c) {
this->set_name(c.get_name());
this->_music = c._music;
this->_player = c._player;
this->_destroy = c._destroy;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: AudioMusic::get_player
// Access: Protected
// Description: return the player for this music
////////////////////////////////////////////////////////////////////
INLINE AudioTraits::PlayerClass* AudioMusic::get_player(void) {
return _player;
}
////////////////////////////////////////////////////////////////////
// Function: AudioMusic::get_music
// Access: Protected
// Description: return the trait music class for this music
////////////////////////////////////////////////////////////////////
INLINE AudioTraits::MusicClass* AudioMusic::get_music(void) {
return _music;
}
////////////////////////////////////////////////////////////////////
// Function: AudioMusic::equality operator
// Access: Public
// Description: test to see if two musics are the same
////////////////////////////////////////////////////////////////////
INLINE bool AudioMusic::operator==(const AudioMusic& c) const {
return (_music == c._music);
}

View File

@@ -0,0 +1,36 @@
// Filename: audio_music.cxx
// Created by: cary (26Sep00)
//
////////////////////////////////////////////////////////////////////
#include "audio_music.h"
#include "config_audio.h"
TypeHandle AudioMusic::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: AudioMusic::destructor
// Access: Public
// Description: deletes the music data and then lets the system
// destroy this structure
////////////////////////////////////////////////////////////////////
AudioMusic::~AudioMusic(void) {
(*_destroy)(_music);
}
////////////////////////////////////////////////////////////////////
// Function: AudioMusic::status
// Access: Public
// Description: return the current play status of this music
////////////////////////////////////////////////////////////////////
AudioMusic::MusicStatus AudioMusic::status(void) {
AudioTraits::MusicClass::MusicStatus stat = _music->status();
switch (stat) {
case AudioTraits::MusicClass::READY:
return READY;
case AudioTraits::MusicClass::PLAYING:
return PLAYING;
}
audio_cat->error() << "unknown status for music" << endl;
return READY;
}

View File

@@ -0,0 +1,62 @@
// Filename: audio_music.h
// Created by: cary (22Sep00)
//
////////////////////////////////////////////////////////////////////
#ifndef __AUDIO_MUSIC_H__
#define __AUDIO_MUSIC_H__
#include "audio_trait.h"
#include "typedReferenceCount.h"
#include "namable.h"
class AudioPool;
class AudioManager;
class EXPCL_PANDA AudioMusic : public TypedReferenceCount, public Namable {
private:
AudioTraits::MusicClass *_music;
AudioTraits::PlayerClass *_player;
AudioTraits::DeleteMusicFunc *_destroy;
protected:
INLINE AudioMusic(AudioTraits::MusicClass*, AudioTraits::PlayerClass*,
AudioTraits::DeleteMusicFunc*, const string&);
INLINE AudioMusic(const AudioMusic&);
INLINE AudioMusic& operator=(const AudioMusic&);
INLINE AudioTraits::PlayerClass* get_player(void);
INLINE AudioTraits::MusicClass* get_music(void);
friend class AudioPool;
friend class AudioManager;
public:
virtual ~AudioMusic(void);
INLINE bool operator==(const AudioMusic&) const;
enum MusicStatus { READY, PLAYING };
MusicStatus status(void);
public:
// type stuff
static TypeHandle get_class_type(void) {
return _type_handle;
}
static void init_type(void) {
TypedReferenceCount::init_type();
register_type(_type_handle, "AudioMusic",
TypedReferenceCount::get_class_type());
}
virtual TypeHandle get_type(void) const {
return get_class_type();
}
virtual TypeHandle force_init_type(void) {
init_type();
return get_class_type();
}
private:
static TypeHandle _type_handle;
};
#include "audio_music.I"
#endif /* __AUDIO_MUSIC_H__ */

View File

@@ -0,0 +1,13 @@
// Filename: audio_null_traits.I
// Created by: cary (25Sep00)
//
////////////////////////////////////////////////////////////////////
INLINE NullSample::NullSample(void) {
}
INLINE NullMusic::NullMusic(void) {
}
INLINE NullPlayer::NullPlayer(void) {
}

View File

@@ -0,0 +1,70 @@
// Filename: audio_null_traits.cxx
// Created by: cary (25Sep00)
//
////////////////////////////////////////////////////////////////////
#include "audio_null_traits.h"
#include "audio_manager.h"
#include "config_audio.h"
static bool have_initialized = false;
static void update_null(void) {
if (audio_cat->is_debug())
audio_cat->debug() << "Update in Null audio driver" << endl;
}
static void initialize(void) {
if (have_initialized)
return;
AudioManager::set_update_func(update_null);
have_initialized = true;
}
NullSample::~NullSample(void) {
}
float NullSample::length(void) {
if (audio_cat->is_debug())
audio_cat->debug() << "in sample length in Null audio driver" << endl;
return 0.;
}
AudioTraits::SampleClass::SampleStatus NullSample::status(void) {
if (audio_cat->is_debug())
audio_cat->debug() << "in sample status in Null audio driver" << endl;
return AudioTraits::SampleClass::READY;
}
NullMusic::~NullMusic(void) {
}
AudioTraits::MusicClass::MusicStatus NullMusic::status(void) {
if (audio_cat->is_debug())
audio_cat->debug() << "in music status in Null audio driver" << endl;
return READY;
}
NullPlayer::~NullPlayer(void) {
}
void NullPlayer::play_sample(AudioTraits::SampleClass*) {
if (audio_cat->is_debug())
audio_cat->debug() << "in play sample in Null audio driver" << endl;
}
void NullPlayer::play_music(AudioTraits::MusicClass*) {
if (audio_cat->is_debug())
audio_cat->debug() << "in play music in Null audio driver" << endl;
}
void NullPlayer::set_volume(AudioTraits::SampleClass*, int) {
if (audio_cat->is_debug())
audio_cat->debug() << "in set volume (sample) in Null audio driver"
<< endl;
}
void NullPlayer::set_volume(AudioTraits::MusicClass*, int) {
if (audio_cat->is_debug())
audio_cat->debug() << "in set volume (music) in Null audio driver" << endl;
}

View File

@@ -0,0 +1,41 @@
// Filename: audio_null_traits.h
// Created by: cary (25Sep00)
//
////////////////////////////////////////////////////////////////////
#ifndef __AUDIO_NULL_TRAITS_H__
#define __AUDIO_NULL_TRAITS_H__
#include "audio_trait.h"
class EXPCL_PANDA NullSample : public AudioTraits::SampleClass {
public:
INLINE NullSample(void);
virtual ~NullSample(void);
virtual float length(void);
virtual AudioTraits::SampleClass::SampleStatus status(void);
};
class EXPCL_PANDA NullMusic : public AudioTraits::MusicClass {
public:
INLINE NullMusic(void);
virtual ~NullMusic(void);
virtual AudioTraits::MusicClass::MusicStatus status(void);
};
class EXPCL_PANDA NullPlayer : public AudioTraits::PlayerClass {
public:
INLINE NullPlayer(void);
virtual ~NullPlayer(void);
virtual void play_sample(AudioTraits::SampleClass*);
virtual void play_music(AudioTraits::MusicClass*);
virtual void set_volume(AudioTraits::SampleClass*, int);
virtual void set_volume(AudioTraits::MusicClass*, int);
};
#include "audio_null_traits.I"
#endif /* __AUDIO_NULL_TRAITS_H__ */

View File

@@ -0,0 +1,141 @@
// Filename: audio_pool.I
// Created by: cary (22Sep00)
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AudioPool::has_sample
// Access: Public, Static
// Description: Returns true if the sample has ever been loaded,
// false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool AudioPool::has_sample(const string& filename) {
return get_ptr()->ns_has_sample(filename);
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::verify_sample
// Access: Public, Static
// Description: Loads the given filename up into a sample, if it has
// not already been loaded, and returns true to indicate
// success, or false to indicate failure. If this
// returns true, it is guaranteed that a subsequent call
// to load_sample() with the same sample name will
// return a valid AudioSample pointer.
////////////////////////////////////////////////////////////////////
INLINE bool AudioPool::verify_sample(const string& filename) {
return load_sample(filename) != (AudioSample*)0L;
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::load_sample
// Access: Public, Static
// Description: Loads the given filename up into a sample, if it has
// not already been loaded, and returns the new sample.
// If a sample with the same filename was previously
// loaded, returns that one instead. If the sample
// file cannot be found, returns NULL.
////////////////////////////////////////////////////////////////////
INLINE AudioSample* AudioPool::load_sample(const string& filename) {
return get_ptr()->ns_load_sample(filename);
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::release_sample
// Access: Public, Static
// Description: Removes the indicated sample from the pool,
// indicating it will never be loaded again; the sample
// may then be freed. If this function is never called,
// a reference count will be maintained on every sample
// ever loaded, and samples will never be freed.
//
// The sample's name should not have been changed
// during its lifetime, or this function may fail to
// locate it in the pool.
////////////////////////////////////////////////////////////////////
INLINE void AudioPool::release_sample(AudioSample* sample) {
get_ptr()->ns_release_sample(sample);
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::release_all_samples
// Access: Public, Static
// Description: Releases all samples in the pool and restores the
// pool to the empty state.
////////////////////////////////////////////////////////////////////
INLINE void AudioPool::release_all_samples(void) {
get_ptr()->ns_release_all_samples();
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::has_music
// Access: Public, Static
// Description: Returns true if the music has ever been loaded,
// false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool AudioPool::has_music(const string& filename) {
return get_ptr()->ns_has_music(filename);
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::verify_music
// Access: Public, Static
// Description: Loads the given filename up into a music, if it has
// not already been loaded, and returns true to indicate
// success, or false to indicate failure. If this
// returns true, it is guaranteed that a subsequent call
// to load_music() with the same music name will
// return a valid AudioMusic pointer.
////////////////////////////////////////////////////////////////////
INLINE bool AudioPool::verify_music(const string& filename) {
return load_music(filename) != (AudioMusic*)0L;
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::load_music
// Access: Public, Static
// Description: Loads the given filename up into a music, if it has
// not already been loaded, and returns the new music.
// If a music with the same filename was previously
// loaded, returns that one instead. If the music
// file cannot be found, returns NULL.
////////////////////////////////////////////////////////////////////
INLINE AudioMusic* AudioPool::load_music(const string& filename) {
return get_ptr()->ns_load_music(filename);
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::release_music
// Access: Public, Static
// Description: Removes the indicated music from the pool,
// indicating it will never be loaded again; the music
// may then be freed. If this function is never called,
// a reference count will be maintained on every music
// ever loaded, and music will never be freed.
//
// The music's name should not have been changed
// during its lifetime, or this function may fail to
// locate it in the pool.
////////////////////////////////////////////////////////////////////
INLINE void AudioPool::release_music(AudioMusic* music) {
get_ptr()->ns_release_music(music);
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::release_all_music
// Access: Public, Static
// Description: Releases all music in the pool and restores the
// pool to the empty state.
////////////////////////////////////////////////////////////////////
INLINE void AudioPool::release_all_music(void) {
get_ptr()->ns_release_all_music();
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::Constructor
// Access: Private
// Description: The constructor is not intended to be called
// directly; there's only supposed to be one AudioPool
// in the universe and it constructs itself.
////////////////////////////////////////////////////////////////////
INLINE AudioPool::AudioPool(void) {}

View File

@@ -0,0 +1,243 @@
// Filename: audio_pool.cxx
// Created by: cary (22Sep00)
//
////////////////////////////////////////////////////////////////////
#include "audio_pool.h"
#include "config_audio.h"
#include <config_util.h>
AudioPool* AudioPool::_global_ptr = (AudioPool*)0L;
typedef map<string, AudioPool::SampleLoadFunc*> SampleLoaders;
SampleLoaders* _sample_loaders = (SampleLoaders*)0L;
typedef map<string, AudioPool::MusicLoadFunc*> MusicLoaders;
MusicLoaders* _music_loaders = (MusicLoaders*)0L;
////////////////////////////////////////////////////////////////////
// Function: check_sample_loaders
// Access: Static
// Description: ensure that the sample loaders map has been initialized
////////////////////////////////////////////////////////////////////
static void check_sample_loaders(void) {
if (_sample_loaders == (SampleLoaders*)0L)
_sample_loaders = new SampleLoaders;
}
////////////////////////////////////////////////////////////////////
// Function: check_music_loaders
// Access: Static
// Description: ensure that the music loaders map has been initialized
////////////////////////////////////////////////////////////////////
static void check_music_loaders(void) {
if (_music_loaders == (MusicLoaders*)0L)
_music_loaders = new MusicLoaders;
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::get_ptr
// Access: Private, Static
// Description: Initializes and/or returns the global pointer to the
// one AudioPool object in the system.
////////////////////////////////////////////////////////////////////
AudioPool* AudioPool::get_ptr(void) {
if (_global_ptr == (AudioPool*)0L)
_global_ptr = new AudioPool;
return _global_ptr;
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::ns_has_sample
// Access: Private
// Description: The nonstatic implementation of has_sample().
////////////////////////////////////////////////////////////////////
bool AudioPool::ns_has_sample(Filename filename) {
filename.resolve_filename(get_sound_path());
SampleMap::const_iterator si;
si = _samples.find(filename);
if (si != _samples.end()) {
// this sample was previously loaded
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::ns_load_sample
// Access: Private
// Description: The nonstatic implementation of load_sample().
////////////////////////////////////////////////////////////////////
AudioSample* AudioPool::ns_load_sample(Filename filename) {
filename.resolve_filename(get_sound_path());
SampleMap::const_iterator si;
si = _samples.find(filename);
if (si != _samples.end()) {
// this sample was previously loaded
return (*si).second;
}
audio_cat.info() << "Loading sample " << filename << "\n";
AudioTraits::SampleClass* sample = (AudioTraits::SampleClass*)0L;
AudioTraits::PlayerClass* player = (AudioTraits::PlayerClass*)0L;
AudioTraits::DeleteSampleFunc* destroy = (AudioTraits::DeleteSampleFunc*)0L;
string ext = filename.get_extension();
SampleLoaders::const_iterator sli;
check_sample_loaders();
sli = _sample_loaders->find(ext);
if (sli == _sample_loaders->end()) {
audio_cat->error() << "no loader available for audio type '" << ext
<< "'" << endl;
return (AudioSample*)0L;
}
(*((*sli).second))(&sample, &player, &destroy, filename);
if ((sample == (AudioTraits::SampleClass*)0L) ||
(player == (AudioTraits::PlayerClass*)0L) ||
(destroy == (AudioTraits::DeleteSampleFunc*)0L)) {
audio_cat->error() << "could not load '" << filename << "'" << endl;
return (AudioSample*)0L;
}
PT(AudioSample) the_sample = new AudioSample(sample, player, destroy,
filename);
_samples[filename] = the_sample;
return the_sample;
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::ns_release_sample
// Access: Private
// Description: The nonstatic implementation of release_sample().
////////////////////////////////////////////////////////////////////
void AudioPool::ns_release_sample(AudioSample* sample) {
string filename = sample->get_name();
SampleMap::iterator si;
si = _samples.find(filename);
if (si != _samples.end() && (*si).second == sample) {
_samples.erase(si);
}
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::ns_release_all_samples
// Access: Private
// Description: The nonstatic implementation of release_all_samples().
////////////////////////////////////////////////////////////////////
void AudioPool::ns_release_all_samples(void) {
_samples.clear();
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::register_sample_loader
// Access: Public, static
// Description: A static function to register a function for loading
// audio samples.
////////////////////////////////////////////////////////////////////
void AudioPool::register_sample_loader(const string& ext,
AudioPool::SampleLoadFunc* func) {
SampleLoaders::const_iterator sli;
check_sample_loaders();
sli = _sample_loaders->find(ext);
if (sli != _sample_loaders->end()) {
audio_cat->warning() << "attempted to register a loader for audio type '"
<< ext << "' more then once." << endl;
return;
}
(*_sample_loaders)[ext] = func;
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::ns_has_music
// Access: Private
// Description: The nonstatic implementation of has_music().
////////////////////////////////////////////////////////////////////
bool AudioPool::ns_has_music(Filename filename) {
filename.resolve_filename(get_sound_path());
MusicMap::const_iterator si;
si = _music.find(filename);
if (si != _music.end()) {
// this music was previously loaded
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::ns_load_music
// Access: Private
// Description: The nonstatic implementation of load_music().
////////////////////////////////////////////////////////////////////
AudioMusic* AudioPool::ns_load_music(Filename filename) {
filename.resolve_filename(get_sound_path());
MusicMap::const_iterator si;
si = _music.find(filename);
if (si != _music.end()) {
// this sample was previously loaded
return (*si).second;
}
audio_cat.info() << "Loading music " << filename << "\n";
AudioTraits::MusicClass* music = (AudioTraits::MusicClass*)0L;
AudioTraits::PlayerClass* player = (AudioTraits::PlayerClass*)0L;
AudioTraits::DeleteMusicFunc* destroy = (AudioTraits::DeleteMusicFunc*)0L;
string ext = filename.get_extension();
MusicLoaders::const_iterator sli;
check_music_loaders();
sli = _music_loaders->find(ext);
if (sli == _music_loaders->end()) {
audio_cat->error() << "no loader available for audio type '" << ext
<< "'" << endl;
return (AudioMusic*)0L;
}
(*((*sli).second))(&music, &player, &destroy, filename);
if ((music == (AudioTraits::MusicClass*)0L) ||
(player == (AudioTraits::PlayerClass*)0L) ||
(destroy == (AudioTraits::DeleteMusicFunc*)0L)) {
audio_cat->error() << "could not load '" << filename << "'" << endl;
return (AudioMusic*)0L;
}
PT(AudioMusic) the_music = new AudioMusic(music, player, destroy, filename);
_music[filename] = the_music;
return the_music;
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::ns_release_music
// Access: Private
// Description: The nonstatic implementation of release_music().
////////////////////////////////////////////////////////////////////
void AudioPool::ns_release_music(AudioMusic* music) {
string filename = music->get_name();
MusicMap::iterator si;
si = _music.find(filename);
if (si != _music.end() && (*si).second == music) {
_music.erase(si);
}
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::ns_release_all_music
// Access: Private
// Description: The nonstatic implementation of release_all_music().
////////////////////////////////////////////////////////////////////
void AudioPool::ns_release_all_music(void) {
_music.clear();
}
////////////////////////////////////////////////////////////////////
// Function: AudioPool::register_music_loader
// Access: Public, static
// Description: A static function to register a function for loading
// audio music.
////////////////////////////////////////////////////////////////////
void AudioPool::register_music_loader(const string& ext,
AudioPool::MusicLoadFunc* func) {
MusicLoaders::const_iterator sli;
check_music_loaders();
sli = _music_loaders->find(ext);
if (sli != _music_loaders->end()) {
audio_cat->warning() << "attempted to register a loader for audio type '"
<< ext << "' more then once." << endl;
return;
}
(*_music_loaders)[ext] = func;
}

View File

@@ -0,0 +1,63 @@
// Filename: audio_pool.h
// Created by: cary (22Sep00)
//
////////////////////////////////////////////////////////////////////
#ifndef __AUDIO_POOL_H__
#define __AUDIO_POOL_H__
#include "audio_sample.h"
#include "audio_music.h"
#include <map>
#include <pandabase.h>
#include <filename.h>
#include <pointerTo.h>
class EXPCL_PANDA AudioPool {
private:
INLINE AudioPool(void);
bool ns_has_sample(Filename filename);
AudioSample* ns_load_sample(Filename filename);
void ns_release_sample(AudioSample* sample);
void ns_release_all_samples(void);
bool ns_has_music(Filename filename);
AudioMusic* ns_load_music(Filename filename);
void ns_release_music(AudioMusic* music);
void ns_release_all_music(void);
static AudioPool* get_ptr(void);
static AudioPool *_global_ptr;
typedef map<string, PT(AudioSample) > SampleMap;
SampleMap _samples;
typedef map<string, PT(AudioMusic) > MusicMap;
MusicMap _music;
public:
typedef void SampleLoadFunc(AudioTraits::SampleClass**,
AudioTraits::PlayerClass**,
AudioTraits::DeleteSampleFunc**, Filename);
INLINE static bool has_sample(const string& filename);
INLINE static bool verify_sample(const string& filename);
INLINE static AudioSample* load_sample(const string& filename);
INLINE static void release_sample(AudioSample* sample);
INLINE static void release_all_samples(void);
static void register_sample_loader(const string&, SampleLoadFunc*);
typedef void MusicLoadFunc(AudioTraits::MusicClass**,
AudioTraits::PlayerClass**,
AudioTraits::DeleteMusicFunc**, Filename);
INLINE static bool has_music(const string& filename);
INLINE static bool verify_music(const string& filename);
INLINE static AudioMusic* load_music(const string& filename);
INLINE static void release_music(AudioMusic* music);
INLINE static void release_all_music(void);
static void register_music_loader(const string&, MusicLoadFunc*);
};
#include "audio_pool.I"
#endif /* __AUDIO_POOL_H__ */

View File

@@ -0,0 +1,67 @@
// Filename: audio_sample.I
// Created by: cary (23Sep00)
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AudioSample::constructor
// Access: Protected
// Description: initialize a new sample
////////////////////////////////////////////////////////////////////
INLINE AudioSample::AudioSample(AudioTraits::SampleClass* sample,
AudioTraits::PlayerClass* player,
AudioTraits::DeleteSampleFunc* destroy,
const string& filename) : Namable(filename),
_sample(sample),
_player(player),
_destroy(destroy) {}
////////////////////////////////////////////////////////////////////
// Function: AudioSample::copy constructor
// Access: Protected
// Description: copy a sample, but we don't really want to allow this
////////////////////////////////////////////////////////////////////
INLINE AudioSample::AudioSample(const AudioSample& c) : Namable(c.get_name()),
_sample(c._sample),
_player(c._player),
_destroy(c._destroy) {}
////////////////////////////////////////////////////////////////////
// Function: AudioSample::assignment operator
// Access: Protected
// Description: copy a sample, but we don't really want to allow this
////////////////////////////////////////////////////////////////////
INLINE AudioSample& AudioSample::operator=(const AudioSample& c) {
this->set_name(c.get_name());
this->_sample = c._sample;
this->_player = c._player;
this->_destroy = c._destroy;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: AudioSample::get_player
// Access: Protected
// Description: return the player for this sample
////////////////////////////////////////////////////////////////////
INLINE AudioTraits::PlayerClass* AudioSample::get_player(void) {
return _player;
}
////////////////////////////////////////////////////////////////////
// Function: AudioSample::get_sample
// Access: Protected
// Description: return the trait sample class for this sample
////////////////////////////////////////////////////////////////////
INLINE AudioTraits::SampleClass* AudioSample::get_sample(void) {
return _sample;
}
////////////////////////////////////////////////////////////////////
// Function: AudioSample::equality operator
// Access: Public
// Description: test to see if two samples are the same
////////////////////////////////////////////////////////////////////
INLINE bool AudioSample::operator==(const AudioSample& c) const {
return (_sample == c._sample);
}

View File

@@ -0,0 +1,45 @@
// Filename: audio_sample.cxx
// Created by: cary (23Sep00)
//
////////////////////////////////////////////////////////////////////
#include "audio_sample.h"
#include "config_audio.h"
TypeHandle AudioSample::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: AudioSample::destructor
// Access: Public
// Description: deletes the sample data and then lets the system
// destroy this structure
////////////////////////////////////////////////////////////////////
AudioSample::~AudioSample(void) {
(*_destroy)(_sample);
}
////////////////////////////////////////////////////////////////////
// Function: AudioSample::length
// Access: Public
// Description: return the length (in seconds) of the sample
////////////////////////////////////////////////////////////////////
float AudioSample::length(void) {
return _sample->length();
}
////////////////////////////////////////////////////////////////////
// Function: AudioSample::status
// Access: Public
// Description: return the current play status of this sample
////////////////////////////////////////////////////////////////////
AudioSample::SampleStatus AudioSample::status(void) {
AudioTraits::SampleClass::SampleStatus stat = _sample->status();
switch (stat) {
case AudioTraits::SampleClass::READY:
return READY;
case AudioTraits::SampleClass::PLAYING:
return PLAYING;
}
audio_cat->error() << "unknown status for sample" << endl;
return READY;
}

View File

@@ -0,0 +1,63 @@
// Filename: audio_sample.h
// Created by: cary (22Sep00)
//
////////////////////////////////////////////////////////////////////
#ifndef __AUDIO_SAMPLE_H__
#define __AUDIO_SAMPLE_H__
#include "audio_trait.h"
#include "typedReferenceCount.h"
#include "namable.h"
class AudioPool;
class AudioManager;
class EXPCL_PANDA AudioSample : public TypedReferenceCount, public Namable {
private:
AudioTraits::SampleClass *_sample;
AudioTraits::PlayerClass *_player;
AudioTraits::DeleteSampleFunc *_destroy;
protected:
INLINE AudioSample(AudioTraits::SampleClass*, AudioTraits::PlayerClass*,
AudioTraits::DeleteSampleFunc*, const string&);
INLINE AudioSample(const AudioSample&);
INLINE AudioSample& operator=(const AudioSample&);
INLINE AudioTraits::PlayerClass* get_player(void);
INLINE AudioTraits::SampleClass* get_sample(void);
friend class AudioPool;
friend class AudioManager;
public:
virtual ~AudioSample(void);
INLINE bool operator==(const AudioSample&) const;
enum SampleStatus { READY, PLAYING } ;
float length(void);
SampleStatus status(void);
public:
// type stuff
static TypeHandle get_class_type(void) {
return _type_handle;
}
static void init_type(void) {
TypedReferenceCount::init_type();
register_type(_type_handle, "AudioSample",
TypedReferenceCount::get_class_type());
}
virtual TypeHandle get_type(void) const {
return get_class_type();
}
virtual TypeHandle force_init_type(void) {
init_type();
return get_class_type();
}
private:
static TypeHandle _type_handle;
};
#include "audio_sample.I"
#endif /* __AUDIO_SAMPLE_H__ */

View File

@@ -0,0 +1,48 @@
// Filename: audio_trait.cxx
// Created by: cary (23Sep00)
//
////////////////////////////////////////////////////////////////////
#include "audio_trait.h"
#include "config_audio.h"
AudioTraits::SampleClass::~SampleClass(void) {
}
float AudioTraits::SampleClass::length(void) {
audio_cat->error() << "In abstract SampleClass::length!" << endl;
return 0.;
}
AudioTraits::SampleClass::SampleStatus AudioTraits::SampleClass::status(void) {
audio_cat->error() << "In abstract SampleClass::status!" << endl;
return READY;
}
AudioTraits::MusicClass::~MusicClass(void) {
}
AudioTraits::MusicClass::MusicStatus AudioTraits::MusicClass::status(void) {
audio_cat->error() << "In abstract MusicClass::status!" << endl;
return READY;
}
AudioTraits::PlayerClass::~PlayerClass(void) {
}
void AudioTraits::PlayerClass::play_sample(AudioTraits::SampleClass*) {
audio_cat->error() << "In abstract PlayerClass::play_sample!" << endl;
}
void AudioTraits::PlayerClass::play_music(AudioTraits::MusicClass*) {
audio_cat->error() << "In abstract PlayerClass::play_music!" << endl;
}
void AudioTraits::PlayerClass::set_volume(AudioTraits::SampleClass*, int) {
audio_cat->error() << "In abstract PlayerClass::set_volume (sample)!"
<< endl;
}
void AudioTraits::PlayerClass::set_volume(AudioTraits::MusicClass*, int) {
audio_cat->error() << "In abstract PlayerClass::set_volume (music)!" << endl;
}

View File

@@ -0,0 +1,49 @@
// Filename: audio_trait.h
// Created by: frang (06Jul00)
//
////////////////////////////////////////////////////////////////////
#ifndef __AUDIO_TRAIT_H__
#define __AUDIO_TRAIT_H__
#include <pandabase.h>
class EXPCL_PANDA AudioTraits {
public:
class SampleClass;
class MusicClass;
typedef void DeleteSampleFunc(SampleClass*);
typedef void DeleteMusicFunc(MusicClass*);
class EXPCL_PANDA SampleClass {
public:
SampleClass(void) {}
virtual ~SampleClass(void);
enum SampleStatus { READY, PLAYING } ;
virtual float length(void) = 0;
virtual SampleStatus status(void) = 0;
};
class EXPCL_PANDA MusicClass {
public:
MusicClass(void) {}
virtual ~MusicClass(void);
enum MusicStatus { READY, PLAYING };
virtual MusicStatus status(void) = 0;
};
class EXPCL_PANDA PlayerClass {
public:
PlayerClass(void) {}
virtual ~PlayerClass(void);
virtual void play_sample(SampleClass*) = 0;
virtual void play_music(MusicClass*) = 0;
virtual void set_volume(SampleClass*, int) = 0;
virtual void set_volume(MusicClass*, int) = 0;
};
};
#endif /* __AUDIO_TRAIT_H__ */

View File

@@ -0,0 +1,28 @@
// Filename: audio_win_traits.I
// Created by: cary (27Sep00)
//
////////////////////////////////////////////////////////////////////
INLINE WinSample::WinSample(void) : _channel(NULL), _data(NULL), _len(0) {
}
INLINE LPDIRECTSOUNDBUFFER WinSample::get_channel(void) {
return _channel;
}
INLINE WinMusic::WinMusic(void) : _performance(NULL), _music(NULL),
_buffer(NULL), _synth(NULL), _data(NULL),
_len(0) {
init();
}
INLINE IDirectMusicPerformance* WinMusic::get_performance(void) {
return _performance;
}
INLINE IDirectMusicSegment* WinMusic::get_music(void) {
return _music;
}
INLINE WinPlayer::WinPlayer(void) {
}

View File

@@ -0,0 +1,660 @@
// Filename: audio_win_traits.cxx
// Created by: cary (27Sep00)
//
////////////////////////////////////////////////////////////////////
#include "audio_win_traits.h"
#include "audio_manager.h"
#include "config_audio.h"
#include <direct.h>
static bool have_initialized = false;
static HWND global_hwnd;
// these are used by the direct sound playing stuff
static LPDIRECTSOUNDBUFFER soundPrimaryBuffer = NULL;
static LPDIRECTSOUND soundDirectSound = NULL;
// these are used by the direct music playing stuff
static IDirectMusic* musicDirectMusic = NULL;
static IDirectSound* musicDirectSound = NULL;
#define CHECK_RESULT(_result, _msg) \
if (FAILED(_result)) { \
audio_cat->error() << _msg << " at " << __FILE__ << ":" << __LINE__ \
<< endl; \
return; \
}
// #define MULTI_TO_WIDE(_in, _out) MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, _in, -1, _out, DMUS_MAX_FILENAME)
#define MULTI_TO_WIDE(x,y) MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, y, -1, x, _MAX_PATH);
static void update_win(void) {
}
static void initialize(void) {
if (have_initialized)
return;
if (audio_cat->is_debug())
audio_cat->debug() << "in winAudio initialize" << endl;
// rumor has it this will work, if it doesn't we need to create an invisible
// application window for this kind of thing
global_hwnd = GetDesktopWindow();
// initialize COM
HRESULT result = CoInitialize(NULL);
CHECK_RESULT(result, "CoInitialize failed");
//
// initialize the globals for the direct sound drivers
//
// create a direct sound object
result = DirectSoundCreate(NULL, &soundDirectSound, NULL);
CHECK_RESULT(result, "could not create a Direct Sound (tm) object (c)");
// set the cooperative level
result = soundDirectSound->SetCooperativeLevel(global_hwnd, DSSCL_PRIORITY);
if (FAILED(result)) {
audio_cat->warning() << "could not set Direct Sound co-op level to "
<< "DSSCL_PRIORITY, trying DSSCL_NORMAL" << endl;
result = soundDirectSound->SetCooperativeLevel(global_hwnd, DSSCL_NORMAL);
CHECK_RESULT(result, "failed setting to DSSCL_NORMAL");
}
// Move any unused portions of onboard sound memory to a contiguous block
// so that the largest portion of free memory will be available.
soundDirectSound->Compact();
// create the primary buffer
DSBUFFERDESC dsbd;
ZeroMemory(&dsbd, sizeof(DSBUFFERDESC));
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
result = soundDirectSound->CreateSoundBuffer(&dsbd, &soundPrimaryBuffer,
NULL);
CHECK_RESULT(result, "could not create primary buffer");
// set primary buffer format to 22kHz and 16-bit output
// COME BACK LATER TO MAKE THIS CONFIG
WAVEFORMATEX wfx;
ZeroMemory(&wfx, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = 22050;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
result = soundPrimaryBuffer->SetFormat(&wfx);
// SetFormat requires at least DSSCL_PRIORITY, which we may not have
if (result == DSERR_PRIOLEVELNEEDED)
audio_cat->warning() << "could not set format of Primary Buffer because "
<< "we didn't get DSSCL_PRIORITY" << endl;
/*
//
// initialize the globals for the direct music drivers
//
// create the direct sound object
result = DirectSoundCreate(NULL, &musicDirectSound, NULL);
CHECK_RESULT(result,
"could not create a second Direct Sound (tm) object (c)");
// set the cooperative level
result = musicDirectSound->SetCooperativeLevel(global_hwnd, DSSCL_PRIORITY);
if (FAILED(result)) {
audio_cat->warning() << "could not set Direct Sound (2) co-op level to "
<< "DSSCL_PRIORITY, trying DSSCL_NORMAL" << endl;
result = musicDirectSound->SetCooperativeLevel(global_hwnd, DSSCL_NORMAL);
CHECK_RESULT(result, "failed setting to DSSCL_NORMAL");
}
// create the direct music object
result = CoCreateInstance(CLSID_DirectMusic, NULL, CLSCTX_INPROC,
IID_IDirectMusic, (void**)&musicDirectMusic);
CHECK_RESULT(result, "could not create Direct Music (tm) object (c)");
// set direct sound for direct music
result = musicDirectMusic->SetDirectSound(musicDirectSound, NULL);
CHECK_RESULT(result, "could not add Direct Sound (tm) to Direct Music (tm)");
*/
//
// finish out with our stuff
//
AudioManager::set_update_func(update_win);
have_initialized = true;
}
static void shutdown(void) {
// release the primary sound buffer
if (soundPrimaryBuffer) {
soundPrimaryBuffer->Release();
soundPrimaryBuffer = NULL;
}
// release direct sound object
if (soundDirectSound) {
soundDirectSound->Release();
soundDirectSound = NULL;
}
// release direct music object
if (musicDirectMusic) {
musicDirectMusic->Release();
musicDirectMusic = NULL;
}
if (musicDirectSound) {
musicDirectSound->Release();
musicDirectSound = NULL;
}
// shutdown COM
CoUninitialize();
}
WinSample::~WinSample(void) {
// unload any data we have
if (_channel) {
_channel->Release();
_channel = NULL;
}
// we may or may not be leaking the _data
}
float WinSample::length(void) {
// DO THIS
return 0.;
}
AudioTraits::SampleClass::SampleStatus WinSample::status(void) {
if (_channel) {
DWORD dwStatus;
_channel->GetStatus(&dwStatus);
if (dwStatus & DSBSTATUS_PLAYING)
return AudioTraits::SampleClass::PLAYING;
}
return AudioTraits::SampleClass::READY;
}
BYTE* WinSample::lock(void) {
HRESULT result = _channel->Lock(0, 0, (void**)&_data, &_len, NULL, 0,
DSBLOCK_ENTIREBUFFER);
if (FAILED(result)) {
audio_cat->error() << "failed to lock buffer" << endl;
return NULL;
}
return _data;
}
void WinSample::unlock(void) {
HRESULT result = _channel->Unlock(_data, _len, NULL, 0);
CHECK_RESULT(result, "failed to unlock buffer");
}
// these are used by the wav loader
WAVEFORMATEX* pwfx;
HMMIO hmmioIn;
MMCKINFO ckIn;
MMCKINFO ckInRiff;
HRESULT readMMIO(HMMIO hmmio, MMCKINFO* pckInRIFF, WAVEFORMATEX** ppwfxInfo) {
MMCKINFO ckin;
PCMWAVEFORMAT pcmWaveFormat;
*ppwfxInfo = NULL;
if (mmioDescend(hmmio, pckInRIFF, NULL, 0) != 0)
return E_FAIL;
if ((pckInRIFF->ckid != FOURCC_RIFF) ||
(mmioFOURCC('W', 'A', 'V', 'E') != pckInRIFF->fccType))
return E_FAIL;
ckin.ckid = mmioFOURCC('f', 'm', 't', ' ');
if (mmioDescend(hmmio, &ckin, pckInRIFF, MMIO_FINDCHUNK) != 0)
return E_FAIL;
if (ckin.cksize < (LONG)sizeof(PCMWAVEFORMAT))
return E_FAIL;
if (mmioRead(hmmio, (HPSTR)&pcmWaveFormat, sizeof(pcmWaveFormat)) !=
sizeof(pcmWaveFormat))
return E_FAIL;
if (pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM) {
if ((*ppwfxInfo = new WAVEFORMATEX) == NULL)
return E_FAIL;
memcpy(*ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat));
(*ppwfxInfo)->cbSize = 0;
} else {
WORD cbExtraBytes = 0L;
if (mmioRead(hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD))
return E_FAIL;
*ppwfxInfo = (WAVEFORMATEX*)new CHAR[sizeof(WAVEFORMATEX)+cbExtraBytes];
if (*ppwfxInfo == NULL)
return E_FAIL;
memcpy(*ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat));
(*ppwfxInfo)->cbSize = cbExtraBytes;
if (mmioRead(hmmio, (CHAR*)(((BYTE*)&((*ppwfxInfo)->cbSize))+sizeof(WORD)),
cbExtraBytes) != cbExtraBytes) {
delete *ppwfxInfo;
*ppwfxInfo = NULL;
return E_FAIL;
}
}
if (mmioAscend(hmmio, &ckin, 0) != 0) {
delete *ppwfxInfo;
*ppwfxInfo = NULL;
return E_FAIL;
}
return S_OK;
}
HRESULT wave_open_file(const CHAR* strFileName, HMMIO* phmmioIn,
WAVEFORMATEX** ppwfxInfo, MMCKINFO* pckInRIFF) {
HMMIO hmmio = NULL;
if ((hmmio = mmioOpen(const_cast<CHAR*>(strFileName), NULL,
MMIO_ALLOCBUF | MMIO_READ)) == NULL)
return E_FAIL;
HRESULT hr;
if (FAILED(hr = readMMIO(hmmio, pckInRIFF, ppwfxInfo))) {
mmioClose(hmmio, 0);
return hr;
}
*phmmioIn = hmmio;
return S_OK;
}
HRESULT wave_start_data_read(HMMIO* phmmioIn, MMCKINFO* pckIn,
MMCKINFO* pckInRIFF) {
// seek to the data
if (mmioSeek(*phmmioIn, pckInRIFF->dwDataOffset + sizeof(FOURCC),
SEEK_SET) == -1)
return E_FAIL;
//search the input file for the 'data' chunk
pckIn->ckid = mmioFOURCC('d', 'a', 't', 'a');
if (mmioDescend(*phmmioIn, pckIn, pckInRIFF, MMIO_FINDCHUNK) != 0)
return E_FAIL;
return S_OK;
}
HRESULT wave_read_file(HMMIO hmmio, UINT cbRead, BYTE* pbDest, MMCKINFO* pckIn,
UINT* cbActualRead) {
MMIOINFO mmioinfoIn;
*cbActualRead = 0;
if (mmioGetInfo(hmmio, &mmioinfoIn, 0) != 0)
return E_FAIL;
UINT cbDataIn = cbRead;
if (cbDataIn > pckIn->cksize)
cbDataIn = pckIn->cksize;
for (DWORD cT=0; cT<cbDataIn; ++cT) {
// copy bytes from the io to the buffer
if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) {
if (mmioAdvance(hmmio, &mmioinfoIn, MMIO_READ) != 0)
return E_FAIL;
if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead)
return E_FAIL;
}
// actual copy
*((BYTE*)pbDest+cT) = *((BYTE*)mmioinfoIn.pchNext);
mmioinfoIn.pchNext++;
}
if (mmioSetInfo(hmmio, &mmioinfoIn, 0) != 0)
return E_FAIL;
*cbActualRead = cbDataIn;
return S_OK;
}
HRESULT wave_load_internal(const CHAR* filename, WAVEFORMATEX& wavInfo,
BYTE*& wavData, UINT& wavSize) {
wavData = NULL;
wavSize = 0;
HRESULT result = wave_open_file(filename, &hmmioIn, &pwfx, &ckInRiff);
if (FAILED(result))
return result;
result = wave_start_data_read(&hmmioIn, &ckIn, &ckInRiff);
if (SUCCEEDED(result)) {
memcpy(&wavInfo, pwfx, sizeof(WAVEFORMATEX));
DWORD size = ckIn.cksize + ckIn.dwDataOffset;
wavData = new BYTE[size];
result = wave_read_file(hmmioIn, size, wavData, &ckIn, &wavSize);
}
mmioClose(hmmioIn, 0);
return result;
}
HRESULT wave_load(const CHAR* filename, WAVEFORMATEX& wavInfo, BYTE*& wavData,
UINT& wavSize) {
pwfx = NULL;
HRESULT result = wave_load_internal(filename, wavInfo, wavData, wavSize);
if (pwfx) {
delete pwfx;
pwfx = NULL;
}
return result;
}
WinSample* WinSample::load_wav(Filename filename) {
WinSample* ret = (WinSample*)0L;
initialize();
WAVEFORMATEX wavInfo;
UINT wavSize = 0;
BYTE* wavData = NULL;
HRESULT result = wave_load(filename.c_str(), wavInfo, wavData, wavSize);
if (FAILED(result)) {
if (wavData)
delete [] wavData;
return ret;
}
// create direct sound channel
ret = new WinSample();
DSBUFFERDESC dsbdDesc;
ZeroMemory(&dsbdDesc, sizeof(DSBUFFERDESC));
dsbdDesc.dwSize = sizeof(DSBUFFERDESC);
/*
dsbdDesc.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC |
DSBCAPS_GLOBALFOCUS;
*/
dsbdDesc.dwFlags = DSBCAPS_STATIC |
DSBCAPS_GLOBALFOCUS;
dsbdDesc.dwBufferBytes = wavSize;
dsbdDesc.lpwfxFormat = &wavInfo;
dsbdDesc.lpwfxFormat->cbSize = sizeof(wavInfo);
result = soundDirectSound->CreateSoundBuffer(&dsbdDesc, &(ret->_channel), NULL);
if (FAILED(result)) {
delete ret;
ret = (WinSample*)0L;
}
if (ret) {
BYTE* dst = NULL;
dst = ret->lock();
try {
memcpy(dst, wavData, wavSize);
}
catch(...) {
delete ret;
ret = (WinSample*)0L;
}
if (ret)
ret->unlock();
}
if (wavData)
delete [] wavData;
return ret;
}
void WinSample::destroy(AudioTraits::SampleClass* sample) {
delete sample;
}
WinMusic::~WinMusic(void) {
// AudioManager::stop(this);
if (audio_cat->is_debug())
audio_cat->debug() << "in WinMusic::~WinMusic()" << endl;
if (_music) {
_music->Release();
_music = NULL;
}
if (_synth) {
_synth->Release();
_synth = NULL;
}
if (_performance) {
_performance->Release();
_performance = NULL;
}
if (_buffer) {
_buffer->Release();
_buffer = NULL;
}
if (audio_cat->is_debug())
audio_cat->debug() << "out of WinMusic::~WinMusic()" << endl;
}
void WinMusic::init(void) {
if (audio_cat->is_debug())
audio_cat->debug() << "in WinMusic::init()" << endl;
initialize();
// create the direct sound performance object
HRESULT result = CoCreateInstance(CLSID_DirectMusicPerformance, NULL,
CLSCTX_INPROC,
IID_IDirectMusicPerformance2,
(void**)&_performance);
if (FAILED(result)) {
audio_cat->error() << "could not create performance object" << endl;
_performance = NULL;
return;
}
// initialize performance object
// result = _performance->Init(&musicDirectMusic, NULL, NULL);
result = _performance->Init(NULL, NULL, NULL);
CHECK_RESULT(result, "could not initialize performance object");
/*
// create the output synth object
DMUS_PORTPARAMS params;
ZeroMemory(&params, sizeof(DMUS_PORTPARAMS));
params.dwSize = sizeof(DMUS_PORTPARAMS);
result = musicDirectMusic->CreatePort(GUID_NULL, &params, &_synth, NULL);
CHECK_RESULT(result, "could not create synth");
// create sound buffer
WAVEFORMATEX format;
DWORD formatExSize;
DWORD bufferSize;
ZeroMemory(&format, sizeof(WAVEFORMATEX));
formatExSize = format.cbSize = sizeof(WAVEFORMATEX);
result = _synth->GetFormat(&format, &formatExSize, &bufferSize);
CHECK_RESULT(result, "failed to get format from synth");
DSBUFFERDESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(DSBUFFERDESC));
bufferDesc.dwSize = sizeof(DSBUFFERDESC);
*
bufferDesc.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_STICKYFOCUS;
*
bufferDesc.dwFlags = DSBCAPS_STICKYFOCUS;
bufferDesc.dwBufferBytes = bufferSize;
bufferDesc.lpwfxFormat = &format;
bufferDesc.lpwfxFormat->cbSize = sizeof(WAVEFORMATEX);
result = musicDirectSound->CreateSoundBuffer(&bufferDesc, &_buffer, NULL);
CHECK_RESULT(result, "could not create buffer for music");
// initialize synth
result = _synth->SetDirectSound(musicDirectSound, _buffer);
CHECK_RESULT(result, "failed to initialize synth");
// activate synth
result = _synth->Activate(TRUE);
CHECK_RESULT(result, "failed to activate synth");
*/
// add the synth to the performance
// result = _performance->AddPort(_synth);
result = _performance->AddPort(NULL);
CHECK_RESULT(result, "failed to add synth to performance");
/*
// allocate performance channels
result = _performance->AssignPChannelBlock(0, _synth, 1);
CHECK_RESULT(result, "failed to assign performance channels");
*/
if (audio_cat->is_debug())
audio_cat->debug() << "out of WinMusic::init() _performance = "
<< (void*)_performance << " _synth = "
<< (void*)_synth << " _buffer = " << (void*)_buffer
<< endl;
}
AudioTraits::MusicClass::MusicStatus WinMusic::status(void) {
if (audio_cat->is_debug())
audio_cat->debug() << "in WinMusic::status()" << endl;
if (_performance && _music) {
if (_performance->IsPlaying(_music, NULL) == S_OK) {
if (audio_cat->is_debug())
audio_cat->debug() << "returning PLAYING" << endl;
return PLAYING;
}
} else
if (audio_cat->is_debug())
audio_cat->debug() << "MusicStatus no performance or music!" << endl;
if (audio_cat->is_debug())
audio_cat->debug() << "returning READY" << endl;
return READY;
}
WinMusic* WinMusic::load_midi(Filename filename) {
if (audio_cat->is_debug())
audio_cat->debug() << "in WinMusic::load_midi()" << endl;
initialize();
// WinMusic* ret = (WinMusic*)0L;
WinMusic* ret = new WinMusic();
if (ret->_performance && ret->_music) {
if (audio_cat->is_debug())
audio_cat->debug() << "for some reason, have to stop" << endl;
ret->_performance->Stop(NULL, NULL, 0, 0);
}
ret->_music = NULL;
IDirectMusicLoader* loader;
HRESULT result = CoCreateInstance(CLSID_DirectMusicLoader, NULL,
CLSCTX_INPROC, IID_IDirectMusicLoader,
(void**)&loader);
if (FAILED(result)) {
audio_cat->error() << "could not create music loader" << endl;
delete ret;
ret = (WinMusic*)0L;
return ret;
}
char szDir[_MAX_PATH];
WCHAR wszDir[_MAX_PATH];
if (_getcwd(szDir, _MAX_PATH)==NULL) {
audio_cat->error() << "could not getcwd" << endl;
delete ret;
ret = (WinMusic*)0L;
return ret;
}
MULTI_TO_WIDE(wszDir, szDir);
result = loader->SetSearchDirectory(GUID_DirectMusicAllTypes, wszDir, FALSE);
if (FAILED(result)) {
audio_cat->error() << "could not set search directory" << endl;
delete ret;
ret = (WinMusic*)0L;
return ret;
}
DMUS_OBJECTDESC fdesc;
fdesc.guidClass = CLSID_DirectMusicSegment;
fdesc.dwSize = sizeof(DMUS_OBJECTDESC);
// MULTI_TO_WIDE(filename.c_str(), fdesc.wszFileName);
MULTI_TO_WIDE(fdesc.wszFileName, filename.c_str());
// fdesc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;
fdesc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
result = loader->GetObject(&fdesc, IID_IDirectMusicSegment2,
(void**)&(ret->_music));
if (FAILED(result)) {
audio_cat->error() << "failed to load file" << endl;
loader->Release();
delete ret;
ret = (WinMusic*)0L;
return ret;
}
ret->_music->SetParam(GUID_StandardMIDIFile, -1, 0, 0,
(void*)(ret->_performance));
ret->_music->SetParam(GUID_Download, -1, 0, 0, (void*)(ret->_performance));
// ret->_buffer->SetVolume(0);
// ret->_buffer->SetPan(0);
if (audio_cat->is_debug())
audio_cat->debug() << "out of WinMusic::load_midi() _music = "
<< (void*)ret->_music << endl;
return ret;
}
void WinMusic::destroy(AudioTraits::MusicClass* music) {
if (audio_cat->is_debug())
audio_cat->debug() << "in WinMusic::destroy()" << endl;
delete music;
if (audio_cat->is_debug())
audio_cat->debug() << "out of WinMusic::destroy()" << endl;
}
WinPlayer* WinPlayer::_global_instance = (WinPlayer*)0L;
WinPlayer::~WinPlayer(void) {
}
void WinPlayer::play_sample(AudioTraits::SampleClass* sample) {
initialize();
WinSample* wsample = (WinSample*)sample;
LPDIRECTSOUNDBUFFER chan = wsample->get_channel();
if (chan) {
chan->Stop();
HRESULT result = chan->Play(0, 0, 0);
if (FAILED(result))
audio_cat->error() << "sample play failed" << endl;
}
}
void WinPlayer::play_music(AudioTraits::MusicClass* music) {
if (audio_cat->is_debug())
audio_cat->debug() << "in WinPlayer::play_music()" << endl;
initialize();
WinMusic* wmusic = (WinMusic*)music;
IDirectMusicPerformance* _perf = wmusic->get_performance();
IDirectMusicSegment* _msc = wmusic->get_music();
if (audio_cat->is_debug())
audio_cat->debug() << "about to jump in: _perf = " << (void*)_perf
<< " _msc = " << (void*)_msc << endl;
if (_perf && _msc) {
if (audio_cat->is_debug())
audio_cat->debug() << "made it inside" << endl;
// _msc->SetRepeats(0);
IDirectMusicSegmentState* segState;
// HRESULT result = _perf->PlaySegment(_msc, 0, 0, NULL);
HRESULT result = _perf->PlaySegment(_msc, 0, 0, &segState);
if (result != S_OK) {
audio_cat->error() << "music play failed" << endl;
switch (result) {
case E_OUTOFMEMORY: audio_cat->error() << "reports out of memory" << endl;
break;
case E_POINTER: audio_cat->error() << "reports invalid pointer" << endl;
break;
case DMUS_E_NO_MASTER_CLOCK: audio_cat->error() << "reports no master clock" << endl;
break;
case DMUS_E_SEGMENT_INIT_FAILED: audio_cat->error() << "reports segment init failed" << endl;
break;
case DMUS_E_TIME_PAST: audio_cat->error() << "reports time past" << endl;
break;
};
}
}
if (audio_cat->is_debug())
audio_cat->debug() << "out of WinPlayer::play_music()" << endl;
}
void WinPlayer::set_volume(AudioTraits::SampleClass*, int) {
}
void WinPlayer::set_volume(AudioTraits::MusicClass*, int) {
}
WinPlayer* WinPlayer::get_instance(void) {
if (_global_instance == (WinPlayer*)0L)
_global_instance = new WinPlayer();
return _global_instance;
}

View File

@@ -0,0 +1,78 @@
// Filename: audio_win_traits.h
// Created by: cary (27Sep00)
//
////////////////////////////////////////////////////////////////////
#ifndef __AUDIO_WIN_TRAITS_H__
#define __AUDIO_WIN_TRAITS_H__
#include "audio_trait.h"
#include <filename.h>
#include <windows.h>
#include <dsound.h>
#include <dmusici.h>
class EXPCL_PANDA WinSample : public AudioTraits::SampleClass {
private:
LPDIRECTSOUNDBUFFER _channel;
BYTE* _data;
DWORD _len;
public:
INLINE WinSample(void);
virtual ~WinSample(void);
virtual float length(void);
virtual AudioTraits::SampleClass::SampleStatus status(void);
public:
// these are used by the laoders
BYTE* lock(void);
void unlock(void);
static WinSample* load_wav(Filename);
static void destroy(AudioTraits::SampleClass*);
// these are used by the player
INLINE LPDIRECTSOUNDBUFFER get_channel(void);
};
class EXPCL_PANDA WinMusic : public AudioTraits::MusicClass {
private:
IDirectMusicPerformance* _performance;
IDirectMusicSegment* _music;
IDirectSoundBuffer* _buffer;
IDirectMusicPort* _synth;
BYTE* _data;
DWORD _len;
void init(void);
public:
INLINE WinMusic(void);
virtual ~WinMusic(void);
virtual AudioTraits::MusicClass::MusicStatus status(void);
// these are used by the loaders
static WinMusic* load_midi(Filename);
static void destroy(AudioTraits::MusicClass*);
// these are used by the players
INLINE IDirectMusicPerformance* get_performance(void);
INLINE IDirectMusicSegment* get_music(void);
};
class EXPCL_PANDA WinPlayer : public AudioTraits::PlayerClass {
public:
INLINE WinPlayer(void);
virtual ~WinPlayer(void);
virtual void play_sample(AudioTraits::SampleClass*);
virtual void play_music(AudioTraits::MusicClass*);
virtual void set_volume(AudioTraits::SampleClass*, int);
virtual void set_volume(AudioTraits::MusicClass*, int);
public:
// used by the readers
static WinPlayer* get_instance(void);
private:
static WinPlayer* _global_instance;
};
#include "audio_win_traits.I"
#endif /* __AUDIO_WIN_TRAITS_H__ */

View File

@@ -0,0 +1,41 @@
// Filename: config_audio.cxx
// Created by: cary (22Sep00)
//
////////////////////////////////////////////////////////////////////
#include "config_audio.h"
#include "audio_sample.h"
#include "audio_music.h"
#include <dconfig.h>
Configure(config_audio);
NotifyCategoryDef(audio, "");
int audio_sample_voices = config_audio.GetInt("audio-sample-voices", 8);
int audio_mix_freq = config_audio.GetInt("audio-mix-freq", 11025);
string* audio_mode_flags;
int audio_driver_select = config_audio.GetInt("audio-driver-select", 0);
string* audio_driver_params;
ConfigureFn(config_audio) {
AudioSample::init_type();
AudioMusic::init_type();
Config::ConfigTable::Symbol mode;
config_audio.GetAll("audio-mode-flag", mode);
Config::ConfigTable::Symbol::iterator i;
audio_mode_flags = new string;
for (i=mode.begin(); i!=mode.end(); ++i) {
if (!audio_mode_flags->empty())
*audio_mode_flags += " ";
*audio_mode_flags += (*i).Val();
}
Config::ConfigTable::Symbol parms;
config_audio.GetAll("audio-driver-param", parms);
audio_driver_params = new string;
for (i=parms.begin(); i!=parms.end(); ++i) {
if (!audio_driver_params->empty())
*audio_driver_params += " ";
*audio_driver_params += (*i).Val();
}
}

View File

@@ -0,0 +1,20 @@
// Filename: config_audio.h
// Created by: cary (22Sep00)
//
////////////////////////////////////////////////////////////////////
#ifndef __CONFIG_AUDIO_H__
#define __CONFIG_AUDIO_H__
#include <pandabase.h>
#include <notifyCategoryProxy.h>
NotifyCategoryDecl(audio, EXPCL_PANDA, EXPTP_PANDA);
extern int audio_sample_voices;
extern int audio_mix_freq;
extern string* audio_mode_flags;
extern int audio_driver_select;
extern string* audio_driver_params;
#endif /* __CONFIG_AUDIO_H__ */

View File

@@ -0,0 +1,41 @@
// Filename: test_audio.cxx
// Created by: cary (24Sep00)
//
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "audio.h"
#include "config_audio.h"
#include <ipc_traits.h>
int
main(int argc, char* argv[]) {
if (! AudioPool::verify_sample("test.wav")) {
audio_cat->fatal() << "could not locate 'test.wav'" << endl;
exit(-1);
}
AudioSample* sample = AudioPool::load_sample("test.wav");
audio_cat->info() << "test.wav is " << sample->length() << "sec long"
<< endl;
audio_cat->info() << "Playing test.wav" << endl;
AudioManager::play(sample);
while (sample->status() == AudioSample::PLAYING) {
AudioManager::update();
ipc_traits::sleep(0, 1000000);
}
// AudioMidi foo("test.midi");
if (! AudioPool::verify_music("test.midi")) {
audio_cat->fatal() << "could not locate 'test.midi'" << endl;
exit(-1);
}
AudioMusic* music = AudioPool::load_music("test.midi");
audio_cat->info() << "Playing test.midi" << endl;
AudioManager::play(music);
while (music->status() == AudioMusic::PLAYING) {
AudioManager::update();
ipc_traits::sleep(0, 1000000);
}
return 0;
}

View File

@@ -0,0 +1,47 @@
#define OTHER_LIBS interrogatedb dconfig dtoolutil dtoolbase
#begin lib_target
#define TARGET builder
#define LOCAL_LIBS \
linmath gobj sgraph sgattrib graph putil gsgbase mathutil pnmimage \
pandabase
#define SOURCES \
builder.I builder.cxx builder.h builderAttrib.I builderAttrib.cxx \
builderAttrib.h builderBucket.I builderBucket.cxx builderBucket.h \
builderBucketNode.I builderBucketNode.cxx builderBucketNode.h \
builderMisc.cxx builderMisc.h builderNormalVisualizer.I \
builderNormalVisualizer.cxx builderNormalVisualizer.h \
builderPrim.cxx builderPrim.h builderProperties.cxx \
builderProperties.h builderTypes.cxx builderTypes.h builderVertex.I \
builderVertex.cxx builderVertex.h config_builder.cxx \
config_builder.h mesher.cxx mesher.h pta_BuilderC.cxx \
pta_BuilderC.h pta_BuilderN.cxx pta_BuilderN.h pta_BuilderTC.cxx \
pta_BuilderTC.h pta_BuilderV.cxx pta_BuilderV.h vector_BuilderC.cxx \
vector_BuilderC.h vector_BuilderN.cxx vector_BuilderN.h \
vector_BuilderTC.cxx vector_BuilderTC.h vector_BuilderV.cxx \
vector_BuilderV.h
#define INSTALL_HEADERS \
builder.I builder.h builderAttrib.I builderAttrib.h \
builderAttribTempl.I builderAttribTempl.h builderBucket.I \
builderBucket.h builderBucketNode.I builderBucketNode.h \
builderNormalVisualizer.I builderNormalVisualizer.h builderPrim.h \
builderPrimTempl.I builderPrimTempl.h builderProperties.h \
builderTypes.h builderVertex.I builderVertex.h builderVertexTempl.I \
builderVertexTempl.h config_builder.h pta_BuilderC.h pta_BuilderN.h \
pta_BuilderTC.h pta_BuilderV.h vector_BuilderC.h vector_BuilderN.h \
vector_BuilderTC.h vector_BuilderV.h
#end lib_target
#begin test_bin_target
#define TARGET test_builder
#define LOCAL_LIBS \
builder
#define SOURCES \
test_builder.cxx test_builder_data.cxx
#end test_bin_target

View File

@@ -0,0 +1,69 @@
// Filename: builder.I
// Created by: drose (09Sep97)
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: Builder::add_prim
// Access: Public
// Description: Adds the indicated nonindexed primitive, along with
// its associated bucket, to the builder's internal
// structures. This copies all relevant information
// into the builder.
//
// Returns true if the primitive was successfully added,
// false if it was invalid for some reason (for
// instance, a polygon with two vertices).
////////////////////////////////////////////////////////////////////
INLINE bool Builder::
add_prim(const BuilderBucket &bucket,
const BuilderPrim &prim) {
add_bucket(bucket);
return ((BuilderBucketNode &)(*_bi)).add_prim(prim);
}
////////////////////////////////////////////////////////////////////
// Function: Builder::add_prim
// Access: Public
// Description: Adds the indicated indexed primitive, along with
// its associated bucket, to the builder's internal
// structures. This copies all relevant information
// into the builder.
//
// Returns true if the primitive was successfully added,
// false if it was invalid for some reason (for
// instance, a polygon with two vertices).
////////////////////////////////////////////////////////////////////
INLINE bool Builder::
add_prim(const BuilderBucket &bucket,
const BuilderPrimI &prim) {
add_bucket(bucket);
return ((BuilderBucketNode &)(*_bi)).add_prim(prim);
}
////////////////////////////////////////////////////////////////////
// Function: Builder::add_prim_nonindexed
// Access: Public
// Description: Adds the specified indexed primitive as if it were
// nonindexed. This simply looks up each coordinate
// value on the prim in its associated array and stores
// a nonindexed primitive with the actual coordinate
// values, instead of the index numbers.
//
// This is handy for having code that calls the builder
// and might want to build either indexed or nonindexed
// geometry, as selected by the user at run-time.
// Simply build indexed geometry in all cases, then call
// either add_prim or add_prim_nonindexed, according to
// the user's selection.
////////////////////////////////////////////////////////////////////
INLINE bool Builder::
add_prim_nonindexed(const BuilderBucket &bucket,
const BuilderPrimI &prim) {
add_bucket(bucket);
return ((BuilderBucketNode &)(*_bi)).add_prim_nonindexed(prim);
}

View File

@@ -0,0 +1,229 @@
// Filename: builder.cxx
// Created by: drose (09Sep97)
//
////////////////////////////////////////////////////////////////////
#include "builder.h"
#include "builderFuncs.h"
#include "builderMisc.h"
#include <notify.h>
#include <namedNode.h>
#include <geomNode.h>
#include <renderRelation.h>
#include <map>
////////////////////////////////////////////////////////////////////
// Function: Builder::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Builder::
Builder() {
_bi = _buckets.end();
}
////////////////////////////////////////////////////////////////////
// Function: Builder::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Builder::
~Builder() {
// Free all the buckets we allocated. We allocated 'em, we free
// 'em.
Buckets::iterator bi;
for (bi = _buckets.begin();
bi != _buckets.end();
++bi) {
BuilderBucket *bucket = (*bi).get_bucket();
delete bucket;
}
}
// We use the NodeMap class to build up a map of Nodes to GeomNodes.
// There may be several buckets that point to the same Node; these
// should all be given the same GeomNode, when possible.
// However, if two buckets have different sets of scene graph
// properties--that is, the _trans member is different--they must be
// given separate GeomNodes.
// Furthermore, it's possible to name each bucket. If two buckets
// with the same Node pointer have different names, then they should
// be given two different GeomNodes.
class NodeMap : public Namable {
public:
NodeMap(NamedNode *node, const BuilderBucket *bucket)
: _node(node), _bucket(bucket) { }
bool operator < (const NodeMap &other) const {
if (_node != other._node) {
return _node < other._node;
}
if (_bucket->get_name() != other._bucket->get_name()) {
return _bucket->get_name() < other._bucket->get_name();
}
return (_bucket->_trans.compare_to(other._bucket->_trans) < 0);
}
NamedNode *_node;
// Although a bucket pointer is stored here in the NodeMap class,
// you should not use it except to extract the name and/or the
// _trans member. Remember, this bucket pointer stands for any of
// possibly several bucket pointers, all different, except that they
// share the same name and _trans.
const BuilderBucket *_bucket;
};
////////////////////////////////////////////////////////////////////
// Function: Builder::build
// Access: Public
// Description: Creates Geoms for all the primitives added to all
// buckets, and adds them where appropriate to place
// them in the scene graph under their respective
// parents, and/or returns a single GeomNode that
// contains all geometry whose bucket did not reference
// a particular scene graph node to parent them to.
//
// If a bucket's _node pointer was a GeomNode, the
// geometry will be added directly to that node. If the
// _node pointer was any other kind of node, a GeomNode
// will be created and parented to that node, and its
// name will be the name of the bucket. In this case,
// the name of the bucket can also be used to different
// nodes: if two buckets reference the same node, but
// have different names, then two different GeomNodes
// are created, one with each name.
////////////////////////////////////////////////////////////////////
GeomNode *Builder::
build(const string &default_name) {
typedef map<NodeMap, GeomNode *, less<NodeMap> > GeomNodeMap;
GeomNodeMap geom_nodes;
// First, build all the Geoms and create GeomNodes for them. Each
// unique Node gets its own GeomNode. If the Node is itself a
// GeomNode, that GeomNode is used directly.
Buckets::iterator i;
for (i = _buckets.begin();
i != _buckets.end();
++i) {
BuilderBucket *bucket = (*i).get_bucket();
NamedNode *node = bucket->_node;
const string &name = bucket->get_name();
GeomNode *geom_node = NULL;
if (node!=NULL && node->is_of_type(GeomNode::get_class_type())) {
// The node is a GeomNode. In this case, we simply use that
// node. We can't separate them out by name in this case; we'll
// just assign to it the first nonempty name we encounter.
geom_node = (GeomNode *)node;
// Since the caller already created this GeomNode and passed it
// in, we'll leave it up to the caller to name the node and set
// up the state transitions leading into it.
} else {
// The node is not a GeomNode, so look it up in the map.
GeomNodeMap::iterator f = geom_nodes.find(NodeMap(node, bucket));
if (f != geom_nodes.end()) {
geom_node = (*f).second;
} else {
// No such node/name combination. Create a new one.
geom_node = bucket->make_geom_node();
if (geom_node != NULL) {
geom_nodes[NodeMap(node, bucket)] = geom_node;
}
}
}
if (geom_node != NULL) {
(*i).build(geom_node);
}
}
// Now go through and parent the geom_nodes under their respective
// group nodes. Save out the geom_node associated with a NULL Node;
// this one is returned from this function.
GeomNode *base_geom_node = NULL;
GeomNodeMap::iterator gi;
for (gi = geom_nodes.begin();
gi != geom_nodes.end();
++gi) {
const NodeMap &nm = (*gi).first;
GeomNode *geom_node = (*gi).second;
NamedNode *node = nm._node;
const string &name = nm._bucket->get_name();
const NodeTransitions &trans = nm._bucket->_trans;
// Assign the name to the geom, if it doesn't have one already.
if (!geom_node->has_name()) {
if (!name.empty()) {
geom_node->set_name(name);
} else if (!default_name.empty()) {
geom_node->set_name(default_name);
}
}
// Only reparent the geom_node if it has no parent already.
if (geom_node->_parents.empty()) {
if (geom_node->get_num_geoms() == 0) {
// If there was nothing added, never mind.
delete geom_node;
} else if (node==NULL) {
nassertr(base_geom_node == NULL, NULL);
base_geom_node = geom_node;
} else {
RenderRelation *arc = new RenderRelation(node, geom_node);
// Now, this is our only opportunity to apply the scene-graph
// state specified in the bucket to the node: we have created
// our own geom_node for these buckets, and we have parented
// it to the scene graph.
arc->copy_transitions_from(trans);
}
}
}
return base_geom_node;
}
////////////////////////////////////////////////////////////////////
// Function: Builder::add_bucket
// Access: Protected
// Description: Adds a new BuilderBucket just like the given one to
// the set of all used BuilderBuckets, and makes it the
// current bucket. Future primitives will be added to
// this bucket.
////////////////////////////////////////////////////////////////////
void Builder::
add_bucket(const BuilderBucket &bucket) {
// Optimization: maybe it's the same bucket we used last time.
if (_bi != _buckets.end() &&
(*_bi) == BuilderBucketNode((BuilderBucket *)&bucket)) {
return;
}
// Nope. Look again.
_bi = _buckets.find((BuilderBucket *)&bucket);
if (_bi == _buckets.end()) {
BuilderBucket *new_bucket = bucket.make_copy();
_bi = _buckets.insert(new_bucket).first;
}
}

198
panda/src/builder/builder.h Normal file
View File

@@ -0,0 +1,198 @@
// Filename: builder.h
// Created by: drose (09Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDER_H
#define BUILDER_H
////////////////////////////////////////////////////////////////////
//
// Builder
//
// The builder accepts as input a loose collection of polygons with
// various attributes, sizes, and shapes, and does all the work of
// grouping relating polygons and creating triangle strips, etc.,
// ultimately storing the resulting optimized geometry into one or
// more GeomNodes.
//
// It is intended that the builder should be the single entry point
// for all code wishing to create geometry in the scene graph. The
// builder can know about the kinds of geometry that are optimal for a
// particular platform, or even about the kinds of geometry that are
// available for a given platform. (For instance, perhaps on some
// bizarre platform, triangle strips do not exist, but quadstrips are
// really fast. User code should not create triangle strips
// directly.)
//
// Actually, there are two fairly separate pieces in this package.
// The first is the builder itself, which handles the interface to
// user code, and is responsible for collecting polygons from the
// caller, sorting them according to their attributes, and creating
// Geoms that represent the resulting geometry. The second piece is
// the mesher, which receives geometry from the builder and tries to
// create optimal triangle strips (or whichever kind of higher-level
// structure is most appropriate) from them, which it hands back to
// the builder.
//
// It is possible to use the builder without invoking the mesher, in
// which case the builder will create Geoms with the individual prims
// exactly as the user passed them in. It is not possible to use the
// mesher without first going through the builder.
//
//
// The general system of using the builder is as follows:
//
// (a) Create a Builder object.
//
// (b) Iterate through the polygons. For each polygon:
//
// (c) Create a BuilderBucket object and assign to it the
// scene-graph level attributes, such as texture, lighting,
// etc. for your polygon. If several polygons share the same
// attributes, they can of course use the same bucket. But
// there's no reason to be afraid of creating a new bucket
// object each time, if that's more convenient.
//
// (d) Create a BuilderPrim object to describe the polygon. If
// the polygon is to have a polygon color or polygon normal,
// set these on the BuilderPrim.
//
// (e) Iterate through the polygon vertices, in counterclockwise
// order when viewed from the front of the polygon. For each
// vertex:
//
// (f) Create a BuilderVertex object. If the vertex has a
// texture coordinate, normal, or color, set this on the
// BuilderVertex.
//
// (g) Add the BuilderVertex to the BuilderPrim.
//
// (h) Add the BuilderPrim to the Builder.
//
// (i) Call Builder::build() and receive your new geometry!
//
// All of these objects--BuilderBucket, BuilderPrim, and
// BuilderVertex--can, and probably should, be ordinary local
// variables. When they are added into their respective data
// structures they are copied, not referenced, so there's no need to
// try to keep them around after that.
//
// The BuilderBucket is the builder's system for grouping polygons
// that share similar characteristings. Polygons that were added to
// the builder with equivalent (though not necessarily identical)
// buckets may be candidates for joining together into triangle strips
// when possible.
//
//
// That's the basic operation. There are lots of fancy features on
// top of that.
//
// * Other kinds of geometry than polygons are supported. Presently,
// these are light points and line segments. To add these kinds of
// geometry, call set_type() on your BuilderPrim with either
// BPT_point or BPT_line.
//
// * Indexed geometry is supported as well as nonindexed. Indexed
// geometry means that the vertices, UV's, etc. are referenced
// indirectly; an index number into a table is stored instead of
// the actual coordinate values. Indexed geometry may be freely
// mixed in with nonindexed geometry; the builder will sort them
// out (although each polygon must be either entirely indexed or
// entirely nonindexed). To create indexed geometry, use a
// BuilderPrimI object, and assign to it a number of BuilderVertexI
// vertices. The coordinate values you will assign are ushort
// array index numbers. Store the array pointers these refer to in
// the BuilderBucket, via set_coords(), set_normals(), etc.
//
// * The builder is to a certain extent scene-graph aware. In the
// normal usage, you give it a bunch of polygons which are all
// lumped together, and when you call build() it allocates and
// returns a GeomNode which has all of your geometry in it.
// However, you can also ask it to distribute the geometry
// throughout a pre-existing scene graph. To do this, assign the
// _node pointer of your BuilderBucket to point to the node each
// polygon belongs under, as you create the polygons. Now when you
// call build(), the builder will create all the polygons under the
// nodes you indicated, creating new GeomNodes whenever necessary.
// The advantage to this method is that you don't have to process
// your polygons in scene-graph order; the builder can sort them
// out for you. Another advantage is it allows the builder to set
// up the state for you, see the next point:
//
// * It is only when you are taking advantage of the scene-graph
// awareness of the builder that the builder can assign the state
// transitions (like texturing, etc.) you specify to the geometry
// it builds. This is because the state transitions are stored on
// the arcs of the scene graph, and in non-scene graph mode there
// are no arcs!
//
// * You can fine-tune the mesher behavior via a number of parameters
// on the BuilderBucket. Look in builderProperties.h for these
// parameters (BuilderBucket inherits from BuilderProperties).
// This is also where you turn the mesher off if you don't want it.
//
// * You can set global properties on all buckets easily either by
// creating your own default BuilderBucket that you use to
// initialize each individual BuilderBucket you create, or by
// changing the parameters stored in the bucket pointed to by
// BuilderBucket::get_default_bucket(), which is what is used to
// initialize any BuilderBucket created with a default constructor.
// It is suggested that the get_default_bucket() pointer be used to
// define global defaults at applications start-up, while a local
// default BuilderBucket should be used for local defaults.
//
// * You can also control the binning behavior, if you have some
// particular user-specific parameters you want your geometry to be
// grouped on. To do this, subclass from BuilderBucket and
// redefine the comparison operator (it's a virtual function), as
// well as the make_copy() function.
//
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "builderAttrib.h"
#include "builderBucketNode.h"
#include <pointerTo.h>
#include <set>
class GeomNode;
///////////////////////////////////////////////////////////////////
// Class : Builder
// Description : The main driver class to the builder package. See
// the comments above.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG Builder {
public:
Builder();
~Builder();
INLINE bool add_prim(const BuilderBucket &bucket,
const BuilderPrim &prim);
INLINE bool add_prim(const BuilderBucket &bucket,
const BuilderPrimI &prim);
INLINE bool add_prim_nonindexed(const BuilderBucket &bucket,
const BuilderPrimI &prim);
GeomNode *build(const string &default_name = "");
protected:
void add_bucket(const BuilderBucket &bucket);
typedef set<BuilderBucketNode, less<BuilderBucketNode> > Buckets;
Buckets _buckets;
Buckets::iterator _bi;
};
#include "builder.I"
#endif

View File

@@ -0,0 +1,69 @@
// Filename: builderAttrib.I
// Created by: drose (22Jan99)
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BuilderAttrib::set_normal_value
// Access: Public
// Description: Reassigns the normal, without knowing whether the
// attribute is indexed or nonindexed. A nonindexed
// attribute will look up the index in the array and
// store the resulting value, while an indexed attribute
// will just store the index number (which assumes the
// array is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderAttrib::
set_normal_value(const BuilderN *array, ushort index) {
set_normal(array[index]);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttrib::set_color_value
// Access: Public
// Description: Reassigns the color, without knowing whether the
// attribute is indexed or nonindexed. A nonindexed
// attribute will look up the index in the array and
// store the resulting value, while an indexed attribute
// will just store the index number (which assumes the
// array is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderAttrib::
set_color_value(const BuilderC *array, ushort index) {
set_color(array[index]);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribI::set_normal_value
// Access: Public
// Description: Reassigns the normal, without knowing whether the
// attribute is indexed or nonindexed. A nonindexed
// attribute will look up the index in the array and
// store the resulting value, while an indexed attribute
// will just store the index number (which assumes the
// array is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderAttribI::
set_normal_value(const BuilderN *, ushort index) {
set_normal(index);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribI::set_color_value
// Access: Public
// Description: Reassigns the color, without knowing whether the
// attribute is indexed or nonindexed. A nonindexed
// attribute will look up the index in the array and
// store the resulting value, while an indexed attribute
// will just store the index number (which assumes the
// array is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderAttribI::
set_color_value(const BuilderC *, ushort index) {
set_color(index);
}

View File

@@ -0,0 +1,12 @@
// Filename: builderAttrib.cxx
// Created by: drose (11May00)
//
////////////////////////////////////////////////////////////////////
#include "builderAttrib.h"
// Tell GCC that we'll take care of the instantiation explicitly here.
#ifdef __GNUC__
#pragma implementation
#endif

View File

@@ -0,0 +1,59 @@
// Filename: builderAttrib.h
// Created by: drose (22Jan99)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERATTRIB_H
#define BUILDERATTRIB_H
///////////////////////////////////////////////////////////////////
//
// BuilderAttrib, BuilderAttribI
//
// This is the parent class of both BuilderVertex and BuilderPrim, and
// contains the attribute values which may be set on either of them:
// specifically, normal, color, and pixel size. (Pixel size is the
// thickness of the lines, for a polygon or a line, or the size of the
// point, in pixels.)
//
// Like BuilderPrim and BuilderVertex, the two classes BuilderAttrib
// and BuilderAttribI are actually both instantiations of the same
// template class, BuilderAttribTempl.
//
///////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "builderAttribTempl.h"
#define BUILDERATTRIBTEMPL_BUILDERV BuilderAttribTempl<BuilderV, BuilderN, BuilderTC, BuilderC>
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, BUILDERATTRIBTEMPL_BUILDERV);
#define BUILDERATTRIBTEMPL_USHORT BuilderAttribTempl<ushort, ushort, ushort, ushort>
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, BUILDERATTRIBTEMPL_USHORT);
class EXPCL_PANDAEGG BuilderAttrib
: public BuilderAttribTempl<BuilderV, BuilderN, BuilderTC, BuilderC> {
public:
BuilderAttrib() {}
INLINE void set_normal_value(const BuilderN *array, ushort index);
INLINE void set_color_value(const BuilderC *array, ushort index);
};
class EXPCL_PANDAEGG BuilderAttribI
: public BuilderAttribTempl<ushort, ushort, ushort, ushort> {
public:
BuilderAttribI() {}
INLINE void set_normal_value(const BuilderN *array, ushort index);
INLINE void set_color_value(const BuilderC *array, ushort index);
};
#include "builderAttrib.I"
// Tell GCC that we'll take care of the instantiation explicitly here.
#ifdef __GNUC__
#pragma interface
#endif
#endif

View File

@@ -0,0 +1,244 @@
// Filename: builderAttribTempl.I
// Created by: drose (17Sep97)
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderAttribTempl<VT, NT, TT, CT>::
BuilderAttribTempl() {
_flags = 0;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::Copy constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderAttribTempl<VT, NT, TT, CT>::
BuilderAttribTempl(const BuilderAttribTempl &copy) {
(*this) = copy;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::Copy assignment operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderAttribTempl<VT, NT, TT, CT> &BuilderAttribTempl<VT, NT, TT, CT>::
operator = (const BuilderAttribTempl<VT, NT, TT, CT> &copy) {
_normal = copy._normal;
_color = copy._color;
_pixel_size = copy._pixel_size;
_flags = copy._flags;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::clear
// Access: Public
// Description: Resets the attribute flags to their original, empty
// state--where no attributes have been applied.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderAttribTempl<VT, NT, TT, CT> &BuilderAttribTempl<VT, NT, TT, CT>::
clear() {
_flags = 0;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::has_normal
// Access: Public
// Description: Returns true if the attribute has a normal.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE bool BuilderAttribTempl<VT, NT, TT, CT>::
has_normal() const {
return (_flags & BAF_normal)!=0;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::get_normal
// Access: Public
// Description: Returns the attribute's normal. It is an error to
// call this without first verifying that has_normal() is
// true.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderAttribTempl<VT, NT, TT, CT>::NType BuilderAttribTempl<VT, NT, TT, CT>::
get_normal() const {
nassertr(has_normal(), _normal);
return _normal;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::set_normal
// Access: Public
// Description: Resets the attribute's normal.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderAttribTempl<VT, NT, TT, CT> &BuilderAttribTempl<VT, NT, TT, CT>::
set_normal(const NType &n) {
_flags |= BAF_normal;
_normal = n;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::has_color
// Access: Public
// Description: Returns true if the attribute has a color.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE bool BuilderAttribTempl<VT, NT, TT, CT>::
has_color() const {
return (_flags & BAF_color)!=0;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::get_color
// Access: Public
// Description: Returns the attribute's color. It is an error to
// call this without first verifying that has_color() is
// true.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderAttribTempl<VT, NT, TT, CT>::CType BuilderAttribTempl<VT, NT, TT, CT>::
get_color() const {
nassertr(has_color(), _color);
return _color;
}
template <class VT, class NT, class TT, class CT>
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::set_color
// Access: Public
// Description: Resets the attribute's color.
////////////////////////////////////////////////////////////////////
INLINE BuilderAttribTempl<VT, NT, TT, CT> &BuilderAttribTempl<VT, NT, TT, CT>::
set_color(const CType &c) {
_flags |= BAF_color;
_color = c;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::has_pixel_size
// Access: Public
// Description: Returns true if the attribute has a pixel_size.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE bool BuilderAttribTempl<VT, NT, TT, CT>::
has_pixel_size() const {
return (_flags & BAF_pixel_size)!=0;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::get_pixel_size
// Access: Public
// Description: Returns the attribute's pixel_size. It is an error to
// call this without first verifying that has_pixel_size() is
// true.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE float BuilderAttribTempl<VT, NT, TT, CT>::
get_pixel_size() const {
nassertr(has_pixel_size(), _pixel_size);
return _pixel_size;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::set_pixel_size
// Access: Public
// Description: Resets the attribute's pixel_size.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderAttribTempl<VT, NT, TT, CT> &BuilderAttribTempl<VT, NT, TT, CT>::
set_pixel_size(float s) {
_flags |= BAF_pixel_size;
_pixel_size = s;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::operator ==
// Access: Public
// Description: Assigns an ordering to the vertices. This is used by
// the Mesher to group identical vertices. This assumes
// that all vertices in the locus of consideration will
// share the same state: with or without normals,
// texcoords, etc.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE bool BuilderAttribTempl<VT, NT, TT, CT>::
operator == (const BuilderAttribTempl<VT, NT, TT, CT> &other) const {
if (has_normal() && !(_normal == other._normal))
return false;
if (has_color() && !(_color == other._color))
return false;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::operator <
// Access: Public
// Description: Assigns an ordering to the vertices. This is used by
// the Mesher to group identical vertices. This assumes
// that all vertices in the locus of consideration will
// share the same state: with or without normals,
// texcoords, etc.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE bool BuilderAttribTempl<VT, NT, TT, CT>::
operator < (const BuilderAttribTempl<VT, NT, TT, CT> &other) const {
if (has_normal() && !(_normal == other._normal))
return _normal < other._normal;
if (has_color() && !(_color == other._color))
return _color < other._color;
return false;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderAttribTempl::output
// Access: Public
// Description: Formats the attribs for output in some sensible way.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE ostream &BuilderAttribTempl<VT, NT, TT, CT>::
output(ostream &out) const {
if (this!=NULL) {
if (has_normal()) {
out << " normal " << get_normal();
}
if (has_color()) {
out << " color " << get_color();
}
}
return out;
}

View File

@@ -0,0 +1,70 @@
// Filename: builderAttribTempl.h
// Created by: drose (17Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERATTRIBTEMPL_H
#define BUILDERATTRIBTEMPL_H
#include <pandabase.h>
#include "builderTypes.h"
#include <vector>
////////////////////////////////////////////////////////////////////
// Class : BuilderAttribTempl
// Description : The main body of BuilderAttrib and BuilderAttribI,
// and the base class for BuilderVertexTempl and
// BuilderPrimTempl, this class defines the attributes
// that may be specified for either vertices or
// primitives.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
class BuilderAttribTempl {
public:
typedef VT VType;
typedef NT NType;
typedef TT TType;
typedef CT CType;
INLINE BuilderAttribTempl();
INLINE BuilderAttribTempl(const BuilderAttribTempl &copy);
INLINE BuilderAttribTempl &operator = (const BuilderAttribTempl &copy);
INLINE BuilderAttribTempl &clear();
INLINE bool has_normal() const;
INLINE NType get_normal() const;
INLINE BuilderAttribTempl &set_normal(const NType &n);
INLINE bool has_color() const;
INLINE CType get_color() const;
INLINE BuilderAttribTempl &set_color(const CType &c);
INLINE bool has_pixel_size() const;
INLINE float get_pixel_size() const;
INLINE BuilderAttribTempl &set_pixel_size(float s);
INLINE bool operator == (const BuilderAttribTempl &other) const;
INLINE bool operator < (const BuilderAttribTempl &other) const;
INLINE ostream &output(ostream &out) const;
protected:
NType _normal;
CType _color;
float _pixel_size;
int _flags;
};
template <class VT, class NT, class TT, class CT>
INLINE ostream &operator << (ostream &out,
const BuilderAttribTempl<VT, NT, TT, CT> &attrib) {
return attrib.output(out);
}
#include "builderAttribTempl.I"
#endif

View File

@@ -0,0 +1,117 @@
// Filename: builderBucket.I
// Created by: drose (09Sep97)
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::set_coords
// Access: Public
// Description: Sets the array that will be used to define the
// vertices for any indexed geometry that is associated
// with this bucket.
////////////////////////////////////////////////////////////////////
INLINE void BuilderBucket::
set_coords(const PTA_Vertexf &coords) {
_coords = coords;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::get_coords
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PTA_Vertexf BuilderBucket::
get_coords() const {
return _coords;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::set_normals
// Access: Public
// Description: Sets the array that will be used to define the
// normals for any indexed geometry that is associated
// with this bucket.
////////////////////////////////////////////////////////////////////
INLINE void BuilderBucket::
set_normals(const PTA_Normalf &normals) {
_normals = normals;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::get_normals
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PTA_Normalf BuilderBucket::
get_normals() const {
return _normals;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::set_texcoords
// Access: Public
// Description: Sets the array that will be used to define the
// texture coordinates for any indexed geometry that is
// associated with this bucket.
////////////////////////////////////////////////////////////////////
INLINE void BuilderBucket::
set_texcoords(const PTA_TexCoordf &texcoords) {
_texcoords = texcoords;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::get_texcoords
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PTA_TexCoordf BuilderBucket::
get_texcoords() const {
return _texcoords;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::set_colors
// Access: Public
// Description: Sets the array that will be used to define the
// colors for any indexed geometry that is associated
// with this bucket.
////////////////////////////////////////////////////////////////////
INLINE void BuilderBucket::
set_colors(const PTA_Colorf &colors) {
_colors = colors;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::get_colors
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PTA_Colorf BuilderBucket::
get_colors() const {
return _colors;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::get_default_bucket
// Access: Public, Static
// Description: Returns a pointer to the BuilderBucket that is used
// to initialize any BuilderBuckets created with a
// default constructor. This is just a convenient way
// to set some global parameters.
////////////////////////////////////////////////////////////////////
INLINE BuilderBucket *BuilderBucket::
get_default_bucket() {
if (_default_bucket==NULL) {
_default_bucket = new BuilderBucket(true);
}
return _default_bucket;
}

View File

@@ -0,0 +1,240 @@
// Filename: builderBucket.cxx
// Created by: drose (10Sep97)
//
////////////////////////////////////////////////////////////////////
#include "builderAttrib.h"
#include "builderBucket.h"
#include "builderFuncs.h"
#include "builderMisc.h"
#include <namedNode.h>
#include <geomNode.h>
BuilderBucket *BuilderBucket::_default_bucket = NULL;
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
BuilderBucket::
BuilderBucket() {
_node = NULL;
(*this) = (*get_default_bucket());
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::Copy constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
BuilderBucket::
BuilderBucket(const BuilderBucket &copy) {
_node = NULL;
(*this) = copy;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::Copy assignment operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
BuilderBucket &BuilderBucket::
operator = (const BuilderBucket &copy) {
((BuilderProperties &)*this) = (BuilderProperties &)copy;
// setGState(copy._state);
set_name(copy.get_name());
set_coords(copy._coords);
set_normals(copy._normals);
set_texcoords(copy._texcoords);
set_colors(copy._colors);
_node = copy._node;
_drawBin = copy._drawBin;
_drawOrder = copy._drawOrder;
_trans = copy._trans;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
BuilderBucket::
~BuilderBucket() {
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::make_copy
// Access: Public, Virtual
// Description: Allocates and returns a new copy of this object. If
// you are subclassing from BuilderBucket, you must
// redefine this to return an instance of your new
// subclass, because the Builder will call this function
// to get its own copy.
////////////////////////////////////////////////////////////////////
BuilderBucket *BuilderBucket::
make_copy() const {
return new BuilderBucket(*this);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::make_geom_node
// Access: Public, Virtual
// Description: Called by the builder when it is time to create a new
// GeomNode. This function should allocate and return a
// new GeomNode suitable for adding geometry to. You
// may redefine it to return a subclass of GeomNode, or
// to do some initialization to the node.
////////////////////////////////////////////////////////////////////
GeomNode *BuilderBucket::
make_geom_node() {
return new GeomNode;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::done_geom
// Access: Public, Virtual
// Description: Called after all the geometry has been added to the
// Geom. This is just a hook for the user to redefine
// to do any post-processing that may be desired on the
// geometry. It may deallocate it and return a new
// copy. If it returns NULL, the geom is discarded.
////////////////////////////////////////////////////////////////////
Geom *BuilderBucket::
done_geom(Geom *geom) {
return geom;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::Ordering operator
// Access: Public, Virtual
// Description: Defines an arbitrary ordering among different
// buckets, and groups identical buckets together.
// (Buckets a and b are identical if !(a < b) and !(b <
// a).)
//
// The actual order between different buckets is
// arbitrary and largely irrelevant, so long as it is
// consistent. That is, if (a < b) and (b < c), it must
// also be true that (a < c). Also, if (a < b), it
// cannot be true that (b < a).
////////////////////////////////////////////////////////////////////
bool BuilderBucket::
operator < (const BuilderBucket &other) const {
if (get_name() != other.get_name()) {
return get_name() < other.get_name();
}
if (_node != other._node)
return _node < other._node;
if (_coords != other._coords)
return _coords < other._coords;
if (_normals != other._normals)
return _normals < other._normals;
if (_texcoords != other._texcoords)
return _texcoords < other._texcoords;
if (_colors != other._colors)
return _colors < other._colors;
if (_drawBin != other._drawBin)
return _drawBin < other._drawBin;
if (_drawOrder != other._drawOrder)
return _drawOrder < other._drawOrder;
int compare = _trans.compare_to(other._trans);
if (compare != 0) {
return (compare < 0);
}
return BuilderProperties::operator < (other);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::output
// Access: Public, Virtual
// Description: Formats the bucket for output in some sensible way.
////////////////////////////////////////////////////////////////////
void BuilderBucket::
output(ostream &out) const {
out << "Bucket \"" << get_name() << "\"";
if (_node != (NamedNode *)NULL) {
out << " attached to " << *_node << "\n";
}
out << "\n";
if (_coords != (Vertexf *)NULL) {
out << "_coords = " << (void *)_coords << "\n";
}
if (_normals != (Normalf *)NULL) {
out << "_normals = " << (void *)_normals << "\n";
}
if (_texcoords != (TexCoordf *)NULL) {
out << "_texcoords = " << (void *)_texcoords << "\n";
}
if (_colors != (Colorf *)NULL) {
out << "_colors = " << (void *)_colors << "\n";
}
if (_drawBin != -1) {
out << "_drawBin = " << _drawBin << "\n";
}
if (_drawOrder != 0) {
out << "_drawOrder = " << _drawOrder << "\n";
}
BuilderProperties::output(out);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::private Constructor
// Access: Private
// Description: This special constructor is used only to initialize
// the _default_bucket pointer. It sets up the initial
// defaults. The normal constructor copies from this
// instance.
////////////////////////////////////////////////////////////////////
BuilderBucket::
BuilderBucket(int) {
_node = NULL;
_drawBin = -1;
_drawOrder = 0;
// From BuilderProperties
_mesh = true;
_retesselate_coplanar = true;
_show_tstrips = false;
_show_qsheets = false;
_show_quads = false;
_show_normals = false;
_normal_color._v.set(1.0, 0.0, 0.0, 1.0);
_normal_scale = 1.0;
_subdivide_polys = true;
_coplanar_threshold = 0.01;
_unroll_fans = true;
_consider_fans = true;
_max_tfan_angle = 40.0;
_min_tfan_tris = 0;
}

View File

@@ -0,0 +1,104 @@
// Filename: builderBucket.h
// Created by: drose (09Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERBUCKET_H
#define BUILDERBUCKET_H
#include <pandabase.h>
#include "builderProperties.h"
#include <namable.h>
#include <pointerToArray.h>
#include <luse.h>
#include <nodeTransitions.h>
#include <pta_Vertexf.h>
#include <pta_Normalf.h>
#include <pta_Colorf.h>
#include <pta_TexCoordf.h>
#include <stdlib.h>
class NamedNode;
class Geom;
class GeomNode;
///////////////////////////////////////////////////////////////////
// Class : BuilderBucket
// Description : The main grouping tool for BuilderPrims. See the
// comments at the beginning of builder.h.
//
// As each primitive is added to the builder, it is
// associated with a bucket. The bucket stores the
// scene-graph properties of the primitive, and is used
// to identify primitives that have the same properties
// and thus may be joined into a common triangle strip.
//
// This grouping is done via the ordering operator, <,
// which defines an arbitrary ordering for buckets and
// identifies those buckets which are equivalent to each
// other. By subclassing off of BuilderBucket and
// redefining this operator, you can change the grouping
// behavior to suit your needs, if necessary.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG BuilderBucket : public BuilderProperties, public Namable {
public:
BuilderBucket();
BuilderBucket(const BuilderBucket &copy);
BuilderBucket &operator = (const BuilderBucket &copy);
virtual ~BuilderBucket();
virtual BuilderBucket *make_copy() const;
virtual GeomNode *make_geom_node();
virtual Geom *done_geom(Geom *geom);
virtual bool operator < (const BuilderBucket &other) const;
INLINE void set_coords(const PTA_Vertexf &coords);
INLINE PTA_Vertexf get_coords() const;
INLINE void set_normals(const PTA_Normalf &normals);
INLINE PTA_Normalf get_normals() const;
INLINE void set_texcoords(const PTA_TexCoordf &texcoords);
INLINE PTA_TexCoordf get_texcoords() const;
INLINE void set_colors(const PTA_Colorf &colors);
INLINE PTA_Colorf get_colors() const;
INLINE static BuilderBucket *get_default_bucket();
virtual void output(ostream &out) const;
NamedNode *_node;
short _drawBin;
unsigned int _drawOrder;
NodeTransitions _trans;
protected:
PTA_Vertexf _coords;
PTA_Normalf _normals;
PTA_TexCoordf _texcoords;
PTA_Colorf _colors;
static BuilderBucket *_default_bucket;
private:
BuilderBucket(int);
};
INLINE ostream &operator << (ostream &out, const BuilderBucket &bucket) {
bucket.output(out);
return out;
}
#include "builderBucket.I"
#endif

View File

@@ -0,0 +1,92 @@
// Filename: builderBucketNode.I
// Created by: drose (10Sep97)
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE BuilderBucketNode::
BuilderBucketNode(BuilderBucket *bucket) : _bucket(bucket) {
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::Copy constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE BuilderBucketNode::
BuilderBucketNode(const BuilderBucketNode &copy) {
(*this) = copy;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::Copy assignment operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void BuilderBucketNode::
operator = (const BuilderBucketNode &copy) {
_bucket = copy._bucket;
_prims = copy._prims;
_iprims = copy._iprims;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::add_prim_nonindexed
// Access: Public
// Description: Adds the indicated indexed primitive to the bucket as
// if it were nonindexed, and returns true if the
// primitive was valid. Intended to be called from
// Builder::add_prim_nonindexed().
////////////////////////////////////////////////////////////////////
INLINE bool BuilderBucketNode::
add_prim_nonindexed(const BuilderPrimI &prim) {
BuilderPrim nonindexed;
nonindexed.nonindexed_copy(prim, *_bucket);
return add_prim(nonindexed);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::get_bucket
// Access: Public
// Description: Returns the BuilderBucket object associated with this
// node.
////////////////////////////////////////////////////////////////////
INLINE BuilderBucket *BuilderBucketNode::
get_bucket() const {
return _bucket;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::Ordering operator
// Access: Public
// Description: Returns true if this bucket precedes the indicated
// one in ordering. This function is used by the STL
// set in the Builder object to sort buckets into order,
// and to collect similar buckets together.
////////////////////////////////////////////////////////////////////
INLINE bool BuilderBucketNode::
operator < (const BuilderBucketNode &other) const {
return (*_bucket) < (*other._bucket);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::Equivalence operator
// Access: Public
// Description: Returns true if the two buckets are equivalent, based
// on the ordering operator, above.
////////////////////////////////////////////////////////////////////
INLINE bool BuilderBucketNode::
operator == (const BuilderBucketNode &other) const {
return !((*_bucket) < (*other._bucket) ||
(*other._bucket) < (*_bucket));
}

View File

@@ -0,0 +1,87 @@
// Filename: builderBucketNode.cxx
// Created by: drose (10Sep97)
//
////////////////////////////////////////////////////////////////////
#include "builderFuncs.h"
#include "builderBucketNode.h"
#include <geomNode.h>
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::add_prim
// Access: Public
// Description: Adds the indicated indexed primitive to the
// bucket, and returns true if the primitive was valid.
// Intended to be called from Builder::add_prim().
////////////////////////////////////////////////////////////////////
bool BuilderBucketNode::
add_prim(const BuilderPrim &prim) {
bool result = expand(prim, *_bucket, inserter(_prims, _prims.begin()));
return result;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::add_prim
// Access: Public
// Description: Adds the indicated nonindexed primitive to the
// bucket, and returns true if the primitive was valid.
// Intended to be called from Builder::add_prim().
////////////////////////////////////////////////////////////////////
bool BuilderBucketNode::
add_prim(const BuilderPrimI &prim) {
bool result = expand(prim, *_bucket, inserter(_iprims, _iprims.begin()));
return result;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::build
// Access: Public
// Description: Builds all the geometry assigned to this particular
// bucket, and assigns it to the indicated GeomNode.
// Returns the number of Geoms created.
////////////////////////////////////////////////////////////////////
int BuilderBucketNode::
build(GeomNode *geom_node) const {
int count = 0;
{
// First, the nonindexed.
Prims::const_iterator pi, last_pi;
last_pi = _prims.begin();
for (pi = _prims.begin();
pi != _prims.end();
++pi) {
if ((*last_pi) < (*pi)) {
count += mesh_and_build(last_pi, pi, *_bucket, geom_node,
(BuilderPrim *)0);
last_pi = pi;
}
}
count += mesh_and_build(last_pi, pi, *_bucket, geom_node,
(BuilderPrim *)0);
}
{
// Then, the indexed.
IPrims::const_iterator pi, last_pi;
last_pi = _iprims.begin();
for (pi = _iprims.begin();
pi != _iprims.end();
++pi) {
if ((*last_pi) < (*pi)) {
count += mesh_and_build(last_pi, pi, *_bucket, geom_node,
(BuilderPrimI *)0);
last_pi = pi;
}
}
count += mesh_and_build(last_pi, pi, *_bucket, geom_node,
(BuilderPrimI *)0);
}
return count;
}

View File

@@ -0,0 +1,58 @@
// Filename: builderBucketNode.h
// Created by: drose (10Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERBUCKETNODE_H
#define BUILDERBUCKETNODE_H
#include <pandabase.h>
#include "builderPrim.h"
#include "builderBucket.h"
#include <set>
class GeomNode;
///////////////////////////////////////////////////////////////////
// Class : BuilderBucketNode
// Description : This is a wrapper class around BuilderBucket, used by
// the Builder class. It stores a pointer to a
// BuilderBucket object, as well as lists of the
// primitives that have been added to it.
//
// There are no functions in this class that are
// intended to be called directly by user code; instead,
// use the interface provided by Builder.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG BuilderBucketNode {
public:
INLINE BuilderBucketNode(BuilderBucket *bucket);
INLINE BuilderBucketNode(const BuilderBucketNode &copy);
INLINE void operator = (const BuilderBucketNode &copy);
bool add_prim(const BuilderPrim &prim);
bool add_prim(const BuilderPrimI &prim);
INLINE bool add_prim_nonindexed(const BuilderPrimI &prim);
INLINE BuilderBucket *get_bucket() const;
INLINE bool operator < (const BuilderBucketNode &other) const;
INLINE bool operator == (const BuilderBucketNode &other) const;
int build(GeomNode *geom_node) const;
protected:
typedef multiset<BuilderPrim, less<BuilderPrim> > Prims;
typedef multiset<BuilderPrimI, less<BuilderPrimI> > IPrims;
BuilderBucket *_bucket;
Prims _prims;
IPrims _iprims;
};
#include "builderBucketNode.I"
#endif

View File

@@ -0,0 +1,908 @@
// Filename: builderFuncs.cxx
// Created by: drose (09Sep97)
//
////////////////////////////////////////////////////////////////////
#include "builderPrim.h"
#include "mesherTempl.h"
#include "builderNormalVisualizer.h"
#include "config_builder.h"
#include <geom.h>
#include <geomprimitives.h>
#include <geomNode.h>
#include <algorithm>
#ifndef PENV_WIN32
#include <alloca.h>
#endif
#ifdef WIN32_VC
struct Vtx {
int index;
BuilderV coord;
struct Vtx *next;
};
#endif
////////////////////////////////////////////////////////////////////
// Function: decomp_concave
// Description: Decomposes a concave polygon into triangles. Returns
// true if successful, false if the polygon is
// self-intersecting.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
static bool
decomp_concave(const PrimType &prim, BuilderBucket &bucket,
OutputIterator result,
int asum, int x, int y) {
#ifndef WIN32_VC
struct Vtx {
int index;
BuilderV coord;
struct Vtx *next;
};
#endif
#define VX(p, c) p->coord[c]
vector<PrimType> output_prims;
Vtx *p0, *p1, *p2, *t0, *vert;
Vtx *m[3];
float xmin, xmax, ymin, ymax;
int i, init, csum, chek;
float a[3], b[3], c[3], s[3];
int num_verts = prim.get_num_verts();
nassertr(num_verts >= 3, false);
/* Make linked list of verts */
vert = (Vtx *) alloca(sizeof(Vtx));
vert->index = 0;
vert->coord = prim.get_vertex(0).get_coord_value(bucket);
p1 = vert;
for (i = 1; i < num_verts; i++) {
p0 = (Vtx *) alloca(sizeof(Vtx));
p0->index = i;
p0->coord = prim.get_vertex(i).get_coord_value(bucket);
// There shouldn't be two consecutive identical vertices. If
// there are, skip one.
if (!(p0->coord == p1->coord)) {
p1->next = p0;
p1 = p0;
}
}
p1->next = vert;
p0 = vert;
p1 = p0->next;
p2 = p1->next;
m[0] = p0;
m[1] = p1;
m[2] = p2;
chek = 0;
while (p0 != p2->next) {
/* Polygon is self-intersecting so punt */
if (chek &&
m[0] == p0 &&
m[1] == p1 &&
m[2] == p2) {
// builder_cat.info() << "Could not decompose concave polygon!";
return false;
}
chek = 1;
a[0] = VX(p1, y) - VX(p2, y);
b[0] = VX(p2, x) - VX(p1, x);
a[2] = VX(p0, y) - VX(p1, y);
b[2] = VX(p1, x) - VX(p0, x);
csum = ((b[0] * a[2] - b[2] * a[0] >= 0.0) ? 1 : 0);
if (csum ^ asum) {
/* current angle is concave */
p0 = p1;
p1 = p2;
p2 = p2->next;
} else {
/* current angle is convex */
xmin = (VX(p0, x) < VX(p1, x)) ? VX(p0, x) : VX(p1, x);
if (xmin > VX(p2, x))
xmin = VX(p2, x);
xmax = (VX(p0, x) > VX(p1, x)) ? VX(p0, x) : VX(p1, x);
if (xmax < VX(p2, x))
xmax = VX(p2, x);
ymin = (VX(p0, y) < VX(p1, y)) ? VX(p0, y) : VX(p1, y);
if (ymin > VX(p2, y))
ymin = VX(p2, y);
ymax = (VX(p0, y) > VX(p1, y)) ? VX(p0, y) : VX(p1, y);
if (ymax < VX(p2, y))
ymax = VX(p2, y);
for (init = 1, t0 = p2->next; t0 != p0; t0 = t0->next) {
if (VX(t0, x) >= xmin && VX(t0, x) <= xmax &&
VX(t0, y) >= ymin && VX(t0, y) <= ymax) {
if (init) {
a[1] = VX(p2, y) - VX(p0, y);
b[1] = VX(p0, x) - VX(p2, x);
init = 0;
c[0] = VX(p1, x) * VX(p2, y) - VX(p2, x) * VX(p1, y);
c[1] = VX(p2, x) * VX(p0, y) - VX(p0, x) * VX(p2, y);
c[2] = VX(p0, x) * VX(p1, y) - VX(p1, x) * VX(p0, y);
}
s[0] = a[0] * VX(t0, x) + b[0] * VX(t0, y) + c[0];
s[1] = a[1] * VX(t0, x) + b[1] * VX(t0, y) + c[1];
s[2] = a[2] * VX(t0, x) + b[2] * VX(t0, y) + c[2];
if (asum) {
if (s[0] >= 0.0 && s[1] >= 0.0 && s[2] >= 0.0)
break;
} else {
if (s[0] <= 0.0 && s[1] <= 0.0 && s[2] <= 0.0)
break;
}
}
}
if (t0 != p0) {
p0 = p1;
p1 = p2;
p2 = p2->next;
} else {
PrimType new_prim(prim);
new_prim.set_type(BPT_tri);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(p0->index));
new_prim.add_vertex(prim.get_vertex(p1->index));
new_prim.add_vertex(prim.get_vertex(p2->index));
output_prims.push_back(new_prim);
p0->next = p1->next;
p1 = p2;
p2 = p2->next;
m[0] = p0;
m[1] = p1;
m[2] = p2;
chek = 0;
}
}
}
PrimType new_prim(prim);
new_prim.set_type(BPT_tri);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(p0->index));
new_prim.add_vertex(prim.get_vertex(p1->index));
new_prim.add_vertex(prim.get_vertex(p2->index));
output_prims.push_back(new_prim);
copy(output_prims.begin(), output_prims.end(), result);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: triangulate_poly
// Description: Breaks a (possibly concave) higher-order polygon into
// a series of constituent triangles.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
static bool
triangulate_poly(const PrimType &prim, BuilderBucket &bucket,
OutputIterator result) {
BuilderV p0, p1, as;
float dx1, dy1, dx2, dy2, max;
int i, flag, asum, csum, index, x, y, v0, v1, v, even;
// First see if the polygon is just a triangle
int num_verts = prim.get_num_verts();
if (num_verts == 3) {
PrimType new_prim(prim);
new_prim.set_type(BPT_tri);
*result++ = new_prim;
return true;
} else if (num_verts < 3) {
// Or if it's a degenerate polygon.
return false;
}
// calculate signed areas
as[0] = 0.0;
as[1] = 0.0;
as[2] = 0.0;
for (i = 0; i < num_verts; i++) {
p0 = prim.get_vertex(i).get_coord_value(bucket);
p1 = prim.get_vertex((i + 1) % num_verts).get_coord_value(bucket);
as[0] += p0[0] * p1[1] - p0[1] * p1[0];
as[1] += p0[0] * p1[2] - p0[2] * p1[0];
as[2] += p0[1] * p1[2] - p0[2] * p1[1];
}
/* select largest signed area */
max = 0.0;
index = 0;
for (i = 0; i < 3; i++) {
if (as[i] >= 0.0) {
if (as[i] > max) {
max = as[i];
index = i;
flag = 1;
}
} else {
as[i] = -as[i];
if (as[i] > max) {
max = as[i];
index = i;
flag = 0;
}
}
}
/* pointer offsets */
switch (index) {
case 0:
x = 0;
y = 1;
break;
case 1:
x = 0;
y = 2;
break;
case 2:
x = 1;
y = 2;
break;
}
/* concave check */
p0 = prim.get_vertex(0).get_coord_value(bucket);
p1 = prim.get_vertex(1).get_coord_value(bucket);
dx1 = p1[x] - p0[x];
dy1 = p1[y] - p0[y];
p0 = p1;
p1 = prim.get_vertex(2).get_coord_value(bucket);
dx2 = p1[x] - p0[x];
dy2 = p1[y] - p0[y];
asum = ((dx1 * dy2 - dx2 * dy1 >= 0.0) ? 1 : 0);
for (i = 0; i < num_verts - 1; i++) {
p0 = p1;
p1 = prim.get_vertex((i+3) % num_verts).get_coord_value(bucket);
dx1 = dx2;
dy1 = dy2;
dx2 = p1[x] - p0[x];
dy2 = p1[y] - p0[y];
csum = ((dx1 * dy2 - dx2 * dy1 >= 0.0) ? 1 : 0);
if (csum ^ asum) {
return decomp_concave(prim, bucket, result, flag, x, y);
}
}
v0 = 0;
v1 = 1;
v = num_verts - 1;
even = 1;
/*
* Convert to triangles only. Do not fan out from a single vertex
* but zigzag into triangle strip.
*/
for (i = 0; i < num_verts - 2; i++) {
if (even) {
PrimType new_prim(prim);
new_prim.set_type(BPT_tri);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(v0));
new_prim.add_vertex(prim.get_vertex(v1));
new_prim.add_vertex(prim.get_vertex(v));
*result++ = new_prim;
v0 = v1;
v1 = v;
v = v0 + 1;
} else {
PrimType new_prim(prim);
new_prim.set_type(BPT_tri);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(v1));
new_prim.add_vertex(prim.get_vertex(v0));
new_prim.add_vertex(prim.get_vertex(v));
*result++ = new_prim;
v0 = v1;
v1 = v;
v = v0 - 1;
}
even = !even;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: expand_polys
// Description: Identifies a single polygon as a triangle, quad, or
// higher-order polygon, and writes it into the result
// list.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
static bool
expand_polys(PrimType &prim, BuilderBucket &,
OutputIterator result) {
switch (prim.get_num_verts()) {
case 0:
case 1:
case 2:
return false;
case 3:
prim.set_type(BPT_tri);
break;
case 4:
prim.set_type(BPT_quad);
break;
default:
prim.set_type(BPT_poly);
}
*result++ = prim;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: expand_points
// Description: Expands a light points primitive into its individual
// component points, with one point per primitive.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
static bool
expand_points(const PrimType &prim, BuilderBucket &,
OutputIterator result) {
// Each vertex goes in its own primitive.
int num_verts = prim.get_num_verts();
for (int i = 0; i < num_verts; i++) {
PrimType new_prim(prim);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(i));
*result++ = new_prim;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: expand_lines
// Description: Expands a linestrip primitive into its component line
// primitives.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
static bool
expand_lines(const PrimType &prim, BuilderBucket &,
OutputIterator result) {
// Each line segment goes in its own primitive. This breaks up the
// linestrips already defined; we'll re-strip them later if the
// generate-tstrips flag is enabled.
int num_verts = prim.get_num_verts();
for (int i = 1; i < num_verts; i++) {
PrimType new_prim(prim);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(i-1));
new_prim.add_vertex(prim.get_vertex(i));
*result++ = new_prim;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: expand
// Description: Receives a single primitive as a BuilderPrim or
// BuilderPrimI object, as input by the user. Does some
// initial processing on the primitive to verify
// internal consistency (for instance, that a quad has
// four vertices), and returns a new BuilderPrim or
// series of BuilderPrim objects, suitable for building
// with.
//
// More than one primitive might be returned because
// higher-order polygons may be broken up into
// triangles, and linestrips and points are broken into
// their component pieces. The output primitives are
// written into the STL container defined by result.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
bool
expand(const PrimType &prim, BuilderBucket &bucket, OutputIterator result) {
// Make a copy of the prim so we can fiddle with it.
PrimType new_prim = prim;
switch (new_prim.get_type()) {
case BPT_poly:
case BPT_tri:
case BPT_quad:
// These three types are all treated the same, as polygons. We
// don't entirely trust the user to match the polygon type with
// the number of verts, so we'll do it ourselves later.
new_prim.remove_doubled_verts(true);
if (!bucket._subdivide_polys ||
(bucket._mesh && new_prim.get_num_verts() <= 4)) {
// If we're meshing, we'd like to send quads through without
// subdividing. The mesher can take advantage of the extra
// information (and will eventually produce tris anyway).
return expand_polys(new_prim, bucket, result);
} else {
// If we're not meshing, we'll break them into tris now.
return triangulate_poly(new_prim, bucket, result);
}
case BPT_point:
new_prim.remove_doubled_verts(false);
return expand_points(new_prim, bucket, result);
case BPT_line:
new_prim.remove_doubled_verts(false);
return expand_lines(new_prim, bucket, result);
default:
builder_cat.error() << "Unknown prim type\n";
return false;
}
}
////////////////////////////////////////////////////////////////////
// Function: build_geoms
// Description: Accepts a list of BuilderPrim or BuilderPrimI
// objects, defined by the iterators first and last, and
// creates corresponding geometry for them in the
// indicated GeomNode.
////////////////////////////////////////////////////////////////////
template<class InputIterator, class PrimType>
static int
build_geoms(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node,
PrimType *) {
if (first==last) {
return 0;
}
// By the time we get here, we have a list of primitives that all have
// the same properties:
// 1. The BuilderBucket.
// 2. The indexed/nonindexed type.
// 3. The primitive type (polygon, line, point).
// 4. The pixel size.
// The binding of normals, colors, or texcoords: per-vertex,
// per-prim, or per-component, will generally be the same across all
// primitives, but it might not always be the same, because in
// certain special cases the mesher might have changed these
// properties when it built tristrips.
typedef TYPENAME PrimType::VType VType;
typedef TYPENAME PrimType::NType NType;
typedef TYPENAME PrimType::TType TType;
typedef TYPENAME PrimType::CType CType;
// We need to determine the common binding type for all primitives.
// For a given attribute, say normals, there are at most five cases,
// in the order of priority:
//
// 1. If at least one primitive in the list does not have normals,
// the binding will be G_OFF.
//
// 2. If at least one primitive has per-vertex normals, the binding
// will be G_PER_VERTEX.
//
// 3. If at least one primitive has per-component normals, the
// binding will be G_PER_COMPONENT.
//
// 4. If none of the first three apply, it follows that all
// primitives have an overall normal. If any primitive's
// overall normal differs from any other, the binding will be
// G_PER_PRIM.
//
// 5. If none of the above apply, the binding will be G_OVERALL.
//
// An exception to the above is for texcoords, which is either G_OFF
// (by rule 1) or G_PER_VERTEX.
GeomBindType bind_normals = G_OVERALL;
GeomBindType bind_colors = G_OVERALL;
GeomBindType bind_texcoords = G_PER_VERTEX;
NType overall_normal;
CType overall_color;
bool first_normal = true;
bool first_color = true;
InputIterator i;
for (i = first; i != last; ++i) {
// Normals.
// Test rule 1.
if (!(*i).has_any_normal()) {
bind_normals = G_OFF;
} else if (bind_normals != G_OFF) {
// Test rule 2.
if ((*i).has_vertex_normal()) {
bind_normals = G_PER_VERTEX;
} else if (bind_normals != G_PER_VERTEX) {
// Test rule 3.
if ((*i).has_component_normal()) {
bind_normals = G_PER_COMPONENT;
} else if (bind_normals != G_PER_COMPONENT) {
// Test rule 4.
nassertr((*i).has_overall_normal(), 0);
if (first_normal) {
overall_normal = (*i).get_normal();
first_normal = false;
} else if ( !((*i).get_normal() == overall_normal)) {
bind_normals = G_PER_PRIM;
}
}
}
}
// Colors.
// Test rule 1.
if (!(*i).has_any_color()) {
bind_colors = G_OFF;
} else if (bind_colors != G_OFF) {
// Test rule 2.
if ((*i).has_vertex_color()) {
bind_colors = G_PER_VERTEX;
} else if (bind_colors != G_PER_VERTEX) {
// Test rule 3.
if ((*i).has_component_color()) {
bind_colors = G_PER_COMPONENT;
} else if (bind_colors != G_PER_COMPONENT) {
// Test rule 4.
nassertr((*i).has_overall_color(), 0);
if (first_color) {
overall_color = (*i).get_color();
first_color = false;
} else if ( !((*i).get_color() == overall_color)) {
bind_colors = G_PER_PRIM;
}
}
}
}
// Texcoords.
// Test rule 1.
if (!(*i).has_any_texcoord()) {
bind_texcoords = G_OFF;
}
}
// Determine the primitive type and build the lengths array, if needed.
PTA_int lengths;
bool want_lengths = false;
int j;
Geom *geom = NULL;
BuilderPrimType type = (*first).get_type();
switch (type) {
case BPT_poly:
geom = new GeomPolygon;
want_lengths = true;
break;
case BPT_tristrip:
geom = new GeomTristrip;
want_lengths = true;
break;
case BPT_trifan:
geom = new GeomTrifan;
want_lengths = true;
break;
case BPT_line:
geom = new GeomLine;
break;
case BPT_point:
geom = new GeomPoint;
break;
case BPT_tri:
geom = new GeomTri;
break;
case BPT_quad:
geom = new GeomQuad;
break;
default:
builder_cat.fatal() << "Invalid primitive type.\n";
abort();
}
if (geom == NULL) {
builder_cat.error() << "Unsupported primitive type " << type << "\n";
return 0;
}
// Count up the number of prims we're actually building.
int num_prims = 0;
for (i = first; i != last; ++i) {
if ((*i).is_valid()) {
num_prims++;
}
}
if (num_prims==0) {
builder_cat.error() << "All primitives were invalid!\n";
return 0;
}
if (want_lengths) {
lengths = PTA_int(num_prims);
j = 0;
for (i = first; i != last; ++i) {
if ((*i).is_valid()) {
lengths[j++] = (*i).get_num_verts();
}
}
nassertr(j == num_prims, 0);
}
// Now build up some arrays.
PTA(VType) coords(0);
PTA(NType) normals(0);
PTA(TType) texcoords(0);
PTA(CType) colors(0);
int total_verts = 0;
int total_components = 0;
int v, num_verts;
int c, num_components;
for (i = first; i != last; ++i) {
if ((*i).is_valid()) {
num_verts = (*i).get_num_verts();
total_verts += num_verts;
for (v = 0; v < num_verts; v++) {
coords.push_back((*i).get_vertex(v).get_coord());
if (bind_normals == G_PER_VERTEX) {
normals.push_back((*i).get_vertex(v).get_normal());
}
if (bind_texcoords == G_PER_VERTEX) {
texcoords.push_back((*i).get_vertex(v).get_texcoord());
}
if (bind_colors == G_PER_VERTEX) {
colors.push_back((*i).get_vertex(v).get_color());
}
}
num_components = (*i).get_num_components();
total_components += num_components;
for (c = 0; c < num_components; c++) {
if (bind_normals == G_PER_COMPONENT) {
normals.push_back((*i).get_component(c).get_normal());
}
if (bind_colors == G_PER_COMPONENT) {
colors.push_back((*i).get_component(c).get_color());
}
}
if (bind_normals == G_PER_PRIM) {
normals.push_back((*i).get_normal());
}
if (bind_colors == G_PER_PRIM) {
colors.push_back((*i).get_color());
}
}
}
if (bind_normals == G_OVERALL) {
normals.push_back(overall_normal);
}
if (bind_colors == G_OVERALL) {
colors.push_back(overall_color);
}
// Now add all the stuff to our Geom.
geom->set_num_prims(num_prims);
if (lengths != (int *)NULL) {
geom->set_lengths(lengths);
}
PrimType::fill_geom(geom, coords,
bind_normals, normals,
bind_texcoords, texcoords,
bind_colors, colors,
bucket, num_prims,
total_components, total_verts);
/*
if ((*first).has_pixel_size()) {
// Again, we only have to test the first one in the list for a
// pixel_size attribute. If this one has it, then they all have
// the same value.
geom->setPntSize((*first).get_pixel_size());
geom->setLineWidth((*first).get_pixel_size());
}
*/
// geom->setGState((pfGeoState *)bucket.getGState());
// geom->setDrawBin(bucket._drawBin);
// geom->setDrawOrder(bucket._drawOrder);
Geom *new_geom = bucket.done_geom(geom);
if (new_geom != (Geom *)NULL) {
geom_node->add_geom(new_geom);
}
return 1;
}
/////////////////////////////////////////////////////////////////////
// Class : PrimByType
// Description : An STL function object to sort primitives in order by
// type.
////////////////////////////////////////////////////////////////////
template<class PrimType>
class PrimByType {
public:
int operator () (const PrimType &p1, const PrimType &p2) const {
return p1.get_type() < p2.get_type();
}
};
////////////////////////////////////////////////////////////////////
// Function: __mesh_and_build
// Description: The implementation of mesh_and_build(), below. This
// extra function call is just to allow mesh_and_build()
// to infer the PrimType (BuilderPrim or BuilderPrimI)
// from the iterator's value type, and template on that.
////////////////////////////////////////////////////////////////////
template<class InputIterator, class PrimType>
static int
__mesh_and_build(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node,
PrimType *) {
if (first==last) {
return 0;
}
typedef vector<PrimType> Prims;
Prims prims;
BuilderBucket *local_bucket = NULL;
BuilderBucket *bucket_ptr = &bucket;
if (bucket._mesh) {
// Send all the prims through the mesher. First, make a copy of
// the bucket so the mesher can modify it if it wants.
local_bucket = bucket.make_copy();
bucket_ptr = local_bucket;
MesherTempl<PrimType> mesher(local_bucket);
for (InputIterator ii = first; ii != last; ++ii) {
mesher.add_prim(*ii);
}
mesher.mesh();
PrimType prim;
prim = mesher.getPrim();
while (prim.get_num_verts() > 0) {
prims.push_back(prim);
prim = mesher.getPrim();
}
} else {
// Send the prims through without meshing.
copy(first, last, back_inserter(prims));
}
// Now we have an array of prims which all share the same
// properties, except possibly type. Sort them by type and send
// them to build_geoms.
sort(prims.begin(), prims.end(), PrimByType<PrimType>());
int count = 0;
if (!prims.empty()) {
Prims::iterator pi, last_pi;
pi = prims.begin();
last_pi = pi;
for (++pi; pi != prims.end(); ++pi) {
if ((*pi).get_type() != (*last_pi).get_type()) {
count += build_geoms(last_pi, pi, *bucket_ptr, geom_node, (PrimType*)0);
last_pi = pi;
}
}
count += build_geoms(last_pi, pi, *bucket_ptr, geom_node, (PrimType*)0);
}
if (local_bucket!=NULL) {
delete local_bucket;
}
// Finally, if the user so requested, create some visualization for
// the normals.
#ifdef SUPPORT_SHOW_NORMALS
if (bucket._show_normals) {
BuilderNormalVisualizer bnv(bucket);
for (InputIterator ii = first; ii != last; ++ii) {
bnv.add_prim(*ii);
}
bnv.show_normals(geom_node);
}
#endif
return count;
}
////////////////////////////////////////////////////////////////////
// Function: mesh_and_build
// Description: Accepts a list of BuilderPrim or BuilderPrimI
// objects, defined by the iterators first and list,
// runs them through the mesher if specified by the
// bucket, and builds them into the indicated GeomNode.
////////////////////////////////////////////////////////////////////
template<class InputIterator, class value_type>
int
mesh_and_build(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node,
value_type *value_type_ptr) {
return __mesh_and_build(first, last, bucket, geom_node, value_type_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: split
// Description: Splits an STL list into two other lists, according to
// the return value from pred.
////////////////////////////////////////////////////////////////////
template <class InputIterator, class OutputIterator, class Predicate>
OutputIterator split(InputIterator first, InputIterator last,
OutputIterator true_result, OutputIterator false_result,
Predicate pred) {
while (first != last) {
if (pred(*first)) {
*true_result++ = *first++;
} else {
*false_result++ = *first++;
}
}
return true_result;
}

View File

@@ -0,0 +1,66 @@
// Filename: builderFuncs.h
// Created by: drose (09Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERFUNCS_H
#define BUILDERFUNCS_H
#include <pandabase.h>
#include <vector>
#include <string>
class BuilderBucket;
class GeomNode;
////////////////////////////////////////////////////////////////////
// Function: expand
// Description: Receives a single primitive as a BuilderPrim or
// BuilderPrimI object, as input by the user. Does some
// initial processing on the primitive to verify
// internal consistency (for instance, that a quad has
// four vertices), and returns a new BuilderPrim or
// series of BuilderPrim objects, suitable for building
// with.
//
// More than one primitive might be returned because
// higher-order polygons may be broken up into
// triangles, and linestrips and points are broken into
// their component pieces. The output primitives are
// written into the STL container defined by result.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
bool
expand(const PrimType &prim, BuilderBucket &bucket,
OutputIterator result);
////////////////////////////////////////////////////////////////////
// Function: mesh_and_build
// Description: Accepts a list of BuilderPrim or BuilderPrimI
// objects, defined by the iterators first and list,
// runs them through the mesher if specified by the
// bucket, and builds them into the indicated GeomNode.
////////////////////////////////////////////////////////////////////
template<class InputIterator>
int
mesh_and_build(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node);
////////////////////////////////////////////////////////////////////
// Function: split
// Description: Splits an STL list into two other lists, according to
// the return value from pred.
////////////////////////////////////////////////////////////////////
template <class InputIterator, class OutputIterator, class Predicate>
OutputIterator split(InputIterator first, InputIterator last,
OutputIterator true_result, OutputIterator false_result,
Predicate pred);
#include "builderFuncs.I"
#endif

View File

@@ -0,0 +1,37 @@
// Filename: builderMisc.cxx
// Created by: drose (18Sep97)
//
////////////////////////////////////////////////////////////////////
#include "builderMisc.h"
#include "builderTypes.h"
#include <luse.h>
#include <stdlib.h>
////////////////////////////////////////////////////////////////////
// Function: make_random_color
// Description: Chooses a reasonable random color.
////////////////////////////////////////////////////////////////////
void
make_random_color(Colorf &color) {
LVector3f rgb;
float len;
do {
for (int i = 0; i < 3; i++) {
rgb[i] = (double)rand() / (double)RAND_MAX;
}
len = length(rgb);
// Repeat until we have a color that's not too dark or too light.
} while (len < .1 || len > 1.5);
#ifdef WIN32_VC
color.set(rgb[0], rgb[1], rgb[2],
0.25 + 0.75 * (double)rand() / (double)RAND_MAX);
#else
color.set(rgb[0], rgb[1], rgb[2],
0.25 + 0.75 * (double)random() / (double)RAND_MAX);
#endif
}

View File

@@ -0,0 +1,18 @@
// Filename: builderMisc.h
// Created by: drose (18Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERMISC_H
#define BUILDERMISC_H
#include <pandabase.h>
#include <luse.h>
////////////////////////////////////////////////////////////////////
// Function: make_random_color
// Description: Chooses a reasonable random color.
////////////////////////////////////////////////////////////////////
void make_random_color(Colorf &color);
#endif

View File

@@ -0,0 +1,11 @@
// Filename: builderNormalVisualizer.I
// Created by: drose (08Sep99)
//
////////////////////////////////////////////////////////////////////
INLINE BuilderNormalVisualizer::
BuilderNormalVisualizer(BuilderBucket &bucket) : _bucket(bucket) {
_num_vertices = 0;
_net_vertex._v.set(0.0, 0.0, 0.0);
}

View File

@@ -0,0 +1,65 @@
// Filename: builderNormalVisualizer.cxx
// Created by: drose (08Sep99)
//
////////////////////////////////////////////////////////////////////
#ifdef SUPPORT_SHOW_NORMALS
#include "builderNormalVisualizer.h"
#include "builderFuncs.h"
void BuilderNormalVisualizer::
add_prim(const BuilderPrim &prim) {
if (prim.has_overall_normal()) {
// Average up all the vertex values to get the primitive center.
BuilderV net_vertex;
net_vertex._v.set(0.0, 0.0, 0.0);
int num_verts = prim.get_num_verts();
for (int i = 0; i < num_verts; i++) {
net_vertex._v += prim.get_vertex(i).get_coord();
}
net_vertex._v /= num_verts;
add_normal(net_vertex, prim.get_normal());
} else if (prim.has_vertex_normal()) {
// Each vertex gets its own normal.
int num_verts = prim.get_num_verts();
for (int i = 0; i < num_verts; i++) {
add_normal(prim.get_vertex(i).get_coord(), prim.get_vertex(i).get_normal());
}
} else if (prim.has_component_normal()) {
// Each component gets its own normal. We don't presently handle
// this, as it should only happen when the user passes
// already-meshed tristrips into the builder, an unusual
// situation.
}
}
void BuilderNormalVisualizer::
add_prim(const BuilderPrimI &prim) {
BuilderPrim prim_ni;
prim_ni.nonindexed_copy(prim, _bucket);
add_prim(prim_ni);
}
void BuilderNormalVisualizer::
show_normals(GeomNode *node) {
// Ok, now we've got a bunch of normals saved up; create some geometry.
mesh_and_build(_lines.begin(), _lines.end(), _bucket, node, (BuilderPrim *)0);
}
void BuilderNormalVisualizer::
add_normal(const BuilderV &center, const BuilderN &normal) {
BuilderV to = center._v + normal._v * _bucket._normal_scale;
BuilderPrim line;
line.set_type(BPT_line);
line.set_color(_bucket._normal_color);
line.add_vertex(BuilderVertex(center));
line.add_vertex(BuilderVertex(to));
_lines.push_back(line);
}
#endif

View File

@@ -0,0 +1,51 @@
// Filename: builderNormalVisualizer.h
// Created by: drose (08Sep99)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERNORMALVISUALIZER_H
#define BUILDERNORMALVISUALIZER_H
#ifdef SUPPORT_SHOW_NORMALS
#include <pandabase.h>
#include "builderBucket.h"
#include "builderAttrib.h"
#include "builderVertex.h"
#include "builderPrim.h"
#include <vector>
///////////////////////////////////////////////////////////////////
// Class : BuilderNormalVisualizer
// Description : A useful class for collecting information about
// vertices and their associated normals as geometry is
// built, so that its normals may be visualized via
// renderable geometry. This is activated by the
// _show_normals flag in the BuilderProperties.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG BuilderNormalVisualizer {
public:
INLINE BuilderNormalVisualizer(BuilderBucket &bucket);
void add_prim(const BuilderPrim &prim);
void add_prim(const BuilderPrimI &prim);
void show_normals(GeomNode *node);
private:
void add_normal(const BuilderV &center, const BuilderN &normal);
BuilderBucket &_bucket;
BuilderV _net_vertex;
int _num_vertices;
vector<BuilderPrim> _lines;
};
#include "builderNormalVisualizer.I"
#endif // SUPPORT_SHOW_NORMALS
#endif

View File

@@ -0,0 +1,194 @@
// Filename: builderPrim.cxx
// Created by: drose (10Sep97)
//
////////////////////////////////////////////////////////////////////
#include "builderPrim.h"
#include <geom.h>
#include <notify.h>
// Tell GCC that we'll take care of the instantiation explicitly here.
#ifdef __GNUC__
#pragma implementation
#endif
////////////////////////////////////////////////////////////////////
// Function: BuilderPrim::nonindexed_copy
// Access: Public
// Description: Makes a nonindexed copy of the given indexed prim, by
// looking up the current values of the indexed
// coordinates in the given bucket.
////////////////////////////////////////////////////////////////////
BuilderPrim &BuilderPrim::
nonindexed_copy(const BuilderPrimTempl<BuilderVertexI> &copy,
const BuilderBucket &bucket) {
clear();
set_type(copy.get_type());
if (copy.has_normal()) {
nassertr(bucket.get_normals() != (Normalf *)NULL, *this);
set_normal(bucket.get_normals()[copy.get_normal()]);
}
if (copy.has_color()) {
nassertr(bucket.get_colors() != (Colorf *)NULL, *this);
set_color(bucket.get_colors()[copy.get_color()]);
}
if (copy.has_pixel_size()) {
set_pixel_size(copy.get_pixel_size());
}
int num_verts = copy.get_num_verts();
int i;
for (i = 0; i < num_verts; i++) {
const BuilderVertexI &cv = copy.get_vertex(i);
BuilderVertex v;
if (cv.has_coord()) {
v.set_coord(cv.get_coord_value(bucket));
}
if (cv.has_normal()) {
v.set_normal(cv.get_normal_value(bucket));
}
if (cv.has_texcoord()) {
v.set_texcoord(cv.get_texcoord_value(bucket));
}
if (cv.has_color()) {
v.set_color(cv.get_color_value(bucket));
}
if (cv.has_pixel_size()) {
v.set_pixel_size(cv.get_pixel_size());
}
add_vertex(v);
}
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderPrim::fill_geom
// Access: Public
// Description: Fills up the attribute values of a Geom with the
// indicated arrays. This creates a nonindexed Geom.
////////////////////////////////////////////////////////////////////
void BuilderPrim::
fill_geom(Geom *geom, const PTA_BuilderV &v_array,
GeomBindType n_attr, const PTA_BuilderN &n_array,
GeomBindType t_attr, const PTA_BuilderTC &t_array,
GeomBindType c_attr, const PTA_BuilderC &c_array,
const BuilderBucket &, int, int, int) {
// WARNING! This is questionable practice. We have a
// PTA_BuilderV etc.; since a BuilderV is just a proxy
// to a Vertexf, we can get away with casting this to a
// PTA_Vertexf.
geom->set_coords((PTA_Vertexf &)v_array, G_PER_VERTEX);
if (n_attr != G_OFF) {
geom->set_normals((PTA_Normalf &)n_array, n_attr);
}
if (t_attr != G_OFF) {
geom->set_texcoords((PTA_TexCoordf &)t_array, t_attr);
}
if (c_attr != G_OFF) {
geom->set_colors((PTA_Colorf &)c_array, c_attr);
}
}
////////////////////////////////////////////////////////////////////
// Function: BuilderPrimI::fill_geom
// Access: Public
// Description: Fills up the attribute values of a Geom with the
// indicated arrays. This creates an indexed Geom.
////////////////////////////////////////////////////////////////////
void BuilderPrimI::
fill_geom(Geom *geom, const PTA_ushort &v_array,
GeomBindType n_attr, PTA_ushort n_array,
GeomBindType t_attr, PTA_ushort t_array,
GeomBindType c_attr, PTA_ushort c_array,
const BuilderBucket &bucket,
int num_prims, int num_components, int num_verts) {
PTA_Vertexf v_data = bucket.get_coords();
PTA_Normalf n_data = bucket.get_normals();
PTA_TexCoordf t_data = bucket.get_texcoords();
PTA_Colorf c_data = bucket.get_colors();
// Make sure the data pointers are NULL if the attribute is off.
if (n_attr == G_OFF) {
n_data = NULL;
n_array = NULL;
}
if (t_attr == G_OFF) {
t_data = NULL;
t_array = NULL;
}
if (c_attr == G_OFF) {
c_data = NULL;
c_array = NULL;
}
int n_len =
(n_attr==G_PER_VERTEX) ? num_verts :
(n_attr==G_PER_COMPONENT) ? num_components :
(n_attr==G_PER_PRIM) ? num_prims :
(n_attr==G_OVERALL) ? 1 : 0;
int t_len =
(t_attr==G_PER_VERTEX) ? num_verts :
(t_attr==G_PER_COMPONENT) ? num_components :
(t_attr==G_PER_PRIM) ? num_prims :
(t_attr==G_OVERALL) ? 1 : 0;
int c_len =
(c_attr==G_PER_VERTEX) ? num_verts :
(c_attr==G_PER_COMPONENT) ? num_components :
(c_attr==G_PER_PRIM) ? num_prims :
(c_attr==G_OVERALL) ? 1 : 0;
// See if we can share some of the index lists.
if (n_attr != G_OFF &&
memcmp(v_array, n_array, sizeof(ushort) * n_len)==0) {
n_array = v_array;
}
if (t_attr != G_OFF) {
if (memcmp(v_array, t_array, sizeof(ushort) * t_len)==0) {
t_array = v_array;
} else if (t_len <= n_len &&
memcmp(n_array, t_array, sizeof(ushort) * t_len)==0) {
t_array = n_array;
}
}
if (c_attr != G_OFF) {
if (memcmp(v_array, c_array, sizeof(ushort) * c_len)==0) {
c_array = v_array;
} else if (c_len <= n_len &&
memcmp(n_array, c_array, sizeof(ushort) * c_len)==0) {
c_array = n_array;
} else if (c_len <= t_len &&
memcmp(t_array, c_array, sizeof(ushort) * c_len)==0) {
c_array = t_array;
}
}
geom->set_coords(v_data, G_PER_VERTEX, v_array);
if (n_attr != G_OFF) {
geom->set_normals(n_data, n_attr, n_array);
}
if (t_attr != G_OFF) {
geom->set_texcoords(t_data, t_attr, t_array);
}
if (c_attr != G_OFF) {
geom->set_colors(c_data, c_attr, c_array);
}
}

View File

@@ -0,0 +1,119 @@
// Filename: builderPrim.h
// Created by: drose (09Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERPRIM_H
#define BUILDERPRIM_H
///////////////////////////////////////////////////////////////////
//
// BuilderPrim, BuilderPrimI
//
// The basic class for passing primitives (polygons, etc.) to the
// builder. See the comments at the beginning of builder.h and
// builderVertex.h.
//
// A BuilderPrim has a few attributes of its own--color and
// normal--which are defined in builderAttrib.h (which it inherits
// from). It also has a collection of vertices, represented as
// BuilderVertex objects, each of which can have its own attributes as
// well. Any additional attributes, such as texture, lighting, etc.,
// are considered to be external to the primitive, and are defined in
// the BuilderBucket object.
//
// BuilderPrimI is exactly like BuilderPrim, except that it represents
// an indexed primitive. A BuilderPrimI keeps its collection of
// vertices as BuilderVertexI's, which store their values as index
// numbers into an array rather than as actual coordinate values. The
// arrays themselves are stored in the BuilderBucket.
//
// In fact, BuilderPrim and BuilderPrimI are both instantiations of
// the same template object, BuilderPrimTempl, with different vertex
// types (BuilderVertex and BuilderVertexI, respectively).
//
// It is this templating that drives most of the code in this package.
// A lot of stuff in the builder tool, and everything in the mesher
// tool, is templated on the BuilderPrim type, so the same code is
// used to support both indexed and nonindexed primitives.
//
//
// In addition to storing the primitives--individual polygons,
// generally--as passed in by user code, BuilderPrim objects can store
// the compound primitives that might have been generated by the
// mesher, like triangle strips. In this case, in addition to an
// array of vertices, it has an array of component attributes, which
// store the attributes specific to each individual component
// (e.g. the normal of each triangle in a triangle strip).
//
///////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "builderPrimTempl.h"
#include "builderBucket.h"
#include "pta_BuilderV.h"
#include "pta_BuilderN.h"
#include "pta_BuilderTC.h"
#include "pta_BuilderC.h"
#include <pta_ushort.h>
#include <geom.h>
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, BuilderPrimTempl<BuilderVertex>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, BuilderPrimTempl<BuilderVertexI>);
/////////////////////////////////////////////////////////////////////
// Class : BuilderPrim
// Description : The basic class for passing nonindexed primitives
// to the builder. See the comments at the the head of
// this file, and in builder.h.
//
// Look in builderPrimTempl.h and builderAttribTempl.h
// for most of the interface to BuilderPrim.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG BuilderPrim : public BuilderPrimTempl<BuilderVertex> {
public:
BuilderPrim() {}
BuilderPrim &nonindexed_copy(const BuilderPrimTempl<BuilderVertexI> &copy,
const BuilderBucket &bucket);
static void fill_geom(Geom *geom, const PTA_BuilderV &v_array,
GeomBindType n_attr, const PTA_BuilderN &n_array,
GeomBindType t_attr, const PTA_BuilderTC &t_array,
GeomBindType c_attr, const PTA_BuilderC &c_array,
const BuilderBucket &bucket,
int num_prims, int num_components, int num_verts);
};
///////////////////////////////////////////////////////////////////
// Class : BuilderPrimI
// Description : The basic class for passing indexed primitives
// to the builder.
//
// Look in builderPrimTempl.h and builderAttribTempl.h
// for most of the interface to BuilderPrimI.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG BuilderPrimI : public BuilderPrimTempl<BuilderVertexI> {
public:
BuilderPrimI() {}
static void fill_geom(Geom *geom, const PTA_ushort &v_array,
GeomBindType n_attr, PTA_ushort n_array,
GeomBindType t_attr, PTA_ushort t_array,
GeomBindType c_attr, PTA_ushort c_array,
const BuilderBucket &bucket,
int num_prims, int num_components, int num_verts);
};
// Tell GCC that we'll take care of the instantiation explicitly here.
#ifdef __GNUC__
#pragma interface
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,143 @@
// Filename: builderPrimTempl.h
// Created by: drose (11Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERPRIMTEMPL_H
#define BUILDERPRIMTEMPL_H
#include <pandabase.h>
#include "builderVertex.h"
#include "builderAttrib.h"
#include "builderTypes.h"
#include <vector>
/////////////////////////////////////////////////////////////////////
// Class : BuilderPrimTempl
// Description : The main body of BuilderPrim and BuilderPrimI. This
// is a template class on vertex type, which must be
// either BuilderVertex or BuilderVertexI; these classes
// are themselves template classes on vertex type,
// texcoord type, color type, etc.
////////////////////////////////////////////////////////////////////
template <class VTX>
class BuilderPrimTempl : public VTX::Attrib {
public:
typedef VTX Vertex;
typedef TYPENAME VTX::VType VType;
typedef TYPENAME VTX::NType NType;
typedef TYPENAME VTX::TType TType;
typedef TYPENAME VTX::CType CType;
typedef TYPENAME VTX::Attrib DAttrib;
INLINE BuilderPrimTempl();
INLINE BuilderPrimTempl(const BuilderPrimTempl &copy);
INLINE BuilderPrimTempl &operator = (const BuilderPrimTempl &copy);
void remove_doubled_verts(int closed);
bool is_valid() const;
// has_normal() etc. is true if the primitive has a normal, as
// assigned by the user. This is unrelated to the vertices or
// component primitives that may or may not also have normals.
INLINE bool has_normal() const;
INLINE bool has_color() const;
INLINE bool has_pixel_size() const;
// The following has_* functions are based on information derived
// from examining the vertices and the component primitives that
// make up this primitive.
// has_overall_normal() etc. is true if the primitive has a single,
// overall normal shared among all vertices and all component
// primitives, or if its normal was assigned directly via
// set_normal(). For a polygon, this is the polygon normal. For a
// tristrip, this means all triangles share the same normal.
INLINE bool has_overall_normal() const;
INLINE bool has_overall_color() const;
INLINE bool has_overall_pixel_size() const;
// has_vertex_normal() etc. is true if each vertex in the primitive
// has its own normal. It is not true if any vertex does not have a
// normal.
INLINE bool has_vertex_normal() const;
INLINE bool has_vertex_color() const;
INLINE bool has_vertex_texcoord() const;
INLINE bool has_vertex_pixel_size() const;
// has_component_normal() can only be true for aggregate primitive
// types like tristrips. In that case, it is true if each
// individual component (e.g. each triangle of the tristrip) has its
// own normal.
INLINE bool has_component_normal() const;
INLINE bool has_component_color() const;
INLINE bool has_component_pixel_size() const;
// In the above, only one of has_overall_normal(),
// has_vertex_normal(), and has_component_normal() can be true for a
// given primitive. For convenience, the following functions return
// true if any of the above is true:
INLINE bool has_any_normal() const;
INLINE bool has_any_color() const;
INLINE bool has_any_texcoord() const;
INLINE bool has_any_pixel_size() const;
INLINE BuilderPrimTempl &clear();
INLINE BuilderPrimTempl &clear_vertices();
INLINE BuilderPrimTempl &set_attrib(const DAttrib &attrib);
INLINE BuilderPrimType get_type() const;
INLINE BuilderPrimTempl &set_type(BuilderPrimType t);
INLINE NType get_normal() const;
INLINE BuilderPrimTempl &set_normal(const NType &n);
INLINE CType get_color() const;
INLINE BuilderPrimTempl &set_color(const CType &c);
INLINE float get_pixel_size() const;
INLINE BuilderPrimTempl &set_pixel_size(float s);
INLINE BuilderPrimTempl &add_vertex(const Vertex &v);
INLINE int get_num_verts() const;
INLINE Vertex &get_vertex(int n);
INLINE const Vertex &get_vertex(int n) const;
INLINE BuilderPrimTempl &add_component(const DAttrib &attrib);
INLINE int get_num_components() const;
INLINE DAttrib &get_component(int n);
INLINE const DAttrib &get_component(int n) const;
INLINE bool operator < (const BuilderPrimTempl &other) const;
ostream &output(ostream &out) const;
protected:
INLINE int sort_value() const;
void update_overall_attrib();
typedef vector<Vertex> Verts;
typedef vector<DAttrib> Components;
Verts _verts;
Components _components;
BuilderPrimType _type;
int _overall;
};
template <class VTX>
INLINE ostream &operator << (ostream &out,
const BuilderPrimTempl<VTX> &prim) {
return prim.output(out);
}
#include "builderPrimTempl.I"
#endif

View File

@@ -0,0 +1,116 @@
// Filename: builderProperties.cxx
// Created by: drose (17Sep97)
//
////////////////////////////////////////////////////////////////////
#include "builderProperties.h"
////////////////////////////////////////////////////////////////////
// Function: BuilderProperties::Ordering operator
// Access: Public
// Description: Defines an arbitrary ordering among different
// properties, and groups identical sets of properties
// together. This operator is used for the more
// important task of grouping BuilderBuckets together;
// see the comments for the similar function in
// builderBucket.cxx.
////////////////////////////////////////////////////////////////////
bool BuilderProperties::
operator < (const BuilderProperties &other) const {
int sv1 = sort_value();
int sv2 = other.sort_value();
if (sv1 != sv2) {
return sv1 < sv2;
}
if (_coplanar_threshold != other._coplanar_threshold) {
return _coplanar_threshold < other._coplanar_threshold;
}
if (_max_tfan_angle != other._max_tfan_angle) {
return _max_tfan_angle < other._max_tfan_angle;
}
if (_min_tfan_tris != other._min_tfan_tris) {
return _min_tfan_tris < other._min_tfan_tris;
}
if (_show_normals) {
if (_normal_scale != other._normal_scale) {
return _normal_scale < other._normal_scale;
}
if (_normal_color != other._normal_color) {
return _normal_color < other._normal_color;
}
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderPrimTempl::output
// Access: Public
// Description: Outputs the properties meaningfully.
////////////////////////////////////////////////////////////////////
void BuilderProperties::
output(ostream &out) const {
if (_mesh) {
out << "T-Mesh using Mesher\n";
if (_show_tstrips) {
out << "Color individual tristrips\n";
} else if (_show_qsheets) {
out << "Color individual quadsheets\n";
} else if (_show_quads) {
out << "Color individual quads\n";
}
if (_retesselate_coplanar) {
out << "Retesselate coplanar triangles when needed; threshold = "
<< _coplanar_threshold << "\n";
}
}
if (_subdivide_polys) {
out << "Subdivide polygons into tris.\n";
}
if (_consider_fans) {
out << "Look for possible triangle fans with max per-triangle angle of "
<< _max_tfan_angle << " degrees.\n";
if (_min_tfan_tris==0) {
out << "Do not create tfans";
} else {
out << "Do not create tfans smaller than " << _min_tfan_tris << " tris";
}
if (_unroll_fans) {
out << "; retesselate to tstrips.\n";
} else {
out << ".\n";
}
}
}
////////////////////////////////////////////////////////////////////
// Function: BuilderPrimTempl::sort_value
// Access: Protected
// Description: Returns a number for grouping properties. This is
// used as a helper function to the ordering operator,
// above. It simply collects all the booleans together
// into a single number.
////////////////////////////////////////////////////////////////////
int BuilderProperties::
sort_value() const {
return
((_mesh!=0) << 8) |
((_show_tstrips!=0) << 7) |
((_show_qsheets!=0) << 6) |
((_show_quads!=0) << 5) |
((_show_normals!=0) << 4) |
((_retesselate_coplanar!=0) << 3) |
((_unroll_fans!=0) << 2) |
((_subdivide_polys!=0) << 1) |
((_consider_fans!=0) << 0);
}

View File

@@ -0,0 +1,115 @@
// Filename: builderProperties.h
// Created by: drose (17Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERPROPERTIES_H
#define BUILDERPROPERTIES_H
#include <pandabase.h>
#include "builderTypes.h"
#ifndef WIN32_VC
#include <stl_config.h>
#endif
////////////////////////////////////////////////////////////////////
// Class : BuilderProperties
// Description : A class which defines several parameters used to
// control specific behavior of the builder and mesher.
// BuilderBucket inherits from this class, so each of
// these properties may be set directly on a
// BuilderBucket to control the geometry made with just
// that bucket. There may in this way be several
// different sets of properties in effect at a given
// time.
//
// The initial values for these are set in the private
// constructor to BuilderBucket, at the bottom of
// builderBucket.cxx.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG BuilderProperties {
public:
bool operator < (const BuilderProperties &other) const;
void output(ostream &out) const;
// If this is true, the mesher will be invoked to break up large
// polygons and build triangles into tristrips wherever possible.
bool _mesh;
// If this is true, a pair of adjacent coplanar triangles that form
// a quad may be replaced with a pair of triangles forming the same
// quad but with the opposite diagonal, if this will help the
// building of tristrips.
bool _retesselate_coplanar;
// If this is true, a coplanar fan may be treated as a single large
// polygon, and then subdivided into a single tristrip, instead of
// treating it as a fan. This can sometimes help form longer
// continuous tristrips.
bool _unroll_fans;
// The following three flags serve to illustrate the mesher's
// effectiveness by coloring geometry.
// This colors each created triangle strip with a random color. The
// first triangle of each strip is a little darker than the rest of
// the strip.
bool _show_tstrips;
// This colors each rectangular group of quads--called a quadsheet
// by the mesher--with a random color. The mesher always creates
// linear tristrips across whatever quadsheets it can identify.
bool _show_qsheets;
// This colors quads blue, and doesn't mesh them further. Since a
// large part of the mesher's algorithm is reassembling adjacent
// triangles into quads, it's sometimes helpful to see where it
// thinks the best quads lie.
bool _show_quads;
// This shows normals created by creating little colored line
// segments to represent each normal.
bool _show_normals;
double _normal_scale;
BuilderC _normal_color;
// If this is true, large polygons will be subdivided into
// triangles. Otherwise, they will remain large polygons.
bool _subdivide_polys;
// This is the flatness tolerance below which two polygons will be
// considered coplanar. Making it larger makes it easier for the
// mesher to reverse triangle diagonals to achieve a good mesh, at
// the expense of precision of the surface.
double _coplanar_threshold;
// True if fans are to be considered at all. Sometimes making fans
// is more trouble than they're worth, since they tend to get in the
// way of long tristrips.
bool _consider_fans;
// The maximum average angle of the apex of each triangle involved
// in a fan. If the triangles are more loosely packed than this,
// don't consider putting them into a fan.
double _max_tfan_angle;
// The minimum number of triangles to be involved in a fan. Setting
// this number lower results in more fans, probably at the expense
// of tristrips. However, setting it to zero means no tfans will be
// built (although fans may still be unrolled into tstrips if
// _unroll_fans is true).
int _min_tfan_tris;
protected:
int sort_value() const;
};
INLINE ostream &operator << (ostream &out, const BuilderProperties &props) {
props.output(out);
return out;
}
#endif

View File

@@ -0,0 +1,102 @@
// Filename: builderTypes.cxx
// Created by: drose (11Sep97)
//
////////////////////////////////////////////////////////////////////
#include "builderTypes.h"
#include <notify.h>
ostream &operator << (ostream &out, BuilderAttribFlags baf) {
const char *space = "";
if (baf & BAF_coord) {
out << space << "coord";
space = " ";
}
if (baf & BAF_normal) {
out << space << "normal";
space = " ";
}
if (baf & BAF_texcoord) {
out << space << "texcoord";
space = " ";
}
if (baf & BAF_color) {
out << space << "color";
space = " ";
}
if (baf & BAF_pixel_size) {
out << space << "pixel_size";
space = " ";
}
if (baf & BAF_overall_updated) {
out << space << "overall_updated";
space = " ";
}
if (baf & BAF_overall_normal) {
out << space << "overall_normal";
space = " ";
}
if (baf & BAF_overall_color) {
out << space << "overall_color";
space = " ";
}
if (baf & BAF_overall_pixel_size) {
out << space << "overall_pixel_size";
space = " ";
}
if (baf & BAF_vertex_normal) {
out << space << "vertex_normal";
space = " ";
}
if (baf & BAF_vertex_texcoord) {
out << space << "vertex_texcoord";
space = " ";
}
if (baf & BAF_vertex_color) {
out << space << "vertex_color";
space = " ";
}
if (baf & BAF_vertex_pixel_size) {
out << space << "vertex_pixel_size";
space = " ";
}
if (baf & BAF_component_normal) {
out << space << "component_normal";
space = " ";
}
if (baf & BAF_component_color) {
out << space << "component_color";
space = " ";
}
if (baf & BAF_component_pixel_size) {
out << space << "component_pixel_size";
space = " ";
}
return out;
}
ostream &operator << (ostream &out, BuilderPrimType bpt) {
switch (bpt) {
case BPT_poly:
return out << "poly";
case BPT_point:
return out << "point";
case BPT_line:
return out << "line";
case BPT_tri:
return out << "tri";
case BPT_tristrip:
return out << "tristrip";
case BPT_trifan:
return out << "trifan";
case BPT_quad:
return out << "quad";
case BPT_quadstrip:
return out << "quadstrip";
}
nassertr(false, out);
return out << "(**invalid**)";
}

View File

@@ -0,0 +1,221 @@
// Filename: builderTypes.h
// Created by: drose (11Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERTYPES_H
#define BUILDERTYPES_H
#include <pandabase.h>
#include <luse.h>
#include <typedef.h>
#ifndef WIN32_VC
#include <stl_config.h>
#endif
static const float nearly_zero = 0.0001;
// The BuilderVec classes are a series of proxies around Vertexf,
// Normalf, TexCoordf, and Colorf. They're useful for building
// collections of these vertex values, and provide handy things like
// (almost) equivalence operators and sorting operators.
// The BuilderVec's each have a special constructor with a single int.
// These constructors create an instance of the vector with all values
// initialized to zero. This is a cheat to create a uniform way to create
// a zero-valued VType, CType, or TType without knowing whether the type
// is indexed (a ushort) or nonindexed (a BuilderVec).
class EXPCL_PANDAEGG BuilderTC {
public:
BuilderTC() {}
BuilderTC(int) : _v(0.0, 0.0) {}
BuilderTC(const TexCoordf &v) : _v(v) {}
BuilderTC(const TexCoordd &v) : _v(v[0], v[1]) {}
BuilderTC(const BuilderTC &copy) : _v(copy._v) {}
operator TexCoordf & () {
return _v;
}
operator const TexCoordf & () const {
return _v;
}
float operator [] (int n) const { return _v[n]; }
float &operator [] (int n) { return _v[n]; }
BuilderTC &operator = (const BuilderTC &copy) {
_v = copy._v;
return *this;
}
bool operator == (const BuilderTC &other) const {
return _v.almost_equal(other._v, nearly_zero);
}
// The < operator is simply for ordering vectors in a sorted
// container; it has no useful mathematical meaning.
bool operator < (const BuilderTC &other) const {
return (_v.compare_to(other._v) < 0);
}
TexCoordf _v;
};
class EXPCL_PANDAEGG BuilderV {
public:
BuilderV() {}
BuilderV(int) : _v(0.0, 0.0, 0.0) {}
BuilderV(const Vertexf &v) : _v(v) {}
BuilderV(const Vertexd &v) : _v(v[0], v[1], v[2]) {}
BuilderV(const BuilderV &copy) : _v(copy._v) {}
operator Vertexf & () {
return _v;
}
operator const Vertexf & () const {
return _v;
}
float operator [] (int n) const { return _v[n]; }
float &operator [] (int n) { return _v[n]; }
BuilderV &operator = (const BuilderV &copy) {
_v = copy._v;
return *this;
}
bool operator == (const BuilderV &other) const {
return _v.almost_equal(other._v, nearly_zero);
}
bool operator < (const BuilderV &other) const {
return (_v.compare_to(other._v) < 0);
}
Vertexf _v;
};
class EXPCL_PANDAEGG BuilderN {
public:
BuilderN() {}
BuilderN(int) : _v(0.0, 0.0, 0.0) {}
BuilderN(const Normalf &v) : _v(v) {}
BuilderN(const Normald &v) : _v(v[0], v[1], v[2]) {}
BuilderN(const BuilderN &copy) : _v(copy._v) {}
operator Normalf & () {
return _v;
}
operator const Normalf & () const {
return _v;
}
float operator [] (int n) const { return _v[n]; }
float &operator [] (int n) { return _v[n]; }
BuilderN &operator = (const BuilderN &copy) {
_v = copy._v;
return *this;
}
bool operator == (const BuilderN &other) const {
return _v.almost_equal(other._v, nearly_zero);
}
bool operator < (const BuilderN &other) const {
return (_v.compare_to(other._v) < 0);
}
Normalf _v;
};
class EXPCL_PANDAEGG BuilderC {
public:
BuilderC() {}
BuilderC(int) : _v(0.0, 0.0, 0.0, 0.0) {}
BuilderC(const Colorf &v) : _v(v) {}
BuilderC(const Colord &v) : _v(v[0], v[1], v[2], v[3]) {}
BuilderC(const BuilderC &copy) : _v(copy._v) {}
operator Colorf & () {
return _v;
}
operator const Colorf & () const {
return _v;
}
float operator [] (int n) const { return _v[n]; }
float &operator [] (int n) { return _v[n]; }
BuilderC &operator = (const BuilderC &copy) {
_v = copy._v;
return *this;
}
bool operator != (const BuilderC &other) const {
return !(*this == other);
}
bool operator == (const BuilderC &other) const {
return _v.almost_equal(other._v, nearly_zero);
}
bool operator < (const BuilderC &other) const {
return (_v.compare_to(other._v) < 0);
}
Colorf _v;
};
INLINE ostream &operator << (ostream &out, const BuilderTC &v) {
return out << "(" << v[0] << " " << v[1] << ")";
}
INLINE ostream &operator << (ostream &out, const BuilderV &v) {
return out << "(" << v[0] << " " << v[1] << " " << v[2] << ")";
}
INLINE ostream &operator << (ostream &out, const BuilderN &v) {
return out << "(" << v[0] << " " << v[1] << " " << v[2] << ")";
}
INLINE ostream &operator << (ostream &out, const BuilderC &v) {
return out << "(" << v[0] << " " << v[1] << " " << v[2] << " "
<< v[3] << ")";
}
enum BuilderAttribFlags {
BAF_coord = 0x00001,
BAF_normal = 0x00002,
BAF_texcoord = 0x00004,
BAF_color = 0x00008,
BAF_pixel_size = 0x00010,
BAF_overall_updated = 0x00100,
BAF_overall_normal = 0x00200,
BAF_overall_color = 0x00400,
BAF_overall_pixel_size = 0x00800,
BAF_vertex_normal = 0x01000,
BAF_vertex_texcoord = 0x02000,
BAF_vertex_color = 0x04000,
BAF_vertex_pixel_size = 0x08000,
BAF_component_normal = 0x10000,
BAF_component_color = 0x20000,
BAF_component_pixel_size = 0x04000,
};
ostream &operator << (ostream &out, BuilderAttribFlags baf);
enum BuilderPrimType {
BPT_poly,
BPT_point,
BPT_line,
// The following types are generated internally by the builder and
// mesher. Normally they will not be seen by the user.
BPT_tri,
BPT_tristrip,
BPT_trifan,
BPT_quad,
BPT_quadstrip,
};
ostream &operator << (ostream &out, BuilderPrimType bpt);
#endif

View File

@@ -0,0 +1,265 @@
// Filename: builderVertex.I
// Created by: drose (18Sep97)
//
////////////////////////////////////////////////////////////////////
#include <notify.h>
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::set_coord_value
// Access: Public
// Description: Reassigns the vertex coordinate, without knowing
// whether the vertex is indexed or nonindexed. A
// nonindexed vertex will look up the index in the array
// and store the resulting value, while an indexed
// vertex will just store the index number (which
// assumes the array is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderVertex::
set_coord_value(const BuilderV *array, ushort index) {
set_coord(array[index]);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::set_normal_value
// Access: Public
// Description: Reassigns the vertex normal, without knowing whether
// the vertex is indexed or nonindexed. A nonindexed
// vertex will look up the index in the array and store
// the resulting value, while an indexed vertex will
// just store the index number (which assumes the array
// is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderVertex::
set_normal_value(const BuilderN *array, ushort index) {
set_normal(array[index]);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::set_texcoord_value
// Access: Public
// Description: Reassigns the vertex texture coordinate, without
// knowing whether the vertex is indexed or nonindexed.
// A nonindexed vertex will look up the index in the
// array and store the resulting value, while an indexed
// vertex will just store the index number (which
// assumes the array is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderVertex::
set_texcoord_value(const BuilderTC *array, ushort index) {
set_texcoord(array[index]);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::set_color_value
// Access: Public
// Description: Reassigns the vertex color, without knowing whether
// the vertex is indexed or nonindexed. A nonindexed
// vertex will look up the index in the array and store
// the resulting value, while an indexed vertex will
// just store the index number (which assumes the array
// is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderVertex::
set_color_value(const BuilderC *array, ushort index) {
set_color(array[index]);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::get_coord_value
// Access: Public
// Description: Returns the actual coordinate value of the vertex,
// whether it is indexed or nonindexed. Normally, the
// value returned by get_coord(), which will be either a
// BuilderV or a ushort, is sufficient, but there are
// occasional times when it is necessary to get the
// actual location in space of the vertex position (for
// instance, to subdivide a concave polygon).
//
// This function returns the actual coordinate value.
// For a nonindexed vertex, its return value is the same
// as get_coord(); for an indexed vertex, it looks up
// the vertex's index in the bucket's coord array, and
// returns that value.
//
// Note that this makes some perhaps unwarranted
// assumptions about indexed geometry; specifically,
// that its value is valid at creation time, and that it
// won't change too drastically during runtime.
////////////////////////////////////////////////////////////////////
INLINE BuilderV BuilderVertex::
get_coord_value(const BuilderBucket &) const {
return get_coord();
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::get_normal_value
// Access: Public
// Description: Returns the actual normal value of the vertex,
// whether it is indexed or nonindexed. See
// get_coord_value().
////////////////////////////////////////////////////////////////////
INLINE BuilderN BuilderVertex::
get_normal_value(const BuilderBucket &) const {
return get_normal();
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::get_texcoord_value
// Access: Public
// Description: Returns the actual texture coordinate value of the
// vertex, whether it is indexed or nonindexed. See
// get_coord_value().
////////////////////////////////////////////////////////////////////
INLINE BuilderTC BuilderVertex::
get_texcoord_value(const BuilderBucket &) const {
return get_texcoord();
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::get_color_value
// Access: Public
// Description: Returns the actual color value of the vertex,
// whether it is indexed or nonindexed. See
// get_coord_value().
////////////////////////////////////////////////////////////////////
INLINE BuilderC BuilderVertex::
get_color_value(const BuilderBucket &) const {
return get_color();
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::set_coord_value
// Access: Public
// Description: Reassigns the vertex coordinate, without knowing
// whether the vertex is indexed or nonindexed. A
// nonindexed vertex will look up the index in the array
// and store the resulting value, while an indexed
// vertex will just store the index number (which
// assumes the array is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderVertexI::
set_coord_value(const BuilderV *, ushort index) {
set_coord(index);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::set_normal_value
// Access: Public
// Description: Reassigns the vertex normal, without knowing whether
// the vertex is indexed or nonindexed. A nonindexed
// vertex will look up the index in the array and store
// the resulting value, while an indexed vertex will
// just store the index number (which assumes the array
// is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderVertexI::
set_normal_value(const BuilderN *, ushort index) {
set_normal(index);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::set_texcoord_value
// Access: Public
// Description: Reassigns the vertex texture coordinate, without
// knowing whether the vertex is indexed or nonindexed.
// A nonindexed vertex will look up the index in the
// array and store the resulting value, while an indexed
// vertex will just store the index number (which
// assumes the array is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderVertexI::
set_texcoord_value(const BuilderTC *, ushort index) {
set_texcoord(index);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::set_color_value
// Access: Public
// Description: Reassigns the vertex color, without knowing whether
// the vertex is indexed or nonindexed. A nonindexed
// vertex will look up the index in the array and store
// the resulting value, while an indexed vertex will
// just store the index number (which assumes the array
// is the same one it's indexing on).
////////////////////////////////////////////////////////////////////
INLINE void BuilderVertexI::
set_color_value(const BuilderC *, ushort index) {
set_color(index);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::get_coord_value
// Access: Public
// Description: Returns the actual coordinate value of the vertex,
// whether it is indexed or nonindexed. Normally, the
// value returned by get_coord(), which will be either a
// BuilderV or a ushort, is sufficient, but there are
// occasional times when it is necessary to get the
// actual location in space of the vertex position (for
// instance, to subdivide a concave polygon).
//
// This function returns the actual coordinate value.
// For a nonindexed vertex, its return value is the same
// as get_coord(); for an indexed vertex, it looks up
// the vertex's index in the bucket's coord array, and
// returns that value.
//
// Note that this makes some perhaps unwarranted
// assumptions about indexed geometry; specifically,
// that its value is valid at creation time, and that it
// won't change too drastically during runtime.
////////////////////////////////////////////////////////////////////
INLINE BuilderV BuilderVertexI::
get_coord_value(const BuilderBucket &bucket) const {
nassertr(bucket.get_coords() != (Vertexf *)NULL, BuilderV());
return bucket.get_coords()[get_coord()];
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::get_normal_value
// Access: Public
// Description: Returns the actual normal value of the vertex,
// whether it is indexed or nonindexed. See
// get_coord_value().
////////////////////////////////////////////////////////////////////
INLINE BuilderN BuilderVertexI::
get_normal_value(const BuilderBucket &bucket) const {
nassertr(bucket.get_normals() != (Normalf *)NULL, BuilderN());
return bucket.get_normals()[get_normal()];
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::get_texcoord_value
// Access: Public
// Description: Returns the actual texture coordinate value of the
// vertex, whether it is indexed or nonindexed. See
// get_coord_value().
////////////////////////////////////////////////////////////////////
INLINE BuilderTC BuilderVertexI::
get_texcoord_value(const BuilderBucket &bucket) const {
nassertr(bucket.get_texcoords() != (TexCoordf *)NULL, BuilderTC());
return bucket.get_texcoords()[get_texcoord()];
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertex::get_color_value
// Access: Public
// Description: Returns the actual color value of the vertex,
// whether it is indexed or nonindexed. See
// get_coord_value().
////////////////////////////////////////////////////////////////////
INLINE BuilderC BuilderVertexI::
get_color_value(const BuilderBucket &bucket) const {
nassertr(bucket.get_colors() != (Colorf *)NULL, BuilderC());
return bucket.get_colors()[get_color()];
}

View File

@@ -0,0 +1,12 @@
// Filename: builderVertex.cxx
// Created by: drose (11May00)
//
////////////////////////////////////////////////////////////////////
#include "builderAttrib.h"
#include "builderVertex.h"
// Tell GCC that we'll take care of the instantiation explicitly here.
#ifdef __GNUC__
#pragma implementation
#endif

View File

@@ -0,0 +1,119 @@
// Filename: builderVertex.h
// Created by: drose (18Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERVERTEX_H
#define BUILDERVERTEX_H
///////////////////////////////////////////////////////////////////
//
// BuilderVertex, BuilderVertexI
//
// The basic class for passing vertex values to the builder. See the
// comments at the beginning of builder.h and builderPrim.h.
//
// Like BuilderPrim, the BuilderVertex and BuilderVertexI classes are
// actually two different instantiations of the same template class,
// BuilderVertexTempl. The difference is in the types of the
// attribute values for the four kinds of attributes: vertices
// (coords), normals, texture coordinates, and colors. BuilderVertex
// specifies Coordf, Normalf, TexCoordf, and Colorf for each of these
// (actually, it's BuilderV, BuilderN, BuilderTC, and BuilderC, which
// are simply wrappers around the above types), while BuilderVertexI
// specifies ushort for all of them.
//
// It is this templating that drives the whole indexed/nonindexed
// support in this package and in the mesher. The two kinds of
// BuilderVertex are designed to present largely the same interface,
// regardless of whether its component values are actual vector
// values, or simply index numbers. Lots of things, therefore, can
// template on the BuilderPrim type (which in turn termplates on the
// BuilderVertex type) and thus easily support both indexed and
// nonindexed geometry.
//
///////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "builderAttrib.h"
#include "builderVertexTempl.h"
#include "builderBucket.h"
// We need to define this temporary macro so we can pass a parameter
// containing a comma through the macro.
#define BUILDERVERTEXTEMPL_BUILDERV BuilderVertexTempl<BuilderV, BuilderN, BuilderTC, BuilderC>
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, BUILDERVERTEXTEMPL_BUILDERV);
#define BUILDERVERTEXTEMPL_USHORT BuilderVertexTempl<ushort, ushort, ushort, ushort>
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, BUILDERVERTEXTEMPL_USHORT);
/////////////////////////////////////////////////////////////////////
// Class : BuilderVertex
// Description : The basic class for passing nonindexed vertices to
// the builder. See the comments at the the head of
// this file, and in builder.h.
//
// Look in builderVertexTempl.h and builderAttribTempl.h
// for most of the interface to BuilderVertex.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG BuilderVertex
: public BuilderVertexTempl<BuilderV, BuilderN, BuilderTC, BuilderC> {
public:
typedef BuilderAttrib Attrib;
BuilderVertex() {}
BuilderVertex(const BuilderV &c) :
BuilderVertexTempl<BuilderV, BuilderN, BuilderTC, BuilderC>(c) {}
INLINE void set_coord_value(const BuilderV *array, ushort index);
INLINE void set_normal_value(const BuilderN *array, ushort index);
INLINE void set_texcoord_value(const BuilderTC *array, ushort index);
INLINE void set_color_value(const BuilderC *array, ushort index);
INLINE BuilderV get_coord_value(const BuilderBucket &bucket) const;
INLINE BuilderN get_normal_value(const BuilderBucket &bucket) const;
INLINE BuilderTC get_texcoord_value(const BuilderBucket &bucket) const;
INLINE BuilderC get_color_value(const BuilderBucket &bucket) const;
};
/////////////////////////////////////////////////////////////////////
// Class : BuilderVertexI
// Description : The basic class for passing indexed vertices to the
// builder. See the comments at the the head of this
// file, and in builder.h.
//
// Look in builderVertexTempl.h and builderAttribTempl.h
// for most of the interface to BuilderVertex.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG BuilderVertexI
: public BuilderVertexTempl<ushort, ushort, ushort, ushort> {
public:
typedef BuilderAttribI Attrib;
BuilderVertexI() {}
BuilderVertexI(ushort c) :
BuilderVertexTempl<ushort, ushort, ushort, ushort>(c) {}
INLINE void set_coord_value(const BuilderV *array, ushort index);
INLINE void set_normal_value(const BuilderN *array, ushort index);
INLINE void set_texcoord_value(const BuilderTC *array, ushort index);
INLINE void set_color_value(const BuilderC *array, ushort index);
INLINE BuilderV get_coord_value(const BuilderBucket &bucket) const;
INLINE BuilderN get_normal_value(const BuilderBucket &bucket) const;
INLINE BuilderTC get_texcoord_value(const BuilderBucket &bucket) const;
INLINE BuilderC get_color_value(const BuilderBucket &bucket) const;
};
#include "builderVertex.I"
// Tell GCC that we'll take care of the instantiation explicitly here.
#ifdef __GNUC__
#pragma interface
#endif
#endif

View File

@@ -0,0 +1,291 @@
// Filename: builderVertexTempl.I
// Created by: drose (11Sep97)
//
////////////////////////////////////////////////////////////////////
#include <notify.h>
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT>::
BuilderVertexTempl() {
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::Constructor (with VType)
// Access: Public
// Description: Initializes the vertex coordinate with an initial
// value. A handy constructor.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT>::
BuilderVertexTempl(const VType &c) {
set_coord(c);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::Copy constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT>::
BuilderVertexTempl(const BuilderVertexTempl &copy) {
(*this) = copy;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::Copy assignment operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
operator = (const BuilderVertexTempl<VT, NT, TT, CT> &copy) {
BuilderAttribTempl<VT, NT, TT, CT>::operator = (copy);
_coord = copy._coord;
_texcoord = copy._texcoord;
_pixel_size = copy._pixel_size;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::is_valid
// Access: Public
// Description: Returns true if the vertex is valid, i.e. if it has a
// vertex coordinate.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE bool BuilderVertexTempl<VT, NT, TT, CT>::
is_valid() const {
return has_coord();
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::clear
// Access: Public
// Description: Resets the vertex to its initial, empty state.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
clear() {
BuilderAttribTempl<VT, NT, TT, CT>::clear();
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::has_coord
// Access: Public
// Description: Returns true if the vertex has a vertex coordinate.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE bool BuilderVertexTempl<VT, NT, TT, CT>::
has_coord() const {
return _flags & BAF_coord;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::get_coord
// Access: Public
// Description: Returns the vertex's coordinate. It is an error to
// call this without first verifying that has_coord() is
// true.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT>::VType BuilderVertexTempl<VT, NT, TT, CT>::
get_coord() const {
nassertr(has_coord(), _coord);
return _coord;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::set_coord
// Access: Public
// Description: Resets the vertex's coordinate.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
set_coord(const VType &c) {
_flags |= BAF_coord;
_coord = c;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::set_normal
// Access: Public
// Description: Resets the vertex's normal. This is overridden from
// BuilderAttrib just so we can typecast the return
// value to BuilderVertex. The other functions,
// has_normal() and get_normal(), are inherited
// untouched from BuilderAttrib.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
set_normal(const NType &n) {
BuilderAttribTempl<VT, NT, TT, CT>::set_normal(n);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::has_texcoord
// Access: Public
// Description: Returns true if the vertex has a texture coordinate.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE bool BuilderVertexTempl<VT, NT, TT, CT>::
has_texcoord() const {
return (_flags & BAF_texcoord) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::set_texcoord
// Access: Public
// Description: Resets the vertex's texture coordinate.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
set_texcoord(const TType &t) {
_flags |= BAF_texcoord;
_texcoord = t;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::get_texcoord
// Access: Public
// Description: Returns the vertex's texture coordinate. It is an
// error to call this without first verifying that
// has_texcoord() is true.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT>::TType BuilderVertexTempl<VT, NT, TT, CT>::
get_texcoord() const {
nassertr(has_texcoord(), _texcoord);
return _texcoord;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::set_color
// Access: Public
// Description: Resets the vertex's color. This is overridden from
// BuilderAttrib just so we can typecast the return
// value to BuilderVertex. The other functions,
// has_color() and get_color(), are inherited
// untouched from BuilderAttrib.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
set_color(const CType &c) {
BuilderAttribTempl<VT, NT, TT, CT>::set_color(c);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::set_pixel_size
// Access: Public
// Description: Resets the vertex's pixel_size. This is overridden
// from BuilderAttrib just so we can typecast the return
// value to BuilderVertex. The other functions,
// has_pixel_size() and get_pixel_size(), are inherited
// untouched from BuilderAttrib.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
set_pixel_size(float s) {
BuilderAttribTempl<VT, NT, TT, CT>::set_pixel_size(s);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::operator ==
// Access: Public
// Description: Assigns an ordering to the vertices. This is used by
// the Mesher to group identical vertices. This assumes
// that all vertices in the locus of consideration will
// share the same state: with or without normals,
// texcoords, etc.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
bool BuilderVertexTempl<VT, NT, TT, CT>::
operator == (const BuilderVertexTempl<VT, NT, TT, CT> &other) const {
if (has_coord() && !(_coord == other._coord))
return false;
if (has_texcoord() && !(_texcoord == other._texcoord))
return false;
return BuilderAttribTempl<VT, NT, TT, CT>::operator == (other);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::operator <
// Access: Public
// Description: Assigns an ordering to the vertices. This is used by
// the Mesher to group identical vertices. This assumes
// that all vertices to be meshed together must share
// the same state: with or without normals, texcoords,
// etc.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
bool BuilderVertexTempl<VT, NT, TT, CT>::
operator < (const BuilderVertexTempl<VT, NT, TT, CT> &other) const {
if (has_coord() && !(_coord == other._coord))
return _coord < other._coord;
if (has_texcoord() && !(_texcoord == other._texcoord))
return _texcoord < other._texcoord;
return BuilderAttribTempl<VT, NT, TT, CT>::operator < (other);
}
////////////////////////////////////////////////////////////////////
// Function: BuilderVertexTempl::output
// Access: Public
// Description: Formats the vertex for output in some sensible way.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
ostream &BuilderVertexTempl<VT, NT, TT, CT>::
output(ostream &out) const {
if (this!=NULL) {
if (has_coord()) {
out << get_coord();
}
/*
if (has_normal()) {
out << " normal " << get_normal();
}
if (has_texcoord()) {
out << " texcoord " << get_texcoord();
}
if (has_color()) {
out << " color " << get_color();
}
if (has_pixel_size()) {
out << " pixel_size " << get_pixel_size();
}
*/
}
return out;
}

View File

@@ -0,0 +1,73 @@
// Filename: builderVertexTempl.h
// Created by: drose (09Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef BUILDERVERTEXTEMPL_H
#define BUILDERVERTEXTEMPL_H
#include <pandabase.h>
#include "builderTypes.h"
#include "builderAttribTempl.h"
#include <vector>
/////////////////////////////////////////////////////////////////////
// Class : BuilderVertexTempl
// Description : The main body of BuilderVertex and BuilderVertexI.
// This is a template class on each of the four
// attribute types: vertex coordinates, normal, texture
// coordinates, and color. See builderVertex.h.
////////////////////////////////////////////////////////////////////
template <class VT, class NT, class TT, class CT>
class BuilderVertexTempl : public BuilderAttribTempl<VT, NT, TT, CT> {
public:
typedef VT VType;
typedef NT NType;
typedef TT TType;
typedef CT CType;
INLINE BuilderVertexTempl();
INLINE BuilderVertexTempl(const VType &c);
INLINE BuilderVertexTempl(const BuilderVertexTempl &copy);
INLINE BuilderVertexTempl &operator = (const BuilderVertexTempl &copy);
INLINE bool is_valid() const;
INLINE BuilderVertexTempl &clear();
INLINE bool has_coord() const;
INLINE VType get_coord() const;
INLINE BuilderVertexTempl &set_coord(const VType &c);
INLINE BuilderVertexTempl &set_normal(const NType &c);
INLINE bool has_texcoord() const;
INLINE TType get_texcoord() const;
INLINE BuilderVertexTempl &set_texcoord(const TType &t);
INLINE BuilderVertexTempl &set_color(const CType &c);
INLINE BuilderVertexTempl &set_pixel_size(float s);
bool operator == (const BuilderVertexTempl &other) const;
bool operator < (const BuilderVertexTempl &other) const;
ostream &output(ostream &out) const;
protected:
VType _coord;
TType _texcoord;
};
template <class VT, class NT, class TT, class CT>
INLINE ostream &operator << (ostream &out,
const BuilderVertexTempl<VT, NT, TT, CT> &vertex) {
return vertex.output(out);
}
#include "builderVertexTempl.I"
#endif

View File

@@ -0,0 +1,14 @@
// Filename: config_builder.cxx
// Created by: drose (29Feb00)
//
////////////////////////////////////////////////////////////////////
#include "config_builder.h"
#include <dconfig.h>
Configure(config_builder);
NotifyCategoryDef(builder, "");
ConfigureFn(config_builder) {
}

View File

@@ -0,0 +1,14 @@
// Filename: config_builder.h
// Created by: drose (29Feb00)
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_BUILDER_H
#define CONFIG_BUILDER_H
#include <pandabase.h>
#include <notifyCategoryProxy.h>
NotifyCategoryDecl(builder, EXPCL_PANDAEGG, EXPTP_PANDAEGG);
#endif

View File

@@ -0,0 +1,11 @@
// Filename: mesher.cxx
// Created by: drose (11May00)
//
////////////////////////////////////////////////////////////////////
#include "mesher.h"
// Tell GCC that we'll take care of the instantiation explicitly here.
#ifdef __GNUC__
#pragma implementation
#endif

View File

@@ -0,0 +1,42 @@
// Filename: mesher.h
// Created by: drose (17Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef MESHER_H
#define MESHER_H
#include <pandabase.h>
#include "mesherFanMaker.h"
#include "mesherEdge.h"
#include "mesherStrip.h"
#include "mesherTempl.h"
#include "builderPrim.h"
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, MesherFanMaker<BuilderPrim>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, MesherEdge<BuilderPrim>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, MesherStrip<BuilderPrim>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, MesherTempl<BuilderPrim>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, MesherFanMaker<BuilderPrimI>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, MesherEdge<BuilderPrimI>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, MesherStrip<BuilderPrimI>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, MesherTempl<BuilderPrimI>);
class EXPCL_PANDAEGG Mesher : public MesherTempl<BuilderPrim> {
public:
Mesher(BuilderBucket *bucket) : MesherTempl<BuilderPrim>(bucket) {}
};
class EXPCL_PANDAEGG MesherI : public MesherTempl<BuilderPrimI> {
public:
MesherI(BuilderBucket *bucket) : MesherTempl<BuilderPrimI>(bucket) {}
};
// Tell GCC that we'll take care of the instantiation explicitly here.
#ifdef __GNUC__
#pragma interface
#endif
#endif

View File

@@ -0,0 +1,143 @@
// Filename: mesherEdge.I
// Created by: drose (15Sep97)
//
////////////////////////////////////////////////////////////////////
template <class PrimType>
INLINE MesherEdge<PrimType>::
MesherEdge(const Vertex *a, const Vertex *b) : _a(a), _b(b) {
_opposite = NULL;
}
template <class PrimType>
INLINE MesherEdge<PrimType>::
MesherEdge(const MesherEdge &copy) :
_a(copy._a),
_b(copy._b),
_strips(copy._strips),
_opposite(copy._opposite)
{
}
template <class PrimType>
INLINE bool MesherEdge<PrimType>::
contains_vertex(const Vertex *v) const {
return (_a==v || _b==v);
}
template <class PrimType>
INLINE bool MesherEdge<PrimType>::
matches(const MesherEdge &other) const {
return (_a == other._a && _b == other._b) ||
(_b == other._a && _a == other._b);
}
template <class PrimType>
INLINE MesherEdge<PrimType> *MesherEdge<PrimType>::
common_ptr() {
return min(this, _opposite);
}
template <class PrimType>
INLINE bool MesherEdge<PrimType>::
operator == (const MesherEdge &other) const {
return _a == other._a && _b == other._b;
}
template <class PrimType>
INLINE bool MesherEdge<PrimType>::
operator < (const MesherEdge &other) const {
return _a < other._a || (_a == other._a && _b < other._b);
}
template <class PrimType>
INLINE float MesherEdge<PrimType>::
compute_length(const BuilderBucket &bucket) const {
LVector3f v = ((const Vertexf &)_a->get_coord_value(bucket) -
(const Vertexf &)_b->get_coord_value(bucket));
return length(v);
}
template <class PrimType>
INLINE Vertexf MesherEdge<PrimType>::
compute_box(const BuilderBucket &bucket) const {
LVector3f v = ((const Vertexf &)_a->get_coord_value(bucket) -
(const Vertexf &)_b->get_coord_value(bucket));
return Vertexf(fabs(v[0]), fabs(v[1]), fabs(v[2]));
}
////////////////////////////////////////////////////////////////////
// Function: MesherEdge::remove
// Access: Public
// Description: Removes an edge from a particular strip.
////////////////////////////////////////////////////////////////////
template <class PrimType>
void MesherEdge<PrimType>::
remove(Strip *strip) {
strip->_edges.remove(this);
strip->_edges.remove(_opposite);
_strips.remove(strip);
_opposite->_strips.remove(strip);
}
////////////////////////////////////////////////////////////////////
// Function: MesherEdge::change_strip
// Access: Public
// Description: Reparents the edge from strip "from" to strip "to".
////////////////////////////////////////////////////////////////////
template <class PrimType>
void MesherEdge<PrimType>::
change_strip(Strip *from, Strip *to) {
Strips::iterator si;
for (si = _strips.begin(); si != _strips.end(); ++si) {
if (*si == from) {
*si = to;
}
}
for (si = _opposite->_strips.begin();
si != _opposite->_strips.end();
++si) {
if (*si == from) {
*si = to;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: MesherEdge::output
// Access: Public
// Description: Formats the edge for output in some sensible way.
////////////////////////////////////////////////////////////////////
template <class PrimType>
ostream &MesherEdge<PrimType>::
output(ostream &out) const {
out << "Edge [" << *_a << " to " << *_b << "], "
<< _strips.size() << " strips:";
Strips::const_iterator si;
for (si = _strips.begin(); si != _strips.end(); ++si) {
out << " " << (*si)->_index;
}
if (_opposite!=NULL) {
out << " opposite "
<< _opposite->_strips.size() << " strips:";
for (si = _opposite->_strips.begin();
si != _opposite->_strips.end();
++si) {
out << " " << (*si)->_index;
}
}
return out;
}

View File

@@ -0,0 +1,62 @@
// Filename: mesherEdge.h
// Created by: drose (15Sep97)
//
////////////////////////////////////////////////////////////////////
#ifndef MESHEREDGE_H
#define MESHEREDGE_H
#include <pandabase.h>
#include "builderBucket.h"
#include <list>
#include <math.h>
template <class PrimType>
class MesherStrip;
template <class PrimType>
class MesherEdge {
public:
typedef PrimType Prim;
typedef TYPENAME PrimType::Vertex Vertex;
typedef MesherStrip<PrimType> Strip;
INLINE MesherEdge(const Vertex *a, const Vertex *b);
INLINE MesherEdge(const MesherEdge &copy);
void remove(Strip *strip);
void change_strip(Strip *from, Strip *to);
INLINE bool contains_vertex(const Vertex *v) const;
INLINE bool matches(const MesherEdge &other) const;
INLINE MesherEdge *common_ptr();
INLINE bool operator == (const MesherEdge &other) const;
INLINE bool operator < (const MesherEdge &other) const;
INLINE float compute_length(const BuilderBucket &bucket) const;
INLINE Vertexf compute_box(const BuilderBucket &bucket) const;
ostream &output(ostream &out) const;
const Vertex *_a, *_b;
typedef list<Strip *> Strips;
Strips _strips;
MesherEdge *_opposite;
};
template <class PrimType>
INLINE ostream &operator << (ostream &out,
const MesherEdge<PrimType> &edge) {
return edge.output(out);
}
#include "mesherEdge.I"
#endif

View File

@@ -0,0 +1,312 @@
// Filename: mesherFanMaker.I
// Created by: drose (21Sep97)
//
////////////////////////////////////////////////////////////////////
#include "builderFuncs.h"
#include <notify.h>
#include <mathNumbers.h>
#include <math.h>
template <class PrimType>
INLINE bool MesherFanMaker<PrimType>::
operator < (const MesherFanMaker &other) const {
return _edges.front() < other._edges.front();
}
template <class PrimType>
INLINE bool MesherFanMaker<PrimType>::
operator == (const MesherFanMaker &other) const {
return _edges.front() == other._edges.front();
}
template <class PrimType>
INLINE bool MesherFanMaker<PrimType>::
is_empty() const {
return (_edges.empty());
}
template <class PrimType>
INLINE bool MesherFanMaker<PrimType>::
is_valid() const {
return (_edges.size() > 2);
}
////////////////////////////////////////////////////////////////////
// Function: MesherFanMaker::is_coplanar_with
// Access: Public
// Description: Returns true if the strip and the other strip are
// coplanar.
////////////////////////////////////////////////////////////////////
template <class PrimType>
INLINE bool MesherFanMaker<PrimType>::
is_coplanar_with(const MesherFanMaker &other) const {
return _planar && other._planar &&
_strips.front()->is_coplanar_with(*other._strips.front(),
_bucket->_coplanar_threshold);
}
template <class PrimType>
MesherFanMaker<PrimType>::
MesherFanMaker(const Vertex *vertex, Strip *tri, Mesher *mesher) {
_vertex = vertex;
_edges.push_back(tri->find_opposite_edge(vertex));
_strips.push_back(tri);
_planar = tri->_planar;
_mesher = mesher;
_bucket = _mesher->_bucket;
}
template <class PrimType>
bool MesherFanMaker<PrimType>::
join(MesherFanMaker &other) {
nassertr(_vertex == other._vertex, false);
nassertr(_mesher == other._mesher, false);
nassertr(_bucket == other._bucket, false);
if (_edges.back()->_b == other._edges.front()->_a) {
_planar = is_coplanar_with(other);
_edges.splice(_edges.end(), other._edges);
_strips.splice(_strips.end(), other._strips);
return true;
} else if (_edges.front()->_a == other._edges.back()->_b) {
_planar = is_coplanar_with(other);
_edges.splice(_edges.begin(), other._edges);
_strips.splice(_strips.begin(), other._strips);
return true;
} else {
return false;
}
}
template <class PrimType>
float MesherFanMaker<PrimType>::
compute_angle() const {
// We sum up the angles of each triangle. This is more correct than
// taking the net angle from the first edge to the last (since we
// may not be in a plane).
nassertr(is_valid(), 0.0);
double angle = 0.0;
Vertexf v0 = _vertex->get_coord_value(*_bucket);
Edges::const_iterator ei;
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
Normalf v1 = (Vertexf &)(*ei)->_a->get_coord_value(*_bucket) - v0;
Normalf v2 = (Vertexf &)(*ei)->_b->get_coord_value(*_bucket) - v0;
v1 = normalize(v1);
v2 = normalize(v2);
angle += acos(dot(v1, v2));
}
return angle * 180.0 / MathNumbers::pi;
}
template <class PrimType>
int MesherFanMaker<PrimType>::
build() {
nassertr(_edges.size() == _strips.size(), 0);
int num_tris = _edges.size();
float net_angle = compute_angle();
float avg_angle = net_angle / num_tris;
if (avg_angle > _bucket->_max_tfan_angle) {
// The triangles are too loose to justify making a fan; it'll
// probably make a better quadsheet.
return 0;
}
if (_bucket->_min_tfan_tris==0 || num_tris < _bucket->_min_tfan_tris) {
// Oops, not enough triangles to justify a fan.
if (!_bucket->_unroll_fans) {
return 0;
}
// However, we could (maybe) make it a few tristrips!
// Each section of the fan which is made up of coplanar tris with
// identical properties may be retesselated into a tristrip. What
// a sneaky trick! To do this, we must first identify each such
// qualifying section.
// We define a seam as the edge between any two tris which are
// noncoplanar or which do not share identical properties. Then
// we can send each piece between the seams to unroll().
Strips::iterator si, last_si;
Edges::iterator ei, last_ei;
// First, rotate the fan so it begins at a seam. We do this so we
// won't be left out with part of one piece at the beginning and
// also at the end.
si = _strips.begin();
last_si = si;
ei = _edges.begin();
last_ei = ei;
int found_seam = false;
for (++si, ++ei; si != _strips.end() && !found_seam; ++si, ++ei) {
nassertr(ei != _edges.end(), 0);
if ( !((*si)->_prims.front() == (*last_si)->_prims.front()) ||
!(*si)->is_coplanar_with(*(*last_si), _bucket->_coplanar_threshold)) {
// Here's a seam. Break the fan here.
found_seam = true;
_edges.splice(_edges.begin(), _edges, ei, _edges.end());
_strips.splice(_strips.begin(), _strips, si, _strips.end());
}
}
// Now break the fan up along its seams and unroll each piece
// separately.
si = _strips.begin();
last_si = si;
ei = _edges.begin();
last_ei = ei;
int count = 0;
for (++si, ++ei; si != _strips.end(); ++si, ++ei) {
nassertr(ei != _edges.end(), 0);
if ( !((*si)->_prims.front() == (*last_si)->_prims.front()) ||
!(*si)->is_coplanar_with(*(*last_si), _bucket->_coplanar_threshold)) {
// Here's the end of a run of matching pieces.
count += unroll(last_si, si, last_ei, ei);
last_si = si;
last_ei = ei;
}
}
count += unroll(last_si, si, last_ei, ei);
return count;
} else {
Strip new_fan;
new_fan._type = BPT_trifan;
new_fan._verts.push_back(_vertex);
new_fan._verts.push_back(_edges.front()->_a);
Edges::iterator ei;
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
new_fan._verts.push_back((*ei)->_b);
}
Strips::iterator si;
for (si = _strips.begin(); si != _strips.end(); ++si) {
new_fan._prims.splice(new_fan._prims.end(), (*si)->_prims);
(*si)->remove_all_edges();
(*si)->_verts.clear();
(*si)->_status = MS_dead;
}
// If we'd built our list of edges and strips right, this sum should
// come out so that there are two more vertices than triangles in
// the new fan.
nassertr(new_fan._verts.size() == new_fan._prims.size() + 2, 0);
// Now we've built a fan, and it won't be able to mate with
// anything else, so add it to the done list.
_mesher->_done.push_back(new_fan);
}
return 1;
}
template <class PrimType>
int MesherFanMaker<PrimType>::
unroll(Strips::iterator strip_begin, Strips::iterator strip_end,
Edges::iterator edge_begin, Edges::iterator edge_end) {
Edges::iterator ei;
Strips::iterator si;
int num_tris = 0;
for (ei = edge_begin; ei != edge_end; ++ei) {
num_tris++;
}
if (num_tris < 3) {
// Don't even bother.
return 0;
}
Prim poly;
// Now we build an n-sided polygon. We'll decompose it into tris
// in a second.
poly.set_type(BPT_poly);
poly.set_attrib((*strip_begin)->_prims.front());
ei = edge_end;
--ei;
if ( !((*ei)->_b == (*edge_begin)->_a)) {
// If the fan is less than a full circle, we need to keep the
// hub vertex and initial vertex in the poly. Otherwise, we'll
// discard them.
poly.add_vertex(*_vertex);
poly.add_vertex(*(*edge_begin)->_a);
}
for (ei = edge_begin; ei != edge_end; ++ei) {
poly.add_vertex(*(*ei)->_b);
}
int result = true;
if (_bucket->_show_quads) {
// If we're showing quads, also show retesselated triangles.
_mesher->add_prim(poly, MO_fanpoly);
} else {
// Now decompose the new polygon into triangles.
vector<Prim> tris;
result = expand(poly, *_bucket, back_inserter(tris));
if (result) {
// Now add each triangle back into the mesher.
vector<Prim>::iterator ti;
for (ti = tris.begin(); ti != tris.end(); ++ti) {
_mesher->add_prim(*ti);
}
}
}
if (result) {
// Now that we've created a new poly, kill off all the old ones.
for (si = strip_begin; si != strip_end; ++si) {
(*si)->remove_all_edges();
(*si)->_verts.clear();
(*si)->_prims.clear();
(*si)->_status = MS_dead;
}
return 1;
} else {
return 0;
}
}
template <class PrimType>
ostream &MesherFanMaker<PrimType>::
output(ostream &out) const {
out << *_vertex << ":[";
if (!_edges.empty()) {
Edges::const_iterator ei;
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
out << " " << *(*ei)->_a;
}
out << " " << *_edges.back()->_b;
}
out << " ]";
if (_planar) {
out << " (planar)";
}
return out;
}

Some files were not shown because too many files have changed in this diff Show More