Compare commits
164
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a4e703f16 | ||
|
|
61984730ac | ||
|
|
f196d3bab8 | ||
|
|
7da45cb49e | ||
|
|
e994305da6 | ||
|
|
2af37b484e | ||
|
|
faf41f7d96 | ||
|
|
7629e29397 | ||
|
|
1cff7fcfea | ||
|
|
694cf6e958 | ||
|
|
0e12fbb2a0 | ||
|
|
450ad45882 | ||
|
|
d674e50591 | ||
|
|
61f2f4b761 | ||
|
|
baa2f49b14 | ||
|
|
8c0bd234d8 | ||
|
|
c4fd41562f | ||
|
|
a1d1b4e49f | ||
|
|
96fb7a45f7 | ||
|
|
d5eedd2c65 | ||
|
|
fe4f907099 | ||
|
|
1b45eaf3de | ||
|
|
cfbc0a1579 | ||
|
|
db1b99d8dd | ||
|
|
65a880e9fa | ||
|
|
37b4005d3e | ||
|
|
70faa252e7 | ||
|
|
3620be8dbc | ||
|
|
21c64dd60f | ||
|
|
fb69d790ce | ||
|
|
debd066edd | ||
|
|
f58d81b1e9 | ||
|
|
8d507f161b | ||
|
|
b015f7c801 | ||
|
|
80abe952ba | ||
|
|
c12162407c | ||
|
|
7f5c3b223a | ||
|
|
2f3e4ebf39 | ||
|
|
2c14f8587e | ||
|
|
42224052e2 | ||
|
|
a8dd5aa0fc | ||
|
|
f3d0a9bc3f | ||
|
|
d629b9e36a | ||
|
|
4d54ba2200 | ||
|
|
0035ef9194 | ||
|
|
fcb20296d7 | ||
|
|
6bb9080017 | ||
|
|
bbde16dc08 | ||
|
|
ac9716f193 | ||
|
|
8a2bc1c21b | ||
|
|
942b474ad7 | ||
|
|
f3ef9b671f | ||
|
|
3538631e8e | ||
|
|
1577ab04e1 | ||
|
|
7f2dfaa5b4 | ||
|
|
fd126746f7 | ||
|
|
63f7e9feb0 | ||
|
|
5eb380e103 | ||
|
|
832e821919 | ||
|
|
197e3f144d | ||
|
|
056b5b41e2 | ||
|
|
15d40fd64a | ||
|
|
979d3da69c | ||
|
|
72984cc4a8 | ||
|
|
0a7a815124 | ||
|
|
1ce68a49c6 | ||
|
|
b1b6abf285 | ||
|
|
9dfd6970f1 | ||
|
|
3583c13339 | ||
|
|
00ab198c9f | ||
|
|
669d9a89ca | ||
|
|
9c54603726 | ||
|
|
dc09a50472 | ||
|
|
68eb7031e2 | ||
|
|
19623cac21 | ||
|
|
4ca25ca533 | ||
|
|
178c49a430 | ||
|
|
32e2cd9f06 | ||
|
|
7aa514d9ba | ||
|
|
7c2575d723 | ||
|
|
f93ea20d5e | ||
|
|
73cb6ff00d | ||
|
|
72267fa60b | ||
|
|
6b6a27e849 | ||
|
|
daea10121c | ||
|
|
999a1e514b | ||
|
|
be30960366 | ||
|
|
38e5084018 | ||
|
|
fdd9bb1af6 | ||
|
|
81546820ab | ||
|
|
84e87f0e8a | ||
|
|
901592a88e | ||
|
|
24f908d9be | ||
|
|
f62ff0ad66 | ||
|
|
8e0ecbeb8f | ||
|
|
095367f760 | ||
|
|
5d34eb12e0 | ||
|
|
d4e760efe1 | ||
|
|
75ab8e697b | ||
|
|
f4b05d46ed | ||
|
|
04c5f2c36a | ||
|
|
db50f95482 | ||
|
|
0e52a08a47 | ||
|
|
7b5d49ef60 | ||
|
|
430ba60b33 | ||
|
|
3af1f3bc63 | ||
|
|
bdcb94af81 | ||
|
|
2ea9e723c2 | ||
|
|
e19091d809 | ||
|
|
64ab59c0e0 | ||
|
|
4707b363aa | ||
|
|
1a72245c15 | ||
|
|
dea7b9050d | ||
|
|
3bd810fedc | ||
|
|
f9cbf8361d | ||
|
|
eccd4d0325 | ||
|
|
e0decf1233 | ||
|
|
100927f16c | ||
|
|
bb670f6658 | ||
|
|
d37992aaf9 | ||
|
|
9048ee533d | ||
|
|
2b1e5927ca | ||
|
|
b5e03030d1 | ||
|
|
65056bfa72 | ||
|
|
c50bb90374 | ||
|
|
ec4fc265e0 | ||
|
|
8ea41af5c4 | ||
|
|
966331dac7 | ||
|
|
cf056bace7 | ||
|
|
405a455906 | ||
|
|
3a8b431a5b | ||
|
|
3ce0c17237 | ||
|
|
61a2e0f104 | ||
|
|
7c44251216 | ||
|
|
26e70664d6 | ||
|
|
8ac27cc798 | ||
|
|
d314164fed | ||
|
|
d2cbed151b | ||
|
|
fc06ae58b2 | ||
|
|
a8768c78a2 | ||
|
|
ee8763f60d | ||
|
|
db633330fe | ||
|
|
c1ffafd663 | ||
|
|
72f35dc914 | ||
|
|
e5f82f53b9 | ||
|
|
e39e6893e0 | ||
|
|
9ab77d65f4 | ||
|
|
8ed96cad1d | ||
|
|
7795eb8239 | ||
|
|
207c7ab1e0 | ||
|
|
27af79684f | ||
|
|
6b61a8eed1 | ||
|
|
181e6eac75 | ||
|
|
fd1979857c | ||
|
|
448bc3facd | ||
|
|
97cabadb88 | ||
|
|
8e284a70b7 | ||
|
|
73f9febe06 | ||
|
|
6a6cc22e9c | ||
|
|
b293639b76 | ||
|
|
f06036be09 | ||
|
|
867571af78 | ||
|
|
f6314d3124 | ||
|
|
1e87dd7903 |
@@ -22,7 +22,7 @@ PROJECT_NAME = SimGear
|
||||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER = 0.3.8
|
||||
PROJECT_NUMBER = 0.3.9
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ EXTRA_DIST = \
|
||||
SUBDIRS = src-libs simgear
|
||||
|
||||
dist-hook:
|
||||
(cd $(top_srcdir); $(HOME)/Projects/FlightGear-0.9/admin/am2dsp.pl)
|
||||
(cd $(top_srcdir); $(HOME)/Projects/FlightGear/admin/am2dsp.pl)
|
||||
|
||||
#
|
||||
# Rule to build RPM distribution package
|
||||
|
||||
@@ -1,7 +1,34 @@
|
||||
New in 0.3.9
|
||||
* November 17, 2005
|
||||
|
||||
* Add support for OpenAL 1.1 (with a separate alut library.)
|
||||
* Add support for volumetric shadows. Aircraft can cast shadows on themselves
|
||||
as well as onto the ground (by Harald Johnsen.)
|
||||
* New 3d volumetric clouds by Harald Johnsen (along with several rounds of
|
||||
followup fixes and improvements.)
|
||||
* Remove Mark Harris's old 3d clouds because they were never properly
|
||||
integrated. And we now have new 3d clouds.
|
||||
* Add support for seasonal textures (with a set of winter textures added
|
||||
to FlightGear.)
|
||||
* Updated Nasal scripting system. Adds several new syntax convenience
|
||||
features, fixes parser bugs, fixes several internal bugs.
|
||||
* Our 3d cockpit jitter problem is fixed (woohoo!)
|
||||
* Add code to support rendering to a texture.
|
||||
* Allow "tip" popups to pop themselves down after the appropriate
|
||||
timeout, even if the sim time is paused.
|
||||
* Various low model level animation fixes and additions ... color,
|
||||
transparency, 'chrome' effects, randomized spin, etc.
|
||||
* Create our own portable stdint.h implementation.
|
||||
* Fixed several memory leaks.
|
||||
* removeChildren() added to the property system.
|
||||
* Fix many cases of 'const'.
|
||||
* Fixes for cygwin, solaris/sun, Mac OS X, MSVC, gcc-3.4.x.
|
||||
|
||||
|
||||
New in 0.3.8
|
||||
* January 18, 2005
|
||||
|
||||
* Configure script does a sanity check for the existance of openal.
|
||||
* Configure script does a sanity check for the existence of openal.
|
||||
* Better pthreads detection for FreeBSD.
|
||||
* Abstract out the location of gl.h, glu.h, and glut.h so we can more
|
||||
easily support MacOS which puts these in an oddball location.
|
||||
@@ -15,7 +42,7 @@ New in 0.3.8
|
||||
* Fixes to property tree loading and saving.
|
||||
* Make volume inaudible at startup.
|
||||
* Solaris fixes.
|
||||
* For low density cloud coverages, blend the layer to nothing as we pass
|
||||
* For low density cloud coverage, blend the layer to nothing as we pass
|
||||
through instead of fully engulfing the aircraft in the cloud.
|
||||
* Add several new capabilities to the texture management code for building
|
||||
normal maps and doing some simple on-the-fly effects on textures.
|
||||
@@ -58,7 +85,7 @@ New in 0.3.5
|
||||
* Support VASI/PAPI lights correctly.
|
||||
* Fixes to cloud animation.
|
||||
* Updates to sky dome coloring as well as sun/moon coloring.
|
||||
* Vary environment lighting with visibility (subtlely.)
|
||||
* Vary environment lighting with visibility (subtlety.)
|
||||
* Support control of alpha test in model animation.
|
||||
* Complete rewrite of the event manager.
|
||||
* Updates to low level socket code to make it more flexible.
|
||||
@@ -109,7 +136,7 @@ New in 0.3.2
|
||||
management, basic model and model animation management, sky
|
||||
rendering, and low level loaders for the "TerraGear" tile object format.
|
||||
* Removed support of the flat shaded and non-textured material
|
||||
property varients. You can still do these things, but extra states
|
||||
property variants. You can still do these things, but extra states
|
||||
are no longer set up automatically.
|
||||
* Removed 3d clouds from the default build ... these need a maintainer
|
||||
or better yet, a complete plib-based rewrite.
|
||||
@@ -154,7 +181,7 @@ New in 0.2.0
|
||||
* Removed efence support (in favor of valgrind.)
|
||||
|
||||
* Added a javascript interpreter.
|
||||
* SGSocket reimplimented on top of plib/net libs.
|
||||
* SGSocket reimplemented on top of plib/net libs.
|
||||
* Added a new random number generation algorithm.
|
||||
* Total rewrite of the strutils package.
|
||||
|
||||
@@ -164,7 +191,7 @@ New in 0.2.0
|
||||
* Mac OS X fixes.
|
||||
* Irix fixes.
|
||||
* Code clean ups to remove warning messages.
|
||||
* Optimizations in sg_binobj to reduce the amout of memory copying
|
||||
* Optimizations in sg_binobj to reduce the amount of memory copying
|
||||
needed when loading a binobj format file.
|
||||
* Fixed a couple places where variables could be used before they were
|
||||
initialized.
|
||||
@@ -184,7 +211,7 @@ New in 0.0.18
|
||||
* Upgrade to metakit-2.4.2-32.tar.gz (latest upstream release)
|
||||
* Added support for point objects in the scenery file format.
|
||||
* Additions to the binary file format to make it *much* more flexible.
|
||||
For each major primative type: points, triangles, fans, and strips, you
|
||||
For each major primitive type: points, triangles, fans, and strips, you
|
||||
can specify an index list of vertices, normals, colors, and texture
|
||||
coordinates. You can skip any of these you like to save on space.
|
||||
* Added support for new file features in the binary -> ascii scenery file
|
||||
@@ -235,7 +262,7 @@ New in 0.0.17pre1
|
||||
|
||||
New in 0.0.16
|
||||
* July 12, 2001
|
||||
* Various changes to the property manager implimentation to better support
|
||||
* Various changes to the property manager implementation to better support
|
||||
dumping out the desired portions of the property tree to file.
|
||||
* Don't compile the metakit demos by default (causes problems for Irix)'
|
||||
* Other various tweaks for Irix.
|
||||
@@ -278,7 +305,7 @@ New in 0.0.15
|
||||
read/write routines.
|
||||
* Added doxygen comments for all public interface code. Documentation
|
||||
can be accessed via the SimGear web page.
|
||||
* Many FG -> SG name space changes for better consistancy throughout
|
||||
* Many FG -> SG name space changes for better consistency throughout
|
||||
this package.
|
||||
* Added property aliases, repeated name tags, and a general xml
|
||||
inclusion facilities. Many other property manager clean ups
|
||||
@@ -369,4 +396,4 @@ New in 0.0.4
|
||||
|
||||
|
||||
New in 0.0.3
|
||||
* Release that conincides with FlightGear-0.7.2
|
||||
* Release that coincides with FlightGear-0.7.2
|
||||
|
||||
+129
-917
File diff suppressed because it is too large
Load Diff
+18
-18
@@ -3,7 +3,7 @@ dnl originally from ncftp 2.3.0
|
||||
dnl added wi_EXTRA_PDIR and wi_ANSI_C
|
||||
dnl $Id$
|
||||
dnl
|
||||
AC_DEFUN(wi_EXTRA_IDIR, [
|
||||
AC_DEFUN([wi_EXTRA_IDIR], [
|
||||
incdir="$1"
|
||||
if test -r $incdir ; then
|
||||
case "$CPPFLAGS" in
|
||||
@@ -25,7 +25,7 @@ dnl
|
||||
dnl
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_EXTRA_LDIR, [
|
||||
AC_DEFUN([wi_EXTRA_LDIR], [
|
||||
mylibdir="$1"
|
||||
if test -r $mylibdir ; then
|
||||
case "$LDFLAGS" in
|
||||
@@ -47,7 +47,7 @@ dnl
|
||||
dnl __FP__
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_EXTRA_PDIR, [
|
||||
AC_DEFUN([wi_EXTRA_PDIR], [
|
||||
progdir="$1"
|
||||
if test -r $progdir ; then
|
||||
case "$PATH" in
|
||||
@@ -76,7 +76,7 @@ dnl
|
||||
dnl If you want to look for subdirectories in include/lib directories,
|
||||
dnl you pass the names in argument 3, otherwise pass a dash.
|
||||
dnl
|
||||
AC_DEFUN(wi_EXTRA_DIRS, [echo "checking for extra include and lib directories..." 1>&6
|
||||
AC_DEFUN([wi_EXTRA_DIRS], [echo "checking for extra include and lib directories..." 1>&6
|
||||
ifelse([$1], yes, [dnl
|
||||
b1=`cd .. ; pwd`
|
||||
b2=`cd ../.. ; pwd`
|
||||
@@ -111,7 +111,7 @@ done
|
||||
dnl
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_HPUX_CFLAGS,
|
||||
AC_DEFUN([wi_HPUX_CFLAGS],
|
||||
[AC_MSG_CHECKING(if HP-UX ansi C compiler flags are needed)
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
os=`uname -s | tr '[A-Z]' '[a-z]'`
|
||||
@@ -144,7 +144,7 @@ AC_MSG_RESULT($ac_cv_hpux_flags)
|
||||
dnl
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_CFLAGS, [AC_REQUIRE([AC_PROG_CC])
|
||||
AC_DEFUN([wi_CFLAGS], [AC_REQUIRE([AC_PROG_CC])
|
||||
wi_HPUX_CFLAGS
|
||||
if test "$CFLAGS" = "" ; then
|
||||
CFLAGS="-O"
|
||||
@@ -165,7 +165,7 @@ wi_HPUX_CFLAGS
|
||||
dnl
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_PROTOTYPES, [
|
||||
AC_DEFUN([wi_PROTOTYPES], [
|
||||
AC_MSG_CHECKING(if the compiler supports function prototypes)
|
||||
AC_TRY_COMPILE(,[extern void exit(int status);],[wi_cv_prototypes=yes
|
||||
AC_DEFINE(PROTOTYPES)],wi_cv_prototypes=no)
|
||||
@@ -174,7 +174,7 @@ AC_MSG_RESULT($wi_cv_prototypes)
|
||||
dnl
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_ANSI_C, [
|
||||
AC_DEFUN([wi_ANSI_C], [
|
||||
AC_MSG_CHECKING(ANSI-style function definitions)
|
||||
AC_TRY_COMPILE(,[int blubb(int x) { return 0; }],[wi_cv_ansi_funcs=yes
|
||||
AC_DEFINE(ANSI_FUNCS)],wi_cv_ansi_funcs=no)
|
||||
@@ -183,7 +183,7 @@ AC_MSG_RESULT($wi_cv_ansi_funcs)
|
||||
dnl
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_HEADER_SYS_SELECT_H, [
|
||||
AC_DEFUN([wi_HEADER_SYS_SELECT_H], [
|
||||
# See if <sys/select.h> is includable after <sys/time.h>
|
||||
if test "$ac_cv_header_sys_time_h" = no ; then
|
||||
AC_CHECK_HEADERS(sys/time.h sys/select.h)
|
||||
@@ -211,7 +211,7 @@ fi
|
||||
dnl
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_LIB_RESOLV, [
|
||||
AC_DEFUN([wi_LIB_RESOLV], [
|
||||
# See if we could access two well-known sites without help of any special
|
||||
# libraries, like resolv.
|
||||
|
||||
@@ -244,7 +244,7 @@ dnl
|
||||
dnl
|
||||
dnl
|
||||
|
||||
AC_DEFUN(wi_LIB_NSL, [
|
||||
AC_DEFUN([wi_LIB_NSL], [
|
||||
AC_MSG_CHECKING(if we can use -lnsl)
|
||||
ac_save_LIBS="$LIBS";
|
||||
LIBS="$LIBS -lnsl";
|
||||
@@ -261,7 +261,7 @@ dnl
|
||||
dnl
|
||||
dnl
|
||||
|
||||
AC_DEFUN(nc_PATH_PROG_ZCAT, [
|
||||
AC_DEFUN([nc_PATH_PROG_ZCAT], [
|
||||
AC_PATH_PROG(GZCAT,gzcat)
|
||||
AC_PATH_PROG(ZCAT,zcat)
|
||||
if test "x$GZCAT" = x ; then
|
||||
@@ -287,7 +287,7 @@ fi
|
||||
dnl
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_SYSV_EXTRA_DIRS, [
|
||||
AC_DEFUN([wi_SYSV_EXTRA_DIRS], [
|
||||
# Use System V because their curses extensions are required. This must
|
||||
# be done early so we use the -I and -L in the library checks also.
|
||||
# This is mostly a Solaris/SunOS hack. Note that doing this will also
|
||||
@@ -305,7 +305,7 @@ fi
|
||||
dnl
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_DEFINE_UNAME, [
|
||||
AC_DEFUN([wi_DEFINE_UNAME], [
|
||||
# Get first 127 chars of all uname information. Some folks have
|
||||
# way too much stuff there, so grab only the first 127.
|
||||
unam=`uname -a 2>/dev/null | cut -c1-127`
|
||||
@@ -316,7 +316,7 @@ fi
|
||||
dnl
|
||||
dnl
|
||||
dnl
|
||||
AC_DEFUN(wi_READLINE_WITH_NCURSES, [
|
||||
AC_DEFUN([wi_READLINE_WITH_NCURSES], [
|
||||
# Readline and Ncurses could both define "backspace".
|
||||
# Warn about this if we have both things in our definitions list.
|
||||
|
||||
@@ -352,7 +352,7 @@ dnl
|
||||
|
||||
dnl AC_EXT_DAYLIGHT
|
||||
dnl Check for an external variable daylight. Stolen from w3c-libwww.
|
||||
AC_DEFUN(AC_EXT_DAYLIGHT,
|
||||
AC_DEFUN([AC_EXT_DAYLIGHT],
|
||||
[ AC_MSG_CHECKING(int daylight variable)
|
||||
AC_TRY_COMPILE([#include <time.h>], [return daylight;],
|
||||
have_daylight=yes,
|
||||
@@ -362,7 +362,7 @@ AC_MSG_RESULT($have_daylight)
|
||||
|
||||
dnl AC_EXT_TIMEZONE
|
||||
dnl Check for an external variable timezone. Stolen from tcl-8.0.
|
||||
AC_DEFUN(AC_EXT_TIMEZONE,
|
||||
AC_DEFUN([AC_EXT_TIMEZONE],
|
||||
[
|
||||
#
|
||||
# Its important to include time.h in this check, as some systems (like convex)
|
||||
@@ -395,7 +395,7 @@ fi
|
||||
|
||||
## AC_BZ_SET_COMPILER: Addition by Theodore Papadopoulo
|
||||
## Patch by Jim McKelvey: change sed -e 's/ /@/g' to sed -e 's/ /@/'
|
||||
AC_DEFUN(AC_SG_SET_COMPILER,
|
||||
AC_DEFUN([AC_SG_SET_COMPILER],
|
||||
[cxxwith=`echo $1 | sed -e 's/ /@/'`
|
||||
case "$cxxwith" in
|
||||
*:*@*) # Full initialization syntax
|
||||
|
||||
+6
-6
@@ -8,7 +8,7 @@ dnl Require at least automake 2.52
|
||||
AC_PREREQ(2.52)
|
||||
|
||||
dnl Initialize the automake stuff
|
||||
AM_INIT_AUTOMAKE(SimGear, 0.3.8)
|
||||
AM_INIT_AUTOMAKE(SimGear, 0.3.9)
|
||||
|
||||
dnl Specify KAI C++ compiler and flags.
|
||||
dnl Borrowed with slight modification from blitz distribution.
|
||||
@@ -121,7 +121,7 @@ fi
|
||||
|
||||
dnl Determine an extra directories to add to include/lib search paths
|
||||
case "${host}" in
|
||||
*-apple-darwin* | *-*-mingw32*)
|
||||
*-apple-darwin* | *-*-cygwin* | *-*-mingw32*)
|
||||
echo no EXTRA_DIRS for $host
|
||||
;;
|
||||
|
||||
@@ -170,7 +170,7 @@ if test "x$ac_cv_header_pthread_h" = "xyes"; then
|
||||
|
||||
if test "x$ac_cv_search_pthread_exit" = "x-lc_r"; then
|
||||
CXXFLAGS="-pthread $CXXFLAGS"
|
||||
CFLAGS="-pthread $FLAGS"
|
||||
CFLAGS="-pthread $CFLAGS"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -258,7 +258,8 @@ OPENAL_OK="no"
|
||||
case "${host}" in
|
||||
*-*-cygwin* | *-*-mingw32*)
|
||||
dnl CygWin under Windoze.
|
||||
|
||||
INCLUDES="$INCLUDES -I/usr/local/include"
|
||||
LIBS="$LIBS -L/usr/local/lib"
|
||||
AC_SEARCH_LIBS(alGenBuffers, openal32)
|
||||
AC_SEARCH_LIBS(alutInit, [ openal32 ALut ] )
|
||||
LIBS="$LIBS -lwinmm -ldsound -ldxguid -lole32"
|
||||
@@ -281,6 +282,7 @@ case "${host}" in
|
||||
save_LIBS=$LIBS
|
||||
LIBS="$LIBS $thread_LIBS"
|
||||
AC_SEARCH_LIBS(alGenBuffers, openal)
|
||||
AC_SEARCH_LIBS(alutInit, [ alut openal ] )
|
||||
OPENAL_OK="$ac_cv_search_alGenBuffers"
|
||||
openal_LIBS="$LIBS"
|
||||
LIBS=$save_LIBS
|
||||
@@ -424,7 +426,6 @@ AC_CONFIG_FILES([ \
|
||||
simgear/scene/material/Makefile \
|
||||
simgear/scene/model/Makefile \
|
||||
simgear/scene/sky/Makefile \
|
||||
simgear/scene/sky/clouds3d/Makefile \
|
||||
simgear/scene/tgdb/Makefile \
|
||||
simgear/screen/Makefile \
|
||||
simgear/serial/Makefile \
|
||||
@@ -432,7 +433,6 @@ AC_CONFIG_FILES([ \
|
||||
simgear/structure/Makefile \
|
||||
simgear/threads/Makefile \
|
||||
simgear/timing/Makefile \
|
||||
simgear/xgl/Makefile \
|
||||
simgear/xml/Makefile \
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
+1
-2
@@ -32,7 +32,6 @@ SUBDIRS = \
|
||||
serial \
|
||||
sound \
|
||||
$(SGTHREAD_DIR) \
|
||||
timing \
|
||||
xgl
|
||||
timing
|
||||
|
||||
DIST_SUBDIRS = $(SUBDIRS) compatibility threads
|
||||
|
||||
@@ -208,7 +208,7 @@ double SGBucket::get_width_m() const {
|
||||
double clat_rad = clat * SGD_DEGREES_TO_RADIANS;
|
||||
double cos_lat = cos( clat_rad );
|
||||
double local_radius = cos_lat * SG_EQUATORIAL_RADIUS_M;
|
||||
double local_perimeter = 2.0 * local_radius * SGD_PI;
|
||||
double local_perimeter = local_radius * SGD_2PI;
|
||||
double degree_width = local_perimeter / 360.0;
|
||||
|
||||
return sg_bucket_span( get_center_lat() ) * degree_width;
|
||||
@@ -217,7 +217,7 @@ double SGBucket::get_width_m() const {
|
||||
|
||||
// return height of the tile in meters
|
||||
double SGBucket::get_height_m() const {
|
||||
double perimeter = 2.0 * SG_EQUATORIAL_RADIUS_M * SGD_PI;
|
||||
double perimeter = SG_EQUATORIAL_RADIUS_M * SGD_2PI;
|
||||
double degree_height = perimeter / 360.0;
|
||||
|
||||
return SG_BUCKET_SPAN * degree_height;
|
||||
@@ -271,16 +271,32 @@ void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) {
|
||||
#endif
|
||||
|
||||
// longitude difference
|
||||
double c1_lon = b1.get_center_lon();
|
||||
double c2_lon = b2.get_center_lon();
|
||||
double diff_lon = c2_lon - c1_lon;
|
||||
double span;
|
||||
if ( sg_bucket_span(c1_lat) <= sg_bucket_span(c2_lat) ) {
|
||||
double diff_lon=0.0;
|
||||
double span=0.0;
|
||||
|
||||
SGBucket tmp_bucket;
|
||||
// To handle crossing the bucket size boundary
|
||||
// we need to account for different size buckets.
|
||||
|
||||
if ( sg_bucket_span(c1_lat) <= sg_bucket_span(c2_lat) )
|
||||
{
|
||||
span = sg_bucket_span(c1_lat);
|
||||
} else {
|
||||
span = sg_bucket_span(c2_lat);
|
||||
}
|
||||
|
||||
diff_lon = b2.get_center_lon() - b1.get_center_lon();
|
||||
|
||||
if (diff_lon <0.0)
|
||||
{
|
||||
diff_lon -= b1.get_width()*0.5 + b2.get_width()*0.5 - span;
|
||||
}
|
||||
else
|
||||
{
|
||||
diff_lon += b1.get_width()*0.5 + b2.get_width()*0.5 - span;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_RINT
|
||||
*dx = (int)rint( diff_lon / span );
|
||||
#else
|
||||
|
||||
+6
-1
@@ -324,7 +324,7 @@
|
||||
#endif // Native SGI compilers
|
||||
|
||||
|
||||
#if defined ( sun )
|
||||
#if defined (__sun)
|
||||
# include <strings.h>
|
||||
# include <memory.h>
|
||||
# if defined ( __cplusplus )
|
||||
@@ -372,11 +372,15 @@
|
||||
|
||||
#ifdef __APPLE__
|
||||
# define SG_GL_H <OpenGL/gl.h>
|
||||
# define SG_GLX_H <AGL/agl.h>
|
||||
# define SG_GLU_H <OpenGL/glu.h>
|
||||
# define SG_GLEXT_H <OpenGL/glext.h>
|
||||
# define SG_GLUT_H <GLUT/glut.h>
|
||||
|
||||
inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
|
||||
#else
|
||||
# define SG_GL_H <GL/gl.h>
|
||||
# define SG_GLX_H <GL/glx.h>
|
||||
# define SG_GLU_H <GL/glu.h>
|
||||
# define SG_GLEXT_H <GL/glext.h>
|
||||
# define SG_GLUT_H <GL/glut.h>
|
||||
@@ -464,3 +468,4 @@ inline const_mem_fun_ref_t<_Ret,_Tp> mem_fun_ref(_Ret (_Tp::*__f)() const)
|
||||
#endif // SG_INCOMPLETE_FUNCTIONAL
|
||||
|
||||
#endif // _SG_COMPILER_H
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#ifdef SG_HAVE_STD_INCLUDES
|
||||
# include <cmath>
|
||||
#else
|
||||
|
||||
@@ -185,7 +185,7 @@ inline logbuf::int_type
|
||||
logbuf::overflow( int c )
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
static has_console = false;
|
||||
static bool has_console = false;
|
||||
if ( logging_enabled ) {
|
||||
if ( !has_console ) {
|
||||
AllocConsole();
|
||||
|
||||
@@ -2,8 +2,8 @@ includedir = @includedir@/environment
|
||||
|
||||
lib_LIBRARIES = libsgenvironment.a
|
||||
|
||||
include_HEADERS = metar.hxx
|
||||
include_HEADERS = metar.hxx visual_enviro.hxx
|
||||
|
||||
libsgenvironment_a_SOURCES = metar.cxx
|
||||
libsgenvironment_a_SOURCES = metar.cxx visual_enviro.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
|
||||
#include <simgear/io/sg_socket.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
@@ -59,8 +60,10 @@
|
||||
* double d = n.getDewpoint_C();
|
||||
* @endcode
|
||||
*/
|
||||
SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const string& auth) :
|
||||
SGMetar::SGMetar(const string& m, const string& proxy, const string& port,
|
||||
const string& auth, const time_t time) :
|
||||
_grpcount(0),
|
||||
_x_proxy(false),
|
||||
_year(-1),
|
||||
_month(-1),
|
||||
_day(-1),
|
||||
@@ -74,13 +77,17 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const
|
||||
_wind_range_to(-1),
|
||||
_temp(NaN),
|
||||
_dewp(NaN),
|
||||
_pressure(NaN)
|
||||
_pressure(NaN),
|
||||
_rain(false),
|
||||
_hail(false),
|
||||
_snow(false),
|
||||
_cavok(false)
|
||||
{
|
||||
if (m.length() == 4 && isalnum(m[0]) && isalnum(m[1]) && isalnum(m[2]) && isalnum(m[3])) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
_icao[i] = toupper(m[i]);
|
||||
_icao[4] = '\0';
|
||||
_data = loadData(_icao, proxy, port, auth);
|
||||
_data = loadData(_icao, proxy, port, auth, time);
|
||||
} else {
|
||||
_data = new char[m.length() + 2]; // make room for " \0"
|
||||
strcpy(_data, m.c_str());
|
||||
@@ -92,7 +99,8 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const
|
||||
_icao[0] = '\0';
|
||||
|
||||
// NOAA preample
|
||||
scanPreambleDate();
|
||||
if (!scanPreambleDate())
|
||||
useCurrentDate();
|
||||
scanPreambleTime();
|
||||
|
||||
// METAR header
|
||||
@@ -127,6 +135,7 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const
|
||||
delete[] _data;
|
||||
throw sg_io_exception("metar data incomplete (" + _url + ')');
|
||||
}
|
||||
|
||||
_url = "";
|
||||
}
|
||||
|
||||
@@ -143,6 +152,20 @@ SGMetar::~SGMetar()
|
||||
}
|
||||
|
||||
|
||||
void SGMetar::useCurrentDate()
|
||||
{
|
||||
struct tm now;
|
||||
time_t now_sec = time(0);
|
||||
#if defined( _MSC_VER ) || defined ( __MINGW32__ )
|
||||
now = *gmtime(&now_sec);
|
||||
#else
|
||||
gmtime_r(&now_sec, &now);
|
||||
#endif
|
||||
_year = now.tm_year + 1900;
|
||||
_month = now.tm_mon + 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If called with "KSFO" loads data from
|
||||
* @code
|
||||
@@ -157,10 +180,15 @@ SGMetar::~SGMetar()
|
||||
* @return pointer to Metar data string, allocated by new char[].
|
||||
* @see rfc2068.txt for proxy spec ("Proxy-Authorization")
|
||||
*/
|
||||
char *SGMetar::loadData(const char *id, const string& proxy, const string& port, const string& auth)
|
||||
char *SGMetar::loadData(const char *id, const string& proxy, const string& port,
|
||||
const string& auth, time_t time)
|
||||
{
|
||||
const int buflen = 512;
|
||||
char buf[2 * buflen];
|
||||
|
||||
string host = proxy.empty() ? "weather.noaa.gov" : proxy;
|
||||
string path = "/pub/data/observations/metar/stations/";
|
||||
|
||||
path += string(id) + ".TXT";
|
||||
_url = "http://weather.noaa.gov" + path;
|
||||
|
||||
@@ -174,24 +202,25 @@ char *SGMetar::loadData(const char *id, const string& proxy, const string& port,
|
||||
string get = "GET ";
|
||||
if (!proxy.empty())
|
||||
get += "http://weather.noaa.gov";
|
||||
get += path + " HTTP/1.0\r\n";
|
||||
|
||||
sprintf(buf, "%ld", time);
|
||||
get += path + " HTTP/1.0\015\012X-Time: " + buf + "\015\012";
|
||||
|
||||
if (!auth.empty())
|
||||
get += "Proxy-Authorization: " + auth + "\015\012";
|
||||
|
||||
get += "\015\012";
|
||||
sock->writestring(get.c_str());
|
||||
|
||||
if (!auth.empty()) {
|
||||
get = "Proxy-Authorization: " + auth + "\r\n";
|
||||
sock->writestring(get.c_str());
|
||||
}
|
||||
|
||||
sock->writestring("\r\n");
|
||||
|
||||
int i;
|
||||
const int buflen = 512;
|
||||
char buf[2 * buflen];
|
||||
|
||||
// skip HTTP header
|
||||
while ((i = sock->readline(buf, buflen)))
|
||||
while ((i = sock->readline(buf, buflen))) {
|
||||
if (i <= 2 && isspace(buf[0]) && (!buf[1] || isspace(buf[1])))
|
||||
break;
|
||||
if (!strncmp(buf, "X-MetarProxy: ", 9))
|
||||
_x_proxy = true;
|
||||
}
|
||||
if (i) {
|
||||
i = sock->readline(buf, buflen);
|
||||
if (i)
|
||||
@@ -392,7 +421,7 @@ bool SGMetar::scanWind()
|
||||
if (gust != NaN)
|
||||
_gust_speed = gust * factor;
|
||||
_grpcount++;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -643,14 +672,15 @@ bool SGMetar::scanWeather()
|
||||
}
|
||||
|
||||
string pre, post;
|
||||
int intensity = 0;
|
||||
if (*m == '-')
|
||||
m++, pre = "light ";
|
||||
m++, pre = "light ", intensity = 1;
|
||||
else if (*m == '+')
|
||||
m++, pre = "heavy ";
|
||||
m++, pre = "heavy ", intensity = 3;
|
||||
else if (!strncmp(m, "VC", 2))
|
||||
m += 2, post = "in the vicinity ";
|
||||
else
|
||||
pre = "moderate ";
|
||||
pre = "moderate ", intensity = 2;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
@@ -662,6 +692,12 @@ bool SGMetar::scanWeather()
|
||||
if (!(a = scanToken(&m, phenomenon)))
|
||||
break;
|
||||
weather += string(a->text) + " ";
|
||||
if (!strcmp(a->id, "RA"))
|
||||
_rain = intensity;
|
||||
else if (!strcmp(a->id, "HA"))
|
||||
_hail = intensity;
|
||||
else if (!strcmp(a->id, "SN"))
|
||||
_snow = intensity;
|
||||
}
|
||||
if (!weather.length())
|
||||
return false;
|
||||
@@ -714,8 +750,13 @@ bool SGMetar::scanSkyCondition()
|
||||
m += i;
|
||||
if (!scanBoundary(&m))
|
||||
return false;
|
||||
cl._coverage = 0;
|
||||
_clouds.push_back(cl);
|
||||
|
||||
if (i == 3) {
|
||||
cl._coverage = 0;
|
||||
_clouds.push_back(cl);
|
||||
} else {
|
||||
_cavok = true;
|
||||
}
|
||||
_m = m;
|
||||
return true;
|
||||
}
|
||||
@@ -907,10 +948,11 @@ bool SGMetar::scanRunwayReport()
|
||||
|
||||
if (!strncmp(m, "CLRD", 4)) {
|
||||
m += 4; // runway cleared
|
||||
r._deposit = "cleared";
|
||||
r._deposit_string = "cleared";
|
||||
} else {
|
||||
if (scanNumber(&m, &i, 1)) {
|
||||
r._deposit = runway_deposit[i];
|
||||
r._deposit = i;
|
||||
r._deposit_string = runway_deposit[i];
|
||||
} else if (*m == '/')
|
||||
m++;
|
||||
else
|
||||
@@ -1137,4 +1179,24 @@ const struct Token *SGMetar::scanToken(char **str, const struct Token *list)
|
||||
return longest;
|
||||
}
|
||||
|
||||
|
||||
void SGMetarCloud::set(double alt, int cov)
|
||||
{
|
||||
_altitude = alt;
|
||||
if (cov != -1)
|
||||
_coverage = cov;
|
||||
}
|
||||
|
||||
|
||||
void SGMetarVisibility::set(double dist, int dir, int mod, int tend)
|
||||
{
|
||||
_distance = dist;
|
||||
if (dir != -1)
|
||||
_direction = dir;
|
||||
if (mod != -1)
|
||||
_modifier = mod;
|
||||
if (tend != 1)
|
||||
_tendency = tend;
|
||||
}
|
||||
|
||||
#undef NaN
|
||||
|
||||
@@ -67,6 +67,8 @@ public:
|
||||
DECREASING
|
||||
};
|
||||
|
||||
void set(double dist, int dir = -1, int mod = -1, int tend = -1);
|
||||
|
||||
inline double getVisibility_m() const { return _distance; }
|
||||
inline double getVisibility_ft() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_FEET; }
|
||||
inline double getVisibility_sm() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_SM; }
|
||||
@@ -87,7 +89,8 @@ class SGMetarRunway {
|
||||
friend class SGMetar;
|
||||
public:
|
||||
SGMetarRunway() :
|
||||
_deposit(0),
|
||||
_deposit(-1),
|
||||
_deposit_string(0),
|
||||
_extent(-1),
|
||||
_extent_string(0),
|
||||
_depth(NaN),
|
||||
@@ -96,7 +99,8 @@ public:
|
||||
_comment(0),
|
||||
_wind_shear(false) {}
|
||||
|
||||
inline const char *getDeposit() const { return _deposit; }
|
||||
inline int getDeposit() const { return _deposit; }
|
||||
inline const char *getDepositString() const { return _deposit_string; }
|
||||
inline double getExtent() const { return _extent; }
|
||||
inline const char *getExtentString() const { return _extent_string; }
|
||||
inline double getDepth() const { return _depth; }
|
||||
@@ -104,13 +108,14 @@ public:
|
||||
inline const char *getFrictionString() const { return _friction_string; }
|
||||
inline const char *getComment() const { return _comment; }
|
||||
inline const bool getWindShear() const { return _wind_shear; }
|
||||
inline SGMetarVisibility getMinVisibility() const { return _min_visibility; }
|
||||
inline SGMetarVisibility getMaxVisibility() const { return _max_visibility; }
|
||||
inline const SGMetarVisibility& getMinVisibility() const { return _min_visibility; }
|
||||
inline const SGMetarVisibility& getMaxVisibility() const { return _max_visibility; }
|
||||
|
||||
protected:
|
||||
SGMetarVisibility _min_visibility;
|
||||
SGMetarVisibility _max_visibility;
|
||||
const char *_deposit;
|
||||
int _deposit;
|
||||
const char *_deposit_string;
|
||||
int _extent;
|
||||
const char *_extent_string;
|
||||
double _depth;
|
||||
@@ -131,6 +136,8 @@ public:
|
||||
_type(0),
|
||||
_type_long(0) {}
|
||||
|
||||
void set(double alt, int cov = -1);
|
||||
|
||||
inline int getCoverage() const { return _coverage; }
|
||||
inline double getAltitude_m() const { return _altitude; }
|
||||
inline double getAltitude_ft() const { return _altitude == NaN ? NaN : _altitude * SG_METER_TO_FEET; }
|
||||
@@ -147,7 +154,8 @@ protected:
|
||||
|
||||
class SGMetar {
|
||||
public:
|
||||
SGMetar(const string& m, const string& proxy = "", const string& port = "", const string &auth = "");
|
||||
SGMetar(const string& m, const string& proxy = "", const string& port = "",
|
||||
const string &auth = "", const time_t time = 0);
|
||||
~SGMetar();
|
||||
|
||||
enum ReportType {
|
||||
@@ -159,6 +167,7 @@ public:
|
||||
|
||||
inline const char *getData() const { return _data; }
|
||||
inline const char *getUnusedData() const { return _m; }
|
||||
inline const bool getProxy() const { return _x_proxy; }
|
||||
inline const char *getId() const { return _icao; }
|
||||
inline int getYear() const { return _year; }
|
||||
inline int getMonth() const { return _month; }
|
||||
@@ -181,10 +190,10 @@ public:
|
||||
inline int getWindRangeFrom() const { return _wind_range_from; }
|
||||
inline int getWindRangeTo() const { return _wind_range_to; }
|
||||
|
||||
inline SGMetarVisibility& getMinVisibility() { return _min_visibility; }
|
||||
inline SGMetarVisibility& getMaxVisibility() { return _max_visibility; }
|
||||
inline SGMetarVisibility& getVertVisibility() { return _vert_visibility; }
|
||||
inline SGMetarVisibility *getDirVisibility() { return _dir_visibility; }
|
||||
inline const SGMetarVisibility& getMinVisibility() const { return _min_visibility; }
|
||||
inline const SGMetarVisibility& getMaxVisibility() const { return _max_visibility; }
|
||||
inline const SGMetarVisibility& getVertVisibility() const { return _vert_visibility; }
|
||||
inline const SGMetarVisibility *getDirVisibility() const { return _dir_visibility; }
|
||||
|
||||
inline double getTemperature_C() const { return _temp; }
|
||||
inline double getTemperature_F() const { return _temp == NaN ? NaN : 1.8 * _temp + 32; }
|
||||
@@ -193,15 +202,21 @@ public:
|
||||
inline double getPressure_hPa() const { return _pressure == NaN ? NaN : _pressure / 100; }
|
||||
inline double getPressure_inHg() const { return _pressure == NaN ? NaN : _pressure * SG_PA_TO_INHG; }
|
||||
|
||||
inline int getRain() const { return _rain; }
|
||||
inline int getHail() const { return _hail; }
|
||||
inline int getSnow() const { return _snow; }
|
||||
inline bool getCAVOK() const { return _cavok; }
|
||||
|
||||
double getRelHumidity() const;
|
||||
|
||||
inline vector<SGMetarCloud>& getClouds() { return _clouds; }
|
||||
inline map<string, SGMetarRunway>& getRunways() { return _runways; }
|
||||
inline vector<string>& getWeather() { return _weather; }
|
||||
inline const vector<SGMetarCloud>& getClouds() const { return _clouds; }
|
||||
inline const map<string, SGMetarRunway>& getRunways() const { return _runways; }
|
||||
inline const vector<string>& getWeather() const { return _weather; }
|
||||
|
||||
protected:
|
||||
string _url;
|
||||
int _grpcount;
|
||||
bool _x_proxy;
|
||||
char *_data;
|
||||
char *_m;
|
||||
char _icao[5];
|
||||
@@ -219,6 +234,10 @@ protected:
|
||||
double _temp;
|
||||
double _dewp;
|
||||
double _pressure;
|
||||
int _rain;
|
||||
int _hail;
|
||||
int _snow;
|
||||
bool _cavok;
|
||||
|
||||
SGMetarVisibility _min_visibility;
|
||||
SGMetarVisibility _max_visibility;
|
||||
@@ -230,6 +249,7 @@ protected:
|
||||
|
||||
bool scanPreambleDate();
|
||||
bool scanPreambleTime();
|
||||
void useCurrentDate();
|
||||
|
||||
bool scanType();
|
||||
bool scanId();
|
||||
@@ -253,7 +273,8 @@ protected:
|
||||
int scanNumber(char **str, int *num, int min, int max = 0);
|
||||
bool scanBoundary(char **str);
|
||||
const struct Token *scanToken(char **str, const struct Token *list);
|
||||
char *loadData(const char *id, const string& proxy, const string& port, const string &auth);
|
||||
char *loadData(const char *id, const string& proxy, const string& port,
|
||||
const string &auth, time_t time);
|
||||
void normalizeData();
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,698 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
#include <simgear/math/polar3d.hxx>
|
||||
#include <simgear/sound/soundmgr_openal.hxx>
|
||||
#include <simgear/scene/sky/cloudfield.hxx>
|
||||
#include <simgear/scene/sky/newcloud.hxx>
|
||||
#include "visual_enviro.hxx"
|
||||
|
||||
#include <vector>
|
||||
|
||||
SG_USING_STD(vector);
|
||||
|
||||
|
||||
typedef struct {
|
||||
Point3D pt;
|
||||
int depth;
|
||||
int prev;
|
||||
} lt_tree_seg;
|
||||
|
||||
#define MAX_RAIN_SLICE 200
|
||||
static float rainpos[MAX_RAIN_SLICE];
|
||||
#define MAX_LT_TREE_SEG 400
|
||||
|
||||
/**
|
||||
* A class to render lightnings.
|
||||
*/
|
||||
class SGLightning {
|
||||
public:
|
||||
/**
|
||||
* Build a new lightning.
|
||||
* The lightning has a limited life time. It will also play a thunder sounder once.
|
||||
* @param lon lon longitude in degree
|
||||
* @param lat lat latitude in degree
|
||||
* @param alt asl of top of lightning
|
||||
*/
|
||||
SGLightning(double lon, double lat, double alt);
|
||||
~SGLightning();
|
||||
void lt_Render(void);
|
||||
void lt_build(void);
|
||||
void lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize);
|
||||
|
||||
// contains all the segments of the lightning
|
||||
lt_tree_seg lt_tree[MAX_LT_TREE_SEG];
|
||||
// segment count
|
||||
int nb_tree;
|
||||
// position of lightning
|
||||
double lon, lat, alt;
|
||||
int sequence_count;
|
||||
// time to live
|
||||
double age;
|
||||
};
|
||||
|
||||
typedef vector<SGLightning *> list_of_lightning;
|
||||
static list_of_lightning lightnings;
|
||||
|
||||
SGEnviro sgEnviro;
|
||||
|
||||
SGEnviro::SGEnviro(void) :
|
||||
view_in_cloud(false),
|
||||
turbulence_enable_state(false),
|
||||
precipitation_enable_state(true),
|
||||
lightning_enable_state(false),
|
||||
soundMgr(NULL),
|
||||
snd_active(false),
|
||||
snd_dist(0.0),
|
||||
last_cloud_turbulence(0.0),
|
||||
cloud_turbulence(0.0),
|
||||
elapsed_time(0.0),
|
||||
dt(0.0),
|
||||
min_time_before_lt(0.0),
|
||||
fov_width(55.0),
|
||||
fov_height(55.0),
|
||||
precipitation_max_alt(0.0),
|
||||
precipitation_density(100.0)
|
||||
|
||||
{
|
||||
for(int i = 0; i < MAX_RAIN_SLICE ; i++)
|
||||
rainpos[i] = sg_random();
|
||||
radarEcho.reserve(100);
|
||||
}
|
||||
|
||||
SGEnviro::~SGEnviro(void) {
|
||||
list_of_lightning::iterator iLightning;
|
||||
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
|
||||
delete (*iLightning);
|
||||
}
|
||||
lightnings.clear();
|
||||
}
|
||||
|
||||
void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time) {
|
||||
view_in_cloud = false;
|
||||
// ask the impostor cache to do some cleanup
|
||||
if(SGNewCloud::cldCache)
|
||||
SGNewCloud::cldCache->startNewFrame();
|
||||
last_cloud_turbulence = cloud_turbulence;
|
||||
cloud_turbulence = 0.0;
|
||||
elapsed_time += delta_time;
|
||||
min_time_before_lt -= delta_time;
|
||||
dt = delta_time;
|
||||
|
||||
sgMat4 T1, LON, LAT;
|
||||
sgVec3 axis;
|
||||
|
||||
sgMakeTransMat4( T1, p );
|
||||
|
||||
sgSetVec3( axis, 0.0, 0.0, 1.0 );
|
||||
sgMakeRotMat4( LON, lon, axis );
|
||||
|
||||
sgSetVec3( axis, 0.0, 1.0, 0.0 );
|
||||
sgMakeRotMat4( LAT, 90.0 - lat, axis );
|
||||
|
||||
sgMat4 TRANSFORM;
|
||||
|
||||
sgCopyMat4( TRANSFORM, T1 );
|
||||
sgPreMultMat4( TRANSFORM, LON );
|
||||
sgPreMultMat4( TRANSFORM, LAT );
|
||||
|
||||
sgCoord pos;
|
||||
sgSetCoord( &pos, TRANSFORM );
|
||||
|
||||
sgMakeCoordMat4( transform, &pos );
|
||||
last_lon = lon;
|
||||
last_lat = lat;
|
||||
last_alt = alt;
|
||||
|
||||
radarEcho.clear();
|
||||
precipitation_max_alt = 400.0;
|
||||
}
|
||||
|
||||
void SGEnviro::endOfFrame(void) {
|
||||
}
|
||||
|
||||
double SGEnviro::get_cloud_turbulence(void) const {
|
||||
return last_cloud_turbulence;
|
||||
}
|
||||
|
||||
// this can be queried to add some turbulence for example
|
||||
bool SGEnviro::is_view_in_cloud(void) const {
|
||||
return view_in_cloud;
|
||||
}
|
||||
void SGEnviro::set_view_in_cloud(bool incloud) {
|
||||
view_in_cloud = incloud;
|
||||
}
|
||||
|
||||
int SGEnviro::get_CacheResolution(void) const {
|
||||
return SGCloudField::get_CacheResolution();
|
||||
}
|
||||
|
||||
int SGEnviro::get_clouds_CacheSize(void) const {
|
||||
return SGCloudField::get_CacheSize();
|
||||
}
|
||||
float SGEnviro::get_clouds_visibility(void) const {
|
||||
return SGCloudField::get_CloudVis();
|
||||
}
|
||||
float SGEnviro::get_clouds_density(void) const {
|
||||
return SGCloudField::get_density();
|
||||
}
|
||||
bool SGEnviro::get_clouds_enable_state(void) const {
|
||||
return SGCloudField::get_enable3dClouds();
|
||||
}
|
||||
|
||||
bool SGEnviro::get_turbulence_enable_state(void) const {
|
||||
return turbulence_enable_state;
|
||||
}
|
||||
|
||||
void SGEnviro::set_CacheResolution(int resolutionPixels) {
|
||||
SGCloudField::set_CacheResolution(resolutionPixels);
|
||||
}
|
||||
|
||||
void SGEnviro::set_clouds_CacheSize(int sizeKb) {
|
||||
SGCloudField::set_CacheSize(sizeKb);
|
||||
}
|
||||
void SGEnviro::set_clouds_visibility(float distance) {
|
||||
SGCloudField::set_CloudVis(distance);
|
||||
}
|
||||
void SGEnviro::set_clouds_density(float density) {
|
||||
SGCloudField::set_density(density);
|
||||
}
|
||||
void SGEnviro::set_clouds_enable_state(bool enable) {
|
||||
SGCloudField::set_enable3dClouds(enable);
|
||||
}
|
||||
void SGEnviro::set_turbulence_enable_state(bool enable) {
|
||||
turbulence_enable_state = enable;
|
||||
}
|
||||
// rain/snow
|
||||
float SGEnviro::get_precipitation_density(void) const {
|
||||
return precipitation_density;
|
||||
}
|
||||
bool SGEnviro::get_precipitation_enable_state(void) const {
|
||||
return precipitation_enable_state;
|
||||
}
|
||||
|
||||
void SGEnviro::set_precipitation_density(float density) {
|
||||
precipitation_density = density;
|
||||
}
|
||||
void SGEnviro::set_precipitation_enable_state(bool enable) {
|
||||
precipitation_enable_state = enable;
|
||||
}
|
||||
|
||||
// others
|
||||
bool SGEnviro::get_lightning_enable_state(void) const {
|
||||
return lightning_enable_state;
|
||||
}
|
||||
|
||||
void SGEnviro::set_lightning_enable_state(bool enable) {
|
||||
lightning_enable_state = enable;
|
||||
if( ! enable ) {
|
||||
// TODO:cleanup
|
||||
}
|
||||
}
|
||||
|
||||
void SGEnviro::setLight(sgVec4 adj_fog_color) {
|
||||
sgCopyVec4( fog_color, adj_fog_color );
|
||||
if( false ) {
|
||||
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
|
||||
}
|
||||
}
|
||||
|
||||
void SGEnviro::callback_cloud(float heading, float alt, float radius, int familly, float dist, int cloudId) {
|
||||
// send data to wx radar
|
||||
// compute turbulence
|
||||
// draw precipitation
|
||||
// draw lightning
|
||||
// compute illumination
|
||||
|
||||
// http://www.pilotfriend.com/flight_training/weather/THUNDERSTORM%20HAZARDS1.htm
|
||||
double turbulence = 0.0;
|
||||
if( dist < radius * radius * 2.25f ) {
|
||||
switch(familly) {
|
||||
case SGNewCloud::CLFamilly_st:
|
||||
turbulence = 0.2;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_ci:
|
||||
case SGNewCloud::CLFamilly_cs:
|
||||
case SGNewCloud::CLFamilly_cc:
|
||||
case SGNewCloud::CLFamilly_ac:
|
||||
case SGNewCloud::CLFamilly_as:
|
||||
turbulence = 0.1;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_sc:
|
||||
turbulence = 0.3;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_ns:
|
||||
turbulence = 0.4;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_cu:
|
||||
turbulence = 0.5;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_cb:
|
||||
turbulence = 0.6;
|
||||
break;
|
||||
}
|
||||
// full turbulence inside cloud, half in the vicinity
|
||||
if( dist > radius * radius )
|
||||
turbulence *= 0.5;
|
||||
if( turbulence > cloud_turbulence )
|
||||
cloud_turbulence = turbulence;
|
||||
// we can do 'local' precipitations too
|
||||
}
|
||||
|
||||
// convert to LWC for radar (experimental)
|
||||
// http://www-das.uwyo.edu/~geerts/cwx/notes/chap08/moist_cloud.html
|
||||
double LWC = 0.0;
|
||||
switch(familly) {
|
||||
case SGNewCloud::CLFamilly_st:
|
||||
LWC = 0.29;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_cu:
|
||||
LWC = 0.27;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_cb:
|
||||
LWC = 2.0;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_sc:
|
||||
LWC = 0.44;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_ci:
|
||||
LWC = 0.03;
|
||||
break;
|
||||
// no data
|
||||
case SGNewCloud::CLFamilly_cs:
|
||||
case SGNewCloud::CLFamilly_cc:
|
||||
case SGNewCloud::CLFamilly_ac:
|
||||
case SGNewCloud::CLFamilly_as:
|
||||
LWC = 0.03;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_ns:
|
||||
LWC = 0.29*2.0;
|
||||
break;
|
||||
}
|
||||
// add to the list for the wxRadar instrument
|
||||
if( LWC > 0.0 )
|
||||
radarEcho.push_back( SGWxRadarEcho ( heading, alt, radius, dist, LWC, false, cloudId ) );
|
||||
|
||||
// NB:data valid only from cockpit view
|
||||
|
||||
// spawn a new lightning
|
||||
if(lightning_enable_state && min_time_before_lt <= 0.0 && (familly == SGNewCloud::CLFamilly_cb) &&
|
||||
dist < 15000.0 * 15000.0 && sg_random() > 0.9f) {
|
||||
double lat, lon;
|
||||
Point3D orig, dest;
|
||||
orig.setlat(last_lat * SG_DEGREES_TO_RADIANS );
|
||||
orig.setlon(last_lon * SG_DEGREES_TO_RADIANS );
|
||||
orig.setelev(0.0);
|
||||
dist = sgSqrt(dist);
|
||||
dest = calc_gc_lon_lat(orig, heading, dist);
|
||||
lon = dest.lon() * SG_RADIANS_TO_DEGREES;
|
||||
lat = dest.lat() * SG_RADIANS_TO_DEGREES;
|
||||
addLightning( lon, lat, alt );
|
||||
|
||||
// reset timer
|
||||
min_time_before_lt = 5.0 + sg_random() * 30;
|
||||
// DEBUG only
|
||||
// min_time_before_lt = 5.0;
|
||||
}
|
||||
if( (alt - radius * 0.1) > precipitation_max_alt )
|
||||
switch(familly) {
|
||||
case SGNewCloud::CLFamilly_st:
|
||||
case SGNewCloud::CLFamilly_cu:
|
||||
case SGNewCloud::CLFamilly_cb:
|
||||
case SGNewCloud::CLFamilly_ns:
|
||||
case SGNewCloud::CLFamilly_sc:
|
||||
precipitation_max_alt = alt - radius * 0.1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
|
||||
return &radarEcho;
|
||||
}
|
||||
|
||||
// precipitation rendering code
|
||||
void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
|
||||
|
||||
sgVec3 light;
|
||||
sgVec3 min_light = {0.35, 0.35, 0.35};
|
||||
sgAddVec3( light, fog_color, min_light );
|
||||
float da = SG_PI * 2.0f / (float) slices;
|
||||
// low number = faster
|
||||
float speedf = 2.5f - speed / 200.0;
|
||||
if( speedf < 1.0f )
|
||||
speedf = 1.0f;
|
||||
float lenf = 0.03f + speed / 2000.0;
|
||||
if( lenf > 0.10f )
|
||||
lenf = 0.10f;
|
||||
float t = fmod((float) elapsed_time, speedf) / speedf;
|
||||
// t = 0.1f;
|
||||
if( !down )
|
||||
t = 1.0f - t;
|
||||
float angle = 0.0f;
|
||||
glColor4f(1.0f, 0.7f, 0.7f, 0.9f);
|
||||
glBegin(GL_LINES);
|
||||
int rainpos_indice = 0;
|
||||
for( int i = 0 ; i < slices ; i++ ) {
|
||||
float x = cos(angle) * baseRadius;
|
||||
float y = sin(angle) * baseRadius;
|
||||
angle += da;
|
||||
sgVec3 dir = {x, -height, y};
|
||||
|
||||
// rain drops at 2 different speed to simulate depth
|
||||
float t1 = (i & 1 ? t : t + t) + rainpos[rainpos_indice];
|
||||
if(t1 > 1.0f) t1 -= 1.0f;
|
||||
if(t1 > 1.0f) t1 -= 1.0f;
|
||||
|
||||
// distant raindrops are more transparent
|
||||
float c = (i & 1 ? t1 * 0.5f : t1 * 0.9f);
|
||||
glColor4f(c * light[0], c * light[1], c * light[2], c);
|
||||
sgVec3 p1, p2;
|
||||
sgScaleVec3(p1, dir, t1);
|
||||
// distant raindrops are shorter
|
||||
float t2 = t1 + (i & 1 ? lenf : lenf+lenf);
|
||||
sgScaleVec3(p2, dir, t2);
|
||||
|
||||
glVertex3f(p1[0], p1[1] + height, p1[2]);
|
||||
glVertex3f(p2[0], p2[1] + height, p2[2]);
|
||||
if( ++rainpos_indice >= MAX_RAIN_SLICE )
|
||||
rainpos_indice = 0;
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void SGEnviro::drawRain(double pitch, double roll, double heading, double speed, double rain_norm) {
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
|
||||
glDisable( GL_FOG );
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
int slice_count = (40.0 + rain_norm*150.0)* precipitation_density / 100.0;
|
||||
|
||||
float angle = speed;
|
||||
if( angle > 90.0 )
|
||||
angle = 90.0;
|
||||
|
||||
glPushMatrix();
|
||||
// TODO:find the real view orientation, not the AC one
|
||||
// the cone rotate with speed
|
||||
angle = -pitch - angle;
|
||||
glRotatef(angle, 1.0, 0.0, 0.0);
|
||||
glRotatef(roll, 0.0, 1.0, 0.0);
|
||||
glRotatef(heading, 0.0, 0.0, 1.0);
|
||||
|
||||
// up cone
|
||||
DrawCone2(15.0, 30.0, slice_count, true, rain_norm, speed);
|
||||
// down cone (usually not visible)
|
||||
if(angle > 0.0 || heading != 0.0)
|
||||
DrawCone2(15.0, -30.0, slice_count, false, rain_norm, speed);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
|
||||
glEnable( GL_FOG );
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
}
|
||||
|
||||
void SGEnviro::set_soundMgr(SGSoundMgr *mgr) {
|
||||
soundMgr = mgr;
|
||||
}
|
||||
|
||||
void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double speed) {
|
||||
if( precipitation_enable_state && rain_norm > 0.0)
|
||||
if( precipitation_max_alt >= last_alt )
|
||||
drawRain(pitch, roll, heading, speed, rain_norm);
|
||||
}
|
||||
|
||||
|
||||
SGLightning::SGLightning(double _lon, double _lat, double _alt) :
|
||||
lon(_lon),
|
||||
lat(_lat),
|
||||
alt(_alt),
|
||||
age(1.0 + sg_random() * 4.0),
|
||||
nb_tree(0)
|
||||
{
|
||||
// sequence_count = 1 + sg_random() * 5.0;
|
||||
lt_build();
|
||||
}
|
||||
|
||||
SGLightning::~SGLightning() {
|
||||
}
|
||||
|
||||
// lightning rendering code
|
||||
void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) {
|
||||
|
||||
sgVec3 dir, newdir;
|
||||
int nseg = 0;
|
||||
Point3D pt = start;
|
||||
if( nbseg == 50 )
|
||||
sgSetVec3( dir, 0.0, -1.0, 0.0 );
|
||||
else {
|
||||
sgSetVec3( dir, sg_random() - 0.5f, sg_random() - 0.5f, sg_random() - 0.5f);
|
||||
sgNormaliseVec3(dir);
|
||||
}
|
||||
if( nb_tree >= MAX_LT_TREE_SEG )
|
||||
return;
|
||||
|
||||
lt_tree[nb_tree].depth = tree_nr;
|
||||
nseg = 0;
|
||||
lt_tree[nb_tree].pt = pt;
|
||||
lt_tree[nb_tree].prev = -1;
|
||||
nb_tree ++;
|
||||
|
||||
// TODO:check agl
|
||||
while(nseg < nbseg && pt.y() > 0.0) {
|
||||
int prev = nb_tree - 1;
|
||||
nseg++;
|
||||
// add a branch
|
||||
if( energy * sg_random() > 0.8f )
|
||||
lt_build_tree_branch(tree_nr + 1, pt, energy * 0.9f, nbseg == 50 ? 10 : nbseg * 0.4f, segsize * 0.7f);
|
||||
|
||||
if( nb_tree >= MAX_LT_TREE_SEG )
|
||||
return;
|
||||
sgSetVec3(newdir, (sg_random() - 0.5f), (sg_random() - 0.5f) - (nbseg == 50 ? 0.5f : 0.0), (sg_random() - 0.5f));
|
||||
sgNormaliseVec3(newdir);
|
||||
sgAddVec3( dir, newdir);
|
||||
sgNormaliseVec3(dir);
|
||||
sgVec3 scaleDir;
|
||||
sgScaleVec3( scaleDir, dir, segsize * energy * 0.5f );
|
||||
pt[PX] += scaleDir[0];
|
||||
pt[PY] += scaleDir[1];
|
||||
pt[PZ] += scaleDir[2];
|
||||
|
||||
lt_tree[nb_tree].depth = tree_nr;
|
||||
lt_tree[nb_tree].pt = pt;
|
||||
lt_tree[nb_tree].prev = prev;
|
||||
nb_tree ++;
|
||||
}
|
||||
}
|
||||
|
||||
void SGLightning::lt_build(void) {
|
||||
Point3D top;
|
||||
nb_tree = 0;
|
||||
top[PX] = 0 ;
|
||||
top[PY] = alt;
|
||||
top[PZ] = 0;
|
||||
lt_build_tree_branch(0, top, 1.0, 50, top[PY] / 8.0);
|
||||
if( ! sgEnviro.soundMgr )
|
||||
return;
|
||||
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
double course = 0.0, dist = 0.0;
|
||||
calc_gc_course_dist( dest, start, &course, &dist );
|
||||
if( dist < 10000.0 && ! sgEnviro.snd_playing && (dist < sgEnviro.snd_dist || ! sgEnviro.snd_active) ) {
|
||||
sgEnviro.snd_timer = 0.0;
|
||||
sgEnviro.snd_wait = dist / 340;
|
||||
sgEnviro.snd_dist = dist;
|
||||
sgEnviro.snd_pos_lat = lat;
|
||||
sgEnviro.snd_pos_lon = lon;
|
||||
sgEnviro.snd_active = true;
|
||||
sgEnviro.snd_playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SGLightning::lt_Render(void) {
|
||||
float flash = 0.5;
|
||||
if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 )
|
||||
flash = sg_random() * 0.75f + 0.25f;
|
||||
float h = lt_tree[0].pt[PY];
|
||||
sgVec4 col={0.62f, 0.83f, 1.0f, 1.0f};
|
||||
sgVec4 c;
|
||||
|
||||
#define DRAW_SEG() \
|
||||
{glBegin(GL_LINES); \
|
||||
glColor4fv(c); \
|
||||
glVertex3f(lt_tree[n].pt[PX], lt_tree[n].pt[PZ], lt_tree[n].pt[PY]); \
|
||||
glVertex3f(lt_tree[lt_tree[n].prev].pt[PX], lt_tree[lt_tree[n].prev].pt[PZ], lt_tree[lt_tree[n].prev].pt[PY]); \
|
||||
glEnd();}
|
||||
|
||||
glDepthMask( GL_FALSE );
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc( GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable( GL_FOG );
|
||||
glPushMatrix();
|
||||
sgMat4 modelview, tmp;
|
||||
ssgGetModelviewMatrix( modelview );
|
||||
sgCopyMat4( tmp, sgEnviro.transform );
|
||||
sgPostMultMat4( tmp, modelview );
|
||||
ssgLoadModelviewMatrix( tmp );
|
||||
|
||||
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
double course = 0.0, dist = 0.0;
|
||||
calc_gc_course_dist( dest, start, &course, &dist );
|
||||
double ax = 0.0, ay = 0.0;
|
||||
ax = cos(course) * dist;
|
||||
ay = sin(course) * dist;
|
||||
|
||||
glTranslatef( ax, ay, -sgEnviro.last_alt );
|
||||
|
||||
sgEnviro.radarEcho.push_back( SGWxRadarEcho ( course, 0.0, 0.0, dist, age, true, 0 ) );
|
||||
|
||||
for( int n = 0 ; n < nb_tree ; n++ ) {
|
||||
if( lt_tree[n].prev < 0 )
|
||||
continue;
|
||||
|
||||
float t1 = sgLerp(0.5, 1.0, lt_tree[n].pt[PY] / h);
|
||||
t1 *= flash;
|
||||
if( lt_tree[n].depth >= 2 ) {
|
||||
glLineWidth(3);
|
||||
sgScaleVec4(c, col, t1 * 0.6f);
|
||||
DRAW_SEG();
|
||||
} else {
|
||||
if( lt_tree[n].depth == 0 ) {
|
||||
glLineWidth(12);
|
||||
sgScaleVec4(c, col, t1 * 0.5f);
|
||||
DRAW_SEG();
|
||||
|
||||
glLineWidth(6);
|
||||
sgScaleVec4(c, col, t1);
|
||||
DRAW_SEG();
|
||||
} else {
|
||||
glLineWidth(6);
|
||||
sgScaleVec4(c, col, t1 * 0.7f);
|
||||
DRAW_SEG();
|
||||
}
|
||||
|
||||
if( lt_tree[n].depth == 0 )
|
||||
glLineWidth(3);
|
||||
else
|
||||
glLineWidth(2);
|
||||
|
||||
sgSetVec4(c, t1, t1, t1, t1);
|
||||
DRAW_SEG();
|
||||
}
|
||||
|
||||
}
|
||||
glLineWidth(1);
|
||||
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
|
||||
glPopMatrix();
|
||||
glDepthMask( GL_TRUE );
|
||||
glEnable( GL_FOG );
|
||||
glEnable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
void SGEnviro::addLightning(double lon, double lat, double alt) {
|
||||
if( lightnings.size() > 10)
|
||||
return;
|
||||
SGLightning *lt= new SGLightning(lon, lat, alt);
|
||||
lightnings.push_back(lt);
|
||||
}
|
||||
|
||||
void SGEnviro::drawLightning(void) {
|
||||
list_of_lightning::iterator iLightning;
|
||||
// play 'thunder' for lightning
|
||||
if( snd_active )
|
||||
if( !snd_playing ) {
|
||||
// wait until sound has reached us
|
||||
snd_timer += dt;
|
||||
if( snd_timer >= snd_wait ) {
|
||||
snd_playing = true;
|
||||
// compute relative position of lightning
|
||||
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
Point3D dest( snd_pos_lon*SG_DEGREES_TO_RADIANS, snd_pos_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
double course = 0.0, dist = 0.0;
|
||||
calc_gc_course_dist( dest, start, &course, &dist );
|
||||
double ax = 0.0, ay = 0.0;
|
||||
ax = cos(course) * dist;
|
||||
ay = sin(course) * dist;
|
||||
SGSoundSample *snd = soundMgr->find("thunder");
|
||||
if( snd ) {
|
||||
ALfloat pos[3]={ax, ay, -sgEnviro.last_alt };
|
||||
snd->set_source_pos(pos);
|
||||
snd->play_once();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if( !soundMgr->is_playing("thunder") ) {
|
||||
snd_active = false;
|
||||
snd_playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( ! lightning_enable_state )
|
||||
return;
|
||||
|
||||
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
|
||||
if( dt )
|
||||
if( sg_random() > 0.95f )
|
||||
(*iLightning)->lt_build();
|
||||
(*iLightning)->lt_Render();
|
||||
(*iLightning)->age -= dt;
|
||||
if( (*iLightning)->age < 0.0 ) {
|
||||
delete (*iLightning);
|
||||
lightnings.erase( iLightning );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SGEnviro::setFOV( float w, float h ) {
|
||||
fov_width = w;
|
||||
fov_height = h;
|
||||
}
|
||||
|
||||
void SGEnviro::getFOV( float &w, float &h ) {
|
||||
w = fov_width;
|
||||
h = fov_height;
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
#ifndef _VISUAL_ENVIRO_HXX
|
||||
#define _VISUAL_ENVIRO_HXX
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include STL_STRING
|
||||
#include <vector>
|
||||
|
||||
SG_USING_STD(vector);
|
||||
SG_USING_STD(string);
|
||||
|
||||
class SGLightning;
|
||||
class SGSoundMgr;
|
||||
|
||||
/**
|
||||
* Simulate some echo on a weather radar.
|
||||
* Container class for the wx radar instrument.
|
||||
*/
|
||||
class SGWxRadarEcho {
|
||||
public:
|
||||
SGWxRadarEcho(float _heading, float _alt, float _radius, float _dist, double _LWC, bool _lightning, int _cloudId) :
|
||||
heading( _heading ),
|
||||
alt ( _alt ),
|
||||
radius ( _radius ),
|
||||
dist ( _dist ),
|
||||
LWC ( _LWC ),
|
||||
lightning ( _lightning ),
|
||||
cloudId ( _cloudId )
|
||||
{}
|
||||
|
||||
/** the heading in radian is versus north */
|
||||
float heading;
|
||||
float alt, radius, dist;
|
||||
/** reflectivity converted to liquid water content. */
|
||||
double LWC;
|
||||
/** if true then this data is for a lightning else it is for water echo. */
|
||||
bool lightning;
|
||||
/** Unique identifier of cloud */
|
||||
int cloudId;
|
||||
};
|
||||
|
||||
typedef vector<SGWxRadarEcho> list_of_SGWxRadarEcho;
|
||||
|
||||
/**
|
||||
* Visual environment helper class.
|
||||
*/
|
||||
class SGEnviro {
|
||||
friend class SGLightning;
|
||||
private:
|
||||
void DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed);
|
||||
void lt_update(void);
|
||||
|
||||
bool view_in_cloud;
|
||||
bool precipitation_enable_state;
|
||||
float precipitation_density;
|
||||
float precipitation_max_alt;
|
||||
bool turbulence_enable_state;
|
||||
double last_cloud_turbulence, cloud_turbulence;
|
||||
bool lightning_enable_state;
|
||||
double elapsed_time, dt;
|
||||
sgVec4 fog_color;
|
||||
sgMat4 transform;
|
||||
double last_lon, last_lat, last_alt;
|
||||
SGSoundMgr *soundMgr;
|
||||
bool snd_active, snd_playing;
|
||||
double snd_timer, snd_wait, snd_pos_lat, snd_pos_lon, snd_dist;
|
||||
double min_time_before_lt;
|
||||
|
||||
float fov_width, fov_height;
|
||||
|
||||
/** a list of all the radar echo. */
|
||||
list_of_SGWxRadarEcho radarEcho;
|
||||
|
||||
public:
|
||||
SGEnviro();
|
||||
~SGEnviro();
|
||||
|
||||
/**
|
||||
* Forward a few states used for renderings.
|
||||
*/
|
||||
void startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time);
|
||||
|
||||
void endOfFrame(void);
|
||||
|
||||
/**
|
||||
* Whenever a cloud is drawn we check his 'impact' on the environment.
|
||||
* @param heading direction of cloud in radians
|
||||
* @param alt asl of cloud in meters
|
||||
* @param radius radius of cloud in meters
|
||||
* @param familly cloud familly
|
||||
* @param dist squared dist to cloud in meters
|
||||
*/
|
||||
void callback_cloud(float heading, float alt, float radius, int familly, float dist, int cloudId);
|
||||
|
||||
void drawRain(double pitch, double roll, double heading, double speed, double rain_norm);
|
||||
/**
|
||||
* Draw rain or snow precipitation around the viewer.
|
||||
* @param rain_norm rain normalized intensity given by metar class
|
||||
* @param snow_norm snow normalized intensity given by metar class
|
||||
* @param hail_norm hail normalized intensity given by metar class
|
||||
* @param pitch pitch rotation of viewer
|
||||
* @param roll roll rotation of viewer
|
||||
* @param speed moving speed of viewer in kt
|
||||
*/
|
||||
void drawPrecipitation(double rain_norm, double snow_norm, double hail_norm,
|
||||
double pitch, double roll, double heading, double speed);
|
||||
|
||||
/**
|
||||
* Draw the lightnings spawned by cumulo nimbus.
|
||||
*/
|
||||
void drawLightning(void);
|
||||
|
||||
/**
|
||||
* Forward the fog color used by the rain rendering.
|
||||
* @param adj_fog_color color of the fog
|
||||
*/
|
||||
void setLight(sgVec4 adj_fog_color);
|
||||
|
||||
// this can be queried to add some turbulence for example
|
||||
bool is_view_in_cloud(void) const;
|
||||
void set_view_in_cloud(bool incloud);
|
||||
double get_cloud_turbulence(void) const;
|
||||
|
||||
// Clouds
|
||||
// return the size of the memory pool used by texture impostors
|
||||
int get_clouds_CacheSize(void) const;
|
||||
int get_CacheResolution(void) const;
|
||||
float get_clouds_visibility(void) const;
|
||||
float get_clouds_density(void) const;
|
||||
bool get_clouds_enable_state(void) const;
|
||||
bool get_turbulence_enable_state(void) const;
|
||||
|
||||
/**
|
||||
* Set the size of the impostor texture cache for 3D clouds.
|
||||
* @param sizeKb size of the texture pool in Kb
|
||||
*/
|
||||
void set_clouds_CacheSize(int sizeKb);
|
||||
/**
|
||||
* Set the resolution of the impostor texture for 3D clouds.
|
||||
* @param resolutionPixels size of each texture in pixels (64|128|256)
|
||||
*/
|
||||
void set_CacheResolution(int resolutionPixels);
|
||||
/**
|
||||
* Set the maximum range used when drawing clouds.
|
||||
* Clouds are blended from totaly transparent at max range to totaly opaque around the viewer
|
||||
* @param distance in meters
|
||||
*/
|
||||
void set_clouds_visibility(float distance);
|
||||
/**
|
||||
* Set the proportion of clouds that will be rendered to limit drop in FPS.
|
||||
* @param density 0..100 no clouds drawn when density == 0, all are drawn when density == 100
|
||||
*/
|
||||
void set_clouds_density(float density);
|
||||
/**
|
||||
* Enable or disable the use of 3D clouds.
|
||||
* @param enable when false we draw the 2D layers
|
||||
*/
|
||||
void set_clouds_enable_state(bool enable);
|
||||
/**
|
||||
* Enable or disable the use of proximity cloud turbulence.
|
||||
* @param enable when true the turbulence is computed based on type of cloud around the AC
|
||||
*/
|
||||
void set_turbulence_enable_state(bool enable);
|
||||
|
||||
// rain/snow
|
||||
float get_precipitation_density(void) const;
|
||||
bool get_precipitation_enable_state(void) const;
|
||||
|
||||
void set_precipitation_density(float density);
|
||||
/**
|
||||
* Enable or disable the rendering of precipitation around the viewer.
|
||||
* @param enable when true we will draw precipitation depending on metar data
|
||||
*/
|
||||
void set_precipitation_enable_state(bool enable);
|
||||
|
||||
// others
|
||||
bool get_lightning_enable_state(void) const;
|
||||
/**
|
||||
* Enable or disable the rendering of lightning and the thunder sound.
|
||||
* @param enable when true we will draw lightning spwaned by cumulonimbus
|
||||
*/
|
||||
void set_lightning_enable_state(bool enable);
|
||||
|
||||
/**
|
||||
* Spawn a new lighning at specified lon/lat.
|
||||
* @param lon position of the new lightning
|
||||
* @param lat position of the new lightning
|
||||
* @param alt asl of the starting point of the lightning in meters
|
||||
*/
|
||||
void addLightning(double lon, double lat, double alt);
|
||||
|
||||
/**
|
||||
* Forward the sound manager instance to be able to play samples.
|
||||
* @param mgr a running sound manager
|
||||
*/
|
||||
void set_soundMgr(SGSoundMgr *mgr);
|
||||
|
||||
void setFOV( float w, float h );
|
||||
void getFOV( float &w, float &h );
|
||||
|
||||
list_of_SGWxRadarEcho *get_radar_echo(void);
|
||||
|
||||
sgMat4 *get_transform(void) { return &transform; }
|
||||
};
|
||||
|
||||
extern SGEnviro sgEnviro;
|
||||
|
||||
#endif // _VISUAL_ENVIRO_HXX
|
||||
@@ -22,6 +22,9 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ void MoonPos::updatePosition(double mjd, double lst, double lat, Star *ourSun)
|
||||
// SG_LOG( SG_GENERAL, SG_INFO, "rho = " << rho );
|
||||
|
||||
if (geoRa < 0)
|
||||
geoRa += (2*SGD_PI);
|
||||
geoRa += SGD_2PI;
|
||||
|
||||
HA = lst - (3.8197186 * geoRa);
|
||||
/* SG_LOG( SG_GENERAL, SG_INFO, "t->getLst() = " << t->getLst()
|
||||
|
||||
@@ -80,7 +80,7 @@ void Star::updatePosition(double mjd)
|
||||
double
|
||||
actTime, eccAnom,
|
||||
xv, yv, v, r,
|
||||
xe, ye, ze, ecl;
|
||||
xe, ecl;
|
||||
|
||||
updateOrbElements(mjd);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ class Star : public CelestialBody
|
||||
private:
|
||||
|
||||
double xs, ys; // the sun's rectangular geocentric coordinates
|
||||
double ye, ze; // the sun's rectangularequatorial rectangular geocentric coordinates
|
||||
double distance; // the sun's distance to the earth
|
||||
|
||||
public:
|
||||
@@ -47,6 +48,8 @@ public:
|
||||
double getw();
|
||||
double getxs();
|
||||
double getys();
|
||||
double getye();
|
||||
double getze();
|
||||
double getDistance();
|
||||
};
|
||||
|
||||
@@ -71,6 +74,16 @@ inline double Star::getys()
|
||||
return ys;
|
||||
}
|
||||
|
||||
inline double Star::getye()
|
||||
{
|
||||
return ye;
|
||||
}
|
||||
|
||||
inline double Star::getze()
|
||||
{
|
||||
return ze;
|
||||
}
|
||||
|
||||
inline double Star::getDistance()
|
||||
{
|
||||
return distance;
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -70,3 +70,9 @@ int SGIOChannel::writestring( const char *str ) {
|
||||
bool SGIOChannel::close() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// dummy eof routine
|
||||
bool SGIOChannel::eof() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -152,6 +152,14 @@ public:
|
||||
*/
|
||||
virtual bool close();
|
||||
|
||||
/**
|
||||
* The eof() method returns true if end of file has been reached
|
||||
* in a context where that makes sense. Otherwise it returns
|
||||
* false.
|
||||
* @return result of eof check
|
||||
*/
|
||||
virtual bool eof();
|
||||
|
||||
inline void set_type( SGChannelType t ) { type = t; }
|
||||
inline SGChannelType get_type() const { return type; }
|
||||
|
||||
|
||||
+38
-38
@@ -59,7 +59,7 @@ void sgReadFloat ( gzFile fd, float *var )
|
||||
read_error = true ;
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int*)var);
|
||||
sgEndianSwap( (uint32_t *)var);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ void sgReadFloat ( gzFile fd, float *var )
|
||||
void sgWriteFloat ( gzFile fd, const float var )
|
||||
{
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int*)&var);
|
||||
sgEndianSwap( (uint32_t *)&var);
|
||||
}
|
||||
if ( gzwrite ( fd, (void *)(&var), sizeof(float) ) != sizeof(float) ) {
|
||||
write_error = true ;
|
||||
@@ -81,7 +81,7 @@ void sgReadDouble ( gzFile fd, double *var )
|
||||
read_error = true ;
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (uint64*)var);
|
||||
sgEndianSwap( (uint64_t *)var);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ void sgReadDouble ( gzFile fd, double *var )
|
||||
void sgWriteDouble ( gzFile fd, const double var )
|
||||
{
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (uint64*)&var);
|
||||
sgEndianSwap( (uint64_t *)&var);
|
||||
}
|
||||
if ( gzwrite ( fd, (void *)(&var), sizeof(double) ) != sizeof(double) ) {
|
||||
write_error = true ;
|
||||
@@ -103,7 +103,7 @@ void sgReadUInt ( gzFile fd, unsigned int *var )
|
||||
read_error = true ;
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int*)var);
|
||||
sgEndianSwap( (uint32_t *)var);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ void sgReadUInt ( gzFile fd, unsigned int *var )
|
||||
void sgWriteUInt ( gzFile fd, const unsigned int var )
|
||||
{
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int*)&var);
|
||||
sgEndianSwap( (uint32_t *)&var);
|
||||
}
|
||||
if ( gzwrite ( fd, (void *)(&var), sizeof(unsigned int) )
|
||||
!= sizeof(unsigned int) )
|
||||
@@ -127,7 +127,7 @@ void sgReadInt ( gzFile fd, int *var )
|
||||
read_error = true ;
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int*)var);
|
||||
sgEndianSwap( (uint32_t *)var);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ void sgReadInt ( gzFile fd, int *var )
|
||||
void sgWriteInt ( gzFile fd, const int var )
|
||||
{
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int*)&var);
|
||||
sgEndianSwap( (uint32_t *)&var);
|
||||
}
|
||||
if ( gzwrite ( fd, (void *)(&var), sizeof(int) ) != sizeof(int) ) {
|
||||
write_error = true ;
|
||||
@@ -143,48 +143,48 @@ void sgWriteInt ( gzFile fd, const int var )
|
||||
}
|
||||
|
||||
|
||||
void sgReadLong ( gzFile fd, long int *var )
|
||||
void sgReadLong ( gzFile fd, int32_t *var )
|
||||
{
|
||||
if ( gzread ( fd, var, sizeof(long int) ) != sizeof(long int) ) {
|
||||
if ( gzread ( fd, var, sizeof(int32_t) ) != sizeof(int32_t) ) {
|
||||
read_error = true ;
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int*)var);
|
||||
sgEndianSwap( (uint32_t *)var);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sgWriteLong ( gzFile fd, const long int var )
|
||||
void sgWriteLong ( gzFile fd, const int32_t var )
|
||||
{
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int*)&var);
|
||||
sgEndianSwap( (uint32_t *)&var);
|
||||
}
|
||||
if ( gzwrite ( fd, (void *)(&var), sizeof(long int) )
|
||||
!= sizeof(long int) )
|
||||
if ( gzwrite ( fd, (void *)(&var), sizeof(int32_t) )
|
||||
!= sizeof(int32_t) )
|
||||
{
|
||||
write_error = true ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sgReadLongLong ( gzFile fd, int64 *var )
|
||||
void sgReadLongLong ( gzFile fd, int64_t *var )
|
||||
{
|
||||
if ( gzread ( fd, var, sizeof(int64) ) != sizeof(int64) ) {
|
||||
if ( gzread ( fd, var, sizeof(int64_t) ) != sizeof(int64_t) ) {
|
||||
read_error = true ;
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (uint64*)var);
|
||||
sgEndianSwap( (uint64_t *)var);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sgWriteLongLong ( gzFile fd, const int64 var )
|
||||
void sgWriteLongLong ( gzFile fd, const int64_t var )
|
||||
{
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (uint64*)&var);
|
||||
sgEndianSwap( (uint64_t *)&var);
|
||||
}
|
||||
if ( gzwrite ( fd, (void *)(&var), sizeof(int64) )
|
||||
!= sizeof(int64) )
|
||||
if ( gzwrite ( fd, (void *)(&var), sizeof(int64_t) )
|
||||
!= sizeof(int64_t) )
|
||||
{
|
||||
write_error = true ;
|
||||
}
|
||||
@@ -197,7 +197,7 @@ void sgReadUShort ( gzFile fd, unsigned short *var )
|
||||
read_error = true ;
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned short int*)var);
|
||||
sgEndianSwap( (uint16_t *)var);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ void sgReadUShort ( gzFile fd, unsigned short *var )
|
||||
void sgWriteUShort ( gzFile fd, const unsigned short var )
|
||||
{
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned short*)&var);
|
||||
sgEndianSwap( (uint16_t *)&var);
|
||||
}
|
||||
if ( gzwrite ( fd, (void *)(&var), sizeof(unsigned short) )
|
||||
!= sizeof(unsigned short) )
|
||||
@@ -221,7 +221,7 @@ void sgReadShort ( gzFile fd, short *var )
|
||||
read_error = true ;
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned short int*)var);
|
||||
sgEndianSwap( (uint16_t *)var);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ void sgReadShort ( gzFile fd, short *var )
|
||||
void sgWriteShort ( gzFile fd, const short var )
|
||||
{
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned short*)&var);
|
||||
sgEndianSwap( (uint16_t *)&var);
|
||||
}
|
||||
if ( gzwrite ( fd, (void *)(&var), sizeof(short) ) != sizeof(short) ) {
|
||||
write_error = true ;
|
||||
@@ -244,7 +244,7 @@ void sgReadFloat ( gzFile fd, const unsigned int n, float *var )
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (unsigned int*)var++);
|
||||
sgEndianSwap( (uint32_t *)var++);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,7 +257,7 @@ void sgWriteFloat ( gzFile fd, const unsigned int n, const float *var )
|
||||
float *ptr = swab;
|
||||
memcpy( swab, var, sizeof(float) * n );
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (unsigned int*)ptr++);
|
||||
sgEndianSwap( (uint32_t *)ptr++);
|
||||
}
|
||||
var = swab;
|
||||
}
|
||||
@@ -275,7 +275,7 @@ void sgReadDouble ( gzFile fd, const unsigned int n, double *var )
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (uint64*)var++);
|
||||
sgEndianSwap( (uint64_t *)var++);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -288,7 +288,7 @@ void sgWriteDouble ( gzFile fd, const unsigned int n, const double *var )
|
||||
double *ptr = swab;
|
||||
memcpy( swab, var, sizeof(double) * n );
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (uint64*)ptr++);
|
||||
sgEndianSwap( (uint64_t *)ptr++);
|
||||
}
|
||||
var = swab;
|
||||
}
|
||||
@@ -325,7 +325,7 @@ void sgReadUShort ( gzFile fd, const unsigned int n, unsigned short *var )
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (unsigned short int*)var++);
|
||||
sgEndianSwap( (uint16_t *)var++);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,7 +338,7 @@ void sgWriteUShort ( gzFile fd, const unsigned int n, const unsigned short *var
|
||||
unsigned short *ptr = swab;
|
||||
memcpy( swab, var, sizeof(unsigned short) * n );
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (unsigned short*)ptr++);
|
||||
sgEndianSwap( (uint16_t *)ptr++);
|
||||
}
|
||||
var = swab;
|
||||
}
|
||||
@@ -360,7 +360,7 @@ void sgReadShort ( gzFile fd, const unsigned int n, short *var )
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (unsigned short int*)var++);
|
||||
sgEndianSwap( (uint16_t *)var++);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,7 +373,7 @@ void sgWriteShort ( gzFile fd, const unsigned int n, const short *var )
|
||||
short *ptr = swab;
|
||||
memcpy( swab, var, sizeof(short) * n );
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (unsigned short*)ptr++);
|
||||
sgEndianSwap( (uint16_t *)ptr++);
|
||||
}
|
||||
var = swab;
|
||||
}
|
||||
@@ -394,7 +394,7 @@ void sgReadUInt ( gzFile fd, const unsigned int n, unsigned int *var )
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (unsigned int*)var++);
|
||||
sgEndianSwap( (uint32_t *)var++);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -407,7 +407,7 @@ void sgWriteUInt ( gzFile fd, const unsigned int n, const unsigned int *var )
|
||||
unsigned int *ptr = swab;
|
||||
memcpy( swab, var, sizeof(unsigned int) * n );
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (unsigned int*)ptr++);
|
||||
sgEndianSwap( (uint32_t *)ptr++);
|
||||
}
|
||||
var = swab;
|
||||
}
|
||||
@@ -429,7 +429,7 @@ void sgReadInt ( gzFile fd, const unsigned int n, int *var )
|
||||
}
|
||||
if ( sgIsBigEndian() ) {
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (unsigned int*)var++);
|
||||
sgEndianSwap( (uint32_t *)var++);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,7 +442,7 @@ void sgWriteInt ( gzFile fd, const unsigned int n, const int *var )
|
||||
int *ptr = swab;
|
||||
memcpy( swab, var, sizeof(int) * n );
|
||||
for ( unsigned int i = 0; i < n; ++i ) {
|
||||
sgEndianSwap( (unsigned int*)ptr++);
|
||||
sgEndianSwap( (uint32_t *)ptr++);
|
||||
}
|
||||
var = swab;
|
||||
}
|
||||
|
||||
+6
-60
@@ -27,19 +27,13 @@
|
||||
#ifndef _SG_LOWLEVEL_HXX
|
||||
#define _SG_LOWLEVEL_HXX
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include <plib/sg.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef __int64 int64;
|
||||
typedef __int64 uint64;
|
||||
#else
|
||||
typedef long long int64;
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/misc/stdint.hxx>
|
||||
|
||||
// Note that output is written in little endian form (and converted as
|
||||
// necessary for big endian machines)
|
||||
@@ -54,10 +48,10 @@ void sgReadUInt ( gzFile fd, unsigned int *var ) ;
|
||||
void sgWriteUInt ( gzFile fd, const unsigned int var ) ;
|
||||
void sgReadInt ( gzFile fd, int *var ) ;
|
||||
void sgWriteInt ( gzFile fd, const int var ) ;
|
||||
void sgReadLong ( gzFile fd, long int *var ) ;
|
||||
void sgWriteLong ( gzFile fd, const long int var ) ;
|
||||
void sgReadLongLong ( gzFile fd, int64 *var ) ;
|
||||
void sgWriteLongLong ( gzFile fd, const int64 var ) ;
|
||||
void sgReadLong ( gzFile fd, int32_t *var ) ;
|
||||
void sgWriteLong ( gzFile fd, const int32_t var ) ;
|
||||
void sgReadLongLong ( gzFile fd, int64_t *var ) ;
|
||||
void sgWriteLongLong ( gzFile fd, const int64_t var ) ;
|
||||
void sgReadUShort ( gzFile fd, unsigned short *var ) ;
|
||||
void sgWriteUShort ( gzFile fd, const unsigned short var ) ;
|
||||
void sgReadShort ( gzFile fd, short *var ) ;
|
||||
@@ -121,52 +115,4 @@ void sgClearWriteError();
|
||||
int sgReadError();
|
||||
int sgWriteError();
|
||||
|
||||
inline bool sgIsLittleEndian() {
|
||||
static const int sgEndianTest = 1;
|
||||
return (*((char *) &sgEndianTest ) != 0);
|
||||
}
|
||||
|
||||
inline bool sgIsBigEndian() {
|
||||
static const int sgEndianTest = 1;
|
||||
return (*((char *) &sgEndianTest ) == 0);
|
||||
}
|
||||
|
||||
inline void sgEndianSwap(unsigned short *x) {
|
||||
*x =
|
||||
(( *x >> 8 ) & 0x00FF ) |
|
||||
(( *x << 8 ) & 0xFF00 ) ;
|
||||
}
|
||||
|
||||
inline void sgEndianSwap(unsigned int *x) {
|
||||
*x =
|
||||
(( *x >> 24 ) & 0x000000FF ) |
|
||||
(( *x >> 8 ) & 0x0000FF00 ) |
|
||||
(( *x << 8 ) & 0x00FF0000 ) |
|
||||
(( *x << 24 ) & 0xFF000000 ) ;
|
||||
}
|
||||
|
||||
inline void sgEndianSwap(uint64 *x) {
|
||||
#ifndef _MSC_VER
|
||||
*x =
|
||||
(( *x >> 56 ) & 0x00000000000000FFULL ) |
|
||||
(( *x >> 40 ) & 0x000000000000FF00ULL ) |
|
||||
(( *x >> 24 ) & 0x0000000000FF0000ULL ) |
|
||||
(( *x >> 8 ) & 0x00000000FF000000ULL ) |
|
||||
(( *x << 8 ) & 0x000000FF00000000ULL ) |
|
||||
(( *x << 24 ) & 0x0000FF0000000000ULL ) |
|
||||
(( *x << 40 ) & 0x00FF000000000000ULL ) |
|
||||
(( *x << 56 ) & 0xFF00000000000000ULL ) ;
|
||||
#else
|
||||
*x =
|
||||
(( *x >> 56 ) & 0x00000000000000FF ) |
|
||||
(( *x >> 40 ) & 0x000000000000FF00 ) |
|
||||
(( *x >> 24 ) & 0x0000000000FF0000 ) |
|
||||
(( *x >> 8 ) & 0x00000000FF000000 ) |
|
||||
(( *x << 8 ) & 0x000000FF00000000 ) |
|
||||
(( *x << 24 ) & 0x0000FF0000000000 ) |
|
||||
(( *x << 40 ) & 0x00FF000000000000 ) |
|
||||
(( *x << 56 ) & 0xFF00000000000000 ) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // _SG_LOWLEVEL_HXX
|
||||
|
||||
@@ -25,22 +25,22 @@ int main() {
|
||||
|
||||
short s = 1111;
|
||||
cout << "short s = " << s << endl;
|
||||
sgEndianSwap((unsigned short *)&s);
|
||||
sgEndianSwap((uint16_t *)&s);
|
||||
cout << "short s = " << s << endl;
|
||||
sgEndianSwap((unsigned short *)&s);
|
||||
sgEndianSwap((uint16_t *)&s);
|
||||
cout << "short s = " << s << endl;
|
||||
|
||||
int i = 1111111;
|
||||
cout << "int i = " << i << endl;
|
||||
sgEndianSwap((unsigned int *)&i);
|
||||
sgEndianSwap((uint32_t *)&i);
|
||||
cout << "int i = " << i << endl;
|
||||
sgEndianSwap((unsigned int *)&i);
|
||||
sgEndianSwap((uint32_t *)&i);
|
||||
cout << "int i = " << i << endl;
|
||||
|
||||
double x = 1111111111;
|
||||
cout << "double x = " << x << endl;
|
||||
sgEndianSwap((unsigned long long *)&x);
|
||||
sgEndianSwap((uint64_t *)&x);
|
||||
cout << "double x = " << x << endl;
|
||||
sgEndianSwap((unsigned long long *)&x);
|
||||
sgEndianSwap((uint64_t *)&x);
|
||||
cout << "double x = " << x << endl;
|
||||
}
|
||||
|
||||
+17
-17
@@ -240,8 +240,8 @@ static void read_object( gzFile fp,
|
||||
if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
|
||||
char *ptr = buf.get_ptr();
|
||||
sgReadBytes( fp, nbytes, ptr );
|
||||
int count = nbytes / (idx_size * sizeof(short));
|
||||
short *sptr = (short *)ptr;
|
||||
int count = nbytes / (idx_size * sizeof(unsigned short));
|
||||
unsigned short *sptr = (unsigned short *)ptr;
|
||||
int_list vs; vs.clear();
|
||||
int_list ns; ns.clear();
|
||||
int_list cs; cs.clear();
|
||||
@@ -249,7 +249,7 @@ static void read_object( gzFile fp,
|
||||
for ( k = 0; k < count; ++k ) {
|
||||
if ( sgIsBigEndian() ) {
|
||||
for ( idx = 0; idx < idx_size; ++idx ) {
|
||||
sgEndianSwap( (unsigned short *)&(sptr[idx]) );
|
||||
sgEndianSwap( (uint16_t *)&(sptr[idx]) );
|
||||
}
|
||||
}
|
||||
idx = 0;
|
||||
@@ -403,9 +403,9 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
|
||||
double *dptr = (double *)ptr;
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (uint64 *)&(dptr[0]) );
|
||||
sgEndianSwap( (uint64 *)&(dptr[1]) );
|
||||
sgEndianSwap( (uint64 *)&(dptr[2]) );
|
||||
sgEndianSwap( (uint64_t *)&(dptr[0]) );
|
||||
sgEndianSwap( (uint64_t *)&(dptr[1]) );
|
||||
sgEndianSwap( (uint64_t *)&(dptr[2]) );
|
||||
}
|
||||
gbs_center = Point3D( dptr[0], dptr[1], dptr[2] );
|
||||
// cout << "Center = " << gbs_center << endl;
|
||||
@@ -413,7 +413,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
|
||||
float *fptr = (float *)ptr;
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int *)fptr );
|
||||
sgEndianSwap( (uint32_t *)fptr );
|
||||
}
|
||||
gbs_radius = fptr[0];
|
||||
// cout << "Bounding radius = " << gbs_radius << endl;
|
||||
@@ -443,9 +443,9 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
wgs84_nodes.reserve( count );
|
||||
for ( k = 0; k < count; ++k ) {
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int *)&(fptr[0]) );
|
||||
sgEndianSwap( (unsigned int *)&(fptr[1]) );
|
||||
sgEndianSwap( (unsigned int *)&(fptr[2]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[0]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[2]) );
|
||||
}
|
||||
wgs84_nodes.push_back( Point3D(fptr[0], fptr[1], fptr[2]) );
|
||||
fptr += 3;
|
||||
@@ -476,10 +476,10 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
colors.reserve(count);
|
||||
for ( k = 0; k < count; ++k ) {
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int *)&(fptr[0]) );
|
||||
sgEndianSwap( (unsigned int *)&(fptr[1]) );
|
||||
sgEndianSwap( (unsigned int *)&(fptr[2]) );
|
||||
sgEndianSwap( (unsigned int *)&(fptr[3]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[0]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[2]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[3]) );
|
||||
}
|
||||
colors.push_back( Point3D( fptr[0], fptr[1], fptr[2] ) );
|
||||
fptr += 4;
|
||||
@@ -544,8 +544,8 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
texcoords.reserve(count);
|
||||
for ( k = 0; k < count; ++k ) {
|
||||
if ( sgIsBigEndian() ) {
|
||||
sgEndianSwap( (unsigned int *)&(fptr[0]) );
|
||||
sgEndianSwap( (unsigned int *)&(fptr[1]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[0]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
||||
}
|
||||
texcoords.push_back( Point3D( fptr[0], fptr[1], 0 ) );
|
||||
fptr += 2;
|
||||
@@ -656,7 +656,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
// write header magic
|
||||
sgWriteUInt( fp, SG_FILE_MAGIC_NUMBER );
|
||||
time_t calendar_time = time(NULL);
|
||||
sgWriteLong( fp, (long int)calendar_time );
|
||||
sgWriteLong( fp, (int32_t)calendar_time );
|
||||
|
||||
// calculate and write number of top level objects
|
||||
string material;
|
||||
|
||||
+13
-2
@@ -29,6 +29,7 @@
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/misc/stdint.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "sg_file.hxx"
|
||||
@@ -39,6 +40,7 @@ SG_USING_STD(string);
|
||||
SGFile::SGFile( const string &file) {
|
||||
set_type( sgFileType );
|
||||
file_name = file;
|
||||
eof_flag = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +72,7 @@ bool SGFile::open( const SGProtocolDir d ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
eof_flag = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -77,7 +80,11 @@ bool SGFile::open( const SGProtocolDir d ) {
|
||||
// read a block of data of specified size
|
||||
int SGFile::read( char *buf, int length ) {
|
||||
// read a chunk
|
||||
return ::read( fp, buf, length );
|
||||
ssize_t result = ::read( fp, buf, length );
|
||||
if ( length > 0 && result == 0 ) {
|
||||
eof_flag = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +94,10 @@ int SGFile::readline( char *buf, int length ) {
|
||||
int pos = lseek( fp, 0, SEEK_CUR );
|
||||
|
||||
// read a chunk
|
||||
int result = ::read( fp, buf, length );
|
||||
ssize_t result = ::read( fp, buf, length );
|
||||
if ( length > 0 && result == 0 ) {
|
||||
eof_flag = true;
|
||||
}
|
||||
|
||||
// find the end of line and reset position
|
||||
int i;
|
||||
@@ -130,5 +140,6 @@ bool SGFile::close() {
|
||||
return false;
|
||||
}
|
||||
|
||||
eof_flag = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ class SGFile : public SGIOChannel {
|
||||
|
||||
string file_name;
|
||||
int fp;
|
||||
bool eof_flag;
|
||||
|
||||
public:
|
||||
|
||||
@@ -89,6 +90,9 @@ public:
|
||||
|
||||
/** @return the name of the file being manipulated. */
|
||||
inline string get_file_name() const { return file_name; }
|
||||
|
||||
/** @return true of eof conditions exists */
|
||||
inline bool eof() const { return eof_flag; };
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <simgear/constants.h>
|
||||
|
||||
#include "fastmath.hxx"
|
||||
#define SGD_PI_2 1.57079632679489661923
|
||||
|
||||
/**
|
||||
* This function is on avarage 9 times faster than the system exp() function
|
||||
|
||||
@@ -185,7 +185,11 @@ operator<< ( ostream& out, const Point3D& p )
|
||||
|
||||
// CONSTRUCTORS
|
||||
|
||||
inline Point3D::Point3D() {}
|
||||
inline Point3D::Point3D()
|
||||
{
|
||||
n[PX] = n[PY] = 0.0;
|
||||
n[PZ] = -9999.0;
|
||||
}
|
||||
|
||||
inline Point3D::Point3D(const double x, const double y, const double z)
|
||||
{
|
||||
|
||||
+228
-4
@@ -30,10 +30,14 @@
|
||||
#include "polar3d.hxx"
|
||||
|
||||
|
||||
// Find the Altitude above the Ellipsoid (WGS84) given the Earth
|
||||
// Centered Cartesian coordinate vector Distances are specified in
|
||||
// meters.
|
||||
double fgGeodAltFromCart(const Point3D& cp)
|
||||
/**
|
||||
* Find the Altitude above the Ellipsoid (WGS84) given the Earth
|
||||
* Centered Cartesian coordinate vector Distances are specified in
|
||||
* meters.
|
||||
* @param cp point specified in cartesian coordinates
|
||||
* @return altitude above the (wgs84) earth in meters
|
||||
*/
|
||||
double sgGeodAltFromCart(const Point3D& cp)
|
||||
{
|
||||
double t_lat, x_alpha, mu_alpha;
|
||||
double lat_geoc, radius;
|
||||
@@ -59,4 +63,224 @@ double fgGeodAltFromCart(const Point3D& cp)
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a polar coordinate to a cartesian coordinate. Lon and Lat
|
||||
* must be specified in radians. The SG convention is for distances
|
||||
* to be specified in meters
|
||||
* @param p point specified in polar coordinates
|
||||
* @return the same point in cartesian coordinates
|
||||
*/
|
||||
Point3D sgPolarToCart3d(const Point3D& p) {
|
||||
double tmp = cos( p.lat() ) * p.radius();
|
||||
|
||||
return Point3D( cos( p.lon() ) * tmp,
|
||||
sin( p.lon() ) * tmp,
|
||||
sin( p.lat() ) * p.radius() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a cartesian coordinate to polar coordinates (lon/lat
|
||||
* specified in radians. Distances are specified in meters.
|
||||
* @param cp point specified in cartesian coordinates
|
||||
* @return the same point in polar coordinates
|
||||
*/
|
||||
Point3D sgCartToPolar3d(const Point3D& cp) {
|
||||
return Point3D( atan2( cp.y(), cp.x() ),
|
||||
SGD_PI_2 -
|
||||
atan2( sqrt(cp.x()*cp.x() + cp.y()*cp.y()), cp.z() ),
|
||||
sqrt(cp.x()*cp.x() + cp.y()*cp.y() + cp.z()*cp.z()) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate new lon/lat given starting lon/lat, and offset radial, and
|
||||
* distance. NOTE: starting point is specifed in radians, distance is
|
||||
* specified in meters (and converted internally to radians)
|
||||
* ... assumes a spherical world.
|
||||
* @param orig specified in polar coordinates
|
||||
* @param course offset radial
|
||||
* @param dist offset distance
|
||||
* @return destination point in polar coordinates
|
||||
*/
|
||||
Point3D calc_gc_lon_lat( const Point3D& orig, double course,
|
||||
double dist ) {
|
||||
Point3D result;
|
||||
|
||||
// lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
|
||||
// IF (cos(lat)=0)
|
||||
// lon=lon1 // endpoint a pole
|
||||
// ELSE
|
||||
// lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
|
||||
// ENDIF
|
||||
|
||||
// printf("calc_lon_lat() offset.theta = %.2f offset.dist = %.2f\n",
|
||||
// offset.theta, offset.dist);
|
||||
|
||||
dist *= SG_METER_TO_NM * SG_NM_TO_RAD;
|
||||
|
||||
result.sety( asin( sin(orig.y()) * cos(dist) +
|
||||
cos(orig.y()) * sin(dist) * cos(course) ) );
|
||||
|
||||
if ( cos(result.y()) < SG_EPSILON ) {
|
||||
result.setx( orig.x() ); // endpoint a pole
|
||||
} else {
|
||||
result.setx(
|
||||
fmod(orig.x() - asin( sin(course) * sin(dist) /
|
||||
cos(result.y()) )
|
||||
+ SGD_PI, SGD_2PI) - SGD_PI );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate course/dist given two spherical points.
|
||||
* @param start starting point
|
||||
* @param dest ending point
|
||||
* @param course resulting course
|
||||
* @param dist resulting distance
|
||||
*/
|
||||
void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
|
||||
double *course, double *dist )
|
||||
{
|
||||
if ( start == dest) {
|
||||
*dist=0;
|
||||
*course=0;
|
||||
return;
|
||||
}
|
||||
// d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 +
|
||||
// cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))
|
||||
double cos_start_y = cos( start.y() );
|
||||
double tmp1 = sin( (start.y() - dest.y()) * 0.5 );
|
||||
double tmp2 = sin( (start.x() - dest.x()) * 0.5 );
|
||||
double d = 2.0 * asin( sqrt( tmp1 * tmp1 +
|
||||
cos_start_y * cos(dest.y()) * tmp2 * tmp2));
|
||||
|
||||
*dist = d * SG_RAD_TO_NM * SG_NM_TO_METER;
|
||||
|
||||
#if 1
|
||||
double c1 = atan2(
|
||||
cos(dest.y())*sin(dest.x()-start.x()),
|
||||
cos(start.y())*sin(dest.y())-
|
||||
sin(start.y())*cos(dest.y())*cos(dest.x()-start.x()));
|
||||
if (c1 >= 0)
|
||||
*course = SGD_2PI-c1;
|
||||
else
|
||||
*course = -c1;
|
||||
#else
|
||||
// We obtain the initial course, tc1, (at point 1) from point 1 to
|
||||
// point 2 by the following. The formula fails if the initial
|
||||
// point is a pole. We can special case this with:
|
||||
//
|
||||
// IF (cos(lat1) < EPS) // EPS a small number ~ machine precision
|
||||
// IF (lat1 > 0)
|
||||
// tc1= pi // starting from N pole
|
||||
// ELSE
|
||||
// tc1= 0 // starting from S pole
|
||||
// ENDIF
|
||||
// ENDIF
|
||||
//
|
||||
// For starting points other than the poles:
|
||||
//
|
||||
// IF sin(lon2-lon1)<0
|
||||
// tc1=acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
|
||||
// ELSE
|
||||
// tc1=2*pi-acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
|
||||
// ENDIF
|
||||
|
||||
// if ( cos(start.y()) < SG_EPSILON ) {
|
||||
// doing it this way saves a transcendental call
|
||||
double sin_start_y = sin( start.y() );
|
||||
if ( fabs(1.0-sin_start_y) < SG_EPSILON ) {
|
||||
// EPS a small number ~ machine precision
|
||||
if ( start.y() > 0 ) {
|
||||
*course = SGD_PI; // starting from N pole
|
||||
} else {
|
||||
*course = 0; // starting from S pole
|
||||
}
|
||||
} else {
|
||||
// For starting points other than the poles:
|
||||
// double tmp3 = sin(d)*cos_start_y);
|
||||
// double tmp4 = sin(dest.y())-sin(start.y())*cos(d);
|
||||
// double tmp5 = acos(tmp4/tmp3);
|
||||
|
||||
// Doing this way gaurentees that the temps are
|
||||
// not stored into memory
|
||||
double tmp5 = acos( (sin(dest.y()) - sin_start_y * cos(d)) /
|
||||
(sin(d) * cos_start_y) );
|
||||
|
||||
// if ( sin( dest.x() - start.x() ) < 0 ) {
|
||||
// the sin of the negative angle is just the opposite sign
|
||||
// of the sin of the angle so tmp2 will have the opposite
|
||||
// sign of sin( dest.x() - start.x() )
|
||||
if ( tmp2 >= 0 ) {
|
||||
*course = tmp5;
|
||||
} else {
|
||||
*course = SGD_2PI - tmp5;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Calculate course/dist given two spherical points.
|
||||
* @param start starting point
|
||||
* @param dest ending point
|
||||
* @param course resulting course
|
||||
* @param dist resulting distance
|
||||
*/
|
||||
void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
|
||||
double *course, double *dist ) {
|
||||
// d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 +
|
||||
// cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))
|
||||
double tmp1 = sin( (start.y() - dest.y()) / 2 );
|
||||
double tmp2 = sin( (start.x() - dest.x()) / 2 );
|
||||
double d = 2.0 * asin( sqrt( tmp1 * tmp1 +
|
||||
cos(start.y()) * cos(dest.y()) * tmp2 * tmp2));
|
||||
// We obtain the initial course, tc1, (at point 1) from point 1 to
|
||||
// point 2 by the following. The formula fails if the initial
|
||||
// point is a pole. We can special case this with:
|
||||
//
|
||||
// IF (cos(lat1) < EPS) // EPS a small number ~ machine precision
|
||||
// IF (lat1 > 0)
|
||||
// tc1= pi // starting from N pole
|
||||
// ELSE
|
||||
// tc1= 0 // starting from S pole
|
||||
// ENDIF
|
||||
// ENDIF
|
||||
//
|
||||
// For starting points other than the poles:
|
||||
//
|
||||
// IF sin(lon2-lon1)<0
|
||||
// tc1=acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
|
||||
// ELSE
|
||||
// tc1=2*pi-acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
|
||||
// ENDIF
|
||||
|
||||
double tc1;
|
||||
|
||||
if ( cos(start.y()) < SG_EPSILON ) {
|
||||
// EPS a small number ~ machine precision
|
||||
if ( start.y() > 0 ) {
|
||||
tc1 = SGD_PI; // starting from N pole
|
||||
} else {
|
||||
tc1 = 0; // starting from S pole
|
||||
}
|
||||
}
|
||||
|
||||
// For starting points other than the poles:
|
||||
|
||||
double tmp3 = sin(d)*cos(start.y());
|
||||
double tmp4 = sin(dest.y())-sin(start.y())*cos(d);
|
||||
double tmp5 = acos(tmp4/tmp3);
|
||||
if ( sin( dest.x() - start.x() ) < 0 ) {
|
||||
tc1 = tmp5;
|
||||
} else {
|
||||
tc1 = SGD_2PI - tmp5;
|
||||
}
|
||||
|
||||
*course = tc1;
|
||||
*dist = d * SG_RAD_TO_NM * SG_NM_TO_METER;
|
||||
}
|
||||
#endif // 0
|
||||
|
||||
+8
-162
@@ -57,13 +57,7 @@ double sgGeodAltFromCart(const Point3D& cp);
|
||||
* @param p point specified in polar coordinates
|
||||
* @return the same point in cartesian coordinates
|
||||
*/
|
||||
inline Point3D sgPolarToCart3d(const Point3D& p) {
|
||||
double tmp = cos( p.lat() ) * p.radius();
|
||||
|
||||
return Point3D( cos( p.lon() ) * tmp,
|
||||
sin( p.lon() ) * tmp,
|
||||
sin( p.lat() ) * p.radius() );
|
||||
}
|
||||
Point3D sgPolarToCart3d(const Point3D& p);
|
||||
|
||||
|
||||
/**
|
||||
@@ -72,12 +66,7 @@ inline Point3D sgPolarToCart3d(const Point3D& p) {
|
||||
* @param cp point specified in cartesian coordinates
|
||||
* @return the same point in polar coordinates
|
||||
*/
|
||||
inline Point3D sgCartToPolar3d(const Point3D& cp) {
|
||||
return Point3D( atan2( cp.y(), cp.x() ),
|
||||
SGD_PI_2 -
|
||||
atan2( sqrt(cp.x()*cp.x() + cp.y()*cp.y()), cp.z() ),
|
||||
sqrt(cp.x()*cp.x() + cp.y()*cp.y() + cp.z()*cp.z()) );
|
||||
}
|
||||
Point3D sgCartToPolar3d(const Point3D& cp);
|
||||
|
||||
|
||||
/**
|
||||
@@ -90,36 +79,7 @@ inline Point3D sgCartToPolar3d(const Point3D& cp) {
|
||||
* @param dist offset distance
|
||||
* @return destination point in polar coordinates
|
||||
*/
|
||||
inline Point3D calc_gc_lon_lat( const Point3D& orig, double course,
|
||||
double dist ) {
|
||||
Point3D result;
|
||||
|
||||
// lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
|
||||
// IF (cos(lat)=0)
|
||||
// lon=lon1 // endpoint a pole
|
||||
// ELSE
|
||||
// lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
|
||||
// ENDIF
|
||||
|
||||
// printf("calc_lon_lat() offset.theta = %.2f offset.dist = %.2f\n",
|
||||
// offset.theta, offset.dist);
|
||||
|
||||
dist *= SG_METER_TO_NM * SG_NM_TO_RAD;
|
||||
|
||||
result.sety( asin( sin(orig.y()) * cos(dist) +
|
||||
cos(orig.y()) * sin(dist) * cos(course) ) );
|
||||
|
||||
if ( cos(result.y()) < SG_EPSILON ) {
|
||||
result.setx( orig.x() ); // endpoint a pole
|
||||
} else {
|
||||
result.setx(
|
||||
fmod(orig.x() - asin( sin(course) * sin(dist) /
|
||||
cos(result.y()) )
|
||||
+ SGD_PI, SGD_2PI) - SGD_PI );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Point3D calc_gc_lon_lat( const Point3D& orig, double course, double dist );
|
||||
|
||||
|
||||
/**
|
||||
@@ -129,71 +89,8 @@ inline Point3D calc_gc_lon_lat( const Point3D& orig, double course,
|
||||
* @param course resulting course
|
||||
* @param dist resulting distance
|
||||
*/
|
||||
inline void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
|
||||
double *course, double *dist )
|
||||
{
|
||||
// d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 +
|
||||
// cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))
|
||||
double cos_start_y = cos( start.y() );
|
||||
volatile double tmp1 = sin( (start.y() - dest.y()) * 0.5 );
|
||||
volatile double tmp2 = sin( (start.x() - dest.x()) * 0.5 );
|
||||
double d = 2.0 * asin( sqrt( tmp1 * tmp1 +
|
||||
cos_start_y * cos(dest.y()) * tmp2 * tmp2));
|
||||
|
||||
*dist = d * SG_RAD_TO_NM * SG_NM_TO_METER;
|
||||
|
||||
// We obtain the initial course, tc1, (at point 1) from point 1 to
|
||||
// point 2 by the following. The formula fails if the initial
|
||||
// point is a pole. We can special case this with:
|
||||
//
|
||||
// IF (cos(lat1) < EPS) // EPS a small number ~ machine precision
|
||||
// IF (lat1 > 0)
|
||||
// tc1= pi // starting from N pole
|
||||
// ELSE
|
||||
// tc1= 0 // starting from S pole
|
||||
// ENDIF
|
||||
// ENDIF
|
||||
//
|
||||
// For starting points other than the poles:
|
||||
//
|
||||
// IF sin(lon2-lon1)<0
|
||||
// tc1=acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
|
||||
// ELSE
|
||||
// tc1=2*pi-acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
|
||||
// ENDIF
|
||||
|
||||
// if ( cos(start.y()) < SG_EPSILON ) {
|
||||
// doing it this way saves a transcendental call
|
||||
double sin_start_y = sin( start.y() );
|
||||
if ( fabs(1.0-sin_start_y) < SG_EPSILON ) {
|
||||
// EPS a small number ~ machine precision
|
||||
if ( start.y() > 0 ) {
|
||||
*course = SGD_PI; // starting from N pole
|
||||
} else {
|
||||
*course = 0; // starting from S pole
|
||||
}
|
||||
} else {
|
||||
// For starting points other than the poles:
|
||||
// double tmp3 = sin(d)*cos_start_y);
|
||||
// double tmp4 = sin(dest.y())-sin(start.y())*cos(d);
|
||||
// double tmp5 = acos(tmp4/tmp3);
|
||||
|
||||
// Doing this way gaurentees that the temps are
|
||||
// not stored into memory
|
||||
double tmp5 = acos( (sin(dest.y()) - sin_start_y * cos(d)) /
|
||||
(sin(d) * cos_start_y) );
|
||||
|
||||
// if ( sin( dest.x() - start.x() ) < 0 ) {
|
||||
// the sin of the negative angle is just the opposite sign
|
||||
// of the sin of the angle so tmp2 will have the opposite
|
||||
// sign of sin( dest.x() - start.x() )
|
||||
if ( tmp2 >= 0 ) {
|
||||
*course = tmp5;
|
||||
} else {
|
||||
*course = 2 * SGD_PI - tmp5;
|
||||
}
|
||||
}
|
||||
}
|
||||
void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
|
||||
double *course, double *dist );
|
||||
|
||||
#if 0
|
||||
/**
|
||||
@@ -203,60 +100,9 @@ inline void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
|
||||
* @param course resulting course
|
||||
* @param dist resulting distance
|
||||
*/
|
||||
inline void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
|
||||
double *course, double *dist ) {
|
||||
// d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 +
|
||||
// cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))
|
||||
double tmp1 = sin( (start.y() - dest.y()) / 2 );
|
||||
double tmp2 = sin( (start.x() - dest.x()) / 2 );
|
||||
double d = 2.0 * asin( sqrt( tmp1 * tmp1 +
|
||||
cos(start.y()) * cos(dest.y()) * tmp2 * tmp2));
|
||||
|
||||
// We obtain the initial course, tc1, (at point 1) from point 1 to
|
||||
// point 2 by the following. The formula fails if the initial
|
||||
// point is a pole. We can special case this with:
|
||||
//
|
||||
// IF (cos(lat1) < EPS) // EPS a small number ~ machine precision
|
||||
// IF (lat1 > 0)
|
||||
// tc1= pi // starting from N pole
|
||||
// ELSE
|
||||
// tc1= 0 // starting from S pole
|
||||
// ENDIF
|
||||
// ENDIF
|
||||
//
|
||||
// For starting points other than the poles:
|
||||
//
|
||||
// IF sin(lon2-lon1)<0
|
||||
// tc1=acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
|
||||
// ELSE
|
||||
// tc1=2*pi-acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
|
||||
// ENDIF
|
||||
|
||||
double tc1;
|
||||
|
||||
if ( cos(start.y()) < SG_EPSILON ) {
|
||||
// EPS a small number ~ machine precision
|
||||
if ( start.y() > 0 ) {
|
||||
tc1 = SGD_PI; // starting from N pole
|
||||
} else {
|
||||
tc1 = 0; // starting from S pole
|
||||
}
|
||||
}
|
||||
|
||||
// For starting points other than the poles:
|
||||
|
||||
double tmp3 = sin(d)*cos(start.y());
|
||||
double tmp4 = sin(dest.y())-sin(start.y())*cos(d);
|
||||
double tmp5 = acos(tmp4/tmp3);
|
||||
if ( sin( dest.x() - start.x() ) < 0 ) {
|
||||
tc1 = tmp5;
|
||||
} else {
|
||||
tc1 = 2 * SGD_PI - tmp5;
|
||||
}
|
||||
|
||||
*course = tc1;
|
||||
*dist = d * SG_RAD_TO_NM * SG_NM_TO_METER;
|
||||
}
|
||||
void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
|
||||
double *course, double *dist );
|
||||
#endif // 0
|
||||
|
||||
#endif // _POLAR3D_HXX
|
||||
|
||||
|
||||
@@ -134,6 +134,13 @@ void sg_srandom_time() {
|
||||
init_genrand(time(NULL));
|
||||
}
|
||||
|
||||
// Seed the random number generater with time() in 10 minute intervals
|
||||
// so we get the same sequence within 10 minutes interval.
|
||||
// This is useful for synchronizing two display systems.
|
||||
void sg_srandom_time_10() {
|
||||
init_genrand(time(NULL) / 600);
|
||||
}
|
||||
|
||||
|
||||
// Seed the random number generater with your own seed so can set up
|
||||
// repeatable randomization.
|
||||
|
||||
@@ -40,6 +40,13 @@ extern "C" {
|
||||
*/
|
||||
void sg_srandom_time();
|
||||
|
||||
/**
|
||||
* Seed the random number generater with time() in 10 minute intervals
|
||||
* so we get the same sequence within 10 minutes interval.
|
||||
* This is useful for synchronizing two display systems.
|
||||
*/
|
||||
void sg_srandom_time_10();
|
||||
|
||||
/**
|
||||
* Seed the random number generater with your own seed so can set up
|
||||
* repeatable randomization.
|
||||
|
||||
@@ -10,7 +10,8 @@ include_HEADERS = \
|
||||
tabbed_values.hxx \
|
||||
texcoord.hxx \
|
||||
zfstream.hxx \
|
||||
interpolator.hxx
|
||||
interpolator.hxx \
|
||||
stdint.hxx
|
||||
|
||||
libsgmisc_a_SOURCES = \
|
||||
sg_path.cxx \
|
||||
@@ -21,7 +22,7 @@ libsgmisc_a_SOURCES = \
|
||||
zfstream.cxx \
|
||||
interpolator.cxx
|
||||
|
||||
noinst_PROGRAMS = tabbed_value_test
|
||||
noinst_PROGRAMS = tabbed_value_test swap_test
|
||||
|
||||
tabbed_value_test_SOURCES = tabbed_values_test.cxx
|
||||
tabbed_value_test_LDADD = \
|
||||
@@ -29,4 +30,6 @@ tabbed_value_test_LDADD = \
|
||||
$(top_builddir)/simgear/xml/libsgxml.a \
|
||||
$(top_builddir)/simgear/debug/libsgdebug.a
|
||||
|
||||
swap_test_SOURCES = swap_test.cpp
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
|
||||
#ifndef _STDINT_HXX
|
||||
#define _STDINT_HXX 1
|
||||
|
||||
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// Written by Curtis Olson - http://www.flightgear.org/~curt
|
||||
// Started September 2001.
|
||||
//
|
||||
// This file is in the Public Domain, and comes with no warranty.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// There are many sick systems out there:
|
||||
//
|
||||
// check for sizeof(float) and sizeof(double)
|
||||
// if sizeof(float) != 4 this code must be patched
|
||||
// if sizeof(double) != 8 this code must be patched
|
||||
//
|
||||
// Those are comments I fetched out of glibc source:
|
||||
// - s390 is big-endian
|
||||
// - Sparc is big-endian, but v9 supports endian conversion
|
||||
// on loads/stores and GCC supports such a mode. Be prepared.
|
||||
// - The MIPS architecture has selectable endianness.
|
||||
// - x86_64 is little-endian.
|
||||
// - CRIS is little-endian.
|
||||
// - m68k is big-endian.
|
||||
// - Alpha is little-endian.
|
||||
// - PowerPC can be little or big endian.
|
||||
// - SH is bi-endian but with a big-endian FPU.
|
||||
// - hppa1.1 big-endian.
|
||||
// - ARM is (usually) little-endian but with a big-endian FPU.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
typedef int ssize_t;
|
||||
#elif defined(sgi) || defined(__sun)
|
||||
# include <sys/types.h>
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
inline uint16_t sg_bswap_16(uint16_t x) {
|
||||
x = (x >> 8) | (x << 8);
|
||||
return x;
|
||||
}
|
||||
|
||||
inline uint32_t sg_bswap_32(uint32_t x) {
|
||||
x = ((x >> 8) & 0x00FF00FFL) | ((x << 8) & 0xFF00FF00L);
|
||||
x = (x >> 16) | (x << 16);
|
||||
return x;
|
||||
}
|
||||
|
||||
inline uint64_t sg_bswap_64(uint64_t x) {
|
||||
x = ((x >> 8) & 0x00FF00FF00FF00FFLL) | ((x << 8) & 0xFF00FF00FF00FF00LL);
|
||||
x = ((x >> 16) & 0x0000FFFF0000FFFFLL) | ((x << 16) & 0xFFFF0000FFFF0000LL);
|
||||
x = (x >> 32) | (x << 32);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
inline bool sgIsLittleEndian() {
|
||||
static const int sgEndianTest = 1;
|
||||
return (*((char *) &sgEndianTest ) != 0);
|
||||
}
|
||||
|
||||
inline bool sgIsBigEndian() {
|
||||
static const int sgEndianTest = 1;
|
||||
return (*((char *) &sgEndianTest ) == 0);
|
||||
}
|
||||
|
||||
inline void sgEndianSwap(uint16_t *x) { *x = sg_bswap_16(*x); }
|
||||
inline void sgEndianSwap(uint32_t *x) { *x = sg_bswap_32(*x); }
|
||||
inline void sgEndianSwap(uint64_t *x) { *x = sg_bswap_64(*x); }
|
||||
|
||||
|
||||
|
||||
#endif // !_STDINT_HXX
|
||||
|
||||
@@ -41,14 +41,14 @@ namespace simgear {
|
||||
|
||||
while (i < len)
|
||||
{
|
||||
while (i < len && isspace(str[i]))
|
||||
while (i < len && isspace((unsigned char)str[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
j = i;
|
||||
|
||||
while (i < len && !isspace(str[i]))
|
||||
while (i < len && !isspace((unsigned char)str[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ namespace simgear {
|
||||
{
|
||||
result.push_back( str.substr(j, i-j) );
|
||||
++countsplit;
|
||||
while (i < len && isspace(str[i]))
|
||||
while (i < len && isspace((unsigned char)str[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include "stdint.hxx"
|
||||
|
||||
int main()
|
||||
{
|
||||
uint16_t sui16, ui16 = 0x0123;
|
||||
uint32_t sui32, ui32 = 0x01234567;
|
||||
uint64_t sui64, ui64 = 0x0123456789ABCDEFLL;
|
||||
|
||||
sui16 = ui16; sgEndianSwap(&sui16);
|
||||
sui32 = ui32; sgEndianSwap(&sui32);
|
||||
sui64 = ui64; sgEndianSwap(&sui64);
|
||||
|
||||
printf("\nUI16: %x (normal)\t\t %x (swapped)\n", ui16, sui16 );
|
||||
printf("UI32: %x (normal)\t\t %x (swapped)\n", ui32, sui32 );
|
||||
printf("UI64: %llx (normal)\t %llx (swapped)\n\n", ui64, sui64 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -189,7 +189,7 @@ point_list sgCalcTexCoords( const SGBucket& b, const point_list& geod_nodes,
|
||||
double clat_rad = clat * SGD_DEGREES_TO_RADIANS;
|
||||
double cos_lat = cos( clat_rad );
|
||||
double local_radius = cos_lat * SG_EQUATORIAL_RADIUS_M;
|
||||
double local_perimeter = 2.0 * local_radius * SGD_PI;
|
||||
double local_perimeter = local_radius * SGD_2PI;
|
||||
double degree_width = local_perimeter / 360.0;
|
||||
|
||||
// cout << "clat = " << clat << endl;
|
||||
@@ -199,7 +199,7 @@ point_list sgCalcTexCoords( const SGBucket& b, const point_list& geod_nodes,
|
||||
// cout << "local_perimeter = " << local_perimeter << endl;
|
||||
// cout << "degree_width = " << degree_width << endl;
|
||||
|
||||
double perimeter = 2.0 * SG_EQUATORIAL_RADIUS_M * SGD_PI;
|
||||
double perimeter = SG_EQUATORIAL_RADIUS_M * SGD_2PI;
|
||||
double degree_height = perimeter / 360.0;
|
||||
// cout << "degree_height = " << degree_height << endl;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ libsgnasal_a_SOURCES = \
|
||||
code.c code.h \
|
||||
codegen.c \
|
||||
data.h \
|
||||
debug.c \
|
||||
gc.c \
|
||||
hash.c \
|
||||
lex.c \
|
||||
@@ -18,6 +17,8 @@ libsgnasal_a_SOURCES = \
|
||||
nasal.h \
|
||||
parse.c parse.h \
|
||||
string.c \
|
||||
vector.c
|
||||
vector.c \
|
||||
thread-posix.c \
|
||||
thread-win32.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
+498
-356
File diff suppressed because it is too large
Load Diff
+74
-21
@@ -5,33 +5,66 @@
|
||||
#include "nasal.h"
|
||||
#include "data.h"
|
||||
|
||||
#define MAX_STACK_DEPTH 1024
|
||||
#define MAX_STACK_DEPTH 512
|
||||
#define MAX_RECURSION 128
|
||||
#define MAX_MARK_DEPTH 32
|
||||
#define MAX_MARK_DEPTH 128
|
||||
|
||||
// Number of objects (per pool per thread) asked for using naGC_get().
|
||||
// Testing with fib.nas shows that this gives the best performance,
|
||||
// without too much per-thread overhead.
|
||||
#define OBJ_CACHE_SZ 128
|
||||
|
||||
enum {
|
||||
OP_AND, OP_OR, OP_NOT, OP_MUL, OP_PLUS, OP_MINUS, OP_DIV, OP_NEG,
|
||||
OP_CAT, OP_LT, OP_LTE, OP_GT, OP_GTE, OP_EQ, OP_NEQ, OP_EACH,
|
||||
OP_JMP, OP_JIFNOT, OP_JIFNIL, OP_FCALL, OP_MCALL, OP_RETURN,
|
||||
OP_JMP, OP_JMPLOOP, OP_JIFNOT, OP_JIFNIL, OP_FCALL, OP_MCALL, OP_RETURN,
|
||||
OP_PUSHCONST, OP_PUSHONE, OP_PUSHZERO, OP_PUSHNIL, OP_POP,
|
||||
OP_DUP, OP_XCHG, OP_INSERT, OP_EXTRACT, OP_MEMBER, OP_SETMEMBER,
|
||||
OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND, OP_NEWHASH, OP_HAPPEND,
|
||||
OP_LINE, OP_MARK, OP_UNMARK, OP_BREAK
|
||||
OP_MARK, OP_UNMARK, OP_BREAK, OP_FTAIL, OP_MTAIL, OP_SETSYM, OP_DUP2,
|
||||
OP_INDEX
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
naRef func; // naFunc object
|
||||
naRef locals; // local per-call namespace
|
||||
naRef args; // vector of arguments
|
||||
int ip; // instruction pointer into code
|
||||
int bp; // opStack pointer to start of frame
|
||||
int line; // current line number
|
||||
};
|
||||
|
||||
struct Globals {
|
||||
// Garbage collecting allocators:
|
||||
struct naPool pools[NUM_NASAL_TYPES];
|
||||
int allocCount;
|
||||
|
||||
// Dead blocks waiting to be freed when it is safe
|
||||
void** deadBlocks;
|
||||
int deadsz;
|
||||
int ndead;
|
||||
|
||||
// Threading stuff
|
||||
int nThreads;
|
||||
int waitCount;
|
||||
int needGC;
|
||||
int bottleneck;
|
||||
void* sem;
|
||||
void* lock;
|
||||
|
||||
// Constants
|
||||
naRef meRef;
|
||||
naRef argRef;
|
||||
naRef parentsRef;
|
||||
|
||||
// A hash of symbol names
|
||||
naRef symbols;
|
||||
|
||||
naRef save;
|
||||
|
||||
struct Context* freeContexts;
|
||||
struct Context* allContexts;
|
||||
};
|
||||
|
||||
struct Context {
|
||||
// Garbage collecting allocators:
|
||||
struct naPool pools[NUM_NASAL_TYPES];
|
||||
|
||||
// Stack(s)
|
||||
struct Frame fStack[MAX_RECURSION];
|
||||
int fTop;
|
||||
@@ -39,26 +72,46 @@ struct Context {
|
||||
int opTop;
|
||||
int markStack[MAX_MARK_DEPTH];
|
||||
int markTop;
|
||||
int done;
|
||||
|
||||
// Constants
|
||||
naRef meRef;
|
||||
naRef argRef;
|
||||
naRef parentsRef;
|
||||
// Free object lists, cached from the global GC
|
||||
struct naObj** free[NUM_NASAL_TYPES];
|
||||
int nfree[NUM_NASAL_TYPES];
|
||||
|
||||
// GC-findable reference point for objects that may live on the
|
||||
// processor ("real") stack during execution. naNew() places them
|
||||
// here, and clears the array each instruction
|
||||
struct naObj** temps;
|
||||
int ntemps;
|
||||
int tempsz;
|
||||
|
||||
// Error handling
|
||||
jmp_buf jumpHandle;
|
||||
char* error;
|
||||
naRef dieArg;
|
||||
|
||||
// GC-findable reference point for objects that may live on the
|
||||
// processor ("real") stack during execution. naNew() places them
|
||||
// here, and clears the array each time we return from a C
|
||||
// function.
|
||||
naRef temps;
|
||||
// Sub-call lists
|
||||
struct Context* callParent;
|
||||
struct Context* callChild;
|
||||
|
||||
naRef save;
|
||||
// Linked list pointers in globals
|
||||
struct Context* nextFree;
|
||||
struct Context* nextAll;
|
||||
};
|
||||
|
||||
void printRefDEBUG(naRef r);
|
||||
#define globals nasal_globals
|
||||
extern struct Globals* globals;
|
||||
|
||||
// Threading low-level functions
|
||||
void* naNewLock();
|
||||
void naLock(void* lock);
|
||||
void naUnlock(void* lock);
|
||||
void* naNewSem();
|
||||
void naSemDown(void* sem);
|
||||
void naSemUpAll(void* sem, int count);
|
||||
|
||||
void naCheckBottleneck();
|
||||
|
||||
#define LOCK() naLock(globals->lock)
|
||||
#define UNLOCK() naUnlock(globals->lock)
|
||||
|
||||
#endif // _CODE_H
|
||||
|
||||
+281
-84
@@ -1,6 +1,8 @@
|
||||
#include "parse.h"
|
||||
#include "code.h"
|
||||
|
||||
#define MAX_FUNARGS 32
|
||||
|
||||
// These are more sensical predicate names in most contexts in this file
|
||||
#define LEFT(tok) ((tok)->children)
|
||||
#define RIGHT(tok) ((tok)->lastChild)
|
||||
@@ -9,24 +11,24 @@
|
||||
// Forward references for recursion
|
||||
static void genExpr(struct Parser* p, struct Token* t);
|
||||
static void genExprList(struct Parser* p, struct Token* t);
|
||||
static naRef newLambda(struct Parser* p, struct Token* t);
|
||||
|
||||
static void emit(struct Parser* p, int byte)
|
||||
static void emit(struct Parser* p, int val)
|
||||
{
|
||||
if(p->cg->nBytes >= p->cg->codeAlloced) {
|
||||
if(p->cg->codesz >= p->cg->codeAlloced) {
|
||||
int i, sz = p->cg->codeAlloced * 2;
|
||||
unsigned char* buf = naParseAlloc(p, sz);
|
||||
unsigned short* buf = naParseAlloc(p, sz*sizeof(unsigned short));
|
||||
for(i=0; i<p->cg->codeAlloced; i++) buf[i] = p->cg->byteCode[i];
|
||||
p->cg->byteCode = buf;
|
||||
p->cg->codeAlloced = sz;
|
||||
}
|
||||
p->cg->byteCode[p->cg->nBytes++] = (unsigned char)byte;
|
||||
p->cg->byteCode[p->cg->codesz++] = (unsigned short)val;
|
||||
}
|
||||
|
||||
static void emitImmediate(struct Parser* p, int byte, int arg)
|
||||
static void emitImmediate(struct Parser* p, int val, int arg)
|
||||
{
|
||||
emit(p, byte);
|
||||
emit(p, arg >> 8);
|
||||
emit(p, arg & 0xff);
|
||||
emit(p, val);
|
||||
emit(p, arg);
|
||||
}
|
||||
|
||||
static void genBinOp(int op, struct Parser* p, struct Token* t)
|
||||
@@ -40,91 +42,218 @@ static void genBinOp(int op, struct Parser* p, struct Token* t)
|
||||
|
||||
static int newConstant(struct Parser* p, naRef c)
|
||||
{
|
||||
int i = p->cg->nConsts++;
|
||||
int i;
|
||||
naVec_append(p->cg->consts, c);
|
||||
i = naVec_size(p->cg->consts) - 1;
|
||||
if(i > 0xffff) naParseError(p, "too many constants in code block", 0);
|
||||
naHash_set(p->cg->consts, naNum(i), c);
|
||||
return i;
|
||||
}
|
||||
|
||||
static naRef getConstant(struct Parser* p, int idx)
|
||||
{
|
||||
naRef c;
|
||||
naHash_get(p->cg->consts, naNum(idx), &c);
|
||||
return c;
|
||||
return naVec_get(p->cg->consts, idx);
|
||||
}
|
||||
|
||||
// Interns a scalar (!) constant and returns its index
|
||||
static int internConstant(struct Parser* p, naRef c)
|
||||
{
|
||||
naRef r;
|
||||
naHash_get(p->cg->interned, c, &r);
|
||||
if(!IS_NIL(r)) {
|
||||
return (int)r.num;
|
||||
int i, n = naVec_size(p->cg->consts);
|
||||
if(IS_CODE(c)) return newConstant(p, c);
|
||||
for(i=0; i<n; i++) {
|
||||
naRef b = naVec_get(p->cg->consts, i);
|
||||
if(IS_NUM(b) && IS_NUM(c) && b.num == c.num) return i;
|
||||
else if(IS_NIL(b) && IS_NIL(c)) return i;
|
||||
else if(naStrEqual(b, c)) return i;
|
||||
}
|
||||
return newConstant(p, c);
|
||||
}
|
||||
|
||||
naRef naInternSymbol(naRef sym)
|
||||
{
|
||||
naRef result;
|
||||
if(naHash_get(globals->symbols, sym, &result))
|
||||
return result;
|
||||
naHash_set(globals->symbols, sym, sym);
|
||||
return sym;
|
||||
}
|
||||
|
||||
static int findConstantIndex(struct Parser* p, struct Token* t)
|
||||
{
|
||||
naRef c, dummy;
|
||||
if(t->type == TOK_NIL) c = naNil();
|
||||
else if(t->str) {
|
||||
c = naStr_fromdata(naNewString(p->context), t->str, t->strlen);
|
||||
naHash_get(globals->symbols, c, &dummy); // noop, make c immutable
|
||||
if(t->type == TOK_SYMBOL) c = naInternSymbol(c);
|
||||
} else if(t->type == TOK_FUNC) c = newLambda(p, t);
|
||||
else if(t->type == TOK_LITERAL) c = naNum(t->num);
|
||||
else naParseError(p, "invalid/non-constant constant", t->line);
|
||||
return internConstant(p, c);
|
||||
}
|
||||
|
||||
static int lastExprInBlock(struct Token* t)
|
||||
{
|
||||
if(!t->parent) return 1;
|
||||
if(t->parent->type == TOK_TOP || t->parent->type == TOK_LCURL) return 1;
|
||||
if(t->parent->type == TOK_SEMI)
|
||||
if(!t->next || t->next->type == TOK_EMPTY)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns true if the node is in "tail context" -- either a child of
|
||||
// a return, the last child of a func block, or else the
|
||||
// last child of an if/elsif/if that is itself in tail context.
|
||||
static int tailContext(struct Token* t)
|
||||
{
|
||||
if(t->parent && t->parent->type == TOK_RETURN)
|
||||
return 1;
|
||||
else if(!lastExprInBlock(t))
|
||||
return 0;
|
||||
|
||||
// Walk up the tree. It is ok to see semicolons, else's, elsifs
|
||||
// and curlies. If we reach the top or a func, then we are in
|
||||
// tail context. If we hit an if, then we are in tail context
|
||||
// only if the "if" node is.
|
||||
while((t = t->parent) != 0)
|
||||
switch(t->type) {
|
||||
case TOK_SEMI: case TOK_LCURL: break;
|
||||
case TOK_ELSE: case TOK_ELSIF: break;
|
||||
case TOK_TOP: case TOK_FUNC: return 1;
|
||||
case TOK_IF: return tailContext(t);
|
||||
default: return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int genScalarConstant(struct Parser* p, struct Token* t)
|
||||
{
|
||||
// These opcodes are for special-case use in other constructs, but
|
||||
// we might as well use them here to save a few bytes in the
|
||||
// instruction stream.
|
||||
if(t->str == 0 && t->num == 1) {
|
||||
emit(p, OP_PUSHONE);
|
||||
} else if(t->str == 0 && t->num == 0) {
|
||||
emit(p, OP_PUSHZERO);
|
||||
} else {
|
||||
int idx = newConstant(p, c);
|
||||
naHash_set(p->cg->interned, c, naNum(idx));
|
||||
int idx = findConstantIndex(p, t);
|
||||
emitImmediate(p, OP_PUSHCONST, idx);
|
||||
return idx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void genScalarConstant(struct Parser* p, struct Token* t)
|
||||
{
|
||||
naRef c = (t->str
|
||||
? naStr_fromdata(naNewString(p->context), t->str, t->strlen)
|
||||
: naNum(t->num));
|
||||
int idx = internConstant(p, c);
|
||||
emitImmediate(p, OP_PUSHCONST, idx);
|
||||
}
|
||||
|
||||
static int genLValue(struct Parser* p, struct Token* t)
|
||||
static int genLValue(struct Parser* p, struct Token* t, int* cidx)
|
||||
{
|
||||
if(t->type == TOK_LPAR) {
|
||||
return genLValue(p, LEFT(t)); // Handle stuff like "(a) = 1"
|
||||
return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1"
|
||||
} else if(t->type == TOK_SYMBOL) {
|
||||
genScalarConstant(p, t);
|
||||
return OP_SETLOCAL;
|
||||
*cidx = genScalarConstant(p, t);
|
||||
return OP_SETSYM;
|
||||
} else if(t->type == TOK_DOT && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
|
||||
genExpr(p, LEFT(t));
|
||||
genScalarConstant(p, RIGHT(t));
|
||||
*cidx = genScalarConstant(p, RIGHT(t));
|
||||
return OP_SETMEMBER;
|
||||
} else if(t->type == TOK_LBRA) {
|
||||
genExpr(p, LEFT(t));
|
||||
genExpr(p, RIGHT(t));
|
||||
return OP_INSERT;
|
||||
} else if(t->type == TOK_VAR && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
|
||||
*cidx = genScalarConstant(p, RIGHT(t));
|
||||
return OP_SETLOCAL;
|
||||
} else {
|
||||
naParseError(p, "bad lvalue", t->line);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void genLambda(struct Parser* p, struct Token* t)
|
||||
static void genEqOp(int op, struct Parser* p, struct Token* t)
|
||||
{
|
||||
int cidx, setop = genLValue(p, LEFT(t), &cidx);
|
||||
if(setop == OP_SETMEMBER) {
|
||||
emit(p, OP_DUP2);
|
||||
emit(p, OP_POP);
|
||||
emitImmediate(p, OP_MEMBER, cidx);
|
||||
} else if(setop == OP_INSERT) {
|
||||
emit(p, OP_DUP2);
|
||||
emit(p, OP_EXTRACT);
|
||||
} else // OP_SETSYM, OP_SETLOCAL
|
||||
emitImmediate(p, OP_LOCAL, cidx);
|
||||
genExpr(p, RIGHT(t));
|
||||
emit(p, op);
|
||||
emit(p, setop);
|
||||
}
|
||||
|
||||
static int defArg(struct Parser* p, struct Token* t)
|
||||
{
|
||||
if(t->type == TOK_LPAR) return defArg(p, RIGHT(t));
|
||||
return findConstantIndex(p, t);
|
||||
}
|
||||
|
||||
static void genArgList(struct Parser* p, struct naCode* c, struct Token* t)
|
||||
{
|
||||
naRef sym;
|
||||
if(t->type == TOK_EMPTY) return;
|
||||
if(!IDENTICAL(c->restArgSym, globals->argRef))
|
||||
naParseError(p, "remainder must be last", t->line);
|
||||
if(t->type == TOK_ELLIPSIS) {
|
||||
if(LEFT(t)->type != TOK_SYMBOL)
|
||||
naParseError(p, "bad function argument expression", t->line);
|
||||
sym = naStr_fromdata(naNewString(p->context),
|
||||
LEFT(t)->str, LEFT(t)->strlen);
|
||||
c->restArgSym = naInternSymbol(sym);
|
||||
c->needArgVector = 1;
|
||||
} else if(t->type == TOK_ASSIGN) {
|
||||
if(LEFT(t)->type != TOK_SYMBOL)
|
||||
naParseError(p, "bad function argument expression", t->line);
|
||||
c->optArgSyms[c->nOptArgs] = findConstantIndex(p, LEFT(t));
|
||||
c->optArgVals[c->nOptArgs++] = defArg(p, RIGHT(t));
|
||||
} else if(t->type == TOK_SYMBOL) {
|
||||
if(c->nOptArgs)
|
||||
naParseError(p, "optional arguments must be last", t->line);
|
||||
if(c->nArgs >= MAX_FUNARGS)
|
||||
naParseError(p, "too many named function arguments", t->line);
|
||||
c->argSyms[c->nArgs++] = findConstantIndex(p, t);
|
||||
} else if(t->type == TOK_COMMA) {
|
||||
genArgList(p, c, LEFT(t));
|
||||
genArgList(p, c, RIGHT(t));
|
||||
} else
|
||||
naParseError(p, "bad function argument expression", t->line);
|
||||
}
|
||||
|
||||
static naRef newLambda(struct Parser* p, struct Token* t)
|
||||
{
|
||||
int idx;
|
||||
struct CodeGenerator* cgSave;
|
||||
naRef codeObj;
|
||||
if(LEFT(t)->type != TOK_LCURL)
|
||||
struct Token* arglist;
|
||||
if(RIGHT(t)->type != TOK_LCURL)
|
||||
naParseError(p, "bad function definition", t->line);
|
||||
|
||||
// Save off the generator state while we do the new one
|
||||
cgSave = p->cg;
|
||||
codeObj = naCodeGen(p, LEFT(LEFT(t)));
|
||||
arglist = LEFT(t)->type == TOK_LPAR ? LEFT(LEFT(t)) : 0;
|
||||
codeObj = naCodeGen(p, LEFT(RIGHT(t)), arglist);
|
||||
p->cg = cgSave;
|
||||
|
||||
idx = newConstant(p, codeObj);
|
||||
emitImmediate(p, OP_PUSHCONST, idx);
|
||||
return codeObj;
|
||||
}
|
||||
|
||||
static void genList(struct Parser* p, struct Token* t)
|
||||
static void genLambda(struct Parser* p, struct Token* t)
|
||||
{
|
||||
emitImmediate(p, OP_PUSHCONST, newConstant(p, newLambda(p, t)));
|
||||
}
|
||||
|
||||
static int genList(struct Parser* p, struct Token* t, int doAppend)
|
||||
{
|
||||
if(t->type == TOK_COMMA) {
|
||||
genExpr(p, LEFT(t));
|
||||
emit(p, OP_VAPPEND);
|
||||
genList(p, RIGHT(t));
|
||||
if(doAppend) emit(p, OP_VAPPEND);
|
||||
return 1 + genList(p, RIGHT(t), doAppend);
|
||||
} else if(t->type == TOK_EMPTY) {
|
||||
return;
|
||||
return 0;
|
||||
} else {
|
||||
genExpr(p, t);
|
||||
emit(p, OP_VAPPEND);
|
||||
if(doAppend) emit(p, OP_VAPPEND);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,18 +283,19 @@ static void genHash(struct Parser* p, struct Token* t)
|
||||
static void genFuncall(struct Parser* p, struct Token* t)
|
||||
{
|
||||
int op = OP_FCALL;
|
||||
int nargs = 0;
|
||||
if(LEFT(t)->type == TOK_DOT) {
|
||||
genExpr(p, LEFT(LEFT(t)));
|
||||
emit(p, OP_DUP);
|
||||
genScalarConstant(p, RIGHT(LEFT(t)));
|
||||
emit(p, OP_MEMBER);
|
||||
emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(LEFT(t))));
|
||||
op = OP_MCALL;
|
||||
} else {
|
||||
genExpr(p, LEFT(t));
|
||||
}
|
||||
emit(p, OP_NEWVEC);
|
||||
if(RIGHT(t)) genList(p, RIGHT(t));
|
||||
emit(p, op);
|
||||
if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0);
|
||||
if(tailContext(t))
|
||||
op = op == OP_FCALL ? OP_FTAIL : OP_MTAIL;
|
||||
emitImmediate(p, op, nargs);
|
||||
}
|
||||
|
||||
static void pushLoop(struct Parser* p, struct Token* label)
|
||||
@@ -191,17 +321,15 @@ static int emitJump(struct Parser* p, int op)
|
||||
{
|
||||
int ip;
|
||||
emit(p, op);
|
||||
ip = p->cg->nBytes;
|
||||
emit(p, 0xff); // dummy address
|
||||
emit(p, 0xff);
|
||||
ip = p->cg->codesz;
|
||||
emit(p, 0xffff); // dummy address
|
||||
return ip;
|
||||
}
|
||||
|
||||
// Points a previous jump instruction at the current "end-of-bytecode"
|
||||
static void fixJumpTarget(struct Parser* p, int spot)
|
||||
{
|
||||
p->cg->byteCode[spot] = p->cg->nBytes >> 8;
|
||||
p->cg->byteCode[spot+1] = p->cg->nBytes & 0xff;
|
||||
p->cg->byteCode[spot] = p->cg->codesz;
|
||||
}
|
||||
|
||||
static void genShortCircuit(struct Parser* p, struct Token* t)
|
||||
@@ -240,6 +368,20 @@ static void genIfElse(struct Parser* p, struct Token* t)
|
||||
genIf(p, t, t->children->next->next);
|
||||
}
|
||||
|
||||
static void genQuestion(struct Parser* p, struct Token* t)
|
||||
{
|
||||
int jumpNext, jumpEnd;
|
||||
if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
|
||||
naParseError(p, "invalid ?: expression", t->line);
|
||||
genExpr(p, LEFT(t)); // the test
|
||||
jumpNext = emitJump(p, OP_JIFNOT);
|
||||
genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
|
||||
jumpEnd = emitJump(p, OP_JMP);
|
||||
fixJumpTarget(p, jumpNext);
|
||||
genExpr(p, RIGHT(RIGHT(t))); // the "else" expr
|
||||
fixJumpTarget(p, jumpEnd);
|
||||
}
|
||||
|
||||
static int countSemis(struct Token* t)
|
||||
{
|
||||
if(!t || t->type != TOK_SEMI) return 0;
|
||||
@@ -255,7 +397,7 @@ static void genLoop(struct Parser* p, struct Token* body,
|
||||
p->cg->loops[p->cg->loopTop-1].breakIP = jumpEnd-1;
|
||||
|
||||
jumpOverContinue = emitJump(p, OP_JMP);
|
||||
p->cg->loops[p->cg->loopTop-1].contIP = p->cg->nBytes;
|
||||
p->cg->loops[p->cg->loopTop-1].contIP = p->cg->codesz;
|
||||
cont = emitJump(p, OP_JMP);
|
||||
fixJumpTarget(p, jumpOverContinue);
|
||||
|
||||
@@ -263,7 +405,7 @@ static void genLoop(struct Parser* p, struct Token* body,
|
||||
emit(p, OP_POP);
|
||||
fixJumpTarget(p, cont);
|
||||
if(update) { genExpr(p, update); emit(p, OP_POP); }
|
||||
emitImmediate(p, OP_JMP, loopTop);
|
||||
emitImmediate(p, OP_JMPLOOP, loopTop);
|
||||
fixJumpTarget(p, jumpEnd);
|
||||
popLoop(p);
|
||||
emit(p, OP_PUSHNIL); // Leave something on the stack
|
||||
@@ -276,7 +418,7 @@ static void genForWhile(struct Parser* p, struct Token* init,
|
||||
int loopTop, jumpEnd;
|
||||
if(init) { genExpr(p, init); emit(p, OP_POP); }
|
||||
pushLoop(p, label);
|
||||
loopTop = p->cg->nBytes;
|
||||
loopTop = p->cg->codesz;
|
||||
genExpr(p, test);
|
||||
jumpEnd = emitJump(p, OP_JIFNOT);
|
||||
genLoop(p, body, update, label, loopTop, jumpEnd);
|
||||
@@ -322,7 +464,7 @@ static void genFor(struct Parser* p, struct Token* t)
|
||||
|
||||
static void genForEach(struct Parser* p, struct Token* t)
|
||||
{
|
||||
int loopTop, jumpEnd, assignOp;
|
||||
int loopTop, jumpEnd, assignOp, dummy;
|
||||
struct Token *elem, *body, *vec, *label=0;
|
||||
struct Token *h = LEFT(LEFT(t));
|
||||
int semis = countSemis(h);
|
||||
@@ -341,10 +483,10 @@ static void genForEach(struct Parser* p, struct Token* t)
|
||||
pushLoop(p, label);
|
||||
genExpr(p, vec);
|
||||
emit(p, OP_PUSHZERO);
|
||||
loopTop = p->cg->nBytes;
|
||||
emit(p, OP_EACH);
|
||||
loopTop = p->cg->codesz;
|
||||
emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
|
||||
jumpEnd = emitJump(p, OP_JIFNIL);
|
||||
assignOp = genLValue(p, elem);
|
||||
assignOp = genLValue(p, elem, &dummy);
|
||||
emit(p, OP_XCHG);
|
||||
emit(p, assignOp);
|
||||
emit(p, OP_POP);
|
||||
@@ -382,18 +524,34 @@ static void genBreakContinue(struct Parser* p, struct Token* t)
|
||||
emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp);
|
||||
}
|
||||
|
||||
static void genExpr(struct Parser* p, struct Token* t)
|
||||
static void newLineEntry(struct Parser* p, int line)
|
||||
{
|
||||
int i;
|
||||
if(t == 0)
|
||||
naParseError(p, "BUG: null subexpression", -1);
|
||||
if(p->cg->nextLineIp >= p->cg->nLineIps) {
|
||||
int nsz = p->cg->nLineIps*2 + 1;
|
||||
unsigned short* n = naParseAlloc(p, sizeof(unsigned short)*2*nsz);
|
||||
for(i=0; i<(p->cg->nextLineIp*2); i++)
|
||||
n[i] = p->cg->lineIps[i];
|
||||
p->cg->lineIps = n;
|
||||
p->cg->nLineIps = nsz;
|
||||
}
|
||||
p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) p->cg->codesz;
|
||||
p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) line;
|
||||
}
|
||||
|
||||
static void genExpr(struct Parser* p, struct Token* t)
|
||||
{
|
||||
int i, dummy;
|
||||
if(t->line != p->cg->lastLine)
|
||||
emitImmediate(p, OP_LINE, t->line);
|
||||
newLineEntry(p, t->line);
|
||||
p->cg->lastLine = t->line;
|
||||
switch(t->type) {
|
||||
case TOK_IF:
|
||||
genIfElse(p, t);
|
||||
break;
|
||||
case TOK_QUESTION:
|
||||
genQuestion(p, t);
|
||||
break;
|
||||
case TOK_WHILE:
|
||||
genWhile(p, t);
|
||||
break;
|
||||
@@ -401,6 +559,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
genFor(p, t);
|
||||
break;
|
||||
case TOK_FOREACH:
|
||||
case TOK_FORINDEX:
|
||||
genForEach(p, t);
|
||||
break;
|
||||
case TOK_BREAK: case TOK_CONTINUE:
|
||||
@@ -421,7 +580,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
genBinOp(OP_EXTRACT, p, t); // a[i]
|
||||
} else {
|
||||
emit(p, OP_NEWVEC);
|
||||
genList(p, LEFT(t));
|
||||
genList(p, LEFT(t), 1);
|
||||
}
|
||||
break;
|
||||
case TOK_LCURL:
|
||||
@@ -429,13 +588,14 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
genHash(p, LEFT(t));
|
||||
break;
|
||||
case TOK_ASSIGN:
|
||||
i = genLValue(p, LEFT(t));
|
||||
i = genLValue(p, LEFT(t), &dummy);
|
||||
genExpr(p, RIGHT(t));
|
||||
emit(p, i); // use the op appropriate to the lvalue
|
||||
break;
|
||||
case TOK_RETURN:
|
||||
if(RIGHT(t)) genExpr(p, RIGHT(t));
|
||||
else emit(p, OP_PUSHNIL);
|
||||
for(i=0; i<p->cg->loopTop; i++) emit(p, OP_UNMARK);
|
||||
emit(p, OP_RETURN);
|
||||
break;
|
||||
case TOK_NOT:
|
||||
@@ -443,8 +603,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
emit(p, OP_NOT);
|
||||
break;
|
||||
case TOK_SYMBOL:
|
||||
genScalarConstant(p, t);
|
||||
emit(p, OP_LOCAL);
|
||||
emitImmediate(p, OP_LOCAL, findConstantIndex(p, t));
|
||||
break;
|
||||
case TOK_LITERAL:
|
||||
genScalarConstant(p, t);
|
||||
@@ -468,8 +627,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
genExpr(p, LEFT(t));
|
||||
if(RIGHT(t)->type != TOK_SYMBOL)
|
||||
naParseError(p, "object field not symbol", RIGHT(t)->line);
|
||||
genScalarConstant(p, RIGHT(t));
|
||||
emit(p, OP_MEMBER);
|
||||
emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
|
||||
break;
|
||||
case TOK_EMPTY: case TOK_NIL:
|
||||
emit(p, OP_PUSHNIL); break; // *NOT* a noop!
|
||||
@@ -486,6 +644,11 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
case TOK_NEQ: genBinOp(OP_NEQ, p, t); break;
|
||||
case TOK_GT: genBinOp(OP_GT, p, t); break;
|
||||
case TOK_GTE: genBinOp(OP_GTE, p, t); break;
|
||||
case TOK_PLUSEQ: genEqOp(OP_PLUS, p, t); break;
|
||||
case TOK_MINUSEQ: genEqOp(OP_MINUS, p, t); break;
|
||||
case TOK_MULEQ: genEqOp(OP_MUL, p, t); break;
|
||||
case TOK_DIVEQ: genEqOp(OP_DIV, p, t); break;
|
||||
case TOK_CATEQ: genEqOp(OP_CAT, p, t); break;
|
||||
default:
|
||||
naParseError(p, "parse error", t->line);
|
||||
};
|
||||
@@ -504,7 +667,7 @@ static void genExprList(struct Parser* p, struct Token* t)
|
||||
}
|
||||
}
|
||||
|
||||
naRef naCodeGen(struct Parser* p, struct Token* t)
|
||||
naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
|
||||
{
|
||||
int i;
|
||||
naRef codeObj;
|
||||
@@ -513,28 +676,62 @@ naRef naCodeGen(struct Parser* p, struct Token* t)
|
||||
|
||||
cg.lastLine = 0;
|
||||
cg.codeAlloced = 1024; // Start fairly big, this is a cheap allocation
|
||||
cg.byteCode = naParseAlloc(p, cg.codeAlloced);
|
||||
cg.nBytes = 0;
|
||||
cg.consts = naNewHash(p->context);
|
||||
cg.interned = naNewHash(p->context);
|
||||
cg.nConsts = 0;
|
||||
cg.byteCode = naParseAlloc(p, cg.codeAlloced *sizeof(unsigned short));
|
||||
cg.codesz = 0;
|
||||
cg.consts = naNewVector(p->context);
|
||||
cg.loopTop = 0;
|
||||
cg.lineIps = 0;
|
||||
cg.nLineIps = 0;
|
||||
cg.nextLineIp = 0;
|
||||
p->cg = &cg;
|
||||
|
||||
genExprList(p, t);
|
||||
genExprList(p, block);
|
||||
emit(p, OP_RETURN);
|
||||
|
||||
// Now make a code object
|
||||
codeObj = naNewCode(p->context);
|
||||
code = codeObj.ref.ptr.code;
|
||||
code->nBytes = cg.nBytes;
|
||||
code->byteCode = naAlloc(cg.nBytes);
|
||||
for(i=0; i < cg.nBytes; i++)
|
||||
|
||||
// Parse the argument list, if any
|
||||
code->restArgSym = globals->argRef;
|
||||
code->nArgs = code->nOptArgs = 0;
|
||||
code->argSyms = code->optArgSyms = code->optArgVals = 0;
|
||||
code->needArgVector = 1;
|
||||
if(arglist) {
|
||||
code->argSyms = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
|
||||
code->optArgSyms = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
|
||||
code->optArgVals = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
|
||||
code->needArgVector = 0;
|
||||
genArgList(p, code, arglist);
|
||||
if(code->nArgs) {
|
||||
int i, *nsyms;
|
||||
nsyms = naAlloc(sizeof(int) * code->nArgs);
|
||||
for(i=0; i<code->nArgs; i++) nsyms[i] = code->argSyms[i];
|
||||
code->argSyms = nsyms;
|
||||
} else code->argSyms = 0;
|
||||
if(code->nOptArgs) {
|
||||
int i, *nsyms, *nvals;
|
||||
nsyms = naAlloc(sizeof(int) * code->nOptArgs);
|
||||
nvals = naAlloc(sizeof(int) * code->nOptArgs);
|
||||
for(i=0; i<code->nOptArgs; i++) nsyms[i] = code->optArgSyms[i];
|
||||
for(i=0; i<code->nOptArgs; i++) nvals[i] = code->optArgVals[i];
|
||||
code->optArgSyms = nsyms;
|
||||
code->optArgVals = nvals;
|
||||
} else code->optArgSyms = code->optArgVals = 0;
|
||||
}
|
||||
|
||||
code->codesz = cg.codesz;
|
||||
code->byteCode = naAlloc(cg.codesz * sizeof(unsigned short));
|
||||
for(i=0; i < cg.codesz; i++)
|
||||
code->byteCode[i] = cg.byteCode[i];
|
||||
code->nConstants = cg.nConsts;
|
||||
code->nConstants = naVec_size(cg.consts);
|
||||
code->constants = naAlloc(code->nConstants * sizeof(naRef));
|
||||
code->srcFile = p->srcFile;
|
||||
for(i=0; i<code->nConstants; i++)
|
||||
code->constants[i] = getConstant(p, i);
|
||||
|
||||
code->nLines = p->cg->nextLineIp;
|
||||
code->lineIps = naAlloc(sizeof(unsigned short)*p->cg->nLineIps*2);
|
||||
for(i=0; i<p->cg->nLineIps*2; i++)
|
||||
code->lineIps[i] = p->cg->lineIps[i];
|
||||
return codeObj;
|
||||
}
|
||||
|
||||
+46
-34
@@ -3,27 +3,27 @@
|
||||
|
||||
#include "nasal.h"
|
||||
|
||||
// Notes: A CODE object is a compiled set of bytecode instructions.
|
||||
// What actually gets executed at runtime is a bound FUNC object,
|
||||
// which combines the raw code with a pointer to a CLOSURE chain of
|
||||
// namespaces.
|
||||
enum { T_STR, T_VEC, T_HASH, T_CODE, T_CLOSURE, T_FUNC, T_CCODE, T_GHOST,
|
||||
enum { T_STR, T_VEC, T_HASH, T_CODE, T_FUNC, T_CCODE, T_GHOST,
|
||||
NUM_NASAL_TYPES }; // V. important that this come last!
|
||||
|
||||
#define IS_REF(r) ((r).ref.reftag == NASAL_REFTAG)
|
||||
#define IS_NUM(r) ((r).ref.reftag != NASAL_REFTAG)
|
||||
#define IS_OBJ(r) (IS_REF((r)) && (r).ref.ptr.obj != 0)
|
||||
//#define IS_OBJ(r) (IS_REF((r)) && (r).ref.ptr.obj != 0 && (((r).ref.ptr.obj->type == 123) ? *(int*)0 : 1))
|
||||
#define IS_NIL(r) (IS_REF((r)) && (r).ref.ptr.obj == 0)
|
||||
#define IS_STR(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_STR)
|
||||
#define IS_VEC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_VEC)
|
||||
#define IS_HASH(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_HASH)
|
||||
#define IS_CODE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CODE)
|
||||
#define IS_FUNC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_FUNC)
|
||||
#define IS_CLOSURE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CLOSURE)
|
||||
#define IS_CCODE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CCODE)
|
||||
#define IS_GHOST(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_GHOST)
|
||||
#define IS_CONTAINER(r) (IS_VEC(r)||IS_HASH(r))
|
||||
#define IS_SCALAR(r) (IS_NUM((r)) || IS_STR((r)))
|
||||
#define IDENTICAL(a, b) (IS_REF(a) && IS_REF(b) \
|
||||
&& a.ref.ptr.obj == b.ref.ptr.obj)
|
||||
|
||||
#define MUTABLE(r) (IS_STR(r) && (r).ref.ptr.str->hashcode == 0)
|
||||
|
||||
// This is a macro instead of a separate struct to allow compilers to
|
||||
// avoid padding. GCC on x86, at least, will always padd the size of
|
||||
@@ -41,13 +41,18 @@ struct naStr {
|
||||
GC_HEADER;
|
||||
int len;
|
||||
unsigned char* data;
|
||||
unsigned int hashcode;
|
||||
};
|
||||
|
||||
struct VecRec {
|
||||
int size;
|
||||
int alloced;
|
||||
naRef array[];
|
||||
};
|
||||
|
||||
struct naVec {
|
||||
GC_HEADER;
|
||||
int size;
|
||||
int alloced;
|
||||
naRef* array;
|
||||
struct VecRec* rec;
|
||||
};
|
||||
|
||||
struct HashNode {
|
||||
@@ -56,32 +61,40 @@ struct HashNode {
|
||||
struct HashNode* next;
|
||||
};
|
||||
|
||||
struct naHash {
|
||||
GC_HEADER;
|
||||
struct HashRec {
|
||||
int size;
|
||||
int dels;
|
||||
int lgalloced;
|
||||
struct HashNode* nodes;
|
||||
struct HashNode** table;
|
||||
int nextnode;
|
||||
struct HashNode* table[];
|
||||
};
|
||||
|
||||
struct naHash {
|
||||
GC_HEADER;
|
||||
struct HashRec* rec;
|
||||
};
|
||||
|
||||
struct naCode {
|
||||
GC_HEADER;
|
||||
unsigned char* byteCode;
|
||||
int nBytes;
|
||||
unsigned char nArgs;
|
||||
unsigned char nOptArgs;
|
||||
unsigned char needArgVector;
|
||||
unsigned short nConstants;
|
||||
unsigned short nLines;
|
||||
unsigned short codesz;
|
||||
unsigned short* byteCode;
|
||||
naRef* constants;
|
||||
int nConstants;
|
||||
int* argSyms; // indices into constants
|
||||
int* optArgSyms;
|
||||
int* optArgVals;
|
||||
unsigned short* lineIps; // pairs of {ip, line}
|
||||
naRef srcFile;
|
||||
naRef restArgSym; // The "..." vector name, defaults to "arg"
|
||||
};
|
||||
|
||||
struct naFunc {
|
||||
GC_HEADER;
|
||||
naRef code;
|
||||
naRef closure;
|
||||
};
|
||||
|
||||
struct naClosure {
|
||||
GC_HEADER;
|
||||
naRef namespace;
|
||||
naRef next; // parent closure
|
||||
};
|
||||
@@ -100,40 +113,39 @@ struct naGhost {
|
||||
struct naPool {
|
||||
int type;
|
||||
int elemsz;
|
||||
int nblocks;
|
||||
struct Block* blocks;
|
||||
int nfree; // number of entries in the free array
|
||||
int freesz; // size of the free array
|
||||
void** free; // pointers to usable elements
|
||||
void** free0; // pointer to the alloced buffer
|
||||
int freesz; // size of the alloced buffer
|
||||
void** free; // current "free frame"
|
||||
int nfree; // down-counting index within the free frame
|
||||
int freetop; // curr. top of the free list
|
||||
};
|
||||
|
||||
void naFree(void* m);
|
||||
void* naAlloc(int n);
|
||||
void* naRealloc(void* buf, int sz);
|
||||
void naBZero(void* m, int n);
|
||||
|
||||
int naTypeSize(int type);
|
||||
void naGarbageCollect();
|
||||
naRef naObj(int type, struct naObj* o);
|
||||
naRef naNew(naContext c, int type);
|
||||
naRef naNewCode(naContext c);
|
||||
naRef naNewClosure(naContext c, naRef namespace, naRef next);
|
||||
|
||||
int naStr_equal(naRef s1, naRef s2);
|
||||
naRef naStr_fromnum(naRef dest, double num);
|
||||
int naStr_numeric(naRef str);
|
||||
int naStr_parsenum(char* str, int len, double* result);
|
||||
int naStr_tonum(naRef str, double* out);
|
||||
|
||||
void naVec_init(naRef vec);
|
||||
naRef naStr_buf(naRef str, int len);
|
||||
|
||||
int naHash_tryset(naRef hash, naRef key, naRef val); // sets if exists
|
||||
void naHash_init(naRef hash);
|
||||
int naHash_sym(struct naHash* h, struct naStr* sym, naRef* out);
|
||||
void naHash_newsym(struct naHash* h, naRef* sym, naRef* val);
|
||||
|
||||
void naGC_init(struct naPool* p, int type);
|
||||
struct naObj* naGC_get(struct naPool* p);
|
||||
int naGC_size(struct naPool* p);
|
||||
void naGC_mark(naRef r);
|
||||
void naGC_reap(struct naPool* p);
|
||||
struct naObj** naGC_get(struct naPool* p, int n, int* nout);
|
||||
void naGC_swapfree(void** target, void* val);
|
||||
void naGC_freedead();
|
||||
|
||||
void naStr_gcclean(struct naStr* s);
|
||||
void naVec_gcclean(struct naVec* s);
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nasal.h"
|
||||
#include "parse.h"
|
||||
#include "code.h"
|
||||
|
||||
// Bytecode operator to string
|
||||
char* opStringDEBUG(int op)
|
||||
{
|
||||
static char buf[256];
|
||||
switch(op) {
|
||||
case OP_AND: return "AND";
|
||||
case OP_OR: return "OR";
|
||||
case OP_NOT: return "NOT";
|
||||
case OP_MUL: return "MUL";
|
||||
case OP_PLUS: return "PLUS";
|
||||
case OP_MINUS: return "MINUS";
|
||||
case OP_DIV: return "DIV";
|
||||
case OP_NEG: return "NEG";
|
||||
case OP_CAT: return "CAT";
|
||||
case OP_LT: return "LT";
|
||||
case OP_LTE: return "LTE";
|
||||
case OP_GT: return "GT";
|
||||
case OP_GTE: return "GTE";
|
||||
case OP_EQ: return "EQ";
|
||||
case OP_NEQ: return "NEQ";
|
||||
case OP_EACH: return "EACH";
|
||||
case OP_JMP: return "JMP";
|
||||
case OP_JIFNOT: return "JIFNOT";
|
||||
case OP_JIFNIL: return "JIFNIL";
|
||||
case OP_FCALL: return "FCALL";
|
||||
case OP_MCALL: return "MCALL";
|
||||
case OP_RETURN: return "RETURN";
|
||||
case OP_PUSHCONST: return "PUSHCONST";
|
||||
case OP_PUSHONE: return "PUSHONE";
|
||||
case OP_PUSHZERO: return "PUSHZERO";
|
||||
case OP_PUSHNIL: return "PUSHNIL";
|
||||
case OP_POP: return "POP";
|
||||
case OP_DUP: return "DUP";
|
||||
case OP_XCHG: return "XCHG";
|
||||
case OP_INSERT: return "INSERT";
|
||||
case OP_EXTRACT: return "EXTRACT";
|
||||
case OP_MEMBER: return "MEMBER";
|
||||
case OP_SETMEMBER: return "SETMEMBER";
|
||||
case OP_LOCAL: return "LOCAL";
|
||||
case OP_SETLOCAL: return "SETLOCAL";
|
||||
case OP_NEWVEC: return "NEWVEC";
|
||||
case OP_VAPPEND: return "VAPPEND";
|
||||
case OP_NEWHASH: return "NEWHASH";
|
||||
case OP_HAPPEND: return "HAPPEND";
|
||||
case OP_LINE: return "LINE";
|
||||
case OP_MARK: return "MARK";
|
||||
case OP_UNMARK: return "UNMARK";
|
||||
case OP_BREAK: return "BREAK";
|
||||
}
|
||||
sprintf(buf, "<bad opcode: %d>\n", op);
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Print a bytecode operator
|
||||
void printOpDEBUG(int ip, int op)
|
||||
{
|
||||
printf("IP: %d OP: %s\n", ip, opStringDEBUG(op));
|
||||
}
|
||||
|
||||
// Print a naRef
|
||||
void printRefDEBUG(naRef r)
|
||||
{
|
||||
int i;
|
||||
if(IS_NUM(r)) {
|
||||
printf("%f\n", r.num);
|
||||
} else if(IS_NIL(r)) {
|
||||
printf("<nil>\n");
|
||||
} else if(IS_STR(r)) {
|
||||
printf("\"");
|
||||
for(i=0; i<r.ref.ptr.str->len; i++)
|
||||
printf("%c", r.ref.ptr.str->data[i]);
|
||||
printf("\"\n");
|
||||
} else if(IS_VEC(r)) {
|
||||
printf("<vec>\n");
|
||||
} else if(IS_HASH(r)) {
|
||||
printf("<hash>\n");
|
||||
} else if(IS_FUNC(r)) {
|
||||
printf("<func>\n");
|
||||
} else if(IS_CLOSURE(r)) {
|
||||
printf("DEBUG: closure object on stack!\n");
|
||||
} else if(IS_CODE(r)) {
|
||||
printf("DEBUG: code object on stack!\n");
|
||||
} else printf("DEBUG ACK\n");
|
||||
}
|
||||
|
||||
// Print the operand stack of the specified context
|
||||
void printStackDEBUG(struct Context* ctx)
|
||||
{
|
||||
int i;
|
||||
printf("\n");
|
||||
for(i=ctx->opTop-1; i>=0; i--) {
|
||||
printf("] ");
|
||||
printRefDEBUG(ctx->opStack[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Token type to string
|
||||
char* tokString(int tok)
|
||||
{
|
||||
switch(tok) {
|
||||
case TOK_TOP: return "TOK_TOP";
|
||||
case TOK_AND: return "TOK_AND";
|
||||
case TOK_OR: return "TOK_OR";
|
||||
case TOK_NOT: return "TOK_NOT";
|
||||
case TOK_LPAR: return "TOK_LPAR";
|
||||
case TOK_RPAR: return "TOK_RPAR";
|
||||
case TOK_LBRA: return "TOK_LBRA";
|
||||
case TOK_RBRA: return "TOK_RBRA";
|
||||
case TOK_LCURL: return "TOK_LCURL";
|
||||
case TOK_RCURL: return "TOK_RCURL";
|
||||
case TOK_MUL: return "TOK_MUL";
|
||||
case TOK_PLUS: return "TOK_PLUS";
|
||||
case TOK_MINUS: return "TOK_MINUS";
|
||||
case TOK_NEG: return "TOK_NEG";
|
||||
case TOK_DIV: return "TOK_DIV";
|
||||
case TOK_CAT: return "TOK_CAT";
|
||||
case TOK_COLON: return "TOK_COLON";
|
||||
case TOK_DOT: return "TOK_DOT";
|
||||
case TOK_COMMA: return "TOK_COMMA";
|
||||
case TOK_SEMI: return "TOK_SEMI";
|
||||
case TOK_ASSIGN: return "TOK_ASSIGN";
|
||||
case TOK_LT: return "TOK_LT";
|
||||
case TOK_LTE: return "TOK_LTE";
|
||||
case TOK_EQ: return "TOK_EQ";
|
||||
case TOK_NEQ: return "TOK_NEQ";
|
||||
case TOK_GT: return "TOK_GT";
|
||||
case TOK_GTE: return "TOK_GTE";
|
||||
case TOK_IF: return "TOK_IF";
|
||||
case TOK_ELSIF: return "TOK_ELSIF";
|
||||
case TOK_ELSE: return "TOK_ELSE";
|
||||
case TOK_FOR: return "TOK_FOR";
|
||||
case TOK_FOREACH: return "TOK_FOREACH";
|
||||
case TOK_WHILE: return "TOK_WHILE";
|
||||
case TOK_RETURN: return "TOK_RETURN";
|
||||
case TOK_BREAK: return "TOK_BREAK";
|
||||
case TOK_CONTINUE: return "TOK_CONTINUE";
|
||||
case TOK_FUNC: return "TOK_FUNC";
|
||||
case TOK_SYMBOL: return "TOK_SYMBOL";
|
||||
case TOK_LITERAL: return "TOK_LITERAL";
|
||||
case TOK_EMPTY: return "TOK_EMPTY";
|
||||
case TOK_NIL: return "TOK_NIL";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Diagnostic: check all list pointers for sanity
|
||||
void ack()
|
||||
{
|
||||
printf("Bad token list!\n");
|
||||
exit(1);
|
||||
}
|
||||
void checkList(struct Token* start, struct Token* end)
|
||||
{
|
||||
struct Token* t = start;
|
||||
while(t) {
|
||||
if(t->next && t->next->prev != t) ack();
|
||||
if(t->next==0 && t != end) ack();
|
||||
t = t->next;
|
||||
}
|
||||
t = end;
|
||||
while(t) {
|
||||
if(t->prev && t->prev->next != t) ack();
|
||||
if(t->prev==0 && t != start) ack();
|
||||
t = t->prev;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Prints a single parser token to stdout
|
||||
void printToken(struct Token* t, char* prefix)
|
||||
{
|
||||
int i;
|
||||
printf("%sline %d %s ", prefix, t->line, tokString(t->type));
|
||||
if(t->type == TOK_LITERAL || t->type == TOK_SYMBOL) {
|
||||
if(t->str) {
|
||||
printf("\"");
|
||||
for(i=0; i<t->strlen; i++) printf("%c", t->str[i]);
|
||||
printf("\" (len: %d)", t->strlen);
|
||||
} else {
|
||||
printf("%f ", t->num);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Prints a parse tree to stdout
|
||||
void dumpTokenList(struct Token* t, int prefix)
|
||||
{
|
||||
char prefstr[128];
|
||||
int i;
|
||||
|
||||
prefstr[0] = 0;
|
||||
for(i=0; i<prefix; i++)
|
||||
strcat(prefstr, ". ");
|
||||
|
||||
while(t) {
|
||||
printToken(t, prefstr);
|
||||
dumpTokenList(t->children, prefix+1);
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
+219
-104
@@ -1,44 +1,131 @@
|
||||
#include "nasal.h"
|
||||
#include "data.h"
|
||||
#include "code.h"
|
||||
|
||||
#define MIN_BLOCK_SIZE 256
|
||||
|
||||
// "type" for an object freed by the collector
|
||||
#define T_GCFREED 123 // DEBUG
|
||||
static void reap(struct naPool* p);
|
||||
static void mark(naRef r);
|
||||
|
||||
struct Block {
|
||||
int size;
|
||||
char* block;
|
||||
struct Block* next;
|
||||
};
|
||||
|
||||
// Decremented every allocation. When it reaches zero, we do a
|
||||
// garbage collection. The value is reset to 1/2 of the total object
|
||||
// count each collection, which is sane: it ensures that no more than
|
||||
// 50% growth can happen between collections, and ensures that garbage
|
||||
// collection work is constant with allocation work (i.e. that O(N)
|
||||
// work is done only every O(1/2N) allocations).
|
||||
static int GlobalAllocCount = 256;
|
||||
|
||||
static void appendfree(struct naPool*p, struct naObj* o)
|
||||
// Must be called with the giant exclusive lock!
|
||||
static void freeDead()
|
||||
{
|
||||
// Need more space?
|
||||
if(p->freesz <= p->nfree) {
|
||||
int i, n = 1+((3*p->nfree)>>1);
|
||||
void** newf = naAlloc(n * sizeof(void*));
|
||||
for(i=0; i<p->nfree; i++)
|
||||
newf[i] = p->free[i];
|
||||
naFree(p->free);
|
||||
p->free = newf;
|
||||
p->freesz = n;
|
||||
int i;
|
||||
for(i=0; i<globals->ndead; i++)
|
||||
naFree(globals->deadBlocks[i]);
|
||||
globals->ndead = 0;
|
||||
}
|
||||
|
||||
static void marktemps(struct Context* c)
|
||||
{
|
||||
int i;
|
||||
naRef r = naNil();
|
||||
for(i=0; i<c->ntemps; i++) {
|
||||
r.ref.ptr.obj = c->temps[i];
|
||||
mark(r);
|
||||
}
|
||||
}
|
||||
|
||||
// Must be called with the big lock!
|
||||
static void garbageCollect()
|
||||
{
|
||||
int i;
|
||||
struct Context* c;
|
||||
globals->allocCount = 0;
|
||||
c = globals->allContexts;
|
||||
while(c) {
|
||||
for(i=0; i<NUM_NASAL_TYPES; i++)
|
||||
c->nfree[i] = 0;
|
||||
for(i=0; i < c->fTop; i++) {
|
||||
mark(c->fStack[i].func);
|
||||
mark(c->fStack[i].locals);
|
||||
}
|
||||
for(i=0; i < c->opTop; i++)
|
||||
mark(c->opStack[i]);
|
||||
mark(c->dieArg);
|
||||
marktemps(c);
|
||||
c = c->nextAll;
|
||||
}
|
||||
|
||||
p->free[p->nfree++] = o;
|
||||
mark(globals->save);
|
||||
mark(globals->symbols);
|
||||
mark(globals->meRef);
|
||||
mark(globals->argRef);
|
||||
mark(globals->parentsRef);
|
||||
|
||||
// Finally collect all the freed objects
|
||||
for(i=0; i<NUM_NASAL_TYPES; i++)
|
||||
reap(&(globals->pools[i]));
|
||||
|
||||
// Make enough space for the dead blocks we need to free during
|
||||
// execution. This works out to 1 spot for every 2 live objects,
|
||||
// which should be limit the number of bottleneck operations
|
||||
// without imposing an undue burden of extra "freeable" memory.
|
||||
if(globals->deadsz < globals->allocCount) {
|
||||
globals->deadsz = globals->allocCount;
|
||||
if(globals->deadsz < 256) globals->deadsz = 256;
|
||||
naFree(globals->deadBlocks);
|
||||
globals->deadBlocks = naAlloc(sizeof(void*) * globals->deadsz);
|
||||
}
|
||||
globals->needGC = 0;
|
||||
}
|
||||
|
||||
void naModLock()
|
||||
{
|
||||
LOCK();
|
||||
globals->nThreads++;
|
||||
UNLOCK();
|
||||
naCheckBottleneck();
|
||||
}
|
||||
|
||||
void naModUnlock()
|
||||
{
|
||||
LOCK();
|
||||
globals->nThreads--;
|
||||
UNLOCK();
|
||||
}
|
||||
|
||||
// Must be called with the main lock. Engages the "bottleneck", where
|
||||
// all threads will block so that one (the last one to call this
|
||||
// function) can run alone. This is done for GC, and also to free the
|
||||
// list of "dead" blocks when it gets full (which is part of GC, if
|
||||
// you think about it).
|
||||
static void bottleneck()
|
||||
{
|
||||
struct Globals* g = globals;
|
||||
g->bottleneck = 1;
|
||||
while(g->bottleneck && g->waitCount < g->nThreads - 1) {
|
||||
g->waitCount++;
|
||||
UNLOCK(); naSemDown(g->sem); LOCK();
|
||||
g->waitCount--;
|
||||
}
|
||||
if(g->waitCount >= g->nThreads - 1) {
|
||||
freeDead();
|
||||
if(g->needGC) garbageCollect();
|
||||
if(g->waitCount) naSemUpAll(g->sem, g->waitCount);
|
||||
g->bottleneck = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void naCheckBottleneck()
|
||||
{
|
||||
if(globals->bottleneck) { LOCK(); bottleneck(); UNLOCK(); }
|
||||
}
|
||||
|
||||
static void naCode_gcclean(struct naCode* o)
|
||||
{
|
||||
naFree(o->byteCode); o->byteCode = 0;
|
||||
naFree(o->constants); o->constants = 0;
|
||||
naFree(o->byteCode); o->byteCode = 0;
|
||||
naFree(o->constants); o->constants = 0;
|
||||
naFree(o->argSyms); o->argSyms = 0;
|
||||
naFree(o->optArgSyms); o->optArgSyms = 0;
|
||||
naFree(o->optArgVals); o->optArgVals = 0;
|
||||
naFree(o->lineIps); o->lineIps = 0;
|
||||
}
|
||||
|
||||
static void naGhost_gcclean(struct naGhost* g)
|
||||
@@ -49,9 +136,6 @@ static void naGhost_gcclean(struct naGhost* g)
|
||||
|
||||
static void freeelem(struct naPool* p, struct naObj* o)
|
||||
{
|
||||
// Mark the object as "freed" for debugging purposes
|
||||
o->type = T_GCFREED; // DEBUG
|
||||
|
||||
// Free any intrinsic (i.e. non-garbage collected) storage the
|
||||
// object might have
|
||||
switch(p->type) {
|
||||
@@ -73,77 +157,100 @@ static void freeelem(struct naPool* p, struct naObj* o)
|
||||
}
|
||||
|
||||
// And add it to the free list
|
||||
appendfree(p, o);
|
||||
p->free[p->nfree++] = o;
|
||||
}
|
||||
|
||||
static void newBlock(struct naPool* p, int need)
|
||||
{
|
||||
int i;
|
||||
char* buf;
|
||||
struct Block* newblocks;
|
||||
struct Block* newb;
|
||||
|
||||
if(need < MIN_BLOCK_SIZE)
|
||||
need = MIN_BLOCK_SIZE;
|
||||
if(need < MIN_BLOCK_SIZE) need = MIN_BLOCK_SIZE;
|
||||
|
||||
newb = naAlloc(sizeof(struct Block));
|
||||
newb->block = naAlloc(need * p->elemsz);
|
||||
newb->size = need;
|
||||
newb->next = p->blocks;
|
||||
p->blocks = newb;
|
||||
naBZero(newb->block, need * p->elemsz);
|
||||
|
||||
newblocks = naAlloc((p->nblocks+1) * sizeof(struct Block));
|
||||
for(i=0; i<p->nblocks; i++) newblocks[i] = p->blocks[i];
|
||||
naFree(p->blocks);
|
||||
p->blocks = newblocks;
|
||||
buf = naAlloc(need * p->elemsz);
|
||||
naBZero(buf, need * p->elemsz);
|
||||
p->blocks[p->nblocks].size = need;
|
||||
p->blocks[p->nblocks].block = buf;
|
||||
p->nblocks++;
|
||||
|
||||
for(i=0; i<need; i++) {
|
||||
struct naObj* o = (struct naObj*)(buf + i*p->elemsz);
|
||||
if(need > p->freesz - p->freetop) need = p->freesz - p->freetop;
|
||||
p->nfree = 0;
|
||||
p->free = p->free0 + p->freetop;
|
||||
for(i=0; i < need; i++) {
|
||||
struct naObj* o = (struct naObj*)(newb->block + i*p->elemsz);
|
||||
o->mark = 0;
|
||||
o->type = p->type;
|
||||
appendfree(p, o);
|
||||
p->free[p->nfree++] = o;
|
||||
}
|
||||
p->freetop += need;
|
||||
}
|
||||
|
||||
void naGC_init(struct naPool* p, int type)
|
||||
{
|
||||
p->type = type;
|
||||
p->elemsz = naTypeSize(type);
|
||||
p->nblocks = 0;
|
||||
p->blocks = 0;
|
||||
p->nfree = 0;
|
||||
p->freesz = 0;
|
||||
p->free = 0;
|
||||
naGC_reap(p);
|
||||
|
||||
p->free0 = p->free = 0;
|
||||
p->nfree = p->freesz = p->freetop = 0;
|
||||
reap(p);
|
||||
}
|
||||
|
||||
int naGC_size(struct naPool* p)
|
||||
static int poolsize(struct naPool* p)
|
||||
{
|
||||
int i, total=0;
|
||||
for(i=0; i<p->nblocks; i++)
|
||||
total += ((struct Block*)(p->blocks + i))->size;
|
||||
int total = 0;
|
||||
struct Block* b = p->blocks;
|
||||
while(b) { total += b->size; b = b->next; }
|
||||
return total;
|
||||
}
|
||||
|
||||
struct naObj* naGC_get(struct naPool* p)
|
||||
struct naObj** naGC_get(struct naPool* p, int n, int* nout)
|
||||
{
|
||||
// Collect every GlobalAllocCount allocations.
|
||||
// This gets set to ~50% of the total object count each
|
||||
// collection (it's incremented in naGC_reap()).
|
||||
if(--GlobalAllocCount < 0) {
|
||||
GlobalAllocCount = 0;
|
||||
naGarbageCollect();
|
||||
struct naObj** result;
|
||||
naCheckBottleneck();
|
||||
LOCK();
|
||||
while(globals->allocCount < 0 || (p->nfree == 0 && p->freetop >= p->freesz)) {
|
||||
globals->needGC = 1;
|
||||
bottleneck();
|
||||
}
|
||||
|
||||
// If we're out, then allocate an extra 12.5%
|
||||
if(p->nfree == 0)
|
||||
newBlock(p, naGC_size(p)/8);
|
||||
return p->free[--p->nfree];
|
||||
newBlock(p, poolsize(p)/8);
|
||||
n = p->nfree < n ? p->nfree : n;
|
||||
*nout = n;
|
||||
p->nfree -= n;
|
||||
globals->allocCount -= n;
|
||||
result = (struct naObj**)(p->free + p->nfree);
|
||||
UNLOCK();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void markvec(naRef r)
|
||||
{
|
||||
int i;
|
||||
struct VecRec* vr = r.ref.ptr.vec->rec;
|
||||
if(!vr) return;
|
||||
for(i=0; i<vr->size; i++)
|
||||
mark(vr->array[i]);
|
||||
}
|
||||
|
||||
static void markhash(naRef r)
|
||||
{
|
||||
int i;
|
||||
struct HashRec* hr = r.ref.ptr.hash->rec;
|
||||
if(!hr) return;
|
||||
for(i=0; i < (1<<hr->lgalloced); i++) {
|
||||
struct HashNode* hn = hr->table[i];
|
||||
while(hn) {
|
||||
mark(hn->key);
|
||||
mark(hn->val);
|
||||
hn = hn->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the reference bit on the object, and recursively on all
|
||||
// objects reachable from it. Clumsy: uses C stack recursion, which
|
||||
// is slower than it need be and may cause problems on some platforms
|
||||
// due to the very large stack depths that result.
|
||||
void naGC_mark(naRef r)
|
||||
// objects reachable from it. Uses the processor stack for recursion...
|
||||
static void mark(naRef r)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -153,62 +260,48 @@ void naGC_mark(naRef r)
|
||||
if(r.ref.ptr.obj->mark == 1)
|
||||
return;
|
||||
|
||||
// Verify that the object hasn't been freed incorrectly:
|
||||
if(r.ref.ptr.obj->type == T_GCFREED) *(int*)0=0; // DEBUG
|
||||
|
||||
r.ref.ptr.obj->mark = 1;
|
||||
switch(r.ref.ptr.obj->type) {
|
||||
case T_VEC:
|
||||
for(i=0; i<r.ref.ptr.vec->size; i++)
|
||||
naGC_mark(r.ref.ptr.vec->array[i]);
|
||||
break;
|
||||
case T_HASH:
|
||||
if(r.ref.ptr.hash->table == 0)
|
||||
break;
|
||||
for(i=0; i < (1<<r.ref.ptr.hash->lgalloced); i++) {
|
||||
struct HashNode* hn = r.ref.ptr.hash->table[i];
|
||||
while(hn) {
|
||||
naGC_mark(hn->key);
|
||||
naGC_mark(hn->val);
|
||||
hn = hn->next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_VEC: markvec(r); break;
|
||||
case T_HASH: markhash(r); break;
|
||||
case T_CODE:
|
||||
naGC_mark(r.ref.ptr.code->srcFile);
|
||||
mark(r.ref.ptr.code->srcFile);
|
||||
for(i=0; i<r.ref.ptr.code->nConstants; i++)
|
||||
naGC_mark(r.ref.ptr.code->constants[i]);
|
||||
break;
|
||||
case T_CLOSURE:
|
||||
naGC_mark(r.ref.ptr.closure->namespace);
|
||||
naGC_mark(r.ref.ptr.closure->next);
|
||||
mark(r.ref.ptr.code->constants[i]);
|
||||
break;
|
||||
case T_FUNC:
|
||||
naGC_mark(r.ref.ptr.func->code);
|
||||
naGC_mark(r.ref.ptr.func->closure);
|
||||
mark(r.ref.ptr.func->code);
|
||||
mark(r.ref.ptr.func->namespace);
|
||||
mark(r.ref.ptr.func->next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Collects all the unreachable objects into a free list, and
|
||||
// allocates more space if needed.
|
||||
void naGC_reap(struct naPool* p)
|
||||
static void reap(struct naPool* p)
|
||||
{
|
||||
int i, elem, total = 0;
|
||||
struct Block* b;
|
||||
int elem, freesz, total = poolsize(p);
|
||||
p->nfree = 0;
|
||||
for(i=0; i<p->nblocks; i++) {
|
||||
struct Block* b = p->blocks + i;
|
||||
total += b->size;
|
||||
freesz = total < MIN_BLOCK_SIZE ? MIN_BLOCK_SIZE : total;
|
||||
freesz = (3 * freesz / 2) + (globals->nThreads * OBJ_CACHE_SZ);
|
||||
if(p->freesz < freesz) {
|
||||
naFree(p->free0);
|
||||
p->freesz = freesz;
|
||||
p->free = p->free0 = naAlloc(sizeof(void*) * p->freesz);
|
||||
}
|
||||
|
||||
for(b = p->blocks; b; b = b->next)
|
||||
for(elem=0; elem < b->size; elem++) {
|
||||
struct naObj* o = (struct naObj*)(b->block + elem * p->elemsz);
|
||||
if(o->mark == 0)
|
||||
freeelem(p, o);
|
||||
o->mark = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Add 50% of our total to the global count
|
||||
GlobalAllocCount += total/2;
|
||||
// allocs of this type until the next collection
|
||||
globals->allocCount += total/2;
|
||||
|
||||
// Allocate more if necessary (try to keep 25-50% of the objects
|
||||
// available)
|
||||
@@ -219,5 +312,27 @@ void naGC_reap(struct naPool* p)
|
||||
if(need > 0)
|
||||
newBlock(p, need);
|
||||
}
|
||||
p->freetop = p->nfree;
|
||||
}
|
||||
|
||||
// Does the swap, returning the old value
|
||||
static void* doswap(void** target, void* val)
|
||||
{
|
||||
void* old = *target;
|
||||
*target = val;
|
||||
return old;
|
||||
}
|
||||
|
||||
// Atomically replaces target with a new pointer, and adds the old one
|
||||
// to the list of blocks to free the next time something holds the
|
||||
// giant lock.
|
||||
void naGC_swapfree(void** target, void* val)
|
||||
{
|
||||
void* old;
|
||||
LOCK();
|
||||
old = doswap(target, val);
|
||||
while(globals->ndead >= globals->deadsz)
|
||||
bottleneck();
|
||||
globals->deadBlocks[globals->ndead++] = old;
|
||||
UNLOCK();
|
||||
}
|
||||
|
||||
+142
-113
@@ -1,42 +1,22 @@
|
||||
#include "nasal.h"
|
||||
#include "data.h"
|
||||
|
||||
static void realloc(naRef hash)
|
||||
{
|
||||
struct naHash* h = hash.ref.ptr.hash;
|
||||
int i, sz, oldsz = h->size;
|
||||
int oldcols = h->table ? 1 << h->lgalloced : 0;
|
||||
#define MIN_HASH_SIZE 4
|
||||
|
||||
// Keep a handle to our original objects
|
||||
struct HashNode* oldnodes = h->nodes;
|
||||
struct HashNode** oldtable = h->table;
|
||||
#define EQUAL(a, b) (((a).ref.reftag == (b).ref.reftag \
|
||||
&& (a).ref.ptr.obj == (b).ref.ptr.obj) \
|
||||
|| naEqual(a, b))
|
||||
|
||||
// Figure out how big we need to be (start with a minimum size of
|
||||
// 16 entries)
|
||||
for(i=3; 1<<i < oldsz; i++);
|
||||
h->lgalloced = i+1;
|
||||
|
||||
// Allocate new ones (note that all the records are allocated in a
|
||||
// single chunk, to avoid zillions of tiny node allocations)
|
||||
sz = 1<<h->lgalloced;
|
||||
h->nodes = naAlloc(sz * (sizeof(struct HashNode) + sizeof(void*)));
|
||||
h->table = (struct HashNode**)(((char*)h->nodes) + sz*sizeof(struct HashNode));
|
||||
naBZero(h->table, sz * sizeof(void*));
|
||||
h->nextnode = 0;
|
||||
h->size = 0;
|
||||
#define HASH_MAGIC 2654435769u
|
||||
|
||||
// Re-insert everything from scratch
|
||||
for(i=0; i<oldcols; i++) {
|
||||
struct HashNode* hn = oldtable[i];
|
||||
while(hn) {
|
||||
naHash_set(hash, hn->key, hn->val);
|
||||
hn = hn->next;
|
||||
}
|
||||
}
|
||||
|
||||
// Free the old memory
|
||||
naFree(oldnodes);
|
||||
}
|
||||
#define INSERT(hh, hkey, hval, hcol) do { \
|
||||
unsigned int cc = (hcol), iidx=(hh)->size++; \
|
||||
if(iidx < (1<<(hh)->lgalloced)) { \
|
||||
struct HashNode* hnn = &(hh)->nodes[iidx]; \
|
||||
hnn->key = (hkey); hnn->val = (hval); \
|
||||
hnn->next = (hh)->table[cc]; \
|
||||
(hh)->table[cc] = hnn; \
|
||||
}} while(0)
|
||||
|
||||
// Computes a hash code for a given scalar
|
||||
static unsigned int hashcode(naRef r)
|
||||
@@ -48,61 +28,107 @@ static unsigned int hashcode(naRef r)
|
||||
// 2*sizeof(int).
|
||||
unsigned int* p = (unsigned int*)&(r.num);
|
||||
return p[0] ^ p[1];
|
||||
} else if(r.ref.ptr.str->hashcode) {
|
||||
return r.ref.ptr.str->hashcode;
|
||||
} else {
|
||||
// This is Daniel Bernstein's djb2 hash function that I found
|
||||
// on the web somewhere. It appears to work pretty well.
|
||||
unsigned int i, hash = 5831;
|
||||
for(i=0; i<r.ref.ptr.str->len; i++)
|
||||
hash = (hash * 33) ^ r.ref.ptr.str->data[i];
|
||||
r.ref.ptr.str->hashcode = hash;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
// Which column in a given hash does the key correspond to.
|
||||
static unsigned int hashcolumn(struct naHash* h, naRef key)
|
||||
static unsigned int hashcolumn(struct HashRec* h, naRef key)
|
||||
{
|
||||
// Multiply by a big number, and take the top N bits. Note
|
||||
// assumption that sizeof(unsigned int) == 4.
|
||||
return (2654435769u * hashcode(key)) >> (32 - h->lgalloced);
|
||||
return (HASH_MAGIC * hashcode(key)) >> (32 - h->lgalloced);
|
||||
}
|
||||
|
||||
struct HashNode* find(struct naHash* h, naRef key)
|
||||
static struct HashRec* realloc(struct naHash* hash)
|
||||
{
|
||||
struct HashNode* hn;
|
||||
if(h->table == 0)
|
||||
return 0;
|
||||
hn = h->table[hashcolumn(h, key)];
|
||||
while(hn) {
|
||||
if(naEqual(key, hn->key))
|
||||
return hn;
|
||||
hn = hn->next;
|
||||
struct HashRec *h, *h0 = hash->rec;
|
||||
int lga, cols, need = h0 ? h0->size - h0->dels : MIN_HASH_SIZE;
|
||||
|
||||
if(need < MIN_HASH_SIZE) need = MIN_HASH_SIZE;
|
||||
for(lga=0; 1<<lga <= need; lga++);
|
||||
cols = 1<<lga;
|
||||
h = naAlloc(sizeof(struct HashRec) +
|
||||
cols * (sizeof(struct HashNode*) + sizeof(struct HashNode)));
|
||||
naBZero(h, sizeof(struct HashRec) + cols * sizeof(struct HashNode*));
|
||||
|
||||
h->lgalloced = lga;
|
||||
h->nodes = (struct HashNode*)(((char*)h)
|
||||
+ sizeof(struct HashRec)
|
||||
+ cols * sizeof(struct HashNode*));
|
||||
for(lga=0; h0 != 0 && lga<(1<<h0->lgalloced); lga++) {
|
||||
struct HashNode* hn = h0->table[lga];
|
||||
while(hn) {
|
||||
INSERT(h, hn->key, hn->val, hashcolumn(h, hn->key));
|
||||
hn = hn->next;
|
||||
}
|
||||
}
|
||||
naGC_swapfree((void**)&hash->rec, h);
|
||||
return h;
|
||||
}
|
||||
|
||||
// Special, optimized version of naHash_get for the express purpose of
|
||||
// looking up symbols in the local variables hash (OP_LOCAL is by far
|
||||
// the most common opcode and deserves some special case
|
||||
// optimization). Elides all the typing checks that are normally
|
||||
// required, presumes that the key is a string and has had its
|
||||
// hashcode precomputed, checks only for object identity, and inlines
|
||||
// the column computation.
|
||||
int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
|
||||
{
|
||||
struct HashRec* h = hash->rec;
|
||||
if(h) {
|
||||
int col = (HASH_MAGIC * sym->hashcode) >> (32 - h->lgalloced);
|
||||
struct HashNode* hn = h->table[col];
|
||||
while(hn) {
|
||||
if(hn->key.ref.ptr.str == sym) {
|
||||
*out = hn->val;
|
||||
return 1;
|
||||
}
|
||||
hn = hn->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void naHash_init(naRef hash)
|
||||
static struct HashNode* find(struct naHash* hash, naRef key)
|
||||
{
|
||||
struct naHash* h = hash.ref.ptr.hash;
|
||||
h->size = 0;
|
||||
h->lgalloced = 0;
|
||||
h->table = 0;
|
||||
h->nodes = 0;
|
||||
struct HashRec* h = hash->rec;
|
||||
if(h) {
|
||||
struct HashNode* hn = h->table[hashcolumn(h, key)];
|
||||
while(hn) {
|
||||
if(EQUAL(key, hn->key))
|
||||
return hn;
|
||||
hn = hn->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Make a temporary string on the stack
|
||||
static naRef tmpStr(struct naStr* str, char* key)
|
||||
static void tmpStr(naRef* out, struct naStr* str, char* key)
|
||||
{
|
||||
char* p = key;
|
||||
while(*p) { p++; }
|
||||
str->len = p - key;
|
||||
str->data = key;
|
||||
return naObj(T_STR, (struct naObj*)str);
|
||||
str->len = 0;
|
||||
str->data = (unsigned char*)key;
|
||||
while(key[str->len]) str->len++;
|
||||
*out = naNil();
|
||||
out->ref.ptr.str = str;
|
||||
}
|
||||
|
||||
naRef naHash_cget(naRef hash, char* key)
|
||||
{
|
||||
struct naStr str;
|
||||
naRef result, key2 = tmpStr(&str, key);
|
||||
naRef result, key2;
|
||||
tmpStr(&key2, &str, key);
|
||||
if(naHash_get(hash, key2, &result))
|
||||
return result;
|
||||
return naNil();
|
||||
@@ -111,80 +137,86 @@ naRef naHash_cget(naRef hash, char* key)
|
||||
void naHash_cset(naRef hash, char* key, naRef val)
|
||||
{
|
||||
struct naStr str;
|
||||
naRef key2 = tmpStr(&str, key);
|
||||
naRef key2;
|
||||
tmpStr(&key2, &str, key);
|
||||
naHash_tryset(hash, key2, val);
|
||||
}
|
||||
|
||||
int naHash_get(naRef hash, naRef key, naRef* out)
|
||||
{
|
||||
struct naHash* h = hash.ref.ptr.hash;
|
||||
struct HashNode* n;
|
||||
if(!IS_HASH(hash)) return 0;
|
||||
n = find(h, key);
|
||||
if(n) {
|
||||
*out = n->val;
|
||||
return 1;
|
||||
} else {
|
||||
*out = naNil();
|
||||
return 0;
|
||||
if(IS_HASH(hash)) {
|
||||
struct HashNode* n = find(hash.ref.ptr.hash, key);
|
||||
if(n) { *out = n->val; return 1; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Simpler version. Don't create a new node if the value isn't there
|
||||
int naHash_tryset(naRef hash, naRef key, naRef val)
|
||||
{
|
||||
struct HashNode* n;
|
||||
if(!IS_HASH(hash)) return 0;
|
||||
n = find(hash.ref.ptr.hash, key);
|
||||
if(n) n->val = val;
|
||||
return n != 0;
|
||||
if(IS_HASH(hash)) {
|
||||
struct HashNode* n = find(hash.ref.ptr.hash, key);
|
||||
if(n) n->val = val;
|
||||
return n != 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Special purpose optimization for use in function call setups. Sets
|
||||
// a value that is known *not* to be present in the hash table. As
|
||||
// for naHash_sym, the key must be a string with a precomputed hash
|
||||
// code.
|
||||
void naHash_newsym(struct naHash* hash, naRef* sym, naRef* val)
|
||||
{
|
||||
int col;
|
||||
struct HashRec* h = hash->rec;
|
||||
while(!h || h->size >= 1<<h->lgalloced)
|
||||
h = realloc(hash);
|
||||
col = (HASH_MAGIC * sym->ref.ptr.str->hashcode) >> (32 - h->lgalloced);
|
||||
INSERT(h, *sym, *val, col);
|
||||
}
|
||||
|
||||
// The cycle check is an integrity requirement for multithreading,
|
||||
// where raced inserts can potentially cause cycles. This ensures
|
||||
// that the "last" thread to hold a reference to an inserted node
|
||||
// breaks any cycles that might have happened (at the expense of
|
||||
// potentially dropping items out of the hash). Under normal
|
||||
// circumstances, chains will be very short and this will be fast.
|
||||
static void chkcycle(struct HashNode* node, int count)
|
||||
{
|
||||
struct HashNode* hn = node;
|
||||
while(hn && (hn = hn->next) != 0)
|
||||
if(count-- <= 0) { node->next = 0; return; }
|
||||
}
|
||||
|
||||
void naHash_set(naRef hash, naRef key, naRef val)
|
||||
{
|
||||
struct naHash* h = hash.ref.ptr.hash;
|
||||
unsigned int col;
|
||||
int col;
|
||||
struct HashRec* h;
|
||||
struct HashNode* n;
|
||||
|
||||
if(!IS_HASH(hash)) return;
|
||||
|
||||
n = find(h, key);
|
||||
if(n) {
|
||||
n->val = val;
|
||||
return;
|
||||
}
|
||||
|
||||
if(h->size+1 >= 1<<h->lgalloced)
|
||||
realloc(hash);
|
||||
|
||||
if((n = find(hash.ref.ptr.hash, key))) { n->val = val; return; }
|
||||
h = hash.ref.ptr.hash->rec;
|
||||
while(!h || h->size >= 1<<h->lgalloced)
|
||||
h = realloc(hash.ref.ptr.hash);
|
||||
col = hashcolumn(h, key);
|
||||
n = h->nodes + h->nextnode++;
|
||||
n->key = key;
|
||||
n->val = val;
|
||||
n->next = h->table[col];
|
||||
h->table[col] = n;
|
||||
h->size++;
|
||||
INSERT(h, key, val, hashcolumn(h, key));
|
||||
chkcycle(h->table[col], h->size - h->dels);
|
||||
}
|
||||
|
||||
// FIXME: this implementation does a realloc() after each delete, and
|
||||
// is therefore needlessly O(N). (The reason is that this avoids the
|
||||
// need to keep a free list around for the much more common case of
|
||||
// adding a new value. Modifying an existing value is O(1), of
|
||||
// course.)
|
||||
void naHash_delete(naRef hash, naRef key)
|
||||
{
|
||||
struct naHash* h = hash.ref.ptr.hash;
|
||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
||||
int col;
|
||||
struct HashNode *last=0, *hn;
|
||||
if(!IS_HASH(hash)) return;
|
||||
if(!IS_HASH(hash) || !h) return;
|
||||
col = hashcolumn(h, key);
|
||||
hn = h->table[col];
|
||||
while(hn) {
|
||||
if(naEqual(hn->key, key)) {
|
||||
if(EQUAL(hn->key, key)) {
|
||||
if(last == 0) h->table[col] = hn->next;
|
||||
else last->next = hn->next;
|
||||
h->size--;
|
||||
realloc(hash);
|
||||
h->dels++;
|
||||
return;
|
||||
}
|
||||
last = hn;
|
||||
@@ -194,9 +226,9 @@ void naHash_delete(naRef hash, naRef key)
|
||||
|
||||
void naHash_keys(naRef dst, naRef hash)
|
||||
{
|
||||
struct naHash* h = hash.ref.ptr.hash;
|
||||
int i;
|
||||
if(!IS_HASH(hash) || !h->table) return;
|
||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
||||
if(!IS_HASH(hash) || !h) return;
|
||||
for(i=0; i<(1<<h->lgalloced); i++) {
|
||||
struct HashNode* hn = h->table[i];
|
||||
while(hn) {
|
||||
@@ -206,18 +238,15 @@ void naHash_keys(naRef dst, naRef hash)
|
||||
}
|
||||
}
|
||||
|
||||
int naHash_size(naRef h)
|
||||
int naHash_size(naRef hash)
|
||||
{
|
||||
if(!IS_HASH(h)) return 0;
|
||||
return h.ref.ptr.hash->size;
|
||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
||||
if(!IS_HASH(hash) || !h) return 0;
|
||||
return h->size - h->dels;
|
||||
}
|
||||
|
||||
void naHash_gcclean(struct naHash* h)
|
||||
{
|
||||
naFree(h->nodes);
|
||||
h->nodes = 0;
|
||||
h->size = 0;
|
||||
h->lgalloced = 0;
|
||||
h->table = 0;
|
||||
h->nextnode = 0;
|
||||
naFree(h->rec);
|
||||
h->rec = 0;
|
||||
}
|
||||
|
||||
+51
-17
@@ -40,7 +40,16 @@ struct Lexeme {
|
||||
{"return", TOK_RETURN},
|
||||
{"break", TOK_BREAK},
|
||||
{"continue", TOK_CONTINUE},
|
||||
{"func", TOK_FUNC}
|
||||
{"func", TOK_FUNC},
|
||||
{"...", TOK_ELLIPSIS},
|
||||
{"?", TOK_QUESTION},
|
||||
{"var", TOK_VAR},
|
||||
{"+=", TOK_PLUSEQ},
|
||||
{"-=", TOK_MINUSEQ},
|
||||
{"*=", TOK_MULEQ},
|
||||
{"/=", TOK_DIVEQ},
|
||||
{"~=", TOK_CATEQ},
|
||||
{"forindex", TOK_FORINDEX},
|
||||
};
|
||||
|
||||
// Build a table of where each line ending is
|
||||
@@ -127,14 +136,19 @@ static void newToken(struct Parser* p, int pos, int type,
|
||||
p->tree.lastChild = tok;
|
||||
}
|
||||
|
||||
// Parse a hex nibble
|
||||
static int hexc(char c, struct Parser* p, int index)
|
||||
static int hex(char c)
|
||||
{
|
||||
if(c >= '0' && c <= '9') return c - '0';
|
||||
if(c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
if(c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
error(p, "bad hex constant", index);
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int hexc(char c, struct Parser* p, int index)
|
||||
{
|
||||
int n = hex(c);
|
||||
if(n < 0) error(p, "bad hex constant", index);
|
||||
return n;
|
||||
}
|
||||
|
||||
// Escape and returns a single backslashed expression in a single
|
||||
@@ -177,13 +191,19 @@ static void dqEscape(char* buf, int len, int index, struct Parser* p,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: should handle UTF8 too
|
||||
static void charLiteral(struct Parser* p, int index, char* s, int len)
|
||||
{
|
||||
if(len != 1) error(p, "character constant not single character", index);
|
||||
newToken(p, index, TOK_LITERAL, 0, 0, *s);
|
||||
}
|
||||
|
||||
// Read in a string literal
|
||||
static int lexStringLiteral(struct Parser* p, int index, int singleQuote)
|
||||
static int lexStringLiteral(struct Parser* p, int index, char q)
|
||||
{
|
||||
int i, j, len, iteration;
|
||||
char* out = 0;
|
||||
char* buf = p->buf;
|
||||
char endMark = singleQuote ? '\'' : '"';
|
||||
|
||||
for(iteration = 0; iteration<2; iteration++) {
|
||||
i = index+1;
|
||||
@@ -191,11 +211,10 @@ static int lexStringLiteral(struct Parser* p, int index, int singleQuote)
|
||||
while(i < p->len) {
|
||||
char c = buf[i];
|
||||
int eaten = 1;
|
||||
if(c == endMark)
|
||||
break;
|
||||
if(c == q) break;
|
||||
if(c == '\\') {
|
||||
if(singleQuote) sqEscape(buf+i, p->len-i, i, p, &c, &eaten);
|
||||
else dqEscape(buf+i, p->len-i, i, p, &c, &eaten);
|
||||
if(q == '\'') sqEscape(buf+i, p->len-i, i, p, &c, &eaten);
|
||||
else dqEscape(buf+i, p->len-i, i, p, &c, &eaten);
|
||||
}
|
||||
if(iteration == 1) out[j++] = c;
|
||||
i += eaten;
|
||||
@@ -204,16 +223,31 @@ static int lexStringLiteral(struct Parser* p, int index, int singleQuote)
|
||||
// Finished stage one -- allocate the buffer for stage two
|
||||
if(iteration == 0) out = naParseAlloc(p, len);
|
||||
}
|
||||
newToken(p, index, TOK_LITERAL, out, len, 0);
|
||||
if(q == '`') charLiteral(p, index, out, len);
|
||||
else newToken(p, index, TOK_LITERAL, out, len, 0);
|
||||
return i+1;
|
||||
}
|
||||
|
||||
static int lexHexLiteral(struct Parser* p, int index)
|
||||
{
|
||||
int nib, i = index;
|
||||
double d = 0;
|
||||
while(i < p->len && (nib = hex(p->buf[i])) >= 0) {
|
||||
d = d*16 + nib;
|
||||
i++;
|
||||
}
|
||||
newToken(p, index, TOK_LITERAL, 0, 0, d);
|
||||
return i;
|
||||
}
|
||||
|
||||
static int lexNumLiteral(struct Parser* p, int index)
|
||||
{
|
||||
int len = p->len, i = index;
|
||||
unsigned char* buf = p->buf;
|
||||
unsigned char* buf = (unsigned char*)p->buf;
|
||||
double d;
|
||||
|
||||
if(i+1<len && buf[i+1] == 'x') return lexHexLiteral(p, index+2);
|
||||
|
||||
while(i<len && buf[i] >= '0' && buf[i] <= '9') i++;
|
||||
if(i<len && buf[i] == '.') {
|
||||
i++;
|
||||
@@ -300,12 +334,12 @@ void naLex(struct Parser* p)
|
||||
case '#':
|
||||
i = lineEnd(p, getLine(p, i));
|
||||
break;
|
||||
case '\'': case '"':
|
||||
i = lexStringLiteral(p, i, (c=='"' ? 0 : 1));
|
||||
case '\'': case '"': case '`':
|
||||
i = lexStringLiteral(p, i, c);
|
||||
break;
|
||||
default:
|
||||
if(c >= '0' && c <= '9') i = lexNumLiteral(p, i);
|
||||
else handled = 0;
|
||||
else handled = 0;
|
||||
}
|
||||
|
||||
// Lexemes and symbols are a little more complicated. Pick
|
||||
@@ -315,7 +349,7 @@ void naLex(struct Parser* p)
|
||||
// symbol (e.g. "orchid"). If neither match, we have a bad
|
||||
// character in the mix.
|
||||
if(!handled) {
|
||||
int symlen=0, lexlen=0, lexeme;
|
||||
int symlen=0, lexlen=0, lexeme=-1;
|
||||
lexlen = tryLexemes(p, i, &lexeme);
|
||||
if((c>='A' && c<='Z') || (c>='a' && c<='z') || (c=='_'))
|
||||
symlen = trySymbol(p, i);
|
||||
|
||||
+387
-81
@@ -1,68 +1,72 @@
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER // sigh...
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
#include "nasal.h"
|
||||
#include "code.h"
|
||||
|
||||
// No need to include <string.h> just for this:
|
||||
// It needs a funny name because MSVC wants to treat "strlen" as a
|
||||
// special symbol. Ugh...
|
||||
static int StrLen(char* s)
|
||||
{
|
||||
char* s0 = s;
|
||||
while(*s) s++;
|
||||
return s - s0;
|
||||
}
|
||||
#define NEWSTR(c, s, l) naStr_fromdata(naNewString(c), s, l)
|
||||
#define NEWCSTR(c, s) NEWSTR(c, s, strlen(s))
|
||||
|
||||
static naRef size(naContext c, naRef args)
|
||||
static naRef size(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef r;
|
||||
if(naVec_size(args) == 0) return naNil();
|
||||
r = naVec_get(args, 0);
|
||||
if(naIsString(r)) return naNum(naStr_len(r));
|
||||
if(naIsVector(r)) return naNum(naVec_size(r));
|
||||
if(naIsHash(r)) return naNum(naHash_size(r));
|
||||
if(argc == 0) return naNil();
|
||||
if(naIsString(args[0])) return naNum(naStr_len(args[0]));
|
||||
if(naIsVector(args[0])) return naNum(naVec_size(args[0]));
|
||||
if(naIsHash(args[0])) return naNum(naHash_size(args[0]));
|
||||
naRuntimeError(c, "object has no size()");
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef keys(naContext c, naRef args)
|
||||
static naRef keys(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef v, h = naVec_get(args, 0);
|
||||
naRef v, h = args[0];
|
||||
if(!naIsHash(h)) return naNil();
|
||||
v = naNewVector(c);
|
||||
naHash_keys(v, h);
|
||||
return v;
|
||||
}
|
||||
|
||||
static naRef append(naContext c, naRef args)
|
||||
{
|
||||
naRef v = naVec_get(args, 0);
|
||||
naRef e = naVec_get(args, 1);
|
||||
if(!naIsVector(v)) return naNil();
|
||||
naVec_append(v, e);
|
||||
return v;
|
||||
}
|
||||
|
||||
static naRef pop(naContext c, naRef args)
|
||||
{
|
||||
naRef v = naVec_get(args, 0);
|
||||
if(!naIsVector(v)) return naNil();
|
||||
return naVec_removelast(v);
|
||||
}
|
||||
|
||||
static naRef setsize(naContext c, naRef args)
|
||||
{
|
||||
naRef v = naVec_get(args, 0);
|
||||
int sz = (int)naNumValue(naVec_get(args, 1)).num;
|
||||
if(!naIsVector(v)) return naNil();
|
||||
naVec_setsize(v, sz);
|
||||
return v;
|
||||
}
|
||||
|
||||
static naRef subvec(naContext c, naRef args)
|
||||
static naRef append(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
naRef nlen, result, v = naVec_get(args, 0);
|
||||
int len = 0, start = (int)naNumValue(naVec_get(args, 1)).num;
|
||||
nlen = naNumValue(naVec_get(args, 2));
|
||||
if(argc < 2) return naNil();
|
||||
if(!naIsVector(args[0])) return naNil();
|
||||
for(i=1; i<argc; i++) naVec_append(args[0], args[i]);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static naRef pop(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc < 1 || !naIsVector(args[0])) return naNil();
|
||||
return naVec_removelast(args[0]);
|
||||
}
|
||||
|
||||
static naRef setsize(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int sz;
|
||||
if(argc < 2) return naNil();
|
||||
sz = (int)naNumValue(args[1]).num;
|
||||
if(!naIsVector(args[0])) return naNil();
|
||||
naVec_setsize(args[0], sz);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static naRef subvec(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
naRef nlen, result, v = args[0];
|
||||
int len = 0, start = (int)naNumValue(args[1]).num;
|
||||
if(argc < 2) return naNil();
|
||||
nlen = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||
if(!naIsNil(nlen))
|
||||
len = (int)naNumValue(naVec_get(args, 2)).num;
|
||||
len = (int)nlen.num;
|
||||
if(!naIsVector(v) || start < 0 || start >= naVec_size(v) || len < 0)
|
||||
return naNil();
|
||||
if(len == 0 || len > naVec_size(v) - start) len = naVec_size(v) - start;
|
||||
@@ -73,51 +77,64 @@ static naRef subvec(naContext c, naRef args)
|
||||
return result;
|
||||
}
|
||||
|
||||
static naRef delete(naContext c, naRef args)
|
||||
static naRef delete(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef h = naVec_get(args, 0);
|
||||
naRef k = naVec_get(args, 1);
|
||||
if(naIsHash(h)) naHash_delete(h, k);
|
||||
if(argc > 1 && naIsHash(args[0])) naHash_delete(args[0], args[1]);
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef intf(naContext c, naRef args)
|
||||
static naRef intf(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef n = naNumValue(naVec_get(args, 0));
|
||||
if(!naIsNil(n)) n.num = (int)n.num;
|
||||
return n;
|
||||
if(argc > 0) {
|
||||
naRef n = naNumValue(args[0]);
|
||||
if(naIsNil(n)) return n;
|
||||
if(n.num < 0) n.num = -floor(-n.num);
|
||||
else n.num = floor(n.num);
|
||||
return n;
|
||||
} else return naNil();
|
||||
}
|
||||
|
||||
static naRef num(naContext c, naRef args)
|
||||
static naRef num(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
return naNumValue(naVec_get(args, 0));
|
||||
return argc > 0 ? naNumValue(args[0]) : naNil();
|
||||
}
|
||||
|
||||
static naRef streq(naContext c, naRef args)
|
||||
static naRef streq(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
naRef a = naVec_get(args, 0);
|
||||
naRef b = naVec_get(args, 1);
|
||||
if(!naIsString(a) || !naIsString(b)) return naNil();
|
||||
if(naStr_len(a) != naStr_len(b)) return naNum(0);
|
||||
for(i=0; i<naStr_len(a); i++)
|
||||
if(naStr_data(a)[i] != naStr_data(b)[i])
|
||||
return naNum(0);
|
||||
return naNum(1);
|
||||
return argc > 1 ? naNum(naStrEqual(args[0], args[1])) : naNil();
|
||||
}
|
||||
|
||||
static naRef substr(naContext c, naRef args)
|
||||
static naRef f_cmp(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef src = naVec_get(args, 0);
|
||||
naRef startR = naVec_get(args, 1);
|
||||
naRef lenR = naVec_get(args, 2);
|
||||
char *a, *b;
|
||||
int i, len;
|
||||
if(argc < 2 || !naIsString(args[0]) || !naIsString(args[1]))
|
||||
naRuntimeError(c, "bad argument to cmp");
|
||||
a = naStr_data(args[0]);
|
||||
b = naStr_data(args[1]);
|
||||
len = naStr_len(args[0]);
|
||||
if(naStr_len(args[1]) < len)
|
||||
len = naStr_len(args[1]);
|
||||
for(i=0; i<len; i++) {
|
||||
int diff = a - b;
|
||||
if(diff < 0) return naNum(-1);
|
||||
else if(diff > 0) return naNum(1);
|
||||
}
|
||||
return naNum(0);
|
||||
}
|
||||
|
||||
static naRef substr(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef src = argc > 1 ? args[0] : naNil();
|
||||
naRef startR = argc > 1 ? naNumValue(args[1]) : naNil();
|
||||
naRef lenR = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||
int start, len;
|
||||
if(!naIsString(src)) return naNil();
|
||||
startR = naNumValue(startR);
|
||||
if(naIsNil(startR)) return naNil();
|
||||
start = (int)startR.num;
|
||||
if(naIsNil(lenR)) {
|
||||
len = naStr_len(src) - start;
|
||||
if(len < 0) return naNil();
|
||||
} else {
|
||||
lenR = naNumValue(lenR);
|
||||
if(naIsNil(lenR)) return naNil();
|
||||
@@ -126,18 +143,27 @@ static naRef substr(naContext c, naRef args)
|
||||
return naStr_substr(naNewString(c), src, start, len);
|
||||
}
|
||||
|
||||
static naRef contains(naContext c, naRef args)
|
||||
static naRef f_chr(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef hash = naVec_get(args, 0);
|
||||
naRef key = naVec_get(args, 1);
|
||||
char chr[1];
|
||||
naRef cr = argc ? naNumValue(args[0]) : naNil();
|
||||
if(IS_NIL(cr)) naRuntimeError(c, "chr argument not string");
|
||||
chr[0] = (char)cr.num;
|
||||
return NEWSTR(c, chr, 1);
|
||||
}
|
||||
|
||||
static naRef contains(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef hash = argc > 0 ? args[0] : naNil();
|
||||
naRef key = argc > 1 ? args[1] : naNil();
|
||||
if(naIsNil(hash) || naIsNil(key)) return naNil();
|
||||
if(!naIsHash(hash)) return naNil();
|
||||
return naHash_get(hash, key, &key) ? naNum(1) : naNum(0);
|
||||
}
|
||||
|
||||
static naRef typeOf(naContext c, naRef args)
|
||||
static naRef typeOf(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef r = naVec_get(args, 0);
|
||||
naRef r = argc > 0 ? args[0] : naNil();
|
||||
char* t = "unknown";
|
||||
if(naIsNil(r)) t = "nil";
|
||||
else if(naIsNum(r)) t = "scalar";
|
||||
@@ -146,10 +172,278 @@ static naRef typeOf(naContext c, naRef args)
|
||||
else if(naIsHash(r)) t = "hash";
|
||||
else if(naIsFunc(r)) t = "func";
|
||||
else if(naIsGhost(r)) t = "ghost";
|
||||
r = naStr_fromdata(naNewString(c), t, StrLen(t));
|
||||
r = NEWCSTR(c, t);
|
||||
return r;
|
||||
}
|
||||
|
||||
static naRef f_compile(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int errLine;
|
||||
naRef script, code, fname;
|
||||
script = argc > 0 ? args[0] : naNil();
|
||||
if(!naIsString(script)) return naNil();
|
||||
fname = NEWCSTR(c, "<compile>");
|
||||
code = naParseCode(c, fname, 1,
|
||||
naStr_data(script), naStr_len(script), &errLine);
|
||||
if(!naIsCode(code)) return naNil(); // FIXME: export error to caller...
|
||||
return naBindToContext(c, code);
|
||||
}
|
||||
|
||||
static naRef f_call(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naContext subc;
|
||||
naRef callargs, callme, callns, result;
|
||||
struct VecRec* vr;
|
||||
callargs = argc > 1 ? args[1] : naNil();
|
||||
callme = argc > 2 ? args[2] : naNil(); // Might be nil, that's OK
|
||||
callns = argc > 3 ? args[3] : naNil(); // ditto
|
||||
if(!IS_HASH(callme)) callme = naNil();
|
||||
if(!IS_HASH(callns)) callns = naNil();
|
||||
if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs)))
|
||||
naRuntimeError(c, "bad argument to call()");
|
||||
subc = naNewContext();
|
||||
subc->callParent = c;
|
||||
c->callChild = subc;
|
||||
vr = IS_NIL(callargs) ? 0 : callargs.ref.ptr.vec->rec;
|
||||
result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0,
|
||||
callme, callns);
|
||||
c->callChild = 0;
|
||||
if(argc > 2 && IS_VEC(args[argc-1])) {
|
||||
if(!IS_NIL(subc->dieArg)) naVec_append(args[argc-1], subc->dieArg);
|
||||
else if(naGetError(subc))
|
||||
naVec_append(args[argc-1], NEWCSTR(subc, naGetError(subc)));
|
||||
}
|
||||
naFreeContext(subc);
|
||||
return result;
|
||||
}
|
||||
|
||||
static naRef f_die(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
c->dieArg = argc > 0 ? args[0] : naNil();
|
||||
naRuntimeError(c, "__die__");
|
||||
return naNil(); // never executes
|
||||
}
|
||||
|
||||
// Wrapper around vsnprintf, iteratively increasing the buffer size
|
||||
// until it fits. Returned buffer should be freed by the caller.
|
||||
char* dosprintf(char* f, ...)
|
||||
{
|
||||
char* buf;
|
||||
va_list va;
|
||||
int len = 16;
|
||||
while(1) {
|
||||
buf = naAlloc(len);
|
||||
va_start(va, f);
|
||||
if(vsnprintf(buf, len, f, va) < len) {
|
||||
va_end(va);
|
||||
return buf;
|
||||
}
|
||||
va_end(va);
|
||||
naFree(buf);
|
||||
len *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Inspects a printf format string f, and finds the next "%..." format
|
||||
// specifier. Stores the start of the specifier in out, the length in
|
||||
// len, and the type in type. Returns a pointer to the remainder of
|
||||
// the format string, or 0 if no format string was found. Recognizes
|
||||
// all of ANSI C's syntax except for the "length modifier" feature.
|
||||
// Note: this does not validate the format character returned in
|
||||
// "type". That is the caller's job.
|
||||
static char* nextFormat(naContext ctx, char* f, char** out, int* len, char* type)
|
||||
{
|
||||
// Skip to the start of the format string
|
||||
while(*f && *f != '%') f++;
|
||||
if(!*f) return 0;
|
||||
*out = f++;
|
||||
|
||||
while(*f && (*f=='-' || *f=='+' || *f==' ' || *f=='0' || *f=='#')) f++;
|
||||
|
||||
// Test for duplicate flags. This is pure pedantry and could
|
||||
// be removed on all known platforms, but just to be safe...
|
||||
{ char *p1, *p2;
|
||||
for(p1 = *out + 1; p1 < f; p1++)
|
||||
for(p2 = p1+1; p2 < f; p2++)
|
||||
if(*p1 == *p2)
|
||||
naRuntimeError(ctx, "duplicate flag in format string"); }
|
||||
|
||||
while(*f && *f >= '0' && *f <= '9') f++;
|
||||
if(*f && *f == '.') f++;
|
||||
while(*f && *f >= '0' && *f <= '9') f++;
|
||||
if(!*f) naRuntimeError(ctx, "invalid format string");
|
||||
|
||||
*type = *f++;
|
||||
*len = f - *out;
|
||||
return f;
|
||||
}
|
||||
|
||||
#define ERR(m) naRuntimeError(ctx, m)
|
||||
#define APPEND(r) result = naStr_concat(naNewString(ctx), result, r)
|
||||
static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
char t, nultmp, *fstr, *next, *fout=0, *s;
|
||||
int flen, argn=1;
|
||||
naRef format, arg, result = naNewString(ctx);
|
||||
|
||||
if(argc < 1) ERR("not enough arguments to sprintf");
|
||||
format = naStringValue(ctx, argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(format)) ERR("bad format string in sprintf");
|
||||
s = naStr_data(format);
|
||||
|
||||
while((next = nextFormat(ctx, s, &fstr, &flen, &t))) {
|
||||
APPEND(NEWSTR(ctx, s, fstr-s)); // stuff before the format string
|
||||
if(flen == 2 && fstr[1] == '%') {
|
||||
APPEND(NEWSTR(ctx, "%", 1));
|
||||
s = next;
|
||||
continue;
|
||||
}
|
||||
if(argn >= argc) ERR("not enough arguments to sprintf");
|
||||
arg = args[argn++];
|
||||
nultmp = fstr[flen]; // sneaky nul termination...
|
||||
fstr[flen] = 0;
|
||||
if(t == 's') {
|
||||
arg = naStringValue(ctx, arg);
|
||||
if(naIsNil(arg)) fout = dosprintf(fstr, "nil");
|
||||
else fout = dosprintf(fstr, naStr_data(arg));
|
||||
} else {
|
||||
arg = naNumValue(arg);
|
||||
if(naIsNil(arg))
|
||||
fout = dosprintf(fstr, "nil");
|
||||
else if(t=='d' || t=='i' || t=='c')
|
||||
fout = dosprintf(fstr, (int)naNumValue(arg).num);
|
||||
else if(t=='o' || t=='u' || t=='x' || t=='X')
|
||||
fout = dosprintf(fstr, (unsigned int)naNumValue(arg).num);
|
||||
else if(t=='e' || t=='E' || t=='f' || t=='F' || t=='g' || t=='G')
|
||||
fout = dosprintf(fstr, naNumValue(arg).num);
|
||||
else
|
||||
ERR("invalid sprintf format type");
|
||||
}
|
||||
fstr[flen] = nultmp;
|
||||
APPEND(NEWSTR(ctx, fout, strlen(fout)));
|
||||
naFree(fout);
|
||||
s = next;
|
||||
}
|
||||
APPEND(NEWSTR(ctx, s, strlen(s)));
|
||||
return result;
|
||||
}
|
||||
|
||||
// FIXME: handle ctx->callParent frames too!
|
||||
static naRef f_caller(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int fidx;
|
||||
struct Frame* frame;
|
||||
naRef result, fr = argc ? naNumValue(args[0]) : naNum(1);
|
||||
if(IS_NIL(fr)) naRuntimeError(ctx, "non numeric argument to caller()");
|
||||
fidx = (int)fr.num;
|
||||
if(fidx > ctx->fTop - 1) return naNil();
|
||||
frame = &ctx->fStack[ctx->fTop - 1 - fidx];
|
||||
result = naNewVector(ctx);
|
||||
naVec_append(result, frame->locals);
|
||||
naVec_append(result, frame->func);
|
||||
naVec_append(result, frame->func.ref.ptr.func->code.ref.ptr.code->srcFile);
|
||||
naVec_append(result, naNum(naGetLine(ctx, fidx)));
|
||||
return result;
|
||||
}
|
||||
|
||||
static naRef f_closure(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
naRef func, idx;
|
||||
struct naFunc* f;
|
||||
func = argc > 0 ? args[0] : naNil();
|
||||
idx = argc > 1 ? naNumValue(args[1]) : naNil();
|
||||
if(!IS_FUNC(func) || IS_NIL(idx))
|
||||
naRuntimeError(ctx, "bad arguments to closure()");
|
||||
i = (int)idx.num;
|
||||
f = func.ref.ptr.func;
|
||||
while(i > 0 && f) { i--; f = f->next.ref.ptr.func; }
|
||||
if(!f) return naNil();
|
||||
return f->namespace;
|
||||
}
|
||||
|
||||
static int match(unsigned char* a, unsigned char* b, int l)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<l; i++) if(a[i] != b[i]) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int find(unsigned char* a, int al, unsigned char* s, int sl, int start)
|
||||
{
|
||||
int i;
|
||||
if(al == 0) return 0;
|
||||
for(i=start; i<sl-al+1; i++) if(match(a, s+i, al)) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static naRef f_find(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int start = 0;
|
||||
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1]))
|
||||
naRuntimeError(ctx, "bad/missing argument to find");
|
||||
if(argc > 2) start = (int)(naNumValue(args[2]).num);
|
||||
return naNum(find(args[0].ref.ptr.str->data, args[0].ref.ptr.str->len,
|
||||
args[1].ref.ptr.str->data, args[1].ref.ptr.str->len,
|
||||
start));
|
||||
}
|
||||
|
||||
static naRef f_split(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int sl, dl, i;
|
||||
char *s, *d, *s0;
|
||||
naRef result;
|
||||
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1]))
|
||||
naRuntimeError(ctx, "bad/missing argument to split");
|
||||
d = naStr_data(args[0]); dl = naStr_len(args[0]);
|
||||
s = naStr_data(args[1]); sl = naStr_len(args[1]);
|
||||
result = naNewVector(ctx);
|
||||
if(dl == 0) { // special case zero-length delimiter
|
||||
for(i=0; i<sl; i++) naVec_append(result, NEWSTR(ctx, s+i, 1));
|
||||
return result;
|
||||
}
|
||||
s0 = s;
|
||||
for(i=0; i <= sl-dl; i++) {
|
||||
if(match((unsigned char*)(s+i), (unsigned char*)d, dl)) {
|
||||
naVec_append(result, NEWSTR(ctx, s0, s+i-s0));
|
||||
s0 = s + i + dl;
|
||||
i += dl - 1;
|
||||
}
|
||||
}
|
||||
if(s0 - s <= sl) naVec_append(result, NEWSTR(ctx, s0, s+sl-s0));
|
||||
return result;
|
||||
}
|
||||
|
||||
// This is a comparatively weak RNG, based on the C library's rand()
|
||||
// function, which is usually not threadsafe and often of limited
|
||||
// precision. The 5x loop guarantees that we get a full double worth
|
||||
// of precision even for 15 bit (Win32...) rand() implementations.
|
||||
static naRef f_rand(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
double r = 0;
|
||||
if(argc) {
|
||||
if(!IS_NUM(args[0])) naRuntimeError(ctx, "rand() seed not number");
|
||||
srand((unsigned int)args[0].num);
|
||||
return naNil();
|
||||
}
|
||||
for(i=0; i<5; i++) r = (r + rand()) * (1.0/(RAND_MAX+1.0));
|
||||
return naNum(r);
|
||||
}
|
||||
|
||||
static naRef f_bind(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef func = argc > 0 ? args[0] : naNil();
|
||||
naRef hash = argc > 1 ? args[1] : naNewHash(ctx);
|
||||
naRef next = argc > 2 ? args[2] : naNil();
|
||||
if(!IS_FUNC(func) || (!IS_NIL(next) && !IS_FUNC(next)) || !IS_HASH(hash))
|
||||
naRuntimeError(ctx, "bad argument to bind");
|
||||
func = naNewFunc(ctx, func.ref.ptr.func->code);
|
||||
func.ref.ptr.func->namespace = hash;
|
||||
func.ref.ptr.func->next = next;
|
||||
return func;
|
||||
}
|
||||
|
||||
struct func { char* name; naCFunction func; };
|
||||
static struct func funcs[] = {
|
||||
{ "size", size },
|
||||
@@ -162,9 +456,21 @@ static struct func funcs[] = {
|
||||
{ "int", intf },
|
||||
{ "num", num },
|
||||
{ "streq", streq },
|
||||
{ "cmp", f_cmp },
|
||||
{ "substr", substr },
|
||||
{ "chr", f_chr },
|
||||
{ "contains", contains },
|
||||
{ "typeof", typeOf },
|
||||
{ "compile", f_compile },
|
||||
{ "call", f_call },
|
||||
{ "die", f_die },
|
||||
{ "sprintf", f_sprintf },
|
||||
{ "caller", f_caller },
|
||||
{ "closure", f_closure },
|
||||
{ "find", f_find },
|
||||
{ "split", f_split },
|
||||
{ "rand", f_rand },
|
||||
{ "bind", f_bind },
|
||||
};
|
||||
|
||||
naRef naStdLib(naContext c)
|
||||
@@ -173,8 +479,8 @@ naRef naStdLib(naContext c)
|
||||
int i, n = sizeof(funcs)/sizeof(struct func);
|
||||
for(i=0; i<n; i++) {
|
||||
naRef code = naNewCCode(c, funcs[i].func);
|
||||
naRef name = naStr_fromdata(naNewString(c),
|
||||
funcs[i].name, StrLen(funcs[i].name));
|
||||
naRef name = NEWSTR(c, funcs[i].name, strlen(funcs[i].name));
|
||||
name = naInternSymbol(name);
|
||||
naHash_set(namespace, name, naNewFunc(c, code));
|
||||
}
|
||||
return namespace;
|
||||
|
||||
+18
-16
@@ -7,55 +7,55 @@
|
||||
|
||||
#include "nasal.h"
|
||||
|
||||
static naRef f_sin(naContext c, naRef args)
|
||||
static naRef f_sin(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(naVec_get(args, 0));
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to sin()");
|
||||
a.num = sin(a.num);
|
||||
return a;
|
||||
}
|
||||
|
||||
static naRef f_cos(naContext c, naRef args)
|
||||
static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(naVec_get(args, 0));
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to cos()");
|
||||
a.num = cos(a.num);
|
||||
return a;
|
||||
}
|
||||
|
||||
static naRef f_exp(naContext c, naRef args)
|
||||
static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(naVec_get(args, 0));
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to exp()");
|
||||
a.num = exp(a.num);
|
||||
return a;
|
||||
}
|
||||
|
||||
static naRef f_ln(naContext c, naRef args)
|
||||
static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(naVec_get(args, 0));
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to ln()");
|
||||
a.num = log(a.num);
|
||||
return a;
|
||||
}
|
||||
|
||||
static naRef f_sqrt(naContext c, naRef args)
|
||||
static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(naVec_get(args, 0));
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to sqrt()");
|
||||
a.num = sqrt(a.num);
|
||||
return a;
|
||||
}
|
||||
|
||||
static naRef f_atan2(naContext c, naRef args)
|
||||
static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(naVec_get(args, 0));
|
||||
naRef b = naNumValue(naVec_get(args, 1));
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
naRef b = naNumValue(argc > 1 ? args[1] : naNil());
|
||||
if(naIsNil(a) || naIsNil(b))
|
||||
naRuntimeError(c, "non numeric argument to atan2()");
|
||||
a.num = atan2(a.num, b.num);
|
||||
@@ -82,12 +82,14 @@ naRef naMathLib(naContext c)
|
||||
naHash_set(namespace, name, naNewFunc(c, code));
|
||||
}
|
||||
|
||||
// Set up constants for math.pi and math.e
|
||||
// Set up constants for math.pi and math.e. Can't use M_PI or
|
||||
// M_E, becuase those aren't technically part of the C standard. Sigh.
|
||||
name = naStr_fromdata(naNewString(c), "pi", 2);
|
||||
naHash_set(namespace, name, naNum(M_PI));
|
||||
naHash_set(namespace, name, naNum(3.14159265358979323846));
|
||||
|
||||
name = naStr_fromdata(naNewString(c), "e", 1);
|
||||
naHash_set(namespace, name, naNum(M_E));
|
||||
name = naInternSymbol(name);
|
||||
naHash_set(namespace, name, naNum(2.7182818284590452354));
|
||||
|
||||
return namespace;
|
||||
}
|
||||
|
||||
+51
-63
@@ -7,8 +7,25 @@
|
||||
|
||||
void naFree(void* m) { free(m); }
|
||||
void* naAlloc(int n) { return malloc(n); }
|
||||
void* naRealloc(void* b, int n) { return realloc(b, n); }
|
||||
void naBZero(void* m, int n) { memset(m, 0, n); }
|
||||
|
||||
void naTempSave(naContext c, naRef r)
|
||||
{
|
||||
int i;
|
||||
if(!IS_OBJ(r)) return;
|
||||
if(c->ntemps >= c->tempsz) {
|
||||
struct naObj** newtemps;
|
||||
c->tempsz *= 2;
|
||||
newtemps = naAlloc(c->tempsz * sizeof(struct naObj*));
|
||||
for(i=0; i<c->ntemps; i++)
|
||||
newtemps[i] = c->temps[i];
|
||||
naFree(c->temps);
|
||||
c->temps = newtemps;
|
||||
}
|
||||
c->temps[c->ntemps++] = r.ref.ptr.obj;
|
||||
}
|
||||
|
||||
naRef naObj(int type, struct naObj* o)
|
||||
{
|
||||
naRef r;
|
||||
@@ -49,8 +66,12 @@ naRef naStringValue(naContext c, naRef r)
|
||||
|
||||
naRef naNew(struct Context* c, int type)
|
||||
{
|
||||
naRef result = naObj(type, naGC_get(&(c->pools[type])));
|
||||
naVec_append(c->temps, result);
|
||||
naRef result;
|
||||
if(c->nfree[type] == 0)
|
||||
c->free[type] = naGC_get(&globals->pools[type],
|
||||
OBJ_CACHE_SZ, &c->nfree[type]);
|
||||
result = naObj(type, c->free[type][--c->nfree[type]]);
|
||||
naTempSave(c, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -59,20 +80,21 @@ naRef naNewString(struct Context* c)
|
||||
naRef s = naNew(c, T_STR);
|
||||
s.ref.ptr.str->len = 0;
|
||||
s.ref.ptr.str->data = 0;
|
||||
s.ref.ptr.str->hashcode = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
naRef naNewVector(struct Context* c)
|
||||
{
|
||||
naRef r = naNew(c, T_VEC);
|
||||
naVec_init(r);
|
||||
r.ref.ptr.vec->rec = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
naRef naNewHash(struct Context* c)
|
||||
{
|
||||
naRef r = naNew(c, T_HASH);
|
||||
naHash_init(r);
|
||||
r.ref.ptr.hash->rec = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -92,18 +114,11 @@ naRef naNewFunc(struct Context* c, naRef code)
|
||||
{
|
||||
naRef func = naNew(c, T_FUNC);
|
||||
func.ref.ptr.func->code = code;
|
||||
func.ref.ptr.func->closure = naNil();
|
||||
func.ref.ptr.func->namespace = naNil();
|
||||
func.ref.ptr.func->next = naNil();
|
||||
return func;
|
||||
}
|
||||
|
||||
naRef naNewClosure(struct Context* c, naRef namespace, naRef next)
|
||||
{
|
||||
naRef closure = naNew(c, T_CLOSURE);
|
||||
closure.ref.ptr.closure->namespace = namespace;
|
||||
closure.ref.ptr.closure->next = next;
|
||||
return closure;
|
||||
}
|
||||
|
||||
naRef naNewGhost(naContext c, naGhostType* type, void* ptr)
|
||||
{
|
||||
naRef ghost = naNew(c, T_GHOST);
|
||||
@@ -162,6 +177,19 @@ int naEqual(naRef a, naRef b)
|
||||
return na == nb ? 1 : 0;
|
||||
}
|
||||
|
||||
int naStrEqual(naRef a, naRef b)
|
||||
{
|
||||
int i;
|
||||
if(!(IS_STR(a) && IS_STR(b)))
|
||||
return 0;
|
||||
if(a.ref.ptr.str->len != b.ref.ptr.str->len)
|
||||
return 0;
|
||||
for(i=0; i<a.ref.ptr.str->len; i++)
|
||||
if(a.ref.ptr.str->data[i] != b.ref.ptr.str->data[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int naTypeSize(int type)
|
||||
{
|
||||
switch(type) {
|
||||
@@ -170,59 +198,19 @@ int naTypeSize(int type)
|
||||
case T_HASH: return sizeof(struct naHash);
|
||||
case T_CODE: return sizeof(struct naCode);
|
||||
case T_FUNC: return sizeof(struct naFunc);
|
||||
case T_CLOSURE: return sizeof(struct naClosure);
|
||||
case T_CCODE: return sizeof(struct naCCode);
|
||||
case T_GHOST: return sizeof(struct naGhost);
|
||||
};
|
||||
return 0x7fffffff; // Make sure the answer is nonsense :)
|
||||
}
|
||||
|
||||
int naIsNil(naRef r)
|
||||
{
|
||||
return IS_NIL(r);
|
||||
}
|
||||
|
||||
int naIsNum(naRef r)
|
||||
{
|
||||
return IS_NUM(r);
|
||||
}
|
||||
|
||||
int naIsString(naRef r)
|
||||
{
|
||||
return (!IS_NIL(r))&&IS_STR(r);
|
||||
}
|
||||
|
||||
int naIsScalar(naRef r)
|
||||
{
|
||||
return IS_SCALAR(r);
|
||||
}
|
||||
|
||||
int naIsVector(naRef r)
|
||||
{
|
||||
return (!IS_NIL(r))&&IS_VEC(r);
|
||||
}
|
||||
|
||||
int naIsHash(naRef r)
|
||||
{
|
||||
return (!IS_NIL(r))&&IS_HASH(r);
|
||||
}
|
||||
|
||||
int naIsFunc(naRef r)
|
||||
{
|
||||
return (!IS_NIL(r))&&IS_FUNC(r);
|
||||
}
|
||||
|
||||
int naIsCode(naRef r)
|
||||
{
|
||||
return IS_CODE(r);
|
||||
}
|
||||
|
||||
int naIsCCode(naRef r)
|
||||
{
|
||||
return IS_CCODE(r);
|
||||
}
|
||||
|
||||
int naIsGhost(naRef r)
|
||||
{
|
||||
return IS_GHOST(r);
|
||||
}
|
||||
int naIsNil(naRef r) { return IS_NIL(r); }
|
||||
int naIsNum(naRef r) { return IS_NUM(r); }
|
||||
int naIsString(naRef r) { return IS_STR(r); }
|
||||
int naIsScalar(naRef r) { return IS_SCALAR(r); }
|
||||
int naIsVector(naRef r) { return IS_VEC(r); }
|
||||
int naIsHash(naRef r) { return IS_HASH(r); }
|
||||
int naIsFunc(naRef r) { return IS_FUNC(r); }
|
||||
int naIsCode(naRef r) { return IS_CODE(r); }
|
||||
int naIsCCode(naRef r) { return IS_CCODE(r); }
|
||||
int naIsGhost(naRef r) { return IS_GHOST(r); }
|
||||
|
||||
+33
-4
@@ -62,7 +62,6 @@ typedef union {
|
||||
struct naHash* hash;
|
||||
struct naCode* code;
|
||||
struct naFunc* func;
|
||||
struct naClosure* closure;
|
||||
struct naCCode* ccode;
|
||||
struct naGhost* ghost;
|
||||
} ptr;
|
||||
@@ -75,15 +74,21 @@ typedef union {
|
||||
typedef struct Context* naContext;
|
||||
|
||||
// The function signature for an extension function:
|
||||
typedef naRef (*naCFunction)(naContext ctx, naRef args);
|
||||
typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args);
|
||||
|
||||
// All Nasal code runs under the watch of a naContext:
|
||||
naContext naNewContext();
|
||||
void naFreeContext(naContext c);
|
||||
|
||||
// Save this object in the context, preventing it (and objects
|
||||
// referenced by it) from being garbage collected.
|
||||
void naSave(naContext ctx, naRef obj);
|
||||
|
||||
// Similar, but the object is automatically released when the
|
||||
// context next runs native bytecode. Useful for saving off C-space
|
||||
// temporaries to protect them before passing back into a naCall.
|
||||
void naTempSave(naContext c, naRef r);
|
||||
|
||||
// Parse a buffer in memory into a code object.
|
||||
naRef naParseCode(naContext c, naRef srcFile, int firstLine,
|
||||
char* buf, int len, int* errLine);
|
||||
@@ -95,10 +100,14 @@ naRef naParseCode(naContext c, naRef srcFile, int firstLine,
|
||||
// information from function objects.
|
||||
naRef naBindFunction(naContext ctx, naRef code, naRef closure);
|
||||
|
||||
// Similar, but it binds to the current context's closure (i.e. the
|
||||
// namespace at the top of the current call stack).
|
||||
naRef naBindToContext(naContext ctx, naRef code);
|
||||
|
||||
// Call a code or function object with the specifed arguments "on" the
|
||||
// specified object and using the specified hash for the local
|
||||
// variables. Any of args, obj or locals may be nil.
|
||||
naRef naCall(naContext ctx, naRef func, naRef args, naRef obj, naRef locals);
|
||||
naRef naCall(naContext ctx, naRef func, int argc, naRef* args, naRef obj, naRef locals);
|
||||
|
||||
// Throw an error from the current call stack. This function makes a
|
||||
// longjmp call to a handler in naCall() and DOES NOT RETURN. It is
|
||||
@@ -115,8 +124,12 @@ naRef naMethod(naContext ctx, naRef func, naRef object);
|
||||
// Useful for passing as a namespace to an initial function call
|
||||
naRef naStdLib(naContext c);
|
||||
|
||||
// Ditto, with math functions
|
||||
// Ditto, for other core libraries
|
||||
naRef naMathLib(naContext c);
|
||||
naRef naBitsLib(naContext c);
|
||||
naRef naIOLib(naContext c);
|
||||
naRef naRegexLib(naContext c);
|
||||
naRef naUnixLib(naContext c);
|
||||
|
||||
// Current line number & error message
|
||||
int naStackDepth(naContext ctx);
|
||||
@@ -146,6 +159,7 @@ naRef naNewCCode(naContext c, naCFunction fptr);
|
||||
|
||||
// Some useful conversion/comparison routines
|
||||
int naEqual(naRef a, naRef b);
|
||||
int naStrEqual(naRef a, naRef b);
|
||||
int naTrue(naRef b);
|
||||
naRef naNumValue(naRef n);
|
||||
naRef naStringValue(naContext c, naRef n);
|
||||
@@ -156,6 +170,7 @@ char* naStr_data(naRef s);
|
||||
naRef naStr_fromdata(naRef dst, char* data, int len);
|
||||
naRef naStr_concat(naRef dest, naRef s1, naRef s2);
|
||||
naRef naStr_substr(naRef dest, naRef str, int start, int len);
|
||||
naRef naInternSymbol(naRef sym);
|
||||
|
||||
// Vector utilities:
|
||||
int naVec_size(naRef v);
|
||||
@@ -183,6 +198,20 @@ naGhostType* naGhost_type(naRef ghost);
|
||||
void* naGhost_ptr(naRef ghost);
|
||||
int naIsGhost(naRef r);
|
||||
|
||||
// Acquires a "modification lock" on a context, allowing the C code to
|
||||
// modify Nasal data without fear that such data may be "lost" by the
|
||||
// garbage collector (the C stack is not examined in GC!). This
|
||||
// disallows garbage collection until the current thread can be
|
||||
// blocked. The lock should be acquired whenever modifications to
|
||||
// Nasal objects are made. It need not be acquired when only read
|
||||
// access is needed. It MUST NOT be acquired by naCFunction's, as
|
||||
// those are called with the lock already held; acquiring two locks
|
||||
// for the same thread will cause a deadlock when the GC is invoked.
|
||||
// It should be UNLOCKED by naCFunction's when they are about to do
|
||||
// any long term non-nasal processing and/or blocking I/O.
|
||||
void naModLock();
|
||||
void naModUnlock();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
+24
-11
@@ -6,20 +6,23 @@
|
||||
// (tight binding, do last).
|
||||
enum { PREC_BINARY, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
|
||||
|
||||
#define MAX_PREC_TOKS 5
|
||||
#define MAX_PREC_TOKS 6
|
||||
struct precedence {
|
||||
int toks[MAX_PREC_TOKS];
|
||||
int rule;
|
||||
} PRECEDENCE[] = {
|
||||
{ { TOK_SEMI, TOK_COMMA }, PREC_REVERSE },
|
||||
{ { TOK_COLON }, PREC_BINARY },
|
||||
{ { TOK_ELLIPSIS }, PREC_SUFFIX },
|
||||
{ { TOK_RETURN, TOK_BREAK, TOK_CONTINUE }, PREC_PREFIX },
|
||||
{ { TOK_ASSIGN }, PREC_REVERSE },
|
||||
{ { TOK_ASSIGN, TOK_PLUSEQ, TOK_MINUSEQ,
|
||||
TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ }, PREC_REVERSE },
|
||||
{ { TOK_COLON, TOK_QUESTION }, PREC_REVERSE },
|
||||
{ { TOK_VAR }, PREC_PREFIX },
|
||||
{ { TOK_OR }, PREC_BINARY },
|
||||
{ { TOK_AND }, PREC_BINARY },
|
||||
{ { TOK_EQ, TOK_NEQ }, PREC_BINARY },
|
||||
{ { TOK_LT, TOK_LTE, TOK_GT, TOK_GTE }, PREC_BINARY },
|
||||
{ { TOK_PLUS, TOK_MINUS, TOK_CAT }, PREC_REVERSE },
|
||||
{ { TOK_PLUS, TOK_MINUS, TOK_CAT }, PREC_BINARY },
|
||||
{ { TOK_MUL, TOK_DIV }, PREC_BINARY },
|
||||
{ { TOK_MINUS, TOK_NEG, TOK_NOT }, PREC_PREFIX },
|
||||
{ { TOK_LPAR, TOK_LBRA }, PREC_SUFFIX },
|
||||
@@ -210,14 +213,22 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
|
||||
t = start;
|
||||
while(t) {
|
||||
switch(t->type) {
|
||||
case TOK_ELSE: case TOK_FUNC:
|
||||
case TOK_FUNC:
|
||||
// Slurp an optional paren block containing an arglist, then
|
||||
// fall through to parse the curlies...
|
||||
if(t->next && t->next->type == TOK_LPAR) {
|
||||
c = t->next;
|
||||
addNewChild(t, c);
|
||||
fixBlockStructure(p, c);
|
||||
}
|
||||
case TOK_ELSE: // and TOK_FUNC!
|
||||
// These guys precede a single curly block
|
||||
if(!t->next || t->next->type != TOK_LCURL) oops(p, t);
|
||||
c = t->next;
|
||||
addNewChild(t, c);
|
||||
fixBlockStructure(p, c);
|
||||
break;
|
||||
case TOK_FOR: case TOK_FOREACH: case TOK_WHILE:
|
||||
case TOK_FOR: case TOK_FOREACH: case TOK_FORINDEX: case TOK_WHILE:
|
||||
case TOK_IF: case TOK_ELSIF:
|
||||
// Expect a paren and then a curly
|
||||
if(!t->next || t->next->type != TOK_LPAR) oops(p, t);
|
||||
@@ -268,7 +279,7 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
|
||||
|| t->prev->type == TOK_LCURL)
|
||||
addSemi = 1;
|
||||
break;
|
||||
case TOK_FOR: case TOK_FOREACH: case TOK_WHILE:
|
||||
case TOK_FOR: case TOK_FOREACH: case TOK_FORINDEX: case TOK_WHILE:
|
||||
addSemi = 1;
|
||||
break;
|
||||
case TOK_FUNC:
|
||||
@@ -276,6 +287,8 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
|
||||
addSemi = 1;
|
||||
break;
|
||||
}
|
||||
if(t->next && t->next->type == TOK_SEMI)
|
||||
addSemi = 0; // don't bother if it's already there!
|
||||
if(addSemi) {
|
||||
struct Token* semi = emptyToken(p);
|
||||
semi->type = TOK_SEMI;
|
||||
@@ -311,7 +324,7 @@ static int isBlock(int t)
|
||||
{
|
||||
return t == TOK_IF || t == TOK_ELSIF || t == TOK_ELSE
|
||||
|| t == TOK_FOR || t == TOK_FOREACH || t == TOK_WHILE
|
||||
|| t == TOK_FUNC;
|
||||
|| t == TOK_FUNC || t == TOK_FORINDEX;
|
||||
}
|
||||
|
||||
static void precChildren(struct Parser* p, struct Token* t);
|
||||
@@ -490,7 +503,7 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
|
||||
struct Parser p;
|
||||
|
||||
// Protect from garbage collection
|
||||
naVec_append(c->temps, srcFile);
|
||||
naTempSave(c, srcFile);
|
||||
|
||||
// Catch parser errors here.
|
||||
*errLine = 0;
|
||||
@@ -519,11 +532,11 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
|
||||
p.tree.lastChild = t;
|
||||
|
||||
// Generate code!
|
||||
codeObj = naCodeGen(&p, &(p.tree));
|
||||
codeObj = naCodeGen(&p, &(p.tree), 0);
|
||||
|
||||
// Clean up our mess
|
||||
naParseDestroy(&p);
|
||||
naVec_append(c->temps, codeObj);
|
||||
naTempSave(c, codeObj);
|
||||
|
||||
return codeObj;
|
||||
}
|
||||
|
||||
+13
-8
@@ -14,7 +14,9 @@ enum {
|
||||
TOK_ASSIGN, TOK_LT, TOK_LTE, TOK_EQ, TOK_NEQ, TOK_GT, TOK_GTE,
|
||||
TOK_IF, TOK_ELSIF, TOK_ELSE, TOK_FOR, TOK_FOREACH, TOK_WHILE,
|
||||
TOK_RETURN, TOK_BREAK, TOK_CONTINUE, TOK_FUNC, TOK_SYMBOL,
|
||||
TOK_LITERAL, TOK_EMPTY, TOK_NIL
|
||||
TOK_LITERAL, TOK_EMPTY, TOK_NIL, TOK_ELLIPSIS, TOK_QUESTION, TOK_VAR,
|
||||
TOK_PLUSEQ, TOK_MINUSEQ, TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ,
|
||||
TOK_FORINDEX
|
||||
};
|
||||
|
||||
struct Token {
|
||||
@@ -58,7 +60,7 @@ struct Parser {
|
||||
// Computed line number table for the lexer
|
||||
int* lines;
|
||||
int nLines;
|
||||
|
||||
|
||||
struct CodeGenerator* cg;
|
||||
};
|
||||
|
||||
@@ -66,10 +68,15 @@ struct CodeGenerator {
|
||||
int lastLine;
|
||||
|
||||
// Accumulated byte code array
|
||||
unsigned char* byteCode;
|
||||
int nBytes;
|
||||
unsigned short* byteCode;
|
||||
int codesz;
|
||||
int codeAlloced;
|
||||
|
||||
// Inst. -> line table, stores pairs of {ip, line}
|
||||
unsigned short* lineIps;
|
||||
int nLineIps; // number of pairs
|
||||
int nextLineIp;
|
||||
|
||||
// Stack of "loop" frames for break/continue statements
|
||||
struct {
|
||||
int breakIP;
|
||||
@@ -79,9 +86,7 @@ struct CodeGenerator {
|
||||
int loopTop;
|
||||
|
||||
// Dynamic storage for constants, to be compiled into a static table
|
||||
naRef consts; // index -> naRef
|
||||
naRef interned; // naRef -> index (scalars only!)
|
||||
int nConsts;
|
||||
naRef consts;
|
||||
};
|
||||
|
||||
void naParseError(struct Parser* p, char* msg, int line);
|
||||
@@ -89,7 +94,7 @@ void naParseInit(struct Parser* p);
|
||||
void* naParseAlloc(struct Parser* p, int bytes);
|
||||
void naParseDestroy(struct Parser* p);
|
||||
void naLex(struct Parser* p);
|
||||
naRef naCodeGen(struct Parser* p, struct Token* tok);
|
||||
naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist);
|
||||
|
||||
void naParse(struct Parser* p);
|
||||
|
||||
|
||||
+45
-30
@@ -8,11 +8,6 @@
|
||||
// double.
|
||||
#define DIGITS 16
|
||||
|
||||
// The minimum size we'll allocate for a string. Since a string
|
||||
// structure is already 12 bytes, and each naRef that points to it is
|
||||
// 8, there isn't much point in being stingy.
|
||||
#define MINLEN 16
|
||||
|
||||
static int tonum(unsigned char* s, int len, double* result);
|
||||
static int fromnum(double val, unsigned char* s);
|
||||
|
||||
@@ -25,21 +20,22 @@ int naStr_len(naRef s)
|
||||
char* naStr_data(naRef s)
|
||||
{
|
||||
if(!IS_STR(s)) return 0;
|
||||
return s.ref.ptr.str->data;
|
||||
return (char*)s.ref.ptr.str->data;
|
||||
}
|
||||
|
||||
static void setlen(struct naStr* s, int sz)
|
||||
{
|
||||
int currSz, waste;
|
||||
sz += 1; // Allow for an extra nul terminator
|
||||
currSz = s->len+1 < MINLEN ? MINLEN : s->len+1;
|
||||
waste = currSz - sz; // how much extra if we don't reallocate?
|
||||
if(s->data == 0 || waste < 0 || waste > MINLEN) {
|
||||
naFree(s->data);
|
||||
s->data = naAlloc(sz < MINLEN ? MINLEN : sz);
|
||||
}
|
||||
s->len = sz - 1;
|
||||
s->data[s->len] = 0; // nul terminate
|
||||
if(s->data) naFree(s->data);
|
||||
s->len = sz;
|
||||
s->data = naAlloc(sz+1);
|
||||
s->data[sz] = 0; // nul terminate
|
||||
}
|
||||
|
||||
naRef naStr_buf(naRef dst, int len)
|
||||
{
|
||||
setlen(dst.ref.ptr.str, len);
|
||||
naBZero(dst.ref.ptr.str->data, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
naRef naStr_fromdata(naRef dst, char* data, int len)
|
||||
@@ -94,7 +90,7 @@ naRef naStr_fromnum(naRef dest, double num)
|
||||
|
||||
int naStr_parsenum(char* str, int len, double* result)
|
||||
{
|
||||
return tonum(str, len, result);
|
||||
return tonum((unsigned char*)str, len, result);
|
||||
}
|
||||
|
||||
int naStr_tonum(naRef str, double* out)
|
||||
@@ -110,10 +106,8 @@ int naStr_numeric(naRef str)
|
||||
|
||||
void naStr_gcclean(struct naStr* str)
|
||||
{
|
||||
if(str->len > MINLEN) {
|
||||
naFree(str->data);
|
||||
str->data = 0;
|
||||
}
|
||||
naFree(str->data);
|
||||
str->data = 0;
|
||||
str->len = 0;
|
||||
}
|
||||
|
||||
@@ -147,17 +141,21 @@ static int readdec(unsigned char* s, int len, int i, double* v)
|
||||
|
||||
// Reads a signed integer out of the string starting at i, stores it
|
||||
// in v, and returns the next index to start at. Zero-length
|
||||
// decimal numbers (and length-1 strings like '+') are allowed, and
|
||||
// are returned as zero.
|
||||
// decimal numbers are allowed, and are returned as zero.
|
||||
static int readsigned(unsigned char* s, int len, int i, double* v)
|
||||
{
|
||||
int i0 = i, i2;
|
||||
double sgn=1, val;
|
||||
if(i >= len) { *v = 0; return len; }
|
||||
if(s[i] == '+') { i++; }
|
||||
else if(s[i] == '-') { i++; sgn = -1; }
|
||||
i = readdec(s, len, i, &val);
|
||||
i2 = readdec(s, len, i, &val);
|
||||
if(i0 == i && i2 == i) {
|
||||
*v = 0;
|
||||
return i0; // don't successfully parse bare "+" or "-"
|
||||
}
|
||||
*v = sgn*val;
|
||||
return i;
|
||||
return i2;
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +178,17 @@ static int tonum(unsigned char* s, int len, double* result)
|
||||
int i=0, fraclen=0;
|
||||
double sgn=1, val, frac=0, exp=0;
|
||||
|
||||
// Special case, "." is not a number, even though "1." and ".0" are.
|
||||
if(len == 1 && s[0] == '.')
|
||||
return 0;
|
||||
|
||||
// Strip off the leading negative sign first, so we can correctly
|
||||
// parse things like -.xxx which would otherwise confuse
|
||||
// readsigned.
|
||||
if(len > 1 && s[0] == '-' && s[1] != '-') {
|
||||
sgn = -1; s++; len--;
|
||||
}
|
||||
|
||||
// Read the integer part
|
||||
i = readsigned(s, len, i, &val);
|
||||
if(val < 0) { sgn = -1; val = -val; }
|
||||
@@ -191,9 +200,15 @@ static int tonum(unsigned char* s, int len, double* result)
|
||||
i += fraclen;
|
||||
}
|
||||
|
||||
// Nothing so far? Then the parse failed.
|
||||
if(i == 0) return 0;
|
||||
|
||||
// Read the exponent, if any
|
||||
if(i < len && (s[i] == 'e' || s[i] == 'E'))
|
||||
if(i < len && (s[i] == 'e' || s[i] == 'E')) {
|
||||
int i0 = i+1;
|
||||
i = readsigned(s, len, i+1, &exp);
|
||||
if(i == i0) return 0; // Must have a number after the "e"
|
||||
}
|
||||
|
||||
// compute the result
|
||||
*result = sgn * (val + frac * decpow(-fraclen)) * decpow(exp);
|
||||
@@ -205,13 +220,13 @@ static int tonum(unsigned char* s, int len, double* result)
|
||||
|
||||
// Very simple positive (!) integer print routine. Puts the result in
|
||||
// s and returns the number of characters written. Does not null
|
||||
// terminate the result.
|
||||
// terminate the result. Presumes at least a 32 bit integer, and
|
||||
// cannot print integers larger than 9999999999.
|
||||
static int decprint(int val, unsigned char* s)
|
||||
{
|
||||
int p=1, i=0;
|
||||
if(val == 0) { *s = '0'; return 1; }
|
||||
while(p <= val) p *= 10;
|
||||
p /= 10;
|
||||
while(p <= 999999999 && p*10 <= val) p *= 10;
|
||||
while(p > 0) {
|
||||
int count = 0;
|
||||
while(val >= p) { val -= p; count++; }
|
||||
@@ -270,7 +285,7 @@ static int fromnum(double val, unsigned char* s)
|
||||
if(raw[i] != '0') break;
|
||||
digs = i+1;
|
||||
|
||||
if(exp > 0 || exp < -(DIGITS+2)) {
|
||||
if(exp > 0 || exp < -(DIGITS+3)) {
|
||||
// Standard scientific notation
|
||||
exp += DIGITS-1;
|
||||
*ptr++ = raw[0];
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <pthread.h>
|
||||
#include "code.h"
|
||||
|
||||
void* naNewLock()
|
||||
{
|
||||
pthread_mutex_t* lock = naAlloc(sizeof(pthread_mutex_t));
|
||||
pthread_mutex_init(lock, 0);
|
||||
return lock;
|
||||
}
|
||||
|
||||
void naLock(void* lock)
|
||||
{
|
||||
pthread_mutex_lock((pthread_mutex_t*)lock);
|
||||
}
|
||||
|
||||
void naUnlock(void* lock)
|
||||
{
|
||||
pthread_mutex_unlock((pthread_mutex_t*)lock);
|
||||
}
|
||||
|
||||
struct naSem {
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cvar;
|
||||
int count;
|
||||
};
|
||||
|
||||
void* naNewSem()
|
||||
{
|
||||
struct naSem* sem = naAlloc(sizeof(struct naSem));
|
||||
pthread_mutex_init(&sem->lock , 0);
|
||||
pthread_cond_init(&sem->cvar, 0);
|
||||
sem->count = 0;
|
||||
return sem;
|
||||
}
|
||||
|
||||
void naSemDown(void* sh)
|
||||
{
|
||||
struct naSem* sem = (struct naSem*)sh;
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
while(sem->count <= 0)
|
||||
pthread_cond_wait(&sem->cvar, &sem->lock);
|
||||
sem->count--;
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
}
|
||||
|
||||
void naSemUpAll(void* sh, int count)
|
||||
{
|
||||
struct naSem* sem = (struct naSem*)sh;
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
sem->count = count;
|
||||
pthread_cond_broadcast(&sem->cvar);
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extern int GccWarningWorkaround_IsoCForbidsAnEmptySourceFile;
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define MAX_SEM_COUNT 1024 // What are the tradeoffs with this value?
|
||||
|
||||
void* naNewLock()
|
||||
{
|
||||
LPCRITICAL_SECTION lock = malloc(sizeof(CRITICAL_SECTION));
|
||||
InitializeCriticalSection(lock);
|
||||
return lock;
|
||||
}
|
||||
|
||||
void naLock(void* lock) { EnterCriticalSection((LPCRITICAL_SECTION)lock); }
|
||||
void naUnlock(void* lock) { LeaveCriticalSection((LPCRITICAL_SECTION)lock); }
|
||||
void* naNewSem() { return CreateSemaphore(0, 0, MAX_SEM_COUNT, 0); }
|
||||
void naSemDown(void* sem) { WaitForSingleObject((HANDLE)sem, INFINITE); }
|
||||
void naSemUpAll(void* sem, int count) { ReleaseSemaphore(sem, count, 0); }
|
||||
|
||||
#endif
|
||||
|
||||
extern int GccWarningWorkaround_IsoCForbidsAnEmptySourceFile;
|
||||
+59
-45
@@ -1,84 +1,98 @@
|
||||
#include "nasal.h"
|
||||
#include "data.h"
|
||||
|
||||
static void realloc(struct naVec* v)
|
||||
static struct VecRec* newvecrec(struct VecRec* old)
|
||||
{
|
||||
int i, newsz = 1 + ((v->size*3)>>1);
|
||||
naRef* na = naAlloc(sizeof(naRef) * newsz);
|
||||
v->alloced = newsz;
|
||||
for(i=0; i<v->size; i++)
|
||||
na[i] = v->array[i];
|
||||
naFree(v->array);
|
||||
v->array = na;
|
||||
int i, oldsz = old ? old->size : 0, newsz = 1 + ((oldsz*3)>>1);
|
||||
struct VecRec* vr = naAlloc(sizeof(struct VecRec) + sizeof(naRef) * newsz);
|
||||
if(oldsz > newsz) oldsz = newsz; // race protection
|
||||
vr->alloced = newsz;
|
||||
vr->size = oldsz;
|
||||
for(i=0; i<oldsz; i++)
|
||||
vr->array[i] = old->array[i];
|
||||
return vr;
|
||||
}
|
||||
|
||||
void naVec_init(naRef vec)
|
||||
static void realloc(struct naVec* v)
|
||||
{
|
||||
struct naVec* v = vec.ref.ptr.vec;
|
||||
v->array = 0;
|
||||
v->size = 0;
|
||||
v->alloced = 0;
|
||||
struct VecRec* vr = newvecrec(v->rec);
|
||||
naGC_swapfree((void**)&(v->rec), vr);
|
||||
}
|
||||
|
||||
void naVec_gcclean(struct naVec* v)
|
||||
{
|
||||
naFree(v->array);
|
||||
v->size = 0;
|
||||
v->alloced = 0;
|
||||
v->array = 0;
|
||||
naFree(v->rec);
|
||||
v->rec = 0;
|
||||
}
|
||||
|
||||
naRef naVec_get(naRef v, int i)
|
||||
{
|
||||
if(!IS_VEC(v)) return naNil();
|
||||
if(i >= v.ref.ptr.vec->size) return naNil();
|
||||
return v.ref.ptr.vec->array[i];
|
||||
if(IS_VEC(v)) {
|
||||
struct VecRec* r = v.ref.ptr.vec->rec;
|
||||
if(r) {
|
||||
if(i < 0) i += r->size;
|
||||
if(i >= 0 && i < r->size) return r->array[i];
|
||||
}
|
||||
}
|
||||
return naNil();
|
||||
}
|
||||
|
||||
void naVec_set(naRef vec, int i, naRef o)
|
||||
{
|
||||
struct naVec* v = vec.ref.ptr.vec;
|
||||
if(!IS_VEC(vec) || i >= v->size) return;
|
||||
v->array[i] = o;
|
||||
if(IS_VEC(vec)) {
|
||||
struct VecRec* r = vec.ref.ptr.vec->rec;
|
||||
if(r && i >= r->size) return;
|
||||
r->array[i] = o;
|
||||
}
|
||||
}
|
||||
|
||||
int naVec_size(naRef v)
|
||||
{
|
||||
if(!IS_VEC(v)) return 0;
|
||||
return v.ref.ptr.vec->size;
|
||||
if(IS_VEC(v)) {
|
||||
struct VecRec* r = v.ref.ptr.vec->rec;
|
||||
return r ? r->size : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int naVec_append(naRef vec, naRef o)
|
||||
{
|
||||
struct naVec* v = vec.ref.ptr.vec;
|
||||
if(!IS_VEC(vec)) return 0;
|
||||
if(v->size >= v->alloced)
|
||||
realloc(v);
|
||||
v->array[v->size] = o;
|
||||
return v->size++;
|
||||
if(IS_VEC(vec)) {
|
||||
struct VecRec* r = vec.ref.ptr.vec->rec;
|
||||
while(!r || r->size >= r->alloced) {
|
||||
realloc(vec.ref.ptr.vec);
|
||||
r = vec.ref.ptr.vec->rec;
|
||||
}
|
||||
r->array[r->size] = o;
|
||||
return r->size++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void naVec_setsize(naRef vec, int sz)
|
||||
{
|
||||
int i;
|
||||
struct naVec* v = vec.ref.ptr.vec;
|
||||
naRef* na = naAlloc(sizeof(naRef) * sz);
|
||||
struct VecRec* v = vec.ref.ptr.vec->rec;
|
||||
struct VecRec* nv = naAlloc(sizeof(struct VecRec) + sizeof(naRef) * sz);
|
||||
nv->size = sz;
|
||||
nv->alloced = sz;
|
||||
for(i=0; i<sz; i++)
|
||||
na[i] = (i < v->size) ? v->array[i] : naNil();
|
||||
naFree(v->array);
|
||||
v->array = na;
|
||||
v->size = sz;
|
||||
v->alloced = sz;
|
||||
nv->array[i] = (v && i < v->size) ? v->array[i] : naNil();
|
||||
naFree(v);
|
||||
vec.ref.ptr.vec->rec = nv;
|
||||
}
|
||||
|
||||
naRef naVec_removelast(naRef vec)
|
||||
{
|
||||
naRef o;
|
||||
struct naVec* v = vec.ref.ptr.vec;
|
||||
if(!IS_VEC(vec) || v->size == 0) return naNil();
|
||||
o = v->array[v->size - 1];
|
||||
v->size--;
|
||||
if(v->size < (v->alloced >> 1))
|
||||
realloc(v);
|
||||
return o;
|
||||
if(IS_VEC(vec)) {
|
||||
struct VecRec* v = vec.ref.ptr.vec->rec;
|
||||
if(!v || v->size == 0) return naNil();
|
||||
o = v->array[v->size - 1];
|
||||
v->size--;
|
||||
if(v->size < (v->alloced >> 1))
|
||||
realloc(vec.ref.ptr.vec);
|
||||
return o;
|
||||
}
|
||||
return naNil();
|
||||
}
|
||||
|
||||
+99
-36
@@ -275,7 +275,7 @@ find_node (SGPropertyNode * current,
|
||||
|
||||
// Success! This is the one we want.
|
||||
else if (position >= (int)components.size()) {
|
||||
return current;
|
||||
return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
|
||||
}
|
||||
|
||||
// Empty component means root.
|
||||
@@ -471,7 +471,7 @@ SGPropertyNode::set_string (const char * val)
|
||||
}
|
||||
|
||||
void
|
||||
SGPropertyNode::clear_value ()
|
||||
SGPropertyNode::clearValue ()
|
||||
{
|
||||
switch (_type) {
|
||||
case NONE:
|
||||
@@ -762,7 +762,7 @@ SGPropertyNode::~SGPropertyNode ()
|
||||
delete [] _display_name;
|
||||
delete [] _path;
|
||||
delete _path_cache;
|
||||
clear_value();
|
||||
clearValue();
|
||||
delete _listeners;
|
||||
}
|
||||
|
||||
@@ -775,7 +775,7 @@ SGPropertyNode::alias (SGPropertyNode * target)
|
||||
{
|
||||
if (target == 0 || _type == ALIAS || _tied)
|
||||
return false;
|
||||
clear_value();
|
||||
clearValue();
|
||||
_value.alias = target;
|
||||
_type = ALIAS;
|
||||
return true;
|
||||
@@ -911,6 +911,32 @@ SGPropertyNode::getChildren (const char * name) const
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove child by position.
|
||||
*/
|
||||
SGPropertyNode_ptr
|
||||
SGPropertyNode::removeChild (int pos, bool keep)
|
||||
{
|
||||
SGPropertyNode_ptr node;
|
||||
if (pos < 0 || pos >= _children.size())
|
||||
return node;
|
||||
|
||||
vector<SGPropertyNode_ptr>::iterator it = _children.begin();
|
||||
it += pos;
|
||||
node = _children[pos];
|
||||
_children.erase(it);
|
||||
if (keep) {
|
||||
_removedChildren.push_back(node);
|
||||
}
|
||||
if (_path_cache)
|
||||
_path_cache->erase(node->getName()); // EMH - TODO: Take "index" into account!
|
||||
node->setAttribute(REMOVED, true);
|
||||
node->clearValue();
|
||||
fireChildRemoved(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a child node
|
||||
*/
|
||||
@@ -919,22 +945,29 @@ SGPropertyNode::removeChild (const char * name, int index, bool keep)
|
||||
{
|
||||
SGPropertyNode_ptr ret;
|
||||
int pos = find_child(name, index, _children);
|
||||
if (pos >= 0) {
|
||||
vector<SGPropertyNode_ptr>::iterator it = _children.begin();
|
||||
it += pos;
|
||||
SGPropertyNode_ptr node = _children[pos];
|
||||
_children.erase(it);
|
||||
if (keep) {
|
||||
_removedChildren.push_back(node);
|
||||
}
|
||||
node->setAttribute(REMOVED, true);
|
||||
ret = node;
|
||||
fireChildRemoved(node);
|
||||
}
|
||||
if (pos >= 0)
|
||||
ret = removeChild(pos, keep);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove all children with the specified name.
|
||||
*/
|
||||
vector<SGPropertyNode_ptr>
|
||||
SGPropertyNode::removeChildren (const char * name, bool keep)
|
||||
{
|
||||
vector<SGPropertyNode_ptr> children;
|
||||
|
||||
for (int pos = _children.size() - 1; pos >= 0; pos--)
|
||||
if (compare_strings(_children[pos]->getName(), name))
|
||||
children.push_back(removeChild(pos, keep));
|
||||
|
||||
sort(children.begin(), children.end(), CompareIndices());
|
||||
return children;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
SGPropertyNode::getDisplayName (bool simplify) const
|
||||
{
|
||||
@@ -1168,7 +1201,7 @@ SGPropertyNode::setBoolValue (bool value)
|
||||
bool result = false;
|
||||
TEST_WRITE;
|
||||
if (_type == NONE || _type == UNSPECIFIED) {
|
||||
clear_value();
|
||||
clearValue();
|
||||
_tied = false;
|
||||
_type = BOOL;
|
||||
}
|
||||
@@ -1216,7 +1249,7 @@ SGPropertyNode::setIntValue (int value)
|
||||
bool result = false;
|
||||
TEST_WRITE;
|
||||
if (_type == NONE || _type == UNSPECIFIED) {
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = INT;
|
||||
_local_val.int_val = 0;
|
||||
}
|
||||
@@ -1267,7 +1300,7 @@ SGPropertyNode::setLongValue (long value)
|
||||
bool result = false;
|
||||
TEST_WRITE;
|
||||
if (_type == NONE || _type == UNSPECIFIED) {
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = LONG;
|
||||
_local_val.long_val = 0L;
|
||||
}
|
||||
@@ -1318,7 +1351,7 @@ SGPropertyNode::setFloatValue (float value)
|
||||
bool result = false;
|
||||
TEST_WRITE;
|
||||
if (_type == NONE || _type == UNSPECIFIED) {
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = FLOAT;
|
||||
_local_val.float_val = 0;
|
||||
}
|
||||
@@ -1369,7 +1402,7 @@ SGPropertyNode::setDoubleValue (double value)
|
||||
bool result = false;
|
||||
TEST_WRITE;
|
||||
if (_type == NONE || _type == UNSPECIFIED) {
|
||||
clear_value();
|
||||
clearValue();
|
||||
_local_val.double_val = value;
|
||||
_type = DOUBLE;
|
||||
}
|
||||
@@ -1420,7 +1453,7 @@ SGPropertyNode::setStringValue (const char * value)
|
||||
bool result = false;
|
||||
TEST_WRITE;
|
||||
if (_type == NONE || _type == UNSPECIFIED) {
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = STRING;
|
||||
}
|
||||
|
||||
@@ -1464,7 +1497,7 @@ SGPropertyNode::setUnspecifiedValue (const char * value)
|
||||
bool result = false;
|
||||
TEST_WRITE;
|
||||
if (_type == NONE) {
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = UNSPECIFIED;
|
||||
}
|
||||
|
||||
@@ -1513,7 +1546,7 @@ SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
|
||||
if (useDefault)
|
||||
old_val = getBoolValue();
|
||||
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = BOOL;
|
||||
_tied = true;
|
||||
_value.bool_val = rawValue.clone();
|
||||
@@ -1535,7 +1568,7 @@ SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
|
||||
if (useDefault)
|
||||
old_val = getIntValue();
|
||||
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = INT;
|
||||
_tied = true;
|
||||
_value.int_val = rawValue.clone();
|
||||
@@ -1557,7 +1590,7 @@ SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
|
||||
if (useDefault)
|
||||
old_val = getLongValue();
|
||||
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = LONG;
|
||||
_tied = true;
|
||||
_value.long_val = rawValue.clone();
|
||||
@@ -1579,7 +1612,7 @@ SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
|
||||
if (useDefault)
|
||||
old_val = getFloatValue();
|
||||
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = FLOAT;
|
||||
_tied = true;
|
||||
_value.float_val = rawValue.clone();
|
||||
@@ -1601,7 +1634,7 @@ SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
|
||||
if (useDefault)
|
||||
old_val = getDoubleValue();
|
||||
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = DOUBLE;
|
||||
_tied = true;
|
||||
_value.double_val = rawValue.clone();
|
||||
@@ -1624,7 +1657,7 @@ SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
|
||||
if (useDefault)
|
||||
old_val = getStringValue();
|
||||
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = STRING;
|
||||
_tied = true;
|
||||
_value.string_val = rawValue.clone();
|
||||
@@ -1644,35 +1677,35 @@ SGPropertyNode::untie ()
|
||||
switch (_type) {
|
||||
case BOOL: {
|
||||
bool val = getBoolValue();
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = BOOL;
|
||||
_local_val.bool_val = val;
|
||||
break;
|
||||
}
|
||||
case INT: {
|
||||
int val = getIntValue();
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = INT;
|
||||
_local_val.int_val = val;
|
||||
break;
|
||||
}
|
||||
case LONG: {
|
||||
long val = getLongValue();
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = LONG;
|
||||
_local_val.long_val = val;
|
||||
break;
|
||||
}
|
||||
case FLOAT: {
|
||||
float val = getFloatValue();
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = FLOAT;
|
||||
_local_val.float_val = val;
|
||||
break;
|
||||
}
|
||||
case DOUBLE: {
|
||||
double val = getDoubleValue();
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = DOUBLE;
|
||||
_local_val.double_val = val;
|
||||
break;
|
||||
@@ -1680,7 +1713,7 @@ SGPropertyNode::untie ()
|
||||
case STRING:
|
||||
case UNSPECIFIED: {
|
||||
string val = getStringValue();
|
||||
clear_value();
|
||||
clearValue();
|
||||
_type = STRING;
|
||||
_local_val.string_val = copy_string(val.c_str());
|
||||
break;
|
||||
@@ -1736,7 +1769,7 @@ SGPropertyNode::getNode (const char * relative_path, int index, bool create)
|
||||
vector<PathComponent> components;
|
||||
parse_path(relative_path, components);
|
||||
if (components.size() > 0)
|
||||
components[components.size()-1].index = index;
|
||||
components.back().index = index;
|
||||
return find_node(this, components, 0, create);
|
||||
}
|
||||
|
||||
@@ -2140,6 +2173,7 @@ SGPropertyNode::hash_table::bucket::~bucket ()
|
||||
{
|
||||
for (int i = 0; i < _length; i++)
|
||||
delete _entries[i];
|
||||
delete [] _entries;
|
||||
}
|
||||
|
||||
SGPropertyNode::hash_table::entry *
|
||||
@@ -2166,6 +2200,23 @@ SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SGPropertyNode::hash_table::bucket::erase (const char * key)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < _length; i++) {
|
||||
if (!strcmp(_entries[i]->get_key(), key))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < _length) {
|
||||
for (++i; i < _length; i++) {
|
||||
_entries[i-1] = _entries[i];
|
||||
}
|
||||
_length--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGPropertyNode::hash_table::hash_table ()
|
||||
: _data_length(0),
|
||||
@@ -2177,6 +2228,7 @@ SGPropertyNode::hash_table::~hash_table ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _data_length; i++)
|
||||
delete _data[i];
|
||||
delete [] _data;
|
||||
}
|
||||
|
||||
SGPropertyNode *
|
||||
@@ -2211,6 +2263,17 @@ SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
|
||||
e->set_value(value);
|
||||
}
|
||||
|
||||
void
|
||||
SGPropertyNode::hash_table::erase (const char * key)
|
||||
{
|
||||
if (_data_length == 0)
|
||||
return;
|
||||
unsigned int index = hashcode(key) % _data_length;
|
||||
if (_data[index] == 0)
|
||||
return;
|
||||
_data[index]->erase(key);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
SGPropertyNode::hash_table::hashcode (const char * key)
|
||||
{
|
||||
|
||||
+30
-16
@@ -706,12 +706,24 @@ public:
|
||||
vector<SGPropertyNode_ptr> getChildren (const char * name) const;
|
||||
|
||||
|
||||
/**
|
||||
* Remove child by position.
|
||||
*/
|
||||
SGPropertyNode_ptr removeChild (int pos, bool keep = true);
|
||||
|
||||
|
||||
/**
|
||||
* Remove a child node
|
||||
*/
|
||||
SGPropertyNode_ptr removeChild (const char * name, int index = 0,
|
||||
bool keep = true);
|
||||
|
||||
/**
|
||||
* Remove all children with the specified name.
|
||||
*/
|
||||
vector<SGPropertyNode_ptr> removeChildren (const char * name,
|
||||
bool keep = true);
|
||||
|
||||
|
||||
//
|
||||
// Alias support.
|
||||
@@ -1172,6 +1184,12 @@ public:
|
||||
void fireChildRemoved (SGPropertyNode * child);
|
||||
|
||||
|
||||
/**
|
||||
* Clear any existing value and set the type to NONE.
|
||||
*/
|
||||
void clearValue ();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void fireValueChanged (SGPropertyNode * node);
|
||||
@@ -1203,12 +1221,6 @@ private:
|
||||
bool set_string (const char * value);
|
||||
|
||||
|
||||
/**
|
||||
* Clear any existing value and set the type to NONE.
|
||||
*/
|
||||
void clear_value ();
|
||||
|
||||
|
||||
/**
|
||||
* Get the value as a string.
|
||||
*/
|
||||
@@ -1293,11 +1305,11 @@ private:
|
||||
class entry {
|
||||
public:
|
||||
entry ();
|
||||
virtual ~entry ();
|
||||
virtual const char * get_key () { return _key; }
|
||||
virtual void set_key (const char * key);
|
||||
virtual SGPropertyNode * get_value () { return _value; }
|
||||
virtual void set_value (SGPropertyNode * value);
|
||||
~entry ();
|
||||
const char * get_key () { return _key; }
|
||||
void set_key (const char * key);
|
||||
SGPropertyNode * get_value () { return _value; }
|
||||
void set_value (SGPropertyNode * value);
|
||||
private:
|
||||
char * _key;
|
||||
SGPropertyNode * _value;
|
||||
@@ -1310,8 +1322,9 @@ private:
|
||||
class bucket {
|
||||
public:
|
||||
bucket ();
|
||||
virtual ~bucket ();
|
||||
virtual entry * get_entry (const char * key, bool create = false);
|
||||
~bucket ();
|
||||
entry * get_entry (const char * key, bool create = false);
|
||||
void erase(const char * key);
|
||||
private:
|
||||
int _length;
|
||||
entry ** _entries;
|
||||
@@ -1320,9 +1333,10 @@ private:
|
||||
friend class bucket;
|
||||
|
||||
hash_table ();
|
||||
virtual ~hash_table ();
|
||||
virtual SGPropertyNode * get (const char * key);
|
||||
virtual void put (const char * key, SGPropertyNode * value);
|
||||
~hash_table ();
|
||||
SGPropertyNode * get (const char * key);
|
||||
void put (const char * key, SGPropertyNode * value);
|
||||
void erase(const char * key);
|
||||
|
||||
private:
|
||||
unsigned int hashcode (const char * key);
|
||||
|
||||
@@ -214,7 +214,10 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
||||
}
|
||||
}
|
||||
|
||||
push_state(node, atts.getValue("type"), mode);
|
||||
const char *type = atts.getValue("type");
|
||||
if (type)
|
||||
node->clearValue();
|
||||
push_state(node, type, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,6 +591,9 @@ copyProperties (const SGPropertyNode *in, SGPropertyNode *out)
|
||||
}
|
||||
}
|
||||
|
||||
// copy the attributes.
|
||||
out->setAttributes( in->getAttributes() );
|
||||
|
||||
// Next, copy the children.
|
||||
int nChildren = in->nChildren();
|
||||
for (int i = 0; i < nChildren; i++) {
|
||||
|
||||
@@ -153,10 +153,10 @@ public:
|
||||
inline void set_distance( double d ) { distance = d; }
|
||||
|
||||
/** @return waypoint id */
|
||||
inline string get_id() const { return id; }
|
||||
inline const string& get_id() const { return id; }
|
||||
|
||||
/** @return waypoint name */
|
||||
inline string get_name() const { return name; }
|
||||
inline const string& get_name() const { return name; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
SG_USING_STD(map);
|
||||
|
||||
@@ -48,10 +49,10 @@ SG_USING_STD(map);
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props )
|
||||
SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props, const char *season )
|
||||
{
|
||||
init();
|
||||
read_properties( fg_root, props );
|
||||
read_properties( fg_root, props, season );
|
||||
build_ssg_state( false );
|
||||
}
|
||||
|
||||
@@ -86,13 +87,20 @@ SGMaterial::~SGMaterial (void)
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props )
|
||||
SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props, const char *season )
|
||||
{
|
||||
// Gather the path(s) to the texture(s)
|
||||
vector<SGPropertyNode_ptr> textures = props->getChildren("texture");
|
||||
for (unsigned int i = 0; i < textures.size(); i++)
|
||||
{
|
||||
string tname = textures[i]->getStringValue();
|
||||
string otname = tname;
|
||||
if (season && strncmp(season, "summer", 6))
|
||||
{
|
||||
if (tname.substr(0,7) == "Terrain")
|
||||
tname.insert(7,"."+string(season));
|
||||
}
|
||||
|
||||
if (tname == "") {
|
||||
tname = "unknown.rgb";
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
* state information for the material. This node is usually
|
||||
* loaded from the $FG_ROOT/materials.xml file.
|
||||
*/
|
||||
SGMaterial( const string &fg_root, const SGPropertyNode *props );
|
||||
SGMaterial( const string &fg_root, const SGPropertyNode *props, const char *season );
|
||||
|
||||
|
||||
/**
|
||||
@@ -249,7 +249,7 @@ private:
|
||||
|
||||
SGMaterial( const string &fg_root, const SGMaterial &mat ); // unimplemented
|
||||
|
||||
void read_properties( const string &fg_root, const SGPropertyNode *props );
|
||||
void read_properties( const string &fg_root, const SGPropertyNode *props, const char *season );
|
||||
void build_ssg_state( bool defer_tex_load );
|
||||
void set_ssg_state( ssgSimpleState *s );
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ static int gen_taxiway_dir_light_map( int r, int g, int b, int alpha ) {
|
||||
|
||||
|
||||
// Load a library of material properties
|
||||
bool SGMaterialLib::load( const string &fg_root, const string& mpath ) {
|
||||
bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char *season ) {
|
||||
|
||||
SGPropertyNode materials;
|
||||
|
||||
@@ -192,7 +192,7 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath ) {
|
||||
for (int i = 0; i < nMaterials; i++) {
|
||||
const SGPropertyNode * node = materials.getChild(i);
|
||||
if (!strcmp(node->getName(), "material")) {
|
||||
SGMaterial *m = new SGMaterial( fg_root, node );
|
||||
SGMaterial *m = new SGMaterial( fg_root, node, season );
|
||||
|
||||
vector<SGPropertyNode_ptr>names = node->getChildren("name");
|
||||
for ( unsigned int j = 0; j < names.size(); j++ ) {
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
SGMaterialLib ( void );
|
||||
|
||||
// Load a library of material properties
|
||||
bool load( const string &fg_root, const string& mpath );
|
||||
bool load( const string &fg_root, const string& mpath, const char *season );
|
||||
|
||||
// Add the named texture with default properties
|
||||
bool add_item( const string &tex_path );
|
||||
|
||||
@@ -110,7 +110,7 @@ SGMatModel::~SGMatModel ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _models.size(); i++) {
|
||||
if (_models[i] != 0) {
|
||||
_models[i]->deRef();
|
||||
ssgDeRefDelete(_models[i]);
|
||||
_models[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ include_HEADERS = \
|
||||
model.hxx \
|
||||
modellib.hxx \
|
||||
personality.hxx \
|
||||
placement.hxx
|
||||
placement.hxx \
|
||||
placementtrans.hxx \
|
||||
shadowvolume.hxx
|
||||
|
||||
libsgmodel_a_SOURCES = \
|
||||
animation.cxx \
|
||||
@@ -20,6 +22,9 @@ libsgmodel_a_SOURCES = \
|
||||
model.cxx \
|
||||
modellib.cxx \
|
||||
personality.cxx \
|
||||
placement.cxx
|
||||
placement.cxx \
|
||||
placementtrans.cxx \
|
||||
shadowvolume.cxx \
|
||||
shadanim.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
@@ -179,7 +179,8 @@ double SGAnimation::sim_time_sec = 0.0;
|
||||
SGPersonalityBranch *SGAnimation::current_object = 0;
|
||||
|
||||
SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
|
||||
: _branch(branch)
|
||||
: _branch(branch),
|
||||
animation_type(0)
|
||||
{
|
||||
_branch->setName(props->getStringValue("name", 0));
|
||||
if ( props->getBoolValue( "enable-hot", true ) ) {
|
||||
@@ -293,7 +294,7 @@ SGRangeAnimation::update()
|
||||
ranges[1] = 1000000000.f;
|
||||
}
|
||||
((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -339,7 +340,7 @@ SGSelectAnimation::update()
|
||||
((ssgSelector *)_branch)->select(0xffff);
|
||||
else
|
||||
((ssgSelector *)_branch)->select(0x0000);
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -352,9 +353,8 @@ SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props,
|
||||
double sim_time_sec )
|
||||
: SGAnimation(props, new ssgTransform),
|
||||
_use_personality( props->getBoolValue("use-personality",false) ),
|
||||
_prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
|
||||
_factor(props->getDoubleValue("factor", 1.0)),
|
||||
_position_deg(props->getDoubleValue("starting-position-deg", 0)),
|
||||
_last_time_sec( sim_time_sec ),
|
||||
_condition(0)
|
||||
{
|
||||
@@ -391,6 +391,38 @@ SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
|
||||
_center[2] = props->getFloatValue("center/z-m", 0);
|
||||
}
|
||||
sgNormalizeVec3(_axis);
|
||||
|
||||
//_factor(props->getDoubleValue("factor", 1.0)),
|
||||
_factor = 1.0;
|
||||
_factor_min = 1.0;
|
||||
_factor_max = 1.0;
|
||||
SGPropertyNode_ptr factor_n = props->getNode( "factor" );
|
||||
if ( factor_n != 0 ) {
|
||||
SGPropertyNode_ptr rand_n = factor_n->getNode( "random" );
|
||||
if ( rand_n != 0 ) {
|
||||
_factor_min = rand_n->getDoubleValue( "min", 0.0 );
|
||||
_factor_max = rand_n->getDoubleValue( "max", 1.0 );
|
||||
_factor = _factor_min + sg_random() * ( _factor_max - _factor_min );
|
||||
} else {
|
||||
_factor = _factor_min = _factor_max = props->getDoubleValue("factor", 1.0);
|
||||
}
|
||||
}
|
||||
//_position_deg(props->getDoubleValue("starting-position-deg", 0)),
|
||||
_position_deg = 0.0;
|
||||
_position_deg_min = 0.0;
|
||||
_position_deg_max = 0.0;
|
||||
SGPropertyNode_ptr position_deg_n = props->getNode( "starting-position-deg" );
|
||||
if ( position_deg_n != 0 ) {
|
||||
SGPropertyNode_ptr rand_n = position_deg_n->getNode( "random" );
|
||||
if ( rand_n != 0 ) {
|
||||
_position_deg_min = rand_n->getDoubleValue( "min", 0.0 );
|
||||
_position_deg_max = rand_n->getDoubleValue( "max", 1.0 );
|
||||
_position_deg = _position_deg_min + sg_random() * ( _position_deg_max - _position_deg_min );
|
||||
} else {
|
||||
_position_deg = _position_deg_min = _position_deg_max =
|
||||
props->getDoubleValue("starting-position-deg", 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SGSpinAnimation::~SGSpinAnimation ()
|
||||
@@ -401,15 +433,47 @@ int
|
||||
SGSpinAnimation::update()
|
||||
{
|
||||
if ( _condition == 0 || _condition->test() ) {
|
||||
double dt = sim_time_sec - _last_time_sec;
|
||||
_last_time_sec = sim_time_sec;
|
||||
double dt;
|
||||
float velocity_rpms;
|
||||
if ( _use_personality ) {
|
||||
SGPersonalityBranch *key = current_object;
|
||||
if ( !key->getIntValue( this, INIT_SPIN ) ) {
|
||||
double v = _factor_min + sg_random() * ( _factor_max - _factor_min );
|
||||
key->setDoubleValue( v, this, FACTOR_SPIN );
|
||||
|
||||
key->setDoubleValue( sim_time_sec, this, LAST_TIME_SEC_SPIN );
|
||||
key->setIntValue( 1, this, INIT_SPIN );
|
||||
|
||||
v = _position_deg_min + sg_random() * ( _position_deg_max - _position_deg_min );
|
||||
key->setDoubleValue( v, this, POSITION_DEG_SPIN );
|
||||
}
|
||||
|
||||
_factor = key->getDoubleValue( this, FACTOR_SPIN );
|
||||
_position_deg = key->getDoubleValue( this, POSITION_DEG_SPIN );
|
||||
_last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_SPIN );
|
||||
dt = sim_time_sec - _last_time_sec;
|
||||
_last_time_sec = sim_time_sec;
|
||||
key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_SPIN );
|
||||
|
||||
velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
|
||||
_position_deg += (dt * velocity_rpms * 360);
|
||||
while (_position_deg < 0)
|
||||
_position_deg += 360.0;
|
||||
while (_position_deg >= 360.0)
|
||||
_position_deg -= 360.0;
|
||||
key->setDoubleValue( _position_deg, this, POSITION_DEG_SPIN );
|
||||
} else {
|
||||
dt = sim_time_sec - _last_time_sec;
|
||||
_last_time_sec = sim_time_sec;
|
||||
|
||||
velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
|
||||
_position_deg += (dt * velocity_rpms * 360);
|
||||
while (_position_deg < 0)
|
||||
_position_deg += 360.0;
|
||||
while (_position_deg >= 360.0)
|
||||
_position_deg -= 360.0;
|
||||
}
|
||||
|
||||
float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
|
||||
_position_deg += (dt * velocity_rpms * 360);
|
||||
while (_position_deg < 0)
|
||||
_position_deg += 360.0;
|
||||
while (_position_deg >= 360.0)
|
||||
_position_deg -= 360.0;
|
||||
set_rotation(_matrix, _position_deg, _center, _axis);
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
}
|
||||
@@ -480,13 +544,13 @@ SGTimedAnimation::update()
|
||||
{
|
||||
if ( _use_personality ) {
|
||||
SGPersonalityBranch *key = current_object;
|
||||
if ( !key->getIntValue( this, INIT ) ) {
|
||||
if ( !key->getIntValue( this, INIT_TIMED ) ) {
|
||||
double total = 0;
|
||||
double offset = 1.0;
|
||||
for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
|
||||
DurationSpec &sp = _branch_duration_specs[ i ];
|
||||
double v = sp._min + sg_random() * ( sp._max - sp._min );
|
||||
key->setDoubleValue( v, this, BRANCH_DURATION_SEC, i );
|
||||
key->setDoubleValue( v, this, BRANCH_DURATION_SEC_TIMED, i );
|
||||
if ( i == 0 )
|
||||
offset = v;
|
||||
total += v;
|
||||
@@ -496,21 +560,21 @@ SGTimedAnimation::update()
|
||||
total = 0.01;
|
||||
}
|
||||
offset *= sg_random();
|
||||
key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC );
|
||||
key->setDoubleValue( total, this, TOTAL_DURATION_SEC );
|
||||
key->setIntValue( 0, this, STEP );
|
||||
key->setIntValue( 1, this, INIT );
|
||||
key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC_TIMED );
|
||||
key->setDoubleValue( total, this, TOTAL_DURATION_SEC_TIMED );
|
||||
key->setIntValue( 0, this, STEP_TIMED );
|
||||
key->setIntValue( 1, this, INIT_TIMED );
|
||||
}
|
||||
|
||||
_step = key->getIntValue( this, STEP );
|
||||
_last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC );
|
||||
_total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC );
|
||||
_step = key->getIntValue( this, STEP_TIMED );
|
||||
_last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_TIMED );
|
||||
_total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC_TIMED );
|
||||
while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
|
||||
_last_time_sec += _total_duration_sec;
|
||||
}
|
||||
double duration = _duration_sec;
|
||||
if ( _step < (int)_branch_duration_specs.size() ) {
|
||||
duration = key->getDoubleValue( this, BRANCH_DURATION_SEC, _step );
|
||||
duration = key->getDoubleValue( this, BRANCH_DURATION_SEC_TIMED, _step );
|
||||
}
|
||||
if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
|
||||
_last_time_sec += duration;
|
||||
@@ -519,8 +583,8 @@ SGTimedAnimation::update()
|
||||
_step = 0;
|
||||
}
|
||||
((ssgSelector *)getBranch())->selectStep( _step );
|
||||
key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC );
|
||||
key->setIntValue( _step, this, STEP );
|
||||
key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_TIMED );
|
||||
key->setIntValue( _step, this, STEP_TIMED );
|
||||
} else {
|
||||
while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
|
||||
_last_time_sec += _total_duration_sec;
|
||||
@@ -567,14 +631,18 @@ SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
|
||||
_center[0] = 0;
|
||||
_center[1] = 0;
|
||||
_center[2] = 0;
|
||||
if (props->hasValue("axis/x1-m")) {
|
||||
if (props->hasValue("axis/x") || props->hasValue("axis/y") || props->hasValue("axis/z")) {
|
||||
_axis[0] = props->getFloatValue("axis/x", 0);
|
||||
_axis[1] = props->getFloatValue("axis/y", 0);
|
||||
_axis[2] = props->getFloatValue("axis/z", 0);
|
||||
} else {
|
||||
double x1,y1,z1,x2,y2,z2;
|
||||
x1 = props->getFloatValue("axis/x1-m");
|
||||
y1 = props->getFloatValue("axis/y1-m");
|
||||
z1 = props->getFloatValue("axis/z1-m");
|
||||
x2 = props->getFloatValue("axis/x2-m");
|
||||
y2 = props->getFloatValue("axis/y2-m");
|
||||
z2 = props->getFloatValue("axis/z2-m");
|
||||
x1 = props->getFloatValue("axis/x1-m", 0);
|
||||
y1 = props->getFloatValue("axis/y1-m", 0);
|
||||
z1 = props->getFloatValue("axis/z1-m", 0);
|
||||
x2 = props->getFloatValue("axis/x2-m", 0);
|
||||
y2 = props->getFloatValue("axis/y2-m", 0);
|
||||
z2 = props->getFloatValue("axis/z2-m", 0);
|
||||
_center[0] = (x1+x2)/2;
|
||||
_center[1]= (y1+y2)/2;
|
||||
_center[2] = (z1+z2)/2;
|
||||
@@ -582,15 +650,12 @@ SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
|
||||
_axis[0] = (x2-x1)/vector_length;
|
||||
_axis[1] = (y2-y1)/vector_length;
|
||||
_axis[2] = (z2-z1)/vector_length;
|
||||
} else {
|
||||
_axis[0] = props->getFloatValue("axis/x", 0);
|
||||
_axis[1] = props->getFloatValue("axis/y", 0);
|
||||
_axis[2] = props->getFloatValue("axis/z", 0);
|
||||
}
|
||||
if (props->hasValue("center/x-m")) {
|
||||
_center[0] = props->getFloatValue("center/x-m", 0);
|
||||
_center[1] = props->getFloatValue("center/y-m", 0);
|
||||
_center[2] = props->getFloatValue("center/z-m", 0);
|
||||
if (props->hasValue("center/x-m") || props->hasValue("center/y-m")
|
||||
|| props->hasValue("center/z-m")) {
|
||||
_center[0] = props->getFloatValue("center/x-m", 0);
|
||||
_center[1] = props->getFloatValue("center/y-m", 0);
|
||||
_center[2] = props->getFloatValue("center/z-m", 0);
|
||||
}
|
||||
sgNormalizeVec3(_axis);
|
||||
}
|
||||
@@ -616,7 +681,7 @@ SGRotateAnimation::update()
|
||||
set_rotation(_matrix, _position_deg, _center, _axis);
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
}
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -707,7 +772,7 @@ SGTranslateAnimation::update()
|
||||
{
|
||||
if (_condition == 0 || _condition->test()) {
|
||||
if (_table == 0) {
|
||||
_position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
|
||||
_position_m = (_prop->getDoubleValue() * _factor) + _offset_m;
|
||||
if (_has_min && _position_m < _min_m)
|
||||
_position_m = _min_m;
|
||||
if (_has_max && _position_m > _max_m)
|
||||
@@ -718,7 +783,7 @@ SGTranslateAnimation::update()
|
||||
set_translation(_matrix, _position_m, _axis);
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
}
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -793,7 +858,7 @@ SGScaleAnimation::update()
|
||||
|
||||
set_scale(_matrix, _x_scale, _y_scale, _z_scale );
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -842,7 +907,7 @@ SGTexRotateAnimation::update()
|
||||
}
|
||||
set_rotation(_matrix, _position_deg, _center, _axis);
|
||||
((ssgTexTrans *)_branch)->setTransform(_matrix);
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -890,7 +955,7 @@ SGTexTranslateAnimation::update()
|
||||
}
|
||||
set_translation(_matrix, _position, _axis);
|
||||
((ssgTexTrans *)_branch)->setTransform(_matrix);
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -1007,7 +1072,7 @@ SGTexMultipleAnimation::update()
|
||||
}
|
||||
}
|
||||
((ssgTexTrans *)_branch)->setTransform(tmatrix);
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -1047,6 +1112,266 @@ void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGMaterialAnimation
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SGMaterialAnimation::SGMaterialAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props, const SGPath &texture_path)
|
||||
: SGAnimation(props, new ssgBranch),
|
||||
_prop_root(prop_root),
|
||||
_prop_base(""),
|
||||
_texture_base(texture_path),
|
||||
_cached_material(0),
|
||||
_cloned_material(0),
|
||||
_read(0),
|
||||
_update(0),
|
||||
_global(props->getBoolValue("global", false))
|
||||
{
|
||||
SGPropertyNode_ptr n;
|
||||
n = props->getChild("condition");
|
||||
_condition = n ? sgReadCondition(_prop_root, n) : 0;
|
||||
n = props->getChild("property-base");
|
||||
if (n) {
|
||||
_prop_base = n->getStringValue();
|
||||
if (!_prop_base.empty() && _prop_base.end()[-1] != '/')
|
||||
_prop_base += '/';
|
||||
}
|
||||
|
||||
initColorGroup(props->getChild("diffuse"), &_diff, DIFFUSE);
|
||||
initColorGroup(props->getChild("ambient"), &_amb, AMBIENT);
|
||||
initColorGroup(props->getChild("emission"), &_emis, EMISSION);
|
||||
initColorGroup(props->getChild("specular"), &_spec, SPECULAR);
|
||||
|
||||
_shi = props->getFloatValue("shininess", -1.0);
|
||||
if (_shi >= 0.0)
|
||||
_update |= SHININESS;
|
||||
|
||||
SGPropertyNode_ptr group = props->getChild("transparency");
|
||||
if (group) {
|
||||
_trans.value = group->getFloatValue("alpha", -1.0);
|
||||
_trans.factor = group->getFloatValue("factor", 1.0);
|
||||
_trans.offset = group->getFloatValue("offset", 0.0);
|
||||
_trans.min = group->getFloatValue("min", 0.0);
|
||||
if (_trans.min < 0.0)
|
||||
_trans.min = 0.0;
|
||||
_trans.max = group->getFloatValue("max", 1.0);
|
||||
if (_trans.max > 1.0)
|
||||
_trans.max = 1.0;
|
||||
if (_trans.dirty())
|
||||
_update |= TRANSPARENCY;
|
||||
|
||||
n = group->getChild("alpha-prop");
|
||||
_trans.value_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
n = group->getChild("factor-prop");
|
||||
_trans.factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
n = group->getChild("offset-prop");
|
||||
_trans.offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
if (_trans.live())
|
||||
_read |= TRANSPARENCY;
|
||||
}
|
||||
|
||||
_thresh = props->getFloatValue("threshold", -1.0);
|
||||
if (_thresh >= 0.0)
|
||||
_update |= THRESHOLD;
|
||||
|
||||
string _texture_str = props->getStringValue("texture", "");
|
||||
if (!_texture_str.empty()) {
|
||||
_texture = _texture_base;
|
||||
_texture.append(_texture_str);
|
||||
_update |= TEXTURE;
|
||||
}
|
||||
|
||||
n = props->getChild("shininess-prop");
|
||||
_shi_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
n = props->getChild("threshold-prop");
|
||||
_thresh_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
n = props->getChild("texture-prop");
|
||||
_tex_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
}
|
||||
|
||||
void SGMaterialAnimation::initColorGroup(SGPropertyNode_ptr group, ColorSpec *col, int flag)
|
||||
{
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
col->red = group->getFloatValue("red", -1.0);
|
||||
col->green = group->getFloatValue("green", -1.0);
|
||||
col->blue = group->getFloatValue("blue", -1.0);
|
||||
col->factor = group->getFloatValue("factor", 1.0);
|
||||
col->offset = group->getFloatValue("offset", 0.0);
|
||||
if (col->dirty())
|
||||
_update |= flag;
|
||||
|
||||
SGPropertyNode *n;
|
||||
n = group->getChild("red-prop");
|
||||
col->red_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
n = group->getChild("green-prop");
|
||||
col->green_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
n = group->getChild("blue-prop");
|
||||
col->blue_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
n = group->getChild("factor-prop");
|
||||
col->factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
n = group->getChild("offset-prop");
|
||||
col->offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
|
||||
if (col->live())
|
||||
_read |= flag;
|
||||
}
|
||||
|
||||
void SGMaterialAnimation::init()
|
||||
{
|
||||
if (!_global)
|
||||
cloneMaterials(_branch);
|
||||
}
|
||||
|
||||
int SGMaterialAnimation::update()
|
||||
{
|
||||
if (_condition && !_condition->test())
|
||||
return 2;
|
||||
|
||||
if (_read & DIFFUSE)
|
||||
updateColorGroup(&_diff, DIFFUSE);
|
||||
if (_read & AMBIENT)
|
||||
updateColorGroup(&_amb, AMBIENT);
|
||||
if (_read & EMISSION)
|
||||
updateColorGroup(&_emis, EMISSION);
|
||||
if (_read & SPECULAR)
|
||||
updateColorGroup(&_spec, SPECULAR);
|
||||
|
||||
float f;
|
||||
if (_shi_prop) {
|
||||
f = _shi;
|
||||
_shi = _shi_prop->getFloatValue();
|
||||
if (_shi != f)
|
||||
_update |= SHININESS;
|
||||
}
|
||||
if (_read & TRANSPARENCY) {
|
||||
PropSpec tmp = _trans;
|
||||
if (_trans.value_prop)
|
||||
_trans.value = _trans.value_prop->getFloatValue();
|
||||
if (_trans.factor_prop)
|
||||
_trans.factor = _trans.factor_prop->getFloatValue();
|
||||
if (_trans.offset_prop)
|
||||
_trans.offset = _trans.offset_prop->getFloatValue();
|
||||
if (_trans != tmp)
|
||||
_update |= TRANSPARENCY;
|
||||
}
|
||||
if (_thresh_prop) {
|
||||
f = _thresh;
|
||||
_thresh = _thresh_prop->getFloatValue();
|
||||
if (_thresh != f)
|
||||
_update |= THRESHOLD;
|
||||
}
|
||||
if (_tex_prop) {
|
||||
string t = _tex_prop->getStringValue();
|
||||
if (!t.empty() && t != _texture_str) {
|
||||
_texture_str = t;
|
||||
_texture = _texture_base;
|
||||
_texture.append(t);
|
||||
_update |= TEXTURE;
|
||||
}
|
||||
}
|
||||
if (_update) {
|
||||
setMaterialBranch(_branch);
|
||||
_update = 0;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
void SGMaterialAnimation::updateColorGroup(ColorSpec *col, int flag)
|
||||
{
|
||||
ColorSpec tmp = *col;
|
||||
if (col->red_prop)
|
||||
col->red = col->red_prop->getFloatValue();
|
||||
if (col->green_prop)
|
||||
col->green = col->green_prop->getFloatValue();
|
||||
if (col->blue_prop)
|
||||
col->blue = col->blue_prop->getFloatValue();
|
||||
if (col->factor_prop)
|
||||
col->factor = col->factor_prop->getFloatValue();
|
||||
if (col->offset_prop)
|
||||
col->offset = col->offset_prop->getFloatValue();
|
||||
if (*col != tmp)
|
||||
_update |= flag;
|
||||
}
|
||||
|
||||
void SGMaterialAnimation::cloneMaterials(ssgBranch *b)
|
||||
{
|
||||
for (int i = 0; i < b->getNumKids(); i++)
|
||||
cloneMaterials((ssgBranch *)b->getKid(i));
|
||||
|
||||
if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
|
||||
return;
|
||||
|
||||
ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
|
||||
if (!_cached_material || _cached_material != s) {
|
||||
_cached_material = s;
|
||||
_cloned_material = (ssgSimpleState *)s->clone(SSG_CLONE_STATE);
|
||||
}
|
||||
((ssgLeaf *)b)->setState(_cloned_material);
|
||||
}
|
||||
|
||||
void SGMaterialAnimation::setMaterialBranch(ssgBranch *b)
|
||||
{
|
||||
for (int i = 0; i < b->getNumKids(); i++)
|
||||
setMaterialBranch((ssgBranch *)b->getKid(i));
|
||||
|
||||
if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
|
||||
return;
|
||||
|
||||
ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
|
||||
|
||||
if (_update & DIFFUSE) {
|
||||
float *v = _diff.rgba();
|
||||
SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
|
||||
s->setColourMaterial(GL_DIFFUSE);
|
||||
s->enable(GL_COLOR_MATERIAL);
|
||||
s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], alpha);
|
||||
s->disable(GL_COLOR_MATERIAL);
|
||||
}
|
||||
if (_update & AMBIENT) {
|
||||
s->setColourMaterial(GL_AMBIENT);
|
||||
s->enable(GL_COLOR_MATERIAL);
|
||||
s->setMaterial(GL_AMBIENT, _amb.rgba());
|
||||
s->disable(GL_COLOR_MATERIAL);
|
||||
}
|
||||
if (_update & EMISSION)
|
||||
s->setMaterial(GL_EMISSION, _emis.rgba());
|
||||
if (_update & SPECULAR)
|
||||
s->setMaterial(GL_SPECULAR, _spec.rgba());
|
||||
if (_update & SHININESS)
|
||||
s->setShininess(clamp(_shi, 0.0, 128.0));
|
||||
if (_update & TRANSPARENCY) {
|
||||
SGfloat *v = s->getMaterial(GL_DIFFUSE);
|
||||
float trans = _trans.value * _trans.factor + _trans.offset;
|
||||
trans = trans < _trans.min ? _trans.min : trans > _trans.max ? _trans.max : trans;
|
||||
s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], trans);
|
||||
}
|
||||
if (_update & THRESHOLD)
|
||||
s->setAlphaClamp(clamp(_thresh));
|
||||
if (_update & TEXTURE)
|
||||
s->setTexture(_texture.c_str());
|
||||
if (_update & (TEXTURE|TRANSPARENCY)) {
|
||||
SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
|
||||
ssgTexture *tex = s->getTexture();
|
||||
if ((tex && tex->hasAlpha()) || alpha < 0.999) {
|
||||
s->setColourMaterial(GL_DIFFUSE);
|
||||
s->enable(GL_COLOR_MATERIAL);
|
||||
s->enable(GL_BLEND);
|
||||
s->enable(GL_ALPHA_TEST);
|
||||
s->setTranslucent();
|
||||
s->disable(GL_COLOR_MATERIAL);
|
||||
} else {
|
||||
s->disable(GL_BLEND);
|
||||
s->disable(GL_ALPHA_TEST);
|
||||
s->setOpaque();
|
||||
}
|
||||
}
|
||||
s->force();
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGFlashAnimation
|
||||
@@ -1177,4 +1502,39 @@ void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
|
||||
sgPreMultMat4( r, transform );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGShadowAnimation
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SGShadowAnimation::SGShadowAnimation ( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props )
|
||||
: SGAnimation(props, new ssgBranch),
|
||||
_condition(0),
|
||||
_condition_value(true)
|
||||
{
|
||||
animation_type = 1;
|
||||
SGPropertyNode_ptr node = props->getChild("condition");
|
||||
if (node != 0) {
|
||||
_condition = sgReadCondition(prop_root, node);
|
||||
_condition_value = false;
|
||||
}
|
||||
}
|
||||
|
||||
SGShadowAnimation::~SGShadowAnimation ()
|
||||
{
|
||||
delete _condition;
|
||||
}
|
||||
|
||||
int
|
||||
SGShadowAnimation::update()
|
||||
{
|
||||
if (_condition)
|
||||
_condition_value = _condition->test();
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool SGShadowAnimation::get_condition_value(void) {
|
||||
return _condition_value;
|
||||
}
|
||||
|
||||
// end of animation.cxx
|
||||
|
||||
@@ -22,6 +22,7 @@ SG_USING_STD(map);
|
||||
|
||||
#include <simgear/math/point3d.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
|
||||
// Don't pull in the headers, since we don't need them here.
|
||||
@@ -50,6 +51,10 @@ class SGPersonalityBranch;
|
||||
class SGAnimation : public ssgBase
|
||||
{
|
||||
public:
|
||||
enum PersonalityVar { INIT_SPIN, LAST_TIME_SEC_SPIN, FACTOR_SPIN,
|
||||
POSITION_DEG_SPIN, INIT_TIMED, LAST_TIME_SEC_TIMED,
|
||||
TOTAL_DURATION_SEC_TIMED, BRANCH_DURATION_SEC_TIMED,
|
||||
STEP_TIMED };
|
||||
|
||||
SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch);
|
||||
|
||||
@@ -87,12 +92,15 @@ public:
|
||||
*/
|
||||
static SGPersonalityBranch *current_object;
|
||||
|
||||
int get_animation_type(void) { return animation_type; }
|
||||
|
||||
protected:
|
||||
|
||||
static double sim_time_sec;
|
||||
|
||||
ssgBranch * _branch;
|
||||
|
||||
int animation_type;
|
||||
};
|
||||
|
||||
|
||||
@@ -168,9 +176,14 @@ public:
|
||||
virtual ~SGSpinAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
bool _use_personality;
|
||||
SGPropertyNode_ptr _prop;
|
||||
double _factor;
|
||||
double _factor_min;
|
||||
double _factor_max;
|
||||
double _position_deg;
|
||||
double _position_deg_min;
|
||||
double _position_deg_max;
|
||||
double _last_time_sec;
|
||||
sgMat4 _matrix;
|
||||
sgVec3 _center;
|
||||
@@ -191,7 +204,6 @@ public:
|
||||
virtual int update();
|
||||
private:
|
||||
bool _use_personality;
|
||||
enum PersonalityVar { INIT, LAST_TIME_SEC, TOTAL_DURATION_SEC, BRANCH_DURATION_SEC, STEP };
|
||||
double _duration_sec;
|
||||
double _last_time_sec;
|
||||
double _total_duration_sec;
|
||||
@@ -425,6 +437,112 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An "animation" to modify material properties
|
||||
*/
|
||||
class SGMaterialAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGMaterialAnimation(SGPropertyNode *prop_root, SGPropertyNode_ptr props,
|
||||
const SGPath &texpath);
|
||||
virtual ~SGMaterialAnimation() {}
|
||||
virtual void init();
|
||||
virtual int update();
|
||||
private:
|
||||
enum {
|
||||
DIFFUSE = 1,
|
||||
AMBIENT = 2,
|
||||
SPECULAR = 4,
|
||||
EMISSION = 8,
|
||||
SHININESS = 16,
|
||||
TRANSPARENCY = 32,
|
||||
THRESHOLD = 64,
|
||||
TEXTURE = 128,
|
||||
};
|
||||
struct ColorSpec {
|
||||
float red, green, blue;
|
||||
float factor;
|
||||
float offset;
|
||||
SGPropertyNode_ptr red_prop;
|
||||
SGPropertyNode_ptr green_prop;
|
||||
SGPropertyNode_ptr blue_prop;
|
||||
SGPropertyNode_ptr factor_prop;
|
||||
SGPropertyNode_ptr offset_prop;
|
||||
sgVec4 v;
|
||||
inline bool dirty() {
|
||||
return red >= 0.0 || green >= 0.0 || blue >= 0.0;
|
||||
}
|
||||
inline bool live() {
|
||||
return red_prop || green_prop || blue_prop
|
||||
|| factor_prop || offset_prop;
|
||||
}
|
||||
inline bool operator!=(ColorSpec& a) {
|
||||
return red != a.red || green != a.green || blue != a.blue
|
||||
|| factor != a.factor || offset != a.offset;
|
||||
}
|
||||
sgVec4 &rgba() {
|
||||
v[0] = clamp(red * factor + offset);
|
||||
v[1] = clamp(green * factor + offset);
|
||||
v[2] = clamp(blue * factor + offset);
|
||||
v[3] = 1.0;
|
||||
return v;
|
||||
}
|
||||
inline float clamp(float val) {
|
||||
return val < 0.0 ? 0.0 : val > 1.0 ? 1.0 : val;
|
||||
}
|
||||
};
|
||||
struct PropSpec {
|
||||
float value;
|
||||
float factor;
|
||||
float offset;
|
||||
float min;
|
||||
float max;
|
||||
SGPropertyNode_ptr value_prop;
|
||||
SGPropertyNode_ptr factor_prop;
|
||||
SGPropertyNode_ptr offset_prop;
|
||||
inline bool dirty() { return value >= 0.0; }
|
||||
inline bool live() { return value_prop || factor_prop || offset_prop; }
|
||||
inline bool operator!=(PropSpec& a) {
|
||||
return value != a.value || factor != a.factor || offset != a.offset;
|
||||
}
|
||||
};
|
||||
SGCondition *_condition;
|
||||
SGPropertyNode *_prop_root;
|
||||
string _prop_base;
|
||||
SGPath _texture_base;
|
||||
SGPath _texture;
|
||||
string _texture_str;
|
||||
ssgSimpleState* _cached_material;
|
||||
ssgSimpleState* _cloned_material;
|
||||
unsigned _read;
|
||||
unsigned _update;
|
||||
bool _global;
|
||||
ColorSpec _diff;
|
||||
ColorSpec _amb;
|
||||
ColorSpec _emis;
|
||||
ColorSpec _spec;
|
||||
float _shi;
|
||||
PropSpec _trans;
|
||||
float _thresh; // alpha_clamp (see man glAlphaFunc)
|
||||
string _tex;
|
||||
string _tmpstr;
|
||||
SGPropertyNode_ptr _shi_prop;
|
||||
SGPropertyNode_ptr _thresh_prop;
|
||||
SGPropertyNode_ptr _tex_prop;
|
||||
|
||||
void cloneMaterials(ssgBranch *b);
|
||||
void setMaterialBranch(ssgBranch *b);
|
||||
void initColorGroup(SGPropertyNode_ptr, ColorSpec *, int flag);
|
||||
void updateColorGroup(ColorSpec *, int flag);
|
||||
inline float clamp(float val, float min = 0.0, float max = 1.0) {
|
||||
return val < min ? min : val > max ? max : val;
|
||||
}
|
||||
const char *path(const char *rel) {
|
||||
return (_tmpstr = _prop_base + rel).c_str();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An "animation" that compute a scale according to
|
||||
* the angle between an axis and the view direction
|
||||
@@ -465,5 +583,51 @@ private:
|
||||
SGInterpTable * _table;
|
||||
};
|
||||
|
||||
/**
|
||||
* An animation to tell wich objects don't cast shadows.
|
||||
*/
|
||||
class SGShadowAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGShadowAnimation ( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGShadowAnimation ();
|
||||
virtual int update();
|
||||
bool get_condition_value(void);
|
||||
private:
|
||||
SGCondition * _condition;
|
||||
bool _condition_value;
|
||||
};
|
||||
|
||||
/**
|
||||
+ * An "animation" that replace fixed opengl pipeline by shaders
|
||||
+ */
|
||||
class SGShaderAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGShaderAnimation ( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGShaderAnimation ();
|
||||
virtual void init();
|
||||
virtual int update();
|
||||
bool get_condition_value(void);
|
||||
private:
|
||||
SGCondition * _condition;
|
||||
bool _condition_value;
|
||||
int _shader_type;
|
||||
float _param_1;
|
||||
sgVec4 _param_color;
|
||||
public:
|
||||
bool _depth_test;
|
||||
float _factor;
|
||||
SGPropertyNode_ptr _factor_prop;
|
||||
float _speed;
|
||||
SGPropertyNode_ptr _speed_prop;
|
||||
ssgTexture *_effectTexture;
|
||||
unsigned char *_textureData;
|
||||
GLint _texWidth, _texHeight;
|
||||
sgVec4 _envColor;
|
||||
};
|
||||
|
||||
|
||||
#endif // _SG_ANIMATION_HXX
|
||||
|
||||
@@ -93,7 +93,6 @@ static void MakeTRANS( sgMat4 dst, const double Theta,
|
||||
dst[1][3] = SG_ZERO ;
|
||||
dst[0][3] = SG_ZERO ;
|
||||
dst[3][3] = SG_ONE ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -103,19 +102,16 @@ static void MakeTRANS( sgMat4 dst, const double Theta,
|
||||
|
||||
// Constructor
|
||||
SGLocation::SGLocation( void ):
|
||||
_dirty(true),
|
||||
_position_dirty(true), _orientation_dirty(true),
|
||||
_lon_deg(-1000),
|
||||
_lat_deg(0),
|
||||
_alt_ft(0),
|
||||
_roll_deg(0),
|
||||
_pitch_deg(0),
|
||||
_heading_deg(0),
|
||||
_cur_elev_m(0),
|
||||
_tile_center(0)
|
||||
_cur_elev_m(0)
|
||||
{
|
||||
sgdZeroVec3(_absolute_view_pos);
|
||||
sgZeroVec3(_relative_view_pos);
|
||||
sgZeroVec3(_zero_elev_view_pos);
|
||||
sgMakeRotMat4( UP, 0.0, 0.0, 0.0 );
|
||||
sgMakeRotMat4( TRANS, 0.0, 0.0, 0.0 );
|
||||
}
|
||||
@@ -125,25 +121,10 @@ SGLocation::SGLocation( void ):
|
||||
SGLocation::~SGLocation( void ) {
|
||||
}
|
||||
|
||||
void
|
||||
SGLocation::init ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SGLocation::bind ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SGLocation::unbind ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SGLocation::setPosition (double lon_deg, double lat_deg, double alt_ft)
|
||||
{
|
||||
_dirty = true;
|
||||
_position_dirty = true;
|
||||
_lon_deg = lon_deg;
|
||||
_lat_deg = lat_deg;
|
||||
_alt_ft = alt_ft;
|
||||
@@ -152,105 +133,83 @@ SGLocation::setPosition (double lon_deg, double lat_deg, double alt_ft)
|
||||
void
|
||||
SGLocation::setOrientation (double roll_deg, double pitch_deg, double heading_deg)
|
||||
{
|
||||
_dirty = true;
|
||||
_orientation_dirty = true;
|
||||
_roll_deg = roll_deg;
|
||||
_pitch_deg = pitch_deg;
|
||||
_heading_deg = heading_deg;
|
||||
}
|
||||
|
||||
double *
|
||||
SGLocation::get_absolute_view_pos( const Point3D scenery_center )
|
||||
SGLocation::get_absolute_view_pos()
|
||||
{
|
||||
if ( _dirty ) {
|
||||
recalc( scenery_center );
|
||||
}
|
||||
recalcAbsolutePosition();
|
||||
return _absolute_view_pos;
|
||||
}
|
||||
|
||||
float *
|
||||
SGLocation::getRelativeViewPos( const Point3D scenery_center )
|
||||
SGLocation::get_view_pos( const Point3D& scenery_center )
|
||||
{
|
||||
if ( _dirty ) {
|
||||
recalc( scenery_center );
|
||||
}
|
||||
recalcAbsolutePosition();
|
||||
for (int i = 0; i < 3; i++)
|
||||
_relative_view_pos[i] = _absolute_view_pos[i] - scenery_center[i];
|
||||
return _relative_view_pos;
|
||||
}
|
||||
|
||||
float *
|
||||
SGLocation::getZeroElevViewPos( const Point3D scenery_center )
|
||||
{
|
||||
if ( _dirty ) {
|
||||
recalc( scenery_center );
|
||||
}
|
||||
return _zero_elev_view_pos;
|
||||
}
|
||||
|
||||
|
||||
// recalc() is done every time one of the setters is called (making the
|
||||
// cached data "dirty") on the next "get". It calculates all the outputs
|
||||
// for viewer.
|
||||
void
|
||||
SGLocation::recalc( const Point3D scenery_center )
|
||||
SGLocation::recalcOrientation() const
|
||||
{
|
||||
if (_orientation_dirty) {
|
||||
// Make sure UP matrix is up-to-date.
|
||||
recalcAbsolutePosition();
|
||||
|
||||
recalcPosition( _lon_deg, _lat_deg, _alt_ft, scenery_center );
|
||||
|
||||
// Make the world up rotation matrix for eye positioin...
|
||||
sgMakeRotMat4( UP, _lon_deg, 0.0, -_lat_deg );
|
||||
|
||||
|
||||
// get the world up radial vector from planet center for output
|
||||
sgSetVec3( _world_up, UP[0][0], UP[0][1], UP[0][2] );
|
||||
|
||||
// Creat local matrix with current geodetic position. Converting
|
||||
// the orientation (pitch/roll/heading) to vectors.
|
||||
MakeTRANS( TRANS, _pitch_deg * SG_DEGREES_TO_RADIANS,
|
||||
// Create local matrix with current geodetic position. Converting
|
||||
// the orientation (pitch/roll/heading) to vectors.
|
||||
MakeTRANS( TRANS, _pitch_deg * SG_DEGREES_TO_RADIANS,
|
||||
_roll_deg * SG_DEGREES_TO_RADIANS,
|
||||
-_heading_deg * SG_DEGREES_TO_RADIANS,
|
||||
UP);
|
||||
|
||||
// Given a vector pointing straight down (-Z), map into onto the
|
||||
// local plane representing "horizontal". This should give us the
|
||||
// local direction for moving "south".
|
||||
sgVec3 minus_z;
|
||||
sgSetVec3( minus_z, 0.0, 0.0, -1.0 );
|
||||
|
||||
sgmap_vec_onto_cur_surface_plane(_world_up, _relative_view_pos, minus_z,
|
||||
_surface_south);
|
||||
sgNormalizeVec3(_surface_south);
|
||||
|
||||
// now calculate the surface east vector
|
||||
sgVec3 world_down;
|
||||
sgNegateVec3(world_down, _world_up);
|
||||
sgVectorProductVec3(_surface_east, _surface_south, world_down);
|
||||
|
||||
set_clean();
|
||||
-_heading_deg * SG_DEGREES_TO_RADIANS,
|
||||
UP );
|
||||
_orientation_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update values derived from the longitude, latitude and altitude parameters
|
||||
* of this instance. This encompasses absolute position in cartesian
|
||||
* coordinates, the local up, east and south vectors and the UP Matrix.
|
||||
*/
|
||||
void
|
||||
SGLocation::recalcPosition( double lon_deg, double lat_deg, double alt_ft,
|
||||
const Point3D scenery_center ) const
|
||||
SGLocation::recalcAbsolutePosition() const
|
||||
{
|
||||
double lat = lat_deg * SGD_DEGREES_TO_RADIANS;
|
||||
double lon = lon_deg * SGD_DEGREES_TO_RADIANS;
|
||||
double alt = alt_ft * SG_FEET_TO_METER;
|
||||
if (_position_dirty) {
|
||||
double lat = _lat_deg * SGD_DEGREES_TO_RADIANS;
|
||||
double lon = _lon_deg * SGD_DEGREES_TO_RADIANS;
|
||||
double alt = _alt_ft * SG_FEET_TO_METER;
|
||||
|
||||
sgGeodToCart(lat, lon, alt, _absolute_view_pos);
|
||||
sgGeodToCart(lat, lon, alt, _absolute_view_pos);
|
||||
|
||||
// Make the world up rotation matrix for eye positioin...
|
||||
sgMakeRotMat4( UP, _lon_deg, 0.0, -_lat_deg );
|
||||
|
||||
int i;
|
||||
double ground[3];
|
||||
sgGeodToCart(lat, lon, 0, ground);
|
||||
for(i=0; i<3; i++)
|
||||
_zero_elev_view_pos[i] = ground[i] - _tile_center[i];
|
||||
// get the world up radial vector from planet center for output
|
||||
sgSetVec3( _world_up, UP[0][0], UP[0][1], UP[0][2] );
|
||||
|
||||
// FIXME: view position should ONLY be calculated in the viewer...
|
||||
// Anything else should calculate their own positions relative to the
|
||||
// viewer's tile_center.
|
||||
for(i=0; i<3; i++)
|
||||
_relative_view_pos[i] = _absolute_view_pos[i] - scenery_center[i];
|
||||
}
|
||||
// Calculate the surface east and south vectors using the (normalized)
|
||||
// partial derivatives of the up vector Could also be fetched and
|
||||
// normalized from the UP rotation matrix, but I doubt this would
|
||||
// be more efficient.
|
||||
float sin_lon = sin(_lon_deg * SGD_DEGREES_TO_RADIANS);
|
||||
float sin_lat = sin(_lat_deg * SGD_DEGREES_TO_RADIANS);
|
||||
float cos_lon = cos(_lon_deg * SGD_DEGREES_TO_RADIANS);
|
||||
float cos_lat = cos(_lat_deg * SGD_DEGREES_TO_RADIANS);
|
||||
|
||||
_surface_south[0] = (sin_lat*cos_lon);
|
||||
_surface_south[1] = (sin_lat*sin_lon);
|
||||
_surface_south[2] = - cos_lat;
|
||||
|
||||
_surface_east[0] = -sin_lon;
|
||||
_surface_east[1] = cos_lon;
|
||||
_surface_east[2] = 0.f;
|
||||
|
||||
void
|
||||
SGLocation::update (int dt)
|
||||
{
|
||||
_position_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,23 +41,12 @@ class SGLocation
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
SGLocation( void );
|
||||
|
||||
// Destructor
|
||||
virtual ~SGLocation( void );
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Part 1: standard FGSubsystem implementation.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void init ();
|
||||
virtual void bind ();
|
||||
virtual void unbind ();
|
||||
void update (int dt);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Part 2: user settings.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@@ -88,47 +77,42 @@ public:
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Vectors and positions...
|
||||
|
||||
// Get zero view_pos
|
||||
virtual float * get_view_pos() { return _relative_view_pos; }
|
||||
// Get the absolute view position in fgfs coordinates.
|
||||
virtual double * get_absolute_view_pos( const Point3D scenery_center );
|
||||
// Get zero elev
|
||||
virtual float * get_zero_elev() { return _zero_elev_view_pos; }
|
||||
|
||||
//! Get the absolute view position in fgfs coordinates.
|
||||
virtual double * get_absolute_view_pos( );
|
||||
|
||||
//! Return the position relative to the given scenery center.
|
||||
virtual float * get_view_pos( const Point3D& scenery_center );
|
||||
|
||||
// Get world up vector
|
||||
virtual float *get_world_up() { return _world_up; }
|
||||
// Get the relative (to scenery center) view position in fgfs coordinates.
|
||||
virtual float * getRelativeViewPos( const Point3D scenery_center );
|
||||
// Get the absolute zero-elevation view position in fgfs coordinates.
|
||||
virtual float * getZeroElevViewPos( const Point3D scenery_center );
|
||||
virtual float *get_world_up()
|
||||
{ recalcAbsolutePosition(); return _world_up; }
|
||||
|
||||
// Get surface east vector
|
||||
virtual float *get_surface_east() { return _surface_east; }
|
||||
virtual float *get_surface_east()
|
||||
{ recalcAbsolutePosition(); return _surface_east; }
|
||||
|
||||
// Get surface south vector
|
||||
virtual float *get_surface_south() { return _surface_south; }
|
||||
virtual float *get_surface_south()
|
||||
{ recalcAbsolutePosition(); return _surface_south; }
|
||||
|
||||
// Elevation of ground under location (based on scenery output)...
|
||||
void set_cur_elev_m ( double elev ) { _cur_elev_m = elev; }
|
||||
inline double get_cur_elev_m () { return _cur_elev_m; }
|
||||
// Interface to current buckets for use with tilemgr...
|
||||
void set_tile_center ( Point3D tile_center ) { _tile_center = tile_center; }
|
||||
inline Point3D get_tile_center () { return _tile_center; }
|
||||
|
||||
void set_cur_elev_m ( double elev ) { _cur_elev_m = elev; }
|
||||
inline double get_cur_elev_m () { return _cur_elev_m; }
|
||||
|
||||
// Matrices...
|
||||
virtual const sgVec4 *getTransformMatrix( const Point3D scenery_center ) {
|
||||
if ( _dirty ) {
|
||||
recalc( scenery_center );
|
||||
}
|
||||
return TRANS;
|
||||
virtual const sgVec4 *getTransformMatrix() {
|
||||
recalcOrientation();
|
||||
return TRANS;
|
||||
}
|
||||
virtual const sgVec4 *getCachedTransformMatrix() { return TRANS; }
|
||||
virtual const sgVec4 *getUpMatrix( const Point3D scenery_center ) {
|
||||
if ( _dirty ) {
|
||||
recalc( scenery_center );
|
||||
}
|
||||
return UP;
|
||||
|
||||
virtual const sgVec4 *getUpMatrix(const Point3D& scenery_center) {
|
||||
recalcAbsolutePosition();
|
||||
return UP;
|
||||
}
|
||||
virtual const sgVec4 *getCachedUpMatrix() { return UP; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
@@ -136,11 +120,10 @@ private:
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// flag forcing a recalc of derived view parameters
|
||||
bool _dirty;
|
||||
mutable bool _orientation_dirty, _position_dirty;
|
||||
|
||||
mutable sgdVec3 _absolute_view_pos;
|
||||
mutable sgVec3 _relative_view_pos;
|
||||
mutable sgVec3 _zero_elev_view_pos;
|
||||
|
||||
double _lon_deg;
|
||||
double _lat_deg;
|
||||
@@ -152,33 +135,27 @@ private:
|
||||
|
||||
// elevation of ground under this location...
|
||||
double _cur_elev_m;
|
||||
Point3D _tile_center;
|
||||
|
||||
// surface vector heading south
|
||||
sgVec3 _surface_south;
|
||||
mutable sgVec3 _surface_south;
|
||||
|
||||
// surface vector heading east (used to unambiguously align sky
|
||||
// with sun)
|
||||
sgVec3 _surface_east;
|
||||
mutable sgVec3 _surface_east;
|
||||
|
||||
// world up vector (normal to the plane tangent to the earth's
|
||||
// surface at the spot we are directly above
|
||||
sgVec3 _world_up;
|
||||
// surface at the spot we are directly above)
|
||||
mutable sgVec3 _world_up;
|
||||
|
||||
// sg versions of our friendly matrices
|
||||
sgMat4 TRANS, UP;
|
||||
mutable sgMat4 TRANS, UP;
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// private functions //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
void recalc( const Point3D scenery_center );
|
||||
void recalcPosition( double lon_deg, double lat_deg, double alt_ft,
|
||||
const Point3D scenery_center ) const;
|
||||
|
||||
inline void set_dirty() { _dirty = true; }
|
||||
inline void set_clean() { _dirty = false; }
|
||||
|
||||
void recalcOrientation() const;
|
||||
void recalcAbsolutePosition() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <plib/ul.h>
|
||||
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
|
||||
@@ -125,6 +124,7 @@ sgMakeAnimation( ssgBranch * model,
|
||||
SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr node,
|
||||
double sim_time_sec,
|
||||
SGPath &texture_path,
|
||||
set<ssgBranch *> &ignore_branches )
|
||||
{
|
||||
bool ignore = false;
|
||||
@@ -159,10 +159,16 @@ sgMakeAnimation( ssgBranch * model,
|
||||
ignore = true;
|
||||
} else if (!strcmp("alpha-test", type)) {
|
||||
animation = new SGAlphaTestAnimation(node);
|
||||
} else if (!strcmp("material", type)) {
|
||||
animation = new SGMaterialAnimation(prop_root, node, texture_path);
|
||||
} else if (!strcmp("flash", type)) {
|
||||
animation = new SGFlashAnimation(node);
|
||||
} else if (!strcmp("dist-scale", type)) {
|
||||
animation = new SGDistScaleAnimation(node);
|
||||
} else if (!strcmp("noshadow", type)) {
|
||||
animation = new SGShadowAnimation(prop_root, node);
|
||||
} else if (!strcmp("shader", type)) {
|
||||
animation = new SGShaderAnimation(prop_root, node);
|
||||
} else {
|
||||
animation = new SGNullAnimation(node);
|
||||
SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type);
|
||||
@@ -222,6 +228,7 @@ static void makeDList( ssgBranch *b, const set<ssgBranch *> &ignore )
|
||||
for (int i = 0; i<nb; i++) {
|
||||
ssgEntity *e = b->getKid(i);
|
||||
if (e->isAKindOf(ssgTypeLeaf())) {
|
||||
if( ((ssgLeaf*)e)->getNumVertices() > 0)
|
||||
((ssgLeaf*)e)->makeDList();
|
||||
} else if (e->isAKindOf(ssgTypeBranch()) && ignore.find((ssgBranch *)e) == ignore.end()) {
|
||||
makeDList( (ssgBranch*)e, ignore );
|
||||
@@ -317,23 +324,6 @@ sgLoad3DModel( const string &fg_root, const string &path,
|
||||
model->addKid(align);
|
||||
}
|
||||
|
||||
// Load animations
|
||||
set<ssgBranch *> ignore_branches;
|
||||
vector<SGPropertyNode_ptr> animation_nodes = props.getChildren("animation");
|
||||
for (i = 0; i < animation_nodes.size(); i++) {
|
||||
const char * name = animation_nodes[i]->getStringValue("name", 0);
|
||||
vector<SGPropertyNode_ptr> name_nodes =
|
||||
animation_nodes[i]->getChildren("object-name");
|
||||
sgMakeAnimation( model, name, name_nodes, prop_root, animation_nodes[i],
|
||||
sim_time_sec, ignore_branches);
|
||||
}
|
||||
|
||||
#if PLIB_VERSION > 183
|
||||
if ( model != 0 && sgUseDisplayList ) {
|
||||
makeDList( model, ignore_branches );
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( load_panel ) {
|
||||
// Load panels
|
||||
vector<SGPropertyNode_ptr> panel_nodes = props.getChildren("panel");
|
||||
@@ -345,6 +335,23 @@ sgLoad3DModel( const string &fg_root, const string &path,
|
||||
model->addKid(panel);
|
||||
}
|
||||
}
|
||||
// Load animations
|
||||
set<ssgBranch *> ignore_branches;
|
||||
vector<SGPropertyNode_ptr> animation_nodes = props.getChildren("animation");
|
||||
for (i = 0; i < animation_nodes.size(); i++) {
|
||||
const char * name = animation_nodes[i]->getStringValue("name", 0);
|
||||
vector<SGPropertyNode_ptr> name_nodes =
|
||||
animation_nodes[i]->getChildren("object-name");
|
||||
sgMakeAnimation( model, name, name_nodes, prop_root, animation_nodes[i],
|
||||
sim_time_sec, texturepath, ignore_branches);
|
||||
}
|
||||
|
||||
#if PLIB_VERSION > 183
|
||||
if ( model != 0 && sgUseDisplayList ) {
|
||||
makeDList( model, ignore_branches );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return alignmainmodel;
|
||||
}
|
||||
@@ -357,5 +364,10 @@ sgSetModelFilter( bool filter )
|
||||
return old;
|
||||
}
|
||||
|
||||
bool
|
||||
sgCheckAnimationBranch (ssgEntity * entity)
|
||||
{
|
||||
return entity->getTravCallback(SSG_CALLBACK_PRETRAV) == animation_callback;
|
||||
}
|
||||
|
||||
// end of model.cxx
|
||||
|
||||
@@ -19,6 +19,7 @@ SG_USING_STD(set);
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
|
||||
@@ -66,6 +67,7 @@ sgMakeAnimation( ssgBranch * model,
|
||||
SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr node,
|
||||
double sim_time_sec,
|
||||
SGPath &texture_path,
|
||||
set<ssgBranch *> &ignore_branches );
|
||||
|
||||
/**
|
||||
@@ -74,6 +76,12 @@ sgMakeAnimation( ssgBranch * model,
|
||||
bool
|
||||
sgSetModelFilter( bool filter );
|
||||
|
||||
/**
|
||||
* Check if the ssg node contains an animation
|
||||
*/
|
||||
bool
|
||||
sgCheckAnimationBranch (ssgEntity * entity);
|
||||
|
||||
/**
|
||||
* Enable or disable Display list usage
|
||||
*/
|
||||
|
||||
@@ -23,7 +23,7 @@ SGModelLib::~SGModelLib ()
|
||||
{
|
||||
map<string, ssgBase *>::iterator it = _table.begin();
|
||||
while (it != _table.end()) {
|
||||
it->second->deRef();
|
||||
ssgDeRefDelete(it->second);
|
||||
_table.erase(it);
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ SGModelLib::flush1()
|
||||
// If there is only one reference, it's
|
||||
// ours; no one else is using the item.
|
||||
if (item->getRef() == 1) {
|
||||
item->deRef();
|
||||
ssgDeRefDelete(item);
|
||||
_table.erase(it);
|
||||
}
|
||||
it++;
|
||||
|
||||
@@ -11,18 +11,15 @@
|
||||
|
||||
#include <string.h> // for strcmp()
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <plib/ul.h>
|
||||
|
||||
#include "location.hxx"
|
||||
#include "placementtrans.hxx"
|
||||
|
||||
#include "placement.hxx"
|
||||
|
||||
SG_USING_STD(vector);
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -37,7 +34,7 @@ SGModelPlacement::SGModelPlacement ()
|
||||
_pitch_deg(0),
|
||||
_heading_deg(0),
|
||||
_selector(new ssgSelector),
|
||||
_position(new ssgTransform),
|
||||
_position(new ssgPlacementTransform),
|
||||
_location(new SGLocation)
|
||||
{
|
||||
}
|
||||
@@ -57,23 +54,14 @@ SGModelPlacement::init( ssgBranch * model )
|
||||
}
|
||||
|
||||
void
|
||||
SGModelPlacement::update( const Point3D scenery_center )
|
||||
SGModelPlacement::update()
|
||||
{
|
||||
_location->setPosition( _lon_deg, _lat_deg, _elev_ft );
|
||||
_location->setOrientation( _roll_deg, _pitch_deg, _heading_deg );
|
||||
|
||||
sgCopyMat4( POS, _location->getTransformMatrix(scenery_center) );
|
||||
|
||||
sgVec3 trans;
|
||||
sgCopyVec3(trans, _location->get_view_pos());
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
float tmp = POS[i][3];
|
||||
for( int j=0; j<3; j++ ) {
|
||||
POS[i][j] += (tmp * trans[j]);
|
||||
}
|
||||
}
|
||||
_position->setTransform(POS);
|
||||
sgMat4 rotation;
|
||||
sgCopyMat4( rotation, _location->getTransformMatrix() );
|
||||
_position->setTransform(_location->get_absolute_view_pos(), rotation);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
SG_USING_STD(vector);
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
|
||||
@@ -24,6 +20,7 @@ SG_USING_STD(vector);
|
||||
|
||||
// Don't pull in the headers, since we don't need them here.
|
||||
class SGLocation;
|
||||
class ssgPlacementTransform;
|
||||
|
||||
|
||||
// Has anyone done anything *really* stupid, like making min and max macros?
|
||||
@@ -49,12 +46,9 @@ public:
|
||||
SGModelPlacement ();
|
||||
virtual ~SGModelPlacement ();
|
||||
|
||||
virtual void SGModelPlacement::init( ssgBranch * model );
|
||||
/* virtual void init( const string &fg_root,
|
||||
const string &path,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec, int dummy ); */
|
||||
virtual void update( const Point3D scenery_center );
|
||||
virtual void SGModelPlacement::init( ssgBranch * model );
|
||||
|
||||
virtual void update();
|
||||
|
||||
virtual ssgEntity * getSceneGraph () { return (ssgEntity *)_selector; }
|
||||
|
||||
@@ -82,9 +76,8 @@ public:
|
||||
virtual void setOrientation (double roll_deg, double pitch_deg,
|
||||
double heading_deg);
|
||||
|
||||
// Addition by Diarmuid Tyson for Multiplayer Support
|
||||
// Allows multiplayer to get players position transform
|
||||
virtual const sgVec4 *get_POS() { return POS; }
|
||||
ssgPlacementTransform * getTransform(void)
|
||||
{ return _position; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -99,17 +92,10 @@ private:
|
||||
double _heading_deg;
|
||||
|
||||
ssgSelector * _selector;
|
||||
ssgTransform * _position;
|
||||
ssgPlacementTransform * _position;
|
||||
|
||||
// Location
|
||||
SGLocation * _location;
|
||||
|
||||
|
||||
// Addition by Diarmuid Tyson for Multiplayer Support
|
||||
// Moved from update method
|
||||
// POS for transformation Matrix
|
||||
sgMat4 POS;
|
||||
|
||||
};
|
||||
|
||||
#endif // _SG_PLACEMENT_HXX
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// placementtrans.hxx -- class for carrying transforms for placing models in the world
|
||||
//
|
||||
// Written by Mathias Froehlich, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Mathias Froehlich
|
||||
//
|
||||
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/constants.h>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
|
||||
#include "placementtrans.hxx"
|
||||
|
||||
ssgPlacementTransform::ssgPlacementTransform(void)
|
||||
{
|
||||
}
|
||||
|
||||
ssgPlacementTransform::~ssgPlacementTransform(void)
|
||||
{
|
||||
}
|
||||
|
||||
ssgBase *ssgPlacementTransform::clone(int clone_flags)
|
||||
{
|
||||
ssgPlacementTransform *b = new ssgPlacementTransform;
|
||||
b->copy_from(this, clone_flags);
|
||||
return b;
|
||||
}
|
||||
|
||||
void
|
||||
ssgPlacementTransform::copy_from(ssgPlacementTransform *src, int clone_flags)
|
||||
{
|
||||
ssgBaseTransform::copy_from(src, clone_flags);
|
||||
sgdCopyVec3(_placement_offset, src->_placement_offset);
|
||||
sgdCopyVec3(_scenery_center, src->_scenery_center);
|
||||
}
|
||||
|
||||
void ssgPlacementTransform::setTransform(sgdVec3 off)
|
||||
{
|
||||
sgdCopyVec3(_placement_offset, off);
|
||||
sgdVec3 tmp;
|
||||
sgdSubVec3(tmp, _placement_offset, _scenery_center);
|
||||
sgMat4 tmat;
|
||||
sgZeroVec4(tmat[0]);
|
||||
tmat[0][0] = 1;
|
||||
sgZeroVec4(tmat[1]);
|
||||
tmat[1][1] = 1;
|
||||
sgZeroVec4(tmat[2]);
|
||||
tmat[2][2] = 1;
|
||||
sgSetVec3(tmat[3], tmp);
|
||||
tmat[3][3] = 1;
|
||||
ssgTransform::setTransform(tmat);
|
||||
}
|
||||
|
||||
void ssgPlacementTransform::setTransform(sgdVec3 off, sgMat4 rot)
|
||||
{
|
||||
sgdCopyVec3(_placement_offset, off);
|
||||
sgdVec3 tmp;
|
||||
sgdSubVec3(tmp, _placement_offset, _scenery_center);
|
||||
sgMat4 tmat;
|
||||
sgCopyVec4(tmat[0], rot[0]);
|
||||
sgCopyVec4(tmat[1], rot[1]);
|
||||
sgCopyVec4(tmat[2], rot[2]);
|
||||
sgSetVec3(tmat[3], tmp);
|
||||
tmat[3][3] = 1;
|
||||
ssgTransform::setTransform(tmat);
|
||||
}
|
||||
|
||||
void ssgPlacementTransform::setSceneryCenter(sgdVec3 xyz)
|
||||
{
|
||||
sgdCopyVec3(_scenery_center, xyz);
|
||||
sgdVec3 tmp;
|
||||
sgdSubVec3(tmp, _placement_offset, _scenery_center);
|
||||
sgMat4 tmat;
|
||||
getTransform(tmat);
|
||||
sgSetVec3(tmat[3], tmp);
|
||||
ssgTransform::setTransform(tmat);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// placementtrans.hxx -- class for carrying transforms for placing models in the world
|
||||
//
|
||||
// Written by Mathias Froehlich, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Mathias Froehlich
|
||||
//
|
||||
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
|
||||
|
||||
#ifndef _SG_PLACEMENTTRANS_HXX
|
||||
#define _SG_PLACEMENTTRANS_HXX
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/constants.h>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
|
||||
class ssgPlacementTransform : public ssgTransform
|
||||
{
|
||||
public:
|
||||
|
||||
ssgPlacementTransform(void);
|
||||
virtual ~ssgPlacementTransform(void);
|
||||
|
||||
// using ssgTransform::addKid(ssgEntity*);
|
||||
|
||||
virtual ssgBase *clone(int clone_flags);
|
||||
protected:
|
||||
void copy_from(ssgPlacementTransform *src, int clone_flags);
|
||||
|
||||
private:
|
||||
// virtual void setTransform(sgVec3 xyz);
|
||||
// virtual void setTransform(sgCoord *xform);
|
||||
// virtual void setTransform(sgCoord *xform, float sx, float sy, float sz);
|
||||
// virtual void setTransform(sgMat4 xform);
|
||||
public:
|
||||
|
||||
void setTransform(sgdVec3 off);
|
||||
void setTransform(sgdVec3 off, sgMat4 rot);
|
||||
void setSceneryCenter(sgdVec3 xyz);
|
||||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// private data //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
sgdVec3 _placement_offset;
|
||||
sgdVec3 _scenery_center;
|
||||
|
||||
};
|
||||
|
||||
#endif // _SG_LOCATION_HXX
|
||||
@@ -0,0 +1,628 @@
|
||||
// non fixed Opengl pipeline rendering
|
||||
//
|
||||
// Written by Harald JOHNSEN, started Jully 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN
|
||||
//
|
||||
// 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <plib/ul.h>
|
||||
|
||||
#include <simgear/props/condition.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/screen/extensions.hxx>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <simgear/screen/shader.h>
|
||||
|
||||
#include "animation.hxx"
|
||||
/*
|
||||
<animation>
|
||||
<type>shader</type>
|
||||
<shader>fresnel</shader>
|
||||
<object-name>...</object-name>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
<type>shader</type>
|
||||
<shader>heat-haze</shader>
|
||||
<object-name>...</object-name>
|
||||
<speed>...</speed>
|
||||
<speed-prop>...</speed-prop>
|
||||
<factor>...</factor>
|
||||
<factor-prop>...</factor-prop>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
<type>shader</type>
|
||||
<shader>chrome</shader>
|
||||
<texture>...</texture>
|
||||
<object-name>...</object-name>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
<type>shader</type>
|
||||
<shader></shader>
|
||||
<object-name>...</object-name>
|
||||
<depth-test>false</depth-test>
|
||||
</animation>
|
||||
|
||||
*/
|
||||
static Shader *shFresnel=NULL;
|
||||
static GLuint texFresnel = 0;
|
||||
|
||||
static GLuint texBackground = 0;
|
||||
static int texBackgroundWidth = 1024, texBackgroundHeight = 1024;
|
||||
static GLenum texBackgroundTarget = GL_TEXTURE_2D;
|
||||
static bool isRectangleTextureSupported = false;
|
||||
static bool istexBackgroundRectangle = false;
|
||||
static bool initDone = false;
|
||||
static bool haveBackground = false;
|
||||
|
||||
static glActiveTextureProc glActiveTexturePtr = 0;
|
||||
static double totalTime = 0.0;
|
||||
static sgMat4 shadIdentMatrix;
|
||||
|
||||
|
||||
static int null_shader_callback( ssgEntity *e ) {
|
||||
GLuint dlist = 0;
|
||||
ssgLeaf *leaf = (ssgLeaf *) e;
|
||||
#ifdef _SSG_USE_DLIST
|
||||
dlist = leaf->getDListIndex();
|
||||
if( ! dlist ) {
|
||||
leaf->makeDList();
|
||||
dlist = leaf->getDListIndex();
|
||||
}
|
||||
#endif
|
||||
if( ! dlist )
|
||||
return true;
|
||||
ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
|
||||
if ( sst )
|
||||
sst->apply();
|
||||
|
||||
SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
|
||||
if( ! my_shader->_depth_test )
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glCallList ( dlist ) ;
|
||||
// restore states
|
||||
if( ! my_shader->_depth_test )
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
|
||||
// don't draw !
|
||||
return false;
|
||||
}
|
||||
|
||||
static int heat_haze_shader_callback( ssgEntity *e ) {
|
||||
GLuint dlist = 0;
|
||||
ssgLeaf *leaf = (ssgLeaf *) e;
|
||||
#ifdef _SSG_USE_DLIST
|
||||
dlist = leaf->getDListIndex();
|
||||
if( ! dlist ) {
|
||||
leaf->makeDList();
|
||||
dlist = leaf->getDListIndex();
|
||||
}
|
||||
#endif
|
||||
if( ! dlist )
|
||||
return true;
|
||||
|
||||
GLint viewport[4];
|
||||
glGetIntegerv( GL_VIEWPORT, viewport );
|
||||
const int screen_width = viewport[2];
|
||||
const int screen_height = viewport[3];
|
||||
if( ! haveBackground ) {
|
||||
// store the backbuffer in a texture
|
||||
if( ! texBackground ) {
|
||||
// allocate our texture here so we don't waste memory if no model use that effect
|
||||
// check if we need a rectangle texture and if the card support it
|
||||
if( (screen_width > 1024 || screen_height > 1024) && isRectangleTextureSupported ) {
|
||||
// Note that the 3 (same) extensions use the same enumerants
|
||||
texBackgroundTarget = GL_TEXTURE_RECTANGLE_NV;
|
||||
istexBackgroundRectangle = true;
|
||||
texBackgroundWidth = screen_width;
|
||||
texBackgroundHeight = screen_height;
|
||||
}
|
||||
glGenTextures(1, &texBackground);
|
||||
glEnable(texBackgroundTarget);
|
||||
glBindTexture(texBackgroundTarget, texBackground);
|
||||
// trying to match the backbuffer pixel format
|
||||
GLint internalFormat = GL_RGB8;
|
||||
GLint colorBits = 0, alphaBits = 0;
|
||||
glGetIntegerv( GL_BLUE_BITS, &colorBits );
|
||||
glGetIntegerv( GL_ALPHA_BITS, &alphaBits );
|
||||
if(colorBits == 5) {
|
||||
if( alphaBits == 0 )
|
||||
internalFormat = GL_RGB5;
|
||||
else
|
||||
internalFormat = GL_RGB5_A1;
|
||||
} else {
|
||||
if( alphaBits != 0 )
|
||||
internalFormat = GL_RGBA8;
|
||||
}
|
||||
glTexImage2D(texBackgroundTarget, 0, internalFormat,
|
||||
texBackgroundWidth, texBackgroundHeight, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
|
||||
glTexParameteri(texBackgroundTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(texBackgroundTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(texBackgroundTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(texBackgroundTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
glEnable(texBackgroundTarget);
|
||||
glBindTexture(texBackgroundTarget, texBackground);
|
||||
// center of texture = center of screen
|
||||
// obviously we don't have the whole screen if screen_width > texBackgroundWidth
|
||||
// if rectangle textures are not supported, this give some artifacts on the borders
|
||||
if( istexBackgroundRectangle ) {
|
||||
glCopyTexSubImage2D( texBackgroundTarget, 0, 0, 0,
|
||||
0, 0, texBackgroundWidth, texBackgroundHeight );
|
||||
} else {
|
||||
glCopyTexSubImage2D( texBackgroundTarget, 0, 0, 0,
|
||||
(screen_width - texBackgroundWidth) / 2,
|
||||
(screen_height - texBackgroundHeight) / 2,
|
||||
texBackgroundWidth, texBackgroundHeight );
|
||||
}
|
||||
haveBackground = true;
|
||||
glBindTexture(texBackgroundTarget, 0);
|
||||
glDisable(texBackgroundTarget);
|
||||
}
|
||||
ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
|
||||
if ( sst )
|
||||
sst->apply();
|
||||
|
||||
SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
|
||||
if( ! my_shader->_depth_test )
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glDepthMask( GL_FALSE );
|
||||
glDisable( GL_LIGHTING );
|
||||
if(1) {
|
||||
// noise texture, tex coord from the model translated by a time factor
|
||||
glActiveTexturePtr( GL_TEXTURE0_ARB );
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
const float noiseDist = fmod(- totalTime * my_shader->_factor * my_shader->_speed, 4.0);
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glTranslatef( noiseDist, 0.0f, 0.0f );
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
|
||||
// background texture
|
||||
glActiveTexturePtr( GL_TEXTURE1_ARB );
|
||||
glEnable(texBackgroundTarget);
|
||||
glBindTexture(texBackgroundTarget, texBackground);
|
||||
|
||||
// automatic generation of texture coordinates
|
||||
// map to screen space
|
||||
sgMat4 CameraProjM, CameraViewM;
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *) CameraProjM);
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) CameraViewM);
|
||||
const float dummy_scale = 1.0f; //0.95f;
|
||||
const float deltaPos = 0.05f;
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
if( istexBackgroundRectangle ) {
|
||||
// coords go from 0.0 to n, not from 0.0 to 1.0
|
||||
glTranslatef( texBackgroundWidth * 0.5f, texBackgroundHeight * 0.5f, 0.0f );
|
||||
glScalef( texBackgroundWidth * 0.5f,
|
||||
texBackgroundHeight * 0.5f, 1.0f );
|
||||
} else {
|
||||
glTranslatef( 0.5f, 0.5f, 0.0f );
|
||||
glScalef( float( screen_width ) / float( texBackgroundWidth ) * 0.5f,
|
||||
float( screen_height ) / float( texBackgroundHeight ) * 0.5f, 1.0f );
|
||||
}
|
||||
glMultMatrixf( (GLfloat *) CameraProjM );
|
||||
glMultMatrixf( (GLfloat *) CameraViewM );
|
||||
glTranslatef( deltaPos, deltaPos, deltaPos );
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
|
||||
glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
|
||||
glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
|
||||
glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
|
||||
glTexGenfv( GL_S, GL_EYE_PLANE, shadIdentMatrix[0] );
|
||||
glTexGenfv( GL_T, GL_EYE_PLANE, shadIdentMatrix[1] );
|
||||
glTexGenfv( GL_R, GL_EYE_PLANE, shadIdentMatrix[2] );
|
||||
glTexGenfv( GL_Q, GL_EYE_PLANE, shadIdentMatrix[3] );
|
||||
glEnable( GL_TEXTURE_GEN_S );
|
||||
glEnable( GL_TEXTURE_GEN_T );
|
||||
glEnable( GL_TEXTURE_GEN_R );
|
||||
glEnable( GL_TEXTURE_GEN_Q );
|
||||
|
||||
sgVec4 enviro = {1.00f, 1.00f, 1.00f, 0.85f};
|
||||
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, enviro);
|
||||
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0_ARB);
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PRIMARY_COLOR_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA );
|
||||
|
||||
glCallList ( dlist ) ;
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glTranslatef( - deltaPos*2.0f, -deltaPos*2.5f, -deltaPos*2.0f );
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glCallList ( dlist ) ;
|
||||
|
||||
// alter colors only on last rendering
|
||||
sgVec4 fLight = {0.93f, 0.93f, 1.00f, 0.85f};
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glTranslatef( deltaPos*0.7f, deltaPos*1.7f, deltaPos*0.7f );
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glCallList ( dlist ) ;
|
||||
|
||||
|
||||
glActiveTexturePtr( GL_TEXTURE1_ARB );
|
||||
glDisable( GL_TEXTURE_GEN_S );
|
||||
glDisable( GL_TEXTURE_GEN_T );
|
||||
glDisable( GL_TEXTURE_GEN_R );
|
||||
glDisable( GL_TEXTURE_GEN_Q );
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
glDisable(texBackgroundTarget);
|
||||
glActiveTexturePtr( GL_TEXTURE0_ARB );
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
// restore states
|
||||
if( ! my_shader->_depth_test )
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
|
||||
glEnable( GL_LIGHTING );
|
||||
glDepthMask( GL_TRUE );
|
||||
if( sst )
|
||||
sst->force();
|
||||
|
||||
// don't draw !
|
||||
return false;
|
||||
}
|
||||
|
||||
static int fresnel_shader_callback( ssgEntity *e ) {
|
||||
GLuint dlist = 0;
|
||||
ssgLeaf *leaf = (ssgLeaf *) e;
|
||||
#ifdef _SSG_USE_DLIST
|
||||
dlist = leaf->getDListIndex();
|
||||
if( ! dlist ) {
|
||||
leaf->makeDList();
|
||||
dlist = leaf->getDListIndex();
|
||||
}
|
||||
#endif
|
||||
if( ! dlist )
|
||||
return true;
|
||||
ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
|
||||
if ( sst )
|
||||
sst->apply();
|
||||
|
||||
sgVec4 sunColor, ambientColor;
|
||||
ssgGetLight( 0 )->getColour(GL_DIFFUSE, sunColor );
|
||||
ssgGetLight( 0 )->getColour(GL_AMBIENT, ambientColor );
|
||||
|
||||
SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.0f);
|
||||
|
||||
if( true ) {
|
||||
// sgVec4 R = {0.5,0.0,0.0,0.0};
|
||||
sgVec4 enviro = {1.0,0.0,0.0,1.0};
|
||||
// sgCopyVec4( enviro, sunColor );
|
||||
glActiveTexturePtr( GL_TEXTURE0_ARB );
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
glActiveTexturePtr( GL_TEXTURE1_ARB );
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_TEXTURE_1D);
|
||||
glBindTexture(GL_TEXTURE_1D, texFresnel);
|
||||
// c = a0 * a2 + a1 * (1-a2)
|
||||
// glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
// glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR );
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, enviro);
|
||||
shFresnel->enable();
|
||||
shFresnel->bind();
|
||||
glCallList ( dlist ) ;
|
||||
shFresnel->disable();
|
||||
glActiveTexturePtr( GL_TEXTURE1_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glActiveTexturePtr( GL_TEXTURE0_ARB );
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
// restore states
|
||||
// glBindTexture(GL_TEXTURE_2D, 0);
|
||||
// glDepthFunc(GL_LESS);
|
||||
// glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
|
||||
if( sst )
|
||||
sst->force();
|
||||
|
||||
// don't draw !
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int chrome_shader_callback( ssgEntity *e ) {
|
||||
GLuint dlist = 0;
|
||||
ssgLeaf *leaf = (ssgLeaf *) e;
|
||||
#ifdef _SSG_USE_DLIST
|
||||
dlist = leaf->getDListIndex();
|
||||
if( ! dlist ) {
|
||||
leaf->makeDList();
|
||||
dlist = leaf->getDListIndex();
|
||||
}
|
||||
#endif
|
||||
if( ! dlist )
|
||||
return true;
|
||||
ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
|
||||
if ( sst )
|
||||
sst->apply();
|
||||
|
||||
SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
|
||||
if( ! my_shader->_depth_test )
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
|
||||
GLint maskTexComponent = 3;
|
||||
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPONENTS, &maskTexComponent);
|
||||
|
||||
// The fake env chrome texture
|
||||
glActiveTexturePtr( GL_TEXTURE1_ARB );
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
{
|
||||
// No lighting is computed in spherical mapping mode because the environment
|
||||
// is supposed to be allready lighted. We must reshade our environment texture.
|
||||
sgVec4 sunColor, ambientColor, envColor;
|
||||
ssgGetLight( 0 )->getColour(GL_DIFFUSE, sunColor );
|
||||
ssgGetLight( 0 )->getColour(GL_AMBIENT, ambientColor );
|
||||
sgAddScaledVec3( envColor, ambientColor, sunColor, 0.4f);
|
||||
glBindTexture(GL_TEXTURE_2D, my_shader->_effectTexture->getHandle());
|
||||
|
||||
sgVec3 delta_light;
|
||||
sgSubVec3(delta_light, envColor, my_shader->_envColor);
|
||||
if( (fabs(delta_light[0]) + fabs(delta_light[1]) + fabs(delta_light[2])) > 0.05f ) {
|
||||
sgCopyVec3( my_shader->_envColor, envColor );
|
||||
// reload the texture data and let the driver reshade it for us
|
||||
glPixelTransferf( GL_RED_SCALE, envColor[0] );
|
||||
glPixelTransferf( GL_GREEN_SCALE, envColor[1] );
|
||||
glPixelTransferf( GL_BLUE_SCALE, envColor[2] );
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, my_shader->_texWidth, my_shader->_texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, my_shader->_textureData);
|
||||
glPixelTransferf( GL_RED_SCALE, 1.0f );
|
||||
glPixelTransferf( GL_GREEN_SCALE, 1.0f );
|
||||
glPixelTransferf( GL_BLUE_SCALE, 1.0f );
|
||||
}
|
||||
}
|
||||
if( maskTexComponent == 4 ) {
|
||||
// c = lerp(model tex, chrome tex, model tex alpha)
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_PREVIOUS_ARB );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA );
|
||||
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
} else {
|
||||
// c = chrome tex
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
|
||||
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
}
|
||||
// automatic generation of texture coordinates
|
||||
// from normals
|
||||
|
||||
glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
|
||||
glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
|
||||
glEnable( GL_TEXTURE_GEN_S );
|
||||
glEnable( GL_TEXTURE_GEN_T );
|
||||
|
||||
glCallList ( dlist ) ;
|
||||
|
||||
glActiveTexturePtr( GL_TEXTURE1_ARB );
|
||||
glDisable( GL_TEXTURE_GEN_S );
|
||||
glDisable( GL_TEXTURE_GEN_T );
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexturePtr( GL_TEXTURE0_ARB );
|
||||
|
||||
// restore states
|
||||
if( ! my_shader->_depth_test )
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
|
||||
if( sst )
|
||||
sst->force();
|
||||
|
||||
// don't draw !
|
||||
return false;
|
||||
}
|
||||
|
||||
static void init_shaders(void) {
|
||||
Shader::Init();
|
||||
if( false && Shader::is_VP_supported() ) {
|
||||
shFresnel = new Shader("/FlightGear/data/Textures/fresnel_vp.txt", "fresnel_vp");
|
||||
// shFresnel->bindNames("somedata", 0);
|
||||
}
|
||||
glActiveTexturePtr = (glActiveTextureProc) SGLookupFunction("glActiveTextureARB");
|
||||
const int fresnelSize = 512;
|
||||
unsigned char imageFresnel[ fresnelSize * 3 ];
|
||||
for(int i = 0; i < fresnelSize; i++) {
|
||||
const float R0 = 0.2f;
|
||||
float NdotV = float( i ) / float( fresnelSize );
|
||||
float f = R0 + (1.0f-R0)*pow(1.0f - NdotV, 5);
|
||||
unsigned char ff = (unsigned char) (f * 255.0);
|
||||
imageFresnel[i*3+0] = imageFresnel[i*3+1] = imageFresnel[i*3+2] = ff;
|
||||
}
|
||||
glGenTextures( 1, &texFresnel );
|
||||
glBindTexture(GL_TEXTURE_1D, texFresnel );
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_GENERATE_MIPMAP_SGIS, true);
|
||||
glTexImage1D(GL_TEXTURE_1D, 0, 3, fresnelSize, 0, GL_RGB, GL_UNSIGNED_BYTE, imageFresnel);
|
||||
glBindTexture(GL_TEXTURE_1D, 0 );
|
||||
|
||||
sgMakeIdentMat4( shadIdentMatrix );
|
||||
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGShaderAnimation
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SGShaderAnimation::SGShaderAnimation ( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props )
|
||||
: SGAnimation(props, new ssgBranch),
|
||||
_condition(0),
|
||||
_condition_value(true),
|
||||
_shader_type(0),
|
||||
_param_1(props->getFloatValue("param", 1.0f)),
|
||||
_depth_test(props->getBoolValue("depth-test", true)),
|
||||
_factor(props->getFloatValue("factor", 1.0f)),
|
||||
_factor_prop(0),
|
||||
_speed(props->getFloatValue("speed", 1.0f)),
|
||||
_speed_prop(0),
|
||||
_effectTexture(0),
|
||||
_textureData(0),
|
||||
_texWidth(0),
|
||||
_texHeight(0)
|
||||
|
||||
{
|
||||
SGPropertyNode_ptr node = props->getChild("condition");
|
||||
if (node != 0) {
|
||||
_condition = sgReadCondition(prop_root, node);
|
||||
_condition_value = false;
|
||||
}
|
||||
node = props->getChild("factor-prop");
|
||||
if( node )
|
||||
_factor_prop = prop_root->getNode(node->getStringValue(), true);
|
||||
node = props->getChild("speed-prop");
|
||||
if( node )
|
||||
_speed_prop = prop_root->getNode(node->getStringValue(), true);
|
||||
|
||||
sgSetVec4(_envColor, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
node = props->getChild("texture");
|
||||
if( node ) {
|
||||
_effectTexture = ssgGetCurrentOptions()->createTexture( (char *) node->getStringValue(), 0, 0, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, _effectTexture->getHandle() );
|
||||
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &_texWidth);
|
||||
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &_texHeight);
|
||||
|
||||
_textureData = new unsigned char[_texWidth * _texHeight * 3];
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, _textureData);
|
||||
glBindTexture(GL_TEXTURE_2D, 0 );
|
||||
}
|
||||
string shader_name = props->getStringValue("shader");
|
||||
if( shader_name == "fresnel" || shader_name == "reflection" )
|
||||
_shader_type = 1;
|
||||
else if( shader_name == "heat-haze" )
|
||||
_shader_type = 2;
|
||||
else if( shader_name == "chrome" && _effectTexture)
|
||||
_shader_type = 3;
|
||||
}
|
||||
|
||||
static void setCallBack(ssgBranch *branch, ssgBase *user_data, ssgCallback cb) {
|
||||
for (int i = 0; i < branch->getNumKids(); i++) {
|
||||
ssgEntity *e = branch->getKid(i);
|
||||
if( e->isAKindOf( ssgTypeBranch() ) )
|
||||
setCallBack( (ssgBranch *) e, user_data, cb);
|
||||
else if( e->isAKindOf( ssgTypeVtxTable() ) ) {
|
||||
e->setCallback( SSG_CALLBACK_PREDRAW, cb );
|
||||
e->setUserData( user_data );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SGShaderAnimation::init()
|
||||
{
|
||||
if( ! initDone )
|
||||
init_shaders();
|
||||
if( _shader_type == 1 && Shader::is_VP_supported() && shFresnel)
|
||||
setCallBack( getBranch(), (ssgBase *) this, fresnel_shader_callback );
|
||||
else if( _shader_type == 2 ) {
|
||||
// this is the same extension with different names
|
||||
isRectangleTextureSupported = SGIsOpenGLExtensionSupported("GL_EXT_texture_rectangle") ||
|
||||
SGIsOpenGLExtensionSupported("GL_ARB_texture_rectangle") ||
|
||||
SGIsOpenGLExtensionSupported("GL_NV_texture_rectangle");
|
||||
setCallBack( getBranch(), (ssgBase *) this, heat_haze_shader_callback );
|
||||
}
|
||||
else if( _shader_type == 3 )
|
||||
setCallBack( getBranch(), (ssgBase *) this, chrome_shader_callback );
|
||||
else
|
||||
setCallBack( getBranch(), (ssgBase *) this, null_shader_callback );
|
||||
}
|
||||
|
||||
SGShaderAnimation::~SGShaderAnimation()
|
||||
{
|
||||
delete _condition;
|
||||
delete _effectTexture;
|
||||
delete _textureData;
|
||||
}
|
||||
|
||||
int
|
||||
SGShaderAnimation::update()
|
||||
{
|
||||
if (_condition)
|
||||
_condition_value = _condition->test();
|
||||
if( _factor_prop)
|
||||
_factor = _factor_prop->getFloatValue();
|
||||
if( _speed_prop)
|
||||
_speed = _speed_prop->getFloatValue();
|
||||
return 2;
|
||||
}
|
||||
|
||||
void sgShaderFrameInit(double delta_time_sec) {
|
||||
haveBackground = false;
|
||||
totalTime += delta_time_sec;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,145 @@
|
||||
// Shadow volume class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started June 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _SHADOWVOLUME_HXX
|
||||
#define _SHADOWVOLUME_HXX
|
||||
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
SG_USING_STD(vector);
|
||||
SG_USING_STD(map);
|
||||
|
||||
class ssgBranch;
|
||||
class ssgLeaf;
|
||||
class SGPropertyNode;
|
||||
|
||||
/**
|
||||
* A class wich add shadows in a postprocess stage.
|
||||
*/
|
||||
class SGShadowVolume {
|
||||
|
||||
public:
|
||||
SGShadowVolume( ssgBranch *root );
|
||||
~SGShadowVolume();
|
||||
|
||||
typedef enum {
|
||||
occluderTypeAircraft,
|
||||
occluderTypeAI,
|
||||
occluderTypeTileObject
|
||||
} OccluderType;
|
||||
|
||||
void init(SGPropertyNode *sim_rendering_options);
|
||||
void startOfFrame(void);
|
||||
void addOccluder(ssgBranch *occluder, OccluderType occluder_type, ssgBranch *tile=0);
|
||||
void deleteOccluder(ssgBranch *occluder);
|
||||
void deleteOccluderFromTile(ssgBranch *tile);
|
||||
void setupShadows(double lon, double lat,
|
||||
double gst, double SunRightAscension, double SunDeclination, double sunAngle );
|
||||
void endOfFrame(void);
|
||||
static int ACpostTravCB( ssgEntity *entity, int traversal_mask );
|
||||
|
||||
private:
|
||||
|
||||
class ShadowCaster
|
||||
{
|
||||
public:
|
||||
typedef struct {
|
||||
sgVec4 planeEquations;
|
||||
int neighbourIndices[3];
|
||||
bool isSilhouetteEdge[3];
|
||||
bool isFacingLight;
|
||||
} triData;
|
||||
|
||||
ssgBranch *geometry_leaf;
|
||||
ssgBranch *scenery_object;
|
||||
ssgBranch *lib_object;
|
||||
ssgBranch *first_select;
|
||||
sgVec3 last_lightpos;
|
||||
sgMat4 last_transform;
|
||||
int frameNumber;
|
||||
|
||||
int *indices;
|
||||
int numTriangles;
|
||||
triData *triangles;
|
||||
|
||||
sgVec4 * vertices;
|
||||
GLushort *silhouetteEdgeIndices;
|
||||
int lastSilhouetteIndicesCount;
|
||||
bool isTranslucent;
|
||||
|
||||
ShadowCaster( int _num_tri, ssgBranch * _geometry_leaf );
|
||||
~ShadowCaster();
|
||||
void addLeaf( int & tri_idx, int & ind_idx, ssgLeaf *_geometry_leaf );
|
||||
void SetConnectivity();
|
||||
void CalculateSilhouetteEdges(sgVec3 lightPosition);
|
||||
void DrawInfiniteShadowVolume(sgVec3 lightPosition, bool drawCaps);
|
||||
void computeShadows(sgMat4 rotation, sgMat4 rotation_translation, OccluderType occluder_type);
|
||||
void getNetTransform ( ssgBranch * branch, sgMat4 xform );
|
||||
bool isSelected ( ssgBranch * branch, float dist);
|
||||
|
||||
bool sameVertex(int edge1, int edge2);
|
||||
};
|
||||
typedef vector<ShadowCaster *> ShadowCaster_list;
|
||||
|
||||
class SceneryObject {
|
||||
public:
|
||||
SceneryObject(ssgBranch *_scenery_object, OccluderType _occluder_type);
|
||||
~SceneryObject();
|
||||
void computeShadows(void);
|
||||
void traverseTree(ssgBranch *branch);
|
||||
void find_trans(void);
|
||||
ssgBranch *scenery_object;
|
||||
ssgBranch *lib_object;
|
||||
ssgBranch *pending_object;
|
||||
ssgBranch *tile;
|
||||
ShadowCaster_list parts;
|
||||
OccluderType occluder_type;
|
||||
};
|
||||
typedef map<ssgBranch *, SceneryObject *> SceneryObject_map;
|
||||
|
||||
|
||||
private:
|
||||
void update_light_view(void);
|
||||
void computeShadows(void);
|
||||
void cull ( ssgBranch *b, sgFrustum *f, sgMat4 m, int test_needed );
|
||||
|
||||
bool shadows_enabled;
|
||||
bool shadowsAC_enabled, shadowsAI_enabled, shadowsTO_enabled, shadowsDebug_enabled;
|
||||
bool shadowsAC_transp_enabled;
|
||||
bool use_alpha;
|
||||
bool canDoAlpha, canDoStencil;
|
||||
SGPropertyNode *sim_rendering;
|
||||
|
||||
sgVec3 sunPos;
|
||||
int frameNumber;
|
||||
int lastTraverseTreeFrame;
|
||||
sgMat4 CameraViewM;
|
||||
double sun_angle;
|
||||
SceneryObject_map sceneryObjects;
|
||||
ssgBranch *ssg_root;
|
||||
bool shadows_rendered;
|
||||
};
|
||||
|
||||
#endif // _SHADOWVOLUME_HXX
|
||||
@@ -1,7 +1,5 @@
|
||||
includedir = @includedir@/scene/sky
|
||||
|
||||
SUBDIRS = clouds3d
|
||||
|
||||
lib_LIBRARIES = libsgsky.a
|
||||
|
||||
include_HEADERS = \
|
||||
@@ -11,7 +9,10 @@ include_HEADERS = \
|
||||
oursun.hxx \
|
||||
sky.hxx \
|
||||
sphere.hxx \
|
||||
stars.hxx
|
||||
stars.hxx \
|
||||
bbcache.hxx \
|
||||
cloudfield.hxx \
|
||||
newcloud.hxx
|
||||
|
||||
libsgsky_a_SOURCES = \
|
||||
cloud.cxx \
|
||||
@@ -20,6 +21,9 @@ libsgsky_a_SOURCES = \
|
||||
oursun.cxx \
|
||||
sky.cxx \
|
||||
sphere.cxx \
|
||||
stars.cxx
|
||||
stars.cxx \
|
||||
bbcache.cxx \
|
||||
cloudfield.cxx \
|
||||
newcloud.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
// Billboard helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <simgear/screen/extensions.hxx>
|
||||
#include <simgear/screen/RenderTexture.h>
|
||||
#include SG_GLU_H
|
||||
|
||||
#include "bbcache.hxx"
|
||||
|
||||
|
||||
/*
|
||||
memory usage :
|
||||
size 1 tex 8 tex 32 tex 64 tex
|
||||
64x64x4 16k 128k 512k 1Mo
|
||||
128x128x4 64k 512k 2Mo 4Mo
|
||||
256x256x4 256k 2Mo 8Mo 16Mo
|
||||
*/
|
||||
|
||||
void SGBbCache::freeTextureMemory(void) {
|
||||
|
||||
if( bbListCount ) {
|
||||
for(int i = 0 ; i < bbListCount ; i++) {
|
||||
bbList[i].cldID = 0;
|
||||
if(bbList[i].texID)
|
||||
glDeleteTextures(1, & bbList[i].texID);
|
||||
}
|
||||
delete [] bbList;
|
||||
}
|
||||
bbListCount = 0;
|
||||
cacheSizeKb = 0;
|
||||
textureWH = 0;
|
||||
}
|
||||
|
||||
bool SGBbCache::allocTextureMemory(int cacheCount, int textureDimension) {
|
||||
textureWH = textureDimension;
|
||||
bbListCount = cacheCount;
|
||||
bbList = new bbInfo[bbListCount];
|
||||
for(int i = 0 ; i < bbListCount ; i++) {
|
||||
bbList[i].cldID = 0;
|
||||
bbList[i].texID = 0;
|
||||
glGenTextures(1, &bbList[i].texID);
|
||||
glBindTexture(GL_TEXTURE_2D, bbList[i].texID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
|
||||
textureDimension, textureDimension, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
cacheSizeKb = (textureDimension * textureDimension * 4);
|
||||
cacheSizeKb *= cacheCount;
|
||||
cacheSizeKb /= 1024;
|
||||
if(rtAvailable) {
|
||||
if( rt->BeginCapture() ) {
|
||||
glViewport(0, 0, textureDimension, textureDimension);
|
||||
rt->EndCapture();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SGBbCache::SGBbCache(void) :
|
||||
bbListCount(0),
|
||||
cacheSizeKb(0),
|
||||
textureWH(0),
|
||||
builtBBCount(0),
|
||||
rt(0),
|
||||
rtAvailable(false),
|
||||
frameNumber(0),
|
||||
maxImpostorRegenFrame(20)
|
||||
{
|
||||
}
|
||||
|
||||
SGBbCache::~SGBbCache(void) {
|
||||
if(rt)
|
||||
delete rt;
|
||||
freeTextureMemory();
|
||||
}
|
||||
|
||||
|
||||
void SGBbCache::init(int cacheCount) {
|
||||
GLint colorBits = 0;
|
||||
glGetIntegerv( GL_BLUE_BITS, &colorBits );
|
||||
|
||||
rt = new RenderTexture();
|
||||
// don't use default rtt on nvidia/win because of poor performance of glCopyTexSubImage2D
|
||||
// wihtout default pattrib params - see opengl forum
|
||||
if( colorBits < 8 )
|
||||
rt->Reset("rgba=5,5,5,1 ctt");
|
||||
else
|
||||
rt->Reset("rgba ctt");
|
||||
|
||||
// rt->Reset("rgba tex2D ctt");
|
||||
// rt->Reset("rgba tex2D");
|
||||
if( rt->Initialize(256, 256, true) ) {
|
||||
SG_LOG(SG_ALL, SG_INFO, "bbcache:Initialize sucessfull");
|
||||
if (rt->BeginCapture())
|
||||
{
|
||||
SG_LOG(SG_ALL, SG_INFO, "bbcache:BeginCapture sucessfull, RTT available");
|
||||
rtAvailable = true;
|
||||
glViewport(0, 0, 256, 256);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(60.0, 1, 1, 5.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_FOG);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.0f);
|
||||
glEnable(GL_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
rt->EndCapture();
|
||||
} else
|
||||
SG_LOG(SG_ALL, SG_WARN, "bbcache:BeginCapture failed, RTT not available for 3D clouds");
|
||||
} else
|
||||
SG_LOG(SG_ALL, SG_WARN, "bbcache:Initialize failed, RTT not available for 3D clouds");
|
||||
if( cacheCount )
|
||||
allocTextureMemory( cacheCount, 64 );
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool SGBbCache::setCacheSize(int count, int textureDimension) {
|
||||
if( count < 0 || count > 500)
|
||||
return false;
|
||||
freeTextureMemory();
|
||||
if( count == 0)
|
||||
return true;
|
||||
|
||||
// only allow some reasonable dimensions
|
||||
switch(textureDimension) {
|
||||
case 0:
|
||||
// default size
|
||||
textureDimension = 256;
|
||||
break;
|
||||
case 64:
|
||||
case 128:
|
||||
case 256:
|
||||
break;
|
||||
case 512:
|
||||
// rt is 256 so higher texture size has no meaning
|
||||
textureDimension = 256;
|
||||
break;
|
||||
default:
|
||||
textureDimension = 128;
|
||||
break;
|
||||
}
|
||||
return allocTextureMemory( count, textureDimension);
|
||||
}
|
||||
|
||||
|
||||
bool SGBbCache::setCacheSize(int sizeKb) {
|
||||
if( sizeKb < 0 || sizeKb > 256*1024)
|
||||
return false;
|
||||
freeTextureMemory();
|
||||
if( sizeKb == 0)
|
||||
return true;
|
||||
int count = 1;
|
||||
int textureDimension = 256;
|
||||
if( sizeKb >= 8*1024 ) {
|
||||
// more than 32 256x256 textures
|
||||
textureDimension = 256;
|
||||
} else if( sizeKb >= 2*1024 ) {
|
||||
// more than 32 128x128 textures
|
||||
textureDimension = 128;
|
||||
} else {
|
||||
// don't go under 64x64 textures
|
||||
textureDimension = 64;
|
||||
}
|
||||
count = (sizeKb * 1024) / (textureDimension * textureDimension * 4);
|
||||
if(count == 0)
|
||||
count = 1;
|
||||
return allocTextureMemory( count, textureDimension);
|
||||
}
|
||||
|
||||
int SGBbCache::queryCacheSize(void) {
|
||||
return cacheSizeKb;
|
||||
}
|
||||
|
||||
void SGBbCache::free(int bbId, int cldId) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return;
|
||||
if( bbList[bbId].cldID != cldId )
|
||||
return;
|
||||
bbList[bbId].cldID = 0;
|
||||
}
|
||||
|
||||
int SGBbCache::alloc(int cldId) {
|
||||
// pretend we have no more texture if render to texture is not available
|
||||
if( ! rtAvailable )
|
||||
return -1;
|
||||
for(int i = 0 ; i < bbListCount ; i++) {
|
||||
if( (bbList[i].cldID == 0) && (bbList[i].texID != 0) ) {
|
||||
bbList[i].cldID = cldId;
|
||||
bbList[i].angleX = -999;
|
||||
bbList[i].angleY = -999;
|
||||
bbList[i].frameUsed = 0;
|
||||
bbList[i].needRedraw = true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
GLuint SGBbCache::QueryTexID(int cldId, int bbId) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return 0;
|
||||
if( bbList[bbId].cldID != cldId )
|
||||
return 0;
|
||||
return bbList[bbId].texID;
|
||||
}
|
||||
|
||||
int SGBbCache::queryImpostorAge(int bbId) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return 0;
|
||||
return frameNumber - bbList[bbId].frame;
|
||||
}
|
||||
|
||||
void SGBbCache::beginCapture(void) {
|
||||
|
||||
rt->BeginCapture();
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SGBbCache::setRadius(float radius, float dist_center) {
|
||||
float border;
|
||||
//set viewport to texture resolution
|
||||
//glViewport(0, 0, 256, 256);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
float near_ = dist_center - radius;
|
||||
float far_ = dist_center + radius;
|
||||
if( near_ <= 0 ) {
|
||||
// we are in trouble
|
||||
glFrustum(-1, 1, -1, 1, 1, 1 + radius * 2);
|
||||
} else {
|
||||
border = (near_ * radius) / sqrt(dist_center * dist_center - radius * radius);
|
||||
glFrustum(-border, border, -border, border, near_, far_);
|
||||
}
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
void SGBbCache::setTextureData(int bbId) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, bbList[bbId].texID);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, textureWH, textureWH);
|
||||
|
||||
// bbList[bbId].angleX = angleX;
|
||||
// bbList[bbId].angleY = angleY;
|
||||
bbList[bbId].frame = frameNumber;
|
||||
bbList[bbId].frameUsed = frameNumber;
|
||||
bbList[bbId].needRedraw = false;
|
||||
builtBBCount ++;
|
||||
builtBBframe ++;
|
||||
}
|
||||
|
||||
void SGBbCache::endCapture(void) {
|
||||
|
||||
rt->EndCapture();
|
||||
// glBindTexture(GL_TEXTURE_2D, rt->GetTextureID() );
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool SGBbCache::isBbValid( int cldId, int bbId, float angleY, float angleX) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return false;
|
||||
if( bbList[bbId].cldID != cldId )
|
||||
return false;
|
||||
|
||||
// it was just allocated
|
||||
if( bbList[bbId].frameUsed == 0)
|
||||
return false;
|
||||
|
||||
// we reuse old impostor to speed up things
|
||||
if( builtBBframe >= maxImpostorRegenFrame )
|
||||
return true;
|
||||
|
||||
if( bbList[bbId].needRedraw )
|
||||
return false;
|
||||
|
||||
// if( fabs(angleY - bbList[bbId].angleY) >= 4.0 )
|
||||
// return false;
|
||||
|
||||
// if( fabs(angleX - bbList[bbId].angleX) >= 4.0 )
|
||||
// return false;
|
||||
|
||||
bbList[bbId].frameUsed = frameNumber;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO:this is not the right way to handle that
|
||||
void SGBbCache::setReference( int cldId, int bbId, float angleY, float angleX) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return;
|
||||
if( bbList[bbId].cldID != cldId )
|
||||
return;
|
||||
bbList[bbId].angleX = angleX;
|
||||
bbList[bbId].angleY = angleY;
|
||||
}
|
||||
|
||||
void SGBbCache::startNewFrame(void) {
|
||||
builtBBframe = 0;
|
||||
// TOTO:find reasonable value
|
||||
int minFrameNumber = frameNumber - 100;
|
||||
frameNumber++;
|
||||
// cleanup of unused enties
|
||||
for( int bbId = 0 ; bbId < bbListCount ; bbId++)
|
||||
if( (bbList[bbId].cldID != 0) && (bbList[bbId].frameUsed < minFrameNumber) ) {
|
||||
// entry is now free
|
||||
bbList[bbId].cldID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// force all impostors to be rebuilt, this will enventually be done over several frames
|
||||
void SGBbCache::invalidateCache(void) {
|
||||
|
||||
for( int bbId = 0 ; bbId < bbListCount ; bbId++)
|
||||
// bbList[bbId].cldID = 0;
|
||||
bbList[bbId].needRedraw = true;
|
||||
}
|
||||
|
||||
// flag the impostor for a lazy update
|
||||
void SGBbCache::invalidate(int cldId, int bbId) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return;
|
||||
if( bbList[bbId].cldID != cldId )
|
||||
return;
|
||||
bbList[bbId].needRedraw = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
// Billboard helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _BBCACHE_HXX
|
||||
#define _BBCACHE_HXX
|
||||
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <simgear/screen/extensions.hxx>
|
||||
#include <simgear/screen/RenderTexture.h>
|
||||
|
||||
/**
|
||||
* Billboard helper class.
|
||||
*/
|
||||
class SGBbCache {
|
||||
private:
|
||||
|
||||
/**
|
||||
* storage class for impostors state.
|
||||
*/
|
||||
class bbInfo {
|
||||
public:
|
||||
/// the texture used by this impostor
|
||||
GLuint texID;
|
||||
/// the cloud owning this impostor
|
||||
int cldID;
|
||||
float angleX, angleY;
|
||||
// creation frame number for debug only
|
||||
int frame;
|
||||
/// last time this entry was used
|
||||
int frameUsed;
|
||||
/// dirty flag for lazy rebuild of impostor
|
||||
bool needRedraw;
|
||||
};
|
||||
|
||||
void freeTextureMemory(void);
|
||||
/**
|
||||
* Allocate and initialize the texture pool.
|
||||
* @param count the number of texture to build
|
||||
* @param textureDimension size in pixel of each texture
|
||||
*/
|
||||
bool allocTextureMemory(int count, int textureDimension);
|
||||
|
||||
// a list of impostors
|
||||
bbInfo *bbList;
|
||||
int bbListCount;
|
||||
int textureWH;
|
||||
int cacheSizeKb;
|
||||
|
||||
// for debug only, stats
|
||||
int builtBBCount;
|
||||
// count of generated BB during the current frame
|
||||
int builtBBframe;
|
||||
|
||||
long frameNumber;
|
||||
RenderTexture *rt;
|
||||
bool rtAvailable;
|
||||
|
||||
public:
|
||||
SGBbCache(void);
|
||||
~SGBbCache(void);
|
||||
|
||||
/**
|
||||
* Call this first to initialize the cache.
|
||||
* @param cacheCount the number of texture to allocate
|
||||
*/
|
||||
void init(int cacheCount);
|
||||
|
||||
/**
|
||||
* Free one cache slot, usualy when the cached object is destroyed.
|
||||
* @param bbId the impostor slot
|
||||
* @param cldId the cloud identifier
|
||||
*/
|
||||
void free(int bbId, int cldId);
|
||||
|
||||
/**
|
||||
* Allocate a new impostor.
|
||||
* @param cldId the cloud identifier
|
||||
* @return an impostor slot
|
||||
*/
|
||||
int alloc(int cldId);
|
||||
|
||||
/**
|
||||
* Query the texture name associated with this cloud.
|
||||
* @param bbId the impostor slot
|
||||
* @param cldId the cloud identifier
|
||||
* @return a texture name
|
||||
*/
|
||||
GLuint QueryTexID(int cldId, int bbId);
|
||||
|
||||
/**
|
||||
* Save the rendered texture from the current context to a new texture.
|
||||
* @param bbId the impostor slot
|
||||
*/
|
||||
void setTextureData(int bbId);
|
||||
|
||||
/**
|
||||
* Start the rendering of a billboard in the RTT context.
|
||||
*/
|
||||
void beginCapture(void);
|
||||
|
||||
/**
|
||||
* Adjust the projection matrix of the RTT context to the size of the object.
|
||||
* @param radius radius in meters of the object to draw
|
||||
* @param dist_center distance between viewer and object
|
||||
*/
|
||||
void setRadius(float radius, float dist_center);
|
||||
|
||||
/**
|
||||
* Forget the RTT and go back to the previous rendering context.
|
||||
*/
|
||||
void endCapture(void);
|
||||
|
||||
/**
|
||||
* For debugging only, give the number of frames since the impostor was built.
|
||||
* @param bbId the impostor slot
|
||||
*/
|
||||
int queryImpostorAge(int bbId);
|
||||
|
||||
/**
|
||||
* Can we still use this impostor ? Check versus view angles and load.
|
||||
* @param bbId the impostor slot
|
||||
* @param cloudId the cloud identifier
|
||||
* @param angleY rotation needed to face the impostor
|
||||
* @param angleX rotation needed to face the impostor
|
||||
*/
|
||||
bool isBbValid( int cloudId, int bbId, float angleY, float angleX);
|
||||
|
||||
/**
|
||||
* Save view angles of this billboard.
|
||||
* @param bbId the impostor slot
|
||||
* @param cloudId the cloud identifier
|
||||
* @param angleY rotation needed to face the impostor
|
||||
* @param angleX rotation needed to face the impostor
|
||||
*/
|
||||
void setReference( int cloudId, int bbId, float angleY, float angleX);
|
||||
|
||||
/**
|
||||
* Prepare the cache for the rendering of a new frame.
|
||||
* Do some garbage collect of unused impostors
|
||||
*/
|
||||
void startNewFrame(void);
|
||||
|
||||
/**
|
||||
* Alloc the impostors texture memory given the size of the memory pool.
|
||||
* If sizeKb == 0 then the memory pool is freed and impostors are disabled
|
||||
* @param sizeKb size of the texture pool in K
|
||||
*/
|
||||
bool setCacheSize(int sizeKb);
|
||||
|
||||
/**
|
||||
* Alloc the impostors texture memory given the count and size of texture.
|
||||
* If count == 0 then the memory pool is freed and impostors are disabled
|
||||
* @param count number of texture to allocate
|
||||
* @param textureDimension size of each texture in pixels
|
||||
*/
|
||||
bool setCacheSize(int count, int textureDimension);
|
||||
|
||||
bool isRttAvailable(void) { return rtAvailable; }
|
||||
|
||||
/**
|
||||
* Force all impostors to be rebuilt.
|
||||
*/
|
||||
void invalidateCache(void);
|
||||
|
||||
/**
|
||||
* Flag the impostor for a lazy update.
|
||||
* @param bbId the impostor slot
|
||||
* @param cldId the cloud identifier
|
||||
*/
|
||||
void invalidate(int cldId, int bbId);
|
||||
|
||||
/**
|
||||
* Return the size of the memory pool used by texture impostors.
|
||||
* @return size of the memory pool in Kb
|
||||
*/
|
||||
int queryCacheSize(void);
|
||||
|
||||
/**
|
||||
* Maximum number of impostor to regen each frame.
|
||||
* If we can't update all of them we will do that in the next frame
|
||||
*/
|
||||
int maxImpostorRegenFrame;
|
||||
};
|
||||
|
||||
#endif // _BBCACHE_HXX
|
||||
@@ -21,13 +21,6 @@
|
||||
// #include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined (__APPLE__)
|
||||
// any C++ header file undefines isinf and isnan
|
||||
// so this should be included before <iostream>
|
||||
inline int (isinf)(double r) { return isinf(r); }
|
||||
inline int (isnan)(double r) { return isnan(r); }
|
||||
#endif
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
|
||||
@@ -39,6 +32,8 @@ inline int (isnan)(double r) { return isnan(r); }
|
||||
#include <simgear/screen/extensions.hxx>
|
||||
#include <simgear/screen/texture.hxx>
|
||||
|
||||
#include "newcloud.hxx"
|
||||
#include "cloudfield.hxx"
|
||||
#include "cloud.hxx"
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
@@ -57,7 +52,7 @@ inline int (isnan)(double r) { return isnan(r); }
|
||||
static ssgStateSelector *layer_states[SGCloudLayer::SG_MAX_CLOUD_COVERAGES];
|
||||
static bool state_initialized = false;
|
||||
static bool bump_mapping = false;
|
||||
static int nb_texture_unit = 0;
|
||||
static GLint nb_texture_unit = 0;
|
||||
static ssgTexture *normal_map[SGCloudLayer::SG_MAX_CLOUD_COVERAGES][2] = { 0 };
|
||||
static ssgTexture *color_map[SGCloudLayer::SG_MAX_CLOUD_COVERAGES][2] = { 0 };
|
||||
static GLuint normalization_cube_map;
|
||||
@@ -221,12 +216,14 @@ SGCloudLayer::SGCloudLayer( const string &tex_path ) :
|
||||
layer[0] = layer[1] = layer[2] = layer[3] = NULL;
|
||||
|
||||
layer_root->addKid(layer_transform);
|
||||
layer3D = new SGCloudField;
|
||||
rebuild();
|
||||
}
|
||||
|
||||
// Destructor
|
||||
SGCloudLayer::~SGCloudLayer()
|
||||
{
|
||||
delete layer3D;
|
||||
delete vertices;
|
||||
delete indices;
|
||||
delete layer_root; // deletes layer_transform and layer as well
|
||||
@@ -460,6 +457,8 @@ SGCloudLayer::rebuild()
|
||||
|
||||
layer_states[SG_CLOUD_CLEAR] = 0;
|
||||
}
|
||||
SGNewCloud::loadTextures(texture_path.str());
|
||||
layer3D->buildTestLayer();
|
||||
}
|
||||
|
||||
if ( bump_mapping ) {
|
||||
@@ -837,6 +836,7 @@ bool SGCloudLayer::reposition( sgVec3 p, sgVec3 up, double lon, double lat,
|
||||
last_lat = lat;
|
||||
}
|
||||
|
||||
layer3D->reposition( p, up, lon, lat, alt, dt, direction, speed);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -844,6 +844,9 @@ bool SGCloudLayer::reposition( sgVec3 p, sgVec3 up, double lon, double lat,
|
||||
void SGCloudLayer::draw( bool top ) {
|
||||
if ( layer_coverage != SG_CLOUD_CLEAR ) {
|
||||
|
||||
if ( SGCloudField::enable3D && layer3D->is3D())
|
||||
layer3D->Render();
|
||||
else
|
||||
if ( bump_mapping && enable_bump_mapping ) {
|
||||
|
||||
sgMat4 modelview,
|
||||
|
||||
@@ -39,6 +39,7 @@ SG_USING_STD(string);
|
||||
// SG_USING_STD(cout);
|
||||
// SG_USING_STD(endl);
|
||||
|
||||
class SGCloudField;
|
||||
|
||||
/**
|
||||
* A class layer to model a single cloud layer
|
||||
@@ -183,6 +184,9 @@ public:
|
||||
|
||||
static bool enable_bump_mapping;
|
||||
|
||||
/** return the 3D layer cloud associated with this 2D layer */
|
||||
SGCloudField *get_layer3D(void) { return layer3D; }
|
||||
|
||||
private:
|
||||
|
||||
struct CloudVertex {
|
||||
@@ -225,6 +229,8 @@ private:
|
||||
// position, not view position
|
||||
// double xoff, yoff;
|
||||
double last_lon, last_lat, last_course;
|
||||
|
||||
SGCloudField *layer3D;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,493 @@
|
||||
// a layer of 3d clouds
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/math/polar3d.hxx>
|
||||
|
||||
#include STL_ALGORITHM
|
||||
#include <vector>
|
||||
|
||||
SG_USING_STD(vector);
|
||||
|
||||
#include <simgear/environment/visual_enviro.hxx>
|
||||
#include "sky.hxx"
|
||||
#include "newcloud.hxx"
|
||||
#include "cloudfield.hxx"
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
#define isnan(x) _isnan(x)
|
||||
#endif
|
||||
|
||||
#if defined (__FreeBSD__)
|
||||
# if __FreeBSD_version < 500000
|
||||
extern "C" {
|
||||
inline int isnan(double r) { return !(r <= 0 || r >= 0); }
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern SGSky *thesky;
|
||||
|
||||
static list_of_culledCloud inViewClouds;
|
||||
|
||||
// visibility distance for clouds in meters
|
||||
float SGCloudField::CloudVis = 25000.0f;
|
||||
bool SGCloudField::enable3D = false;
|
||||
// fieldSize must be > CloudVis or we can destroy the impostor cache
|
||||
// a cloud must only be seen once or the impostor will be generated for each of his positions
|
||||
double SGCloudField::fieldSize = 50000.0;
|
||||
float SGCloudField::density = 100.0;
|
||||
double SGCloudField::timer_dt = 0.0;
|
||||
sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
|
||||
|
||||
static int last_cache_size = 1*1024;
|
||||
static int cacheResolution = 64;
|
||||
static sgVec3 last_sunlight={0.0f, 0.0f, 0.0f};
|
||||
|
||||
int SGCloudField::get_CacheResolution(void) {
|
||||
return cacheResolution;
|
||||
}
|
||||
|
||||
void SGCloudField::set_CacheResolution(int resolutionPixels) {
|
||||
if(cacheResolution == resolutionPixels)
|
||||
return;
|
||||
cacheResolution = resolutionPixels;
|
||||
if(enable3D) {
|
||||
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
|
||||
if(count == 0)
|
||||
count = 1;
|
||||
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
|
||||
}
|
||||
}
|
||||
|
||||
int SGCloudField::get_CacheSize(void) {
|
||||
return SGNewCloud::cldCache->queryCacheSize();
|
||||
}
|
||||
|
||||
void SGCloudField::set_CacheSize(int sizeKb) {
|
||||
// apply in rendering option dialog
|
||||
if(last_cache_size == sizeKb)
|
||||
return;
|
||||
if(sizeKb == 0)
|
||||
return;
|
||||
if(sizeKb)
|
||||
last_cache_size = sizeKb;
|
||||
if(enable3D) {
|
||||
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
|
||||
if(count == 0)
|
||||
count = 1;
|
||||
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
|
||||
}
|
||||
}
|
||||
void SGCloudField::set_CloudVis(float distance) {
|
||||
if( distance <= fieldSize )
|
||||
SGCloudField::CloudVis = distance;
|
||||
}
|
||||
void SGCloudField::set_density(float density) {
|
||||
SGCloudField::density = density;
|
||||
}
|
||||
void SGCloudField::set_enable3dClouds(bool enable) {
|
||||
if(enable3D == enable)
|
||||
return;
|
||||
enable3D = enable;
|
||||
if(enable) {
|
||||
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
|
||||
if(count == 0)
|
||||
count = 1;
|
||||
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
|
||||
} else {
|
||||
SGNewCloud::cldCache->setCacheSize(0);
|
||||
}
|
||||
}
|
||||
|
||||
// reposition the cloud layer at the specified origin and orientation
|
||||
void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed) {
|
||||
sgMat4 T1, LON, LAT;
|
||||
sgVec3 axis;
|
||||
|
||||
sgMakeTransMat4( T1, p );
|
||||
|
||||
sgSetVec3( axis, 0.0, 0.0, 1.0 );
|
||||
sgMakeRotMat4( LON, lon * SGD_RADIANS_TO_DEGREES, axis );
|
||||
|
||||
sgSetVec3( axis, 0.0, 1.0, 0.0 );
|
||||
sgMakeRotMat4( LAT, 90.0 - lat * SGD_RADIANS_TO_DEGREES, axis );
|
||||
|
||||
sgMat4 TRANSFORM;
|
||||
|
||||
sgCopyMat4( TRANSFORM, T1 );
|
||||
sgPreMultMat4( TRANSFORM, LON );
|
||||
sgPreMultMat4( TRANSFORM, LAT );
|
||||
|
||||
sgCoord layerpos;
|
||||
sgSetCoord( &layerpos, TRANSFORM );
|
||||
|
||||
sgMakeCoordMat4( transform, &layerpos );
|
||||
|
||||
|
||||
this->alt = alt;
|
||||
|
||||
// simulate clouds movement from wind
|
||||
double sp_dist = speed*dt;
|
||||
if (sp_dist > 0) {
|
||||
double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
|
||||
double by = sin((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
|
||||
relative_position[SG_X] += bx;
|
||||
relative_position[SG_Y] += by;
|
||||
}
|
||||
|
||||
if ( lon != last_lon || lat != last_lat || sp_dist != 0 ) {
|
||||
Point3D start( last_lon, last_lat, 0.0 );
|
||||
Point3D dest( lon, lat, 0.0 );
|
||||
double course = 0.0, dist = 0.0;
|
||||
|
||||
calc_gc_course_dist( dest, start, &course, &dist );
|
||||
// if start and dest are too close together,
|
||||
// calc_gc_course_dist() can return a course of "nan". If
|
||||
// this happens, lets just use the last known good course.
|
||||
// This is a hack, and it would probably be better to make
|
||||
// calc_gc_course_dist() more robust.
|
||||
if ( isnan(course) ) {
|
||||
course = last_course;
|
||||
} else {
|
||||
last_course = course;
|
||||
}
|
||||
|
||||
// calculate cloud movement due to external forces
|
||||
double ax = 0.0, ay = 0.0;
|
||||
|
||||
if (dist > 0.0) {
|
||||
ax = cos(course) * dist;
|
||||
ay = sin(course) * dist;
|
||||
}
|
||||
|
||||
deltax += ax;
|
||||
deltay += ay;
|
||||
|
||||
last_lon = lon;
|
||||
last_lat = lat;
|
||||
}
|
||||
|
||||
|
||||
// correct the frustum with the right far plane
|
||||
ssgContext *context = ssgGetCurrentContext();
|
||||
frustum = *context->getFrustum();
|
||||
|
||||
float w, h;
|
||||
sgEnviro.getFOV( w, h );
|
||||
frustum.setFOV( w, h );
|
||||
frustum.setNearFar(1.0, CloudVis);
|
||||
timer_dt = dt;
|
||||
}
|
||||
|
||||
SGCloudField::SGCloudField() :
|
||||
draw_in_3d(true),
|
||||
last_density(0.0),
|
||||
deltax(0.0),
|
||||
deltay(0.0),
|
||||
last_course(0.0)
|
||||
{
|
||||
sgSetVec3( relative_position, 0,0,0);
|
||||
theField.reserve(200);
|
||||
inViewClouds.reserve(200);
|
||||
sg_srandom_time_10();
|
||||
}
|
||||
|
||||
SGCloudField::~SGCloudField() {
|
||||
list_of_Cloud::iterator iCloud;
|
||||
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
|
||||
delete iCloud->aCloud;
|
||||
}
|
||||
theField.clear();
|
||||
}
|
||||
|
||||
|
||||
void SGCloudField::clear(void) {
|
||||
list_of_Cloud::iterator iCloud;
|
||||
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
|
||||
delete iCloud->aCloud;
|
||||
}
|
||||
theField.clear();
|
||||
// force a recompute of density on first redraw
|
||||
last_density = 0.0;
|
||||
// true to come back in set density after layer is built
|
||||
draw_in_3d = true;
|
||||
}
|
||||
|
||||
// use a table or else we see poping when moving the slider...
|
||||
static int densTable[][10] = {
|
||||
{0,0,0,0,0,0,0,0,0,0},
|
||||
{1,0,0,0,0,0,0,0,0,0},
|
||||
{1,0,0,0,1,0,0,0,0,0},
|
||||
{1,0,0,0,1,0,0,1,0,0}, // 30%
|
||||
{1,0,1,0,1,0,0,1,0,0},
|
||||
{1,0,1,0,1,0,1,1,0,0}, // 50%
|
||||
{1,0,1,0,1,0,1,1,0,1},
|
||||
{1,0,1,1,1,0,1,1,0,1}, // 70%
|
||||
{1,1,1,1,1,0,1,1,0,1},
|
||||
{1,1,1,1,1,0,1,1,1,1}, // 90%
|
||||
{1,1,1,1,1,1,1,1,1,1}
|
||||
};
|
||||
|
||||
// set the visible flag depending on density
|
||||
void SGCloudField::applyDensity(void) {
|
||||
int row = (int) (density / 10.0);
|
||||
int col = 0;
|
||||
sgBox fieldBox;
|
||||
|
||||
list_of_Cloud::iterator iCloud;
|
||||
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
|
||||
if(++col > 9)
|
||||
col = 0;
|
||||
if( densTable[row][col] ) {
|
||||
iCloud->visible = true;
|
||||
fieldBox.extend( *iCloud->aCloud->getCenter() );
|
||||
} else
|
||||
iCloud->visible = false;
|
||||
}
|
||||
last_density = density;
|
||||
draw_in_3d = ( theField.size() != 0);
|
||||
sgVec3 center;
|
||||
sgSubVec3( center, fieldBox.getMax(), fieldBox.getMin() );
|
||||
sgScaleVec3( center, 0.5f );
|
||||
center[1] = 0.0f;
|
||||
field_sphere.setCenter( center );
|
||||
field_sphere.setRadius( fieldSize * 0.5f * 1.414f );
|
||||
}
|
||||
|
||||
// add one cloud, data is not copied, ownership given
|
||||
void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) {
|
||||
Cloud cl;
|
||||
cl.aCloud = cloud;
|
||||
cl.visible = true;
|
||||
cloud->SetPos( pos );
|
||||
sgCopyVec3( cl.pos, *cloud->getCenter() );
|
||||
theField.push_back( cl );
|
||||
}
|
||||
|
||||
|
||||
static float Rnd(float n) {
|
||||
return n * (-0.5f + sg_random());
|
||||
}
|
||||
|
||||
// for debug only
|
||||
// build a field of cloud of size 25x25 km, its a grid of 11x11 clouds
|
||||
void SGCloudField::buildTestLayer(void) {
|
||||
|
||||
const float s = 2250.0f;
|
||||
|
||||
for( int z = -5 ; z <= 5 ; z++) {
|
||||
for( int x = -5 ; x <= 5 ; x++ ) {
|
||||
SGNewCloud *cloud = new SGNewCloud(SGNewCloud::CLFamilly_cu);
|
||||
cloud->new_cu();
|
||||
sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s};
|
||||
addCloud(pos, cloud);
|
||||
}
|
||||
}
|
||||
applyDensity();
|
||||
}
|
||||
|
||||
// cull all clouds of a tiled field
|
||||
void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) {
|
||||
list_of_Cloud::iterator iCloud;
|
||||
|
||||
sgSphere tile_sphere;
|
||||
tile_sphere.setRadius( field_sphere.getRadius() );
|
||||
sgVec3 tile_center;
|
||||
sgSubVec3( tile_center, field_sphere.getCenter(), eyePos );
|
||||
tile_sphere.setCenter( tile_center );
|
||||
tile_sphere.orthoXform(mat);
|
||||
if( frustum.contains( & tile_sphere ) == SG_OUTSIDE )
|
||||
return;
|
||||
|
||||
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
|
||||
sgVec3 dist;
|
||||
sgSphere sphere;
|
||||
if( ! iCloud->visible )
|
||||
continue;
|
||||
sgSubVec3( dist, iCloud->pos, eyePos );
|
||||
sphere.setCenter(dist[0], dist[2], dist[1] + eyePos[1]);
|
||||
float radius = iCloud->aCloud->getRadius();
|
||||
sphere.setRadius(radius);
|
||||
sphere.orthoXform(mat);
|
||||
if( frustum.contains( & sphere ) != SG_OUTSIDE ) {
|
||||
float squareDist = dist[0]*dist[0] + dist[1]*dist[1] + dist[2]*dist[2];
|
||||
culledCloud tmp;
|
||||
tmp.aCloud = iCloud->aCloud;
|
||||
sgCopyVec3( tmp.eyePos, eyePos );
|
||||
// save distance for later sort, opposite distance because we want back to front
|
||||
tmp.dist = - squareDist;
|
||||
tmp.heading = -SG_PI/2.0 - atan2( dist[0], dist[2] ); // + SG_PI;
|
||||
tmp.alt = iCloud->pos[1];
|
||||
inViewClouds.push_back(tmp);
|
||||
if( squareDist - radius*radius < 100*100 )
|
||||
sgEnviro.set_view_in_cloud(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Render a cloud field
|
||||
// because no field can have an infinite size (and we don't want to reach his border)
|
||||
// we draw this field and adjacent fields.
|
||||
// adjacent fields are not real, its the same field displaced by some offset
|
||||
void SGCloudField::Render(void) {
|
||||
sgVec3 eyePos;
|
||||
double relx, rely;
|
||||
|
||||
if( ! enable3D )
|
||||
return;
|
||||
|
||||
if( last_density != density ) {
|
||||
last_density = density;
|
||||
applyDensity();
|
||||
}
|
||||
|
||||
if( ! draw_in_3d )
|
||||
return;
|
||||
|
||||
if( ! SGNewCloud::cldCache->isRttAvailable() )
|
||||
return;
|
||||
|
||||
inViewClouds.clear();
|
||||
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
sgMat4 modelview, tmp, invtrans;
|
||||
|
||||
// try to find the sun position
|
||||
sgTransposeNegateMat4( invtrans, transform );
|
||||
sgVec3 lightVec;
|
||||
ssgGetLight( 0 )->getPosition( lightVec );
|
||||
sgXformVec3( lightVec, invtrans );
|
||||
|
||||
sgSetVec3( SGNewCloud::modelSunDir, lightVec[0], lightVec[2], lightVec[1]);
|
||||
// try to find the lighting data (not accurate)
|
||||
sgVec4 diffuse, ambient;
|
||||
ssgGetLight( 0 )->getColour( GL_DIFFUSE, diffuse );
|
||||
ssgGetLight( 0 )->getColour( GL_AMBIENT, ambient );
|
||||
// sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 1.0f);
|
||||
sgScaleVec3 ( SGNewCloud::ambLight, ambient , 1.1f);
|
||||
// trying something else : clouds are more yellow/red at dawn/dusk
|
||||
// and added a bit of blue ambient
|
||||
float *sun_color = thesky->get_sun_color();
|
||||
sgScaleVec3 ( SGNewCloud::sunlight, sun_color , 0.4f);
|
||||
SGNewCloud::ambLight[2] += 0.1f;
|
||||
|
||||
sgVec3 delta_light;
|
||||
sgSubVec3(delta_light, last_sunlight, SGNewCloud::sunlight);
|
||||
if( (fabs(delta_light[0]) + fabs(delta_light[1]) + fabs(delta_light[2])) > 0.05f ) {
|
||||
sgCopyVec3( last_sunlight, SGNewCloud::sunlight );
|
||||
// force the redraw of all the impostors
|
||||
SGNewCloud::cldCache->invalidateCache();
|
||||
}
|
||||
|
||||
// voodoo things on the matrix stack
|
||||
ssgGetModelviewMatrix( modelview );
|
||||
sgCopyMat4( tmp, transform );
|
||||
sgPostMultMat4( tmp, modelview );
|
||||
|
||||
// cloud fields are tiled on the flat earth
|
||||
// compute the position in the tile
|
||||
relx = fmod( deltax + relative_position[SG_X], fieldSize );
|
||||
rely = fmod( deltay + relative_position[SG_Y], fieldSize );
|
||||
|
||||
relx = fmod( relx + fieldSize, fieldSize );
|
||||
rely = fmod( rely + fieldSize, fieldSize );
|
||||
sgSetVec3( eyePos, relx, alt, rely);
|
||||
|
||||
sgSetVec3( view_X, tmp[0][0], tmp[1][0], tmp[2][0] );
|
||||
sgSetVec3( view_Y, tmp[0][1], tmp[1][1], tmp[2][1] );
|
||||
sgSetVec3( view_vec, tmp[0][2], tmp[1][2], tmp[2][2] );
|
||||
|
||||
ssgLoadModelviewMatrix( tmp );
|
||||
|
||||
/* flat earth
|
||||
|
||||
^
|
||||
|
|
||||
| FFF
|
||||
| FoF
|
||||
| FFF
|
||||
|
|
||||
O----------->
|
||||
o = we are here
|
||||
F = adjacent fields
|
||||
*/
|
||||
|
||||
for(int x = -1 ; x <= 1 ; x++)
|
||||
for(int y = -1 ; y <= 1 ; y++ ) {
|
||||
sgVec3 fieldPos;
|
||||
// pretend we are not where we are
|
||||
sgSetVec3(fieldPos, eyePos[0] + x*fieldSize, eyePos[1], eyePos[2] + y*fieldSize);
|
||||
cullClouds(fieldPos, tmp);
|
||||
}
|
||||
// sort all visible clouds back to front (because of transparency)
|
||||
std::sort( inViewClouds.begin(), inViewClouds.end() );
|
||||
|
||||
// TODO:push states
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.0f);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask( GL_FALSE );
|
||||
glEnable(GL_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
|
||||
glEnable( GL_TEXTURE_2D );
|
||||
glDisable( GL_FOG );
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
// test data: field = 11x11 cloud, 9 fields
|
||||
// depending on position and view direction, perhaps 40 to 60 clouds not culled
|
||||
list_of_culledCloud::iterator iCloud;
|
||||
for( iCloud = inViewClouds.begin() ; iCloud != inViewClouds.end() ; iCloud++ ) {
|
||||
// iCloud->aCloud->drawContainers();
|
||||
iCloud->aCloud->Render(iCloud->eyePos);
|
||||
sgEnviro.callback_cloud(iCloud->heading, iCloud->alt,
|
||||
iCloud->aCloud->getRadius(), iCloud->aCloud->getFamilly(), - iCloud->dist, iCloud->aCloud->getId());
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
|
||||
glEnable( GL_FOG );
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
ssgLoadModelviewMatrix( modelview );
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
// a layer of 3d clouds
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _CLOUDFIELD_HXX
|
||||
#define _CLOUDFIELD_HXX
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <simgear/compiler.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
SG_USING_STD(vector);
|
||||
|
||||
class SGNewCloud;
|
||||
|
||||
class culledCloud {
|
||||
public:
|
||||
SGNewCloud *aCloud;
|
||||
sgVec3 eyePos;
|
||||
float dist;
|
||||
float heading;
|
||||
float alt;
|
||||
bool operator<(const culledCloud &b) const {
|
||||
return (this->dist < b.dist);
|
||||
}
|
||||
};
|
||||
typedef vector<culledCloud> list_of_culledCloud;
|
||||
|
||||
/**
|
||||
* A layer of 3D clouds.
|
||||
*/
|
||||
class SGCloudField {
|
||||
|
||||
private:
|
||||
class Cloud {
|
||||
public:
|
||||
SGNewCloud *aCloud;
|
||||
sgVec3 pos;
|
||||
bool visible;
|
||||
};
|
||||
|
||||
|
||||
typedef vector<Cloud> list_of_Cloud;
|
||||
|
||||
// cull all clouds of a tiled field
|
||||
void cullClouds(sgVec3 eyePos, sgMat4 mat);
|
||||
|
||||
void applyDensity(void);
|
||||
|
||||
list_of_Cloud theField;
|
||||
// this is a relative position only, with that we can move all clouds at once
|
||||
sgVec3 relative_position;
|
||||
// double lon, lat;
|
||||
|
||||
sgFrustum frustum;
|
||||
|
||||
sgMat4 transform;
|
||||
double deltax, deltay, alt;
|
||||
double last_lon, last_lat, last_course;
|
||||
sgSphere field_sphere;
|
||||
float last_density;
|
||||
bool draw_in_3d;
|
||||
|
||||
public:
|
||||
|
||||
SGCloudField();
|
||||
~SGCloudField();
|
||||
|
||||
void clear(void);
|
||||
|
||||
// add one cloud, data is not copied, ownership given
|
||||
void addCloud( sgVec3 pos, SGNewCloud *cloud);
|
||||
|
||||
// for debug only
|
||||
void buildTestLayer(void);
|
||||
|
||||
// Render a cloud field
|
||||
void Render(void);
|
||||
|
||||
// reposition the cloud layer at the specified origin and orientation
|
||||
void reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed);
|
||||
|
||||
bool is3D(void) { return draw_in_3d; }
|
||||
|
||||
// visibility distance for clouds in meters
|
||||
static float CloudVis;
|
||||
|
||||
static sgVec3 view_vec, view_X, view_Y;
|
||||
|
||||
static float density;
|
||||
static double timer_dt;
|
||||
static double fieldSize;
|
||||
static bool enable3D;
|
||||
|
||||
// return the size of the memory pool used by texture impostors
|
||||
static int get_CacheSize(void);
|
||||
static int get_CacheResolution(void);
|
||||
static float get_CloudVis(void) { return CloudVis; }
|
||||
static float get_density(void) { return density; }
|
||||
static bool get_enable3dClouds(void) { return enable3D; }
|
||||
|
||||
static void set_CacheSize(int sizeKb);
|
||||
static void set_CacheResolution(int resolutionPixels);
|
||||
static void set_CloudVis(float distance);
|
||||
static void set_density(float density);
|
||||
static void set_enable3dClouds(bool enable);
|
||||
};
|
||||
|
||||
#endif // _CLOUDFIELD_HXX
|
||||
@@ -1,3 +0,0 @@
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
@@ -1,54 +0,0 @@
|
||||
includedir = @includedir@/scene/sky/clouds3d
|
||||
|
||||
# enable the following line once extgl.c get's added to the distro
|
||||
EXTRA_DIST = extgl.c extgl.h
|
||||
|
||||
if EXTGL_NEEDED
|
||||
EXTGL_SOURCE = extgl.c extgl.h
|
||||
else
|
||||
EXTGL_SOURCE =
|
||||
endif
|
||||
|
||||
lib_LIBRARIES = libsgclouds3d.a
|
||||
|
||||
include_HEADERS = \
|
||||
SkySceneLoader.hpp \
|
||||
SkyUtil.hpp
|
||||
|
||||
libsgclouds3d_a_SOURCES = \
|
||||
$(EXTGL_SOURCE) \
|
||||
vec3fv.cpp vec3fv.hpp vec3f.hpp vec4f.hpp vec2f.hpp \
|
||||
mat16fv.cpp mat16fv.hpp \
|
||||
mat33.hpp mat33impl.hpp \
|
||||
mat44.hpp mat44impl.hpp \
|
||||
tri.cpp tri.hpp \
|
||||
plane.cpp plane.hpp \
|
||||
camera.cpp camera.hpp \
|
||||
camutils.cpp camutils.hpp \
|
||||
glut_shapes.c glut_shapes.h \
|
||||
minmaxbox.cpp minmaxbox.hpp \
|
||||
SkyAABBTree.hpp \
|
||||
SkyArchive.cpp SkyArchive.hpp \
|
||||
SkyBoundingVolume.hpp \
|
||||
SkyBVTree.hpp SkyBVTreeSplitter.hpp \
|
||||
SkyCloud.cpp SkyCloud.hpp \
|
||||
SkyCloudParticle.hpp \
|
||||
SkyContext.cpp SkyContext.hpp \
|
||||
SkyDynamicTextureManager.cpp SkyDynamicTextureManager.hpp \
|
||||
SkyLight.cpp SkyLight.hpp \
|
||||
SkyMaterial.cpp SkyMaterial.hpp \
|
||||
SkyMinMaxBox.cpp SkyMinMaxBox.hpp \
|
||||
SkyRenderable.hpp \
|
||||
SkyRenderableInstance.hpp \
|
||||
SkyRenderableInstanceCloud.cpp SkyRenderableInstanceCloud.hpp \
|
||||
SkyRenderableInstanceGeneric.hpp \
|
||||
SkyRenderableInstanceGroup.cpp SkyRenderableInstanceGroup.hpp \
|
||||
SkySceneLoader.cpp \
|
||||
SkySceneManager.cpp SkySceneManager.hpp \
|
||||
SkySingleton.hpp \
|
||||
SkyTexture.hpp \
|
||||
SkyTextureManager.cpp SkyTextureManager.hpp \
|
||||
SkyTextureState.cpp SkyTextureState.hpp \
|
||||
SkyUtil.cpp
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
@@ -1,19 +0,0 @@
|
||||
//============================================================================
|
||||
// File : SkyAABBTree.hpp
|
||||
//
|
||||
// Author : Wesley Hunt
|
||||
//
|
||||
// Content : axis-aligned bounding box tree
|
||||
//
|
||||
//============================================================================
|
||||
#ifndef __SKYAABBTREE_HPP__
|
||||
#define __SKYAABBTREE_HPP__
|
||||
|
||||
#include "SkyBVTree.hpp"
|
||||
#include "SkyBVTreeSplitter.hpp"
|
||||
|
||||
template <class object>
|
||||
class SkyAABBTree : public SkyBVTree<object, SkyMinMaxBox, SkyAABBTreeSplitter<object> >
|
||||
{};
|
||||
|
||||
#endif //__SKYAABBTREE_HPP__
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,243 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File : SkyArchive.hpp
|
||||
//------------------------------------------------------------------------------
|
||||
// SkyWorks : Copyright 2002 Mark J. Harris and
|
||||
// The University of North Carolina at Chapel Hill
|
||||
//------------------------------------------------------------------------------
|
||||
// Permission to use, copy, modify, distribute and sell this software and its
|
||||
// documentation for any purpose is hereby granted without fee, provided that
|
||||
// the above copyright notice appear in all copies and that both that copyright
|
||||
// notice and this permission notice appear in supporting documentation.
|
||||
// Binaries may be compiled with this software without any royalties or
|
||||
// restrictions.
|
||||
//
|
||||
// The author(s) and The University of North Carolina at Chapel Hill make no
|
||||
// representations about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or
|
||||
// implied warranty.
|
||||
/**
|
||||
* @file SkyArchive.hpp
|
||||
*
|
||||
* A hierarchical archive Class for storing data.
|
||||
*/
|
||||
#ifndef __SKYARCHIVE_HPP__
|
||||
#define __SKYARCHIVE_HPP__
|
||||
|
||||
// #pragma warning( disable : 4786 )
|
||||
|
||||
#include "vec2f.hpp"
|
||||
#include "vec3f.hpp"
|
||||
#include "vec4f.hpp"
|
||||
#include "SkyUtil.hpp"
|
||||
|
||||
#include <map> // for std::multimap
|
||||
|
||||
//! Types supported by the archive system
|
||||
enum SkyArchiveTypeCode
|
||||
{
|
||||
BOOL_TYPE,
|
||||
INT8_TYPE,
|
||||
INT16_TYPE,
|
||||
INT32_TYPE,
|
||||
UINT8_TYPE,
|
||||
UINT16_TYPE,
|
||||
UINT32_TYPE,
|
||||
FLOAT32_TYPE,
|
||||
FLOAT64_TYPE,
|
||||
STRING_TYPE,
|
||||
VEC2F_TYPE,
|
||||
VEC3F_TYPE,
|
||||
VEC4F_TYPE,
|
||||
ARCHIVE_TYPE,
|
||||
ANY_TYPE,
|
||||
NULL_TYPE
|
||||
};
|
||||
|
||||
struct SkyArchiveEntry;
|
||||
|
||||
struct StringLessFunctor
|
||||
{
|
||||
bool operator() (const char* p1, const char* p2) const
|
||||
{
|
||||
return ::strcmp( p1, p2) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// Class : SkyArchive
|
||||
//
|
||||
//! A simple hierarchical archive file useful for loading and saving data.
|
||||
//
|
||||
/*! SkyArchive bundles information so that an application can store,
|
||||
manipulate, and retrieve data in a storage-independent manner. Information
|
||||
stored in an SkyArchive file can be modified without breaking
|
||||
compatibility with the code that retrieves the data. In essence, it can be
|
||||
thought of as a very basic database mechanism.
|
||||
|
||||
A SkyArchive is simply a container. The class defines methods that allow
|
||||
you to put information in a SkyArchive, determine the information in a
|
||||
SkyArchive, and retrieve information from a SkyArchive. It's important
|
||||
to note that the SkyArchive is a recursive storage mechanism; a
|
||||
SkyArchive itself can hold one or more other SkyArchives.
|
||||
|
||||
Data are added to an archive in fields. The datum in a field is associated
|
||||
with a name, number of bytes, and a type code. The name can be anything you
|
||||
choose and is not required to be unique. The number of bytes must be accurate.
|
||||
The type code must be one of the SkyArchiveTypeCode enums. Several of the Add
|
||||
functions have been specialized for the common base types. It isn't necessary
|
||||
to provide the number of bytes when using the specialized functions, since it can be
|
||||
inferred from the type code.
|
||||
|
||||
The functions that retrieve fields from an archive are similar to the ones
|
||||
that add data, only their roles are reversed. As with the Add functions,
|
||||
there are several specialized functions for the common base types while
|
||||
custom information can be retrieved using the generic FindData function.
|
||||
|
||||
Querying the contents of an archive is provided through the GetInfo
|
||||
functions. These functions are important as they allow you to write
|
||||
code that can intelligently determine how to retrieve information at
|
||||
run-time: you no longer have to hardcode the order in which you retrieve
|
||||
data from your files.
|
||||
|
||||
archive data fields are held in using an STL multimap. The multimap key
|
||||
is a QString (field name) and the data is held in a SkyArchiveEntry
|
||||
structure (see SkyArchive.cpp for details of this structure).
|
||||
The fields are stored in alphabetical order based on the key names.
|
||||
*/
|
||||
class SkyArchive
|
||||
{
|
||||
public:
|
||||
//=========================================================================
|
||||
// Creation & Destruction
|
||||
//=========================================================================
|
||||
// Empty archive: no name, no data fields.
|
||||
SkyArchive();
|
||||
// Creates a named archive with no data fields.
|
||||
SkyArchive( const char* pName);
|
||||
// Deep copy the contents of one archive to another.
|
||||
SkyArchive( const SkyArchive& src);
|
||||
// Deep copy the contents of one archive to another.
|
||||
SkyArchive& operator=( const SkyArchive& src);
|
||||
|
||||
~SkyArchive();
|
||||
|
||||
//=========================================================================
|
||||
// Basic SkyArchive Information
|
||||
//=========================================================================
|
||||
// Returns true if the archive contains no data fields.
|
||||
bool IsEmpty() const;
|
||||
//! Returns the archive's name.
|
||||
const char* GetName() const { return _pName; };
|
||||
|
||||
//=========================================================================
|
||||
// Adding Content to SkyArchive
|
||||
//=========================================================================
|
||||
// Adds a new datafield to the archive.
|
||||
SKYRESULT AddData(const char* pName,
|
||||
SkyArchiveTypeCode eType,
|
||||
const void* pData,
|
||||
unsigned int iNumBytes,
|
||||
unsigned int iNumItems = 1);
|
||||
|
||||
SKYRESULT AddBool( const char* pName, bool aBool);
|
||||
SKYRESULT AddInt8( const char* pName, char anInt8);
|
||||
SKYRESULT AddInt16( const char* pName, short anInt16);
|
||||
SKYRESULT AddInt32( const char* pName, int anInt32);
|
||||
SKYRESULT AddUInt8( const char* pName, unsigned char anUInt8);
|
||||
SKYRESULT AddUInt16( const char* pName, unsigned short anUInt16);
|
||||
SKYRESULT AddUInt32( const char* pName, unsigned int anUInt32);
|
||||
SKYRESULT AddFloat32( const char* pName, float aFloat32);
|
||||
SKYRESULT AddFloat64( const char* pName, double aFloat64);
|
||||
SKYRESULT AddString( const char* pName, const char* pString);
|
||||
|
||||
SKYRESULT AddArchive( const SkyArchive& anArchive);
|
||||
|
||||
// Vector types (MJH:: only supports float versions for now!!!)
|
||||
SKYRESULT AddVec2f( const char* pName, const Vec2f& aPoint2f);
|
||||
SKYRESULT AddVec3f( const char* pName, const Vec3f& aPoint3f);
|
||||
SKYRESULT AddVec4f( const char* pName, const Vec4f& aPoint4f);
|
||||
|
||||
//=========================================================================
|
||||
// Retrieving Content from SkyArchive
|
||||
//=========================================================================
|
||||
// Retrieves the specified datafield the archive, if it exists.
|
||||
SKYRESULT FindData( const char* pName,
|
||||
SkyArchiveTypeCode eType,
|
||||
void** const pData,
|
||||
unsigned int* pNumBytes,
|
||||
unsigned int index = 0) const;
|
||||
|
||||
SKYRESULT FindBool( const char* pName, bool* pBool, unsigned int index = 0) const;
|
||||
SKYRESULT FindInt8( const char* pName, char* pInt8, unsigned int index = 0) const;
|
||||
SKYRESULT FindInt16( const char* pName, short* pInt16, unsigned int index = 0) const;
|
||||
SKYRESULT FindInt32( const char* pName, int* pInt32, unsigned int index = 0) const;
|
||||
SKYRESULT FindUInt8( const char* pName, unsigned char* pUInt8, unsigned int index = 0) const;
|
||||
SKYRESULT FindUInt16( const char* pName, unsigned short* pUInt16, unsigned int index = 0) const;
|
||||
SKYRESULT FindUInt32( const char* pName, unsigned int* pUInt32, unsigned int index = 0) const;
|
||||
SKYRESULT FindFloat32(const char* pName, float* pFloat32, unsigned int index = 0) const;
|
||||
SKYRESULT FindFloat64(const char* pName, double* pFloat64, unsigned int index = 0) const;
|
||||
SKYRESULT FindString( const char* pName, char** const pString, unsigned int index = 0) const;
|
||||
SKYRESULT FindArchive(const char* pName, SkyArchive* pArchive, unsigned int index = 0) const;
|
||||
|
||||
SKYRESULT FindVec2f( const char* pName, Vec2f* pVec2f, unsigned int index = 0) const;
|
||||
SKYRESULT FindVec3f( const char* pName, Vec3f* pVec3f, unsigned int index = 0) const;
|
||||
SKYRESULT FindVec4f( const char* pName, Vec4f* pVec4f, unsigned int index = 0) const;
|
||||
|
||||
SKYRESULT AccessArchive(const char* pName, SkyArchive** pArchive, unsigned int index = 0) const;
|
||||
|
||||
//=========================================================================
|
||||
// Querying Contents of SkyArchive
|
||||
//=========================================================================
|
||||
// Computes the number of fields that contain the given name and type.
|
||||
SKYRESULT GetInfo(const char* pName,
|
||||
SkyArchiveTypeCode eType,
|
||||
unsigned int* pNumFound = NULL) const;
|
||||
|
||||
// Returns information about the key at the specified index.
|
||||
SKYRESULT GetInfo(unsigned int iNameIndex,
|
||||
char** pNameFound,
|
||||
SkyArchiveTypeCode* pTypeCode,
|
||||
unsigned int* pNumFound);
|
||||
|
||||
// Computes the number of unique key names in _dataTableable.
|
||||
unsigned int GetNumUniqueNames() const;
|
||||
|
||||
|
||||
// Remove the contents of the SkyArchive.
|
||||
SKYRESULT MakeEmpty();
|
||||
|
||||
// Loads the contents from a file.
|
||||
SKYRESULT Load(const char* pFileName);
|
||||
|
||||
// Commits the contents of a SkyArchive to file storage.
|
||||
SKYRESULT Save(const char* pFileName) const;
|
||||
|
||||
private:
|
||||
|
||||
char* _pName; // this archive's name
|
||||
|
||||
//=========================================================================
|
||||
// Data storage
|
||||
//=========================================================================
|
||||
typedef std::multimap<char*, SkyArchiveEntry*, StringLessFunctor> SkyArchiveMMap;
|
||||
typedef SkyArchiveMMap::const_iterator SkyMMapConstIter;
|
||||
typedef SkyArchiveMMap::iterator SkyMMapIter;
|
||||
|
||||
SkyArchiveMMap _dataTable; // this is where the data reside.
|
||||
|
||||
// Performs a deep-copy of one archive's archive_mmap_t to another.
|
||||
void _CopyDataTable( const SkyArchiveMMap& src);
|
||||
|
||||
// Locates an archive entry in _dataTable
|
||||
const SkyArchiveEntry* _FindEntry( const char* pName,
|
||||
unsigned int index,
|
||||
SkyArchiveTypeCode eType) const;
|
||||
|
||||
// Saves the archive to a file stream.
|
||||
SKYRESULT _Save(FILE* pDestFile) const;
|
||||
// Initializes the archive from a file stream.
|
||||
SKYRESULT _Load(FILE* pSrcFile);
|
||||
};
|
||||
|
||||
#endif //__SKYARCHIVE_HPP__
|
||||
@@ -1,297 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File : SkyBVTree.hpp
|
||||
//------------------------------------------------------------------------------
|
||||
// Empyrean / SkyWorks : Copyright 2002 Mark J. Harris
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @file SkyBVTree.hpp
|
||||
*
|
||||
* This source was written by Wesley Hunt. Many thanks to him for providing it.
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
// SkyBVTree.hpp
|
||||
//
|
||||
// Author: Wesley Hunt (hunt@cs.unc.edu)
|
||||
// Date: 2000/12/19
|
||||
//-----------------------------------------------------------------------------
|
||||
// Overview
|
||||
// --------
|
||||
// declare an SkyBVTree with whatever object type and bounding volume type you
|
||||
// want. The hard part is to pass in a NodeSplitter class that determines how
|
||||
// to split a node up. See below for a description of its requirements.
|
||||
// Finally, use that tree like so:
|
||||
// * BeginTree()
|
||||
// * AddObject(Object, ObjectBV)
|
||||
// * ...
|
||||
// * EndTree()
|
||||
// < Do whatever you want with GetRoot() >
|
||||
// < Use GetLeftChild() and GetRightChild() to traverse the nodes >
|
||||
//
|
||||
// The class hierarchy is designed for a flexible, simple public interface.
|
||||
// This pushes some extra complexity into the class hierarchy, but there are two
|
||||
// main advantages to the final approach:
|
||||
// 1. There are no interface requirements for the Object and BoundingVolume
|
||||
// template parameters. This means you don't have to modify your existing
|
||||
// class interfaces to use them with the tree.
|
||||
// 2. All the dependent logic for dealing with the bounding volumes is pushed
|
||||
// into the NodeSplitter class. So there is one centralized location for
|
||||
// adapting your bounding volume classes to work with the tree. See the
|
||||
// description of the NodeSplitter template requirements for more details.
|
||||
//
|
||||
// Class Descriptions
|
||||
// ------------------
|
||||
//
|
||||
// SkyBaseBVTree
|
||||
// -------------
|
||||
// declares the node class that the tree holds. It exposes
|
||||
// the public functions of the nodes and defines protected accessors that
|
||||
// the derived tree class can use to manipulate nodes and build the tree.
|
||||
//
|
||||
// Node
|
||||
// ----
|
||||
// This is the class that gives access to the tree. You can access each
|
||||
// object and bounding volume owned by a node, along with that node's
|
||||
// children.
|
||||
//
|
||||
// NodeObject
|
||||
// ----------------
|
||||
// An aggregation of an object and its associated bounding volume.
|
||||
// Each node in the tree essentially owns an array of NodeObjects. This
|
||||
// array is passed to the NodeSplitter class to allow it to examine a
|
||||
// node's contained objects before making a decision on how to split the
|
||||
// node up.
|
||||
//
|
||||
// SkyBVTree
|
||||
// ---------
|
||||
// The main tree class. To use it, supply and object type, a bounding volume
|
||||
// type, and a NodeSplitter class that is used to split the nodes up during
|
||||
// tree construction.
|
||||
//
|
||||
// Template class requirements
|
||||
// ---------------------------
|
||||
//
|
||||
// Object
|
||||
// ------
|
||||
// None
|
||||
//
|
||||
// BoundingVolume
|
||||
// --------------
|
||||
// None
|
||||
//
|
||||
// NodeSplitter
|
||||
// ------------
|
||||
// This is the user-supplied class that decides how to split a node during
|
||||
// tree construction. It is given an array of NodeObjects that the node owns and
|
||||
// is responsible for determining the node's bounding volume as well as how to
|
||||
// split the node up into left and right children.
|
||||
// The required API is as follows:
|
||||
//
|
||||
// * a constructor that takes an array of NodeObject and an unsigned int giving
|
||||
// the size of the array. These are the objects owned by the node to be split.
|
||||
// * a method GetNodeBV() that returns the BoundingVolume of the node.
|
||||
// Typically this is the union of the bounding volumes of the objects owned
|
||||
// by the node.
|
||||
// * A unary function operator used to partition the objects in the node. The
|
||||
// operator must take a single NodeObject as a parameter and return as
|
||||
// a bool whether to place the NodeObject in the left or right child.
|
||||
// Basically, it should be compatible with std::partition using NodeObjects.
|
||||
// * A binary function operator used to sort the objects. If a partition fails,
|
||||
// the nodes are then sorted based on this function and half are sent to each child.
|
||||
// This operator must define a total ordering of the NodeObjects.
|
||||
// Basically, it should be compatible with std::sort using NodeObjects.
|
||||
//
|
||||
// Example:
|
||||
// struct NodeSplitter
|
||||
// {
|
||||
// NodeSplitter(const NodeObject* objs, unsigned int numObjs);
|
||||
// BoundingVolume& GetNodeBV() const;
|
||||
// // Partition predicate
|
||||
// bool operator()(const NodeObject& obj) const;
|
||||
// // Sort predicate
|
||||
// bool operator()(const NodeObject& obj1, const NodeObject& obj2) const;
|
||||
// };
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __SKYBVTREE_HPP__
|
||||
#define __SKYBVTREE_HPP__
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SkyBaseBVTree<Object, BoundingVolume>
|
||||
//-----------------------------------------------------------------------------
|
||||
// See header description for details.
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Object, class BoundingVolume>
|
||||
class SkyBaseBVTree
|
||||
{
|
||||
public:
|
||||
typedef BoundingVolume BV;
|
||||
class NodeObject;
|
||||
|
||||
public:
|
||||
class Node
|
||||
{
|
||||
friend class SkyBaseBVTree<Object, BoundingVolume>;
|
||||
public:
|
||||
Node() : _pObjs(NULL), _iNumObjs(0) {}
|
||||
Node(NodeObject* pObjs, unsigned int iNumObjs) : _pObjs(pObjs), _iNumObjs(iNumObjs) {}
|
||||
|
||||
// Public interface
|
||||
const Object& GetObj(unsigned int index) const { assert(_iNumObjs != 0 && _pObjs != NULL && index < _iNumObjs); return _pObjs[index].GetObj(); }
|
||||
const BV& GetBV(unsigned int index) const { assert(_iNumObjs != 0 && _pObjs != NULL && index < _iNumObjs); return _pObjs[index].GetBV(); }
|
||||
unsigned int GetNumObjs() const { assert(_iNumObjs != 0 && _pObjs != NULL); return _iNumObjs; }
|
||||
const BV& GetNodeBV() const { assert(_iNumObjs != 0 && _pObjs != NULL); return _volume; }
|
||||
const Node* GetLeftChild() const { assert(_iNumObjs != 0 && _pObjs != NULL); return this+1; }
|
||||
const Node* GetRightChild() const { assert(_iNumObjs != 0 && _pObjs != NULL); return this+(GetLeftChild()->GetNumObjs()<<1); }
|
||||
bool IsLeaf() const { assert(_iNumObjs != 0 && _pObjs != NULL); return _iNumObjs == 1; }
|
||||
|
||||
private:
|
||||
// List of Objects owned by the node
|
||||
NodeObject *_pObjs;
|
||||
unsigned int _iNumObjs;
|
||||
BV _volume;
|
||||
};
|
||||
|
||||
public:
|
||||
class NodeObject
|
||||
{
|
||||
public:
|
||||
NodeObject(const Object& o, const BV& v) : _obj(o), _volume(v) {}
|
||||
|
||||
const Object& GetObj() const { return _obj; }
|
||||
const BV& GetBV() const { return _volume; }
|
||||
private:
|
||||
Object _obj;
|
||||
BV _volume;
|
||||
};
|
||||
|
||||
protected:
|
||||
// Give non-const access to the node for descendant classes to build the tree
|
||||
BV& GetNodeBV(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode->_volume; }
|
||||
Node* GetLeftChild(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode+1; }
|
||||
Node* GetRightChild(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode+(GetLeftChild(pNode)->GetNumObjs()<<1); }
|
||||
NodeObject* GetObjs(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode->_pObjs; }
|
||||
|
||||
// Links a node's children by assigning the given number of objects to each child
|
||||
// assumes the node has already had it's objects partitioned
|
||||
void LinkNodeChildren(Node* pNode, unsigned int iLeftNumObjs)
|
||||
{
|
||||
assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL);
|
||||
GetLeftChild(pNode)->_pObjs = pNode->_pObjs;
|
||||
GetLeftChild(pNode)->_iNumObjs = iLeftNumObjs;
|
||||
GetRightChild(pNode)->_pObjs = pNode->_pObjs + iLeftNumObjs;
|
||||
GetRightChild(pNode)->_iNumObjs = pNode->_iNumObjs - iLeftNumObjs;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Function : ClearVector
|
||||
// Description :
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @fn ClearVector(std::vector<T>& vec)
|
||||
* @brief This utility function uses the std::vector::swap trick to free the memory of a vector
|
||||
*
|
||||
* This is necessary since clear() doesn't actually free anything.
|
||||
*/
|
||||
template<class T>
|
||||
void ClearVector(std::vector<T>& vec)
|
||||
{
|
||||
std::vector<T>().swap(vec);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SkyBVTree<Object, BoundingVolume, NodeSplitter>
|
||||
//-----------------------------------------------------------------------------
|
||||
// See header description for details.
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Object, class BoundingVolume, class NodeSplitter>
|
||||
class SkyBVTree : public SkyBaseBVTree<Object, BoundingVolume>
|
||||
{
|
||||
public:
|
||||
typedef SkyBaseBVTree<Object, BoundingVolume> BaseTree;
|
||||
typedef typename SkyBaseBVTree<Object, BoundingVolume>::BV BV;
|
||||
typedef typename BaseTree::NodeObject NodeObject;
|
||||
typedef typename BaseTree::Node Node;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
BeginTree();
|
||||
}
|
||||
|
||||
void BeginTree(unsigned int iNumObjs = 0)
|
||||
{
|
||||
ClearVector(_objList);
|
||||
ClearVector(_nodes);
|
||||
if (iNumObjs > 0) _objList.reserve(iNumObjs);
|
||||
}
|
||||
|
||||
void AddObject(const Object &obj, const BV& volume)
|
||||
{
|
||||
_objList.push_back(NodeObject(obj, volume));
|
||||
}
|
||||
|
||||
void EndTree()
|
||||
{
|
||||
if (_objList.size() == 0) return;
|
||||
// Initialize the root node with all the objects
|
||||
_nodes.push_back(Node(&_objList[0], _objList.size()));
|
||||
// create room for the other nodes. They are initialized in BuildTree().
|
||||
_nodes.reserve(_objList.size()*2-1);
|
||||
_nodes.resize(_objList.size()*2-1);
|
||||
BuildTree(&_nodes[0]);
|
||||
}
|
||||
|
||||
const Node *GetRoot() const { return _nodes.empty() ? NULL : &_nodes[0]; }
|
||||
|
||||
// Memory usage info
|
||||
unsigned int CalcMemUsage() const
|
||||
{
|
||||
unsigned int usage = 0;
|
||||
usage += sizeof(*this);
|
||||
usage += _objList.capacity() * sizeof(_objList[0]);
|
||||
usage += _nodes.capacity() * sizeof(_nodes[0]);
|
||||
return usage;
|
||||
}
|
||||
|
||||
public:
|
||||
private:
|
||||
// Does the real work
|
||||
void BuildTree(Node *pCurNode)
|
||||
{
|
||||
int iLeftNumObjs;
|
||||
{
|
||||
// Initialize the node splitter with the current node
|
||||
NodeSplitter splitter(GetObjs(pCurNode), pCurNode->GetNumObjs());
|
||||
|
||||
// set the node's bounding volume using the splitter
|
||||
GetNodeBV(pCurNode) = splitter.GetNodeBV();
|
||||
|
||||
// When a node has one object we can stop
|
||||
if (pCurNode->GetNumObjs() == 1) return;
|
||||
|
||||
// Try and partition the objects
|
||||
iLeftNumObjs = std::partition(GetObjs(pCurNode), &GetObjs(pCurNode)[pCurNode->GetNumObjs()], splitter) - GetObjs(pCurNode);
|
||||
|
||||
if ((iLeftNumObjs == 0) || (iLeftNumObjs == pCurNode->GetNumObjs()))
|
||||
{
|
||||
// Partition failed. Sort and split again to force a complete tree
|
||||
std::sort(GetObjs(pCurNode), &GetObjs(pCurNode)[pCurNode->GetNumObjs()], splitter);
|
||||
iLeftNumObjs = pCurNode->GetNumObjs() / 2;
|
||||
}
|
||||
}
|
||||
|
||||
LinkNodeChildren(pCurNode, iLeftNumObjs);
|
||||
BuildTree(GetLeftChild(pCurNode));
|
||||
BuildTree(GetRightChild(pCurNode));
|
||||
}
|
||||
|
||||
std::vector<Node> _nodes;
|
||||
std::vector<NodeObject> _objList;
|
||||
};
|
||||
|
||||
#endif //__SKYBVTREE_HPP__
|
||||
@@ -1,242 +0,0 @@
|
||||
//============================================================================
|
||||
// File : SkyBVTreeSplitter.hpp
|
||||
//
|
||||
// Author : Wesley Hunt
|
||||
//
|
||||
// Content : NodeSplitter classes for SkyBVTrees using SkyBoundingBox or
|
||||
// SkyBoundingSphere (not implemented).
|
||||
//
|
||||
//============================================================================
|
||||
#ifndef __SKYBVTREESPLITTER_HPP__
|
||||
#define __SKYBVTREESPLITTER_HPP__
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//-- Includes ----------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------
|
||||
#include "SkyBVTree.hpp"
|
||||
#include "SkyMinMaxBox.hpp"
|
||||
//#include <Mlx/MlxBoundingSphere.hpp>
|
||||
//#if _MSC_VER == 1200
|
||||
//#include <Auxlib/AuxCompileTimeChecker.hpp>
|
||||
//#endif
|
||||
//----------------------------------------------------------------------------
|
||||
//-- Forward Declarations ----------------------------------------------------
|
||||
//----------------------------------------------------------------------------
|
||||
// A strategy for splitting nodes compatible with bounding boxes and spheres.
|
||||
template<class Object> class SkyBoundingBoxSplitter;
|
||||
// SkyBVTree compatible node splitters implemented using the above strategy.
|
||||
template<class Object> class SkyAABBTreeSplitter;
|
||||
//template<class Object> class SkySphereTreeSplitter;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//-- Defines, Constants, Enumerated Types ------------------------------------
|
||||
//----------------------------------------------------------------------------
|
||||
const float rLongObjectPercentageTolerance = 0.75f;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// SkyBoundingBoxSplitter
|
||||
//----------------------------------------------------------------------------
|
||||
// This class defines a NodeSplitter strategy that has the functionality
|
||||
// required by SkyBVTree's NodeSplitter template class. Can be used with
|
||||
// SkyMinMaxBox and SkyBoundingSphere.
|
||||
//
|
||||
// It defines a two-tiered split strategy:
|
||||
//
|
||||
// * First it tries to separate large objects from any smaller objects.
|
||||
// * If there are no large objects, it splits along the midpoint of the longest
|
||||
// axis defined by the objects.
|
||||
// * Finally, if all else fails, it defines a total ordering along the longest
|
||||
// axis based on the center of each node.
|
||||
//----------------------------------------------------------------------------
|
||||
template<class Object>
|
||||
class SkyBoundingBoxSplitter
|
||||
{
|
||||
public:
|
||||
typedef typename SkyBaseBVTree<Object, SkyMinMaxBox>::NodeObject NodeObjectBox;
|
||||
//typedef SkyBaseBVTree<Object, SkyBoundingSphere>::NodeObject NodeObjectSphere;
|
||||
|
||||
#if _MSC_VER == 1200
|
||||
// !!! WRH HACK MSVC++6 SP5 Workaround.
|
||||
// VC6 can't disambiguate this constructor because it doesn't consider the two
|
||||
// NodeObject templates to be different classes for the purposes of
|
||||
// overloading. It won't recognize that the second template parameters are
|
||||
// different. Forcing them to be explicit template specializations fixes
|
||||
// the problem.
|
||||
template<class BV>
|
||||
SkyBoundingBoxSplitter(const SkyBaseBVTree<Object, BV>::NodeObject*, unsigned int)
|
||||
{
|
||||
//AUX_STATIC_CHECK(false, VisualC_6_WorkAround); ???
|
||||
}
|
||||
template<>
|
||||
#endif
|
||||
SkyBoundingBoxSplitter(const NodeObjectBox* pObjs, unsigned int iNumObjs)
|
||||
{
|
||||
for (unsigned int i = 0; i < iNumObjs; ++i)
|
||||
{
|
||||
_nodeBBox.Union(pObjs[i].GetBV());
|
||||
}
|
||||
Init(pObjs, iNumObjs);
|
||||
}
|
||||
/*#if _MSC_VER == 1200
|
||||
template<>
|
||||
#endif
|
||||
SkyBoundingBoxSplitter(const NodeObjectSphere* objs,
|
||||
#ifdef _PLATFORM_XBOX
|
||||
Int32
|
||||
#else
|
||||
UInt32
|
||||
#endif
|
||||
numObjs)
|
||||
{
|
||||
for (int i=0; i<numObjs; ++i)
|
||||
{
|
||||
SkyMinMaxBox box;
|
||||
box.AddPoint(objs[i].GetBV().GetCenter());
|
||||
box.Bloat(objs[i].GetBV().GetRadius());
|
||||
_nodeBBox.Union(box);
|
||||
}
|
||||
Init(objs, numObjs);
|
||||
}*/
|
||||
|
||||
template<class nodeObj>
|
||||
bool SplitLeft(const nodeObj& obj) const
|
||||
{
|
||||
if (_bIsolateLongObjects)
|
||||
return GetSplitAxisLength(obj.GetBV()) < _rMaxObjectLength;
|
||||
else
|
||||
return GetSplitAxisCenter(obj.GetBV()) < _rSplitValue;
|
||||
}
|
||||
|
||||
template<class nodeObj>
|
||||
bool LessThan(const nodeObj& obj1, const nodeObj& obj2) const
|
||||
{
|
||||
return GetSplitAxisCenter(obj1.GetBV()) < GetSplitAxisCenter(obj2.GetBV());
|
||||
}
|
||||
|
||||
const SkyMinMaxBox& GetNodeBBox() const { return _nodeBBox; }
|
||||
|
||||
private:
|
||||
template<class nodeObj>
|
||||
void Init(const nodeObj* pObjs, unsigned int iNumObjs)
|
||||
{
|
||||
_iSplitAxis = FindSplitAxis(_nodeBBox);
|
||||
_rSplitValue = FindSplitValue(_nodeBBox, _iSplitAxis);
|
||||
_rMaxObjectLength = GetSplitAxisLength(_nodeBBox) * rLongObjectPercentageTolerance;
|
||||
|
||||
_bIsolateLongObjects = false;
|
||||
for (unsigned int i = 0; i < iNumObjs; ++i)
|
||||
{
|
||||
if (GetSplitAxisLength(pObjs[i].GetBV()) > _rMaxObjectLength)
|
||||
{
|
||||
_bIsolateLongObjects = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FindSplitAxis(const SkyMinMaxBox& bbox)
|
||||
{
|
||||
int iAxis = 0, i;
|
||||
Vec3f vecExt = bbox.GetMax() - bbox.GetMin();
|
||||
for (i = 1; i < 3; ++i) if (vecExt[i] > vecExt[iAxis]) iAxis = i;
|
||||
return iAxis;
|
||||
}
|
||||
float FindSplitValue(const SkyMinMaxBox& bbox, int iSplitAxis)
|
||||
{
|
||||
return (bbox.GetMin()[iSplitAxis] + bbox.GetMax()[iSplitAxis])*0.5f;
|
||||
}
|
||||
|
||||
/*float GetSplitAxisLength(const SkyBoundingSphere& sphere) const
|
||||
{
|
||||
return 2.f*sphere.GetRadius();
|
||||
}*/
|
||||
float GetSplitAxisLength(const SkyMinMaxBox& bbox) const
|
||||
{
|
||||
return bbox.GetMax()[_iSplitAxis] - bbox.GetMin()[_iSplitAxis];
|
||||
}
|
||||
|
||||
float GetSplitAxisCenter(const SkyMinMaxBox& bbox) const
|
||||
{
|
||||
return (bbox.GetMin()[_iSplitAxis] + bbox.GetMax()[_iSplitAxis]) * 0.5f;
|
||||
}
|
||||
/*float GetSplitAxisCenter(const SkyBoundingSphere& sphere) const
|
||||
{
|
||||
return sphere.GetCenter()[SplitAxis];
|
||||
}*/
|
||||
|
||||
int _iSplitAxis;
|
||||
float _rSplitValue;
|
||||
bool _bIsolateLongObjects;
|
||||
float _rMaxObjectLength;
|
||||
|
||||
SkyMinMaxBox _nodeBBox;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// SkyAABBTreeSplitter
|
||||
//----------------------------------------------------------------------------
|
||||
// A NodeSplitter that is compatible with SkyBVTree for SkyMinMaxBox.
|
||||
// Implemented using the SkyBoundingBoxSplitter strategy.
|
||||
//----------------------------------------------------------------------------
|
||||
template<class Object>
|
||||
class SkyAABBTreeSplitter
|
||||
{
|
||||
public:
|
||||
typedef SkyMinMaxBox BV;
|
||||
typedef typename SkyBaseBVTree<Object, BV>::NodeObject NodeObject;
|
||||
|
||||
SkyAABBTreeSplitter(const NodeObject* pObjs, unsigned int iNumObjs) : _splitter(pObjs, iNumObjs) {}
|
||||
|
||||
const BV& GetNodeBV() const { return _splitter.GetNodeBBox(); }
|
||||
|
||||
bool operator()(const NodeObject& obj) const
|
||||
{
|
||||
return _splitter.SplitLeft(obj);
|
||||
}
|
||||
|
||||
bool operator()(const NodeObject& obj1, const NodeObject& obj2) const
|
||||
{
|
||||
return _splitter.LessThan(obj1, obj2);
|
||||
}
|
||||
|
||||
private:
|
||||
SkyBoundingBoxSplitter<Object> _splitter;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// SkySphereTreeSplitter
|
||||
//----------------------------------------------------------------------------
|
||||
// A NodeSplitter that is compatible with SkyBVTree for SkyBoundingSphere.
|
||||
// Implemented using the SkyBoundingBoxSplitter strategy.
|
||||
//----------------------------------------------------------------------------
|
||||
/*template<class Object>
|
||||
class SkySphereTreeSplitter
|
||||
{
|
||||
public:
|
||||
typedef SkyBoundingSphere BV;
|
||||
typedef SkyBaseBVTree<Object, BV>::NodeObject NodeObject;
|
||||
|
||||
MlxSphereTreeSplitter(const NodeObject* pObjs, unsigned int iNumObjs) : _splitter(pObjs, iNumObjs)
|
||||
{
|
||||
_nodeBV = pObjs[0].GetBV();
|
||||
for (unsigned int i = 1; i < iNumObjs; ++i) _nodeBV.Union(pObjs[i].GetBV());
|
||||
}
|
||||
|
||||
const BV& GetNodeBV() const { return _nodeBV; }
|
||||
|
||||
bool operator()(const NodeObject& obj) const
|
||||
{
|
||||
return _splitter.SplitLeft(obj);
|
||||
}
|
||||
|
||||
bool operator()(const NodeObject& obj1, const NodeObject& obj2) const
|
||||
{
|
||||
return _splitter.LessThan(obj1, obj2);
|
||||
}
|
||||
|
||||
private:
|
||||
BV _nodeBV;
|
||||
SkyBoundingBoxSplitter<Object> _splitter;
|
||||
};*/
|
||||
|
||||
#endif //__SKYBVTREESPLITTER_HPP__
|
||||
@@ -1,151 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File : SkyBoundingVolume.hpp
|
||||
//------------------------------------------------------------------------------
|
||||
// SkyWorks : Copyright 2002 Mark J. Harris and
|
||||
// The University of North Carolina at Chapel Hill
|
||||
//------------------------------------------------------------------------------
|
||||
// Permission to use, copy, modify, distribute and sell this software and its
|
||||
// documentation for any purpose is hereby granted without fee, provided that
|
||||
// the above copyright notice appear in all copies and that both that copyright
|
||||
// notice and this permission notice appear in supporting documentation.
|
||||
// Binaries may be compiled with this software without any royalties or
|
||||
// restrictions.
|
||||
//
|
||||
// The author(s) and The University of North Carolina at Chapel Hill make no
|
||||
// representations about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or
|
||||
// implied warranty.
|
||||
/**
|
||||
* @file SkyBoundingVolume.hpp
|
||||
*
|
||||
* Base class interface definition for a bounding volume.
|
||||
*/
|
||||
#ifndef __SKYBOUNDINGVOLUME_HPP__
|
||||
#define __SKYBOUNDINGVOLUME_HPP__
|
||||
|
||||
#include "vec3f.hpp"
|
||||
#include "mat44.hpp"
|
||||
|
||||
// forward to reduce unnecessary dependencies
|
||||
class Camera;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @class SkyBoundingVolume
|
||||
* @brief An abstract base class for bounding volumes (AABB,OBB,Sphere,etc.)
|
||||
*
|
||||
* This base class maintains a center and a radius, so it is effectively a bounding
|
||||
* sphere. Derived classes may represent other types of bounding volumes, but they
|
||||
* should be sure to update the radius and center, because some objects will treat
|
||||
* all bounding volumes as spheres.
|
||||
*
|
||||
*/
|
||||
class SkyBoundingVolume
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
SkyBoundingVolume() : _vecCenter(0, 0, 0), _rRadius(0) {}
|
||||
//! Destructor
|
||||
virtual ~SkyBoundingVolume() {}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Function : SetCenter
|
||||
// Description :
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @fn SetCenter(const Vec3f ¢er)
|
||||
* @brief Sets the center of the bounding volume.
|
||||
*/
|
||||
virtual void SetCenter(const Vec3f ¢er) { _vecCenter = center; }
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Function : SetRadius
|
||||
// Description :
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @fn SetRadius(float radius)
|
||||
* @brief Sets the radius of the bounding volume.
|
||||
*/
|
||||
virtual void SetRadius(float radius) { _rRadius = radius; }
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Function : Vec3f& GetCenter
|
||||
// Description :
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @fn Vec3f& GetCenter() const
|
||||
* @brief Returns the center of the bounding volume.
|
||||
*/
|
||||
virtual const Vec3f& GetCenter() const { return _vecCenter; }
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Function : GetRadius
|
||||
// Description :
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @fn GetRadius() const
|
||||
* @brief Returns the radius ofthe bounding volume.
|
||||
*/
|
||||
virtual float GetRadius() const { return _rRadius; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Function : ViewFrustumCull
|
||||
// Description :
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @fn ViewFrustumCull( const Camera &cam, const Mat44f &mat )
|
||||
* @brief Cull a bounding volume.
|
||||
*
|
||||
* Returns false if the bounding volume is entirely outside the camera's frustum,
|
||||
* true otherwise.
|
||||
*/
|
||||
virtual bool ViewFrustumCull( const Camera &cam, const Mat44f &mat ) = 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Function : AddPoint
|
||||
// Description :
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* @fn AddPoint( const Vec3f &pt )
|
||||
* @brief Add a point to a bounding volume.
|
||||
*
|
||||
* One way to create a bounding volume is to add points. What should/could happen
|
||||
* is that the BV will store an object space BV and then when a call to SetPosition
|
||||
* is called, the stored values will be transformed and stored separately, so that
|
||||
* the original values always exist.
|
||||
*
|
||||
*/
|
||||
//virtual void AddPoint( const Vec3f &point ) = 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Function : AddPoint
|
||||
// Description :
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* @fn AddPoint( float x, float y, float z )
|
||||
* @brief Add a point to a bounding volume.
|
||||
*
|
||||
* @see AddPoint(const Vec3f &pt)
|
||||
*/
|
||||
//virtual void AddPoint( float x, float y, float z ) = 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Function : Clear
|
||||
// Description :
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* @fn Clear()
|
||||
* @brief Clear all data from the bounding volume.
|
||||
*/
|
||||
//virtual void Clear() = 0;
|
||||
|
||||
protected:
|
||||
Vec3f _vecCenter;
|
||||
float _rRadius;
|
||||
};
|
||||
|
||||
#endif //__SKYBOUNDINGVOLUME_HPP__
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user