Compare commits
157 Commits
PRE_OSG_PL
...
sm-lastmai
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bcdf2e4dc | ||
|
|
cd5a720211 | ||
|
|
5cb04946b0 | ||
|
|
c8953c6275 | ||
|
|
e8dc9c9454 | ||
|
|
a0c325681f | ||
|
|
8d3bf19422 | ||
|
|
4477867ef4 | ||
|
|
e696c884dc | ||
|
|
80bcaa49e6 | ||
|
|
0096c1bb02 | ||
|
|
38b37a068d | ||
|
|
0281f31df2 | ||
|
|
40b182c550 | ||
|
|
d1dedc7511 | ||
|
|
04cd9b3eb6 | ||
|
|
de6003367d | ||
|
|
a5f42eeddf | ||
|
|
a8ba041b67 | ||
|
|
e700fc6f34 | ||
|
|
af29d3d257 | ||
|
|
487701a143 | ||
|
|
f32e037c58 | ||
|
|
8bd903dd96 | ||
|
|
560c100484 | ||
|
|
52444d177b | ||
|
|
b4f7ff29ef | ||
|
|
f7c6a5bfa2 | ||
|
|
6fe14f7a6b | ||
|
|
786e5addd8 | ||
|
|
2e9a15f523 | ||
|
|
bb0d2ddc53 | ||
|
|
702fb014a5 | ||
|
|
834eab9457 | ||
|
|
a85da04601 | ||
|
|
414f1c27e4 | ||
|
|
c76e2eb900 | ||
|
|
c523e15302 | ||
|
|
2dc8de295d | ||
|
|
d645fd6327 | ||
|
|
219a7f3a07 | ||
|
|
d95e3e0055 | ||
|
|
2cc31ff425 | ||
|
|
8258fd7d9f | ||
|
|
784cca2233 | ||
|
|
436539a700 | ||
|
|
dcb3da9f28 | ||
|
|
a354c841f1 | ||
|
|
3824f064cd | ||
|
|
cba6db752b | ||
|
|
a458e26581 | ||
|
|
9d68727a84 | ||
|
|
38b9a874e0 | ||
|
|
7a680fb9f2 | ||
|
|
a5f9262adb | ||
|
|
b05e32fa8c | ||
|
|
53d8cff835 | ||
|
|
00fe97ff88 | ||
|
|
607511fd64 | ||
|
|
8663c265d8 | ||
|
|
6c5d35d6ce | ||
|
|
95532cb318 | ||
|
|
4d91bc5908 | ||
|
|
b13900402d | ||
|
|
1bb6c03bd0 | ||
|
|
1445949e31 | ||
|
|
360d3834ca | ||
|
|
aacdcad529 | ||
|
|
ad9341835f | ||
|
|
b028adb6af | ||
|
|
39f683b272 | ||
|
|
a6c46c89eb | ||
|
|
d534cf6f02 | ||
|
|
dd4326f7c4 | ||
|
|
40aecd688e | ||
|
|
63730a6e2c | ||
|
|
4d4d26aef8 | ||
|
|
de6b32d8c6 | ||
|
|
a0af7f0524 | ||
|
|
c043bd3422 | ||
|
|
18ae1d6940 | ||
|
|
d6f64f9773 | ||
|
|
db99a4cb90 | ||
|
|
108689661f | ||
|
|
d3e00dba8e | ||
|
|
fcd33e5035 | ||
|
|
af9082cd9f | ||
|
|
6a0bb18fca | ||
|
|
8aa8d87781 | ||
|
|
4998af8d7a | ||
|
|
c6aa95f3f3 | ||
|
|
481be29366 | ||
|
|
3617b6ad8c | ||
|
|
3fb8e19a38 | ||
|
|
2ea2f1b4f2 | ||
|
|
26cb8ec4f1 | ||
|
|
7fe56bea86 | ||
|
|
11b16b8a86 | ||
|
|
de020ee695 | ||
|
|
3b83487611 | ||
|
|
09bab4f162 | ||
|
|
49fcc799ca | ||
|
|
10bc803775 | ||
|
|
4f40770fc6 | ||
|
|
a4495c6ef1 | ||
|
|
67d837c4ec | ||
|
|
138825af6d | ||
|
|
c093841336 | ||
|
|
2df1da4226 | ||
|
|
2792d60e2d | ||
|
|
656a3ace07 | ||
|
|
aec8e88c14 | ||
|
|
bdd5ca140d | ||
|
|
8b3b0def03 | ||
|
|
6440ece177 | ||
|
|
bd3518637c | ||
|
|
aef2a1c484 | ||
|
|
a4b28e5737 | ||
|
|
a3bc2eb836 | ||
|
|
3059da5805 | ||
|
|
18d5a492c8 | ||
|
|
160b0ea7d9 | ||
|
|
4dd1267bea | ||
|
|
b5c4328682 | ||
|
|
571fc69ef4 | ||
|
|
f51595cfc9 | ||
|
|
d54aea0036 | ||
|
|
51bb2974bc | ||
|
|
7a859061fd | ||
|
|
cefa9fcd75 | ||
|
|
d3bacd0b73 | ||
|
|
b94a98fc90 | ||
|
|
e0b2687231 | ||
|
|
cc6179a4dd | ||
|
|
e947bac4a3 | ||
|
|
11ecbb6ca7 | ||
|
|
322789cd4c | ||
|
|
f28464dba0 | ||
|
|
8f6456b1f8 | ||
|
|
1f32786c82 | ||
|
|
829c729ee9 | ||
|
|
5d3aacb892 | ||
|
|
741e9c5ed5 | ||
|
|
1408c1b623 | ||
|
|
c256f8d09e | ||
|
|
55c018c525 | ||
|
|
3fa94b5143 | ||
|
|
5127e2f89c | ||
|
|
3175fa3aca | ||
|
|
5614174b39 | ||
|
|
39fc52fe0a | ||
|
|
81188705b1 | ||
|
|
63c4873d8a | ||
|
|
1a85dcd890 | ||
|
|
27470fc504 | ||
|
|
65d18445d3 | ||
|
|
84dd54b33a |
@@ -2,10 +2,9 @@ EXTRA_DIST = \
|
||||
acinclude.m4 \
|
||||
autogen.sh \
|
||||
DoxygenMain.cxx \
|
||||
project/VC8 \
|
||||
README.MSVC \
|
||||
README.zlib \
|
||||
projects \
|
||||
projects \
|
||||
SimGear.dsp \
|
||||
SimGear.dsw
|
||||
|
||||
|
||||
100
SimGear.dsp
100
SimGear.dsp
@@ -556,21 +556,6 @@ SOURCE=.\simgear\math\vector.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\math\fastmath.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgmath"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgmath"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\math\SGGeodesy.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
@@ -1184,21 +1169,6 @@ SOURCE=.\simgear\scene\model\animation.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\custtrans.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgmodel"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgmodel"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\location.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
@@ -1244,7 +1214,7 @@ SOURCE=.\simgear\scene\model\modellib.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\personality.cxx
|
||||
SOURCE=.\simgear\scene\model\persparam.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
@@ -1289,7 +1259,7 @@ SOURCE=.\simgear\scene\model\placementtrans.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\shadowvolume.cxx
|
||||
SOURCE=.\simgear\scene\model\shadanim.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
@@ -1304,7 +1274,7 @@ SOURCE=.\simgear\scene\model\shadowvolume.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\shadanim.cxx
|
||||
SOURCE=.\simgear\scene\model\SGMaterialAnimation.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
@@ -1549,6 +1519,40 @@ SOURCE=.\simgear\scene\tgdb\userdata.cxx
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Lib_sgutil"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\util\SGStateAttributeVisitor.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgutil"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgutil"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\util\SGTextureStateAttributeVisitor.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgutil"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgutil"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Lib_sgscreen"
|
||||
@@ -1805,6 +1809,36 @@ SOURCE=.\simgear\structure\subsystem_mgr.cxx
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\structure\SGAtomic.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgstructure"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgstructure"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\structure\SGBinding.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgstructure"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgstructure"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Lib_sgtiming"
|
||||
|
||||
21
Thanks
21
Thanks
@@ -47,6 +47,18 @@ Jean-Francois Doue
|
||||
http://www.animats.com/simpleppp/ftp/public_html/topics/developers.html
|
||||
|
||||
|
||||
Melchior Franz
|
||||
METAR parser and fetcher. "material" animation (based on Jim Wilsons's
|
||||
"emission" animation). Debugging and extension of property listener
|
||||
features. Addition of removeChildren.
|
||||
|
||||
|
||||
Mathias Froehlich
|
||||
Reworked and cleaned up large parts of the infrastructure, of math
|
||||
files, animations and rendering in preparation of a transition to
|
||||
the OSG library. Added new handlers for shared and referenced objects.
|
||||
|
||||
|
||||
Bruce Finney <bfinney@gte.net>
|
||||
MSVC5 compatibility.
|
||||
|
||||
@@ -71,6 +83,10 @@ Bruce Jackson of NASA <e.b.jackson@larc.nasa.gov>
|
||||
http://dcb.larc.nasa.gov/www/DCBStaff/ebj/ebj.html
|
||||
|
||||
|
||||
Maik Justus
|
||||
Fixed an old bug in the SGPropertyNode class.
|
||||
|
||||
|
||||
Richard Kaszeta <bofh@me.umn.edu>
|
||||
Contributed screen buffer to ppm screen shot routine.
|
||||
Rich has also helped in the early development of the Flight Gear "altitude
|
||||
@@ -90,6 +106,11 @@ David Megginson <david@megginson.com>
|
||||
SimGear property manager/registry
|
||||
|
||||
|
||||
Tim Moore
|
||||
Ported the (chrome) "shader" animation to OSG, and helped with porting
|
||||
the "material" animation.
|
||||
|
||||
|
||||
Curt Olson http://www.flightgear.org/~curt/
|
||||
Curt is responsible for overall project and source code management.
|
||||
He has his hands in many of the areas.
|
||||
|
||||
@@ -119,6 +119,14 @@ if test "x$with_plib" != "x" ; then
|
||||
EXTRA_DIRS="${EXTRA_DIRS} $with_plib"
|
||||
fi
|
||||
|
||||
# specify the osg location
|
||||
AC_ARG_WITH(osg, [ --with-osg=PREFIX Specify the prefix path to osg])
|
||||
|
||||
if test "x$with_osg" != "x" ; then
|
||||
echo "osg prefix is $with_osg"
|
||||
EXTRA_DIRS="${EXTRA_DIRS} $with_osg"
|
||||
fi
|
||||
|
||||
dnl Determine an extra directories to add to include/lib search paths
|
||||
case "${host}" in
|
||||
*-apple-darwin* | *-*-cygwin* | *-*-mingw32*)
|
||||
@@ -430,6 +438,7 @@ AC_CONFIG_FILES([ \
|
||||
simgear/scene/model/Makefile \
|
||||
simgear/scene/sky/Makefile \
|
||||
simgear/scene/tgdb/Makefile \
|
||||
simgear/scene/util/Makefile \
|
||||
simgear/screen/Makefile \
|
||||
simgear/serial/Makefile \
|
||||
simgear/sound/Makefile \
|
||||
|
||||
4
projects/VC7.1/.cvsignore
Executable file
4
projects/VC7.1/.cvsignore
Executable file
@@ -0,0 +1,4 @@
|
||||
Debug
|
||||
Release
|
||||
SimGear.ncb
|
||||
SimGear.suo
|
||||
21
projects/VC7.1/SimGear.sln
Executable file
21
projects/VC7.1/SimGear.sln
Executable file
@@ -0,0 +1,21 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimGear", "SimGear.vcproj", "{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Debug = Debug
|
||||
Release = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Debug.ActiveCfg = Debug|Win32
|
||||
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Debug.Build.0 = Debug|Win32
|
||||
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Release.ActiveCfg = Release|Win32
|
||||
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Release.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
1079
projects/VC7.1/SimGear.vcproj
Executable file
1079
projects/VC7.1/SimGear.vcproj
Executable file
File diff suppressed because it is too large
Load Diff
@@ -41,11 +41,11 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../..;../../..;../../Simgear;../../../devel/include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
|
||||
AdditionalIncludeDirectories="../..;../../..;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../Simgear;../../../3rdparty/include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
@@ -103,11 +103,11 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
AdditionalIncludeDirectories="../..;../../..;../../Simgear;../../../devel/include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
|
||||
AdditionalIncludeDirectories="../..;../../..;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../Simgear;../../../3rdparty/include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
|
||||
StringPooling="true"
|
||||
MinimalRebuild="true"
|
||||
RuntimeLibrary="0"
|
||||
RuntimeLibrary="2"
|
||||
FloatingPointModel="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
@@ -215,10 +215,6 @@
|
||||
RelativePath="..\..\simgear\magvar\coremag.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\custtrans.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\data.h"
|
||||
>
|
||||
@@ -507,10 +503,26 @@
|
||||
RelativePath="..\..\simgear\math\sg_types.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\structure\SGAtomic.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\structure\SGBinding.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGCMath.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGDebugDrawCallback.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGEnlargeBoundingBox.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGGeoc.hxx"
|
||||
>
|
||||
@@ -531,6 +543,10 @@
|
||||
RelativePath="..\..\simgear\math\SGLimits.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGMaterialAnimation.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGMath.hxx"
|
||||
>
|
||||
@@ -547,6 +563,18 @@
|
||||
RelativePath="..\..\simgear\math\SGMisc.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGNodeMasks.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\tgdb\SGOceanTile.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGOffsetTransform.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGQuat.hxx"
|
||||
>
|
||||
@@ -559,18 +587,54 @@
|
||||
RelativePath="..\..\simgear\structure\SGReferenced.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGRotateTransform.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGScaleTransform.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGSceneFeatures.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGSceneUserData.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\structure\SGSharedPtr.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGStateAttributeVisitor.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\misc\sgstream.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGTextureStateAttributeVisitor.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\threads\SGThread.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGTranslateTransform.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGUpdateVisitor.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\tgdb\SGVasiDrawable.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGVec3.hxx"
|
||||
>
|
||||
@@ -587,20 +651,6 @@
|
||||
RelativePath="..\..\simgear\scene\model\shadowvolume.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\simgear_config.h"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description=""
|
||||
CommandLine=""
|
||||
Outputs=""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\sky\sky.hxx"
|
||||
>
|
||||
@@ -765,6 +815,10 @@
|
||||
RelativePath="..\..\simgear\scene\sky\bbcache.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\bitslib.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\ephemeris\celestialBody.cxx"
|
||||
>
|
||||
@@ -797,10 +851,6 @@
|
||||
RelativePath="..\..\simgear\magvar\coremag.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\custtrans.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\sky\dome.cxx"
|
||||
>
|
||||
@@ -858,11 +908,11 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\ephemeris\jupiter.cxx"
|
||||
RelativePath="..\..\simgear\nasal\iolib.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\tgdb\leaf.cxx"
|
||||
RelativePath="..\..\simgear\ephemeris\jupiter.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@@ -969,10 +1019,6 @@
|
||||
RelativePath="..\..\simgear\nasal\parse.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\personality.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\persparam.cxx"
|
||||
>
|
||||
@@ -1061,18 +1107,70 @@
|
||||
RelativePath="..\..\simgear\timing\sg_time.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\structure\SGBinding.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGEnlargeBoundingBox.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGGeodesy.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGMaterialAnimation.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\tgdb\SGOceanTile.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGOffsetTransform.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGRotateTransform.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGScaleTransform.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGSceneFeatures.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGSceneUserData.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGStateAttributeVisitor.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\misc\sgstream.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGTextureStateAttributeVisitor.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\threads\SGThread.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGTranslateTransform.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\tgdb\SGVasiDrawable.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\shadanim.cxx"
|
||||
>
|
||||
@@ -1081,10 +1179,6 @@
|
||||
RelativePath="..\..\simgear\screen\shader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\shadowvolume.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\sky\sky.cxx"
|
||||
>
|
||||
@@ -1141,6 +1235,10 @@
|
||||
RelativePath="..\..\simgear\nasal\thread-win32.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\threadlib.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\timing\timestamp.cxx"
|
||||
>
|
||||
@@ -1161,6 +1259,10 @@
|
||||
RelativePath="..\..\simgear\scene\tgdb\userdata.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\utf8lib.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\vector.c"
|
||||
>
|
||||
@@ -1218,6 +1320,28 @@
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath="..\..\simgear\simgear_config.h-msvc71"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="copy "$(InputPath)" "$(InputDir)\$(InputName).h"
"
|
||||
Outputs=""${InputDir}\$(InputName).h""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="copy "$(InputPath)" "$(InputDir)\$(InputName).h"
"
|
||||
Outputs="${InputDir}\$(InputName).h"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
|
||||
@@ -7,7 +7,7 @@ endif
|
||||
# METAR_DIRS =
|
||||
METAR_DIRS = environment
|
||||
|
||||
EXTRA_DIST = simgear_config.h.vc5 version.h.in
|
||||
EXTRA_DIST = simgear_config.h.vc5 simgear_config.h-msvc71 version.h.in
|
||||
|
||||
include_HEADERS = \
|
||||
compiler.h constants.h sg_inlines.h sg_traits.hxx version.h
|
||||
@@ -34,4 +34,4 @@ SUBDIRS = \
|
||||
$(SGTHREAD_DIR) \
|
||||
timing
|
||||
|
||||
DIST_SUBDIRS = $(SUBDIRS) compatibility threads
|
||||
DIST_SUBDIRS = $(SUBDIRS) compatibility
|
||||
|
||||
@@ -44,6 +44,9 @@ SGBucket::SGBucket(const double dlon, const double dlat) {
|
||||
set_bucket(dlon, dlat);
|
||||
}
|
||||
|
||||
SGBucket::SGBucket(const SGGeod& geod) {
|
||||
set_bucket(geod);
|
||||
}
|
||||
|
||||
// create an impossible bucket if false
|
||||
SGBucket::SGBucket(const bool is_good) {
|
||||
@@ -73,11 +76,6 @@ SGBucket::SGBucket(const long int bindex) {
|
||||
}
|
||||
|
||||
|
||||
// default destructor
|
||||
SGBucket::~SGBucket() {
|
||||
}
|
||||
|
||||
|
||||
// Set the bucket params for the specified lat and lon
|
||||
void SGBucket::set_bucket( double *lonlat ) {
|
||||
set_bucket( lonlat[0], lonlat[1] );
|
||||
@@ -135,6 +133,11 @@ void SGBucket::set_bucket( double dlon, double dlat ) {
|
||||
}
|
||||
|
||||
|
||||
void SGBucket::set_bucket(const SGGeod& geod)
|
||||
{
|
||||
set_bucket(geod.getLongitudeDeg(), geod.getLatitudeDeg());
|
||||
}
|
||||
|
||||
// Build the path name for this bucket
|
||||
string SGBucket::gen_base_path() const {
|
||||
// long int index;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#ifdef SG_HAVE_STD_INCLUDES
|
||||
# include <cmath>
|
||||
@@ -133,6 +134,13 @@ public:
|
||||
*/
|
||||
SGBucket(const double dlon, const double dlat);
|
||||
|
||||
/**
|
||||
* Construct a bucket given a specific location.
|
||||
* @param dlon longitude specified in degrees
|
||||
* @param dlat latitude specified in degrees
|
||||
*/
|
||||
SGBucket(const SGGeod& geod);
|
||||
|
||||
/** Construct a bucket.
|
||||
* @param is_good if false, create an invalid bucket. This is
|
||||
* useful * if you are comparing cur_bucket to last_bucket and
|
||||
@@ -146,11 +154,6 @@ public:
|
||||
*/
|
||||
SGBucket(const long int bindex);
|
||||
|
||||
/**
|
||||
* Default destructor.
|
||||
*/
|
||||
~SGBucket();
|
||||
|
||||
/**
|
||||
* Reset a bucket to represent a new lat and lon
|
||||
* @param dlon longitude specified in degrees
|
||||
@@ -165,6 +168,13 @@ public:
|
||||
*/
|
||||
void set_bucket( double *lonlat );
|
||||
|
||||
/**
|
||||
* Reset a bucket to represent a new lat and lon
|
||||
* @param dlon longitude specified in degrees
|
||||
* @param dlat latitude specified in degrees
|
||||
*/
|
||||
void set_bucket(const SGGeod& geod);
|
||||
|
||||
/**
|
||||
* Create an impossible bucket.
|
||||
* This is useful if you are comparing cur_bucket to last_bucket
|
||||
@@ -252,7 +262,24 @@ public:
|
||||
* @return the height of the tile in meters.
|
||||
*/
|
||||
double get_height_m() const;
|
||||
|
||||
|
||||
/**
|
||||
* @return the center of the bucket in geodetic coordinates.
|
||||
*/
|
||||
SGGeod get_center() const
|
||||
{ return SGGeod::fromDeg(get_center_lon(), get_center_lat()); }
|
||||
|
||||
/**
|
||||
* @return the center of the bucket in geodetic coordinates.
|
||||
*/
|
||||
SGGeod get_corner(unsigned num) const
|
||||
{
|
||||
double lonFac = ((num + 1) & 2) ? 0.5 : -0.5;
|
||||
double latFac = ((num ) & 2) ? 0.5 : -0.5;
|
||||
return SGGeod::fromDeg(get_center_lon() + lonFac*get_width(),
|
||||
get_center_lat() + latFac*get_height());
|
||||
}
|
||||
|
||||
// Informational methods.
|
||||
|
||||
/**
|
||||
|
||||
@@ -230,6 +230,7 @@
|
||||
|
||||
# define isnan _isnan
|
||||
# define snprintf _snprintf
|
||||
# define copysign _copysign
|
||||
|
||||
# pragma warning(disable: 4786) // identifier was truncated to '255' characters
|
||||
# pragma warning(disable: 4244) // conversion from double to float
|
||||
|
||||
@@ -747,6 +747,14 @@ bool SGMetar::scanSkyCondition()
|
||||
int i;
|
||||
SGMetarCloud cl;
|
||||
|
||||
if (!strncmp(m, "//////", 6)) {
|
||||
m += 6;
|
||||
if (!scanBoundary(&m))
|
||||
return false;
|
||||
_m = m;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strncmp(m, "CLR", i = 3) // clear
|
||||
|| !strncmp(m, "SKC", i = 3) // sky clear
|
||||
|| !strncmp(m, "NSC", i = 3) // no significant clouds
|
||||
@@ -836,7 +844,7 @@ bool SGMetar::scanTemperature()
|
||||
return false;
|
||||
if (!scanBoundary(&m)) {
|
||||
if (!strncmp(m, "XX", 2)) // not spec compliant!
|
||||
m += 2, sign = 0;
|
||||
m += 2, sign = 0, dew = temp;
|
||||
else {
|
||||
sign = 1;
|
||||
if (*m == 'M')
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
// Minor changes/additions by Vivian Meazza Apr- May 2007
|
||||
//
|
||||
// Ported to OSG by Tim Moore Jun 2007
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
@@ -189,6 +192,8 @@ SGEnviro::SGEnviro() :
|
||||
}
|
||||
|
||||
SGEnviro::~SGEnviro(void) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
list_of_lightning::iterator iLightning;
|
||||
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
|
||||
delete (*iLightning);
|
||||
@@ -197,6 +202,8 @@ SGEnviro::~SGEnviro(void) {
|
||||
}
|
||||
|
||||
void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
view_in_cloud = false;
|
||||
// ask the impostor cache to do some cleanup
|
||||
if(SGNewCloud::cldCache)
|
||||
@@ -319,13 +326,15 @@ void SGEnviro::set_lightning_enable_state(bool enable) {
|
||||
}
|
||||
|
||||
void SGEnviro::setLight(sgVec4 adj_fog_color) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
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 family, float dist, int cloudId) {
|
||||
void SGEnviro::callback_cloud(float bearing, float alt, float radius, int family, float dist, int cloudId) {
|
||||
// send data to wx radar
|
||||
// compute turbulence
|
||||
// draw precipitation
|
||||
@@ -397,9 +406,10 @@ void SGEnviro::callback_cloud(float heading, float alt, float radius, int family
|
||||
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 ) );
|
||||
radarEcho.push_back( SGWxRadarEcho ( bearing, alt, radius, dist, 0.0 , LWC, false, cloudId, false ) );
|
||||
|
||||
// NB:data valid only from cockpit view
|
||||
|
||||
@@ -412,7 +422,7 @@ void SGEnviro::callback_cloud(float heading, float alt, float radius, int family
|
||||
orig.setlon(last_lon * SG_DEGREES_TO_RADIANS );
|
||||
orig.setelev(0.0);
|
||||
dist = sgSqrt(dist);
|
||||
dest = calc_gc_lon_lat(orig, heading, dist);
|
||||
dest = calc_gc_lon_lat(orig, bearing, dist);
|
||||
lon = dest.lon() * SG_RADIANS_TO_DEGREES;
|
||||
lat = dest.lat() * SG_RADIANS_TO_DEGREES;
|
||||
addLightning( lon, lat, alt );
|
||||
@@ -440,6 +450,8 @@ list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
|
||||
|
||||
// precipitation rendering code
|
||||
void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
sgVec3 light;
|
||||
sgAddVec3( light, fog_color, min_light );
|
||||
float da = SG_PI * 2.0f / (float) slices;
|
||||
@@ -488,6 +500,8 @@ void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down,
|
||||
}
|
||||
|
||||
void SGEnviro::drawRain(double pitch, double roll, double heading, double hspeed, double rain_norm) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
|
||||
#if 0
|
||||
static int debug_period = 0;
|
||||
@@ -557,6 +571,8 @@ void SGEnviro::set_soundMgr(SGSoundMgr *mgr) {
|
||||
}
|
||||
|
||||
void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double hspeed) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
if( precipitation_enable_state && rain_norm > 0.0)
|
||||
if( precipitation_max_alt >= last_alt )
|
||||
drawRain(pitch, roll, heading, hspeed, rain_norm);
|
||||
@@ -579,6 +595,8 @@ SGLightning::~SGLightning() {
|
||||
|
||||
// lightning rendering code
|
||||
void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
|
||||
sgVec3 dir, newdir;
|
||||
int nseg = 0;
|
||||
@@ -626,6 +644,8 @@ void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy
|
||||
}
|
||||
|
||||
void SGLightning::lt_build(void) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
Point3D top;
|
||||
nb_tree = 0;
|
||||
top[PX] = 0 ;
|
||||
@@ -651,6 +671,8 @@ void SGLightning::lt_build(void) {
|
||||
|
||||
|
||||
void SGLightning::lt_Render(void) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
float flash = 0.5;
|
||||
if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 )
|
||||
flash = sg_random() * 0.75f + 0.25f;
|
||||
@@ -675,10 +697,12 @@ void SGLightning::lt_Render(void) {
|
||||
glDisable( GL_FOG );
|
||||
glPushMatrix();
|
||||
sgMat4 modelview, tmp;
|
||||
ssgGetModelviewMatrix( modelview );
|
||||
// OSGFIXME
|
||||
// ssgGetModelviewMatrix( modelview );
|
||||
sgCopyMat4( tmp, sgEnviro.transform );
|
||||
sgPostMultMat4( tmp, modelview );
|
||||
ssgLoadModelviewMatrix( tmp );
|
||||
// OSGFIXME
|
||||
// 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 );
|
||||
@@ -690,7 +714,7 @@ void SGLightning::lt_Render(void) {
|
||||
|
||||
glTranslatef( ax, ay, -sgEnviro.last_alt );
|
||||
|
||||
sgEnviro.radarEcho.push_back( SGWxRadarEcho ( course, 0.0, 0.0, dist, age, true, 0 ) );
|
||||
sgEnviro.radarEcho.push_back( SGWxRadarEcho ( course, 0.0, 0.0, dist, 0.0, age, true, 0, false ) );
|
||||
|
||||
for( int n = 0 ; n < nb_tree ; n++ ) {
|
||||
if( lt_tree[n].prev < 0 )
|
||||
@@ -736,6 +760,8 @@ void SGLightning::lt_Render(void) {
|
||||
}
|
||||
|
||||
void SGEnviro::addLightning(double lon, double lat, double alt) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
if( lightnings.size() > 10)
|
||||
return;
|
||||
SGLightning *lt= new SGLightning(lon, lat, alt);
|
||||
@@ -743,6 +769,8 @@ void SGEnviro::addLightning(double lon, double lat, double alt) {
|
||||
}
|
||||
|
||||
void SGEnviro::drawLightning(void) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
list_of_lightning::iterator iLightning;
|
||||
// play 'thunder' for lightning
|
||||
if( snd_active )
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
// Minor changes/additions by Vivian Meazza Apr- May 2007
|
||||
//
|
||||
// Ported to OSG by Tim Moore Jun 2007
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
@@ -40,23 +43,32 @@ class SGSoundMgr;
|
||||
*/
|
||||
class SGWxRadarEcho {
|
||||
public:
|
||||
SGWxRadarEcho(float _heading, float _alt, float _radius, float _dist, double _LWC, bool _lightning, int _cloudId) :
|
||||
SGWxRadarEcho(float _bearing, float _alt, float _radius, float _dist, float _heading,
|
||||
double _LWC, bool _lightning, int _cloudId, bool _aircraft) :
|
||||
bearing (_bearing),
|
||||
heading( _heading ),
|
||||
alt ( _alt ),
|
||||
radius ( _radius ),
|
||||
dist ( _dist ),
|
||||
LWC ( _LWC ),
|
||||
lightning ( _lightning ),
|
||||
aircraft ( _aircraft ),
|
||||
cloudId ( _cloudId )
|
||||
{}
|
||||
|
||||
/** the heading in radian is versus north */
|
||||
float heading;
|
||||
/** the heading and bearing in radian are versus north */
|
||||
float bearing, 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;
|
||||
|
||||
/** if true then this data is for an aircraft */
|
||||
bool aircraft;
|
||||
|
||||
/** Unique identifier of cloud */
|
||||
int cloudId;
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
|
||||
// Constructor
|
||||
SGEphemeris::SGEphemeris( const string &path ) {
|
||||
SGEphemeris::SGEphemeris( const std::string &path ) {
|
||||
our_sun = new Star;
|
||||
moon = new MoonPos;
|
||||
mercury = new Mercury;
|
||||
@@ -42,9 +42,8 @@ SGEphemeris::SGEphemeris( const string &path ) {
|
||||
uranus = new Uranus;
|
||||
neptune = new Neptune;
|
||||
nplanets = 7;
|
||||
for ( int i = 0; i < nplanets; ++i ) {
|
||||
sgdSetVec3( planets[i], 0.0, 0.0, 0.0 );
|
||||
}
|
||||
for ( int i = 0; i < nplanets; ++i )
|
||||
planets[i] = SGVec3d::zeros();
|
||||
stars = new SGStarData( SGPath(path) );
|
||||
}
|
||||
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
#ifndef _EPHEMERIS_HXX
|
||||
#define _EPHEMERIS_HXX
|
||||
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <string>
|
||||
|
||||
#include <simgear/ephemeris/star.hxx>
|
||||
#include <simgear/ephemeris/moonpos.hxx>
|
||||
@@ -43,6 +42,9 @@
|
||||
#include <simgear/ephemeris/neptune.hxx>
|
||||
#include <simgear/ephemeris/stardata.hxx>
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
|
||||
/** Ephemeris class
|
||||
*
|
||||
@@ -83,7 +85,7 @@ class SGEphemeris {
|
||||
// planets[i][1] = Declination
|
||||
// planets[i][2] = Magnitude
|
||||
int nplanets;
|
||||
sgdVec3 planets[7];
|
||||
SGVec3d planets[7];
|
||||
|
||||
SGStarData *stars;
|
||||
|
||||
@@ -95,7 +97,7 @@ public:
|
||||
* calling the constructor you need to provide a path pointing to
|
||||
* your star database file.
|
||||
* @param path path to your star database */
|
||||
SGEphemeris( const string &path );
|
||||
SGEphemeris( const std::string &path );
|
||||
|
||||
/** Destructor */
|
||||
~SGEphemeris( void );
|
||||
@@ -155,7 +157,7 @@ public:
|
||||
* the second is the declination, and the third is the magnitude.
|
||||
* @return planets array
|
||||
*/
|
||||
inline sgdVec3 *getPlanets() { return planets; }
|
||||
inline SGVec3d *getPlanets() { return planets; }
|
||||
|
||||
/** @return the numbers of defined stars. */
|
||||
inline int getNumStars() const { return stars->getNumStars(); }
|
||||
@@ -167,7 +169,7 @@ public:
|
||||
* third is the magnitude.
|
||||
* @returns star array
|
||||
*/
|
||||
inline sgdVec3 *getStars() { return stars->getStars(); }
|
||||
inline SGVec3d *getStars() { return stars->getStars(); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#endif
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
|
||||
#include "stardata.hxx"
|
||||
@@ -34,16 +35,9 @@
|
||||
#endif
|
||||
|
||||
// Constructor
|
||||
SGStarData::SGStarData() :
|
||||
nstars(0)
|
||||
SGStarData::SGStarData( const SGPath& path )
|
||||
{
|
||||
}
|
||||
|
||||
SGStarData::SGStarData( SGPath path ) :
|
||||
nstars(0)
|
||||
{
|
||||
data_path = SGPath( path );
|
||||
load();
|
||||
load(path);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,31 +46,28 @@ SGStarData::~SGStarData() {
|
||||
}
|
||||
|
||||
|
||||
bool SGStarData::load() {
|
||||
bool SGStarData::load( const SGPath& path ) {
|
||||
|
||||
// -dw- avoid local data > 32k error by dynamic allocation of the
|
||||
// array, problem for some compilers
|
||||
stars = new sgdVec3[SG_MAX_STARS];
|
||||
_stars.clear();
|
||||
|
||||
// build the full path name to the stars data base file
|
||||
data_path.append( "stars" );
|
||||
SG_LOG( SG_ASTRO, SG_INFO, " Loading stars from " << data_path.str() );
|
||||
// build the full path name to the stars data base file
|
||||
SGPath tmp = path;
|
||||
tmp.append( "stars" );
|
||||
SG_LOG( SG_ASTRO, SG_INFO, " Loading stars from " << tmp.str() );
|
||||
|
||||
sg_gzifstream in( data_path.str() );
|
||||
sg_gzifstream in( tmp.str() );
|
||||
if ( ! in.is_open() ) {
|
||||
SG_LOG( SG_ASTRO, SG_ALERT, "Cannot open star file: "
|
||||
<< data_path.str() );
|
||||
exit(-1);
|
||||
<< tmp.str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
double ra, dec, mag;
|
||||
char c;
|
||||
string name;
|
||||
|
||||
nstars = 0;
|
||||
|
||||
// read in each line of the file
|
||||
while ( ! in.eof() && nstars < SG_MAX_STARS ) {
|
||||
while ( ! in.eof() ) {
|
||||
in >> skipcomment;
|
||||
|
||||
getline( in, name, ',' );
|
||||
@@ -116,13 +107,10 @@ bool SGStarData::load() {
|
||||
in >> mag;
|
||||
|
||||
// cout << " star data = " << ra << " " << dec << " " << mag << endl;
|
||||
|
||||
sgdSetVec3( stars[nstars], ra, dec, mag );
|
||||
|
||||
++nstars;
|
||||
_stars.push_back(SGVec3d(ra, dec, mag));
|
||||
}
|
||||
|
||||
SG_LOG( SG_ASTRO, SG_INFO, " Loaded " << nstars << " stars" );
|
||||
SG_LOG( SG_ASTRO, SG_INFO, " Loaded " << _stars.size() << " stars" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,37 +24,28 @@
|
||||
#ifndef _SG_STARDATA_HXX
|
||||
#define _SG_STARDATA_HXX
|
||||
|
||||
#include <vector>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#include <plib/sg.h>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
|
||||
#define SG_MAX_STARS 850
|
||||
|
||||
class SGPath;
|
||||
|
||||
class SGStarData {
|
||||
|
||||
int nstars;
|
||||
sgdVec3 *stars;
|
||||
|
||||
SGPath data_path;
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
SGStarData();
|
||||
SGStarData( SGPath path );
|
||||
SGStarData( const SGPath& path );
|
||||
|
||||
// Destructor
|
||||
~SGStarData();
|
||||
|
||||
// load the stars database
|
||||
bool load();
|
||||
bool load( const SGPath& path );
|
||||
|
||||
// stars
|
||||
inline int getNumStars() const { return nstars; }
|
||||
inline sgdVec3 *getStars() { return stars; }
|
||||
inline int getNumStars() const { return _stars.size(); }
|
||||
inline SGVec3d *getStars() { return &(_stars[0]); }
|
||||
|
||||
private:
|
||||
std::vector<SGVec3d> _stars;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -37,14 +37,14 @@ int main( int argc, char **argv ) {
|
||||
obj.get_gbs_radius());
|
||||
cout << endl;
|
||||
|
||||
point_list nodes = obj.get_wgs84_nodes();
|
||||
std::vector<SGVec3d> nodes = obj.get_wgs84_nodes();
|
||||
cout << "# vertex list" << endl;
|
||||
for ( i = 0; i < (int)nodes.size(); ++i ) {
|
||||
printf("v %.5f %.5f %.5f\n", nodes[i].x(), nodes[i].y(), nodes[i].z() );
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
point_list normals = obj.get_normals();
|
||||
std::vector<SGVec3f> normals = obj.get_normals();
|
||||
cout << "# vertex normal list" << endl;
|
||||
for ( i = 0; i < (int)normals.size(); ++i ) {
|
||||
printf("vn %.5f %.5f %.5f\n",
|
||||
@@ -52,7 +52,7 @@ int main( int argc, char **argv ) {
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
point_list texcoords = obj.get_texcoords();
|
||||
std::vector<SGVec2f> texcoords = obj.get_texcoords();
|
||||
cout << "# texture coordinate list" << endl;
|
||||
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
||||
printf("vt %.5f %.5f\n",
|
||||
|
||||
@@ -174,7 +174,7 @@ static void read_object( gzFile fp,
|
||||
int idx_size;
|
||||
bool do_vertices, do_normals, do_colors, do_texcoords;
|
||||
int j, k, idx;
|
||||
static sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||
sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||
char material[256];
|
||||
|
||||
// default values
|
||||
@@ -280,13 +280,13 @@ static void read_object( gzFile fp,
|
||||
|
||||
// read a binary file and populate the provided structures.
|
||||
bool SGBinObject::read_bin( const string& file ) {
|
||||
Point3D p;
|
||||
SGVec3d p;
|
||||
int i, j, k;
|
||||
unsigned int nbytes;
|
||||
static sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||
sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||
|
||||
// zero out structures
|
||||
gbs_center = Point3D( 0 );
|
||||
gbs_center = SGVec3d(0, 0, 0);
|
||||
gbs_radius = 0.0;
|
||||
|
||||
wgs84_nodes.clear();
|
||||
@@ -322,7 +322,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
string filegz = file + ".gz";
|
||||
if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) {
|
||||
SG_LOG( SG_EVENT, SG_ALERT,
|
||||
"ERROR: opening " << file << " or " << filegz << "for reading!");
|
||||
"ERROR: opening " << file << " or " << filegz << " for reading!");
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -407,7 +407,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
sgEndianSwap( (uint64_t *)&(dptr[1]) );
|
||||
sgEndianSwap( (uint64_t *)&(dptr[2]) );
|
||||
}
|
||||
gbs_center = Point3D( dptr[0], dptr[1], dptr[2] );
|
||||
gbs_center = SGVec3d( dptr[0], dptr[1], dptr[2] );
|
||||
// cout << "Center = " << gbs_center << endl;
|
||||
ptr += sizeof(double) * 3;
|
||||
|
||||
@@ -447,7 +447,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[2]) );
|
||||
}
|
||||
wgs84_nodes.push_back( Point3D(fptr[0], fptr[1], fptr[2]) );
|
||||
wgs84_nodes.push_back( SGVec3d(fptr[0], fptr[1], fptr[2]) );
|
||||
fptr += 3;
|
||||
}
|
||||
}
|
||||
@@ -481,7 +481,8 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
sgEndianSwap( (uint32_t *)&(fptr[2]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[3]) );
|
||||
}
|
||||
colors.push_back( Point3D( fptr[0], fptr[1], fptr[2] ) );
|
||||
SGVec4f color( fptr[0], fptr[1], fptr[2], fptr[3] );
|
||||
colors.push_back( color );
|
||||
fptr += 4;
|
||||
}
|
||||
}
|
||||
@@ -508,14 +509,11 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
int count = nbytes / 3;
|
||||
normals.reserve( count );
|
||||
for ( k = 0; k < count; ++k ) {
|
||||
sgdVec3 normal;
|
||||
sgdSetVec3( normal,
|
||||
(ptr[0]) / 127.5 - 1.0,
|
||||
(ptr[1]) / 127.5 - 1.0,
|
||||
(ptr[2]) / 127.5 - 1.0 );
|
||||
sgdNormalizeVec3( normal );
|
||||
SGVec3f normal((ptr[0]) / 127.5 - 1.0,
|
||||
(ptr[1]) / 127.5 - 1.0,
|
||||
(ptr[2]) / 127.5 - 1.0);
|
||||
|
||||
normals.push_back(Point3D(normal[0], normal[1], normal[2]));
|
||||
normals.push_back(normalize(normal));
|
||||
ptr += 3;
|
||||
}
|
||||
}
|
||||
@@ -547,7 +545,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
sgEndianSwap( (uint32_t *)&(fptr[0]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
||||
}
|
||||
texcoords.push_back( Point3D( fptr[0], fptr[1], 0 ) );
|
||||
texcoords.push_back( SGVec2f( fptr[0], fptr[1] ) );
|
||||
fptr += 2;
|
||||
}
|
||||
}
|
||||
@@ -612,10 +610,6 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
const SGBucket& b )
|
||||
{
|
||||
Point3D p;
|
||||
sgVec2 t;
|
||||
sgVec3 pt;
|
||||
sgVec4 color;
|
||||
int i, j;
|
||||
unsigned char idx_mask;
|
||||
int idx_size;
|
||||
@@ -738,9 +732,8 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
sgWriteShort( fp, 1 ); // nelements
|
||||
sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes
|
||||
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
|
||||
p = wgs84_nodes[i] - gbs_center;
|
||||
sgSetVec3( pt, p.x(), p.y(), p.z() );
|
||||
sgWriteVec3( fp, pt );
|
||||
SGVec3f p = toVec3f(wgs84_nodes[i] - gbs_center);
|
||||
sgWriteVec3( fp, p.data() );
|
||||
}
|
||||
|
||||
// dump vertex color list
|
||||
@@ -749,12 +742,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
sgWriteShort( fp, 1 ); // nelements
|
||||
sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes
|
||||
for ( i = 0; i < (int)colors.size(); ++i ) {
|
||||
p = colors[i];
|
||||
// Right now we have a place holder for color alpha but we
|
||||
// need to update the interface so the calling program can
|
||||
// provide the info.
|
||||
sgSetVec4( color, p.x(), p.y(), p.z(), 1.0 );
|
||||
sgWriteVec4( fp, color );
|
||||
sgWriteVec4( fp, colors[i].data() );
|
||||
}
|
||||
|
||||
// dump vertex normal list
|
||||
@@ -764,7 +752,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
sgWriteUInt( fp, normals.size() * 3 ); // nbytes
|
||||
char normal[3];
|
||||
for ( i = 0; i < (int)normals.size(); ++i ) {
|
||||
p = normals[i];
|
||||
SGVec3f p = normals[i];
|
||||
normal[0] = (unsigned char)((p.x() + 1.0) * 127.5);
|
||||
normal[1] = (unsigned char)((p.y() + 1.0) * 127.5);
|
||||
normal[2] = (unsigned char)((p.z() + 1.0) * 127.5);
|
||||
@@ -777,9 +765,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
sgWriteShort( fp, 1 ); // nelements
|
||||
sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes
|
||||
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
||||
p = texcoords[i];
|
||||
sgSetVec2( t, p.x(), p.y() );
|
||||
sgWriteVec2( fp, t );
|
||||
sgWriteVec2( fp, texcoords[i].data() );
|
||||
}
|
||||
|
||||
// dump point groups if they exist
|
||||
@@ -1042,7 +1028,6 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
const SGBucket& b )
|
||||
{
|
||||
Point3D p;
|
||||
int i, j;
|
||||
|
||||
SGPath file = base + "/" + b.gen_base_path() + "/" + name;
|
||||
@@ -1084,7 +1069,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
// dump vertex list
|
||||
fprintf(fp, "# vertex list\n");
|
||||
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
|
||||
p = wgs84_nodes[i] - gbs_center;
|
||||
SGVec3d p = wgs84_nodes[i] - gbs_center;
|
||||
|
||||
fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
|
||||
}
|
||||
@@ -1092,7 +1077,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
|
||||
fprintf(fp, "# vertex normal list\n");
|
||||
for ( i = 0; i < (int)normals.size(); ++i ) {
|
||||
p = normals[i];
|
||||
SGVec3f p = normals[i];
|
||||
fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
@@ -1100,7 +1085,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
// dump texture coordinates
|
||||
fprintf(fp, "# texture coordinate list\n");
|
||||
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
||||
p = texcoords[i];
|
||||
SGVec2f p = texcoords[i];
|
||||
fprintf(fp, "vt %.5f %.5f\n", p.x(), p.y() );
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
@@ -1126,13 +1111,13 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
// make a list of points for the group
|
||||
point_list group_nodes;
|
||||
group_nodes.clear();
|
||||
Point3D bs_center;
|
||||
SGVec3d bs_center;
|
||||
double bs_radius = 0;
|
||||
for ( i = start; i < end; ++i ) {
|
||||
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
||||
group_nodes.push_back( wgs84_nodes[ tris_v[i][j] ] );
|
||||
bs_center = sgCalcCenter( group_nodes );
|
||||
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
|
||||
group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ tris_v[i][j] ]) );
|
||||
bs_center = sgCalcCenter( group_nodes ).toSGVec3d();
|
||||
bs_radius = sgCalcBoundingRadius( Point3D::fromSGVec3(bs_center), group_nodes );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,13 +1162,13 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
// make a list of points for the group
|
||||
point_list group_nodes;
|
||||
group_nodes.clear();
|
||||
Point3D bs_center;
|
||||
SGVec3d bs_center;
|
||||
double bs_radius = 0;
|
||||
for ( i = start; i < end; ++i ) {
|
||||
for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
|
||||
group_nodes.push_back( wgs84_nodes[ strips_v[i][j] ] );
|
||||
bs_center = sgCalcCenter( group_nodes );
|
||||
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
|
||||
group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ strips_v[i][j] ]) );
|
||||
bs_center = sgCalcCenter( group_nodes ).toSGVec3d();
|
||||
bs_radius = sgCalcBoundingRadius( Point3D::fromSGVec3(bs_center), group_nodes );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,13 +89,13 @@ typedef group_list::const_iterator const_group_list_iterator;
|
||||
class SGBinObject {
|
||||
unsigned short version;
|
||||
|
||||
Point3D gbs_center;
|
||||
SGVec3d gbs_center;
|
||||
float gbs_radius;
|
||||
|
||||
point_list wgs84_nodes; // vertex list
|
||||
point_list colors; // color list
|
||||
point_list normals; // normal list
|
||||
point_list texcoords; // texture coordinate list
|
||||
std::vector<SGVec3d> wgs84_nodes; // vertex list
|
||||
std::vector<SGVec4f> colors; // color list
|
||||
std::vector<SGVec3f> normals; // normal list
|
||||
std::vector<SGVec2f> texcoords; // texture coordinate list
|
||||
|
||||
group_list pts_v; // points vertex index
|
||||
group_list pts_n; // points normal index
|
||||
@@ -125,23 +125,51 @@ public:
|
||||
|
||||
inline unsigned short get_version() const { return version; }
|
||||
|
||||
inline const Point3D& get_gbs_center() const { return gbs_center; }
|
||||
inline void set_gbs_center( const Point3D& p ) { gbs_center = p; }
|
||||
inline Point3D get_gbs_center() const { return Point3D::fromSGVec3(gbs_center); }
|
||||
inline void set_gbs_center( const Point3D& p ) { gbs_center = p.toSGVec3d(); }
|
||||
inline const SGVec3d& get_gbs_center2() const { return gbs_center; }
|
||||
inline void set_gbs_center( const SGVec3d& p ) { gbs_center = p; }
|
||||
|
||||
inline float get_gbs_radius() const { return gbs_radius; }
|
||||
inline void set_gbs_radius( float r ) { gbs_radius = r; }
|
||||
|
||||
inline const point_list& get_wgs84_nodes() const { return wgs84_nodes; }
|
||||
inline void set_wgs84_nodes( const point_list& n ) { wgs84_nodes = n; }
|
||||
inline const std::vector<SGVec3d>& get_wgs84_nodes() const
|
||||
{ return wgs84_nodes; }
|
||||
inline void set_wgs84_nodes( const std::vector<SGVec3d>& n )
|
||||
{ wgs84_nodes = n; }
|
||||
inline void set_wgs84_nodes( const point_list& n )
|
||||
{
|
||||
wgs84_nodes.resize(n.size());
|
||||
for (unsigned i = 0; i < wgs84_nodes.size(); ++i)
|
||||
wgs84_nodes[i] = n[i].toSGVec3d();
|
||||
}
|
||||
|
||||
inline const point_list& get_colors() const { return colors; }
|
||||
inline void set_colors( const point_list& c ) { colors = c; }
|
||||
inline const std::vector<SGVec4f>& get_colors() const { return colors; }
|
||||
inline void set_colors( const std::vector<SGVec4f>& c ) { colors = c; }
|
||||
inline void set_colors( const point_list& c )
|
||||
{
|
||||
colors.resize(c.size());
|
||||
for (unsigned i = 0; i < colors.size(); ++i)
|
||||
colors[i] = SGVec4f(c[i].toSGVec3f(), 1);
|
||||
}
|
||||
|
||||
inline const point_list& get_normals() const { return normals; }
|
||||
inline void set_normals( const point_list& n ) { normals = n; }
|
||||
inline const std::vector<SGVec3f>& get_normals() const { return normals; }
|
||||
inline void set_normals( const std::vector<SGVec3f>& n ) { normals = n; }
|
||||
inline void set_normals( const point_list& n )
|
||||
{
|
||||
normals.resize(n.size());
|
||||
for (unsigned i = 0; i < normals.size(); ++i)
|
||||
normals[i] = n[i].toSGVec3f();
|
||||
}
|
||||
|
||||
inline const point_list& get_texcoords() const { return texcoords; }
|
||||
inline void set_texcoords( const point_list& t ) { texcoords = t; }
|
||||
inline const std::vector<SGVec2f>& get_texcoords() const { return texcoords; }
|
||||
inline void set_texcoords( const std::vector<SGVec2f>& t ) { texcoords = t; }
|
||||
inline void set_texcoords( const point_list& t )
|
||||
{
|
||||
texcoords.resize(t.size());
|
||||
for (unsigned i = 0; i < texcoords.size(); ++i)
|
||||
texcoords[i] = t[i].toSGVec2f();
|
||||
}
|
||||
|
||||
inline const group_list& get_pts_v() const { return pts_v; }
|
||||
inline void set_pts_v( const group_list& g ) { pts_v = g; }
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
includedir = @includedir@/math
|
||||
|
||||
check_PROGRAMS = SGMathTest
|
||||
check_PROGRAMS = SGMathTest SGGeometryTest
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
SGMathTest_SOURCES = SGMathTest.cxx
|
||||
SGMathTest_LDADD = libsgmath.a $(base_LIBS)
|
||||
|
||||
SGGeometryTest_SOURCES = SGGeometryTest.cxx
|
||||
SGGeometryTest_LDADD = libsgmath.a $(base_LIBS)
|
||||
|
||||
lib_LIBRARIES = libsgmath.a
|
||||
|
||||
@@ -19,19 +21,28 @@ include_HEADERS = \
|
||||
sg_random.h \
|
||||
sg_types.hxx \
|
||||
vector.hxx \
|
||||
SGBox.hxx \
|
||||
SGCMath.hxx \
|
||||
SGGeoc.hxx \
|
||||
SGGeod.hxx \
|
||||
SGGeodesy.hxx \
|
||||
SGGeometry.hxx \
|
||||
SGGeometryFwd.hxx \
|
||||
SGIntersect.hxx \
|
||||
SGLimits.hxx \
|
||||
SGLineSegment.hxx \
|
||||
SGMatrix.hxx \
|
||||
SGMath.hxx \
|
||||
SGMathFwd.hxx \
|
||||
SGMisc.hxx \
|
||||
SGPlane.hxx \
|
||||
SGQuat.hxx \
|
||||
SGVec4.hxx \
|
||||
SGVec3.hxx
|
||||
|
||||
SGRay.hxx \
|
||||
SGSphere.hxx \
|
||||
SGTriangle.hxx \
|
||||
SGVec2.hxx \
|
||||
SGVec3.hxx \
|
||||
SGVec4.hxx
|
||||
|
||||
libsgmath_a_SOURCES = \
|
||||
interpolater.cxx \
|
||||
|
||||
107
simgear/math/SGBox.hxx
Normal file
107
simgear/math/SGBox.hxx
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGBox_H
|
||||
#define SGBox_H
|
||||
|
||||
template<typename T>
|
||||
class SGBox {
|
||||
public:
|
||||
SGBox() :
|
||||
_min(SGLimits<T>::max(), SGLimits<T>::max(), SGLimits<T>::max()),
|
||||
_max(-SGLimits<T>::max(), -SGLimits<T>::max(), -SGLimits<T>::max())
|
||||
{ }
|
||||
void setMin(const SGVec3<T>& min)
|
||||
{ _min = min; }
|
||||
const SGVec3<T>& getMin() const
|
||||
{ return _min; }
|
||||
|
||||
void setMax(const SGVec3<T>& max)
|
||||
{ _max = max; }
|
||||
const SGVec3<T>& getMax() const
|
||||
{ return _max; }
|
||||
|
||||
// Only works for floating point types
|
||||
SGVec3<T> getCenter() const
|
||||
{ return T(0.5)*(_min + _max); }
|
||||
|
||||
// Only valid for nonempty boxes
|
||||
SGVec3<T> getSize() const
|
||||
{ return _max - _min; }
|
||||
|
||||
T getVolume() const
|
||||
{
|
||||
if (empty())
|
||||
return 0;
|
||||
return (_max[0] - _min[0])*(_max[1] - _min[1])*(_max[2] - _min[2]);
|
||||
}
|
||||
|
||||
const bool empty() const
|
||||
{ return !valid(); }
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
if (_max[0] < _min[0])
|
||||
return false;
|
||||
if (_max[1] < _min[1])
|
||||
return false;
|
||||
if (_max[2] < _min[2])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
_min[0] = SGLimits<T>::max();
|
||||
_min[1] = SGLimits<T>::max();
|
||||
_min[2] = SGLimits<T>::max();
|
||||
_max[0] = -SGLimits<T>::max();
|
||||
_max[1] = -SGLimits<T>::max();
|
||||
_max[2] = -SGLimits<T>::max();
|
||||
}
|
||||
|
||||
void expandBy(const SGVec3<T>& v)
|
||||
{ _min = min(_min, v); _max = max(_max, v); }
|
||||
|
||||
void expandBy(const SGBox<T>& b)
|
||||
{ _min = min(_min, b._min); _max = max(_max, b._max); }
|
||||
|
||||
// Note that this only works if the box is nonmepty
|
||||
unsigned getBroadestAxis() const
|
||||
{
|
||||
SGVec3d size = getSize();
|
||||
if (size[1] <= size[0] && size[2] <= size[0])
|
||||
return 0;
|
||||
else if (size[2] <= size[1])
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
private:
|
||||
SGVec3<T> _min;
|
||||
SGVec3<T> _max;
|
||||
};
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGBox<T>& box)
|
||||
{ return s << "min = " << box.getMin() << ", max = " << box.getMax(); }
|
||||
|
||||
#endif
|
||||
38
simgear/math/SGGeometry.hxx
Normal file
38
simgear/math/SGGeometry.hxx
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGGeometry_HXX
|
||||
#define SGGeometry_HXX
|
||||
|
||||
// Required ...
|
||||
#include "SGMath.hxx"
|
||||
|
||||
// Make sure all is defined
|
||||
#include "SGGeometryFwd.hxx"
|
||||
|
||||
// Geometric primitives we know about
|
||||
#include "SGBox.hxx"
|
||||
#include "SGSphere.hxx"
|
||||
#include "SGRay.hxx"
|
||||
#include "SGLineSegment.hxx"
|
||||
#include "SGPlane.hxx"
|
||||
#include "SGTriangle.hxx"
|
||||
|
||||
// Intersection tests
|
||||
#include "SGIntersect.hxx"
|
||||
|
||||
#endif
|
||||
51
simgear/math/SGGeometryFwd.hxx
Normal file
51
simgear/math/SGGeometryFwd.hxx
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGGeometryFwd_HXX
|
||||
#define SGGeometryFwd_HXX
|
||||
|
||||
template<typename T>
|
||||
class SGBox;
|
||||
typedef SGBox<float> SGBoxf;
|
||||
typedef SGBox<double> SGBoxd;
|
||||
|
||||
template<typename T>
|
||||
class SGSphere;
|
||||
typedef SGSphere<float> SGSpheref;
|
||||
typedef SGSphere<double> SGSphered;
|
||||
|
||||
template<typename T>
|
||||
class SGRay;
|
||||
typedef SGRay<float> SGRayf;
|
||||
typedef SGRay<double> SGRayd;
|
||||
|
||||
template<typename T>
|
||||
class SGLineSegment;
|
||||
typedef SGLineSegment<float> SGLineSegmentf;
|
||||
typedef SGLineSegment<double> SGLineSegmentd;
|
||||
|
||||
template<typename T>
|
||||
class SGPlane;
|
||||
typedef SGPlane<float> SGPlanef;
|
||||
typedef SGPlane<double> SGPlaned;
|
||||
|
||||
template<typename T>
|
||||
class SGTriangle;
|
||||
typedef SGTriangle<float> SGTrianglef;
|
||||
typedef SGTriangle<double> SGTriangled;
|
||||
|
||||
#endif
|
||||
442
simgear/math/SGGeometryTest.cxx
Normal file
442
simgear/math/SGGeometryTest.cxx
Normal file
@@ -0,0 +1,442 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "SGGeometry.hxx"
|
||||
#include "sg_random.h"
|
||||
|
||||
template<typename T>
|
||||
SGVec3<T> rndVec3(void)
|
||||
{
|
||||
return SGVec3<T>(sg_random(), sg_random(), sg_random());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
TriangleLineIntersectionTest(void)
|
||||
{
|
||||
unsigned nTests = 100000;
|
||||
unsigned failedCount = 0;
|
||||
for (unsigned i = 0; i < nTests; ++i) {
|
||||
SGVec3<T> v0 = rndVec3<T>();
|
||||
SGVec3<T> v1 = rndVec3<T>();
|
||||
SGVec3<T> v2 = rndVec3<T>();
|
||||
|
||||
SGTriangle<T> tri(v0, v1, v2);
|
||||
|
||||
// generate random coeficients
|
||||
T u = 4*sg_random() - 2;
|
||||
T v = 4*sg_random() - 2;
|
||||
T t = 4*sg_random() - 2;
|
||||
|
||||
SGVec3<T> isectpt = v0 + u*(v1 - v0) + v*(v2 - v0);
|
||||
|
||||
SGLineSegment<T> lineSegment;
|
||||
SGVec3<T> dir = rndVec3<T>();
|
||||
|
||||
SGVec3<T> isectres;
|
||||
lineSegment.set(isectpt - t*dir, isectpt + (1 - t)*dir);
|
||||
|
||||
if (intersects(isectres, tri, lineSegment)) {
|
||||
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t && t <= 1) {
|
||||
if (!equivalent(isectres, isectpt)) {
|
||||
std::cout << "Failed line segment intersection test #" << i
|
||||
<< ": not equivalent!\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
std::cout << "Failed line segment intersection test #" << i
|
||||
<< ": false positive!\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t && t <= 1) {
|
||||
std::cout << "Failed line segment intersection test #" << i
|
||||
<< ": false negative!\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
|
||||
SGRay<T> ray;
|
||||
ray.set(isectpt - t*dir, dir);
|
||||
if (intersects(isectres, tri, ray)) {
|
||||
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t) {
|
||||
if (!equivalent(isectres, isectpt)) {
|
||||
std::cout << "Failed ray intersection test #" << i
|
||||
<< ": not equivalent!\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
std::cout << "Failed ray intersection test #" << i
|
||||
<< ": false positive!\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t) {
|
||||
std::cout << "Failed ray intersection test #" << i
|
||||
<< ": false negative !\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nTests < 100*failedCount) {
|
||||
std::cout << "Failed ray intersection tests: " << failedCount
|
||||
<< " tests out of " << nTests
|
||||
<< " went wrong. Abort!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Some crude handmade test
|
||||
SGVec3<T> v0 = SGVec3<T>(0, 0, 0);
|
||||
SGVec3<T> v1 = SGVec3<T>(1, 0, 0);
|
||||
SGVec3<T> v2 = SGVec3<T>(0, 1, 0);
|
||||
|
||||
SGTriangle<T> tri(v0, v1, v2);
|
||||
|
||||
SGRay<T> ray;
|
||||
ray.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0.1, 0.1, -1));
|
||||
if (!intersects(tri, ray)) {
|
||||
std::cout << "Failed test #1!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ray.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 0, -1));
|
||||
if (!intersects(tri, ray)) {
|
||||
std::cout << "Failed test #2!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
SGLineSegment<T> lineSegment;
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0.1, 0.1, -1));
|
||||
if (!intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #3!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 0, -1));
|
||||
if (!intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #4!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 1, -1));
|
||||
if (!intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #5!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 0, -1));
|
||||
if (!intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #6!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 1, -1));
|
||||
if (!intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #7!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// is exactly in the plane
|
||||
// FIXME: cannot detect that yet ??
|
||||
// lineSegment.set(SGVec3<T>(0, 0, 0), SGVec3<T>(1, 0, 0));
|
||||
// if (!intersects(tri, lineSegment)) {
|
||||
// std::cout << "Failed test #8!" << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// is exactly in the plane
|
||||
// FIXME: cannot detect that yet ??
|
||||
// lineSegment.set(SGVec3<T>(-1, 0, 0), SGVec3<T>(1, 0, 0));
|
||||
// if (!intersects(tri, lineSegment)) {
|
||||
// std::cout << "Failed test #9!" << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// is exactly paralell to the plane
|
||||
// FIXME: cannot detect that yet ??
|
||||
// lineSegment.set(SGVec3<T>(-1, 1, 0), SGVec3<T>(1, 1, 0));
|
||||
// if (intersects(tri, lineSegment)) {
|
||||
// std::cout << "Failed test #10!" << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// should fail since the line segment poins slightly beyond the triangle
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 1, -0.9));
|
||||
if (intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #11!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, -0.1, -1));
|
||||
if (intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #12!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(-0.1, -0.1, -1));
|
||||
if (intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #13!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(-0.1, 0, -1));
|
||||
if (intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #14!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
SphereLineIntersectionTest(void)
|
||||
{
|
||||
unsigned nTests = 100000;
|
||||
unsigned failedCount = 0;
|
||||
for (unsigned i = 0; i < nTests; ++i) {
|
||||
SGVec3<T> center = rndVec3<T>();
|
||||
T radius = 2*sg_random();
|
||||
SGSphere<T> sphere(center, radius);
|
||||
|
||||
SGVec3<T> offset = normalize(rndVec3<T>());
|
||||
T t = 4*sg_random();
|
||||
|
||||
// This one is the point we use to judge if the test should fail or not
|
||||
SGVec3<T> base = center + t*offset;
|
||||
|
||||
SGVec3<T> per = perpendicular(offset);
|
||||
SGVec3<T> start = base + 4*sg_random()*per;
|
||||
SGVec3<T> end = base - 4*sg_random()*per;
|
||||
|
||||
SGLineSegment<T> lineSegment;
|
||||
lineSegment.set(start, end);
|
||||
if (intersects(sphere, lineSegment)) {
|
||||
if (radius < t) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false positive!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (t <= radius) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false negative!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
|
||||
SGRay<T> ray;
|
||||
ray.set(start, end - start);
|
||||
if (intersects(sphere, ray)) {
|
||||
if (radius < t) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false positive!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (t <= radius) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false negative!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nTests < 100*failedCount) {
|
||||
std::cout << "Failed sphere line intersection tests: " << failedCount
|
||||
<< " tests out of " << nTests
|
||||
<< " went wrong. Abort!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
failedCount = 0;
|
||||
for (unsigned i = 0; i < nTests; ++i) {
|
||||
SGVec3<T> center = rndVec3<T>();
|
||||
T radius = 2*sg_random();
|
||||
SGSphere<T> sphere(center, radius);
|
||||
|
||||
SGVec3<T> offset = normalize(rndVec3<T>());
|
||||
T t = 4*sg_random();
|
||||
|
||||
// This one is the point we use to judge if the test should fail or not
|
||||
SGVec3<T> base = center + t*offset;
|
||||
|
||||
SGVec3<T> start = base;
|
||||
SGVec3<T> end = base + 2*sg_random()*offset;
|
||||
|
||||
SGLineSegment<T> lineSegment;
|
||||
lineSegment.set(start, end);
|
||||
if (intersects(sphere, lineSegment)) {
|
||||
if (radius < t) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false positive!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (t <= radius) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false negative!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
|
||||
SGRay<T> ray;
|
||||
ray.set(start, end - start);
|
||||
if (intersects(sphere, ray)) {
|
||||
if (radius < t) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false positive!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (t <= radius) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false negative!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nTests < 100*failedCount) {
|
||||
std::cout << "Failed sphere line intersection tests: " << failedCount
|
||||
<< " tests out of " << nTests
|
||||
<< " went wrong. Abort!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
BoxLineIntersectionTest(void)
|
||||
{
|
||||
// ok, bad test case coverage, but better than nothing ...
|
||||
|
||||
unsigned nTests = 100000;
|
||||
unsigned failedCount = 0;
|
||||
for (unsigned i = 0; i < nTests; ++i) {
|
||||
SGBox<T> box;
|
||||
box.expandBy(rndVec3<T>());
|
||||
box.expandBy(rndVec3<T>());
|
||||
|
||||
SGVec3<T> center = box.getCenter();
|
||||
|
||||
// This one is the point we use to judge if the test should fail or not
|
||||
SGVec3<T> base = rndVec3<T>();
|
||||
SGVec3<T> dir = base - center;
|
||||
|
||||
SGLineSegment<T> lineSegment;
|
||||
lineSegment.set(base, base + dir);
|
||||
if (intersects(box, lineSegment)) {
|
||||
if (!intersects(box, base)) {
|
||||
std::cout << "Failed box line intersection test #" << i
|
||||
<< ": false positive!\n"
|
||||
<< box << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (intersects(box, base)) {
|
||||
std::cout << "Failed box line intersection test #" << i
|
||||
<< ": false negative!\n"
|
||||
<< box << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
|
||||
SGRay<T> ray;
|
||||
ray.set(base, dir);
|
||||
if (intersects(box, ray)) {
|
||||
if (!intersects(box, base)) {
|
||||
std::cout << "Failed box line intersection test #" << i
|
||||
<< ": false positive!\n"
|
||||
<< box << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (intersects(box, base)) {
|
||||
std::cout << "Failed box line intersection test #" << i
|
||||
<< ": false negative!\n"
|
||||
<< box << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nTests < 100*failedCount) {
|
||||
std::cout << "Failed box line intersection tests: " << failedCount
|
||||
<< " tests out of " << nTests
|
||||
<< " went wrong. Abort!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
std::cout << "Testing Geometry intersection routines.\n"
|
||||
<< "Some of these tests can fail due to roundoff problems...\n"
|
||||
<< "Dont worry if only a few of them fail..." << std::endl;
|
||||
|
||||
if (!TriangleLineIntersectionTest<float>())
|
||||
return EXIT_FAILURE;
|
||||
if (!TriangleLineIntersectionTest<double>())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!SphereLineIntersectionTest<float>())
|
||||
return EXIT_FAILURE;
|
||||
if (!SphereLineIntersectionTest<double>())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!BoxLineIntersectionTest<float>())
|
||||
return EXIT_FAILURE;
|
||||
if (!BoxLineIntersectionTest<double>())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
std::cout << "Successfully passed all tests!" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
627
simgear/math/SGIntersect.hxx
Normal file
627
simgear/math/SGIntersect.hxx
Normal file
@@ -0,0 +1,627 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGIntersect_HXX
|
||||
#define SGIntersect_HXX
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGBox<T>& box, const SGSphere<T>& sphere)
|
||||
{
|
||||
if (sphere.empty())
|
||||
return false;
|
||||
// Is more or less trivially included in the next tests
|
||||
// if (box.empty())
|
||||
// return false;
|
||||
|
||||
if (sphere.getCenter().x() < box.getMin().x() - sphere.getRadius())
|
||||
return false;
|
||||
if (sphere.getCenter().y() < box.getMin().y() - sphere.getRadius())
|
||||
return false;
|
||||
if (sphere.getCenter().z() < box.getMin().z() - sphere.getRadius())
|
||||
return false;
|
||||
|
||||
if (box.getMax().x() + sphere.getRadius() < sphere.getCenter().x())
|
||||
return false;
|
||||
if (box.getMax().y() + sphere.getRadius() < sphere.getCenter().y())
|
||||
return false;
|
||||
if (box.getMax().z() + sphere.getRadius() < sphere.getCenter().z())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGSphere<T>& sphere, const SGBox<T>& box)
|
||||
{ return intersects(box, sphere); }
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGVec3<T>& v, const SGBox<T>& box)
|
||||
{
|
||||
if (v[0] < box.getMin()[0])
|
||||
return false;
|
||||
if (box.getMax()[0] < v[0])
|
||||
return false;
|
||||
if (v[1] < box.getMin()[1])
|
||||
return false;
|
||||
if (box.getMax()[1] < v[1])
|
||||
return false;
|
||||
if (v[2] < box.getMin()[2])
|
||||
return false;
|
||||
if (box.getMax()[2] < v[2])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGBox<T>& box, const SGVec3<T>& v)
|
||||
{ return intersects(v, box); }
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGRay<T>& ray, const SGPlane<T>& plane)
|
||||
{
|
||||
// We compute the intersection point
|
||||
// x = origin + \alpha*direction
|
||||
// from the ray origin and non nomalized direction.
|
||||
// For 0 <= \alpha the ray intersects the infinite plane.
|
||||
// The intersection point x can also be written
|
||||
// x = n*dist + y
|
||||
// where n is the planes normal, dist is the distance of the plane from
|
||||
// the origin in normal direction and y is ana aproriate vector
|
||||
// perpendicular to n.
|
||||
// Equate the x values and take the scalar product with the plane normal n.
|
||||
// dot(n, origin) + \alpha*dot(n, direction) = dist
|
||||
// We can now compute alpha from the above equation.
|
||||
// \alpha = (dist - dot(n, origin))/dot(n, direction)
|
||||
|
||||
// The negative numerator for the \alpha expression
|
||||
T num = plane.getPositiveDist();
|
||||
num -= dot(plane.getNormal(), ray.getOrigin());
|
||||
|
||||
// If the numerator is zero, we have the rays origin included in the plane
|
||||
if (fabs(num) <= SGLimits<T>::min())
|
||||
return true;
|
||||
|
||||
// The denominator for the \alpha expression
|
||||
T den = dot(plane.getNormal(), ray.getDirection());
|
||||
|
||||
// If we get here, we already know that the rays origin is not included
|
||||
// in the plane. Thus if we have a zero denominator we have
|
||||
// a ray paralell to the plane. That is no intersection.
|
||||
if (fabs(den) <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
// We would now compute \alpha = num/den and compare with 0 and 1.
|
||||
// But to avoid that expensive division, check equation multiplied by
|
||||
// the denominator.
|
||||
T alphaDen = copysign(1, den)*num;
|
||||
if (alphaDen < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGPlane<T>& plane, const SGRay<T>& ray)
|
||||
{ return intersects(ray, plane); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(SGVec3<T>& dst, const SGRay<T>& ray, const SGPlane<T>& plane)
|
||||
{
|
||||
// We compute the intersection point
|
||||
// x = origin + \alpha*direction
|
||||
// from the ray origin and non nomalized direction.
|
||||
// For 0 <= \alpha the ray intersects the infinite plane.
|
||||
// The intersection point x can also be written
|
||||
// x = n*dist + y
|
||||
// where n is the planes normal, dist is the distance of the plane from
|
||||
// the origin in normal direction and y is ana aproriate vector
|
||||
// perpendicular to n.
|
||||
// Equate the x values and take the scalar product with the plane normal n.
|
||||
// dot(n, origin) + \alpha*dot(n, direction) = dist
|
||||
// We can now compute alpha from the above equation.
|
||||
// \alpha = (dist - dot(n, origin))/dot(n, direction)
|
||||
|
||||
// The negative numerator for the \alpha expression
|
||||
T num = plane.getPositiveDist();
|
||||
num -= dot(plane.getNormal(), ray.getOrigin());
|
||||
|
||||
// If the numerator is zero, we have the rays origin included in the plane
|
||||
if (fabs(num) <= SGLimits<T>::min()) {
|
||||
dst = ray.getOrigin();
|
||||
return true;
|
||||
}
|
||||
|
||||
// The denominator for the \alpha expression
|
||||
T den = dot(plane.getNormal(), ray.getDirection());
|
||||
|
||||
// If we get here, we already know that the rays origin is not included
|
||||
// in the plane. Thus if we have a zero denominator we have
|
||||
// a ray paralell to the plane. That is no intersection.
|
||||
if (fabs(den) <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
// We would now compute \alpha = num/den and compare with 0 and 1.
|
||||
// But to avoid that expensive division, check equation multiplied by
|
||||
// the denominator.
|
||||
T alpha = num/den;
|
||||
if (alpha < 0)
|
||||
return false;
|
||||
|
||||
dst = ray.getOrigin() + alpha*ray.getDirection();
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(SGVec3<T>& dst, const SGPlane<T>& plane, const SGRay<T>& ray)
|
||||
{ return intersects(dst, ray, plane); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGLineSegment<T>& lineSegment, const SGPlane<T>& plane)
|
||||
{
|
||||
// We compute the intersection point
|
||||
// x = origin + \alpha*direction
|
||||
// from the line segments origin and non nomalized direction.
|
||||
// For 0 <= \alpha <= 1 the line segment intersects the infinite plane.
|
||||
// The intersection point x can also be written
|
||||
// x = n*dist + y
|
||||
// where n is the planes normal, dist is the distance of the plane from
|
||||
// the origin in normal direction and y is ana aproriate vector
|
||||
// perpendicular to n.
|
||||
// Equate the x values and take the scalar product with the plane normal n.
|
||||
// dot(n, origin) + \alpha*dot(n, direction) = dist
|
||||
// We can now compute alpha from the above equation.
|
||||
// \alpha = (dist - dot(n, origin))/dot(n, direction)
|
||||
|
||||
// The negative numerator for the \alpha expression
|
||||
T num = plane.getPositiveDist();
|
||||
num -= dot(plane.getNormal(), lineSegment.getOrigin());
|
||||
|
||||
// If the numerator is zero, we have the lines origin included in the plane
|
||||
if (fabs(num) <= SGLimits<T>::min())
|
||||
return true;
|
||||
|
||||
// The denominator for the \alpha expression
|
||||
T den = dot(plane.getNormal(), lineSegment.getDirection());
|
||||
|
||||
// If we get here, we already know that the lines origin is not included
|
||||
// in the plane. Thus if we have a zero denominator we have
|
||||
// a line paralell to the plane. That is no intersection.
|
||||
if (fabs(den) <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
// We would now compute \alpha = num/den and compare with 0 and 1.
|
||||
// But to avoid that expensive division, compare equations
|
||||
// multiplied by |den|. Note that copysign is usually a compiler intrinsic
|
||||
// that expands in assembler code that not even stalls the cpus pipes.
|
||||
T alphaDen = copysign(1, den)*num;
|
||||
if (alphaDen < 0)
|
||||
return false;
|
||||
if (den < alphaDen)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGPlane<T>& plane, const SGLineSegment<T>& lineSegment)
|
||||
{ return intersects(lineSegment, plane); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(SGVec3<T>& dst, const SGLineSegment<T>& lineSegment, const SGPlane<T>& plane)
|
||||
{
|
||||
// We compute the intersection point
|
||||
// x = origin + \alpha*direction
|
||||
// from the line segments origin and non nomalized direction.
|
||||
// For 0 <= \alpha <= 1 the line segment intersects the infinite plane.
|
||||
// The intersection point x can also be written
|
||||
// x = n*dist + y
|
||||
// where n is the planes normal, dist is the distance of the plane from
|
||||
// the origin in normal direction and y is an aproriate vector
|
||||
// perpendicular to n.
|
||||
// Equate the x values and take the scalar product with the plane normal n.
|
||||
// dot(n, origin) + \alpha*dot(n, direction) = dist
|
||||
// We can now compute alpha from the above equation.
|
||||
// \alpha = (dist - dot(n, origin))/dot(n, direction)
|
||||
|
||||
// The negative numerator for the \alpha expression
|
||||
T num = plane.getPositiveDist();
|
||||
num -= dot(plane.getNormal(), lineSegment.getOrigin());
|
||||
|
||||
// If the numerator is zero, we have the lines origin included in the plane
|
||||
if (fabs(num) <= SGLimits<T>::min()) {
|
||||
dst = lineSegment.getOrigin();
|
||||
return true;
|
||||
}
|
||||
|
||||
// The denominator for the \alpha expression
|
||||
T den = dot(plane.getNormal(), lineSegment.getDirection());
|
||||
|
||||
// If we get here, we already know that the lines origin is not included
|
||||
// in the plane. Thus if we have a zero denominator we have
|
||||
// a line paralell to the plane. That is: no intersection.
|
||||
if (fabs(den) <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
// We would now compute \alpha = num/den and compare with 0 and 1.
|
||||
// But to avoid that expensive division, check equation multiplied by
|
||||
// the denominator. FIXME: shall we do so? or compute like that?
|
||||
T alpha = num/den;
|
||||
if (alpha < 0)
|
||||
return false;
|
||||
if (1 < alpha)
|
||||
return false;
|
||||
|
||||
dst = lineSegment.getOrigin() + alpha*lineSegment.getDirection();
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(SGVec3<T>& dst, const SGPlane<T>& plane, const SGLineSegment<T>& lineSegment)
|
||||
{ return intersects(dst, lineSegment, plane); }
|
||||
|
||||
|
||||
// Distance of a line segment to a point
|
||||
template<typename T>
|
||||
inline T
|
||||
distSqr(const SGLineSegment<T>& lineSeg, const SGVec3<T>& p)
|
||||
{
|
||||
SGVec3<T> ps = p - lineSeg.getStart();
|
||||
|
||||
T psdotdir = dot(ps, lineSeg.getDirection());
|
||||
if (psdotdir <= 0)
|
||||
return dot(ps, ps);
|
||||
|
||||
SGVec3<T> pe = p - lineSeg.getEnd();
|
||||
if (0 <= dot(pe, lineSeg.getDirection()))
|
||||
return dot(pe, pe);
|
||||
|
||||
return dot(ps, ps) - psdotdir*psdotdir/dot(lineSeg.getDirection(), lineSeg.getDirection());
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline T
|
||||
distSqr(const SGVec3<T>& p, const SGLineSegment<T>& lineSeg)
|
||||
{ return distSqr(lineSeg, p); }
|
||||
// with sqrt
|
||||
template<typename T>
|
||||
inline T
|
||||
dist(const SGVec3<T>& p, const SGLineSegment<T>& lineSeg)
|
||||
{ return sqrt(distSqr(lineSeg, p)); }
|
||||
template<typename T>
|
||||
inline T
|
||||
dist(const SGLineSegment<T>& lineSeg, const SGVec3<T>& p)
|
||||
{ return sqrt(distSqr(lineSeg, p)); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGRay<T>& ray, const SGSphere<T>& sphere)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering,
|
||||
// second edition, page 571
|
||||
SGVec3<T> l = sphere.getCenter() - ray.getOrigin();
|
||||
T s = dot(l, ray.getDirection());
|
||||
T l2 = dot(l, l);
|
||||
|
||||
T r2 = sphere.getRadius2();
|
||||
if (s < 0 && l2 > r2)
|
||||
return false;
|
||||
|
||||
T d2 = dot(ray.getDirection(), ray.getDirection());
|
||||
// The original test would read
|
||||
// T m2 = l2 - s*s/d2;
|
||||
// if (m2 > r2)
|
||||
// return false;
|
||||
// but to avoid the expensive division, we multiply by d2
|
||||
T m2 = d2*l2 - s*s;
|
||||
if (m2 > d2*r2)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGSphere<T>& sphere, const SGRay<T>& ray)
|
||||
{ return intersects(ray, sphere); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGLineSegment<T>& lineSegment, const SGSphere<T>& sphere)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering,
|
||||
// second edition, page 571
|
||||
SGVec3<T> l = sphere.getCenter() - lineSegment.getStart();
|
||||
T ld = length(lineSegment.getDirection());
|
||||
T s = dot(l, lineSegment.getDirection())/ld;
|
||||
T l2 = dot(l, l);
|
||||
|
||||
T r2 = sphere.getRadius2();
|
||||
if (s < 0 && l2 > r2)
|
||||
return false;
|
||||
|
||||
T m2 = l2 - s*s;
|
||||
if (m2 > r2)
|
||||
return false;
|
||||
|
||||
T q = sqrt(r2 - m2);
|
||||
T t = s - q;
|
||||
if (ld < t)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGSphere<T>& sphere, const SGLineSegment<T>& lineSegment)
|
||||
{ return intersects(lineSegment, sphere); }
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
// FIXME do not use that default argument later. Just for development now
|
||||
intersects(SGVec3<T>& x, const SGTriangle<T>& tri, const SGRay<T>& ray, T eps = 0)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
|
||||
|
||||
// Method based on the observation that we are looking for a
|
||||
// point x that can be expressed in terms of the triangle points
|
||||
// x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0)
|
||||
// with 0 <= u, v and u + v <= 1.
|
||||
// OTOH it could be expressed in terms of the ray
|
||||
// x = o + t*d
|
||||
// Now we can compute u, v and t.
|
||||
SGVec3<T> p = cross(ray.getDirection(), tri.getEdge(1));
|
||||
|
||||
T denom = dot(p, tri.getEdge(0));
|
||||
T signDenom = copysign(1, denom);
|
||||
|
||||
SGVec3<T> s = ray.getOrigin() - tri.getBaseVertex();
|
||||
SGVec3<T> q = cross(s, tri.getEdge(0));
|
||||
// Now t would read
|
||||
// t = 1/denom*dot(q, tri.getEdge(1));
|
||||
// To avoid an expensive division we multiply by |denom|
|
||||
T tDenom = signDenom*dot(q, tri.getEdge(1));
|
||||
if (tDenom < 0)
|
||||
return false;
|
||||
// For line segment we would test against
|
||||
// if (1 < t)
|
||||
// return false;
|
||||
// with the original t. The multiplied test would read
|
||||
// if (absDenom < tDenom)
|
||||
// return false;
|
||||
|
||||
T absDenom = fabs(denom);
|
||||
T absDenomEps = absDenom*eps;
|
||||
|
||||
// T u = 1/denom*dot(p, s);
|
||||
T u = signDenom*dot(p, s);
|
||||
if (u < -absDenomEps)
|
||||
return false;
|
||||
// T v = 1/denom*dot(q, d);
|
||||
// if (v < -eps)
|
||||
// return false;
|
||||
T v = signDenom*dot(q, ray.getDirection());
|
||||
if (v < -absDenomEps)
|
||||
return false;
|
||||
|
||||
if (u + v > absDenom + absDenomEps)
|
||||
return false;
|
||||
|
||||
// return if paralell ??? FIXME what if paralell and in plane?
|
||||
// may be we are ok below than anyway??
|
||||
if (absDenom <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
x = ray.getOrigin();
|
||||
// if we have survived here it could only happen with denom == 0
|
||||
// that the point is already in plane. Then return the origin ...
|
||||
if (SGLimitsd::min() < absDenom)
|
||||
x += (tDenom/absDenom)*ray.getDirection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGTriangle<T>& tri, const SGRay<T>& ray, T eps = 0)
|
||||
{
|
||||
// FIXME: for now just wrap the other method. When that has prooven
|
||||
// well optimized, implement that special case
|
||||
SGVec3<T> dummy;
|
||||
return intersects(dummy, tri, ray, eps);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
// FIXME do not use that default argument later. Just for development now
|
||||
intersects(SGVec3<T>& x, const SGTriangle<T>& tri, const SGLineSegment<T>& lineSegment, T eps = 0)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
|
||||
|
||||
// Method based on the observation that we are looking for a
|
||||
// point x that can be expressed in terms of the triangle points
|
||||
// x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0)
|
||||
// with 0 <= u, v and u + v <= 1.
|
||||
// OTOH it could be expressed in terms of the lineSegment
|
||||
// x = o + t*d
|
||||
// Now we can compute u, v and t.
|
||||
SGVec3<T> p = cross(lineSegment.getDirection(), tri.getEdge(1));
|
||||
|
||||
T denom = dot(p, tri.getEdge(0));
|
||||
T signDenom = copysign(1, denom);
|
||||
|
||||
SGVec3<T> s = lineSegment.getStart() - tri.getBaseVertex();
|
||||
SGVec3<T> q = cross(s, tri.getEdge(0));
|
||||
// Now t would read
|
||||
// t = 1/denom*dot(q, tri.getEdge(1));
|
||||
// To avoid an expensive division we multiply by |denom|
|
||||
T tDenom = signDenom*dot(q, tri.getEdge(1));
|
||||
if (tDenom < 0)
|
||||
return false;
|
||||
// For line segment we would test against
|
||||
// if (1 < t)
|
||||
// return false;
|
||||
// with the original t. The multiplied test reads
|
||||
T absDenom = fabs(denom);
|
||||
if (absDenom < tDenom)
|
||||
return false;
|
||||
|
||||
// take the CPU accuracy in account
|
||||
T absDenomEps = absDenom*eps;
|
||||
|
||||
// T u = 1/denom*dot(p, s);
|
||||
T u = signDenom*dot(p, s);
|
||||
if (u < -absDenomEps)
|
||||
return false;
|
||||
// T v = 1/denom*dot(q, d);
|
||||
// if (v < -eps)
|
||||
// return false;
|
||||
T v = signDenom*dot(q, lineSegment.getDirection());
|
||||
if (v < -absDenomEps)
|
||||
return false;
|
||||
|
||||
if (u + v > absDenom + absDenomEps)
|
||||
return false;
|
||||
|
||||
// return if paralell ??? FIXME what if paralell and in plane?
|
||||
// may be we are ok below than anyway??
|
||||
if (absDenom <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
x = lineSegment.getStart();
|
||||
// if we have survived here it could only happen with denom == 0
|
||||
// that the point is already in plane. Then return the origin ...
|
||||
if (SGLimitsd::min() < absDenom)
|
||||
x += (tDenom/absDenom)*lineSegment.getDirection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGTriangle<T>& tri, const SGLineSegment<T>& lineSegment, T eps = 0)
|
||||
{
|
||||
// FIXME: for now just wrap the othr method. When that has prooven
|
||||
// well optimized, implement that special case
|
||||
SGVec3<T> dummy;
|
||||
return intersects(dummy, tri, lineSegment, eps);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGVec3<T>& v, const SGSphere<T>& sphere)
|
||||
{
|
||||
if (sphere.empty())
|
||||
return false;
|
||||
return distSqr(v, sphere.getCenter()) <= sphere.getRadius2();
|
||||
}
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGSphere<T>& sphere, const SGVec3<T>& v)
|
||||
{ return intersects(v, sphere); }
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGBox<T>& box, const SGLineSegment<T>& lineSegment)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
|
||||
|
||||
SGVec3<T> c = lineSegment.getCenter() - box.getCenter();
|
||||
SGVec3<T> w = 0.5*lineSegment.getDirection();
|
||||
SGVec3<T> v(fabs(w.x()), fabs(w.y()), fabs(w.z()));
|
||||
SGVec3<T> h = 0.5*box.getSize();
|
||||
|
||||
if (fabs(c[0]) > v[0] + h[0])
|
||||
return false;
|
||||
if (fabs(c[1]) > v[1] + h[1])
|
||||
return false;
|
||||
if (fabs(c[2]) > v[2] + h[2])
|
||||
return false;
|
||||
|
||||
if (fabs(c[1]*w[2] - c[2]*w[1]) > h[1]*v[2] + h[2]*v[1])
|
||||
return false;
|
||||
if (fabs(c[0]*w[2] - c[2]*w[0]) > h[0]*v[2] + h[2]*v[0])
|
||||
return false;
|
||||
if (fabs(c[0]*w[1] - c[1]*w[0]) > h[0]*v[1] + h[1]*v[0])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGLineSegment<T>& lineSegment, const SGBox<T>& box)
|
||||
{ return intersects(box, lineSegment); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGBox<T>& box, const SGRay<T>& ray)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
|
||||
|
||||
for (unsigned i = 0; i < 3; ++i) {
|
||||
T cMin = box.getMin()[i];
|
||||
T cMax = box.getMax()[i];
|
||||
|
||||
T cOrigin = ray.getOrigin()[i];
|
||||
|
||||
T cDir = ray.getDirection()[i];
|
||||
if (fabs(cDir) <= SGLimits<T>::min()) {
|
||||
if (cOrigin < cMin)
|
||||
return false;
|
||||
if (cMax < cOrigin)
|
||||
return false;
|
||||
}
|
||||
|
||||
T nearr = - SGLimits<T>::max();
|
||||
T farr = SGLimits<T>::max();
|
||||
|
||||
T T1 = (cMin - cOrigin) / cDir;
|
||||
T T2 = (cMax - cOrigin) / cDir;
|
||||
if (T1 > T2) std::swap (T1, T2);/* since T1 intersection with near plane */
|
||||
if (T1 > nearr) nearr = T1; /* want largest Tnear */
|
||||
if (T2 < farr) farr = T2; /* want smallest Tfarr */
|
||||
if (nearr > farr) // farr box is missed
|
||||
return false;
|
||||
if (farr < 0) // box is behind ray
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGRay<T>& ray, const SGBox<T>& box)
|
||||
{ return intersects(box, ray); }
|
||||
|
||||
#endif
|
||||
62
simgear/math/SGLineSegment.hxx
Normal file
62
simgear/math/SGLineSegment.hxx
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGLineSegment_H
|
||||
#define SGLineSegment_H
|
||||
|
||||
template<typename T>
|
||||
class SGLineSegment {
|
||||
public:
|
||||
SGLineSegment()
|
||||
{ }
|
||||
SGLineSegment(const SGVec3<T>& start, const SGVec3<T>& end) :
|
||||
_start(start),
|
||||
_direction(end - start)
|
||||
{ }
|
||||
|
||||
void set(const SGVec3<T>& start, const SGVec3<T>& end)
|
||||
{ _start = start; _direction = end - start; }
|
||||
|
||||
const SGVec3<T>& getStart() const
|
||||
{ return _start; }
|
||||
SGVec3<T> getEnd() const
|
||||
{ return _start + _direction; }
|
||||
const SGVec3<T>& getDirection() const
|
||||
{ return _direction; }
|
||||
SGVec3<T> getNormalizedDirection() const
|
||||
{ return normalize(getDirection()); }
|
||||
|
||||
SGVec3<T> getCenter() const
|
||||
{ return _start + T(0.5)*_direction; }
|
||||
|
||||
private:
|
||||
SGVec3<T> _start;
|
||||
SGVec3<T> _direction;
|
||||
};
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s,
|
||||
const SGLineSegment<T>& lineSegment)
|
||||
{
|
||||
return s << "line segment: start = " << lineSegment.getStart()
|
||||
<< ", end = " << lineSegment.getEnd();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -21,6 +21,11 @@
|
||||
/// Just include them all
|
||||
|
||||
#include <iosfwd>
|
||||
// FIXME, make it compile on IRIX
|
||||
#include <osg/GL>
|
||||
#undef GLUT_APIENTRY_DEFINED // GL/glut.h undef APIENTRY when this symbol is defined. osg/GL defines it (?).
|
||||
// This probably would work if we didn't use plib/pu.h that include GL/glut.h
|
||||
// on its side.
|
||||
|
||||
#include "SGMathFwd.hxx"
|
||||
|
||||
@@ -28,6 +33,7 @@
|
||||
#include "SGLimits.hxx"
|
||||
#include "SGMisc.hxx"
|
||||
#include "SGGeodesy.hxx"
|
||||
#include "SGVec2.hxx"
|
||||
#include "SGVec3.hxx"
|
||||
#include "SGVec4.hxx"
|
||||
#include "SGGeoc.hxx"
|
||||
|
||||
@@ -32,6 +32,8 @@ class SGMisc;
|
||||
template<typename T>
|
||||
class SGQuat;
|
||||
template<typename T>
|
||||
class SGVec2;
|
||||
template<typename T>
|
||||
class SGVec3;
|
||||
template<typename T>
|
||||
class SGVec4;
|
||||
@@ -44,6 +46,8 @@ typedef SGMisc<float> SGMiscf;
|
||||
typedef SGMisc<double> SGMiscd;
|
||||
typedef SGQuat<float> SGQuatf;
|
||||
typedef SGQuat<double> SGQuatd;
|
||||
typedef SGVec2<float> SGVec2f;
|
||||
typedef SGVec2<double> SGVec2d;
|
||||
typedef SGVec3<float> SGVec3f;
|
||||
typedef SGVec3<double> SGVec3d;
|
||||
typedef SGVec4<float> SGVec4f;
|
||||
|
||||
@@ -174,7 +174,9 @@ MatrixTest(void)
|
||||
// Create some test matrix
|
||||
SGVec3<T> v0(2, 7, 17);
|
||||
SGQuat<T> q0 = SGQuat<T>::fromAngleAxis(SGMisc<T>::pi(), normalize(v0));
|
||||
SGMatrix<T> m0(q0, v0);
|
||||
SGMatrix<T> m0;
|
||||
m0.postMultTranslate(v0);
|
||||
m0.postMultRotate(q0);
|
||||
|
||||
// Check the tqo forms of the inverse for that kind of special matrix
|
||||
SGMatrix<T> m1, m2;
|
||||
@@ -236,7 +238,9 @@ sgInterfaceTest(void)
|
||||
SGVec3f v3f = SGVec3f::e2();
|
||||
SGVec4f v4f = SGVec4f::e2();
|
||||
SGQuatf qf = SGQuatf::fromEulerRad(1.2, 1.3, -0.4);
|
||||
SGMatrixf mf(qf, v3f);
|
||||
SGMatrixf mf;
|
||||
mf.postMultTranslate(v3f);
|
||||
mf.postMultRotate(qf);
|
||||
|
||||
// Copy to and from plibs types check if result is equal,
|
||||
// test for exact equality
|
||||
@@ -283,7 +287,9 @@ sgdInterfaceTest(void)
|
||||
SGVec3d v3d = SGVec3d::e2();
|
||||
SGVec4d v4d = SGVec4d::e2();
|
||||
SGQuatd qd = SGQuatd::fromEulerRad(1.2, 1.3, -0.4);
|
||||
SGMatrixd md(qd, v3d);
|
||||
SGMatrixd md;
|
||||
md.postMultTranslate(v3d);
|
||||
md.postMultRotate(qd);
|
||||
|
||||
// Copy to and from plibs types check if result is equal,
|
||||
// test for exact equality
|
||||
|
||||
@@ -63,14 +63,13 @@ public:
|
||||
}
|
||||
|
||||
/// Constructor, build up a SGMatrix from a translation
|
||||
SGMatrix(const SGVec3<T>& trans)
|
||||
template<typename S>
|
||||
SGMatrix(const SGVec3<S>& trans)
|
||||
{ set(trans); }
|
||||
|
||||
/// Constructor, build up a SGMatrix from a rotation and a translation
|
||||
SGMatrix(const SGQuat<T>& quat, const SGVec3<T>& trans)
|
||||
{ set(quat, trans); }
|
||||
/// Constructor, build up a SGMatrix from a rotation and a translation
|
||||
SGMatrix(const SGQuat<T>& quat)
|
||||
template<typename S>
|
||||
SGMatrix(const SGQuat<S>& quat)
|
||||
{ set(quat); }
|
||||
|
||||
/// Copy constructor for a transposed negated matrix
|
||||
@@ -78,39 +77,22 @@ public:
|
||||
{ set(tm); }
|
||||
|
||||
/// Set from a tranlation
|
||||
void set(const SGVec3<T>& trans)
|
||||
template<typename S>
|
||||
void set(const SGVec3<S>& trans)
|
||||
{
|
||||
_data.flat[0] = 1; _data.flat[4] = 0;
|
||||
_data.flat[8] = 0; _data.flat[12] = -trans(0);
|
||||
_data.flat[8] = 0; _data.flat[12] = T(trans(0));
|
||||
_data.flat[1] = 0; _data.flat[5] = 1;
|
||||
_data.flat[9] = 0; _data.flat[13] = -trans(1);
|
||||
_data.flat[9] = 0; _data.flat[13] = T(trans(1));
|
||||
_data.flat[2] = 0; _data.flat[6] = 0;
|
||||
_data.flat[10] = 1; _data.flat[14] = -trans(2);
|
||||
_data.flat[10] = 1; _data.flat[14] = T(trans(2));
|
||||
_data.flat[3] = 0; _data.flat[7] = 0;
|
||||
_data.flat[11] = 0; _data.flat[15] = 1;
|
||||
}
|
||||
|
||||
/// Set from a scale/rotation and tranlation
|
||||
void set(const SGQuat<T>& quat, const SGVec3<T>& trans)
|
||||
{
|
||||
T w = quat.w(); T x = quat.x(); T y = quat.y(); T z = quat.z();
|
||||
T xx = x*x; T yy = y*y; T zz = z*z;
|
||||
T wx = w*x; T wy = w*y; T wz = w*z;
|
||||
T xy = x*y; T xz = x*z; T yz = y*z;
|
||||
_data.flat[0] = 1-2*(yy+zz); _data.flat[1] = 2*(xy-wz);
|
||||
_data.flat[2] = 2*(xz+wy); _data.flat[3] = 0;
|
||||
_data.flat[4] = 2*(xy+wz); _data.flat[5] = 1-2*(xx+zz);
|
||||
_data.flat[6] = 2*(yz-wx); _data.flat[7] = 0;
|
||||
_data.flat[8] = 2*(xz-wy); _data.flat[9] = 2*(yz+wx);
|
||||
_data.flat[10] = 1-2*(xx+yy); _data.flat[11] = 0;
|
||||
// Well, this one is ugly here, as that xform method on the current
|
||||
// object needs the above data to be already set ...
|
||||
SGVec3<T> t = xformVec(trans);
|
||||
_data.flat[12] = -t(0); _data.flat[13] = -t(1);
|
||||
_data.flat[14] = -t(2); _data.flat[15] = 1;
|
||||
}
|
||||
/// Set from a scale/rotation and tranlation
|
||||
void set(const SGQuat<T>& quat)
|
||||
template<typename S>
|
||||
void set(const SGQuat<S>& quat)
|
||||
{
|
||||
T w = quat.w(); T x = quat.x(); T y = quat.y(); T z = quat.z();
|
||||
T xx = x*x; T yy = y*y; T zz = z*z;
|
||||
@@ -199,6 +181,45 @@ public:
|
||||
/// Inplace matrix multiplication, post multiply
|
||||
SGMatrix& operator*=(const SGMatrix<T>& m2);
|
||||
|
||||
template<typename S>
|
||||
SGMatrix& preMultTranslate(const SGVec3<S>& t)
|
||||
{
|
||||
for (unsigned i = 0; i < SGMatrix<T>::nCols-1; ++i)
|
||||
(*this)(i,3) += T(t(i));
|
||||
return *this;
|
||||
}
|
||||
template<typename S>
|
||||
SGMatrix& postMultTranslate(const SGVec3<S>& t)
|
||||
{
|
||||
SGVec4<T> col3((*this)(0,3), (*this)(1,3), (*this)(2,3), (*this)(3,3));
|
||||
for (unsigned i = 0; i < SGMatrix<T>::nCols-1; ++i) {
|
||||
SGVec4<T> tmp((*this)(0,3), (*this)(1,3), (*this)(2,3), (*this)(3,3));
|
||||
col3 += T(t(i))*tmp;
|
||||
}
|
||||
(*this)(0,3) = col3(0); (*this)(1,3) = col3(1);
|
||||
(*this)(2,3) = col3(2); (*this)(3,3) = col3(3);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SGMatrix& preMultRotate(const SGQuat<T>& r)
|
||||
{
|
||||
for (unsigned i = 0; i < SGMatrix<T>::nCols; ++i) {
|
||||
SGVec3<T> col((*this)(0,i), (*this)(1,i), (*this)(2,i));
|
||||
col = r.transform(col);
|
||||
(*this)(0,i) = col(0); (*this)(1,i) = col(1); (*this)(2,i) = col(2);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
SGMatrix& postMultRotate(const SGQuat<T>& r)
|
||||
{
|
||||
for (unsigned i = 0; i < SGMatrix<T>::nCols; ++i) {
|
||||
SGVec3<T> col((*this)(i,0), (*this)(i,1), (*this)(i,2));
|
||||
col = r.backTransform(col);
|
||||
(*this)(i,0) = col(0); (*this)(i,1) = col(1); (*this)(i,2) = col(2);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SGVec3<T> xformPt(const SGVec3<T>& pt) const
|
||||
{
|
||||
SGVec3<T> tpt;
|
||||
@@ -574,8 +595,8 @@ toMatrixf(const SGMatrixd& m)
|
||||
{
|
||||
return SGMatrixf((float)m(0,0), (float)m(0,1), (float)m(0,2), (float)m(0,3),
|
||||
(float)m(1,0), (float)m(1,1), (float)m(1,2), (float)m(1,3),
|
||||
(float)m(3,0), (float)m(2,1), (float)m(2,2), (float)m(2,3),
|
||||
(float)m(4,0), (float)m(4,1), (float)m(4,2), (float)m(4,3));
|
||||
(float)m(2,0), (float)m(2,1), (float)m(2,2), (float)m(2,3),
|
||||
(float)m(3,0), (float)m(3,1), (float)m(3,2), (float)m(3,3));
|
||||
}
|
||||
|
||||
inline
|
||||
@@ -584,8 +605,8 @@ toMatrixd(const SGMatrixf& m)
|
||||
{
|
||||
return SGMatrixd(m(0,0), m(0,1), m(0,2), m(0,3),
|
||||
m(1,0), m(1,1), m(1,2), m(1,3),
|
||||
m(3,0), m(2,1), m(2,2), m(2,3),
|
||||
m(4,0), m(4,1), m(4,2), m(4,3));
|
||||
m(2,0), m(2,1), m(2,2), m(2,3),
|
||||
m(3,0), m(3,1), m(3,2), m(3,3));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,8 @@ template<typename T>
|
||||
class SGMisc {
|
||||
public:
|
||||
static T pi() { return T(3.1415926535897932384626433832795029L); }
|
||||
static T twopi() { return 2*T(3.1415926535897932384626433832795029L); }
|
||||
|
||||
static T min(const T& a, const T& b)
|
||||
{ return a < b ? a : b; }
|
||||
static T min(const T& a, const T& b, const T& c)
|
||||
@@ -34,6 +36,11 @@ public:
|
||||
{ return max(max(a, b), c); }
|
||||
static T max(const T& a, const T& b, const T& c, const T& d)
|
||||
{ return max(max(max(a, b), c), d); }
|
||||
|
||||
// clip the value of a to be in the range between and including _min and _max
|
||||
static T clip(const T& a, const T& _min, const T& _max)
|
||||
{ return max(_min, min(_max, a)); }
|
||||
|
||||
static int sign(const T& a)
|
||||
{
|
||||
if (a < -SGLimits<T>::min())
|
||||
@@ -49,6 +56,32 @@ public:
|
||||
static T deg2rad(const T& val)
|
||||
{ return val*pi()/180; }
|
||||
|
||||
// normalize the value to be in a range between [min, max[
|
||||
static T
|
||||
normalizePeriodic(const T& min, const T& max, const T& value)
|
||||
{
|
||||
T range = max - min;
|
||||
if (range < SGLimits<T>::min())
|
||||
return min;
|
||||
T normalized = value - range*floor((value - min)/range);
|
||||
// two security checks that can only happen due to roundoff
|
||||
if (value <= min)
|
||||
return min;
|
||||
if (max <= normalized)
|
||||
return min;
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// normalize the angle to be in a range between [-pi, pi[
|
||||
static T
|
||||
normalizeAngle(const T& angle)
|
||||
{ return normalizePeriodic(-pi(), pi(), angle); }
|
||||
|
||||
// normalize the angle to be in a range between [0, 2pi[
|
||||
static T
|
||||
normalizeAngle2(const T& angle)
|
||||
{ return normalizePeriodic(0, twopi(), angle); }
|
||||
|
||||
static T round(const T& v)
|
||||
{ return floor(v + T(0.5)); }
|
||||
static int roundToInt(const T& v)
|
||||
|
||||
59
simgear/math/SGPlane.hxx
Normal file
59
simgear/math/SGPlane.hxx
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGPlane_H
|
||||
#define SGPlane_H
|
||||
|
||||
template<typename T>
|
||||
class SGPlane {
|
||||
public:
|
||||
SGPlane()
|
||||
{ }
|
||||
SGPlane(const SGVec3<T>& normal, T dist) :
|
||||
_normal(normal), _dist(dist)
|
||||
{ }
|
||||
SGPlane(const SGVec3<T> vertices[3]) :
|
||||
_normal(normalize(cross(vertices[1] - vertices[0],
|
||||
vertices[2] - vertices[0]))),
|
||||
_dist(-dot(_normal, vertices[0]))
|
||||
{ }
|
||||
|
||||
void setNormal(const SGVec3<T>& normal)
|
||||
{ _normal = normal; }
|
||||
const SGVec3<T>& getNormal() const
|
||||
{ return _normal; }
|
||||
|
||||
void setDist(const T& dist)
|
||||
{ _dist = dist; }
|
||||
const T& getDist() const
|
||||
{ return _dist; }
|
||||
|
||||
/// That is the distance where we measure positive in direction of the normal
|
||||
T getPositiveDist() const
|
||||
{ return -_dist; }
|
||||
/// That is the distance where we measure positive in the oposite direction
|
||||
/// of the normal.
|
||||
const T& getNegativeDist() const
|
||||
{ return _dist; }
|
||||
|
||||
private:
|
||||
// That ordering is important because of one constructor
|
||||
SGVec3<T> _normal;
|
||||
T _dist;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -26,10 +26,42 @@
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#include <osg/Quat>
|
||||
|
||||
template<typename T>
|
||||
struct SGQuatStorage {
|
||||
/// Readonly raw storage interface
|
||||
const T (&data(void) const)[4]
|
||||
{ return _data; }
|
||||
/// Readonly raw storage interface
|
||||
T (&data(void))[4]
|
||||
{ return _data; }
|
||||
|
||||
void osg() const
|
||||
{ }
|
||||
|
||||
private:
|
||||
T _data[4];
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGQuatStorage<double> : public osg::Quat {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const double (&data(void) const)[4]
|
||||
{ return osg::Quat::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
double (&data(void))[4]
|
||||
{ return osg::Quat::_v; }
|
||||
|
||||
const osg::Quat& osg() const
|
||||
{ return *this; }
|
||||
osg::Quat& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
/// 3D Vector Class
|
||||
template<typename T>
|
||||
class SGQuat {
|
||||
class SGQuat : protected SGQuatStorage<T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
@@ -42,7 +74,7 @@ public:
|
||||
/// uninitialized values in the debug build very fast ...
|
||||
#ifndef NDEBUG
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
_data[i] = SGLimits<T>::quiet_NaN();
|
||||
data()[i] = SGLimits<T>::quiet_NaN();
|
||||
#endif
|
||||
}
|
||||
/// Constructor. Initialize by the given values
|
||||
@@ -51,11 +83,13 @@ public:
|
||||
/// Constructor. Initialize by the content of a plain array,
|
||||
/// make sure it has at least 4 elements
|
||||
explicit SGQuat(const T* d)
|
||||
{ _data[0] = d[0]; _data[1] = d[1]; _data[2] = d[2]; _data[3] = d[3]; }
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
|
||||
explicit SGQuat(const osg::Quat& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
|
||||
|
||||
/// Return a unit quaternion
|
||||
static SGQuat unit(void)
|
||||
{ return fromRealImag(1, SGVec3<T>(0)); }
|
||||
{ return fromRealImag(1, SGVec3<T>(0, 0, 0)); }
|
||||
|
||||
/// Return a quaternion from euler angles
|
||||
static SGQuat fromEulerRad(T z, T y, T x)
|
||||
@@ -96,13 +130,17 @@ public:
|
||||
static SGQuat fromHeadAttBankDeg(T h, T a, T b)
|
||||
{ return fromEulerDeg(h, a, b); }
|
||||
|
||||
/// Return a quaternion rotation the the horizontal local frame from given
|
||||
/// longitude and latitude
|
||||
/// Return a quaternion rotation from the earth centered to the
|
||||
/// simulation usual horizontal local frame from given
|
||||
/// longitude and latitude.
|
||||
/// The horizontal local frame used in simulations is the frame with x-axis
|
||||
/// pointing north, the y-axis pointing eastwards and the z axis
|
||||
/// pointing downwards.
|
||||
static SGQuat fromLonLatRad(T lon, T lat)
|
||||
{
|
||||
SGQuat q;
|
||||
T zd2 = T(0.5)*lon;
|
||||
T yd2 = T(-0.25)*SGMisc<value_type>::pi() - T(0.5)*lat;
|
||||
T yd2 = T(-0.25)*SGMisc<T>::pi() - T(0.5)*lat;
|
||||
T Szd2 = sin(zd2);
|
||||
T Syd2 = sin(yd2);
|
||||
T Czd2 = cos(zd2);
|
||||
@@ -113,17 +151,51 @@ public:
|
||||
q.z() = Szd2*Cyd2;
|
||||
return q;
|
||||
}
|
||||
|
||||
/// Return a quaternion rotation the the horizontal local frame from given
|
||||
/// longitude and latitude
|
||||
/// Like the above provided for convenience
|
||||
static SGQuat fromLonLatDeg(T lon, T lat)
|
||||
{ return fromLonLatRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); }
|
||||
|
||||
/// Return a quaternion rotation the the horizontal local frame from given
|
||||
/// longitude and latitude
|
||||
/// Like the above provided for convenience
|
||||
static SGQuat fromLonLat(const SGGeod& geod)
|
||||
{ return fromLonLatRad(geod.getLongitudeRad(), geod.getLatitudeRad()); }
|
||||
|
||||
/// Return a quaternion rotation from the earth centered to the
|
||||
/// OpenGL/viewer horizontal local frame from given longitude and latitude.
|
||||
/// This frame matches the usual OpenGL axis directions. That is the target
|
||||
/// frame has an x-axis pointing eastwards, y-axis pointing up and y z-axis
|
||||
/// pointing south.
|
||||
static SGQuat viewHLRad(T lon, T lat)
|
||||
{
|
||||
// That bails down to a 3-2-1 euler sequence lon+pi/2, 0, -lat-pi
|
||||
// what is here is again the hand optimized version ...
|
||||
SGQuat q;
|
||||
T xd2 = -T(0.5)*lat - T(0.5)*SGMisc<T>::pi();
|
||||
T zd2 = T(0.5)*lon + T(0.25)*SGMisc<T>::pi();
|
||||
T Szd2 = sin(zd2);
|
||||
T Sxd2 = sin(xd2);
|
||||
T Czd2 = cos(zd2);
|
||||
T Cxd2 = cos(xd2);
|
||||
q.w() = Cxd2*Czd2;
|
||||
q.x() = Sxd2*Czd2;
|
||||
q.y() = Sxd2*Szd2;
|
||||
q.z() = Cxd2*Szd2;
|
||||
return q;
|
||||
}
|
||||
/// Like the above provided for convenience
|
||||
static SGQuat viewHLDeg(T lon, T lat)
|
||||
{ return viewHLRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); }
|
||||
/// Like the above provided for convenience
|
||||
static SGQuat viewHL(const SGGeod& geod)
|
||||
{ return viewHLRad(geod.getLongitudeRad(), geod.getLatitudeRad()); }
|
||||
|
||||
/// Convert a quaternion rotation from the simulation frame
|
||||
/// to the view (OpenGL) frame. That is it just swaps the axis part of
|
||||
/// this current quaternion.
|
||||
/// That proves useful when you want to use the euler 3-2-1 sequence
|
||||
/// for the usual heading/pitch/roll sequence within the context of
|
||||
/// OpenGL/viewer frames.
|
||||
static SGQuat simToView(const SGQuat& q)
|
||||
{ return SGQuat(q.y(), -q.z(), -q.x(), q.w()); }
|
||||
|
||||
/// Create a quaternion from the angle axis representation
|
||||
static SGQuat fromAngleAxis(T angle, const SGVec3<T>& axis)
|
||||
{
|
||||
@@ -146,14 +218,100 @@ public:
|
||||
return fromRealImag(cos(angle2), T(sin(angle2)/nAxis)*axis);
|
||||
}
|
||||
|
||||
static SGQuat fromRotateTo(const SGVec3<T>& from, const SGVec3<T>& to)
|
||||
{
|
||||
T nfrom = norm(from);
|
||||
T nto = norm(to);
|
||||
if (nfrom < SGLimits<T>::min() || nto < SGLimits<T>::min())
|
||||
return SGQuat::unit();
|
||||
|
||||
return SGQuat::fromRotateToNorm((1/nfrom)*from, (1/nto)*to);
|
||||
}
|
||||
|
||||
// FIXME more finegrained error behavour.
|
||||
static SGQuat fromRotateTo(const SGVec3<T>& v1, unsigned i1,
|
||||
const SGVec3<T>& v2, unsigned i2)
|
||||
{
|
||||
T nrmv1 = norm(v1);
|
||||
T nrmv2 = norm(v2);
|
||||
if (nrmv1 < SGLimits<T>::min() || nrmv2 < SGLimits<T>::min())
|
||||
return SGQuat::unit();
|
||||
|
||||
SGVec3<T> nv1 = (1/nrmv1)*v1;
|
||||
SGVec3<T> nv2 = (1/nrmv2)*v2;
|
||||
T dv1v2 = dot(nv1, nv2);
|
||||
if (fabs(fabs(dv1v2)-1) < SGLimits<T>::epsilon())
|
||||
return SGQuat::unit();
|
||||
|
||||
// The target vector for the first rotation
|
||||
SGVec3<T> nto1 = SGVec3<T>::zeros();
|
||||
SGVec3<T> nto2 = SGVec3<T>::zeros();
|
||||
nto1[i1] = 1;
|
||||
nto2[i2] = 1;
|
||||
|
||||
// The first rotation can be done with the usual routine.
|
||||
SGQuat q = SGQuat::fromRotateToNorm(nv1, nto1);
|
||||
|
||||
// The rotation axis for the second rotation is the
|
||||
// target for the first one, so the rotation axis is nto1
|
||||
// We need to get the angle.
|
||||
|
||||
// Make nv2 exactly orthogonal to nv1.
|
||||
nv2 = normalize(nv2 - dv1v2*nv1);
|
||||
|
||||
SGVec3<T> tnv2 = q.transform(nv2);
|
||||
T cosang = dot(nto2, tnv2);
|
||||
T cos05ang = T(0.5+0.5*cosang);
|
||||
if (cos05ang <= 0)
|
||||
cosang = T(0);
|
||||
cos05ang = sqrt(cos05ang);
|
||||
T sig = dot(nto1, cross(nto2, tnv2));
|
||||
T sin05ang = T(0.5-0.5*cosang);
|
||||
if (sin05ang <= 0)
|
||||
sin05ang = 0;
|
||||
sin05ang = copysign(sqrt(sin05ang), sig);
|
||||
q *= SGQuat::fromRealImag(cos05ang, sin05ang*nto1);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
// Return a quaternion which rotates the vector given by v
|
||||
// to the vector -v. Other directions are *not* preserved.
|
||||
static SGQuat fromChangeSign(const SGVec3<T>& v)
|
||||
{
|
||||
// The vector from points to the oposite direction than to.
|
||||
// Find a vector perpendicular to the vector to.
|
||||
T absv1 = fabs(v(0));
|
||||
T absv2 = fabs(v(1));
|
||||
T absv3 = fabs(v(2));
|
||||
|
||||
SGVec3<T> axis;
|
||||
if (absv2 < absv1 && absv3 < absv1) {
|
||||
T quot = v(1)/v(0);
|
||||
axis = (1/sqrt(1+quot*quot))*SGVec3<T>(quot, -1, 0);
|
||||
} else if (absv1 < absv2 && absv3 < absv2) {
|
||||
T quot = v(2)/v(1);
|
||||
axis = (1/sqrt(1+quot*quot))*SGVec3<T>(0, quot, -1);
|
||||
} else if (absv1 < absv3 && absv2 < absv3) {
|
||||
T quot = v(0)/v(2);
|
||||
axis = (1/sqrt(1+quot*quot))*SGVec3<T>(-1, 0, quot);
|
||||
} else {
|
||||
// The all zero case.
|
||||
return SGQuat::unit();
|
||||
}
|
||||
|
||||
return SGQuat::fromRealImag(0, axis);
|
||||
}
|
||||
|
||||
/// Return a quaternion from real and imaginary part
|
||||
static SGQuat fromRealImag(T r, const SGVec3<T>& i)
|
||||
{
|
||||
SGQuat q;
|
||||
q.w() = r;
|
||||
q.x() = i(0);
|
||||
q.y() = i(1);
|
||||
q.z() = i(2);
|
||||
q.x() = i.x();
|
||||
q.y() = i.y();
|
||||
q.z() = i.z();
|
||||
return q;
|
||||
}
|
||||
|
||||
@@ -164,36 +322,36 @@ public:
|
||||
/// write the euler angles into the references
|
||||
void getEulerRad(T& zRad, T& yRad, T& xRad) const
|
||||
{
|
||||
value_type sqrQW = w()*w();
|
||||
value_type sqrQX = x()*x();
|
||||
value_type sqrQY = y()*y();
|
||||
value_type sqrQZ = z()*z();
|
||||
T sqrQW = w()*w();
|
||||
T sqrQX = x()*x();
|
||||
T sqrQY = y()*y();
|
||||
T sqrQZ = z()*z();
|
||||
|
||||
value_type num = 2*(y()*z() + w()*x());
|
||||
value_type den = sqrQW - sqrQX - sqrQY + sqrQZ;
|
||||
if (fabs(den) < SGLimits<value_type>::min() &&
|
||||
fabs(num) < SGLimits<value_type>::min())
|
||||
T num = 2*(y()*z() + w()*x());
|
||||
T den = sqrQW - sqrQX - sqrQY + sqrQZ;
|
||||
if (fabs(den) < SGLimits<T>::min() &&
|
||||
fabs(num) < SGLimits<T>::min())
|
||||
xRad = 0;
|
||||
else
|
||||
xRad = atan2(num, den);
|
||||
|
||||
value_type tmp = 2*(x()*z() - w()*y());
|
||||
T tmp = 2*(x()*z() - w()*y());
|
||||
if (tmp < -1)
|
||||
yRad = 0.5*SGMisc<value_type>::pi();
|
||||
yRad = 0.5*SGMisc<T>::pi();
|
||||
else if (1 < tmp)
|
||||
yRad = -0.5*SGMisc<value_type>::pi();
|
||||
yRad = -0.5*SGMisc<T>::pi();
|
||||
else
|
||||
yRad = -asin(tmp);
|
||||
|
||||
num = 2*(x()*y() + w()*z());
|
||||
den = sqrQW + sqrQX - sqrQY - sqrQZ;
|
||||
if (fabs(den) < SGLimits<value_type>::min() &&
|
||||
fabs(num) < SGLimits<value_type>::min())
|
||||
if (fabs(den) < SGLimits<T>::min() &&
|
||||
fabs(num) < SGLimits<T>::min())
|
||||
zRad = 0;
|
||||
else {
|
||||
value_type psi = atan2(num, den);
|
||||
T psi = atan2(num, den);
|
||||
if (psi < 0)
|
||||
psi += 2*SGMisc<value_type>::pi();
|
||||
psi += 2*SGMisc<T>::pi();
|
||||
zRad = psi;
|
||||
}
|
||||
}
|
||||
@@ -236,67 +394,66 @@ public:
|
||||
|
||||
/// Access by index, the index is unchecked
|
||||
const T& operator()(unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access by index, the index is unchecked
|
||||
T& operator()(unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const T& operator[](unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
T& operator[](unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access the x component
|
||||
const T& x(void) const
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the x component
|
||||
T& x(void)
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the y component
|
||||
const T& y(void) const
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the y component
|
||||
T& y(void)
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the z component
|
||||
const T& z(void) const
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
/// Access the z component
|
||||
T& z(void)
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
/// Access the w component
|
||||
const T& w(void) const
|
||||
{ return _data[3]; }
|
||||
{ return data()[3]; }
|
||||
/// Access the w component
|
||||
T& w(void)
|
||||
{ return _data[3]; }
|
||||
{ return data()[3]; }
|
||||
|
||||
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
|
||||
const T* data(void) const
|
||||
{ return _data; }
|
||||
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
|
||||
T* data(void)
|
||||
{ return _data; }
|
||||
/// Get the data pointer
|
||||
using SGQuatStorage<T>::data;
|
||||
|
||||
/// Readonly interface function to ssg's sgQuat/sgdQuat
|
||||
const T (&sg(void) const)[4]
|
||||
{ return _data; }
|
||||
{ return data(); }
|
||||
/// Interface function to ssg's sgQuat/sgdQuat
|
||||
T (&sg(void))[4]
|
||||
{ return _data; }
|
||||
{ return data(); }
|
||||
|
||||
/// Interface function to osg's Quat*
|
||||
using SGQuatStorage<T>::osg;
|
||||
|
||||
/// Inplace addition
|
||||
SGQuat& operator+=(const SGQuat& v)
|
||||
{ _data[0]+=v(0);_data[1]+=v(1);_data[2]+=v(2);_data[3]+=v(3);return *this; }
|
||||
{ data()[0]+=v(0);data()[1]+=v(1);data()[2]+=v(2);data()[3]+=v(3);return *this; }
|
||||
/// Inplace subtraction
|
||||
SGQuat& operator-=(const SGQuat& v)
|
||||
{ _data[0]-=v(0);_data[1]-=v(1);_data[2]-=v(2);_data[3]-=v(3);return *this; }
|
||||
{ data()[0]-=v(0);data()[1]-=v(1);data()[2]-=v(2);data()[3]-=v(3);return *this; }
|
||||
/// Inplace scalar multiplication
|
||||
template<typename S>
|
||||
SGQuat& operator*=(S s)
|
||||
{ _data[0] *= s; _data[1] *= s; _data[2] *= s; _data[3] *= s; return *this; }
|
||||
{ data()[0] *= s; data()[1] *= s; data()[2] *= s; data()[3] *= s; return *this; }
|
||||
/// Inplace scalar multiplication by 1/s
|
||||
template<typename S>
|
||||
SGQuat& operator/=(S s)
|
||||
@@ -308,18 +465,18 @@ public:
|
||||
/// frame rotated with the quaternion
|
||||
SGVec3<T> transform(const SGVec3<T>& v) const
|
||||
{
|
||||
value_type r = 2/dot(*this, *this);
|
||||
T r = 2/dot(*this, *this);
|
||||
SGVec3<T> qimag = imag(*this);
|
||||
value_type qr = real(*this);
|
||||
T qr = real(*this);
|
||||
return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag - (r*qr)*cross(qimag, v);
|
||||
}
|
||||
/// Transform a vector from the coordinate frame rotated with the quaternion
|
||||
/// to the current coordinate frame
|
||||
SGVec3<T> backTransform(const SGVec3<T>& v) const
|
||||
{
|
||||
value_type r = 2/dot(*this, *this);
|
||||
T r = 2/dot(*this, *this);
|
||||
SGVec3<T> qimag = imag(*this);
|
||||
value_type qr = real(*this);
|
||||
T qr = real(*this);
|
||||
return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag + (r*qr)*cross(qimag, v);
|
||||
}
|
||||
|
||||
@@ -332,7 +489,7 @@ public:
|
||||
|
||||
/// Return the time derivative of the quaternion given the angular velocity
|
||||
SGQuat
|
||||
derivative(const SGVec3<T>& angVel)
|
||||
derivative(const SGVec3<T>& angVel) const
|
||||
{
|
||||
SGQuat deriv;
|
||||
|
||||
@@ -345,8 +502,65 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
/// The actual data
|
||||
T _data[4];
|
||||
|
||||
// Private because it assumes normalized inputs.
|
||||
static SGQuat
|
||||
fromRotateToSmaller90Deg(T cosang,
|
||||
const SGVec3<T>& from, const SGVec3<T>& to)
|
||||
{
|
||||
// In this function we assume that the angle required to rotate from
|
||||
// the vector from to the vector to is <= 90 deg.
|
||||
// That is done so because of possible instabilities when we rotate more
|
||||
// then 90deg.
|
||||
|
||||
// Note that the next comment does actually cover a *more* *general* case
|
||||
// than we need in this function. That shows that this formula is even
|
||||
// valid for rotations up to 180deg.
|
||||
|
||||
// Because of the signs in the axis, it is sufficient to care for angles
|
||||
// in the interval [-pi,pi]. That means that 0.5*angle is in the interval
|
||||
// [-pi/2,pi/2]. But in that range the cosine is allways >= 0.
|
||||
// So we do not need to care for egative roots in the following equation:
|
||||
T cos05ang = sqrt(0.5+0.5*cosang);
|
||||
|
||||
|
||||
// Now our assumption of angles <= 90 deg comes in play.
|
||||
// For that reason, we know that cos05ang is not zero.
|
||||
// It is even more, we can see from the above formula that
|
||||
// sqrt(0.5) < cos05ang.
|
||||
|
||||
|
||||
// Compute the rotation axis, that is
|
||||
// sin(angle)*normalized rotation axis
|
||||
SGVec3<T> axis = cross(to, from);
|
||||
|
||||
// We need sin(0.5*angle)*normalized rotation axis.
|
||||
// So rescale with sin(0.5*x)/sin(x).
|
||||
// To do that we use the equation:
|
||||
// sin(x) = 2*sin(0.5*x)*cos(0.5*x)
|
||||
return SGQuat::fromRealImag( cos05ang, (1/(2*cos05ang))*axis);
|
||||
}
|
||||
|
||||
// Private because it assumes normalized inputs.
|
||||
static SGQuat
|
||||
fromRotateToNorm(const SGVec3<T>& from, const SGVec3<T>& to)
|
||||
{
|
||||
// To avoid instabilities with roundoff, we distinguish between rotations
|
||||
// with more then 90deg and rotations with less than 90deg.
|
||||
|
||||
// Compute the cosine of the angle.
|
||||
T cosang = dot(from, to);
|
||||
|
||||
// For the small ones do direct computation
|
||||
if (T(-0.5) < cosang)
|
||||
return SGQuat::fromRotateToSmaller90Deg(cosang, from, to);
|
||||
|
||||
// For larger rotations. first rotate from to -from.
|
||||
// Past that we will have a smaller angle again.
|
||||
SGQuat q1 = SGQuat::fromChangeSign(from);
|
||||
SGQuat q2 = SGQuat::fromRotateToSmaller90Deg(-cosang, -from, to);
|
||||
return q1*q2;
|
||||
}
|
||||
};
|
||||
|
||||
/// Unary +, do nothing ...
|
||||
|
||||
62
simgear/math/SGRay.hxx
Normal file
62
simgear/math/SGRay.hxx
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGRay_H
|
||||
#define SGRay_H
|
||||
|
||||
template<typename T>
|
||||
class SGRay {
|
||||
public:
|
||||
SGRay()
|
||||
{ }
|
||||
SGRay(const SGVec3<T>& origin, const SGVec3<T>& dir) :
|
||||
_origin(origin), _direction(dir)
|
||||
{ }
|
||||
|
||||
void set(const SGVec3<T>& origin, const SGVec3<T>& dir)
|
||||
{ _origin = origin; _direction = dir; }
|
||||
|
||||
void setOrigin(const SGVec3<T>& origin)
|
||||
{ _origin = origin; }
|
||||
const SGVec3<T>& getOrigin() const
|
||||
{ return _origin; }
|
||||
|
||||
void setDirection(const SGVec3<T>& direction)
|
||||
{ _direction = direction; }
|
||||
const SGVec3<T>& getDirection() const
|
||||
{ return _direction; }
|
||||
|
||||
SGVec3<T> getNormalizedDirection() const
|
||||
{ return normalize(getDirection()); }
|
||||
|
||||
private:
|
||||
SGVec3<T> _origin;
|
||||
SGVec3<T> _direction;
|
||||
};
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s,
|
||||
const SGRay<T>& ray)
|
||||
{
|
||||
return s << "ray: origin = " << ray.getOrigin()
|
||||
<< ", direction = " << ray.getDirection();
|
||||
}
|
||||
|
||||
#endif
|
||||
87
simgear/math/SGSphere.hxx
Normal file
87
simgear/math/SGSphere.hxx
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGSphere_H
|
||||
#define SGSphere_H
|
||||
|
||||
template<typename T>
|
||||
class SGSphere {
|
||||
public:
|
||||
SGSphere() :
|
||||
_radius(-1)
|
||||
{ }
|
||||
SGSphere(const SGVec3<T>& center, const T& radius) :
|
||||
_center(center),
|
||||
_radius(radius)
|
||||
{ }
|
||||
|
||||
const SGVec3<T>& getCenter() const
|
||||
{ return _center; }
|
||||
void setCenter(const SGVec3<T>& center)
|
||||
{ _center = center; }
|
||||
|
||||
const T& getRadius() const
|
||||
{ return _radius; }
|
||||
void setRadius(const T& radius)
|
||||
{ _radius = radius; }
|
||||
T getRadius2() const
|
||||
{ return _radius*_radius; }
|
||||
|
||||
const bool empty() const
|
||||
{ return !valid(); }
|
||||
|
||||
bool valid() const
|
||||
{ return 0 <= _radius; }
|
||||
|
||||
void clear()
|
||||
{ _radius = -1; }
|
||||
|
||||
void expandBy(const SGVec3<T>& v)
|
||||
{
|
||||
if (empty()) {
|
||||
_center = v;
|
||||
_radius = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
T dist2 = distSqr(_center, v);
|
||||
if (dist2 <= getRadius2())
|
||||
return;
|
||||
|
||||
T dist = sqrt(dist2);
|
||||
T newRadius = T(0.5)*(_radius + dist);
|
||||
_center += ((newRadius - _radius)/dist)*(v - _center);
|
||||
_radius = newRadius;
|
||||
}
|
||||
|
||||
private:
|
||||
SGVec3<T> _center;
|
||||
T _radius;
|
||||
};
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s,
|
||||
const SGSphere<T>& sphere)
|
||||
{
|
||||
return s << "center = " << sphere.getCenter()
|
||||
<< ", radius = " << sphere.getRadius();
|
||||
}
|
||||
|
||||
#endif
|
||||
101
simgear/math/SGTriangle.hxx
Normal file
101
simgear/math/SGTriangle.hxx
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGTriangle_H
|
||||
#define SGTrianlge_H
|
||||
|
||||
template<typename T>
|
||||
class SGTriangle {
|
||||
public:
|
||||
SGTriangle()
|
||||
{ }
|
||||
SGTriangle(const SGVec3<T>& v0, const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ set(v0, v1, v2); }
|
||||
SGTriangle(const SGVec3<T> v[3])
|
||||
{ set(v); }
|
||||
|
||||
void set(const SGVec3<T>& v0, const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{
|
||||
_v0 = v0;
|
||||
_d[0] = v1 - v0;
|
||||
_d[1] = v2 - v0;
|
||||
}
|
||||
void set(const SGVec3<T> v[3])
|
||||
{
|
||||
_v0 = v[0];
|
||||
_d[0] = v[1] - v[0];
|
||||
_d[1] = v[2] - v[0];
|
||||
}
|
||||
|
||||
SGVec3d getCenter() const
|
||||
{
|
||||
SGBoxd box;
|
||||
box.expandBy(_v0);
|
||||
box.expandBy(_v0 + _d[0]);
|
||||
box.expandBy(_v0 + _d[1]);
|
||||
return box.getCenter();
|
||||
}
|
||||
|
||||
// note that the index is unchecked
|
||||
SGVec3<T> getVertex(unsigned i) const
|
||||
{
|
||||
if (0 < i)
|
||||
return _v0 + _d[i-1];
|
||||
return _v0;
|
||||
}
|
||||
/// return the normalized surface normal
|
||||
SGVec3<T> getNormal() const
|
||||
{ return normalize(cross(_d[0], _d[1])); }
|
||||
|
||||
const SGVec3<T>& getBaseVertex() const
|
||||
{ return _v0; }
|
||||
void setBaseVertex(const SGVec3<T>& v)
|
||||
{ _v0 = v; }
|
||||
const SGVec3<T>& getEdge(unsigned i) const
|
||||
{ return _d[i]; }
|
||||
void setEdge(unsigned i, const SGVec3<T>& d)
|
||||
{ _d[i] = d; }
|
||||
|
||||
// flip the positive side
|
||||
void flip()
|
||||
{
|
||||
SGVec3<T> tmp = _d[0];
|
||||
_d[0] = _d[1];
|
||||
_d[1] = tmp;
|
||||
}
|
||||
private:
|
||||
/// Store one vertex directly, _d is the offset of the other two
|
||||
/// vertices wrt the base vertex
|
||||
/// For fast intersection tests this format prooves usefull. For that same
|
||||
/// purpose also cache the cross product of the _d[i].
|
||||
SGVec3<T> _v0;
|
||||
SGVec3<T> _d[2];
|
||||
};
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s,
|
||||
const SGTriangle<T>& triangle)
|
||||
{
|
||||
return s << "triangle: v0 = " << triangle.getVertex(0)
|
||||
<< ", v1 = " << triangle.getVertex(1)
|
||||
<< ", v2 = " << triangle.getVertex(2);
|
||||
}
|
||||
|
||||
#endif
|
||||
405
simgear/math/SGVec2.hxx
Normal file
405
simgear/math/SGVec2.hxx
Normal file
@@ -0,0 +1,405 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGVec2_H
|
||||
#define SGVec2_H
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec2d>
|
||||
|
||||
template<typename T>
|
||||
struct SGVec2Storage {
|
||||
/// Readonly raw storage interface
|
||||
const T (&data(void) const)[2]
|
||||
{ return _data; }
|
||||
/// Readonly raw storage interface
|
||||
T (&data(void))[2]
|
||||
{ return _data; }
|
||||
|
||||
void osg() const
|
||||
{ }
|
||||
|
||||
private:
|
||||
T _data[2];
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec2Storage<float> : public osg::Vec2f {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const float (&data(void) const)[2]
|
||||
{ return osg::Vec2f::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
float (&data(void))[2]
|
||||
{ return osg::Vec2f::_v; }
|
||||
|
||||
const osg::Vec2f& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec2f& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec2Storage<double> : public osg::Vec2d {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const double (&data(void) const)[2]
|
||||
{ return osg::Vec2d::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
double (&data(void))[2]
|
||||
{ return osg::Vec2d::_v; }
|
||||
|
||||
const osg::Vec2d& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec2d& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
/// 2D Vector Class
|
||||
template<typename T>
|
||||
class SGVec2 : protected SGVec2Storage<T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
/// Default constructor. Does not initialize at all.
|
||||
/// If you need them zero initialized, use SGVec2::zeros()
|
||||
SGVec2(void)
|
||||
{
|
||||
/// Initialize with nans in the debug build, that will guarantee to have
|
||||
/// a fast uninitialized default constructor in the release but shows up
|
||||
/// uninitialized values in the debug build very fast ...
|
||||
#ifndef NDEBUG
|
||||
for (unsigned i = 0; i < 2; ++i)
|
||||
data()[i] = SGLimits<T>::quiet_NaN();
|
||||
#endif
|
||||
}
|
||||
/// Constructor. Initialize by the given values
|
||||
SGVec2(T x, T y)
|
||||
{ data()[0] = x; data()[1] = y; }
|
||||
/// Constructor. Initialize by the content of a plain array,
|
||||
/// make sure it has at least 2 elements
|
||||
explicit SGVec2(const T* d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; }
|
||||
explicit SGVec2(const osg::Vec2f& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; }
|
||||
explicit SGVec2(const osg::Vec2d& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; }
|
||||
|
||||
/// Access by index, the index is unchecked
|
||||
const T& operator()(unsigned i) const
|
||||
{ return data()[i]; }
|
||||
/// Access by index, the index is unchecked
|
||||
T& operator()(unsigned i)
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const T& operator[](unsigned i) const
|
||||
{ return data()[i]; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
T& operator[](unsigned i)
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access the x component
|
||||
const T& x(void) const
|
||||
{ return data()[0]; }
|
||||
/// Access the x component
|
||||
T& x(void)
|
||||
{ return data()[0]; }
|
||||
/// Access the y component
|
||||
const T& y(void) const
|
||||
{ return data()[1]; }
|
||||
/// Access the y component
|
||||
T& y(void)
|
||||
{ return data()[1]; }
|
||||
|
||||
/// Get the data pointer
|
||||
using SGVec2Storage<T>::data;
|
||||
|
||||
/// Readonly interface function to ssg's sgVec2/sgdVec2
|
||||
const T (&sg(void) const)[2]
|
||||
{ return data(); }
|
||||
/// Interface function to ssg's sgVec2/sgdVec2
|
||||
T (&sg(void))[2]
|
||||
{ return data(); }
|
||||
|
||||
/// Interface function to osg's Vec2*
|
||||
using SGVec2Storage<T>::osg;
|
||||
|
||||
/// Inplace addition
|
||||
SGVec2& operator+=(const SGVec2& v)
|
||||
{ data()[0] += v(0); data()[1] += v(1); return *this; }
|
||||
/// Inplace subtraction
|
||||
SGVec2& operator-=(const SGVec2& v)
|
||||
{ data()[0] -= v(0); data()[1] -= v(1); return *this; }
|
||||
/// Inplace scalar multiplication
|
||||
template<typename S>
|
||||
SGVec2& operator*=(S s)
|
||||
{ data()[0] *= s; data()[1] *= s; return *this; }
|
||||
/// Inplace scalar multiplication by 1/s
|
||||
template<typename S>
|
||||
SGVec2& operator/=(S s)
|
||||
{ return operator*=(1/T(s)); }
|
||||
|
||||
/// Return an all zero vector
|
||||
static SGVec2 zeros(void)
|
||||
{ return SGVec2(0, 0); }
|
||||
/// Return unit vectors
|
||||
static SGVec2 e1(void)
|
||||
{ return SGVec2(1, 0); }
|
||||
static SGVec2 e2(void)
|
||||
{ return SGVec2(0, 1); }
|
||||
};
|
||||
|
||||
/// Unary +, do nothing ...
|
||||
template<typename T>
|
||||
inline
|
||||
const SGVec2<T>&
|
||||
operator+(const SGVec2<T>& v)
|
||||
{ return v; }
|
||||
|
||||
/// Unary -, do nearly nothing
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
operator-(const SGVec2<T>& v)
|
||||
{ return SGVec2<T>(-v(0), -v(1)); }
|
||||
|
||||
/// Binary +
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
operator+(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return SGVec2<T>(v1(0)+v2(0), v1(1)+v2(1)); }
|
||||
|
||||
/// Binary -
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
operator-(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return SGVec2<T>(v1(0)-v2(0), v1(1)-v2(1)); }
|
||||
|
||||
/// Scalar multiplication
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
operator*(S s, const SGVec2<T>& v)
|
||||
{ return SGVec2<T>(s*v(0), s*v(1)); }
|
||||
|
||||
/// Scalar multiplication
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
operator*(const SGVec2<T>& v, S s)
|
||||
{ return SGVec2<T>(s*v(0), s*v(1)); }
|
||||
|
||||
/// multiplication as a multiplicator, that is assume that the first vector
|
||||
/// represents a 2x2 diagonal matrix with the diagonal elements in the vector.
|
||||
/// Then the result is the product of that matrix times the second vector.
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
mult(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return SGVec2<T>(v1(0)*v2(0), v1(1)*v2(1)); }
|
||||
|
||||
/// component wise min
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
min(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{return SGVec2<T>(SGMisc<T>::min(v1(0), v2(0)), SGMisc<T>::min(v1(1), v2(1)));}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
min(const SGVec2<T>& v, S s)
|
||||
{ return SGVec2<T>(SGMisc<T>::min(s, v(0)), SGMisc<T>::min(s, v(1))); }
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
min(S s, const SGVec2<T>& v)
|
||||
{ return SGVec2<T>(SGMisc<T>::min(s, v(0)), SGMisc<T>::min(s, v(1))); }
|
||||
|
||||
/// component wise max
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
max(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{return SGVec2<T>(SGMisc<T>::max(v1(0), v2(0)), SGMisc<T>::max(v1(1), v2(1)));}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
max(const SGVec2<T>& v, S s)
|
||||
{ return SGVec2<T>(SGMisc<T>::max(s, v(0)), SGMisc<T>::max(s, v(1))); }
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
max(S s, const SGVec2<T>& v)
|
||||
{ return SGVec2<T>(SGMisc<T>::max(s, v(0)), SGMisc<T>::max(s, v(1))); }
|
||||
|
||||
/// Scalar dot product
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
dot(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return v1(0)*v2(0) + v1(1)*v2(1); }
|
||||
|
||||
/// The euclidean norm of the vector, that is what most people call length
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
norm(const SGVec2<T>& v)
|
||||
{ return sqrt(dot(v, v)); }
|
||||
|
||||
/// The euclidean norm of the vector, that is what most people call length
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
length(const SGVec2<T>& v)
|
||||
{ return sqrt(dot(v, v)); }
|
||||
|
||||
/// The 1-norm of the vector, this one is the fastest length function we
|
||||
/// can implement on modern cpu's
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
norm1(const SGVec2<T>& v)
|
||||
{ return fabs(v(0)) + fabs(v(1)); }
|
||||
|
||||
/// The inf-norm of the vector
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
normI(const SGVec2<T>& v)
|
||||
{ return SGMisc<T>::max(fabs(v(0)), fabs(v(1))); }
|
||||
|
||||
/// The euclidean norm of the vector, that is what most people call length
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
normalize(const SGVec2<T>& v)
|
||||
{ return (1/norm(v))*v; }
|
||||
|
||||
/// Return true if exactly the same
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator==(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return v1(0) == v2(0) && v1(1) == v2(1); }
|
||||
|
||||
/// Return true if not exactly the same
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator!=(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return ! (v1 == v2); }
|
||||
|
||||
/// Return true if smaller, good for putting that into a std::map
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else return (v1(1) < v2(1));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<=(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else return (v1(1) <= v2(1));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return operator<(v2, v1); }
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>=(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return operator<=(v2, v1); }
|
||||
|
||||
/// Return true if equal to the relative tolerance tol
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
equivalent(const SGVec2<T>& v1, const SGVec2<T>& v2, T rtol, T atol)
|
||||
{ return norm1(v1 - v2) < rtol*(norm1(v1) + norm1(v2)) + atol; }
|
||||
|
||||
/// Return true if equal to the relative tolerance tol
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
equivalent(const SGVec2<T>& v1, const SGVec2<T>& v2, T rtol)
|
||||
{ return norm1(v1 - v2) < rtol*(norm1(v1) + norm1(v2)); }
|
||||
|
||||
/// Return true if about equal to roundoff of the underlying type
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
equivalent(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{
|
||||
T tol = 100*SGLimits<T>::epsilon();
|
||||
return equivalent(v1, v2, tol, tol);
|
||||
}
|
||||
|
||||
/// The euclidean distance of the two vectors
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
dist(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return norm(v1 - v2); }
|
||||
|
||||
/// The squared euclidean distance of the two vectors
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
distSqr(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ SGVec2<T> tmp = v1 - v2; return dot(tmp, tmp); }
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
isNaN(const SGVec2<T>& v)
|
||||
{
|
||||
return SGMisc<T>::isNaN(v(0)) || SGMisc<T>::isNaN(v(1));
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec2<T>& v)
|
||||
{ return s << "[ " << v(0) << ", " << v(1) << " ]"; }
|
||||
|
||||
inline
|
||||
SGVec2f
|
||||
toVec2f(const SGVec2d& v)
|
||||
{ return SGVec2f((float)v(0), (float)v(1)); }
|
||||
|
||||
inline
|
||||
SGVec2d
|
||||
toVec2d(const SGVec2f& v)
|
||||
{ return SGVec2d(v(0), v(1)); }
|
||||
|
||||
#endif
|
||||
@@ -18,9 +18,58 @@
|
||||
#ifndef SGVec3_H
|
||||
#define SGVec3_H
|
||||
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/Vec3d>
|
||||
|
||||
template<typename T>
|
||||
struct SGVec3Storage {
|
||||
/// Readonly raw storage interface
|
||||
const T (&data(void) const)[3]
|
||||
{ return _data; }
|
||||
/// Readonly raw storage interface
|
||||
T (&data(void))[3]
|
||||
{ return _data; }
|
||||
|
||||
void osg() const
|
||||
{ }
|
||||
|
||||
private:
|
||||
T _data[3];
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec3Storage<float> : public osg::Vec3f {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const float (&data(void) const)[3]
|
||||
{ return osg::Vec3f::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
float (&data(void))[3]
|
||||
{ return osg::Vec3f::_v; }
|
||||
|
||||
const osg::Vec3f& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec3f& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec3Storage<double> : public osg::Vec3d {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const double (&data(void) const)[3]
|
||||
{ return osg::Vec3d::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
double (&data(void))[3]
|
||||
{ return osg::Vec3d::_v; }
|
||||
|
||||
const osg::Vec3d& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec3d& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
/// 3D Vector Class
|
||||
template<typename T>
|
||||
class SGVec3 {
|
||||
class SGVec3 : protected SGVec3Storage<T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
@@ -33,74 +82,79 @@ public:
|
||||
/// uninitialized values in the debug build very fast ...
|
||||
#ifndef NDEBUG
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
_data[i] = SGLimits<T>::quiet_NaN();
|
||||
data()[i] = SGLimits<T>::quiet_NaN();
|
||||
#endif
|
||||
}
|
||||
/// Constructor. Initialize by the given values
|
||||
SGVec3(T x, T y, T z)
|
||||
{ _data[0] = x; _data[1] = y; _data[2] = z; }
|
||||
{ data()[0] = x; data()[1] = y; data()[2] = z; }
|
||||
/// Constructor. Initialize by the content of a plain array,
|
||||
/// make sure it has at least 3 elements
|
||||
explicit SGVec3(const T* data)
|
||||
{ _data[0] = data[0]; _data[1] = data[1]; _data[2] = data[2]; }
|
||||
explicit SGVec3(const T* d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
|
||||
explicit SGVec3(const osg::Vec3f& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
|
||||
explicit SGVec3(const osg::Vec3d& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
|
||||
explicit SGVec3(const SGVec2<T>& v2, const T& v3 = 0)
|
||||
{ data()[0] = v2[0]; data()[1] = v2[1]; data()[2] = v3; }
|
||||
|
||||
/// Access by index, the index is unchecked
|
||||
const T& operator()(unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access by index, the index is unchecked
|
||||
T& operator()(unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const T& operator[](unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
T& operator[](unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access the x component
|
||||
const T& x(void) const
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the x component
|
||||
T& x(void)
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the y component
|
||||
const T& y(void) const
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the y component
|
||||
T& y(void)
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the z component
|
||||
const T& z(void) const
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
/// Access the z component
|
||||
T& z(void)
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
|
||||
/// Get the data pointer
|
||||
const T* data(void) const
|
||||
{ return _data; }
|
||||
/// Get the data pointer
|
||||
T* data(void)
|
||||
{ return _data; }
|
||||
using SGVec3Storage<T>::data;
|
||||
|
||||
/// Readonly interface function to ssg's sgVec3/sgdVec3
|
||||
const T (&sg(void) const)[3]
|
||||
{ return _data; }
|
||||
{ return data(); }
|
||||
/// Interface function to ssg's sgVec3/sgdVec3
|
||||
T (&sg(void))[3]
|
||||
{ return _data; }
|
||||
{ return data(); }
|
||||
|
||||
/// Interface function to osg's Vec3*
|
||||
using SGVec3Storage<T>::osg;
|
||||
|
||||
/// Inplace addition
|
||||
SGVec3& operator+=(const SGVec3& v)
|
||||
{ _data[0] += v(0); _data[1] += v(1); _data[2] += v(2); return *this; }
|
||||
{ data()[0] += v(0); data()[1] += v(1); data()[2] += v(2); return *this; }
|
||||
/// Inplace subtraction
|
||||
SGVec3& operator-=(const SGVec3& v)
|
||||
{ _data[0] -= v(0); _data[1] -= v(1); _data[2] -= v(2); return *this; }
|
||||
{ data()[0] -= v(0); data()[1] -= v(1); data()[2] -= v(2); return *this; }
|
||||
/// Inplace scalar multiplication
|
||||
template<typename S>
|
||||
SGVec3& operator*=(S s)
|
||||
{ _data[0] *= s; _data[1] *= s; _data[2] *= s; return *this; }
|
||||
{ data()[0] *= s; data()[1] *= s; data()[2] *= s; return *this; }
|
||||
/// Inplace scalar multiplication by 1/s
|
||||
template<typename S>
|
||||
SGVec3& operator/=(S s)
|
||||
@@ -123,10 +177,6 @@ public:
|
||||
/// Constructor. Initialize by a geocentric coordinate
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
static SGVec3 fromGeoc(const SGGeoc& geoc);
|
||||
|
||||
private:
|
||||
/// The actual data
|
||||
T _data[3];
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -211,6 +261,73 @@ SGVec3<T>
|
||||
operator*(const SGVec3<T>& v, S s)
|
||||
{ return SGVec3<T>(s*v(0), s*v(1), s*v(2)); }
|
||||
|
||||
/// multiplication as a multiplicator, that is assume that the first vector
|
||||
/// represents a 3x3 diagonal matrix with the diagonal elements in the vector.
|
||||
/// Then the result is the product of that matrix times the second vector.
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
mult(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ return SGVec3<T>(v1(0)*v2(0), v1(1)*v2(1), v1(2)*v2(2)); }
|
||||
|
||||
/// component wise min
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
min(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::min(v1(0), v2(0)),
|
||||
SGMisc<T>::min(v1(1), v2(1)),
|
||||
SGMisc<T>::min(v1(2), v2(2)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
min(const SGVec3<T>& v, S s)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::min(s, v(0)),
|
||||
SGMisc<T>::min(s, v(1)),
|
||||
SGMisc<T>::min(s, v(2)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
min(S s, const SGVec3<T>& v)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::min(s, v(0)),
|
||||
SGMisc<T>::min(s, v(1)),
|
||||
SGMisc<T>::min(s, v(2)));
|
||||
}
|
||||
|
||||
/// component wise max
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
max(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::max(v1(0), v2(0)),
|
||||
SGMisc<T>::max(v1(1), v2(1)),
|
||||
SGMisc<T>::max(v1(2), v2(2)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
max(const SGVec3<T>& v, S s)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::max(s, v(0)),
|
||||
SGMisc<T>::max(s, v(1)),
|
||||
SGMisc<T>::max(s, v(2)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
max(S s, const SGVec3<T>& v)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::max(s, v(0)),
|
||||
SGMisc<T>::max(s, v(1)),
|
||||
SGMisc<T>::max(s, v(2)));
|
||||
}
|
||||
|
||||
/// Scalar dot product
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -240,6 +357,13 @@ T
|
||||
norm1(const SGVec3<T>& v)
|
||||
{ return fabs(v(0)) + fabs(v(1)) + fabs(v(2)); }
|
||||
|
||||
/// The inf-norm of the vector
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
normI(const SGVec3<T>& v)
|
||||
{ return SGMisc<T>::max(fabs(v(0)), fabs(v(1)), fabs(v(2))); }
|
||||
|
||||
/// Vector cross product
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -251,6 +375,31 @@ cross(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
v1(0)*v2(1) - v1(1)*v2(0));
|
||||
}
|
||||
|
||||
/// return any normalized vector perpendicular to v
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
perpendicular(const SGVec3<T>& v)
|
||||
{
|
||||
T absv1 = fabs(v(0));
|
||||
T absv2 = fabs(v(1));
|
||||
T absv3 = fabs(v(2));
|
||||
|
||||
if (absv2 < absv1 && absv3 < absv1) {
|
||||
T quot = v(1)/v(0);
|
||||
return (1/sqrt(1+quot*quot))*SGVec3<T>(quot, -1, 0);
|
||||
} else if (absv3 < absv2) {
|
||||
T quot = v(2)/v(1);
|
||||
return (1/sqrt(1+quot*quot))*SGVec3<T>(0, quot, -1);
|
||||
} else if (SGLimits<T>::min() < absv3) {
|
||||
T quot = v(0)/v(2);
|
||||
return (1/sqrt(1+quot*quot))*SGVec3<T>(-1, 0, quot);
|
||||
} else {
|
||||
// the all zero case ...
|
||||
return SGVec3<T>(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// The euclidean norm of the vector, that is what most people call length
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -272,6 +421,43 @@ bool
|
||||
operator!=(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ return ! (v1 == v2); }
|
||||
|
||||
/// Return true if smaller, good for putting that into a std::map
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else if (v1(1) < v2(1)) return true;
|
||||
else if (v2(1) < v1(1)) return false;
|
||||
else return (v1(2) < v2(2));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<=(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else if (v1(1) < v2(1)) return true;
|
||||
else if (v2(1) < v1(1)) return false;
|
||||
else return (v1(2) <= v2(2));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ return operator<(v2, v1); }
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>=(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ return operator<=(v2, v1); }
|
||||
|
||||
/// Return true if equal to the relative tolerance tol
|
||||
template<typename T>
|
||||
inline
|
||||
|
||||
@@ -18,9 +18,58 @@
|
||||
#ifndef SGVec4_H
|
||||
#define SGVec4_H
|
||||
|
||||
#include <osg/Vec4f>
|
||||
#include <osg/Vec4d>
|
||||
|
||||
template<typename T>
|
||||
struct SGVec4Storage {
|
||||
/// Readonly raw storage interface
|
||||
const T (&data(void) const)[4]
|
||||
{ return _data; }
|
||||
/// Readonly raw storage interface
|
||||
T (&data(void))[4]
|
||||
{ return _data; }
|
||||
|
||||
void osg() const
|
||||
{ }
|
||||
|
||||
private:
|
||||
T _data[4];
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec4Storage<float> : public osg::Vec4f {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const float (&data(void) const)[4]
|
||||
{ return osg::Vec4f::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
float (&data(void))[4]
|
||||
{ return osg::Vec4f::_v; }
|
||||
|
||||
const osg::Vec4f& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec4f& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec4Storage<double> : public osg::Vec4d {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const double (&data(void) const)[4]
|
||||
{ return osg::Vec4d::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
double (&data(void))[4]
|
||||
{ return osg::Vec4d::_v; }
|
||||
|
||||
const osg::Vec4d& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec4d& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
/// 4D Vector Class
|
||||
template<typename T>
|
||||
class SGVec4 {
|
||||
class SGVec4 : protected SGVec4Storage<T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
@@ -33,82 +82,86 @@ public:
|
||||
/// uninitialized values in the debug build very fast ...
|
||||
#ifndef NDEBUG
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
_data[i] = SGLimits<T>::quiet_NaN();
|
||||
data()[i] = SGLimits<T>::quiet_NaN();
|
||||
#endif
|
||||
}
|
||||
/// Constructor. Initialize by the given values
|
||||
SGVec4(T x, T y, T z, T w)
|
||||
{ _data[0] = x; _data[1] = y; _data[2] = z; _data[3] = w; }
|
||||
{ data()[0] = x; data()[1] = y; data()[2] = z; data()[3] = w; }
|
||||
/// Constructor. Initialize by the content of a plain array,
|
||||
/// make sure it has at least 3 elements
|
||||
explicit SGVec4(const T* d)
|
||||
{ _data[0] = d[0]; _data[1] = d[1]; _data[2] = d[2]; _data[3] = d[3]; }
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
|
||||
explicit SGVec4(const osg::Vec4f& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
|
||||
explicit SGVec4(const osg::Vec4d& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
|
||||
explicit SGVec4(const SGVec3<T>& v3, const T& v4 = 0)
|
||||
{ data()[0] = v3[0]; data()[1] = v3[1]; data()[2] = v3[2]; data()[3] = v4; }
|
||||
|
||||
|
||||
/// Access by index, the index is unchecked
|
||||
const T& operator()(unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access by index, the index is unchecked
|
||||
T& operator()(unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const T& operator[](unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
T& operator[](unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access the x component
|
||||
const T& x(void) const
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the x component
|
||||
T& x(void)
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the y component
|
||||
const T& y(void) const
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the y component
|
||||
T& y(void)
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the z component
|
||||
const T& z(void) const
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
/// Access the z component
|
||||
T& z(void)
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
/// Access the x component
|
||||
const T& w(void) const
|
||||
{ return _data[3]; }
|
||||
{ return data()[3]; }
|
||||
/// Access the x component
|
||||
T& w(void)
|
||||
{ return _data[3]; }
|
||||
{ return data()[3]; }
|
||||
|
||||
/// Get the data pointer
|
||||
using SGVec4Storage<T>::data;
|
||||
|
||||
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
|
||||
const T* data(void) const
|
||||
{ return _data; }
|
||||
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
|
||||
T* data(void)
|
||||
{ return _data; }
|
||||
|
||||
/// Readonly interface function to ssg's sgVec3/sgdVec3
|
||||
/// Readonly interface function to ssg's sgVec4/sgdVec4
|
||||
const T (&sg(void) const)[4]
|
||||
{ return _data; }
|
||||
/// Interface function to ssg's sgVec3/sgdVec3
|
||||
{ return data(); }
|
||||
/// Interface function to ssg's sgVec4/sgdVec4
|
||||
T (&sg(void))[4]
|
||||
{ return _data; }
|
||||
{ return data(); }
|
||||
|
||||
/// Interface function to osg's Vec4*
|
||||
using SGVec4Storage<T>::osg;
|
||||
|
||||
/// Inplace addition
|
||||
SGVec4& operator+=(const SGVec4& v)
|
||||
{ _data[0]+=v(0);_data[1]+=v(1);_data[2]+=v(2);_data[3]+=v(3);return *this; }
|
||||
{ data()[0]+=v(0);data()[1]+=v(1);data()[2]+=v(2);data()[3]+=v(3);return *this; }
|
||||
/// Inplace subtraction
|
||||
SGVec4& operator-=(const SGVec4& v)
|
||||
{ _data[0]-=v(0);_data[1]-=v(1);_data[2]-=v(2);_data[3]-=v(3);return *this; }
|
||||
{ data()[0]-=v(0);data()[1]-=v(1);data()[2]-=v(2);data()[3]-=v(3);return *this; }
|
||||
/// Inplace scalar multiplication
|
||||
template<typename S>
|
||||
SGVec4& operator*=(S s)
|
||||
{ _data[0] *= s; _data[1] *= s; _data[2] *= s; _data[3] *= s; return *this; }
|
||||
{ data()[0] *= s; data()[1] *= s; data()[2] *= s; data()[3] *= s; return *this; }
|
||||
/// Inplace scalar multiplication by 1/s
|
||||
template<typename S>
|
||||
SGVec4& operator/=(S s)
|
||||
@@ -126,10 +179,6 @@ public:
|
||||
{ return SGVec4(0, 0, 1, 0); }
|
||||
static SGVec4 e4(void)
|
||||
{ return SGVec4(0, 0, 0, 1); }
|
||||
|
||||
private:
|
||||
/// The actual data
|
||||
T _data[4];
|
||||
};
|
||||
|
||||
/// Unary +, do nothing ...
|
||||
@@ -174,6 +223,79 @@ SGVec4<T>
|
||||
operator*(const SGVec4<T>& v, S s)
|
||||
{ return SGVec4<T>(s*v(0), s*v(1), s*v(2), s*v(3)); }
|
||||
|
||||
/// multiplication as a multiplicator, that is assume that the first vector
|
||||
/// represents a 4x4 diagonal matrix with the diagonal elements in the vector.
|
||||
/// Then the result is the product of that matrix times the second vector.
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
mult(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{ return SGVec4<T>(v1(0)*v2(0), v1(1)*v2(1), v1(2)*v2(2), v1(3)*v2(3)); }
|
||||
|
||||
/// component wise min
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
min(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::min(v1(0), v2(0)),
|
||||
SGMisc<T>::min(v1(1), v2(1)),
|
||||
SGMisc<T>::min(v1(2), v2(2)),
|
||||
SGMisc<T>::min(v1(3), v2(3)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
min(const SGVec4<T>& v, S s)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::min(s, v(0)),
|
||||
SGMisc<T>::min(s, v(1)),
|
||||
SGMisc<T>::min(s, v(2)),
|
||||
SGMisc<T>::min(s, v(3)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
min(S s, const SGVec4<T>& v)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::min(s, v(0)),
|
||||
SGMisc<T>::min(s, v(1)),
|
||||
SGMisc<T>::min(s, v(2)),
|
||||
SGMisc<T>::min(s, v(3)));
|
||||
}
|
||||
|
||||
/// component wise max
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
max(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::max(v1(0), v2(0)),
|
||||
SGMisc<T>::max(v1(1), v2(1)),
|
||||
SGMisc<T>::max(v1(2), v2(2)),
|
||||
SGMisc<T>::max(v1(3), v2(3)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
max(const SGVec4<T>& v, S s)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::max(s, v(0)),
|
||||
SGMisc<T>::max(s, v(1)),
|
||||
SGMisc<T>::max(s, v(2)),
|
||||
SGMisc<T>::max(s, v(3)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
max(S s, const SGVec4<T>& v)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::max(s, v(0)),
|
||||
SGMisc<T>::max(s, v(1)),
|
||||
SGMisc<T>::max(s, v(2)),
|
||||
SGMisc<T>::max(s, v(3)));
|
||||
}
|
||||
|
||||
/// Scalar dot product
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -203,6 +325,13 @@ T
|
||||
norm1(const SGVec4<T>& v)
|
||||
{ return fabs(v(0)) + fabs(v(1)) + fabs(v(2)) + fabs(v(3)); }
|
||||
|
||||
/// The inf-norm of the vector
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
normI(const SGVec4<T>& v)
|
||||
{ return SGMisc<T>::max(fabs(v(0)), fabs(v(1)), fabs(v(2)), fabs(v(2))); }
|
||||
|
||||
/// The euclidean norm of the vector, that is what most people call length
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -224,6 +353,47 @@ bool
|
||||
operator!=(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{ return ! (v1 == v2); }
|
||||
|
||||
/// Return true if smaller, good for putting that into a std::map
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else if (v1(1) < v2(1)) return true;
|
||||
else if (v2(1) < v1(1)) return false;
|
||||
else if (v1(2) < v2(2)) return true;
|
||||
else if (v2(2) < v1(2)) return false;
|
||||
else return (v1(3) < v2(3));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<=(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else if (v1(1) < v2(1)) return true;
|
||||
else if (v2(1) < v1(1)) return false;
|
||||
else if (v1(2) < v2(2)) return true;
|
||||
else if (v2(2) < v1(2)) return false;
|
||||
else return (v1(3) <= v2(3));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{ return operator<(v2, v1); }
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>=(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{ return operator<=(v2, v1); }
|
||||
|
||||
/// Return true if equal to the relative tolerance tol
|
||||
template<typename T>
|
||||
inline
|
||||
|
||||
@@ -25,12 +25,11 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <stdlib.h> // for exit()
|
||||
|
||||
#include STL_STRING
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include "interpolater.hxx"
|
||||
|
||||
@@ -38,22 +37,29 @@ SG_USING_STD(string);
|
||||
|
||||
// Constructor -- starts with an empty table.
|
||||
SGInterpTable::SGInterpTable()
|
||||
: size(0)
|
||||
{
|
||||
}
|
||||
|
||||
SGInterpTable::SGInterpTable(const SGPropertyNode* interpolation)
|
||||
{
|
||||
if (!interpolation)
|
||||
return;
|
||||
std::vector<SGPropertyNode_ptr> entries = interpolation->getChildren("entry");
|
||||
for (unsigned i = 0; i < entries.size(); ++i)
|
||||
addEntry(entries[i]->getDoubleValue("ind", 0.0),
|
||||
entries[i]->getDoubleValue("dep", 0.0));
|
||||
}
|
||||
|
||||
// Constructor -- loads the interpolation table from the specified
|
||||
// file
|
||||
SGInterpTable::SGInterpTable( const string& file )
|
||||
: size(0)
|
||||
{
|
||||
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
|
||||
|
||||
sg_gzifstream in( file );
|
||||
if ( !in.is_open() ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
|
||||
exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
in >> skipcomment;
|
||||
@@ -61,8 +67,7 @@ SGInterpTable::SGInterpTable( const string& file )
|
||||
double ind, dep;
|
||||
in >> ind >> dep;
|
||||
in >> skipws;
|
||||
table.push_back(Entry(ind, dep));
|
||||
size++;
|
||||
_table[ind] = dep;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,51 +75,42 @@ SGInterpTable::SGInterpTable( const string& file )
|
||||
// Add an entry to the table.
|
||||
void SGInterpTable::addEntry (double ind, double dep)
|
||||
{
|
||||
table.push_back(Entry(ind,dep));
|
||||
size++;
|
||||
_table[ind] = dep;
|
||||
}
|
||||
|
||||
|
||||
// Given an x value, linearly interpolate the y value from the table
|
||||
double SGInterpTable::interpolate(double x) const
|
||||
{
|
||||
int i;
|
||||
double y;
|
||||
|
||||
if (size == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
while ( (i < size) && (x > table[i].ind) ) {
|
||||
// cout << " i = " << i << " table[i].ind = " << table[i].ind << endl;
|
||||
// cout << " size = " << size << endl;
|
||||
i++;
|
||||
}
|
||||
|
||||
// printf ("i = %d ", i);
|
||||
|
||||
if ( i <= 0 ) {
|
||||
SG_LOG( SG_MATH, SG_DEBUG,
|
||||
"interpolate(): lookup error, x to small = " << x );
|
||||
return table[0].dep;
|
||||
}
|
||||
|
||||
// cout << " table[size-1].ind = " << table[size-1].ind << endl;
|
||||
if ( i >= size ) {
|
||||
SG_LOG( SG_MATH, SG_DEBUG,
|
||||
"interpolate(): lookup error, x to big = " << x );
|
||||
return table[size-1].dep;
|
||||
}
|
||||
|
||||
// y = y1 + (y0 - y1)(x - x1) / (x0 - x1)
|
||||
y = table[i].dep +
|
||||
( (table[i-1].dep - table[i].dep) *
|
||||
(x - table[i].ind) ) /
|
||||
(table[i-1].ind - table[i].ind);
|
||||
|
||||
return(y);
|
||||
// Empty table??
|
||||
if (_table.empty())
|
||||
return 0;
|
||||
|
||||
// Find the table bounds for the requested input.
|
||||
Table::const_iterator upBoundIt = _table.upper_bound(x);
|
||||
// points to a value outside the map. That is we are out of range.
|
||||
// use the last entry
|
||||
if (upBoundIt == _table.end())
|
||||
return _table.rbegin()->second;
|
||||
|
||||
// points to the first key must be lower
|
||||
// use the first entry
|
||||
if (upBoundIt == _table.begin())
|
||||
return upBoundIt->second;
|
||||
|
||||
// we know that we do not stand at the beginning, so it is safe to do so
|
||||
Table::const_iterator loBoundIt = upBoundIt;
|
||||
--loBoundIt;
|
||||
|
||||
// Just do linear interpolation.
|
||||
double loBound = loBoundIt->first;
|
||||
double upBound = upBoundIt->first;
|
||||
double loVal = loBoundIt->second;
|
||||
double upVal = upBoundIt->second;
|
||||
|
||||
// division by zero should not happen since the std::map
|
||||
// has sorted out duplicate entries before. Also since we have a
|
||||
// map, we know that we get different first values for different iterators
|
||||
return loVal + (upVal - loVal)*(x - loBound)/(upBound - loBound);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -35,12 +35,14 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <vector>
|
||||
SG_USING_STD(vector);
|
||||
#include "simgear/structure/SGReferenced.hxx"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include STL_STRING
|
||||
SG_USING_STD(string);
|
||||
|
||||
class SGPropertyNode;
|
||||
|
||||
/**
|
||||
* A class that provids a simple linear 2d interpolation lookup table.
|
||||
@@ -48,21 +50,7 @@ SG_USING_STD(string);
|
||||
* independant variable must be strictly ascending. The dependent
|
||||
* variable can be anything.
|
||||
*/
|
||||
class SGInterpTable {
|
||||
|
||||
struct Entry
|
||||
{
|
||||
Entry ()
|
||||
: ind(0.0L), dep(0.0L) {}
|
||||
Entry (double independent, double dependent)
|
||||
: ind(independent), dep(dependent) {}
|
||||
double ind;
|
||||
double dep;
|
||||
};
|
||||
|
||||
int size;
|
||||
vector<Entry> table;
|
||||
|
||||
class SGInterpTable : public SGReferenced {
|
||||
public:
|
||||
|
||||
/**
|
||||
@@ -70,6 +58,13 @@ public:
|
||||
*/
|
||||
SGInterpTable();
|
||||
|
||||
/**
|
||||
* Constructor. Loads the interpolation table from an interpolation
|
||||
* property node.
|
||||
* @param interpolation property node having entry children
|
||||
*/
|
||||
SGInterpTable(const SGPropertyNode* interpolation);
|
||||
|
||||
/**
|
||||
* Constructor. Loads the interpolation table from the specified file.
|
||||
* @param file name of interpolation file
|
||||
@@ -95,6 +90,10 @@ public:
|
||||
|
||||
/** Destructor */
|
||||
~SGInterpTable();
|
||||
|
||||
private:
|
||||
typedef std::map<double, double> Table;
|
||||
Table _table;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -97,6 +97,8 @@ public:
|
||||
static Point3D fromSGGeod(const SGGeod& geod);
|
||||
static Point3D fromSGGeoc(const SGGeoc& geoc);
|
||||
static Point3D fromSGVec3(const SGVec3<double>& cart);
|
||||
static Point3D fromSGVec3(const SGVec3<float>& cart);
|
||||
static Point3D fromSGVec2(const SGVec2<double>& cart);
|
||||
|
||||
// Assignment operators
|
||||
|
||||
@@ -132,6 +134,10 @@ public:
|
||||
SGGeod toSGGeod(void) const;
|
||||
SGGeoc toSGGeoc(void) const;
|
||||
|
||||
SGVec3d toSGVec3d(void) const;
|
||||
SGVec3f toSGVec3f(void) const;
|
||||
SGVec2f toSGVec2f(void) const;
|
||||
|
||||
// friends
|
||||
friend Point3D operator - (const Point3D& p); // -p1
|
||||
friend bool operator == (const Point3D& a, const Point3D& b); // p1 == p2?
|
||||
@@ -239,6 +245,24 @@ inline Point3D Point3D::fromSGVec3(const SGVec3<double>& cart)
|
||||
return pt;
|
||||
}
|
||||
|
||||
inline Point3D Point3D::fromSGVec3(const SGVec3<float>& cart)
|
||||
{
|
||||
Point3D pt;
|
||||
pt.setx(cart.x());
|
||||
pt.sety(cart.y());
|
||||
pt.setz(cart.z());
|
||||
return pt;
|
||||
}
|
||||
|
||||
inline Point3D Point3D::fromSGVec2(const SGVec2<double>& cart)
|
||||
{
|
||||
Point3D pt;
|
||||
pt.setx(cart.x());
|
||||
pt.sety(cart.y());
|
||||
pt.setz(0);
|
||||
return pt;
|
||||
}
|
||||
|
||||
// ASSIGNMENT OPERATORS
|
||||
|
||||
inline Point3D& Point3D::operator = (const Point3D& p)
|
||||
@@ -341,6 +365,21 @@ inline SGGeoc Point3D::toSGGeoc(void) const
|
||||
return geoc;
|
||||
}
|
||||
|
||||
inline SGVec3d Point3D::toSGVec3d(void) const
|
||||
{
|
||||
return SGVec3d(x(), y(), z());
|
||||
}
|
||||
|
||||
inline SGVec3f Point3D::toSGVec3f(void) const
|
||||
{
|
||||
return SGVec3f(x(), y(), z());
|
||||
}
|
||||
|
||||
inline SGVec2f Point3D::toSGVec2f(void) const
|
||||
{
|
||||
return SGVec2f(x(), y());
|
||||
}
|
||||
|
||||
// FRIENDS
|
||||
|
||||
inline Point3D operator - (const Point3D& a)
|
||||
|
||||
@@ -195,6 +195,8 @@ bool SGPath::exists() const {
|
||||
|
||||
void SGPath::create_dir( mode_t mode ) {
|
||||
string_list dirlist = sgPathSplit(dir());
|
||||
if ( dirlist.empty() )
|
||||
return;
|
||||
string path = dirlist[0];
|
||||
string_list path_elements = sgPathBranchSplit(path);
|
||||
bool absolute = !path.empty() && path[0] == sgDirPathSep;
|
||||
|
||||
@@ -2,26 +2,12 @@ includedir = @includedir@/nasal
|
||||
|
||||
lib_LIBRARIES = libsgnasal.a
|
||||
|
||||
include_HEADERS = nasal.h
|
||||
include_HEADERS = nasal.h naref.h
|
||||
|
||||
libsgnasal_a_SOURCES = \
|
||||
code.c code.h \
|
||||
codegen.c \
|
||||
data.h \
|
||||
gc.c \
|
||||
hash.c \
|
||||
lex.c \
|
||||
lib.c \
|
||||
mathlib.c \
|
||||
iolib.c \
|
||||
iolib.h \
|
||||
bitslib.c \
|
||||
misc.c \
|
||||
nasal.h \
|
||||
parse.c parse.h \
|
||||
string.c \
|
||||
vector.c \
|
||||
thread-posix.c \
|
||||
thread-win32.c
|
||||
libsgnasal_a_SOURCES = bitslib.c code.c code.h codegen.c data.h gc.c \
|
||||
hash.c iolib.c iolib.h lex.c lib.c mathlib.c \
|
||||
misc.c naref.h nasal.h parse.c parse.h string.c \
|
||||
thread-posix.c thread-win32.c threadlib.c \
|
||||
utf8lib.c vector.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
// bits (i.e. an unsigned int). Using a 64 bit integer would stretch
|
||||
// that beyond what is representable in the double result, but
|
||||
// requires portability work.
|
||||
|
||||
#define BIT(s,l,n) s[l-1-((n)>>3)] & (1<<((n)&7))
|
||||
#define CLRB(s,l,n) s[l-1-((n)>>3)] &= ~(1<<((n)&7))
|
||||
#define SETB(s,l,n) s[l-1-((n)>>3)] |= 1<<((n)&7)
|
||||
#define MSK(n) (1 << (7 - ((n) & 7)))
|
||||
#define BIT(s,l,n) s[(n)>>3] & MSK(n)
|
||||
#define CLRB(s,l,n) s[(n)>>3] &= ~MSK(n)
|
||||
#define SETB(s,l,n) s[(n)>>3] |= MSK(n)
|
||||
|
||||
static unsigned int fld(naContext c, unsigned char* s,
|
||||
int slen, int bit, int flen)
|
||||
@@ -32,7 +32,7 @@ static void setfld(naContext c, unsigned char* s, int slen,
|
||||
|
||||
static naRef dofld(naContext c, int argc, naRef* args, int sign)
|
||||
{
|
||||
struct naStr* s = argc > 0 ? args[0].ref.ptr.str : 0;
|
||||
struct naStr* s = argc > 0 ? PTR(args[0]).str : 0;
|
||||
int bit = argc > 1 ? (int)naNumValue(args[1]).num : -1;
|
||||
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
|
||||
unsigned int f;
|
||||
@@ -56,7 +56,7 @@ static naRef f_fld(naContext c, naRef me, int argc, naRef* args)
|
||||
|
||||
static naRef f_setfld(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
struct naStr* s = argc > 0 ? args[0].ref.ptr.str : 0;
|
||||
struct naStr* s = argc > 0 ? PTR(args[0]).str : 0;
|
||||
int bit = argc > 1 ? (int)naNumValue(args[1]).num : -1;
|
||||
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
|
||||
naRef val = argc > 3 ? naNumValue(args[3]) : naNil();
|
||||
@@ -73,22 +73,15 @@ static naRef f_buf(naContext c, naRef me, int argc, naRef* args)
|
||||
return naStr_buf(naNewString(c), (int)len.num);
|
||||
}
|
||||
|
||||
static struct func { char* name; naCFunction func; } funcs[] = {
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "sfld", f_sfld },
|
||||
{ "fld", f_fld },
|
||||
{ "setfld", f_setfld },
|
||||
{ "buf", f_buf },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
naRef naBitsLib(naContext c)
|
||||
naRef naInit_bits(naContext c)
|
||||
{
|
||||
naRef namespace = naNewHash(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));
|
||||
naHash_set(namespace, name, naNewFunc(c, code));
|
||||
}
|
||||
return namespace;
|
||||
return naGenLib(c, funcs);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "nasal.h"
|
||||
#include "code.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Debugging stuff. ////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//#define DEBUG_NASAL
|
||||
#if !defined(DEBUG_NASAL)
|
||||
//#define INTERPRETER_DUMP
|
||||
#if !defined(INTERPRETER_DUMP)
|
||||
# define DBG(expr) /* noop */
|
||||
#else
|
||||
# define DBG(expr) expr
|
||||
@@ -17,21 +20,44 @@ void printOpDEBUG(int ip, int op);
|
||||
void printStackDEBUG(struct Context* ctx);
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
struct Globals* globals = 0;
|
||||
|
||||
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code);
|
||||
|
||||
#define ERR(c, msg) naRuntimeError((c),(msg))
|
||||
void naRuntimeError(struct Context* c, char* msg)
|
||||
{
|
||||
c->error = msg;
|
||||
void naRuntimeError(struct Context* c, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(c->error, sizeof(c->error), fmt, ap);
|
||||
va_end(ap);
|
||||
longjmp(c->jumpHandle, 1);
|
||||
}
|
||||
|
||||
void naRethrowError(naContext subc)
|
||||
{
|
||||
strncpy(subc->callParent->error, subc->error, sizeof(subc->error));
|
||||
subc->callParent->dieArg = subc->dieArg;
|
||||
longjmp(subc->callParent->jumpHandle, 1);
|
||||
}
|
||||
|
||||
#define END_PTR ((void*)1)
|
||||
#define IS_END(r) (IS_REF((r)) && PTR((r)).obj == END_PTR)
|
||||
static naRef endToken()
|
||||
{
|
||||
naRef r;
|
||||
SETPTR(r, END_PTR);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int boolify(struct Context* ctx, naRef r)
|
||||
{
|
||||
if(IS_NUM(r)) return r.num != 0;
|
||||
if(IS_NIL(r)) return 0;
|
||||
if(IS_NIL(r) || IS_END(r)) return 0;
|
||||
if(IS_STR(r)) {
|
||||
double d;
|
||||
if(naStr_len(r) == 0) return 0;
|
||||
@@ -65,7 +91,9 @@ static int checkVec(struct Context* ctx, naRef vec, naRef idx)
|
||||
{
|
||||
int i = (int)numify(ctx, idx);
|
||||
if(i < 0) i += naVec_size(vec);
|
||||
if(i < 0 || i >= naVec_size(vec)) ERR(ctx, "vector index out of bounds");
|
||||
if(i < 0 || i >= naVec_size(vec))
|
||||
naRuntimeError(ctx, "vector index %d out of bounds (size: %d)",
|
||||
i, naVec_size(vec));
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -73,7 +101,9 @@ static int checkStr(struct Context* ctx, naRef str, naRef idx)
|
||||
{
|
||||
int i = (int)numify(ctx, idx);
|
||||
if(i < 0) i += naStr_len(str);
|
||||
if(i < 0 || i >= naStr_len(str)) ERR(ctx, "string index out of bounds");
|
||||
if(i < 0 || i >= naStr_len(str))
|
||||
naRuntimeError(ctx, "string index %d out of bounds (size: %d)",
|
||||
i, naStr_len(str));
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -82,8 +112,7 @@ static naRef containerGet(struct Context* ctx, naRef box, naRef key)
|
||||
naRef result = naNil();
|
||||
if(!IS_SCALAR(key)) ERR(ctx, "container index not scalar");
|
||||
if(IS_HASH(box)) {
|
||||
if(!naHash_get(box, key, &result))
|
||||
ERR(ctx, "undefined value in container");
|
||||
naHash_get(box, key, &result);
|
||||
} else if(IS_VEC(box)) {
|
||||
result = naVec_get(box, checkVec(ctx, box, key));
|
||||
} else if(IS_STR(box)) {
|
||||
@@ -100,7 +129,7 @@ static void containerSet(struct Context* ctx, naRef box, naRef key, naRef val)
|
||||
else if(IS_HASH(box)) naHash_set(box, key, val);
|
||||
else if(IS_VEC(box)) naVec_set(box, checkVec(ctx, box, key), val);
|
||||
else if(IS_STR(box)) {
|
||||
if(box.ref.ptr.str->hashcode)
|
||||
if(PTR(box).str->hashcode)
|
||||
ERR(ctx, "cannot change immutable string");
|
||||
naStr_data(box)[checkStr(ctx, box, key)] = (char)numify(ctx, val);
|
||||
} else ERR(ctx, "insert into non-container");
|
||||
@@ -128,7 +157,8 @@ static void initContext(struct Context* c)
|
||||
c->callParent = 0;
|
||||
c->callChild = 0;
|
||||
c->dieArg = naNil();
|
||||
c->error = 0;
|
||||
c->error[0] = 0;
|
||||
c->userData = 0;
|
||||
}
|
||||
|
||||
static void initGlobals()
|
||||
@@ -191,9 +221,20 @@ struct Context* naNewContext()
|
||||
return c;
|
||||
}
|
||||
|
||||
struct Context* naSubContext(struct Context* super)
|
||||
{
|
||||
struct Context* ctx = naNewContext();
|
||||
if(super->callChild) naFreeContext(super->callChild);
|
||||
ctx->callParent = super;
|
||||
super->callChild = ctx;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void naFreeContext(struct Context* c)
|
||||
{
|
||||
c->ntemps = 0;
|
||||
if(c->callChild) naFreeContext(c->callChild);
|
||||
if(c->callParent) c->callParent->callChild = 0;
|
||||
LOCK();
|
||||
c->nextFree = globals->freeContexts;
|
||||
globals->freeContexts = c;
|
||||
@@ -212,12 +253,14 @@ void naFreeContext(struct Context* c)
|
||||
static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
|
||||
{
|
||||
int i;
|
||||
struct naCode* c = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
struct naCode* c = PTR(PTR(f->func).func->code).code;
|
||||
|
||||
// Set the argument symbols, and put any remaining args in a vector
|
||||
if(nargs < c->nArgs) ERR(ctx, "not enough arguments to function call");
|
||||
if(nargs < c->nArgs)
|
||||
naRuntimeError(ctx, "too few function args (have %d need %d)",
|
||||
nargs, c->nArgs);
|
||||
for(i=0; i<c->nArgs; i++)
|
||||
naHash_newsym(f->locals.ref.ptr.hash,
|
||||
naHash_newsym(PTR(f->locals).hash,
|
||||
&c->constants[c->argSyms[i]], &args[i]);
|
||||
args += c->nArgs;
|
||||
nargs -= c->nArgs;
|
||||
@@ -225,7 +268,7 @@ static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
|
||||
naRef val = nargs > 0 ? args[i] : c->constants[c->optArgVals[i]];
|
||||
if(IS_CODE(val))
|
||||
val = bindFunction(ctx, &ctx->fStack[ctx->fTop-2], val);
|
||||
naHash_newsym(f->locals.ref.ptr.hash, &c->constants[c->optArgSyms[i]],
|
||||
naHash_newsym(PTR(f->locals).hash, &c->constants[c->optArgSyms[i]],
|
||||
&val);
|
||||
}
|
||||
args += c->nOptArgs;
|
||||
@@ -233,12 +276,12 @@ static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
|
||||
naRef argsv = naNewVector(ctx);
|
||||
naVec_setsize(argsv, nargs > 0 ? nargs : 0);
|
||||
for(i=0; i<nargs; i++)
|
||||
argsv.ref.ptr.vec->rec->array[i] = *args++;
|
||||
naHash_newsym(f->locals.ref.ptr.hash, &c->restArgSym, &argsv);
|
||||
PTR(argsv).vec->rec->array[i] = *args++;
|
||||
naHash_newsym(PTR(f->locals).hash, &c->restArgSym, &argsv);
|
||||
}
|
||||
}
|
||||
|
||||
struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
|
||||
static struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall)
|
||||
{
|
||||
naRef *frame;
|
||||
struct Frame* f;
|
||||
@@ -249,20 +292,20 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
|
||||
if(!IS_FUNC(frame[0]))
|
||||
ERR(ctx, "function/method call invoked on uncallable object");
|
||||
|
||||
// Just do native calls right here, and don't touch the stack
|
||||
// frames; return the current one (unless it's a tail call!).
|
||||
if(frame[0].ref.ptr.func->code.ref.ptr.obj->type == T_CCODE) {
|
||||
ctx->opFrame = ctx->opTop - (nargs + 1 + mcall);
|
||||
|
||||
// Just do native calls right here
|
||||
if(PTR(PTR(frame[0]).func->code).obj->type == T_CCODE) {
|
||||
naRef obj = mcall ? frame[-1] : naNil();
|
||||
naCFunction fp = frame[0].ref.ptr.func->code.ref.ptr.ccode->fptr;
|
||||
naCFunction fp = PTR(PTR(frame[0]).func->code).ccode->fptr;
|
||||
naRef result = (*fp)(ctx, obj, nargs, frame + 1);
|
||||
ctx->opTop -= nargs + 1 + mcall;
|
||||
ctx->opTop = ctx->opFrame;
|
||||
PUSH(result);
|
||||
return &(ctx->fStack[ctx->fTop-1]);
|
||||
}
|
||||
|
||||
if(tail) ctx->fTop--;
|
||||
else if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
|
||||
|
||||
if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
|
||||
|
||||
// Note: assign nil first, otherwise the naNew() can cause a GC,
|
||||
// which will now (after fTop++) see the *old* reference as a
|
||||
// markable value!
|
||||
@@ -271,7 +314,7 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
|
||||
f->locals = naNewHash(ctx);
|
||||
f->func = frame[0];
|
||||
f->ip = 0;
|
||||
f->bp = ctx->opTop - (nargs + 1 + mcall);
|
||||
f->bp = ctx->opFrame;
|
||||
|
||||
if(mcall)
|
||||
naHash_set(f->locals, globals->meRef, frame[-1]);
|
||||
@@ -283,29 +326,35 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
|
||||
return f;
|
||||
}
|
||||
|
||||
static naRef evalAndOr(struct Context* ctx, int op, naRef ra, naRef rb)
|
||||
{
|
||||
int a = boolify(ctx, ra);
|
||||
int b = boolify(ctx, rb);
|
||||
int result;
|
||||
if(op == OP_AND) result = a && b ? 1 : 0;
|
||||
else result = a || b ? 1 : 0;
|
||||
return naNum(result);
|
||||
}
|
||||
|
||||
static naRef evalEquality(int op, naRef ra, naRef rb)
|
||||
{
|
||||
int result = naEqual(ra, rb);
|
||||
return naNum((op==OP_EQ) ? result : !result);
|
||||
}
|
||||
|
||||
static naRef evalCat(naContext ctx, naRef l, naRef r)
|
||||
{
|
||||
if(IS_VEC(l) && IS_VEC(r)) {
|
||||
int i, ls = naVec_size(l), rs = naVec_size(r);
|
||||
naRef v = naNewVector(ctx);
|
||||
naVec_setsize(v, ls + rs);
|
||||
for(i=0; i<ls; i+=1) naVec_set(v, i, naVec_get(l, i));
|
||||
for(i=0; i<rs; i+=1) naVec_set(v, i+ls, naVec_get(r, i));
|
||||
return v;
|
||||
} else {
|
||||
naRef a = stringify(ctx, l);
|
||||
naRef b = stringify(ctx, r);
|
||||
return naStr_concat(naNewString(ctx), a, b);
|
||||
}
|
||||
}
|
||||
|
||||
// When a code object comes out of the constant pool and shows up on
|
||||
// the stack, it needs to be bound with the lexical context.
|
||||
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code)
|
||||
{
|
||||
naRef result = naNewFunc(ctx, code);
|
||||
result.ref.ptr.func->namespace = f->locals;
|
||||
result.ref.ptr.func->next = f->func;
|
||||
PTR(result).func->namespace = f->locals;
|
||||
PTR(result).func->next = f->func;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -313,7 +362,7 @@ static int getClosure(struct naFunc* c, naRef sym, naRef* result)
|
||||
{
|
||||
while(c) {
|
||||
if(naHash_get(c->namespace, sym, result)) return 1;
|
||||
c = c->next.ref.ptr.func;
|
||||
c = PTR(c->next).func;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -322,8 +371,8 @@ static naRef getLocal2(struct Context* ctx, struct Frame* f, naRef sym)
|
||||
{
|
||||
naRef result;
|
||||
if(!naHash_get(f->locals, sym, &result))
|
||||
if(!getClosure(f->func.ref.ptr.func, sym, &result))
|
||||
ERR(ctx, "undefined symbol");
|
||||
if(!getClosure(PTR(f->func).func, sym, &result))
|
||||
naRuntimeError(ctx, "undefined symbol: %s", naStr_data(sym));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -331,14 +380,14 @@ static void getLocal(struct Context* ctx, struct Frame* f,
|
||||
naRef* sym, naRef* out)
|
||||
{
|
||||
struct naFunc* func;
|
||||
struct naStr* str = sym->ref.ptr.str;
|
||||
if(naHash_sym(f->locals.ref.ptr.hash, str, out))
|
||||
struct naStr* str = PTR(*sym).str;
|
||||
if(naHash_sym(PTR(f->locals).hash, str, out))
|
||||
return;
|
||||
func = f->func.ref.ptr.func;
|
||||
while(func && func->namespace.ref.ptr.hash) {
|
||||
if(naHash_sym(func->namespace.ref.ptr.hash, str, out))
|
||||
func = PTR(f->func).func;
|
||||
while(func && PTR(func->namespace).hash) {
|
||||
if(naHash_sym(PTR(func->namespace).hash, str, out))
|
||||
return;
|
||||
func = func->next.ref.ptr.func;
|
||||
func = PTR(func->next).func;
|
||||
}
|
||||
// Now do it again using the more general naHash_get(). This will
|
||||
// only be necessary if something has created the value in the
|
||||
@@ -349,7 +398,7 @@ static void getLocal(struct Context* ctx, struct Frame* f,
|
||||
|
||||
static int setClosure(naRef func, naRef sym, naRef val)
|
||||
{
|
||||
struct naFunc* c = func.ref.ptr.func;
|
||||
struct naFunc* c = PTR(func).func;
|
||||
if(c == 0) { return 0; }
|
||||
else if(naHash_tryset(c->namespace, sym, val)) { return 1; }
|
||||
else { return setClosure(c->next, sym, val); }
|
||||
@@ -365,28 +414,42 @@ static naRef setSymbol(struct Frame* f, naRef sym, naRef val)
|
||||
return val;
|
||||
}
|
||||
|
||||
// Recursively descend into the parents lists
|
||||
static int getMember(struct Context* ctx, naRef obj, naRef fld,
|
||||
naRef* result, int count)
|
||||
// Funky API: returns null to indicate no member, an empty string to
|
||||
// indicate success, or a non-empty error message. Works this way so
|
||||
// we can generate smart error messages without throwing them with a
|
||||
// longjmp -- this gets called under naMember_get() from C code.
|
||||
static const char* getMember_r(naRef obj, naRef field, naRef* out, int count)
|
||||
{
|
||||
int i;
|
||||
naRef p;
|
||||
if(--count < 0) ERR(ctx, "too many parents");
|
||||
if(!IS_HASH(obj)) ERR(ctx, "non-objects have no members");
|
||||
if(naHash_get(obj, fld, result)) {
|
||||
return 1;
|
||||
} else if(naHash_get(obj, globals->parentsRef, &p)) {
|
||||
if(IS_VEC(p)) {
|
||||
int i;
|
||||
struct VecRec* v = p.ref.ptr.vec->rec;
|
||||
for(i=0; i<v->size; i++)
|
||||
if(getMember(ctx, v->array[i], fld, result, count))
|
||||
return 1;
|
||||
} else
|
||||
ERR(ctx, "parents field not vector");
|
||||
struct VecRec* pv;
|
||||
if(--count < 0) return "too many parents";
|
||||
if(!IS_HASH(obj)) return 0;
|
||||
if(naHash_get(obj, field, out)) return "";
|
||||
if(!naHash_get(obj, globals->parentsRef, &p)) return 0;
|
||||
if(!IS_VEC(p)) return "object \"parents\" field not vector";
|
||||
pv = PTR(p).vec->rec;
|
||||
for(i=0; i<pv->size; i++) {
|
||||
const char* err = getMember_r(pv->array[i], field, out, count);
|
||||
if(err) return err; /* either an error or success */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void getMember(struct Context* ctx, naRef obj, naRef fld,
|
||||
naRef* result, int count)
|
||||
{
|
||||
const char* err = getMember_r(obj, fld, result, count);
|
||||
if(!err) naRuntimeError(ctx, "No such member: %s", naStr_data(fld));
|
||||
if(err[0]) naRuntimeError(ctx, err);
|
||||
}
|
||||
|
||||
int naMember_get(naRef obj, naRef field, naRef* out)
|
||||
{
|
||||
const char* err = getMember_r(obj, field, out, 64);
|
||||
return err && !err[0];
|
||||
}
|
||||
|
||||
// OP_EACH works like a vector get, except that it leaves the vector
|
||||
// and index on the stack, increments the index after use, and
|
||||
// pushes a nil if the index is beyond the end.
|
||||
@@ -394,9 +457,9 @@ static void evalEach(struct Context* ctx, int useIndex)
|
||||
{
|
||||
int idx = (int)(ctx->opStack[ctx->opTop-1].num);
|
||||
naRef vec = ctx->opStack[ctx->opTop-2];
|
||||
if(!IS_VEC(vec)) naRuntimeError(ctx, "foreach enumeration of non-vector");
|
||||
if(!vec.ref.ptr.vec->rec || idx >= vec.ref.ptr.vec->rec->size) {
|
||||
PUSH(naNil());
|
||||
if(!IS_VEC(vec)) ERR(ctx, "foreach enumeration of non-vector");
|
||||
if(!PTR(vec).vec->rec || idx >= PTR(vec).vec->rec->size) {
|
||||
PUSH(endToken());
|
||||
return;
|
||||
}
|
||||
ctx->opStack[ctx->opTop-1].num = idx+1; // modify in place
|
||||
@@ -408,13 +471,16 @@ static void evalEach(struct Context* ctx, int useIndex)
|
||||
#define POP() ctx->opStack[--ctx->opTop]
|
||||
#define STK(n) (ctx->opStack[ctx->opTop-(n)])
|
||||
#define FIXFRAME() f = &(ctx->fStack[ctx->fTop-1]); \
|
||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
cd = PTR(PTR(f->func).func->code).code;
|
||||
static naRef run(struct Context* ctx)
|
||||
{
|
||||
struct Frame* f;
|
||||
struct naCode* cd;
|
||||
int op, arg;
|
||||
naRef a, b, c;
|
||||
naRef a, b;
|
||||
|
||||
ctx->dieArg = naNil();
|
||||
ctx->error[0] = 0;
|
||||
|
||||
FIXFRAME();
|
||||
|
||||
@@ -440,8 +506,7 @@ static naRef run(struct Context* ctx)
|
||||
#define BINOP(expr) do { \
|
||||
double l = IS_NUM(STK(2)) ? STK(2).num : numify(ctx, STK(2)); \
|
||||
double r = IS_NUM(STK(1)) ? STK(1).num : numify(ctx, STK(1)); \
|
||||
STK(2).ref.reftag = ~NASAL_REFTAG; \
|
||||
STK(2).num = expr; \
|
||||
SETNUM(STK(2), expr); \
|
||||
ctx->opTop--; } while(0)
|
||||
|
||||
case OP_PLUS: BINOP(l + r); break;
|
||||
@@ -452,24 +517,15 @@ static naRef run(struct Context* ctx)
|
||||
case OP_LTE: BINOP(l <= r ? 1 : 0); break;
|
||||
case OP_GT: BINOP(l > r ? 1 : 0); break;
|
||||
case OP_GTE: BINOP(l >= r ? 1 : 0); break;
|
||||
|
||||
#undef BINOP
|
||||
|
||||
case OP_EQ: case OP_NEQ:
|
||||
STK(2) = evalEquality(op, STK(2), STK(1));
|
||||
ctx->opTop--;
|
||||
break;
|
||||
case OP_AND: case OP_OR:
|
||||
STK(2) = evalAndOr(ctx, op, STK(2), STK(1));
|
||||
ctx->opTop--;
|
||||
break;
|
||||
case OP_CAT:
|
||||
// stringify can call the GC, so don't take stuff of the stack!
|
||||
a = stringify(ctx, ctx->opStack[ctx->opTop-1]);
|
||||
b = stringify(ctx, ctx->opStack[ctx->opTop-2]);
|
||||
c = naStr_concat(naNewString(ctx), b, a);
|
||||
ctx->opTop -= 2;
|
||||
PUSH(c);
|
||||
STK(2) = evalCat(ctx, STK(2), STK(1));
|
||||
ctx->opTop -= 1;
|
||||
break;
|
||||
case OP_NEG:
|
||||
STK(1) = naNum(-numify(ctx, STK(1)));
|
||||
@@ -491,6 +547,9 @@ static naRef run(struct Context* ctx)
|
||||
case OP_PUSHNIL:
|
||||
PUSH(naNil());
|
||||
break;
|
||||
case OP_PUSHEND:
|
||||
PUSH(endToken());
|
||||
break;
|
||||
case OP_NEWVEC:
|
||||
PUSH(naNewVector(ctx));
|
||||
break;
|
||||
@@ -520,8 +579,7 @@ static naRef run(struct Context* ctx)
|
||||
ctx->opTop--;
|
||||
break;
|
||||
case OP_MEMBER:
|
||||
if(!getMember(ctx, STK(1), CONSTARG(), &STK(1), 64))
|
||||
ERR(ctx, "no such member");
|
||||
getMember(ctx, STK(1), CONSTARG(), &STK(1), 64);
|
||||
break;
|
||||
case OP_SETMEMBER:
|
||||
if(!IS_HASH(STK(3))) ERR(ctx, "non-objects have no members");
|
||||
@@ -548,15 +606,29 @@ static naRef run(struct Context* ctx)
|
||||
f->ip = cd->byteCode[f->ip];
|
||||
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
||||
break;
|
||||
case OP_JIFNIL:
|
||||
case OP_JIFEND:
|
||||
arg = ARG();
|
||||
if(IS_NIL(STK(1))) {
|
||||
if(IS_END(STK(1))) {
|
||||
ctx->opTop--; // Pops **ONLY** if it's nil!
|
||||
f->ip = arg;
|
||||
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
||||
}
|
||||
break;
|
||||
case OP_JIFTRUE:
|
||||
arg = ARG();
|
||||
if(boolify(ctx, STK(1))) {
|
||||
f->ip = arg;
|
||||
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
||||
}
|
||||
break;
|
||||
case OP_JIFNOT:
|
||||
arg = ARG();
|
||||
if(!boolify(ctx, STK(1))) {
|
||||
f->ip = arg;
|
||||
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
||||
}
|
||||
break;
|
||||
case OP_JIFNOTPOP:
|
||||
arg = ARG();
|
||||
if(!boolify(ctx, POP())) {
|
||||
f->ip = arg;
|
||||
@@ -564,23 +636,17 @@ static naRef run(struct Context* ctx)
|
||||
}
|
||||
break;
|
||||
case OP_FCALL:
|
||||
f = setupFuncall(ctx, ARG(), 0, 0);
|
||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
break;
|
||||
case OP_FTAIL:
|
||||
f = setupFuncall(ctx, ARG(), 0, 1);
|
||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
f = setupFuncall(ctx, ARG(), 0);
|
||||
cd = PTR(PTR(f->func).func->code).code;
|
||||
break;
|
||||
case OP_MCALL:
|
||||
f = setupFuncall(ctx, ARG(), 1, 0);
|
||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
break;
|
||||
case OP_MTAIL:
|
||||
f = setupFuncall(ctx, ARG(), 1, 1);
|
||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
f = setupFuncall(ctx, ARG(), 1);
|
||||
cd = PTR(PTR(f->func).func->code).code;
|
||||
break;
|
||||
case OP_RETURN:
|
||||
a = STK(1);
|
||||
ctx->dieArg = naNil();
|
||||
if(ctx->callChild) naFreeContext(ctx->callChild);
|
||||
if(--ctx->fTop <= 0) return a;
|
||||
ctx->opTop = f->bp + 1; // restore the correct opstack frame!
|
||||
STK(1) = a;
|
||||
@@ -594,7 +660,7 @@ static naRef run(struct Context* ctx)
|
||||
break;
|
||||
case OP_MARK: // save stack state (e.g. "setjmp")
|
||||
if(ctx->markTop >= MAX_MARK_DEPTH)
|
||||
naRuntimeError(ctx, "mark stack overflow");
|
||||
ERR(ctx, "mark stack overflow");
|
||||
ctx->markStack[ctx->markTop++] = ctx->opTop;
|
||||
break;
|
||||
case OP_UNMARK: // pop stack state set by mark
|
||||
@@ -624,48 +690,55 @@ void naSave(struct Context* ctx, naRef obj)
|
||||
naVec_append(globals->save, obj);
|
||||
}
|
||||
|
||||
// FIXME: handle ctx->callParent
|
||||
int naStackDepth(struct Context* ctx)
|
||||
{
|
||||
return ctx->fTop;
|
||||
return ctx ? ctx->fTop + naStackDepth(ctx->callChild): 0;
|
||||
}
|
||||
|
||||
static int findFrame(naContext ctx, naContext* out, int fn)
|
||||
{
|
||||
int sd = naStackDepth(ctx->callChild);
|
||||
if(fn < sd) return findFrame(ctx->callChild, out, fn);
|
||||
*out = ctx;
|
||||
return ctx->fTop - 1 - (fn - sd);
|
||||
}
|
||||
|
||||
// FIXME: handle ctx->callParent
|
||||
int naGetLine(struct Context* ctx, int frame)
|
||||
{
|
||||
struct Frame* f = &ctx->fStack[ctx->fTop-1-frame];
|
||||
naRef func = f->func;
|
||||
int ip = f->ip;
|
||||
if(IS_FUNC(func) && IS_CODE(func.ref.ptr.func->code)) {
|
||||
struct naCode* c = func.ref.ptr.func->code.ref.ptr.code;
|
||||
struct Frame* f;
|
||||
frame = findFrame(ctx, &ctx, frame);
|
||||
f = &ctx->fStack[frame];
|
||||
if(IS_FUNC(f->func) && IS_CODE(PTR(f->func).func->code)) {
|
||||
struct naCode* c = PTR(PTR(f->func).func->code).code;
|
||||
unsigned short* p = c->lineIps + c->nLines - 2;
|
||||
while(p >= c->lineIps && p[0] > ip)
|
||||
while(p >= c->lineIps && p[0] > f->ip)
|
||||
p -= 2;
|
||||
return p[1];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// FIXME: handle ctx->callParent
|
||||
naRef naGetSourceFile(struct Context* ctx, int frame)
|
||||
{
|
||||
naRef f = ctx->fStack[ctx->fTop-1-frame].func;
|
||||
f = f.ref.ptr.func->code;
|
||||
return f.ref.ptr.code->srcFile;
|
||||
naRef f;
|
||||
frame = findFrame(ctx, &ctx, frame);
|
||||
f = ctx->fStack[frame].func;
|
||||
f = PTR(f).func->code;
|
||||
return PTR(f).code->srcFile;
|
||||
}
|
||||
|
||||
char* naGetError(struct Context* ctx)
|
||||
{
|
||||
if(IS_STR(ctx->dieArg))
|
||||
return (char*)ctx->dieArg.ref.ptr.str->data;
|
||||
return ctx->error;
|
||||
return (char*)PTR(ctx->dieArg).str->data;
|
||||
return ctx->error[0] ? ctx->error : 0;
|
||||
}
|
||||
|
||||
naRef naBindFunction(naContext ctx, naRef code, naRef closure)
|
||||
{
|
||||
naRef func = naNewFunc(ctx, code);
|
||||
func.ref.ptr.func->namespace = closure;
|
||||
func.ref.ptr.func->next = naNil();
|
||||
PTR(func).func->namespace = closure;
|
||||
PTR(func).func->next = naNil();
|
||||
return func;
|
||||
}
|
||||
|
||||
@@ -673,8 +746,8 @@ naRef naBindToContext(naContext ctx, naRef code)
|
||||
{
|
||||
naRef func = naNewFunc(ctx, code);
|
||||
struct Frame* f = &ctx->fStack[ctx->fTop-1];
|
||||
func.ref.ptr.func->namespace = f->locals;
|
||||
func.ref.ptr.func->next = f->func;
|
||||
PTR(func).func->namespace = f->locals;
|
||||
PTR(func).func->next = f->func;
|
||||
return func;
|
||||
}
|
||||
|
||||
@@ -683,7 +756,7 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
|
||||
{
|
||||
int i;
|
||||
naRef result;
|
||||
if(!ctx->callParent) naModLock(ctx);
|
||||
if(!ctx->callParent) naModLock();
|
||||
|
||||
// We might have to allocate objects, which can call the GC. But
|
||||
// the call isn't on the Nasal stack yet, so the GC won't find our
|
||||
@@ -694,22 +767,28 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
|
||||
naTempSave(ctx, obj);
|
||||
naTempSave(ctx, locals);
|
||||
|
||||
if(IS_CCODE(func.ref.ptr.func->code)) {
|
||||
naCFunction fp = func.ref.ptr.func->code.ref.ptr.ccode->fptr;
|
||||
result = (*fp)(ctx, obj, argc, args);
|
||||
// naRuntimeError() calls end up here:
|
||||
if(setjmp(ctx->jumpHandle)) {
|
||||
if(!ctx->callParent) naModUnlock(ctx);
|
||||
return naNil();
|
||||
}
|
||||
|
||||
if(IS_CCODE(PTR(func).func->code)) {
|
||||
naCFunction fp = PTR(PTR(func).func->code).ccode->fptr;
|
||||
result = (*fp)(ctx, obj, argc, args);
|
||||
if(!ctx->callParent) naModUnlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
if(IS_NIL(locals))
|
||||
locals = naNewHash(ctx);
|
||||
if(!IS_FUNC(func))
|
||||
func = naNewFunc(ctx, func); // bind bare code objects
|
||||
if(!IS_FUNC(func)) {
|
||||
func = naNewFunc(ctx, func);
|
||||
PTR(func).func->namespace = locals;
|
||||
}
|
||||
if(!IS_NIL(obj))
|
||||
naHash_set(locals, globals->meRef, obj);
|
||||
|
||||
ctx->dieArg = naNil();
|
||||
|
||||
ctx->opTop = ctx->markTop = 0;
|
||||
ctx->fTop = 1;
|
||||
ctx->fStack[0].func = func;
|
||||
@@ -717,18 +796,42 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
|
||||
ctx->fStack[0].ip = 0;
|
||||
ctx->fStack[0].bp = ctx->opTop;
|
||||
|
||||
setupArgs(ctx, ctx->fStack, args, argc);
|
||||
|
||||
// Return early if an error occurred. It will be visible to the
|
||||
// caller via naGetError().
|
||||
ctx->error = 0;
|
||||
if(setjmp(ctx->jumpHandle)) {
|
||||
if(!ctx->callParent) naModUnlock(ctx);
|
||||
return naNil();
|
||||
}
|
||||
if(args) setupArgs(ctx, ctx->fStack, args, argc);
|
||||
|
||||
result = run(ctx);
|
||||
if(!ctx->callParent) naModUnlock(ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
naRef naContinue(naContext ctx)
|
||||
{
|
||||
naRef result;
|
||||
if(!ctx->callParent) naModLock();
|
||||
|
||||
ctx->dieArg = naNil();
|
||||
ctx->error[0] = 0;
|
||||
|
||||
if(setjmp(ctx->jumpHandle)) {
|
||||
if(!ctx->callParent) naModUnlock(ctx);
|
||||
else naRethrowError(ctx);
|
||||
return naNil();
|
||||
}
|
||||
|
||||
// Wipe off the old function arguments, and push the expected
|
||||
// result (either the result of our subcontext, or a synthesized
|
||||
// nil if the thrown error was from an extension function or
|
||||
// in-script die() call) before re-running the code from the
|
||||
// instruction following the error.
|
||||
ctx->opTop = ctx->opFrame;
|
||||
PUSH(ctx->callChild ? naContinue(ctx->callChild) : naNil());
|
||||
|
||||
// Getting here means the child completed successfully. But
|
||||
// because its original C stack was longjmp'd out of existence,
|
||||
// there is no one left to free the context, so we have to do it.
|
||||
// This is fragile, but unfortunately required.
|
||||
if(ctx->callChild) naFreeContext(ctx->callChild);
|
||||
|
||||
result = run(ctx);
|
||||
if(!ctx->callParent) naModUnlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -10,19 +10,23 @@
|
||||
#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
|
||||
// The idea is that contexts can "cache" allocations to prevent thread
|
||||
// contention on the global pools. But in practice this interacts
|
||||
// very badly with small subcontext calls, which grab huge numbers of
|
||||
// cached objects and don't use them, causing far more collections
|
||||
// than necessary. Just leave it at 1 pending a rework of the
|
||||
// collector synchronization.
|
||||
#define OBJ_CACHE_SZ 1
|
||||
|
||||
enum {
|
||||
OP_AND, OP_OR, OP_NOT, OP_MUL, OP_PLUS, OP_MINUS, OP_DIV, OP_NEG,
|
||||
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_JMPLOOP, OP_JIFNOT, OP_JIFNIL, OP_FCALL, OP_MCALL, OP_RETURN,
|
||||
OP_PUSHCONST, OP_PUSHONE, OP_PUSHZERO, OP_PUSHNIL, OP_POP,
|
||||
OP_JMP, OP_JMPLOOP, OP_JIFNOTPOP, OP_JIFEND, 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_MARK, OP_UNMARK, OP_BREAK, OP_FTAIL, OP_MTAIL, OP_SETSYM, OP_DUP2,
|
||||
OP_INDEX, OP_BREAK2
|
||||
OP_MARK, OP_UNMARK, OP_BREAK, OP_SETSYM, OP_DUP2, OP_INDEX, OP_BREAK2,
|
||||
OP_PUSHEND, OP_JIFTRUE, OP_JIFNOT
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
@@ -69,6 +73,7 @@ struct Context {
|
||||
struct Frame fStack[MAX_RECURSION];
|
||||
int fTop;
|
||||
naRef opStack[MAX_STACK_DEPTH];
|
||||
int opFrame; // like Frame::bp, but for C functions
|
||||
int opTop;
|
||||
int markStack[MAX_MARK_DEPTH];
|
||||
int markTop;
|
||||
@@ -86,7 +91,7 @@ struct Context {
|
||||
|
||||
// Error handling
|
||||
jmp_buf jumpHandle;
|
||||
char* error;
|
||||
char error[128];
|
||||
naRef dieArg;
|
||||
|
||||
// Sub-call lists
|
||||
@@ -96,6 +101,8 @@ struct Context {
|
||||
// Linked list pointers in globals
|
||||
struct Context* nextFree;
|
||||
struct Context* nextAll;
|
||||
|
||||
void* userData;
|
||||
};
|
||||
|
||||
#define globals nasal_globals
|
||||
@@ -103,11 +110,13 @@ extern struct Globals* globals;
|
||||
|
||||
// Threading low-level functions
|
||||
void* naNewLock();
|
||||
void naFreeLock(void* lock);
|
||||
void naLock(void* lock);
|
||||
void naUnlock(void* lock);
|
||||
void* naNewSem();
|
||||
void naFreeSem(void* sem);
|
||||
void naSemDown(void* sem);
|
||||
void naSemUpAll(void* sem, int count);
|
||||
void naSemUp(void* sem, int count);
|
||||
|
||||
void naCheckBottleneck();
|
||||
|
||||
|
||||
@@ -91,41 +91,6 @@ static int findConstantIndex(struct Parser* p, struct Token* t)
|
||||
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
|
||||
@@ -145,7 +110,7 @@ static int genScalarConstant(struct Parser* p, struct Token* t)
|
||||
|
||||
static int genLValue(struct Parser* p, struct Token* t, int* cidx)
|
||||
{
|
||||
if(t->type == TOK_LPAR) {
|
||||
if(t->type == TOK_LPAR && t->rule != PREC_SUFFIX) {
|
||||
return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1"
|
||||
} else if(t->type == TOK_SYMBOL) {
|
||||
*cidx = genScalarConstant(p, t);
|
||||
@@ -187,6 +152,15 @@ static void genEqOp(int op, struct Parser* p, struct Token* t)
|
||||
static int defArg(struct Parser* p, struct Token* t)
|
||||
{
|
||||
if(t->type == TOK_LPAR) return defArg(p, RIGHT(t));
|
||||
if(t->type == TOK_MINUS && RIGHT(t) &&
|
||||
RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
|
||||
{
|
||||
/* default arguments are constants, but "-1" parses as two
|
||||
* tokens, so we have to subset the expression generator for that
|
||||
* case */
|
||||
RIGHT(t)->num *= -1;
|
||||
return defArg(p, RIGHT(t));
|
||||
}
|
||||
return findConstantIndex(p, t);
|
||||
}
|
||||
|
||||
@@ -293,8 +267,6 @@ static void genFuncall(struct Parser* p, struct Token* t)
|
||||
genExpr(p, LEFT(t));
|
||||
}
|
||||
if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0);
|
||||
if(tailContext(t))
|
||||
op = op == OP_FCALL ? OP_FTAIL : OP_MTAIL;
|
||||
emitImmediate(p, op, nargs);
|
||||
}
|
||||
|
||||
@@ -334,15 +306,12 @@ static void fixJumpTarget(struct Parser* p, int spot)
|
||||
|
||||
static void genShortCircuit(struct Parser* p, struct Token* t)
|
||||
{
|
||||
int jumpNext, jumpEnd, isAnd = (t->type == TOK_AND);
|
||||
int end;
|
||||
genExpr(p, LEFT(t));
|
||||
if(isAnd) emit(p, OP_NOT);
|
||||
jumpNext = emitJump(p, OP_JIFNOT);
|
||||
emit(p, isAnd ? OP_PUSHNIL : OP_PUSHONE);
|
||||
jumpEnd = emitJump(p, OP_JMP);
|
||||
fixJumpTarget(p, jumpNext);
|
||||
end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE);
|
||||
emit(p, OP_POP);
|
||||
genExpr(p, RIGHT(t));
|
||||
fixJumpTarget(p, jumpEnd);
|
||||
fixJumpTarget(p, end);
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +319,7 @@ static void genIf(struct Parser* p, struct Token* tif, struct Token* telse)
|
||||
{
|
||||
int jumpNext, jumpEnd;
|
||||
genExpr(p, tif->children); // the test
|
||||
jumpNext = emitJump(p, OP_JIFNOT);
|
||||
jumpNext = emitJump(p, OP_JIFNOTPOP);
|
||||
genExprList(p, tif->children->next->children); // the body
|
||||
jumpEnd = emitJump(p, OP_JMP);
|
||||
fixJumpTarget(p, jumpNext);
|
||||
@@ -374,7 +343,7 @@ static void genQuestion(struct Parser* p, struct Token* t)
|
||||
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);
|
||||
jumpNext = emitJump(p, OP_JIFNOTPOP);
|
||||
genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
|
||||
jumpEnd = emitJump(p, OP_JMP);
|
||||
fixJumpTarget(p, jumpNext);
|
||||
@@ -420,7 +389,7 @@ static void genForWhile(struct Parser* p, struct Token* init,
|
||||
pushLoop(p, label);
|
||||
loopTop = p->cg->codesz;
|
||||
genExpr(p, test);
|
||||
jumpEnd = emitJump(p, OP_JIFNOT);
|
||||
jumpEnd = emitJump(p, OP_JIFNOTPOP);
|
||||
genLoop(p, body, update, label, loopTop, jumpEnd);
|
||||
}
|
||||
|
||||
@@ -485,7 +454,7 @@ static void genForEach(struct Parser* p, struct Token* t)
|
||||
pushLoop(p, label);
|
||||
loopTop = p->cg->codesz;
|
||||
emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
|
||||
jumpEnd = emitJump(p, OP_JIFNIL);
|
||||
jumpEnd = emitJump(p, OP_JIFEND);
|
||||
assignOp = genLValue(p, elem, &dummy);
|
||||
emit(p, OP_XCHG);
|
||||
emit(p, assignOp);
|
||||
@@ -522,7 +491,7 @@ static void genBreakContinue(struct Parser* p, struct Token* t)
|
||||
for(i=0; i<levels; i++)
|
||||
emit(p, (i<levels-1) ? OP_BREAK2 : OP_BREAK);
|
||||
if(t->type == TOK_BREAK)
|
||||
emit(p, OP_PUSHNIL); // breakIP is always a JIFNOT/JIFNIL!
|
||||
emit(p, OP_PUSHEND); // breakIP is always a JIFNOTPOP/JIFEND!
|
||||
emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp);
|
||||
}
|
||||
|
||||
@@ -544,6 +513,8 @@ static void newLineEntry(struct Parser* p, int line)
|
||||
static void genExpr(struct Parser* p, struct Token* t)
|
||||
{
|
||||
int i, dummy;
|
||||
if(!t) naParseError(p, "parse error", -1); // throw line -1...
|
||||
p->errLine = t->line; // ...to use this one instead
|
||||
if(t->line != p->cg->lastLine)
|
||||
newLineEntry(p, t->line);
|
||||
p->cg->lastLine = t->line;
|
||||
@@ -613,7 +584,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
case TOK_MINUS:
|
||||
if(BINARY(t)) {
|
||||
genBinOp(OP_MINUS, p, t); // binary subtraction
|
||||
} else if(RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
|
||||
} else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
|
||||
RIGHT(t)->num *= -1; // Pre-negate constants
|
||||
genScalarConstant(p, RIGHT(t));
|
||||
} else {
|
||||
@@ -627,7 +598,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
break;
|
||||
case TOK_DOT:
|
||||
genExpr(p, LEFT(t));
|
||||
if(RIGHT(t)->type != TOK_SYMBOL)
|
||||
if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
|
||||
naParseError(p, "object field not symbol", RIGHT(t)->line);
|
||||
emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
|
||||
break;
|
||||
@@ -658,7 +629,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
|
||||
static void genExprList(struct Parser* p, struct Token* t)
|
||||
{
|
||||
if(t->type == TOK_SEMI) {
|
||||
if(t && t->type == TOK_SEMI) {
|
||||
genExpr(p, LEFT(t));
|
||||
if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
|
||||
emit(p, OP_POP);
|
||||
@@ -692,7 +663,7 @@ naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
|
||||
|
||||
// Now make a code object
|
||||
codeObj = naNewCode(p->context);
|
||||
code = codeObj.ref.ptr.code;
|
||||
code = PTR(codeObj).code;
|
||||
|
||||
// Parse the argument list, if any
|
||||
code->restArgSym = globals->argRef;
|
||||
|
||||
@@ -3,30 +3,86 @@
|
||||
|
||||
#include "nasal.h"
|
||||
|
||||
#if defined(NASAL_NAN64)
|
||||
|
||||
// On 64 bit systems, Nasal non-numeric references are stored with a
|
||||
// bitmask that sets the top 16 bits. As a double, this is a
|
||||
// signalling NaN that cannot itself be produced by normal numerics
|
||||
// code. The pointer value can be reconstructed if (and only if) we
|
||||
// are guaranteed that all memory that can be pointed to by a naRef
|
||||
// (i.e. all memory returned by naAlloc) lives in the bottom 48 bits
|
||||
// of memory. Linux on x86_64, Win64, Solaris and Irix all have such
|
||||
// policies with address spaces:
|
||||
//
|
||||
// http://msdn.microsoft.com/library/en-us/win64/win64/virtual_address_space.asp
|
||||
// http://docs.sun.com/app/docs/doc/816-5138/6mba6ua5p?a=view
|
||||
// http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi/
|
||||
// ... 0650/bks/SGI_Developer/books/T_IRIX_Prog/sgi_html/ch01.html
|
||||
//
|
||||
// In the above, MS guarantees 44 bits of process address space, SGI
|
||||
// 40, and Sun 43 (Solaris *does* place the stack in the "negative"
|
||||
// address space at 0xffff..., but we don't care as naRefs will never
|
||||
// point there). Linux doesn't document this rigorously, but testing
|
||||
// shows that it allows 47 bits of address space (and current x86_64
|
||||
// implementations are limited to 48 bits of virtual space anyway). So
|
||||
// we choose 48 as the conservative compromise.
|
||||
|
||||
#define REFMAGIC ((1UL<<48) - 1)
|
||||
|
||||
#define _ULP(r) ((unsigned long long)((r).ptr))
|
||||
#define REFPTR(r) (_ULP(r) & REFMAGIC)
|
||||
#define IS_REF(r) ((_ULP(r) & ~REFMAGIC) == ~REFMAGIC)
|
||||
|
||||
// Portability note: this cast from a pointer type to naPtr (a union)
|
||||
// is not defined in ISO C, it's a GCC extention that doesn't work on
|
||||
// (at least) either the SUNWspro or MSVC compilers. Unfortunately,
|
||||
// fixing this would require abandoning the naPtr union for a set of
|
||||
// PTR_<type>() macros, which is a ton of work and a lot of extra
|
||||
// code. And as all enabled 64 bit platforms are gcc anyway, and the
|
||||
// 32 bit fallback code works in any case, this is acceptable for now.
|
||||
#define PTR(r) ((naPtr)((struct naObj*)(_ULP(r) & REFMAGIC)))
|
||||
|
||||
#define SETPTR(r, p) ((r).ptr = (void*)((unsigned long long)p | ~REFMAGIC))
|
||||
#define SETNUM(r, n) ((r).num = n)
|
||||
|
||||
#else
|
||||
|
||||
// On 32 bit systems where the pointer is half the width of the
|
||||
// double, we store a special magic number in the structure to make
|
||||
// the double a NaN. This must appear in the top bits of the double,
|
||||
// which is why the structure layout is endianness-dependent.
|
||||
|
||||
#define NASAL_REFTAG 0x7ff56789 // == 2,146,789,257 decimal
|
||||
#define IS_REF(r) ((r).ref.reftag == NASAL_REFTAG)
|
||||
#define PTR(r) ((r).ref.ptr)
|
||||
|
||||
#define SETPTR(r, p) ((r).ref.ptr.obj = (void*)p, (r).ref.reftag = NASAL_REFTAG)
|
||||
#define SETNUM(r, n) ((r).ref.reftag = ~NASAL_REFTAG, (r).num = n)
|
||||
|
||||
#endif /* platform stuff */
|
||||
|
||||
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_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_NUM(r) (!IS_REF(r))
|
||||
#define IS_OBJ(r) (IS_REF(r) && PTR(r).obj != 0)
|
||||
#define IS_NIL(r) (IS_REF(r) && PTR(r).obj == 0)
|
||||
#define IS_STR(r) (IS_OBJ(r) && PTR(r).obj->type == T_STR)
|
||||
#define IS_VEC(r) (IS_OBJ(r) && PTR(r).obj->type == T_VEC)
|
||||
#define IS_HASH(r) (IS_OBJ(r) && PTR(r).obj->type == T_HASH)
|
||||
#define IS_CODE(r) (IS_OBJ(r) && PTR(r).obj->type == T_CODE)
|
||||
#define IS_FUNC(r) (IS_OBJ(r) && PTR(r).obj->type == T_FUNC)
|
||||
#define IS_CCODE(r) (IS_OBJ(r) && PTR(r).obj->type == T_CCODE)
|
||||
#define IS_GHOST(r) (IS_OBJ(r) && PTR(r).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 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)
|
||||
&& PTR(a).obj == PTR(b).obj)
|
||||
|
||||
#define MUTABLE(r) (IS_STR(r) && (r).ref.ptr.str->hashcode == 0)
|
||||
#define MUTABLE(r) (IS_STR(r) && PTR(r).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
|
||||
// avoid padding. GCC on x86, at least, will always pad the size of
|
||||
// an embedded struct up to 32 bits. Doing it this way allows the
|
||||
// implementing objects to pack in 16 bits worth of data "for free".
|
||||
#define GC_HEADER \
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "data.h"
|
||||
#include "code.h"
|
||||
|
||||
#define MIN_BLOCK_SIZE 256
|
||||
#define MIN_BLOCK_SIZE 32
|
||||
|
||||
static void reap(struct naPool* p);
|
||||
static void mark(naRef r);
|
||||
@@ -27,7 +27,7 @@ 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];
|
||||
SETPTR(r, c->temps[i]);
|
||||
mark(r);
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ static void bottleneck()
|
||||
if(g->waitCount >= g->nThreads - 1) {
|
||||
freeDead();
|
||||
if(g->needGC) garbageCollect();
|
||||
if(g->waitCount) naSemUpAll(g->sem, g->waitCount);
|
||||
if(g->waitCount) naSemUp(g->sem, g->waitCount);
|
||||
g->bottleneck = 0;
|
||||
}
|
||||
}
|
||||
@@ -130,7 +130,7 @@ static void naCode_gcclean(struct naCode* o)
|
||||
|
||||
static void naGhost_gcclean(struct naGhost* g)
|
||||
{
|
||||
if(g->ptr) g->gtype->destroy(g->ptr);
|
||||
if(g->ptr && g->gtype->destroy) g->gtype->destroy(g->ptr);
|
||||
g->ptr = 0;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ struct naObj** naGC_get(struct naPool* p, int n, int* nout)
|
||||
static void markvec(naRef r)
|
||||
{
|
||||
int i;
|
||||
struct VecRec* vr = r.ref.ptr.vec->rec;
|
||||
struct VecRec* vr = PTR(r).vec->rec;
|
||||
if(!vr) return;
|
||||
for(i=0; i<vr->size; i++)
|
||||
mark(vr->array[i]);
|
||||
@@ -223,7 +223,7 @@ static void markvec(naRef r)
|
||||
static void markhash(naRef r)
|
||||
{
|
||||
int i;
|
||||
struct HashRec* hr = r.ref.ptr.hash->rec;
|
||||
struct HashRec* hr = PTR(r).hash->rec;
|
||||
if(!hr) return;
|
||||
for(i=0; i < (1<<hr->lgalloced); i++) {
|
||||
struct HashNode* hn = hr->table[i];
|
||||
@@ -244,22 +244,22 @@ static void mark(naRef r)
|
||||
if(IS_NUM(r) || IS_NIL(r))
|
||||
return;
|
||||
|
||||
if(r.ref.ptr.obj->mark == 1)
|
||||
if(PTR(r).obj->mark == 1)
|
||||
return;
|
||||
|
||||
r.ref.ptr.obj->mark = 1;
|
||||
switch(r.ref.ptr.obj->type) {
|
||||
PTR(r).obj->mark = 1;
|
||||
switch(PTR(r).obj->type) {
|
||||
case T_VEC: markvec(r); break;
|
||||
case T_HASH: markhash(r); break;
|
||||
case T_CODE:
|
||||
mark(r.ref.ptr.code->srcFile);
|
||||
for(i=0; i<r.ref.ptr.code->nConstants; i++)
|
||||
mark(r.ref.ptr.code->constants[i]);
|
||||
mark(PTR(r).code->srcFile);
|
||||
for(i=0; i<PTR(r).code->nConstants; i++)
|
||||
mark(PTR(r).code->constants[i]);
|
||||
break;
|
||||
case T_FUNC:
|
||||
mark(r.ref.ptr.func->code);
|
||||
mark(r.ref.ptr.func->namespace);
|
||||
mark(r.ref.ptr.func->next);
|
||||
mark(PTR(r).func->code);
|
||||
mark(PTR(r).func->namespace);
|
||||
mark(PTR(r).func->next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -270,7 +270,6 @@ static void reap(struct naPool* p)
|
||||
{
|
||||
struct Block* b;
|
||||
int elem, freesz, total = poolsize(p);
|
||||
p->nfree = 0;
|
||||
freesz = total < MIN_BLOCK_SIZE ? MIN_BLOCK_SIZE : total;
|
||||
freesz = (3 * freesz / 2) + (globals->nThreads * OBJ_CACHE_SZ);
|
||||
if(p->freesz < freesz) {
|
||||
@@ -279,6 +278,9 @@ static void reap(struct naPool* p)
|
||||
p->free = p->free0 = naAlloc(sizeof(void*) * p->freesz);
|
||||
}
|
||||
|
||||
p->nfree = 0;
|
||||
p->free = p->free0;
|
||||
|
||||
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);
|
||||
@@ -287,6 +289,8 @@ static void reap(struct naPool* p)
|
||||
o->mark = 0;
|
||||
}
|
||||
|
||||
p->freetop = p->nfree;
|
||||
|
||||
// allocs of this type until the next collection
|
||||
globals->allocCount += total/2;
|
||||
|
||||
@@ -299,7 +303,6 @@ static void reap(struct naPool* p)
|
||||
if(need > 0)
|
||||
newBlock(p, need);
|
||||
}
|
||||
p->freetop = p->nfree;
|
||||
}
|
||||
|
||||
// Does the swap, returning the old value
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
|
||||
#define MIN_HASH_SIZE 4
|
||||
|
||||
#define EQUAL(a, b) (((a).ref.reftag == (b).ref.reftag \
|
||||
&& (a).ref.ptr.obj == (b).ref.ptr.obj) \
|
||||
|| naEqual(a, b))
|
||||
#define EQUAL(a, b) (IDENTICAL(a, b) || naEqual(a, b))
|
||||
|
||||
#define HASH_MAGIC 2654435769u
|
||||
|
||||
@@ -28,15 +26,15 @@ 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 if(PTR(r).str->hashcode) {
|
||||
return PTR(r).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;
|
||||
for(i=0; i<PTR(r).str->len; i++)
|
||||
hash = (hash * 33) ^ PTR(r).str->data[i];
|
||||
PTR(r).str->hashcode = hash;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -90,7 +88,7 @@ int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
|
||||
int col = (HASH_MAGIC * sym->hashcode) >> (32 - h->lgalloced);
|
||||
struct HashNode* hn = h->table[col];
|
||||
while(hn) {
|
||||
if(hn->key.ref.ptr.str == sym) {
|
||||
if(PTR(hn->key).str == sym) {
|
||||
*out = hn->val;
|
||||
return 1;
|
||||
}
|
||||
@@ -103,26 +101,32 @@ int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
|
||||
static struct HashNode* find(struct naHash* hash, naRef key)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
struct HashNode* hn;
|
||||
if(!h) return 0;
|
||||
for(hn = h->table[hashcolumn(h, key)]; hn; hn = hn->next)
|
||||
if(EQUAL(key, hn->key))
|
||||
return hn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Make a temporary string on the stack
|
||||
static void tmpStr(naRef* out, struct naStr* str, char* key)
|
||||
static void tmpStr(naRef* out, struct naStr* str, const char* key)
|
||||
{
|
||||
str->len = 0;
|
||||
str->type = T_STR;
|
||||
str->data = (unsigned char*)key;
|
||||
str->hashcode = 0;
|
||||
while(key[str->len]) str->len++;
|
||||
*out = naNil();
|
||||
out->ref.ptr.str = str;
|
||||
SETPTR(*out, str);
|
||||
}
|
||||
|
||||
int naMember_cget(naRef obj, const char* field, naRef* out)
|
||||
{
|
||||
naRef key;
|
||||
struct naStr str;
|
||||
tmpStr(&key, &str, field);
|
||||
return naMember_get(obj, key, out);
|
||||
}
|
||||
|
||||
naRef naHash_cget(naRef hash, char* key)
|
||||
@@ -146,7 +150,7 @@ void naHash_cset(naRef hash, char* key, naRef val)
|
||||
int naHash_get(naRef hash, naRef key, naRef* out)
|
||||
{
|
||||
if(IS_HASH(hash)) {
|
||||
struct HashNode* n = find(hash.ref.ptr.hash, key);
|
||||
struct HashNode* n = find(PTR(hash).hash, key);
|
||||
if(n) { *out = n->val; return 1; }
|
||||
}
|
||||
return 0;
|
||||
@@ -156,7 +160,7 @@ int naHash_get(naRef hash, naRef key, naRef* out)
|
||||
int naHash_tryset(naRef hash, naRef key, naRef val)
|
||||
{
|
||||
if(IS_HASH(hash)) {
|
||||
struct HashNode* n = find(hash.ref.ptr.hash, key);
|
||||
struct HashNode* n = find(PTR(hash).hash, key);
|
||||
if(n) n->val = val;
|
||||
return n != 0;
|
||||
}
|
||||
@@ -173,7 +177,7 @@ void naHash_newsym(struct naHash* hash, naRef* sym, naRef* val)
|
||||
struct HashRec* h = hash->rec;
|
||||
while(!h || h->size >= 1<<h->lgalloced)
|
||||
h = resize(hash);
|
||||
col = (HASH_MAGIC * sym->ref.ptr.str->hashcode) >> (32 - h->lgalloced);
|
||||
col = (HASH_MAGIC * PTR(*sym).str->hashcode) >> (32 - h->lgalloced);
|
||||
INSERT(h, *sym, *val, col);
|
||||
}
|
||||
|
||||
@@ -196,10 +200,10 @@ void naHash_set(naRef hash, naRef key, naRef val)
|
||||
struct HashRec* h;
|
||||
struct HashNode* n;
|
||||
if(!IS_HASH(hash)) return;
|
||||
if((n = find(hash.ref.ptr.hash, key))) { n->val = val; return; }
|
||||
h = hash.ref.ptr.hash->rec;
|
||||
if((n = find(PTR(hash).hash, key))) { n->val = val; return; }
|
||||
h = PTR(hash).hash->rec;
|
||||
while(!h || h->size >= 1<<h->lgalloced)
|
||||
h = resize(hash.ref.ptr.hash);
|
||||
h = resize(PTR(hash).hash);
|
||||
col = hashcolumn(h, key);
|
||||
INSERT(h, key, val, hashcolumn(h, key));
|
||||
chkcycle(h->table[col], h->size - h->dels);
|
||||
@@ -207,7 +211,7 @@ void naHash_set(naRef hash, naRef key, naRef val)
|
||||
|
||||
void naHash_delete(naRef hash, naRef key)
|
||||
{
|
||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
||||
struct HashRec* h = PTR(hash).hash->rec;
|
||||
int col;
|
||||
struct HashNode *last=0, *hn;
|
||||
if(!IS_HASH(hash) || !h) return;
|
||||
@@ -228,7 +232,7 @@ void naHash_delete(naRef hash, naRef key)
|
||||
void naHash_keys(naRef dst, naRef hash)
|
||||
{
|
||||
int i;
|
||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
||||
struct HashRec* h = PTR(hash).hash->rec;
|
||||
if(!IS_HASH(hash) || !h) return;
|
||||
for(i=0; i<(1<<h->lgalloced); i++) {
|
||||
struct HashNode* hn = h->table[i];
|
||||
@@ -241,7 +245,7 @@ void naHash_keys(naRef dst, naRef hash)
|
||||
|
||||
int naHash_size(naRef hash)
|
||||
{
|
||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
||||
struct HashRec* h = PTR(hash).hash->rec;
|
||||
if(!IS_HASH(hash) || !h) return 0;
|
||||
return h->size - h->dels;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ naGhostType naIOGhostType = { ghostDestroy };
|
||||
|
||||
static struct naIOGhost* ioghost(naRef r)
|
||||
{
|
||||
if(naGhost_type(r) == &naIOGhostType)
|
||||
if(naGhost_type(r) == &naIOGhostType && IOGHOST(r)->handle)
|
||||
return naGhost_ptr(r);
|
||||
return 0;
|
||||
}
|
||||
@@ -32,9 +32,9 @@ static naRef f_read(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef len = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||
if(!g || !MUTABLE(str) || !IS_NUM(len))
|
||||
naRuntimeError(c, "bad argument to read()");
|
||||
if(str.ref.ptr.str->len < (int)len.num)
|
||||
if(PTR(str).str->len < (int)len.num)
|
||||
naRuntimeError(c, "string not big enough for read");
|
||||
return naNum(g->type->read(c, g->handle, (char*)str.ref.ptr.str->data,
|
||||
return naNum(g->type->read(c, g->handle, (char*)PTR(str).str->data,
|
||||
(int)len.num));
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ static naRef f_write(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef str = argc > 1 ? args[1] : naNil();
|
||||
if(!g || !IS_STR(str))
|
||||
naRuntimeError(c, "bad argument to write()");
|
||||
return naNum(g->type->write(c, g->handle, (char*)str.ref.ptr.str->data,
|
||||
str.ref.ptr.str->len));
|
||||
return naNum(g->type->write(c, g->handle, (char*)PTR(str).str->data,
|
||||
PTR(str).str->len));
|
||||
}
|
||||
|
||||
static naRef f_seek(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -113,7 +113,8 @@ static int iotell(naContext c, void* f)
|
||||
|
||||
static void iodestroy(void* f)
|
||||
{
|
||||
ioclose(0, f);
|
||||
if(f != stdin && f != stdout && f != stderr)
|
||||
ioclose(0, f);
|
||||
}
|
||||
|
||||
struct naIOType naStdIOType = { ioclose, ioread, iowrite, ioseek,
|
||||
@@ -133,8 +134,8 @@ static naRef f_open(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef file = argc > 0 ? naStringValue(c, args[0]) : naNil();
|
||||
naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
|
||||
if(!IS_STR(file)) naRuntimeError(c, "bad argument to open()");
|
||||
f = fopen((char*)file.ref.ptr.str->data,
|
||||
IS_STR(mode) ? (const char*)mode.ref.ptr.str->data : "r");
|
||||
f = fopen((char*)PTR(file).str->data,
|
||||
IS_STR(mode) ? (const char*)PTR(mode).str->data : "rb");
|
||||
if(!f) naRuntimeError(c, strerror(errno));
|
||||
return naIOGhost(c, f);
|
||||
}
|
||||
@@ -169,7 +170,8 @@ static naRef f_readln(naContext ctx, naRef me, int argc, naRef* args)
|
||||
if(c == '\r') {
|
||||
char c2 = getcguard(ctx, g->handle, buf);
|
||||
if(c2 != EOF && c2 != '\n')
|
||||
ungetc(c2, g->handle);
|
||||
if(EOF == ungetc(c2, g->handle))
|
||||
break;
|
||||
break;
|
||||
}
|
||||
buf[i++] = c;
|
||||
@@ -186,7 +188,7 @@ static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
|
||||
struct stat s;
|
||||
naRef result, path = argc > 0 ? naStringValue(ctx, args[0]) : naNil();
|
||||
if(!IS_STR(path)) naRuntimeError(ctx, "bad argument to stat()");
|
||||
if(stat((char*)path.ref.ptr.str->data, &s) < 0) {
|
||||
if(stat((char*)PTR(path).str->data, &s) < 0) {
|
||||
if(errno == ENOENT) return naNil();
|
||||
naRuntimeError(ctx, strerror(errno));
|
||||
}
|
||||
@@ -199,7 +201,7 @@ static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct func { char* name; naCFunction func; } funcs[] = {
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "close", f_close },
|
||||
{ "read", f_read },
|
||||
{ "write", f_write },
|
||||
@@ -208,26 +210,17 @@ static struct func { char* name; naCFunction func; } funcs[] = {
|
||||
{ "open", f_open },
|
||||
{ "readln", f_readln },
|
||||
{ "stat", f_stat },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void setsym(naContext c, naRef hash, char* sym, naRef val)
|
||||
naRef naInit_io(naContext c)
|
||||
{
|
||||
naRef name = naStr_fromdata(naNewString(c), sym, strlen(sym));
|
||||
naHash_set(hash, naInternSymbol(name), val);
|
||||
}
|
||||
|
||||
naRef naIOLib(naContext c)
|
||||
{
|
||||
naRef ns = naNewHash(c);
|
||||
int i, n = sizeof(funcs)/sizeof(struct func);
|
||||
for(i=0; i<n; i++)
|
||||
setsym(c, ns, funcs[i].name,
|
||||
naNewFunc(c, naNewCCode(c, funcs[i].func)));
|
||||
setsym(c, ns, "SEEK_SET", naNum(SEEK_SET));
|
||||
setsym(c, ns, "SEEK_CUR", naNum(SEEK_CUR));
|
||||
setsym(c, ns, "SEEK_END", naNum(SEEK_END));
|
||||
setsym(c, ns, "stdin", naIOGhost(c, stdin));
|
||||
setsym(c, ns, "stdout", naIOGhost(c, stdout));
|
||||
setsym(c, ns, "stderr", naIOGhost(c, stderr));
|
||||
naRef ns = naGenLib(c, funcs);
|
||||
naAddSym(c, ns, "SEEK_SET", naNum(SEEK_SET));
|
||||
naAddSym(c, ns, "SEEK_CUR", naNum(SEEK_CUR));
|
||||
naAddSym(c, ns, "SEEK_END", naNum(SEEK_END));
|
||||
naAddSym(c, ns, "stdin", naIOGhost(c, stdin));
|
||||
naAddSym(c, ns, "stdout", naIOGhost(c, stdout));
|
||||
naAddSym(c, ns, "stderr", naIOGhost(c, stderr));
|
||||
return ns;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,20 @@ static int lineEnd(struct Parser* p, int line)
|
||||
static void newToken(struct Parser* p, int pos, int type,
|
||||
char* str, int slen, double num)
|
||||
{
|
||||
struct Token* tok;
|
||||
struct Token *tok, *last = p->tree.lastChild;
|
||||
|
||||
/* Adjacent string literals get concatenated */
|
||||
if(type == TOK_LITERAL && str) {
|
||||
if(last && last->type == TOK_LITERAL) {
|
||||
int i, len1 = last->strlen;
|
||||
char* str2 = naParseAlloc(p, len1 + slen);
|
||||
for(i=0; i<len1; i++) str2[i] = last->str[i];
|
||||
for(i=0; i<slen; i++) str2[i+len1] = str[i];
|
||||
last->str = str2;
|
||||
last->strlen += slen;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tok = naParseAlloc(p, sizeof(struct Token));
|
||||
tok->type = type;
|
||||
@@ -119,17 +132,18 @@ static void newToken(struct Parser* p, int pos, int type,
|
||||
tok->num = num;
|
||||
tok->parent = &p->tree;
|
||||
tok->next = 0;
|
||||
tok->prev = p->tree.lastChild;
|
||||
tok->prev = last;
|
||||
tok->children = 0;
|
||||
tok->lastChild = 0;
|
||||
|
||||
// Context sensitivity hack: a "-" following a binary operator of
|
||||
// higher precedence (MUL and DIV, basically) must be a unary
|
||||
// negation. Needed to get precedence right in the parser for
|
||||
// expressiong like "a * -2"
|
||||
if(type == TOK_MINUS && tok->prev)
|
||||
if(tok->prev->type == TOK_MUL || tok->prev->type == TOK_DIV)
|
||||
// equal or higher precedence must be a unary negation. Needed to
|
||||
// get precedence right in the parser for expressiong like "a * -2"
|
||||
if(type == TOK_MINUS && tok->prev) {
|
||||
int pt = tok->prev->type;
|
||||
if(pt==TOK_PLUS||pt==TOK_MINUS||pt==TOK_CAT||pt==TOK_MUL||pt==TOK_DIV)
|
||||
tok->type = type = TOK_NEG;
|
||||
}
|
||||
|
||||
if(!p->tree.children) p->tree.children = tok;
|
||||
if(p->tree.lastChild) p->tree.lastChild->next = tok;
|
||||
@@ -179,6 +193,7 @@ static void dqEscape(char* buf, int len, int index, struct Parser* p,
|
||||
case 'n': *cOut = '\n'; break;
|
||||
case 't': *cOut = '\t'; break;
|
||||
case '\\': *cOut = '\\'; break;
|
||||
case '`': *cOut = '`'; break;
|
||||
case 'x':
|
||||
if(len < 4) error(p, "unterminated string", index);
|
||||
*cOut = (char)((hexc(buf[2], p, index)<<4) | hexc(buf[3], p, index));
|
||||
@@ -191,11 +206,12 @@ 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);
|
||||
int n, c;
|
||||
c = naLexUtf8C(s, len, &n);
|
||||
if(c < 0 || n != len) error(p, "invalid utf8 character constant", index);
|
||||
newToken(p, index, TOK_LITERAL, 0, 0, c);
|
||||
}
|
||||
|
||||
// Read in a string literal
|
||||
@@ -317,6 +333,7 @@ static int tryLexemes(struct Parser* p, int index, int* lexemeOut)
|
||||
return best;
|
||||
}
|
||||
|
||||
#define ISNUM(c) ((c) >= '0' && (c) <= '9')
|
||||
void naLex(struct Parser* p)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -338,7 +355,8 @@ void naLex(struct Parser* p)
|
||||
i = lexStringLiteral(p, i, c);
|
||||
break;
|
||||
default:
|
||||
if(c >= '0' && c <= '9') i = lexNumLiteral(p, i);
|
||||
if(ISNUM(c) || (c == '.' && (i+1)<p->len && ISNUM(p->buf[i+1])))
|
||||
i = lexNumLiteral(p, i);
|
||||
else handled = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER // sigh...
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
@@ -14,9 +15,14 @@
|
||||
#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 me, int argc, naRef* args)
|
||||
// Generic argument error, assumes that the symbol "c" is a naContext,
|
||||
// and that the __FUNCTION__ string is of the form "f_NASALSYMBOL".
|
||||
#define ARGERR() \
|
||||
naRuntimeError(c, "bad/missing argument to %s()", (__FUNCTION__ + 2))
|
||||
|
||||
static naRef f_size(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc == 0) return naNil();
|
||||
if(argc == 0) ARGERR();
|
||||
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]));
|
||||
@@ -24,41 +30,37 @@ static naRef size(naContext c, naRef me, int argc, naRef* args)
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef keys(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_keys(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef v, h = args[0];
|
||||
if(!naIsHash(h)) return naNil();
|
||||
naRef v, h = argc > 0 ? args[0] : naNil();
|
||||
if(!naIsHash(h)) ARGERR();
|
||||
v = naNewVector(c);
|
||||
naHash_keys(v, h);
|
||||
return v;
|
||||
}
|
||||
|
||||
static naRef append(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_append(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
if(argc < 2) return naNil();
|
||||
if(!naIsVector(args[0])) return naNil();
|
||||
if(argc < 2 || !naIsVector(args[0])) ARGERR();
|
||||
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)
|
||||
static naRef f_pop(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc < 1 || !naIsVector(args[0])) return naNil();
|
||||
if(argc < 1 || !naIsVector(args[0])) ARGERR();
|
||||
return naVec_removelast(args[0]);
|
||||
}
|
||||
|
||||
static naRef setsize(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_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);
|
||||
if(argc < 2 || !naIsVector(args[0])) ARGERR();
|
||||
naVec_setsize(args[0], (int)naNumValue(args[1]).num);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static naRef subvec(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_subvec(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
naRef nlen, result, v = args[0];
|
||||
@@ -68,7 +70,7 @@ static naRef subvec(naContext c, naRef me, int argc, naRef* args)
|
||||
if(!naIsNil(nlen))
|
||||
len = (int)nlen.num;
|
||||
if(!naIsVector(v) || start < 0 || start > naVec_size(v) || len < 0)
|
||||
return naNil();
|
||||
ARGERR();
|
||||
if(naIsNil(nlen) || len > naVec_size(v) - start)
|
||||
len = naVec_size(v) - start;
|
||||
result = naNewVector(c);
|
||||
@@ -78,13 +80,14 @@ static naRef subvec(naContext c, naRef me, int argc, naRef* args)
|
||||
return result;
|
||||
}
|
||||
|
||||
static naRef delete(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_delete(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 1 && naIsHash(args[0])) naHash_delete(args[0], args[1]);
|
||||
return naNil();
|
||||
if(argc < 2 || !naIsHash(args[0])) ARGERR();
|
||||
naHash_delete(args[0], args[1]);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static naRef intf(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_int(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 0) {
|
||||
naRef n = naNumValue(args[0]);
|
||||
@@ -92,15 +95,16 @@ static naRef intf(naContext c, naRef me, int argc, naRef* args)
|
||||
if(n.num < 0) n.num = -floor(-n.num);
|
||||
else n.num = floor(n.num);
|
||||
return n;
|
||||
} else return naNil();
|
||||
} else ARGERR();
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef num(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_num(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
return argc > 0 ? naNumValue(args[0]) : naNil();
|
||||
}
|
||||
|
||||
static naRef streq(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_streq(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
return argc > 1 ? naNum(naStrEqual(args[0], args[1])) : naNil();
|
||||
}
|
||||
@@ -110,7 +114,7 @@ static naRef f_cmp(naContext c, naRef me, int argc, naRef* args)
|
||||
char *a, *b;
|
||||
int i, alen, blen;
|
||||
if(argc < 2 || !naIsString(args[0]) || !naIsString(args[1]))
|
||||
naRuntimeError(c, "bad argument to cmp");
|
||||
ARGERR();
|
||||
a = naStr_data(args[0]);
|
||||
alen = naStr_len(args[0]);
|
||||
b = naStr_data(args[1]);
|
||||
@@ -122,45 +126,45 @@ static naRef f_cmp(naContext c, naRef me, int argc, naRef* args)
|
||||
return naNum(alen == blen ? 0 : (alen < blen ? -1 : 1));
|
||||
}
|
||||
|
||||
static naRef substr(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_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();
|
||||
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();
|
||||
len = (int)lenR.num;
|
||||
}
|
||||
int start, len, srclen;
|
||||
naRef src = argc > 0 ? args[0] : naNil();
|
||||
naRef startr = argc > 1 ? naNumValue(args[1]) : naNil();
|
||||
naRef lenr = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||
if(!naIsString(src)) ARGERR();
|
||||
if(naIsNil(startr) || !naIsNum(startr)) ARGERR();
|
||||
if(!naIsNil(lenr) && !naIsNum(lenr)) ARGERR();
|
||||
srclen = naStr_len(src);
|
||||
start = (int)startr.num;
|
||||
len = naIsNum(lenr) ? (int)lenr.num : (srclen - start);
|
||||
if(start < 0) start += srclen;
|
||||
if(start < 0) start = len = 0;
|
||||
if(start >= srclen) start = len = 0;
|
||||
if(len < 0) len = 0;
|
||||
if(len > srclen - start) len = srclen - start;
|
||||
return naStr_substr(naNewString(c), src, start, len);
|
||||
}
|
||||
|
||||
static naRef f_chr(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
char chr[1];
|
||||
naRef cr = argc ? naNumValue(args[0]) : naNil();
|
||||
if(IS_NIL(cr)) naRuntimeError(c, "chr argument not string");
|
||||
naRef cr = argc > 0 ? naNumValue(args[0]) : naNil();
|
||||
if(IS_NIL(cr)) ARGERR();
|
||||
chr[0] = (char)cr.num;
|
||||
return NEWSTR(c, chr, 1);
|
||||
}
|
||||
|
||||
static naRef contains(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_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(naIsNil(hash) || naIsNil(key)) ARGERR();
|
||||
if(!naIsHash(hash)) return naNil();
|
||||
return naHash_get(hash, key, &key) ? naNum(1) : naNum(0);
|
||||
}
|
||||
|
||||
static naRef typeOf(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_typeof(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef r = argc > 0 ? args[0] : naNil();
|
||||
char* t = "unknown";
|
||||
@@ -171,8 +175,20 @@ static naRef typeOf(naContext c, naRef me, int argc, naRef* args)
|
||||
else if(naIsHash(r)) t = "hash";
|
||||
else if(naIsFunc(r)) t = "func";
|
||||
else if(naIsGhost(r)) t = "ghost";
|
||||
r = NEWCSTR(c, t);
|
||||
return r;
|
||||
return NEWCSTR(c, t);
|
||||
}
|
||||
|
||||
static naRef f_ghosttype(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef g = argc > 0 ? args[0] : naNil();
|
||||
if(!naIsGhost(g)) return naNil();
|
||||
if(naGhost_type(g)->name) {
|
||||
return NEWCSTR(c, (char*)naGhost_type(g)->name);
|
||||
} else {
|
||||
char buf[32];
|
||||
sprintf(buf, "%p", naGhost_type(g));
|
||||
return NEWCSTR(c, buf);
|
||||
}
|
||||
}
|
||||
|
||||
static naRef f_compile(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -184,10 +200,20 @@ static naRef f_compile(naContext c, naRef me, int argc, naRef* args)
|
||||
if(!naIsString(script) || !naIsString(fname)) return naNil();
|
||||
code = naParseCode(c, fname, 1,
|
||||
naStr_data(script), naStr_len(script), &errLine);
|
||||
if(!naIsCode(code)) return naNil(); // FIXME: export error to caller...
|
||||
if(naIsNil(code)) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "Parse error: %s at line %d",
|
||||
naGetError(c), errLine);
|
||||
c->dieArg = NEWCSTR(c, buf);
|
||||
naRuntimeError(c, "__die__");
|
||||
}
|
||||
return naBindToContext(c, code);
|
||||
}
|
||||
|
||||
// FIXME: need a place to save the current IP when we get an error so
|
||||
// that it can be reset if we get a die()/naRethrowError() situation
|
||||
// later. Right now, the IP on the stack trace is the line of the
|
||||
// die() call, when it should be this one...
|
||||
static naRef f_call(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naContext subc;
|
||||
@@ -199,41 +225,49 @@ static naRef f_call(naContext c, naRef me, int argc, naRef* args)
|
||||
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;
|
||||
ARGERR();
|
||||
|
||||
subc = naSubContext(c);
|
||||
vr = IS_NIL(callargs) ? 0 : PTR(callargs).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])) {
|
||||
naRef v = args[argc-1];
|
||||
if(!IS_NIL(subc->dieArg)) naVec_append(v, subc->dieArg);
|
||||
else if(naGetError(subc))
|
||||
naVec_append(v, NEWCSTR(subc, naGetError(subc)));
|
||||
if(naVec_size(v)) {
|
||||
int i, sd = naStackDepth(subc);
|
||||
for(i=0; i<sd; i++) {
|
||||
naVec_append(v, naGetSourceFile(subc, i));
|
||||
naVec_append(v, naNum(naGetLine(subc, i)));
|
||||
}
|
||||
if(!naGetError(subc)) {
|
||||
naFreeContext(subc);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Error handling. Note that we don't free the subcontext after an
|
||||
// error, in case the user re-throws the same error or calls
|
||||
// naContinue()
|
||||
if(argc <= 2 || !IS_VEC(args[argc-1])) {
|
||||
naRethrowError(subc);
|
||||
} else {
|
||||
int i, sd;
|
||||
naRef errv = args[argc-1];
|
||||
if(!IS_NIL(subc->dieArg)) naVec_append(errv, subc->dieArg);
|
||||
else naVec_append(errv, NEWCSTR(subc, naGetError(subc)));
|
||||
sd = naStackDepth(subc);
|
||||
for(i=0; i<sd; i++) {
|
||||
naVec_append(errv, naGetSourceFile(subc, i));
|
||||
naVec_append(errv, naNum(naGetLine(subc, i)));
|
||||
}
|
||||
}
|
||||
naFreeContext(subc);
|
||||
return result;
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_die(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
c->dieArg = argc > 0 ? args[0] : naNil();
|
||||
naRef darg = argc > 0 ? args[0] : naNil();
|
||||
if(!naIsNil(darg) && c->callChild && IDENTICAL(c->callChild->dieArg, darg))
|
||||
naRethrowError(c->callChild);
|
||||
c->dieArg = darg;
|
||||
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, ...)
|
||||
static char* dosprintf(char* f, ...)
|
||||
{
|
||||
char* buf;
|
||||
va_list va;
|
||||
@@ -259,7 +293,7 @@ char* dosprintf(char* f, ...)
|
||||
// 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)
|
||||
static char* nextFormat(naContext c, char* f, char** out, int* len, char* type)
|
||||
{
|
||||
// Skip to the start of the format string
|
||||
while(*f && *f != '%') f++;
|
||||
@@ -274,44 +308,44 @@ static char* nextFormat(naContext ctx, char* f, char** out, int* len, char* type
|
||||
for(p1 = *out + 1; p1 < f; p1++)
|
||||
for(p2 = p1+1; p2 < f; p2++)
|
||||
if(*p1 == *p2)
|
||||
naRuntimeError(ctx, "duplicate flag in format string"); }
|
||||
naRuntimeError(c, "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");
|
||||
if(!*f) naRuntimeError(c, "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)
|
||||
#define ERR(m) naRuntimeError(c, m)
|
||||
#define APPEND(r) result = naStr_concat(naNewString(c), result, r)
|
||||
static naRef f_sprintf(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
char t, nultmp, *fstr, *next, *fout=0, *s;
|
||||
int flen, argn=1;
|
||||
naRef format, arg, result = naNewString(ctx);
|
||||
naRef format, arg, result = naNewString(c);
|
||||
|
||||
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");
|
||||
if(argc < 1) ERR("not enough arguments to sprintf()");
|
||||
format = naStringValue(c, 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
|
||||
while((next = nextFormat(c, s, &fstr, &flen, &t))) {
|
||||
APPEND(NEWSTR(c, s, fstr-s)); // stuff before the format string
|
||||
if(flen == 2 && fstr[1] == '%') {
|
||||
APPEND(NEWSTR(ctx, "%", 1));
|
||||
APPEND(NEWSTR(c, "%", 1));
|
||||
s = next;
|
||||
continue;
|
||||
}
|
||||
if(argn >= argc) ERR("not enough arguments to sprintf");
|
||||
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);
|
||||
arg = naStringValue(c, arg);
|
||||
if(naIsNil(arg)) fout = dosprintf(fstr, "nil");
|
||||
else fout = dosprintf(fstr, naStr_data(arg));
|
||||
} else {
|
||||
@@ -328,43 +362,42 @@ static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args)
|
||||
ERR("invalid sprintf format type");
|
||||
}
|
||||
fstr[flen] = nultmp;
|
||||
APPEND(NEWSTR(ctx, fout, strlen(fout)));
|
||||
APPEND(NEWSTR(c, fout, strlen(fout)));
|
||||
naFree(fout);
|
||||
s = next;
|
||||
}
|
||||
APPEND(NEWSTR(ctx, s, strlen(s)));
|
||||
APPEND(NEWSTR(c, s, strlen(s)));
|
||||
return result;
|
||||
}
|
||||
|
||||
// FIXME: handle ctx->callParent frames too!
|
||||
static naRef f_caller(naContext ctx, naRef me, int argc, naRef* args)
|
||||
// FIXME: needs to honor subcontext list
|
||||
static naRef f_caller(naContext c, 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()");
|
||||
if(IS_NIL(fr)) ARGERR();
|
||||
fidx = (int)fr.num;
|
||||
if(fidx > ctx->fTop - 1) return naNil();
|
||||
frame = &ctx->fStack[ctx->fTop - 1 - fidx];
|
||||
result = naNewVector(ctx);
|
||||
if(fidx > c->fTop - 1) return naNil();
|
||||
frame = &c->fStack[c->fTop - 1 - fidx];
|
||||
result = naNewVector(c);
|
||||
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)));
|
||||
naVec_append(result, PTR(PTR(frame->func).func->code).code->srcFile);
|
||||
naVec_append(result, naNum(naGetLine(c, fidx)));
|
||||
return result;
|
||||
}
|
||||
|
||||
static naRef f_closure(naContext ctx, naRef me, int argc, naRef* args)
|
||||
static naRef f_closure(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
struct naFunc* f;
|
||||
naRef func = argc > 0 ? args[0] : naNil();
|
||||
naRef idx = argc > 1 ? naNumValue(args[1]) : naNum(0);
|
||||
if(!IS_FUNC(func) || IS_NIL(idx))
|
||||
naRuntimeError(ctx, "bad arguments to closure()");
|
||||
if(!IS_FUNC(func) || IS_NIL(idx)) ARGERR();
|
||||
i = (int)idx.num;
|
||||
f = func.ref.ptr.func;
|
||||
while(i > 0 && f) { i--; f = f->next.ref.ptr.func; }
|
||||
f = PTR(func).func;
|
||||
while(i > 0 && f) { i--; f = PTR(f->next).func; }
|
||||
if(!f) return naNil();
|
||||
return f->namespace;
|
||||
}
|
||||
@@ -384,40 +417,38 @@ static int find(unsigned char* a, int al, unsigned char* s, int sl, int start)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static naRef f_find(naContext ctx, naRef me, int argc, naRef* args)
|
||||
static naRef f_find(naContext c, 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 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
|
||||
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,
|
||||
return naNum(find(PTR(args[0]).str->data, PTR(args[0]).str->len,
|
||||
PTR(args[1]).str->data, PTR(args[1]).str->len,
|
||||
start));
|
||||
}
|
||||
|
||||
static naRef f_split(naContext ctx, naRef me, int argc, naRef* args)
|
||||
static naRef f_split(naContext c, 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");
|
||||
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
|
||||
d = naStr_data(args[0]); dl = naStr_len(args[0]);
|
||||
s = naStr_data(args[1]); sl = naStr_len(args[1]);
|
||||
result = naNewVector(ctx);
|
||||
result = naNewVector(c);
|
||||
if(dl == 0) { // special case zero-length delimiter
|
||||
for(i=0; i<sl; i++) naVec_append(result, NEWSTR(ctx, s+i, 1));
|
||||
for(i=0; i<sl; i++) naVec_append(result, NEWSTR(c, 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));
|
||||
naVec_append(result, NEWSTR(c, s0, s+i-s0));
|
||||
s0 = s + i + dl;
|
||||
i += dl - 1;
|
||||
}
|
||||
}
|
||||
if(s0 - s <= sl) naVec_append(result, NEWSTR(ctx, s0, s+sl-s0));
|
||||
if(s0 - s <= sl) naVec_append(result, NEWSTR(c, s0, s+sl-s0));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -425,12 +456,12 @@ static naRef f_split(naContext ctx, naRef me, int argc, naRef* args)
|
||||
// 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)
|
||||
static naRef f_rand(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
double r = 0;
|
||||
if(argc) {
|
||||
if(!IS_NUM(args[0])) naRuntimeError(ctx, "rand() seed not number");
|
||||
if(!IS_NUM(args[0])) naRuntimeError(c, "rand() seed not number");
|
||||
srand((unsigned int)args[0].num);
|
||||
return naNil();
|
||||
}
|
||||
@@ -438,36 +469,91 @@ static naRef f_rand(naContext ctx, naRef me, int argc, naRef* args)
|
||||
return naNum(r);
|
||||
}
|
||||
|
||||
static naRef f_bind(naContext ctx, naRef me, int argc, naRef* args)
|
||||
static naRef f_bind(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef func = argc > 0 ? args[0] : naNil();
|
||||
naRef hash = argc > 1 ? args[1] : naNewHash(ctx);
|
||||
naRef hash = argc > 1 ? args[1] : naNewHash(c);
|
||||
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;
|
||||
ARGERR();
|
||||
func = naNewFunc(c, PTR(func).func->code);
|
||||
PTR(func).func->namespace = hash;
|
||||
PTR(func).func->next = next;
|
||||
return func;
|
||||
}
|
||||
|
||||
struct func { char* name; naCFunction func; };
|
||||
static struct func funcs[] = {
|
||||
{ "size", size },
|
||||
{ "keys", keys },
|
||||
{ "append", append },
|
||||
{ "pop", pop },
|
||||
{ "setsize", setsize },
|
||||
{ "subvec", subvec },
|
||||
{ "delete", delete },
|
||||
{ "int", intf },
|
||||
{ "num", num },
|
||||
{ "streq", streq },
|
||||
/* We use the "SortRec" gadget for two reasons: first, because ANSI
|
||||
* qsort() doesn't give us a mechanism for passing a "context" pointer
|
||||
* to the comparison routine we have to store one in every sorted
|
||||
* record. Second, using an index into the original vector here
|
||||
* allows us to make the sort stable in the event of a zero returned
|
||||
* from the Nasal comparison function. */
|
||||
struct SortData { naContext ctx, subc; struct SortRec* recs;
|
||||
naRef* elems; int n; naRef fn; };
|
||||
struct SortRec { struct SortData* sd; int i; };
|
||||
|
||||
static int sortcmp(struct SortRec* a, struct SortRec* b)
|
||||
{
|
||||
struct SortData* sd = a->sd;
|
||||
naRef args[2], d;
|
||||
args[0] = sd->elems[a->i];
|
||||
args[1] = sd->elems[b->i];
|
||||
d = naCall(sd->subc, sd->fn, 2, args, naNil(), naNil());
|
||||
if(naGetError(sd->subc)) {
|
||||
naFree(sd->recs);
|
||||
naRethrowError(sd->subc);
|
||||
} else if(!naIsNum(d = naNumValue(d))) {
|
||||
naFree(sd->recs);
|
||||
naRuntimeError(sd->ctx, "sort() comparison returned non-number");
|
||||
}
|
||||
return (d.num > 0) ? 1 : ((d.num < 0) ? -1 : (a->i - b->i));
|
||||
}
|
||||
|
||||
static naRef f_sort(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
struct SortData sd;
|
||||
naRef out;
|
||||
if(argc != 2 || !naIsVector(args[0]) || !naIsFunc(args[1]))
|
||||
naRuntimeError(c, "bad/missing argument to sort()");
|
||||
sd.subc = naSubContext(c);
|
||||
if(!PTR(args[0]).vec->rec) return naNewVector(c);
|
||||
sd.elems = PTR(args[0]).vec->rec->array;
|
||||
sd.n = PTR(args[0]).vec->rec->size;
|
||||
sd.fn = args[1];
|
||||
sd.recs = naAlloc(sizeof(struct SortRec) * sd.n);
|
||||
for(i=0; i<sd.n; i++) {
|
||||
sd.recs[i].sd = &sd;
|
||||
sd.recs[i].i = i;
|
||||
}
|
||||
qsort(sd.recs, sd.n, sizeof(sd.recs[0]),
|
||||
(int(*)(const void*,const void*))sortcmp);
|
||||
out = naNewVector(c);
|
||||
naVec_setsize(out, sd.n);
|
||||
for(i=0; i<sd.n; i++)
|
||||
PTR(out).vec->rec->array[i] = sd.elems[sd.recs[i].i];
|
||||
naFree(sd.recs);
|
||||
naFreeContext(sd.subc);
|
||||
return out;
|
||||
}
|
||||
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "size", f_size },
|
||||
{ "keys", f_keys },
|
||||
{ "append", f_append },
|
||||
{ "pop", f_pop },
|
||||
{ "setsize", f_setsize },
|
||||
{ "subvec", f_subvec },
|
||||
{ "delete", f_delete },
|
||||
{ "int", f_int },
|
||||
{ "num", f_num },
|
||||
{ "streq", f_streq },
|
||||
{ "cmp", f_cmp },
|
||||
{ "substr", substr },
|
||||
{ "substr", f_substr },
|
||||
{ "chr", f_chr },
|
||||
{ "contains", contains },
|
||||
{ "typeof", typeOf },
|
||||
{ "contains", f_contains },
|
||||
{ "typeof", f_typeof },
|
||||
{ "ghosttype", f_ghosttype },
|
||||
{ "compile", f_compile },
|
||||
{ "call", f_call },
|
||||
{ "die", f_die },
|
||||
@@ -478,17 +564,11 @@ static struct func funcs[] = {
|
||||
{ "split", f_split },
|
||||
{ "rand", f_rand },
|
||||
{ "bind", f_bind },
|
||||
{ "sort", f_sort },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
naRef naStdLib(naContext c)
|
||||
naRef naInit_std(naContext c)
|
||||
{
|
||||
naRef namespace = naNewHash(c);
|
||||
int i, n = sizeof(funcs)/sizeof(struct func);
|
||||
for(i=0; i<n; i++) {
|
||||
naRef code = naNewCCode(c, funcs[i].func);
|
||||
naRef name = NEWSTR(c, funcs[i].name, strlen(funcs[i].name));
|
||||
name = naInternSymbol(name);
|
||||
naHash_set(namespace, name, naNewFunc(c, code));
|
||||
}
|
||||
return namespace;
|
||||
return naGenLib(c, funcs);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,32 @@
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nasal.h"
|
||||
|
||||
// Toss a runtime error for any NaN or Inf values produced. Note that
|
||||
// this assumes an IEEE 754 format.
|
||||
#define VALIDATE(r) (valid(r.num) ? (r) : die(c, __FUNCTION__+2))
|
||||
|
||||
static int valid(double d)
|
||||
{
|
||||
union { double d; unsigned long long ull; } u;
|
||||
u.d = d;
|
||||
return ((u.ull >> 52) & 0x7ff) != 0x7ff;
|
||||
}
|
||||
|
||||
static naRef die(naContext c, const char* fn)
|
||||
{
|
||||
naRuntimeError(c, "floating point error in math.%s()", fn);
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_sin(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
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;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -19,7 +35,7 @@ static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to cos()");
|
||||
a.num = cos(a.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -28,7 +44,7 @@ static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to exp()");
|
||||
a.num = exp(a.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -37,7 +53,7 @@ static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to ln()");
|
||||
a.num = log(a.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -46,7 +62,7 @@ static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to sqrt()");
|
||||
a.num = sqrt(a.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -56,37 +72,23 @@ static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
|
||||
if(naIsNil(a) || naIsNil(b))
|
||||
naRuntimeError(c, "non numeric argument to atan2()");
|
||||
a.num = atan2(a.num, b.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static struct func { char* name; naCFunction func; } funcs[] = {
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "sin", f_sin },
|
||||
{ "cos", f_cos },
|
||||
{ "exp", f_exp },
|
||||
{ "ln", f_ln },
|
||||
{ "sqrt", f_sqrt },
|
||||
{ "atan2", f_atan2 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
naRef naMathLib(naContext c)
|
||||
naRef naInit_math(naContext c)
|
||||
{
|
||||
naRef name, namespace = naNewHash(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));
|
||||
naHash_set(namespace, name, naNewFunc(c, code));
|
||||
}
|
||||
|
||||
// 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(3.14159265358979323846));
|
||||
|
||||
name = naStr_fromdata(naNewString(c), "e", 1);
|
||||
name = naInternSymbol(name);
|
||||
naHash_set(namespace, name, naNum(2.7182818284590452354));
|
||||
|
||||
return namespace;
|
||||
naRef ns = naGenLib(c, funcs);
|
||||
naAddSym(c, ns, "pi", naNum(3.14159265358979323846));
|
||||
naAddSym(c, ns, "e", naNum(2.7182818284590452354));
|
||||
return ns;
|
||||
}
|
||||
|
||||
@@ -23,14 +23,13 @@ void naTempSave(naContext c, naRef r)
|
||||
naFree(c->temps);
|
||||
c->temps = newtemps;
|
||||
}
|
||||
c->temps[c->ntemps++] = r.ref.ptr.obj;
|
||||
c->temps[c->ntemps++] = PTR(r).obj;
|
||||
}
|
||||
|
||||
naRef naObj(int type, struct naObj* o)
|
||||
{
|
||||
naRef r;
|
||||
r.ref.reftag = NASAL_REFTAG;
|
||||
r.ref.ptr.obj = o;
|
||||
SETPTR(r, o);
|
||||
o->type = type;
|
||||
return r;
|
||||
}
|
||||
@@ -78,23 +77,23 @@ naRef naNew(struct Context* c, int type)
|
||||
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;
|
||||
PTR(s).str->len = 0;
|
||||
PTR(s).str->data = 0;
|
||||
PTR(s).str->hashcode = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
naRef naNewVector(struct Context* c)
|
||||
{
|
||||
naRef r = naNew(c, T_VEC);
|
||||
r.ref.ptr.vec->rec = 0;
|
||||
PTR(r).vec->rec = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
naRef naNewHash(struct Context* c)
|
||||
{
|
||||
naRef r = naNew(c, T_HASH);
|
||||
r.ref.ptr.hash->rec = 0;
|
||||
PTR(r).hash->rec = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -106,59 +105,57 @@ naRef naNewCode(struct Context* c)
|
||||
naRef naNewCCode(struct Context* c, naCFunction fptr)
|
||||
{
|
||||
naRef r = naNew(c, T_CCODE);
|
||||
r.ref.ptr.ccode->fptr = fptr;
|
||||
PTR(r).ccode->fptr = fptr;
|
||||
return r;
|
||||
}
|
||||
|
||||
naRef naNewFunc(struct Context* c, naRef code)
|
||||
{
|
||||
naRef func = naNew(c, T_FUNC);
|
||||
func.ref.ptr.func->code = code;
|
||||
func.ref.ptr.func->namespace = naNil();
|
||||
func.ref.ptr.func->next = naNil();
|
||||
PTR(func).func->code = code;
|
||||
PTR(func).func->namespace = naNil();
|
||||
PTR(func).func->next = naNil();
|
||||
return func;
|
||||
}
|
||||
|
||||
naRef naNewGhost(naContext c, naGhostType* type, void* ptr)
|
||||
{
|
||||
naRef ghost = naNew(c, T_GHOST);
|
||||
ghost.ref.ptr.ghost->gtype = type;
|
||||
ghost.ref.ptr.ghost->ptr = ptr;
|
||||
PTR(ghost).ghost->gtype = type;
|
||||
PTR(ghost).ghost->ptr = ptr;
|
||||
return ghost;
|
||||
}
|
||||
|
||||
naGhostType* naGhost_type(naRef ghost)
|
||||
{
|
||||
if(!IS_GHOST(ghost)) return 0;
|
||||
return ghost.ref.ptr.ghost->gtype;
|
||||
return PTR(ghost).ghost->gtype;
|
||||
}
|
||||
|
||||
void* naGhost_ptr(naRef ghost)
|
||||
{
|
||||
if(!IS_GHOST(ghost)) return 0;
|
||||
return ghost.ref.ptr.ghost->ptr;
|
||||
return PTR(ghost).ghost->ptr;
|
||||
}
|
||||
|
||||
naRef naNil()
|
||||
{
|
||||
naRef r;
|
||||
r.ref.reftag = NASAL_REFTAG;
|
||||
r.ref.ptr.obj = 0;
|
||||
naRef r;
|
||||
SETPTR(r, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
naRef naNum(double num)
|
||||
{
|
||||
naRef r;
|
||||
r.ref.reftag = ~NASAL_REFTAG;
|
||||
r.num = num;
|
||||
SETNUM(r, num);
|
||||
return r;
|
||||
}
|
||||
|
||||
int naEqual(naRef a, naRef b)
|
||||
{
|
||||
double na=0, nb=0;
|
||||
if(IS_REF(a) && IS_REF(b) && a.ref.ptr.obj == b.ref.ptr.obj)
|
||||
if(IS_REF(a) && IS_REF(b) && PTR(a).obj == PTR(b).obj)
|
||||
return 1; // Object identity (and nil == nil)
|
||||
if(IS_NIL(a) || IS_NIL(b))
|
||||
return 0;
|
||||
@@ -182,10 +179,10 @@ 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)
|
||||
if(PTR(a).str->len != PTR(b).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])
|
||||
for(i=0; i<PTR(a).str->len; i++)
|
||||
if(PTR(a).str->data[i] != PTR(b).str->data[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -214,3 +211,24 @@ 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); }
|
||||
|
||||
void naSetUserData(naContext c, void* p) { c->userData = p; }
|
||||
void* naGetUserData(naContext c)
|
||||
{
|
||||
if(c->userData) return c->userData;
|
||||
return c->callParent ? naGetUserData(c->callParent) : 0;
|
||||
}
|
||||
|
||||
void naAddSym(naContext c, naRef ns, char *sym, naRef val)
|
||||
{
|
||||
naRef name = naStr_fromdata(naNewString(c), sym, strlen(sym));
|
||||
naHash_set(ns, naInternSymbol(name), val);
|
||||
}
|
||||
|
||||
naRef naGenLib(naContext c, naCFuncItem *fns)
|
||||
{
|
||||
naRef ns = naNewHash(c);
|
||||
for(/**/; fns->name; fns++)
|
||||
naAddSym(c, ns, fns->name, naNewFunc(c, naNewCCode(c, fns->func)));
|
||||
return ns;
|
||||
}
|
||||
|
||||
59
simgear/nasal/naref.h
Normal file
59
simgear/nasal/naref.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef _NAREF_H
|
||||
#define _NAREF_H
|
||||
|
||||
/* Rather than play elaborate and complicated games with
|
||||
* platform-dependent endianness headers, just detect the platforms we
|
||||
* support. This list is simpler and smaller, yet still quite
|
||||
* complete. */
|
||||
#if (defined(__x86_64) && defined(__linux__)) || defined(__sparcv9)
|
||||
/* Win64 and Irix should work with this too, but have not been
|
||||
* tested */
|
||||
# define NASAL_NAN64
|
||||
#elif defined(_M_IX86) || defined(i386) || defined(__x86_64) || \
|
||||
defined(__ia64__) || defined(_M_IA64) || defined(__ARMEL__)
|
||||
# define NASAL_LE
|
||||
#elif defined(__sparc) || defined(__ppc__) ||defined(__PPC) || \
|
||||
defined(__mips) || defined(__ARMEB__)
|
||||
# define NASAL_BE
|
||||
#else
|
||||
# error Unrecognized CPU architecture
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
struct naObj* obj;
|
||||
struct naStr* str;
|
||||
struct naVec* vec;
|
||||
struct naHash* hash;
|
||||
struct naCode* code;
|
||||
struct naFunc* func;
|
||||
struct naCCode* ccode;
|
||||
struct naGhost* ghost;
|
||||
} naPtr;
|
||||
|
||||
#if defined(NASAL_NAN64)
|
||||
|
||||
/* On suppoted 64 bit platforms (those where all memory returned from
|
||||
* naAlloc() is guaranteed to lie between 0 and 2^48-1) we union the
|
||||
* double with the pointer, and use fancy tricks (see data.h) to make
|
||||
* sure all pointers are stored as NaNs. */
|
||||
typedef union { double num; void* ptr; } naRef;
|
||||
|
||||
#elif defined(NASAL_LE) || defined(NASAL_BE)
|
||||
|
||||
/* 32 bit layouts (and 64 bit platforms where we haven't tested the
|
||||
trick above) need endianness-dependent ordering to make sure that
|
||||
the reftag lies in the top bits of the double */
|
||||
#ifdef NASAL_LE
|
||||
typedef struct { naPtr ptr; int reftag; } naRefPart;
|
||||
#else /* NASAL_BE */
|
||||
typedef struct { int reftag; naPtr ptr; } naRefPart;
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
double num;
|
||||
naRefPart ref;
|
||||
} naRef;
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _NAREF_H
|
||||
@@ -4,73 +4,17 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef BYTE_ORDER
|
||||
#include "naref.h"
|
||||
|
||||
# if (BSD >= 199103)
|
||||
# include <machine/endian.h>
|
||||
# elif defined(__CYGWIN__) || defined(__MINGW32__)
|
||||
# include <sys/param.h>
|
||||
# elif defined(linux)
|
||||
# include <endian.h>
|
||||
# else
|
||||
# ifndef LITTLE_ENDIAN
|
||||
# define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */
|
||||
# endif
|
||||
# ifndef BIG_ENDIAN
|
||||
# define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */
|
||||
# endif
|
||||
|
||||
# if defined(ultrix) || defined(__alpha__) || defined(__alpha) || \
|
||||
defined(__i386__) || defined(__i486__) || defined(_X86_) || \
|
||||
defined(sun386)
|
||||
# define BYTE_ORDER LITTLE_ENDIAN
|
||||
# else
|
||||
# define BYTE_ORDER BIG_ENDIAN
|
||||
# endif
|
||||
# endif /* BSD */
|
||||
#endif /* BYTE_ORDER */
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
# include <limits.h>
|
||||
# if (LONG_MAX == 2147483647)
|
||||
# define NASAL_BIG_ENDIAN_32_BIT 1
|
||||
# endif
|
||||
#if __GNUC__ > 2
|
||||
/* This marks the function as having no side effects and depending on
|
||||
* nothing but its arguments, which allows the optimizer to avoid
|
||||
* duplicate calls to naNil(). */
|
||||
#define GCC_PURE __attribute__((__pure__))
|
||||
#else
|
||||
#define GCC_PURE
|
||||
#endif
|
||||
|
||||
// This is a nasal "reference". They are always copied by value, and
|
||||
// contain either a pointer to a garbage-collectable nasal object
|
||||
// (string, vector, hash) or a floating point number. Keeping the
|
||||
// number here is an optimization to prevent the generation of
|
||||
// zillions of tiny "number" object that have to be collected. Note
|
||||
// sneaky hack: on little endian systems, placing reftag after ptr and
|
||||
// putting 1's in the top 13 (except the sign bit) bits makes the
|
||||
// double value a NaN, and thus unmistakable (no actual number can
|
||||
// appear as a reference, and vice versa). Swap the structure order
|
||||
// on 32 bit big-endian systems. On 64 bit sytems of either
|
||||
// endianness, reftag and the double won't be coincident anyway.
|
||||
#define NASAL_REFTAG 0x7ff56789 // == 2,146,789,257 decimal
|
||||
typedef union {
|
||||
double num;
|
||||
struct {
|
||||
#ifdef NASAL_BIG_ENDIAN_32_BIT
|
||||
int reftag; // Big-endian systems need this here!
|
||||
#endif
|
||||
union {
|
||||
struct naObj* obj;
|
||||
struct naStr* str;
|
||||
struct naVec* vec;
|
||||
struct naHash* hash;
|
||||
struct naCode* code;
|
||||
struct naFunc* func;
|
||||
struct naCCode* ccode;
|
||||
struct naGhost* ghost;
|
||||
} ptr;
|
||||
#ifndef NASAL_BIG_ENDIAN_32_BIT
|
||||
int reftag; // Little-endian and 64 bit systems need this here!
|
||||
#endif
|
||||
} ref;
|
||||
} naRef;
|
||||
|
||||
typedef struct Context* naContext;
|
||||
|
||||
// The function signature for an extension function:
|
||||
@@ -80,7 +24,21 @@ typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args);
|
||||
naContext naNewContext();
|
||||
void naFreeContext(naContext c);
|
||||
|
||||
// Save this object in the context, preventing it (and objects
|
||||
// Use this when making a call to a new context "underneath" a
|
||||
// preexisting context on the same stack. It allows stack walking to
|
||||
// see through the boundary, and eliminates the need to release the
|
||||
// mod lock (i.e. must be called with the mod lock held!)
|
||||
naContext naSubContext(naContext super);
|
||||
|
||||
// The naContext supports a user data pointer that can be used to
|
||||
// store data specific to an naCall invocation without exposing it to
|
||||
// Nasal as a ghost. FIXME: this API is semi-dangerous, there is no
|
||||
// provision for sharing it, nor for validating the source or type of
|
||||
// the pointer returned.
|
||||
void naSetUserData(naContext c, void* p);
|
||||
void* naGetUserData(naContext c) GCC_PURE;
|
||||
|
||||
// "Save" this object in the context, preventing it (and objects
|
||||
// referenced by it) from being garbage collected.
|
||||
void naSave(naContext ctx, naRef obj);
|
||||
|
||||
@@ -89,68 +47,98 @@ void naSave(naContext ctx, naRef obj);
|
||||
// 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.
|
||||
// Parse a buffer in memory into a code object. The srcFile parameter
|
||||
// is a Nasal string representing the "file" from which the code is
|
||||
// read. The "first line" is typically 1, but is settable for
|
||||
// situations where the Nasal code is embedded in another context with
|
||||
// its own numbering convetions. If an error occurs, returns nil and
|
||||
// sets the errLine pointer to point to the line at fault. The string
|
||||
// representation of the error can be retrieved with naGetError() on
|
||||
// the context.
|
||||
naRef naParseCode(naContext c, naRef srcFile, int firstLine,
|
||||
char* buf, int len, int* errLine);
|
||||
|
||||
// Binds a bare code object (as returned from naParseCode) with a
|
||||
// closure object (a hash) to act as the outer scope / namespace.
|
||||
// FIXME: this API is weak. It should expose the recursive nature of
|
||||
// closures, and allow for extracting the closure and namespace
|
||||
// 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, int argc, naRef* args, naRef obj, naRef locals);
|
||||
// Call a code or function object with the specified arguments "on"
|
||||
// the specified object and using the specified hash for the local
|
||||
// variables. Passing a null args array skips the parameter variables
|
||||
// (e.g. "arg") assignments; to get a zero-length arg instead, pass in
|
||||
// argc==0 and a non-null args vector. The obj or locals parameters
|
||||
// may be nil. Will attempt to acquire the mod lock, so call
|
||||
// naModUnlock() first if the lock is already held.
|
||||
naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
|
||||
naRef obj, naRef locals);
|
||||
|
||||
// As naCall(), but continues execution at the operation after a
|
||||
// previous die() call or runtime error. Useful to do "yield"
|
||||
// semantics, leaving the context in a condition where it can be
|
||||
// restarted from C code. Cannot be used currently to restart a
|
||||
// failed operation. Will attempt to acquire the mod lock, so call
|
||||
// naModUnlock() first if the lock is already held.
|
||||
naRef naContinue(naContext ctx);
|
||||
|
||||
// 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
|
||||
// intended for use in library code that cannot otherwise report an
|
||||
// error via the return value, and MUST be used carefully. If in
|
||||
// doubt, return naNil() as your error condition.
|
||||
void naRuntimeError(naContext ctx, char* msg);
|
||||
// doubt, return naNil() as your error condition. Works like
|
||||
// printf().
|
||||
void naRuntimeError(naContext c, const char* fmt, ...);
|
||||
|
||||
// Call a method on an object (NOTE: func is a function binding, *not*
|
||||
// a code object as returned from naParseCode).
|
||||
naRef naMethod(naContext ctx, naRef func, naRef object);
|
||||
// "Re-throws" a runtime error caught from the subcontext. Acts as a
|
||||
// naRuntimeError() called on the parent context. Does not return.
|
||||
void naRethrowError(naContext subc);
|
||||
|
||||
// Retrieve the specified member from the object, respecting the
|
||||
// "parents" array as for "object.field". Returns zero for missing
|
||||
// fields.
|
||||
int naMember_get(naRef obj, naRef field, naRef* out);
|
||||
int naMember_cget(naRef obj, const char* field, naRef* out);
|
||||
|
||||
// Returns a hash containing functions from the Nasal standard library
|
||||
// Useful for passing as a namespace to an initial function call
|
||||
naRef naStdLib(naContext c);
|
||||
naRef naInit_std(naContext c);
|
||||
|
||||
// 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);
|
||||
naRef naInit_math(naContext c);
|
||||
naRef naInit_bits(naContext c);
|
||||
naRef naInit_io(naContext c);
|
||||
naRef naInit_regex(naContext c);
|
||||
naRef naInit_unix(naContext c);
|
||||
naRef naInit_thread(naContext c);
|
||||
naRef naInit_utf8(naContext c);
|
||||
naRef naInit_sqlite(naContext c);
|
||||
naRef naInit_readline(naContext c);
|
||||
naRef naInit_gtk(naContext ctx);
|
||||
naRef naInit_cairo(naContext ctx);
|
||||
|
||||
// Current line number & error message
|
||||
// Context stack inspection, frame zero is the "top"
|
||||
int naStackDepth(naContext ctx);
|
||||
int naGetLine(naContext ctx, int frame);
|
||||
naRef naGetSourceFile(naContext ctx, int frame);
|
||||
char* naGetError(naContext ctx);
|
||||
|
||||
// Type predicates
|
||||
int naIsNil(naRef r);
|
||||
int naIsNum(naRef r);
|
||||
int naIsString(naRef r);
|
||||
int naIsScalar(naRef r);
|
||||
int naIsVector(naRef r);
|
||||
int naIsHash(naRef r);
|
||||
int naIsCode(naRef r);
|
||||
int naIsFunc(naRef r);
|
||||
int naIsCCode(naRef r);
|
||||
int naIsNil(naRef r) GCC_PURE;
|
||||
int naIsNum(naRef r) GCC_PURE;
|
||||
int naIsString(naRef r) GCC_PURE;
|
||||
int naIsScalar(naRef r) GCC_PURE;
|
||||
int naIsVector(naRef r) GCC_PURE;
|
||||
int naIsHash(naRef r) GCC_PURE;
|
||||
int naIsCode(naRef r) GCC_PURE;
|
||||
int naIsFunc(naRef r) GCC_PURE;
|
||||
int naIsCCode(naRef r) GCC_PURE;
|
||||
|
||||
// Allocators/generators:
|
||||
naRef naNil();
|
||||
naRef naNum(double num);
|
||||
naRef naNil() GCC_PURE;
|
||||
naRef naNum(double num) GCC_PURE;
|
||||
naRef naNewString(naContext c);
|
||||
naRef naNewVector(naContext c);
|
||||
naRef naNewHash(naContext c);
|
||||
@@ -158,10 +146,10 @@ naRef naNewFunc(naContext c, naRef code);
|
||||
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);
|
||||
int naEqual(naRef a, naRef b) GCC_PURE;
|
||||
int naStrEqual(naRef a, naRef b) GCC_PURE;
|
||||
int naTrue(naRef b) GCC_PURE;
|
||||
naRef naNumValue(naRef n) GCC_PURE;
|
||||
naRef naStringValue(naContext c, naRef n);
|
||||
|
||||
// String utilities:
|
||||
@@ -192,6 +180,7 @@ void naHash_keys(naRef dst, naRef hash);
|
||||
// Ghost utilities:
|
||||
typedef struct naGhostType {
|
||||
void (*destroy)(void* ghost);
|
||||
const char* name;
|
||||
} naGhostType;
|
||||
naRef naNewGhost(naContext c, naGhostType* t, void* ghost);
|
||||
naGhostType* naGhost_type(naRef ghost);
|
||||
@@ -200,18 +189,31 @@ 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.
|
||||
// garbage collector (nasal data 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 nasal objects are
|
||||
// being modified. It need not be acquired when only read access is
|
||||
// needed, PRESUMING that the Nasal data being read is findable by the
|
||||
// collector (via naSave, for example) and that another Nasal thread
|
||||
// cannot or will not delete the reference to the data. 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. Note that naModLock() may need to
|
||||
// block to allow garbage collection to occur, and that garbage
|
||||
// collection by other threads may be blocked until naModUnlock() is
|
||||
// called. It must also be UNLOCKED by threads that hold a lock
|
||||
// already before making a naCall() or naContinue() call -- these
|
||||
// functions will attempt to acquire the lock again.
|
||||
void naModLock();
|
||||
void naModUnlock();
|
||||
|
||||
// Library utilities. Generate namespaces and add symbols.
|
||||
typedef struct { char* name; naCFunction func; } naCFuncItem;
|
||||
naRef naGenLib(naContext c, naCFuncItem *funcs);
|
||||
void naAddSym(naContext c, naRef ns, char *sym, naRef val);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include <setjmp.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "parse.h"
|
||||
|
||||
// Static precedence table, from low (loose binding, do first) to high
|
||||
// (tight binding, do last).
|
||||
enum { PREC_BINARY, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
|
||||
|
||||
#define MAX_PREC_TOKS 6
|
||||
struct precedence {
|
||||
int toks[MAX_PREC_TOKS];
|
||||
@@ -32,8 +31,10 @@ struct precedence {
|
||||
|
||||
void naParseError(struct Parser* p, char* msg, int line)
|
||||
{
|
||||
// Some errors (e.g. code generation of a null pointer) lack a
|
||||
// line number, so we throw -1 and set the line earlier.
|
||||
if(line > 0) p->errLine = line;
|
||||
p->err = msg;
|
||||
p->errLine = line;
|
||||
longjmp(p->jumpHandle, 1);
|
||||
}
|
||||
|
||||
@@ -205,11 +206,83 @@ static struct Token* emptyToken(struct Parser* p)
|
||||
return t;
|
||||
}
|
||||
|
||||
// Synthesize a curly brace token to wrap token t foward to the end of
|
||||
// "statement". FIXME: unify this with the addNewChild(), which does
|
||||
// very similar stuff.
|
||||
static void embrace(struct Parser* p, struct Token* t)
|
||||
{
|
||||
struct Token *b, *end = t;
|
||||
if(!t) return;
|
||||
while(end->next) {
|
||||
if(end->next->type == TOK_SEMI) {
|
||||
// Slurp up the semi, iff it is followed by an else/elsif,
|
||||
// otherwise leave it in place.
|
||||
if(end->next->next) {
|
||||
if(end->next->next->type == TOK_ELSE) end = end->next;
|
||||
if(end->next->next->type == TOK_ELSIF) end = end->next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(end->next->type == TOK_COMMA) break;
|
||||
if(end->next->type == TOK_ELSE) break;
|
||||
if(end->next->type == TOK_ELSIF) break;
|
||||
end = end->next;
|
||||
}
|
||||
b = emptyToken(p);
|
||||
b->type = TOK_LCURL;
|
||||
b->line = t->line;
|
||||
b->parent = t->parent;
|
||||
b->prev = t->prev;
|
||||
b->next = end->next;
|
||||
b->children = t;
|
||||
b->lastChild = end;
|
||||
if(t->prev) t->prev->next = b;
|
||||
else b->parent->children = b;
|
||||
if(end->next) end->next->prev = b;
|
||||
else b->parent->lastChild = b;
|
||||
t->prev = 0;
|
||||
end->next = 0;
|
||||
for(; t; t = t->next)
|
||||
t->parent = b;
|
||||
}
|
||||
|
||||
#define NEXT(t) (t ? t->next : 0)
|
||||
#define TYPE(t) (t ? t->type : -1)
|
||||
|
||||
static void fixBracelessBlocks(struct Parser* p, struct Token* t)
|
||||
{
|
||||
// Find the end, and march *backward*
|
||||
while(t && t->next) t = t->next;
|
||||
for(/**/; t; t=t->prev) {
|
||||
switch(t->type) {
|
||||
case TOK_FOR: case TOK_FOREACH: case TOK_FORINDEX: case TOK_WHILE:
|
||||
case TOK_IF: case TOK_ELSIF:
|
||||
if(TYPE(NEXT(t)) == TOK_LPAR && TYPE(NEXT(NEXT(t))) != TOK_LCURL)
|
||||
embrace(p, t->next->next);
|
||||
break;
|
||||
case TOK_ELSE:
|
||||
if(TYPE(NEXT(t)) != TOK_LCURL)
|
||||
embrace(p, t->next);
|
||||
break;
|
||||
case TOK_FUNC:
|
||||
if(TYPE(NEXT(t)) == TOK_LPAR) {
|
||||
if(TYPE(NEXT(NEXT(t))) != TOK_LCURL)
|
||||
embrace(p, NEXT(NEXT(t)));
|
||||
} else if(TYPE(NEXT(t)) != TOK_LCURL)
|
||||
embrace(p, t->next);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fixes up parenting for obvious parsing situations, like code blocks
|
||||
// being the child of a func keyword, etc...
|
||||
static void fixBlockStructure(struct Parser* p, struct Token* start)
|
||||
{
|
||||
struct Token *t, *c;
|
||||
fixBracelessBlocks(p, start);
|
||||
t = start;
|
||||
while(t) {
|
||||
switch(t->type) {
|
||||
@@ -287,8 +360,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(!t->next || t->next->type == TOK_SEMI || t->next->type == TOK_COMMA)
|
||||
addSemi = 0; // don't bother, no need
|
||||
if(addSemi) {
|
||||
struct Token* semi = emptyToken(p);
|
||||
semi->type = TOK_SEMI;
|
||||
@@ -297,6 +370,7 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
|
||||
semi->prev = t;
|
||||
semi->parent = t->parent;
|
||||
if(semi->next) semi->next->prev = semi;
|
||||
else semi->parent->lastChild = semi;
|
||||
t->next = semi;
|
||||
t = semi; // don't bother checking the new one
|
||||
}
|
||||
@@ -455,6 +529,8 @@ static struct Token* parsePrecedence(struct Parser* p,
|
||||
if(!top)
|
||||
return parsePrecedence(p, start, end, level+1);
|
||||
|
||||
top->rule = rule;
|
||||
|
||||
if(left) {
|
||||
left->next = right;
|
||||
left->prev = 0;
|
||||
@@ -508,7 +584,7 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
|
||||
// Catch parser errors here.
|
||||
*errLine = 0;
|
||||
if(setjmp(p.jumpHandle)) {
|
||||
c->error = p.err;
|
||||
strncpy(c->error, p.err, sizeof(c->error));
|
||||
*errLine = p.errLine;
|
||||
return naNil();
|
||||
}
|
||||
@@ -540,5 +616,3 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
|
||||
|
||||
return codeObj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,11 +19,15 @@ enum {
|
||||
TOK_FORINDEX
|
||||
};
|
||||
|
||||
// Precedence rules
|
||||
enum { PREC_BINARY=1, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
|
||||
|
||||
struct Token {
|
||||
int type;
|
||||
int line;
|
||||
char* str;
|
||||
int strlen;
|
||||
int rule;
|
||||
double num;
|
||||
struct Token* parent;
|
||||
struct Token* next;
|
||||
@@ -94,6 +98,7 @@ void naParseInit(struct Parser* p);
|
||||
void* naParseAlloc(struct Parser* p, int bytes);
|
||||
void naParseDestroy(struct Parser* p);
|
||||
void naLex(struct Parser* p);
|
||||
int naLexUtf8C(char* s, int len, int* used); /* in utf8lib.c */
|
||||
naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist);
|
||||
|
||||
void naParse(struct Parser* p);
|
||||
|
||||
@@ -14,13 +14,13 @@ static int fromnum(double val, unsigned char* s);
|
||||
int naStr_len(naRef s)
|
||||
{
|
||||
if(!IS_STR(s)) return 0;
|
||||
return s.ref.ptr.str->len;
|
||||
return PTR(s).str->len;
|
||||
}
|
||||
|
||||
char* naStr_data(naRef s)
|
||||
{
|
||||
if(!IS_STR(s)) return 0;
|
||||
return (char*)s.ref.ptr.str->data;
|
||||
return (char*)PTR(s).str->data;
|
||||
}
|
||||
|
||||
static void setlen(struct naStr* s, int sz)
|
||||
@@ -33,24 +33,24 @@ static void setlen(struct naStr* s, int sz)
|
||||
|
||||
naRef naStr_buf(naRef dst, int len)
|
||||
{
|
||||
setlen(dst.ref.ptr.str, len);
|
||||
naBZero(dst.ref.ptr.str->data, len);
|
||||
setlen(PTR(dst).str, len);
|
||||
naBZero(PTR(dst).str->data, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
naRef naStr_fromdata(naRef dst, char* data, int len)
|
||||
{
|
||||
if(!IS_STR(dst)) return naNil();
|
||||
setlen(dst.ref.ptr.str, len);
|
||||
memcpy(dst.ref.ptr.str->data, data, len);
|
||||
setlen(PTR(dst).str, len);
|
||||
memcpy(PTR(dst).str->data, data, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
naRef naStr_concat(naRef dest, naRef s1, naRef s2)
|
||||
{
|
||||
struct naStr* dst = dest.ref.ptr.str;
|
||||
struct naStr* a = s1.ref.ptr.str;
|
||||
struct naStr* b = s2.ref.ptr.str;
|
||||
struct naStr* dst = PTR(dest).str;
|
||||
struct naStr* a = PTR(s1).str;
|
||||
struct naStr* b = PTR(s2).str;
|
||||
if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil();
|
||||
setlen(dst, a->len + b->len);
|
||||
memcpy(dst->data, a->data, a->len);
|
||||
@@ -60,8 +60,8 @@ naRef naStr_concat(naRef dest, naRef s1, naRef s2)
|
||||
|
||||
naRef naStr_substr(naRef dest, naRef str, int start, int len)
|
||||
{
|
||||
struct naStr* dst = dest.ref.ptr.str;
|
||||
struct naStr* s = str.ref.ptr.str;
|
||||
struct naStr* dst = PTR(dest).str;
|
||||
struct naStr* s = PTR(str).str;
|
||||
if(!(IS_STR(dest)&&IS_STR(str))) return naNil();
|
||||
if(start + len > s->len) { dst->len = 0; dst->data = 0; return naNil(); }
|
||||
setlen(dst, len);
|
||||
@@ -71,8 +71,8 @@ naRef naStr_substr(naRef dest, naRef str, int start, int len)
|
||||
|
||||
int naStr_equal(naRef s1, naRef s2)
|
||||
{
|
||||
struct naStr* a = s1.ref.ptr.str;
|
||||
struct naStr* b = s2.ref.ptr.str;
|
||||
struct naStr* a = PTR(s1).str;
|
||||
struct naStr* b = PTR(s2).str;
|
||||
if(a->data == b->data) return 1;
|
||||
if(a->len != b->len) return 0;
|
||||
if(memcmp(a->data, b->data, a->len) == 0) return 1;
|
||||
@@ -81,7 +81,7 @@ int naStr_equal(naRef s1, naRef s2)
|
||||
|
||||
naRef naStr_fromnum(naRef dest, double num)
|
||||
{
|
||||
struct naStr* dst = dest.ref.ptr.str;
|
||||
struct naStr* dst = PTR(dest).str;
|
||||
unsigned char buf[DIGITS+8];
|
||||
setlen(dst, fromnum(num, buf));
|
||||
memcpy(dst->data, buf, dst->len);
|
||||
@@ -95,13 +95,13 @@ int naStr_parsenum(char* str, int len, double* result)
|
||||
|
||||
int naStr_tonum(naRef str, double* out)
|
||||
{
|
||||
return tonum(str.ref.ptr.str->data, str.ref.ptr.str->len, out);
|
||||
return tonum(PTR(str).str->data, PTR(str).str->len, out);
|
||||
}
|
||||
|
||||
int naStr_numeric(naRef str)
|
||||
{
|
||||
double dummy;
|
||||
return tonum(str.ref.ptr.str->data, str.ref.ptr.str->len, &dummy);
|
||||
return tonum(PTR(str).str->data, PTR(str).str->len, &dummy);
|
||||
}
|
||||
|
||||
void naStr_gcclean(struct naStr* str)
|
||||
|
||||
@@ -10,6 +10,12 @@ void* naNewLock()
|
||||
return lock;
|
||||
}
|
||||
|
||||
void naFreeLock(void* lock)
|
||||
{
|
||||
pthread_mutex_destroy(lock);
|
||||
naFree(lock);
|
||||
}
|
||||
|
||||
void naLock(void* lock)
|
||||
{
|
||||
pthread_mutex_lock((pthread_mutex_t*)lock);
|
||||
@@ -35,6 +41,14 @@ void* naNewSem()
|
||||
return sem;
|
||||
}
|
||||
|
||||
void naFreeSem(void* p)
|
||||
{
|
||||
struct naSem* sem = p;
|
||||
pthread_mutex_destroy(&sem->lock);
|
||||
pthread_cond_destroy(&sem->cvar);
|
||||
naFree(sem);
|
||||
}
|
||||
|
||||
void naSemDown(void* sh)
|
||||
{
|
||||
struct naSem* sem = (struct naSem*)sh;
|
||||
@@ -45,11 +59,11 @@ void naSemDown(void* sh)
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
}
|
||||
|
||||
void naSemUpAll(void* sh, int count)
|
||||
void naSemUp(void* sh, int count)
|
||||
{
|
||||
struct naSem* sem = (struct naSem*)sh;
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
sem->count = count;
|
||||
sem->count += count;
|
||||
pthread_cond_broadcast(&sem->cvar);
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
}
|
||||
|
||||
@@ -13,9 +13,11 @@ void* naNewLock()
|
||||
|
||||
void naLock(void* lock) { EnterCriticalSection((LPCRITICAL_SECTION)lock); }
|
||||
void naUnlock(void* lock) { LeaveCriticalSection((LPCRITICAL_SECTION)lock); }
|
||||
void naFreeLock(void* lock) { free(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); }
|
||||
void naSemUp(void* sem, int count) { ReleaseSemaphore(sem, count, 0); }
|
||||
void naFreeSem(void* sem) { ReleaseSemaphore(sem, 1, 0); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
103
simgear/nasal/threadlib.c
Normal file
103
simgear/nasal/threadlib.c
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "data.h"
|
||||
#include "code.h"
|
||||
|
||||
static void lockDestroy(void* lock) { naFreeLock(lock); }
|
||||
static naGhostType LockType = { lockDestroy };
|
||||
|
||||
static void semDestroy(void* sem) { naFreeSem(sem); }
|
||||
static naGhostType SemType = { semDestroy };
|
||||
|
||||
typedef struct {
|
||||
naContext ctx;
|
||||
naRef func;
|
||||
} ThreadData;
|
||||
|
||||
#ifdef _WIN32
|
||||
static DWORD WINAPI threadtop(LPVOID param)
|
||||
#else
|
||||
static void* threadtop(void* param)
|
||||
#endif
|
||||
{
|
||||
ThreadData* td = param;
|
||||
naCall(td->ctx, td->func, 0, 0, naNil(), naNil());
|
||||
naFreeContext(td->ctx);
|
||||
naFree(td);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static naRef f_newthread(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
ThreadData *td;
|
||||
if(argc < 1 || !naIsFunc(args[0]))
|
||||
naRuntimeError(c, "bad/missing argument to newthread");
|
||||
td = naAlloc(sizeof(*td));
|
||||
td->ctx = naNewContext();
|
||||
td->func = args[0];
|
||||
naTempSave(td->ctx, td->func);
|
||||
#ifdef _WIN32
|
||||
CreateThread(0, 0, threadtop, td, 0, 0);
|
||||
#else
|
||||
{ pthread_t t; pthread_create(&t, 0, threadtop, td); }
|
||||
#endif
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_newlock(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
return naNewGhost(c, &LockType, naNewLock());
|
||||
}
|
||||
|
||||
static naRef f_lock(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 0 && naGhost_type(args[0]) == &LockType)
|
||||
naLock(naGhost_ptr(args[0]));
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_unlock(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 0 && naGhost_type(args[0]) == &LockType)
|
||||
naUnlock(naGhost_ptr(args[0]));
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_newsem(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
return naNewGhost(c, &SemType, naNewSem());
|
||||
}
|
||||
|
||||
static naRef f_semdown(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 0 && naGhost_type(args[0]) == &SemType)
|
||||
naSemDown(naGhost_ptr(args[0]));
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_semup(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 0 && naGhost_type(args[0]) == &SemType)
|
||||
naSemUp(naGhost_ptr(args[0]), 1);
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "newthread", f_newthread },
|
||||
{ "newlock", f_newlock },
|
||||
{ "lock", f_lock },
|
||||
{ "unlock", f_unlock },
|
||||
{ "newsem", f_newsem },
|
||||
{ "semdown", f_semdown },
|
||||
{ "semup", f_semup },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
naRef naInit_thread(naContext c)
|
||||
{
|
||||
return naGenLib(c, funcs);
|
||||
}
|
||||
161
simgear/nasal/utf8lib.c
Normal file
161
simgear/nasal/utf8lib.c
Normal file
@@ -0,0 +1,161 @@
|
||||
#include <string.h>
|
||||
#include "nasal.h"
|
||||
#include "parse.h"
|
||||
|
||||
// bytes required to store a given character
|
||||
static int cbytes(unsigned int c)
|
||||
{
|
||||
static const int NB[] = { 0x7f, 0x07ff, 0xffff, 0x001fffff, 0x03ffffff };
|
||||
int i;
|
||||
for(i=0; i<(sizeof(NB)/sizeof(NB[0])) && c>NB[i]; i++) {}
|
||||
return i+1;
|
||||
}
|
||||
|
||||
// Returns a byte with the N high order bits set
|
||||
#define TOPBITS(n) ((unsigned char)(((signed char)0x80)>>((n)-1)))
|
||||
|
||||
// write a utf8 character, return bytes written or zero on error
|
||||
static int writec(unsigned int c, unsigned char* s, int len)
|
||||
{
|
||||
int i, n = cbytes(c);
|
||||
if(len < n) return 0;
|
||||
for(i=n-1; i>0; i--) {
|
||||
s[i] = 0x80 | (c & 0x3f);
|
||||
c >>= 6;
|
||||
}
|
||||
s[0] = (n > 1 ? TOPBITS(n) : 0) | c;
|
||||
return n;
|
||||
}
|
||||
|
||||
// read a utf8 character, or -1 on error.
|
||||
static int readc(unsigned char* s, int len, int* used)
|
||||
{
|
||||
int n, i, c;
|
||||
if(len > 0 && s[0] < 0x80) { *used = 1; return s[0]; }
|
||||
for(n=2; n<7; n++)
|
||||
if((s[0] & TOPBITS(n+1)) == TOPBITS(n))
|
||||
break;
|
||||
if(len < n || n > 6) return -1;
|
||||
c = s[0] & (~TOPBITS(n+1));
|
||||
for(i=1; i<n; i++) {
|
||||
if((s[i] >> 6) != 2) return -1;
|
||||
c = (c << 6) | (s[i] & 0x3f);
|
||||
}
|
||||
if(n != cbytes(c)) return -1;
|
||||
*used = n;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Public symbol used by the parser */
|
||||
int naLexUtf8C(char* s, int len, int* used)
|
||||
{ return readc((void*)s, len, used); }
|
||||
|
||||
static unsigned char* nthchar(unsigned char* s, int n, int* len)
|
||||
{
|
||||
int i, bytes;
|
||||
for(i=0; *len && i<n; i++) {
|
||||
if(readc(s, *len, &bytes) < 0) return 0;
|
||||
s += bytes; *len -= bytes;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static naRef f_chstr(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int n;
|
||||
naRef ch;
|
||||
unsigned char buf[6];
|
||||
if(argc < 1 || naIsNil(ch=naNumValue(args[0])))
|
||||
naRuntimeError(ctx, "bad/missing argument to utf8.chstr");
|
||||
n = writec((int)ch.num, buf, sizeof(buf));
|
||||
return naStr_fromdata(naNewString(ctx), (void*)buf, n);
|
||||
}
|
||||
|
||||
static naRef f_size(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
unsigned char* s;
|
||||
int sz=0, n, len;
|
||||
if(argc < 1 || !naIsString(args[0]))
|
||||
naRuntimeError(c, "bad/missing argument to utf8.strc");
|
||||
s = (void*)naStr_data(args[0]);
|
||||
len = naStr_len(args[0]);
|
||||
while(len > 0) {
|
||||
if(readc(s, len, &n) < 0)
|
||||
naRuntimeError(c, "utf8 encoding error in utf8.size");
|
||||
sz++; len -= n; s += n;
|
||||
}
|
||||
return naNum(sz);
|
||||
}
|
||||
|
||||
static naRef f_strc(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef idx;
|
||||
unsigned char* s;
|
||||
int len, c=0, bytes;
|
||||
if(argc < 2 || !naIsString(args[0]) || naIsNil(idx=naNumValue(args[1])))
|
||||
naRuntimeError(ctx, "bad/missing argument to utf8.strc");
|
||||
len = naStr_len(args[0]);
|
||||
s = nthchar((void*)naStr_data(args[0]), (int)idx.num, &len);
|
||||
if(!s || (c = readc(s, len, &bytes)) < 0)
|
||||
naRuntimeError(ctx, "utf8 encoding error in utf8.strc");
|
||||
return naNum(c);
|
||||
}
|
||||
|
||||
static naRef f_substr(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef start, end;
|
||||
int len;
|
||||
unsigned char *s, *s2;
|
||||
end = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||
if((argc < 2 || !naIsString(args[0]) || naIsNil(start=naNumValue(args[1])))
|
||||
|| (argc > 2 && naIsNil(end)))
|
||||
naRuntimeError(c, "bad/missing argument to utf8.substr");
|
||||
len = naStr_len(args[0]);
|
||||
if(!(s = nthchar((void*)naStr_data(args[0]), (int)start.num, &len)))
|
||||
naRuntimeError(c, "start index overrun in utf8.substr");
|
||||
if(!naIsNil(end)) {
|
||||
if(!(s2 = nthchar(s, (int)end.num, &len)))
|
||||
naRuntimeError(c, "end index overrun in utf8.substr");
|
||||
len = (int)(s2-s);
|
||||
}
|
||||
return naStr_fromdata(naNewString(c), (void*)s, len);
|
||||
}
|
||||
|
||||
static naRef f_validate(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef result, unkc=naNil();
|
||||
int len, len2, lenout=0, n;
|
||||
unsigned char *s, *s2, *buf;
|
||||
if(argc < 1 || !naIsString(args[0]) ||
|
||||
(argc > 1 && naIsNil(unkc=naNumValue(args[1]))))
|
||||
naRuntimeError(c, "bad/missing argument to utf8.strc");
|
||||
if(naIsNil(unkc)) unkc = naNum('?');
|
||||
len = naStr_len(args[0]);
|
||||
s = (void*)naStr_data(args[0]);
|
||||
len2 = 6*len; // max for ridiculous unkc values
|
||||
s2 = buf = naAlloc(len2);
|
||||
while(len > 0) {
|
||||
int c = readc(s, len, &n);
|
||||
if(c < 0) { c = (int)unkc.num; n = 1; }
|
||||
s += n; len -= n;
|
||||
n = writec(c, s2, len2);
|
||||
s2 += n; len2 -= n; lenout += n;
|
||||
}
|
||||
result = naStr_fromdata(naNewString(c), (char*)buf, lenout);
|
||||
naFree(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "chstr", f_chstr },
|
||||
{ "strc", f_strc },
|
||||
{ "substr", f_substr },
|
||||
{ "size", f_size },
|
||||
{ "validate", f_validate },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
naRef naInit_utf8(naContext c)
|
||||
{
|
||||
return naGenLib(c, funcs);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ void naVec_gcclean(struct naVec* v)
|
||||
naRef naVec_get(naRef v, int i)
|
||||
{
|
||||
if(IS_VEC(v)) {
|
||||
struct VecRec* r = v.ref.ptr.vec->rec;
|
||||
struct VecRec* r = PTR(v).vec->rec;
|
||||
if(r) {
|
||||
if(i < 0) i += r->size;
|
||||
if(i >= 0 && i < r->size) return r->array[i];
|
||||
@@ -40,7 +40,7 @@ naRef naVec_get(naRef v, int i)
|
||||
void naVec_set(naRef vec, int i, naRef o)
|
||||
{
|
||||
if(IS_VEC(vec)) {
|
||||
struct VecRec* r = vec.ref.ptr.vec->rec;
|
||||
struct VecRec* r = PTR(vec).vec->rec;
|
||||
if(r && i >= r->size) return;
|
||||
r->array[i] = o;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ void naVec_set(naRef vec, int i, naRef o)
|
||||
int naVec_size(naRef v)
|
||||
{
|
||||
if(IS_VEC(v)) {
|
||||
struct VecRec* r = v.ref.ptr.vec->rec;
|
||||
struct VecRec* r = PTR(v).vec->rec;
|
||||
return r ? r->size : 0;
|
||||
}
|
||||
return 0;
|
||||
@@ -58,10 +58,10 @@ int naVec_size(naRef v)
|
||||
int naVec_append(naRef vec, naRef o)
|
||||
{
|
||||
if(IS_VEC(vec)) {
|
||||
struct VecRec* r = vec.ref.ptr.vec->rec;
|
||||
struct VecRec* r = PTR(vec).vec->rec;
|
||||
while(!r || r->size >= r->alloced) {
|
||||
resize(vec.ref.ptr.vec);
|
||||
r = vec.ref.ptr.vec->rec;
|
||||
resize(PTR(vec).vec);
|
||||
r = PTR(vec).vec->rec;
|
||||
}
|
||||
r->array[r->size] = o;
|
||||
return r->size++;
|
||||
@@ -72,26 +72,25 @@ int naVec_append(naRef vec, naRef o)
|
||||
void naVec_setsize(naRef vec, int sz)
|
||||
{
|
||||
int i;
|
||||
struct VecRec* v = vec.ref.ptr.vec->rec;
|
||||
struct VecRec* v = PTR(vec).vec->rec;
|
||||
struct VecRec* nv = naAlloc(sizeof(struct VecRec) + sizeof(naRef) * sz);
|
||||
nv->size = sz;
|
||||
nv->alloced = sz;
|
||||
for(i=0; i<sz; i++)
|
||||
nv->array[i] = (v && i < v->size) ? v->array[i] : naNil();
|
||||
naFree(v);
|
||||
vec.ref.ptr.vec->rec = nv;
|
||||
naGC_swapfree((void**)&(PTR(vec).vec->rec), nv);
|
||||
}
|
||||
|
||||
naRef naVec_removelast(naRef vec)
|
||||
{
|
||||
naRef o;
|
||||
if(IS_VEC(vec)) {
|
||||
struct VecRec* v = vec.ref.ptr.vec->rec;
|
||||
struct VecRec* v = PTR(vec).vec->rec;
|
||||
if(!v || v->size == 0) return naNil();
|
||||
o = v->array[v->size - 1];
|
||||
v->size--;
|
||||
if(v->size < (v->alloced >> 1))
|
||||
resize(vec.ref.ptr.vec);
|
||||
resize(PTR(vec).vec);
|
||||
return o;
|
||||
}
|
||||
return naNil();
|
||||
|
||||
@@ -65,7 +65,6 @@ SGNotCondition::SGNotCondition (SGCondition * condition)
|
||||
|
||||
SGNotCondition::~SGNotCondition ()
|
||||
{
|
||||
delete _condition;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -86,8 +85,6 @@ SGAndCondition::SGAndCondition ()
|
||||
|
||||
SGAndCondition::~SGAndCondition ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _conditions.size(); i++)
|
||||
delete _conditions[i];
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -119,8 +116,6 @@ SGOrCondition::SGOrCondition ()
|
||||
|
||||
SGOrCondition::~SGOrCondition ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _conditions.size(); i++)
|
||||
delete _conditions[i];
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -398,13 +393,11 @@ SGConditional::SGConditional ()
|
||||
|
||||
SGConditional::~SGConditional ()
|
||||
{
|
||||
delete _condition;
|
||||
}
|
||||
|
||||
void
|
||||
SGConditional::setCondition (SGCondition * condition)
|
||||
{
|
||||
delete _condition;
|
||||
_condition = condition;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -28,7 +29,7 @@
|
||||
*
|
||||
* This class should migrate to somewhere more general.
|
||||
*/
|
||||
class SGCondition
|
||||
class SGCondition : public SGReferenced
|
||||
{
|
||||
public:
|
||||
SGCondition ();
|
||||
@@ -63,12 +64,11 @@ private:
|
||||
class SGNotCondition : public SGCondition
|
||||
{
|
||||
public:
|
||||
// transfer pointer ownership
|
||||
SGNotCondition (SGCondition * condition);
|
||||
virtual ~SGNotCondition ();
|
||||
virtual bool test () const;
|
||||
private:
|
||||
SGCondition * _condition;
|
||||
SGSharedPtr<SGCondition> _condition;
|
||||
};
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
// transfer pointer ownership
|
||||
virtual void addCondition (SGCondition * condition);
|
||||
private:
|
||||
vector<SGCondition *> _conditions;
|
||||
std::vector<SGSharedPtr<SGCondition> > _conditions;
|
||||
};
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
// transfer pointer ownership
|
||||
virtual void addCondition (SGCondition * condition);
|
||||
private:
|
||||
vector<SGCondition *> _conditions;
|
||||
std::vector<SGSharedPtr<SGCondition> > _conditions;
|
||||
};
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ private:
|
||||
* invoke the test() method whenever it needs to decide whether to
|
||||
* active itself, draw itself, and so on.
|
||||
*/
|
||||
class SGConditional
|
||||
class SGConditional : public SGReferenced
|
||||
{
|
||||
public:
|
||||
SGConditional ();
|
||||
@@ -156,7 +156,7 @@ public:
|
||||
virtual const SGCondition * getCondition () const { return _condition; }
|
||||
virtual bool test () const;
|
||||
private:
|
||||
SGCondition * _condition;
|
||||
SGSharedPtr<SGCondition> _condition;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -595,11 +595,11 @@ void
|
||||
SGPropertyNode::trace_write () const
|
||||
{
|
||||
#if PROPS_STANDALONE
|
||||
cerr << "TRACE: Write node " << getPath () << ", value\""
|
||||
cerr << "TRACE: Write node " << getPath () << ", value \""
|
||||
<< make_string() << '"' << endl;
|
||||
#else
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
|
||||
<< ", value\"" << make_string() << '"');
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
|
||||
<< ", value \"" << make_string() << '"');
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -613,7 +613,7 @@ SGPropertyNode::trace_read () const
|
||||
cerr << "TRACE: Write node " << getPath () << ", value \""
|
||||
<< make_string() << '"' << endl;
|
||||
#else
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
|
||||
<< ", value \"" << make_string() << '"');
|
||||
#endif
|
||||
}
|
||||
@@ -910,6 +910,22 @@ SGPropertyNode::getChildren (const char * name) const
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove this node and all children from nodes that link to them
|
||||
* in their path cache.
|
||||
*/
|
||||
void
|
||||
SGPropertyNode::remove_from_path_caches ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _children.size(); ++i)
|
||||
_children[i]->remove_from_path_caches();
|
||||
|
||||
for (unsigned int i = 0; i < _linkedNodes.size(); i++)
|
||||
_linkedNodes[i]->erase(this);
|
||||
_linkedNodes.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove child by position.
|
||||
*/
|
||||
@@ -927,8 +943,8 @@ SGPropertyNode::removeChild (int pos, bool keep)
|
||||
if (keep) {
|
||||
_removedChildren.push_back(node);
|
||||
}
|
||||
if (_path_cache)
|
||||
_path_cache->erase(node->getName()); // EMH - TODO: Take "index" into account!
|
||||
|
||||
node->remove_from_path_caches();
|
||||
node->setAttribute(REMOVED, true);
|
||||
node->clearValue();
|
||||
fireChildRemoved(node);
|
||||
@@ -939,7 +955,7 @@ SGPropertyNode::removeChild (int pos, bool keep)
|
||||
/**
|
||||
* Remove a child node
|
||||
*/
|
||||
SGPropertyNode_ptr
|
||||
SGPropertyNode_ptr
|
||||
SGPropertyNode::removeChild (const char * name, int index, bool keep)
|
||||
{
|
||||
SGPropertyNode_ptr ret;
|
||||
@@ -967,6 +983,24 @@ SGPropertyNode::removeChildren (const char * name, bool keep)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a linked node.
|
||||
*/
|
||||
bool
|
||||
SGPropertyNode::remove_linked_node (hash_table * node)
|
||||
{
|
||||
for (unsigned int i = 0; i < _linkedNodes.size(); i++) {
|
||||
if (_linkedNodes[i] == node) {
|
||||
vector<hash_table *>::iterator it = _linkedNodes.begin();
|
||||
it += i;
|
||||
_linkedNodes.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
SGPropertyNode::getDisplayName (bool simplify) const
|
||||
{
|
||||
@@ -2193,23 +2227,31 @@ SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SGPropertyNode::hash_table::bucket::erase (const char * key)
|
||||
bool
|
||||
SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
|
||||
{
|
||||
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];
|
||||
for (int i = 0; i < _length; i++) {
|
||||
if (_entries[i]->get_value() == node) {
|
||||
delete _entries[i];
|
||||
for (++i; i < _length; i++) {
|
||||
_entries[i-1] = _entries[i];
|
||||
}
|
||||
_length--;
|
||||
return true;
|
||||
}
|
||||
_length--;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SGPropertyNode::hash_table::bucket::clear (SGPropertyNode::hash_table * owner)
|
||||
{
|
||||
for (int i = 0; i < _length; i++) {
|
||||
SGPropertyNode * node = _entries[i]->get_value();
|
||||
if (node)
|
||||
node->remove_linked_node(owner);
|
||||
}
|
||||
}
|
||||
|
||||
SGPropertyNode::hash_table::hash_table ()
|
||||
: _data_length(0),
|
||||
@@ -2219,8 +2261,12 @@ SGPropertyNode::hash_table::hash_table ()
|
||||
|
||||
SGPropertyNode::hash_table::~hash_table ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _data_length; i++)
|
||||
delete _data[i];
|
||||
for (unsigned int i = 0; i < _data_length; i++) {
|
||||
if (_data[i]) {
|
||||
_data[i]->clear(this);
|
||||
delete _data[i];
|
||||
}
|
||||
}
|
||||
delete [] _data;
|
||||
}
|
||||
|
||||
@@ -2254,17 +2300,17 @@ SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
|
||||
}
|
||||
entry * e = _data[index]->get_entry(key, true);
|
||||
e->set_value(value);
|
||||
value->add_linked_node(this);
|
||||
}
|
||||
|
||||
void
|
||||
SGPropertyNode::hash_table::erase (const char * key)
|
||||
bool
|
||||
SGPropertyNode::hash_table::erase (SGPropertyNode * node)
|
||||
{
|
||||
if (_data_length == 0)
|
||||
return;
|
||||
unsigned int index = hashcode(key) % _data_length;
|
||||
if (_data[index] == 0)
|
||||
return;
|
||||
_data[index]->erase(key);
|
||||
for (unsigned int i = 0; i < _data_length; i++)
|
||||
if (_data[i] && _data[i]->erase(node))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
|
||||
@@ -1110,6 +1110,12 @@ public:
|
||||
void removeChangeListener (SGPropertyChangeListener * listener);
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of listeners.
|
||||
*/
|
||||
int nListeners () const { return _listeners ? _listeners->size() : 0; }
|
||||
|
||||
|
||||
/**
|
||||
* Fire a value change event to all listeners.
|
||||
*/
|
||||
@@ -1183,6 +1189,12 @@ private:
|
||||
void trace_write () const;
|
||||
|
||||
|
||||
/**
|
||||
* Remove this node from all nodes that link to it in their path cache.
|
||||
*/
|
||||
void remove_from_path_caches();
|
||||
|
||||
|
||||
class hash_table;
|
||||
|
||||
int _index;
|
||||
@@ -1193,6 +1205,7 @@ private:
|
||||
SGPropertyNode * _parent;
|
||||
vector<SGPropertyNode_ptr> _children;
|
||||
vector<SGPropertyNode_ptr> _removedChildren;
|
||||
vector<hash_table *> _linkedNodes;
|
||||
mutable string _path;
|
||||
mutable string _buffer;
|
||||
hash_table * _path_cache;
|
||||
@@ -1223,9 +1236,16 @@ private:
|
||||
vector <SGPropertyChangeListener *> * _listeners;
|
||||
|
||||
|
||||
/**
|
||||
* Register/unregister node that links to this node in its path cache.
|
||||
*/
|
||||
void add_linked_node (hash_table * node) { _linkedNodes.push_back(node); }
|
||||
bool remove_linked_node (hash_table * node);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A very simple hash table with no remove functionality.
|
||||
* A very simple hash table.
|
||||
*/
|
||||
class hash_table {
|
||||
public:
|
||||
@@ -1243,7 +1263,7 @@ private:
|
||||
void set_value (SGPropertyNode * value);
|
||||
private:
|
||||
string _key;
|
||||
SGSharedPtr<SGPropertyNode> _value;
|
||||
SGSharedPtr<SGPropertyNode> _value;
|
||||
};
|
||||
|
||||
|
||||
@@ -1255,7 +1275,8 @@ private:
|
||||
bucket ();
|
||||
~bucket ();
|
||||
entry * get_entry (const char * key, bool create = false);
|
||||
void erase(const char * key);
|
||||
bool erase (SGPropertyNode * node);
|
||||
void clear (hash_table * owner);
|
||||
private:
|
||||
int _length;
|
||||
entry ** _entries;
|
||||
@@ -1267,7 +1288,7 @@ private:
|
||||
~hash_table ();
|
||||
SGPropertyNode * get (const char * key);
|
||||
void put (const char * key, SGPropertyNode * value);
|
||||
void erase(const char * key);
|
||||
bool erase (SGPropertyNode * node);
|
||||
|
||||
private:
|
||||
unsigned int hashcode (const char * key);
|
||||
|
||||
@@ -229,6 +229,21 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
||||
} catch (sg_io_exception &e) {
|
||||
setException(e);
|
||||
}
|
||||
|
||||
const char *omit = atts.getValue("omit-node");
|
||||
if (omit && !strcmp(omit, "y")) {
|
||||
int nChildren = node->nChildren();
|
||||
for (int i = 0; i < nChildren; i++) {
|
||||
SGPropertyNode *src = node->getChild(i);
|
||||
const char *name = src->getName();
|
||||
int index = st.counters[name];
|
||||
st.counters[name]++;
|
||||
SGPropertyNode *dst = st.node->getChild(name, index, true);
|
||||
copyProperties(src, dst);
|
||||
}
|
||||
st.node->removeChild(node->getName(), node->getIndex(), false);
|
||||
node = st.node;
|
||||
}
|
||||
}
|
||||
|
||||
const char *type = atts.getValue("type");
|
||||
@@ -432,11 +447,11 @@ doIndent (ostream &output, int indent)
|
||||
|
||||
|
||||
static void
|
||||
writeAtts (ostream &output, const SGPropertyNode * node)
|
||||
writeAtts (ostream &output, const SGPropertyNode * node, bool forceindex)
|
||||
{
|
||||
int index = node->getIndex();
|
||||
|
||||
if (index != 0)
|
||||
if (index != 0 || forceindex)
|
||||
output << " n=\"" << index << '"';
|
||||
|
||||
#if 0
|
||||
@@ -484,13 +499,14 @@ writeNode (ostream &output, const SGPropertyNode * node,
|
||||
|
||||
const string name = node->getName();
|
||||
int nChildren = node->nChildren();
|
||||
bool node_has_value = false;
|
||||
|
||||
// If there is a literal value,
|
||||
// write it first.
|
||||
if (node->hasValue() && (write_all || node->getAttribute(archive_flag))) {
|
||||
doIndent(output, indent);
|
||||
output << '<' << name;
|
||||
writeAtts(output, node);
|
||||
writeAtts(output, node, nChildren != 0);
|
||||
if (node->isAlias() && node->getAliasTarget() != 0) {
|
||||
output << " alias=\"" << node->getAliasTarget()->getPath()
|
||||
<< "\"/>" << endl;
|
||||
@@ -501,13 +517,14 @@ writeNode (ostream &output, const SGPropertyNode * node,
|
||||
writeData(output, node->getStringValue());
|
||||
output << "</" << name << '>' << endl;
|
||||
}
|
||||
node_has_value = true;
|
||||
}
|
||||
|
||||
// If there are children, write them next.
|
||||
if (nChildren > 0) {
|
||||
doIndent(output, indent);
|
||||
output << '<' << name;
|
||||
writeAtts(output, node);
|
||||
writeAtts(output, node, node_has_value);
|
||||
output << '>' << endl;
|
||||
for (int i = 0; i < nChildren; i++)
|
||||
writeNode(output, node->getChild(i), write_all, indent + INDENT_STEP, archive_flag);
|
||||
@@ -540,6 +557,9 @@ void
|
||||
writeProperties (const string &file, const SGPropertyNode * start_node,
|
||||
bool write_all, SGPropertyNode::Attribute archive_flag)
|
||||
{
|
||||
SGPath path(file.c_str());
|
||||
path.create_dir(0777);
|
||||
|
||||
ofstream output(file.c_str());
|
||||
if (output.good()) {
|
||||
writeProperties(output, start_node, write_all, archive_flag);
|
||||
|
||||
@@ -19,6 +19,9 @@ waytest_LDADD = \
|
||||
$(top_builddir)/simgear/math/libsgmath.a \
|
||||
$(top_builddir)/simgear/debug/libsgdebug.a \
|
||||
$(top_builddir)/simgear/misc/libsgmisc.a \
|
||||
$(top_builddir)/simgear/props/libsgprops.a \
|
||||
$(top_builddir)/simgear/structure/libsgstructure.a \
|
||||
$(top_builddir)/simgear/xml/libsgxml.a \
|
||||
$(base_LIBS) \
|
||||
-lz
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ double SGRoute::distance_off_route( double x, double y ) const {
|
||||
int n1 = current_wp;
|
||||
sgdVec3 p, p0, p1, d;
|
||||
sgdSetVec3( p, x, y, 0.0 );
|
||||
sgdSetVec3( p0,
|
||||
sgdSetVec3( p0,
|
||||
route[n0].get_target_lon(), route[n0].get_target_lat(),
|
||||
0.0 );
|
||||
sgdSetVec3( p1,
|
||||
@@ -68,3 +68,50 @@ double SGRoute::distance_off_route( double x, double y ) const {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Update the length of the leg ending at waypoint index */
|
||||
void SGRoute::update_distance(int index)
|
||||
{
|
||||
SGWayPoint& curr = route[ index ];
|
||||
double course, dist;
|
||||
|
||||
if ( index == 0 ) {
|
||||
dist = 0;
|
||||
} else {
|
||||
const SGWayPoint& prev = route[ index - 1 ];
|
||||
curr.CourseAndDistance( prev, &course, &dist );
|
||||
}
|
||||
|
||||
curr.set_distance( dist );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add waypoint (default), or insert waypoint at position n.
|
||||
* @param wp a waypoint
|
||||
*/
|
||||
void SGRoute::add_waypoint( const SGWayPoint &wp, int n ) {
|
||||
int size = route.size();
|
||||
if ( n < 0 || n >= size ) {
|
||||
n = size;
|
||||
route.push_back( wp );
|
||||
} else {
|
||||
route.insert( route.begin() + n, 1, wp );
|
||||
// update distance of next leg if not at end of route
|
||||
update_distance( n + 1 );
|
||||
}
|
||||
update_distance( n );
|
||||
}
|
||||
|
||||
/** Delete waypoint with index n (last one if n < 0) */
|
||||
void SGRoute::delete_waypoint( int n ) {
|
||||
int size = route.size();
|
||||
if ( size == 0 )
|
||||
return;
|
||||
if ( n < 0 || n >= size )
|
||||
n = size - 1;
|
||||
|
||||
route.erase( route.begin() + n );
|
||||
// update distance of next leg if not at end of route
|
||||
if ( n < size - 1 )
|
||||
update_distance( n );
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ private:
|
||||
route_list route;
|
||||
int current_wp;
|
||||
|
||||
void update_distance(int index);
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
@@ -73,21 +75,7 @@ public:
|
||||
* Add waypoint (default), or insert waypoint at position n.
|
||||
* @param wp a waypoint
|
||||
*/
|
||||
void add_waypoint( const SGWayPoint &wp, int n = -1 ) {
|
||||
if ( n < 0 || n >= (int)route.size() )
|
||||
route.push_back( wp );
|
||||
else
|
||||
route.insert( route.begin() + n, 1, wp );
|
||||
|
||||
int size = route.size();
|
||||
if ( size > 1 ) {
|
||||
SGWayPoint next_to_last = route[ size - 2 ];
|
||||
double tmpd, tmpc;
|
||||
wp.CourseAndDistance( next_to_last, &tmpc, &tmpd );
|
||||
route[size - 1].set_distance( tmpd );
|
||||
}
|
||||
}
|
||||
|
||||
void add_waypoint( const SGWayPoint &wp, int n = -1 );
|
||||
/**
|
||||
* Get the number of waypoints (i.e. route length )
|
||||
* @return route length
|
||||
@@ -152,14 +140,7 @@ public:
|
||||
inline void delete_first() { delete_waypoint(0); }
|
||||
|
||||
/** Delete waypoint waypoint with index n (last one if n < 0) */
|
||||
void delete_waypoint( int n = 0 ) {
|
||||
if ( !route.size() )
|
||||
return;
|
||||
if ( n < 0 || n >= (int)route.size() )
|
||||
n = route.size() - 1;
|
||||
|
||||
route.erase( route.begin() + n );
|
||||
}
|
||||
void delete_waypoint( int n = 0 );
|
||||
|
||||
/**
|
||||
* Calculate perpendicular distance from the current route segment
|
||||
|
||||
@@ -8,8 +8,20 @@
|
||||
|
||||
SG_USING_STD(cout);
|
||||
SG_USING_STD(endl);
|
||||
|
||||
int main() {
|
||||
|
||||
void dump_route(const SGRoute& route, const char* message)
|
||||
{
|
||||
cout << "Route dump: " << message << endl;
|
||||
for (int i = 0; i < route.size(); i++) {
|
||||
const SGWayPoint wp = route.get_waypoint(i);
|
||||
cout << "\t#" << i << " " << wp.get_id() << " (" << wp.get_target_lat()
|
||||
<< ", " << wp.get_target_lon() << ") @" << wp.get_target_alt()
|
||||
<< " dist: " << wp.get_distance() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
SGRoute route;
|
||||
|
||||
route.add_waypoint( SGWayPoint(0, 0, 0, SGWayPoint::CARTESIAN, "Start") );
|
||||
@@ -17,7 +29,8 @@ int main() {
|
||||
route.add_waypoint( SGWayPoint(2, 0, 0, SGWayPoint::CARTESIAN, "2") );
|
||||
route.add_waypoint( SGWayPoint(2, 2, 0, SGWayPoint::CARTESIAN, "3") );
|
||||
route.add_waypoint( SGWayPoint(4, 2, 0, SGWayPoint::CARTESIAN, "4") );
|
||||
|
||||
|
||||
dump_route(route, "Init");
|
||||
route.set_current( 1 );
|
||||
|
||||
cout << "( 0.5, 0 ) = " << route.distance_off_route( 0.5, 0 ) << endl;
|
||||
@@ -29,5 +42,12 @@ int main() {
|
||||
cout << "( 2, 4 ) = " << route.distance_off_route( 2, 4 ) << endl;
|
||||
cout << "( 2.5, 4 ) = " << route.distance_off_route( 2.5, 4 ) << endl;
|
||||
|
||||
SGWayPoint wp2 = route.get_waypoint(2);
|
||||
route.delete_waypoint(2);
|
||||
dump_route(route, "removed WP2");
|
||||
|
||||
route.add_waypoint(wp2, 3);
|
||||
dump_route(route, "added back WP2 after WP3");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
includedir = @includedir@/scene
|
||||
|
||||
SUBDIRS = material model sky tgdb
|
||||
SUBDIRS = material model sky tgdb util
|
||||
|
||||
# lib_LIBRARIES = libsgscene.a
|
||||
|
||||
|
||||
@@ -37,14 +37,22 @@ SG_USING_STD(map);
|
||||
# include <math.h>
|
||||
#endif
|
||||
|
||||
#include <osg/CullFace>
|
||||
#include <osg/Material>
|
||||
#include <osg/ShadeModel>
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/Texture2D>
|
||||
#include <osgDB/ReadFile>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
|
||||
#include <simgear/scene/model/model.hxx>
|
||||
|
||||
#include "mat.hxx"
|
||||
|
||||
static map<string, ssgTexture *> _tex_cache;
|
||||
static map<string, ssgTexture *>::iterator _tex_cache_iter;
|
||||
static map<string, osg::ref_ptr<osg::Texture2D> > _tex_cache;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -56,7 +64,7 @@ SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props, cons
|
||||
{
|
||||
init();
|
||||
read_properties( fg_root, props, season );
|
||||
build_ssg_state( false );
|
||||
build_state( false );
|
||||
}
|
||||
|
||||
SGMaterial::SGMaterial( const string &texpath )
|
||||
@@ -66,13 +74,13 @@ SGMaterial::SGMaterial( const string &texpath )
|
||||
_internal_state st( NULL, texpath, false );
|
||||
_status.push_back( st );
|
||||
|
||||
build_ssg_state( true );
|
||||
build_state( true );
|
||||
}
|
||||
|
||||
SGMaterial::SGMaterial( ssgSimpleState *s )
|
||||
SGMaterial::SGMaterial( osg::StateSet *s )
|
||||
{
|
||||
init();
|
||||
set_ssg_state( s );
|
||||
set_state( s );
|
||||
}
|
||||
|
||||
SGMaterial::~SGMaterial (void)
|
||||
@@ -141,7 +149,7 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
|
||||
friction_factor = props->getDoubleValue("friction-factor", 1.0);
|
||||
rolling_friction = props->getDoubleValue("rolling-friction", 0.02);
|
||||
bumpiness = props->getDoubleValue("bumpiness", 0.0);
|
||||
load_resistence = props->getDoubleValue("load-resistence", 1e30);
|
||||
load_resistance = props->getDoubleValue("load-resistance", 1e30);
|
||||
|
||||
// Taken from default values as used in ac3d
|
||||
ambient[0] = props->getDoubleValue("ambient/r", 0.2);
|
||||
@@ -203,7 +211,7 @@ SGMaterial::init ()
|
||||
friction_factor = 1;
|
||||
rolling_friction = 0.02;
|
||||
bumpiness = 0;
|
||||
load_resistence = 1e30;
|
||||
load_resistance = 1e30;
|
||||
|
||||
shininess = 1.0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@@ -225,15 +233,15 @@ SGMaterial::load_texture ( int n )
|
||||
if ( !_status[i].texture_loaded ) {
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture "
|
||||
<< _status[i].texture_path );
|
||||
assignTexture(_status[i].state, _status[i].texture_path,
|
||||
wrapu, wrapv, mipmap );
|
||||
assignTexture(_status[i].state.get(), _status[i].texture_path,
|
||||
wrapu, wrapv, mipmap);
|
||||
_status[i].texture_loaded = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ssgSimpleState *
|
||||
osg::StateSet *
|
||||
SGMaterial::get_state (int n) const
|
||||
{
|
||||
if (_status.size() == 0) {
|
||||
@@ -241,80 +249,95 @@ SGMaterial::get_state (int n) const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssgSimpleState *st = (n >= 0) ? _status[n].state
|
||||
: _status[_current_ptr].state;
|
||||
((SGMaterial *)this)->_current_ptr += 1;
|
||||
osg::StateSet *st = (n >= 0) ? _status[n].state.get()
|
||||
: _status[_current_ptr].state.get();
|
||||
_current_ptr += 1;
|
||||
if (_current_ptr >= _status.size())
|
||||
((SGMaterial *)this)->_current_ptr = 0;
|
||||
_current_ptr = 0;
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SGMaterial::build_ssg_state( bool defer_tex_load )
|
||||
SGMaterial::build_state( bool defer_tex_load )
|
||||
{
|
||||
GLenum shade_model = GL_SMOOTH;
|
||||
|
||||
for (unsigned int i = 0; i < _status.size(); i++)
|
||||
{
|
||||
ssgSimpleState *state = new ssgSimpleState();
|
||||
osg::StateSet *stateSet = new osg::StateSet;
|
||||
stateSet->setUserData(new SGMaterialUserData(this));
|
||||
|
||||
// Set up the textured state
|
||||
state->setShadeModel( shade_model );
|
||||
state->enable( GL_LIGHTING );
|
||||
state->enable ( GL_CULL_FACE ) ;
|
||||
state->enable( GL_TEXTURE_2D );
|
||||
state->disable( GL_BLEND );
|
||||
state->disable( GL_ALPHA_TEST );
|
||||
osg::ShadeModel* shadeModel = new osg::ShadeModel;
|
||||
shadeModel->setMode(osg::ShadeModel::SMOOTH);
|
||||
stateSet->setAttribute(shadeModel);
|
||||
|
||||
osg::CullFace* cullFace = new osg::CullFace;
|
||||
cullFace->setMode(osg::CullFace::BACK);
|
||||
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
|
||||
stateSet->setAttribute(cullFace);
|
||||
|
||||
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
|
||||
|
||||
if ( !defer_tex_load ) {
|
||||
SG_LOG(SG_INPUT, SG_INFO, " " << _status[i].texture_path );
|
||||
assignTexture( state, _status[i].texture_path, wrapu, wrapv );
|
||||
assignTexture( stateSet, _status[i].texture_path, wrapu, wrapv);
|
||||
_status[i].texture_loaded = true;
|
||||
} else {
|
||||
_status[i].texture_loaded = false;
|
||||
}
|
||||
|
||||
state->enable( GL_COLOR_MATERIAL );
|
||||
state->setMaterial ( GL_AMBIENT,
|
||||
ambient[0], ambient[1],
|
||||
ambient[2], ambient[3] ) ;
|
||||
state->setMaterial ( GL_DIFFUSE,
|
||||
diffuse[0], diffuse[1],
|
||||
diffuse[2], diffuse[3] ) ;
|
||||
state->setMaterial ( GL_SPECULAR,
|
||||
specular[0], specular[1],
|
||||
specular[2], specular[3] ) ;
|
||||
state->setMaterial ( GL_EMISSION,
|
||||
emission[0], emission[1],
|
||||
emission[2], emission[3] ) ;
|
||||
state->setShininess ( shininess );
|
||||
osg::Material* material = new osg::Material;
|
||||
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
material->setAmbient(osg::Material::FRONT_AND_BACK, ambient.osg());
|
||||
material->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse.osg());
|
||||
material->setSpecular(osg::Material::FRONT_AND_BACK, specular.osg());
|
||||
material->setEmission(osg::Material::FRONT_AND_BACK, emission.osg());
|
||||
material->setShininess(osg::Material::FRONT_AND_BACK, shininess );
|
||||
stateSet->setAttribute(material);
|
||||
|
||||
_status[i].state = state;
|
||||
if (ambient[3] < 1 || diffuse[3] < 1 ||
|
||||
specular[3] < 1 || emission[3] < 1) {
|
||||
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
|
||||
} else {
|
||||
stateSet->setRenderingHint(osg::StateSet::OPAQUE_BIN);
|
||||
stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
|
||||
}
|
||||
|
||||
_status[i].state = stateSet;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SGMaterial::set_ssg_state( ssgSimpleState *s )
|
||||
void SGMaterial::set_state( osg::StateSet *s )
|
||||
{
|
||||
_status.push_back( _internal_state( s, "", true ) );
|
||||
}
|
||||
|
||||
void SGMaterial::assignTexture( ssgSimpleState *state, string &fname,
|
||||
void SGMaterial::assignTexture( osg::StateSet *state, const std::string &fname,
|
||||
int _wrapu, int _wrapv, int _mipmap )
|
||||
{
|
||||
map<string, osg::ref_ptr<osg::Texture2D> >::iterator _tex_cache_iter;
|
||||
_tex_cache_iter = _tex_cache.find(fname);
|
||||
if (_tex_cache_iter == _tex_cache.end())
|
||||
{
|
||||
state->setTexture((char *)fname.c_str(), _wrapu, _wrapv, _mipmap);
|
||||
_tex_cache[fname] = state->getTexture();
|
||||
osg::Texture2D* texture = SGLoadTexture2D(fname, _wrapu, _wrapv,
|
||||
mipmap ? -1 : 0);
|
||||
texture->setMaxAnisotropy( SGGetTextureFilter());
|
||||
state->setTextureAttributeAndModes(0, texture);
|
||||
_tex_cache[fname] = texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->setTexture(_tex_cache_iter->second);
|
||||
state->setTextureAttributeAndModes(0, _tex_cache_iter->second.get());
|
||||
// cout << "Cache hit: " << fname << endl;
|
||||
}
|
||||
osg::TexEnv* texEnv = new osg::TexEnv;
|
||||
texEnv->setMode(osg::TexEnv::MODULATE);
|
||||
state->setTextureAttributeAndModes(0, texEnv);
|
||||
}
|
||||
|
||||
SGMaterialGlyph* SGMaterial::get_glyph (const string& name) const
|
||||
@@ -338,5 +361,12 @@ SGMaterialGlyph::SGMaterialGlyph(SGPropertyNode *p) :
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SGSetTextureFilter( int max) {
|
||||
SGSceneFeatures::instance()->setTextureFilter( max);
|
||||
}
|
||||
|
||||
// end of mat.cxx
|
||||
int
|
||||
SGGetTextureFilter() {
|
||||
return SGSceneFeatures::instance()->getTextureFilter();
|
||||
}
|
||||
|
||||
@@ -38,12 +38,12 @@
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/StateSet>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/structure/ssgSharedPtr.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/scene/util/SGSceneFeatures.hxx>
|
||||
|
||||
#include "matmodel.hxx"
|
||||
|
||||
@@ -54,7 +54,6 @@ SG_USING_STD(map);
|
||||
|
||||
class SGMaterialGlyph;
|
||||
|
||||
|
||||
/**
|
||||
* A material in the scene graph.
|
||||
*
|
||||
@@ -93,15 +92,15 @@ public:
|
||||
|
||||
|
||||
/**
|
||||
* Construct a material around an existing SSG state.
|
||||
* Construct a material around an existing state.
|
||||
*
|
||||
* This constructor allows the application to create a custom,
|
||||
* low-level state for the scene graph and wrap a material around
|
||||
* it. Note: the pointer ownership is transferred to the material.
|
||||
*
|
||||
* @param s The SSG state for this material.
|
||||
* @param s The state for this material.
|
||||
*/
|
||||
SGMaterial( ssgSimpleState *s );
|
||||
SGMaterial( osg::StateSet *s );
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
@@ -122,11 +121,10 @@ public:
|
||||
*/
|
||||
bool load_texture (int n = -1);
|
||||
|
||||
|
||||
/**
|
||||
* Get the textured state.
|
||||
*/
|
||||
ssgSimpleState *get_state (int n = -1) const;
|
||||
osg::StateSet *get_state (int n = -1) const;
|
||||
|
||||
|
||||
/**
|
||||
@@ -178,9 +176,9 @@ public:
|
||||
double get_bumpiness () const { return bumpiness; }
|
||||
|
||||
/**
|
||||
* Get the load resistence
|
||||
* Get the load resistance
|
||||
*/
|
||||
double get_load_resistence () const { return load_resistence; }
|
||||
double get_load_resistance () const { return load_resistance; }
|
||||
|
||||
/**
|
||||
* Get the list of names for this material
|
||||
@@ -209,6 +207,20 @@ public:
|
||||
*/
|
||||
SGMaterialGlyph * get_glyph (const string& name) const;
|
||||
|
||||
void set_light_color(const SGVec4f& color)
|
||||
{ emission = color; }
|
||||
const SGVec4f& get_light_color() const
|
||||
{ return emission; }
|
||||
|
||||
SGVec2f get_tex_coord_scale() const
|
||||
{
|
||||
float tex_width = get_xsize();
|
||||
float tex_height = get_ysize();
|
||||
|
||||
return SGVec2f((0 < tex_width) ? 1000.0f/tex_width : 1.0f,
|
||||
(0 < tex_height) ? 1000.0f/tex_height : 1.0f);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -224,9 +236,9 @@ protected:
|
||||
protected:
|
||||
|
||||
struct _internal_state {
|
||||
_internal_state( ssgSimpleState *s, const string &t, bool l )
|
||||
_internal_state( osg::StateSet *s, const string &t, bool l )
|
||||
: state(s), texture_path(t), texture_loaded(l) {}
|
||||
ssgSharedPtr<ssgSimpleState> state;
|
||||
osg::ref_ptr<osg::StateSet> state;
|
||||
string texture_path;
|
||||
bool texture_loaded;
|
||||
};
|
||||
@@ -242,7 +254,7 @@ private:
|
||||
vector<_internal_state> _status;
|
||||
|
||||
// Round-robin counter
|
||||
unsigned int _current_ptr;
|
||||
mutable unsigned int _current_ptr;
|
||||
|
||||
// texture size
|
||||
double xsize, ysize;
|
||||
@@ -268,8 +280,8 @@ private:
|
||||
// the bumpiness of that surface material
|
||||
double bumpiness;
|
||||
|
||||
// the load resistence of that surface material
|
||||
double load_resistence;
|
||||
// the load resistance of that surface material
|
||||
double load_resistance;
|
||||
|
||||
// material properties
|
||||
SGVec4f ambient, diffuse, specular, emission;
|
||||
@@ -291,10 +303,10 @@ private:
|
||||
SGMaterial( const string &fg_root, const SGMaterial &mat ); // unimplemented
|
||||
|
||||
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 );
|
||||
void build_state( bool defer_tex_load );
|
||||
void set_state( osg::StateSet *s );
|
||||
|
||||
void assignTexture( ssgSimpleState *state, string &fname, int _wrapu = TRUE, int _wrapv = TRUE, int _mipmap = TRUE );
|
||||
void assignTexture( osg::StateSet *state, const std::string &fname, int _wrapu = TRUE, int _wrapv = TRUE, int _mipmap = TRUE );
|
||||
|
||||
};
|
||||
|
||||
@@ -311,7 +323,7 @@ protected:
|
||||
double _right;
|
||||
};
|
||||
|
||||
class SGMaterialUserData : public ssgBase {
|
||||
class SGMaterialUserData : public osg::Referenced {
|
||||
public:
|
||||
SGMaterialUserData(const SGMaterial* material) :
|
||||
mMaterial(material)
|
||||
@@ -322,4 +334,10 @@ private:
|
||||
SGSharedPtr<const SGMaterial> mMaterial;
|
||||
};
|
||||
|
||||
void
|
||||
SGSetTextureFilter( int max);
|
||||
|
||||
int
|
||||
SGGetTextureFilter();
|
||||
|
||||
#endif // _SG_MAT_HXX
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <plib/ssg.h>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
@@ -44,6 +42,19 @@
|
||||
#include <string.h>
|
||||
#include STL_STRING
|
||||
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/CullFace>
|
||||
#include <osg/Material>
|
||||
#include <osg/Point>
|
||||
#include <osg/PointSprite>
|
||||
#include <osg/PolygonMode>
|
||||
#include <osg/PolygonOffset>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/TexGen>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
@@ -57,166 +68,10 @@
|
||||
SG_USING_NAMESPACE(std);
|
||||
SG_USING_STD(string);
|
||||
|
||||
|
||||
// FIXME: should make this configurable
|
||||
static const bool sprite_lighting = true;
|
||||
|
||||
|
||||
// Constructor
|
||||
SGMaterialLib::SGMaterialLib ( void ) {
|
||||
}
|
||||
|
||||
|
||||
#if 0 // debugging infrastructure
|
||||
static int gen_test_light_map() {
|
||||
static const int env_tex_res = 32;
|
||||
int half_res = env_tex_res / 2;
|
||||
unsigned char env_map[env_tex_res][env_tex_res][4];
|
||||
GLuint tex_name;
|
||||
|
||||
for ( int i = 0; i < env_tex_res; ++i ) {
|
||||
for ( int j = 0; j < env_tex_res; ++j ) {
|
||||
double x = (i - half_res) / (double)half_res;
|
||||
double y = (j - half_res) / (double)half_res;
|
||||
double dist = sqrt(x*x + y*y);
|
||||
if ( dist > 1.0 ) { dist = 1.0; }
|
||||
|
||||
// cout << x << "," << y << " " << (int)(dist * 255) << ","
|
||||
// << (int)((1.0 - dist) * 255) << endl;
|
||||
env_map[i][j][0] = (int)(dist * 255);
|
||||
env_map[i][j][1] = (int)((1.0 - dist) * 255);
|
||||
env_map[i][j][2] = 0;
|
||||
env_map[i][j][3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
||||
glGenTextures( 1, &tex_name );
|
||||
glBindTexture( GL_TEXTURE_2D, tex_name );
|
||||
|
||||
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 );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
|
||||
|
||||
return tex_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// generate a light sprite texture map
|
||||
static int gen_standard_light_sprite( int r, int g, int b, int alpha ) {
|
||||
const int env_tex_res = 32;
|
||||
int half_res = env_tex_res / 2;
|
||||
unsigned char env_map[env_tex_res][env_tex_res][4];
|
||||
GLuint tex_name;
|
||||
|
||||
for ( int i = 0; i < env_tex_res; ++i ) {
|
||||
for ( int j = 0; j < env_tex_res; ++j ) {
|
||||
double x = (i - half_res) / (double)half_res;
|
||||
double y = (j - half_res) / (double)half_res;
|
||||
double dist = sqrt(x*x + y*y);
|
||||
if ( dist > 1.0 ) { dist = 1.0; }
|
||||
double bright = cos( dist * SGD_PI_2 );
|
||||
if ( bright < 0.01 ) { bright = 0.0; }
|
||||
env_map[i][j][0] = r;
|
||||
env_map[i][j][1] = g;
|
||||
env_map[i][j][2] = b;
|
||||
env_map[i][j][3] = (int)(bright * alpha);
|
||||
}
|
||||
}
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
||||
glGenTextures( 1, &tex_name );
|
||||
glBindTexture( GL_TEXTURE_2D, tex_name );
|
||||
|
||||
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 );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
|
||||
|
||||
return tex_name;
|
||||
}
|
||||
|
||||
|
||||
// generate standard colored directional light environment texture map
|
||||
static int gen_standard_dir_light_map( int r, int g, int b, int alpha ) {
|
||||
const int env_tex_res = 32;
|
||||
int half_res = env_tex_res / 2;
|
||||
unsigned char env_map[env_tex_res][env_tex_res][4];
|
||||
GLuint tex_name;
|
||||
|
||||
for ( int i = 0; i < env_tex_res; ++i ) {
|
||||
for ( int j = 0; j < env_tex_res; ++j ) {
|
||||
double x = (i - half_res) / (double)half_res;
|
||||
double y = (j - half_res) / (double)half_res;
|
||||
double dist = sqrt(x*x + y*y);
|
||||
if ( dist > 1.0 ) { dist = 1.0; }
|
||||
double bright = cos( dist * SGD_PI_2 );
|
||||
if ( bright < 0.3 ) { bright = 0.3; }
|
||||
env_map[i][j][0] = r;
|
||||
env_map[i][j][1] = g;
|
||||
env_map[i][j][2] = b;
|
||||
env_map[i][j][3] = (int)(bright * alpha);
|
||||
}
|
||||
}
|
||||
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
||||
glGenTextures( 1, &tex_name );
|
||||
glBindTexture( GL_TEXTURE_2D, tex_name );
|
||||
|
||||
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 );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
|
||||
|
||||
return tex_name;
|
||||
}
|
||||
|
||||
|
||||
// generate standard colored directional light environment texture map
|
||||
static int gen_taxiway_dir_light_map( int r, int g, int b, int alpha ) {
|
||||
const int env_tex_res = 32;
|
||||
int half_res = env_tex_res / 2;
|
||||
unsigned char env_map[env_tex_res][env_tex_res][4];
|
||||
GLuint tex_name;
|
||||
|
||||
for ( int i = 0; i < env_tex_res; ++i ) {
|
||||
for ( int j = 0; j < env_tex_res; ++j ) {
|
||||
double x = (i - half_res) / (double)half_res;
|
||||
double y = (j - half_res) / (double)half_res;
|
||||
double tmp = sqrt(x*x + y*y);
|
||||
double dist = tmp * tmp;
|
||||
if ( dist > 1.0 ) { dist = 1.0; }
|
||||
double bright = sin( dist * SGD_PI_2 );
|
||||
if ( bright < 0.2 ) { bright = 0.2; }
|
||||
env_map[i][j][0] = r;
|
||||
env_map[i][j][1] = g;
|
||||
env_map[i][j][2] = b;
|
||||
env_map[i][j][3] = (int)(bright * alpha);
|
||||
}
|
||||
}
|
||||
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
||||
glGenTextures( 1, &tex_name );
|
||||
glBindTexture( GL_TEXTURE_2D, tex_name );
|
||||
|
||||
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 );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
|
||||
|
||||
return tex_name;
|
||||
}
|
||||
|
||||
|
||||
// Load a library of material properties
|
||||
bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char *season ) {
|
||||
|
||||
@@ -231,13 +86,11 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char
|
||||
throw;
|
||||
}
|
||||
|
||||
SGSharedPtr<SGMaterial> m;
|
||||
|
||||
int nMaterials = materials.nChildren();
|
||||
for (int i = 0; i < nMaterials; i++) {
|
||||
const SGPropertyNode * node = materials.getChild(i);
|
||||
if (!strcmp(node->getName(), "material")) {
|
||||
m = new SGMaterial( fg_root, node, season );
|
||||
SGSharedPtr<SGMaterial> m = new SGMaterial(fg_root, node, season);
|
||||
|
||||
vector<SGPropertyNode_ptr>names = node->getChildren("name");
|
||||
for ( unsigned int j = 0; j < names.size(); j++ ) {
|
||||
@@ -254,340 +107,6 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char
|
||||
}
|
||||
}
|
||||
|
||||
// hard coded ground light state
|
||||
ssgSimpleState *gnd_lights = new ssgSimpleState;
|
||||
gnd_lights->disable( GL_TEXTURE_2D );
|
||||
gnd_lights->enable( GL_CULL_FACE );
|
||||
gnd_lights->enable( GL_COLOR_MATERIAL );
|
||||
gnd_lights->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
|
||||
gnd_lights->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
|
||||
gnd_lights->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
|
||||
gnd_lights->enable( GL_BLEND );
|
||||
gnd_lights->disable( GL_ALPHA_TEST );
|
||||
gnd_lights->disable( GL_LIGHTING );
|
||||
m = new SGMaterial( gnd_lights );
|
||||
m->add_name("GROUND_LIGHTS");
|
||||
matlib["GROUND_LIGHTS"] = m;
|
||||
|
||||
GLuint tex_name;
|
||||
|
||||
// hard coded runway white light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 235, 235, 195, 255 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 235, 235, 195, 255 );
|
||||
}
|
||||
ssgSimpleState *rwy_white_lights = new ssgSimpleState();
|
||||
rwy_white_lights->disable( GL_LIGHTING );
|
||||
rwy_white_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_white_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_white_lights->enable( GL_BLEND );
|
||||
rwy_white_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_white_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_white_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_white_lights );
|
||||
m->add_name("RWY_WHITE_LIGHTS");
|
||||
matlib["RWY_WHITE_LIGHTS"] = m;
|
||||
// For backwards compatibility ... remove someday
|
||||
m->add_name("RUNWAY_LIGHTS");
|
||||
matlib["RUNWAY_LIGHTS"] = m;
|
||||
m->add_name("RWY_LIGHTS");
|
||||
matlib["RWY_LIGHTS"] = m;
|
||||
// end of backwards compatitibilty
|
||||
|
||||
// hard coded runway medium intensity white light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 235, 235, 195, 205 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 235, 235, 195, 205 );
|
||||
}
|
||||
ssgSimpleState *rwy_white_medium_lights = new ssgSimpleState();
|
||||
rwy_white_medium_lights->disable( GL_LIGHTING );
|
||||
rwy_white_medium_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_white_medium_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_white_medium_lights->enable( GL_BLEND );
|
||||
rwy_white_medium_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_white_medium_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_white_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_medium_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_white_medium_lights );
|
||||
m->add_name("RWY_WHITE_MEDIUM_LIGHTS");
|
||||
matlib["RWY_WHITE_MEDIUM_LIGHTS"] = m;
|
||||
|
||||
// hard coded runway low intensity white light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 235, 235, 195, 155 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 235, 235, 195, 155 );
|
||||
}
|
||||
ssgSimpleState *rwy_white_low_lights = new ssgSimpleState();
|
||||
rwy_white_low_lights->disable( GL_LIGHTING );
|
||||
rwy_white_low_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_white_low_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_white_low_lights->enable( GL_BLEND );
|
||||
rwy_white_low_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_white_low_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_white_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_low_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_white_low_lights );
|
||||
m->add_name("RWY_WHITE_LOW_LIGHTS");
|
||||
matlib["RWY_WHITE_LOW_LIGHTS"] = m;
|
||||
|
||||
// hard coded runway yellow light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 235, 215, 20, 255 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 235, 215, 20, 255 );
|
||||
}
|
||||
ssgSimpleState *rwy_yellow_lights = new ssgSimpleState();
|
||||
rwy_yellow_lights->disable( GL_LIGHTING );
|
||||
rwy_yellow_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_yellow_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_yellow_lights->enable( GL_BLEND );
|
||||
rwy_yellow_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_yellow_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_yellow_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_yellow_lights );
|
||||
m->add_name("RWY_YELLOW_LIGHTS");
|
||||
matlib["RWY_YELLOW_LIGHTS"] = m;
|
||||
|
||||
// hard coded runway medium intensity yellow light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 235, 215, 20, 205 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 235, 215, 20, 205 );
|
||||
}
|
||||
ssgSimpleState *rwy_yellow_medium_lights = new ssgSimpleState();
|
||||
rwy_yellow_medium_lights->disable( GL_LIGHTING );
|
||||
rwy_yellow_medium_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_yellow_medium_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_yellow_medium_lights->enable( GL_BLEND );
|
||||
rwy_yellow_medium_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_yellow_medium_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_yellow_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_medium_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_yellow_medium_lights );
|
||||
m->add_name("RWY_YELLOW_MEDIUM_LIGHTS");
|
||||
matlib["RWY_YELLOW_MEDIUM_LIGHTS"] = m;
|
||||
|
||||
// hard coded runway low intensity yellow light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 235, 215, 20, 155 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 235, 215, 20, 155 );
|
||||
}
|
||||
ssgSimpleState *rwy_yellow_low_lights = new ssgSimpleState();
|
||||
rwy_yellow_low_lights->disable( GL_LIGHTING );
|
||||
rwy_yellow_low_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_yellow_low_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_yellow_low_lights->enable( GL_BLEND );
|
||||
rwy_yellow_low_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_yellow_low_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_yellow_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_low_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_yellow_low_lights );
|
||||
m->add_name("RWY_YELLOW_LOW_LIGHTS");
|
||||
matlib["RWY_YELLOW_LOW_LIGHTS"] = m;
|
||||
|
||||
// hard coded runway red light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 235, 90, 90, 255 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 235, 90, 90, 255 );
|
||||
}
|
||||
ssgSimpleState *rwy_red_lights = new ssgSimpleState();
|
||||
rwy_red_lights->disable( GL_LIGHTING );
|
||||
rwy_red_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_red_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_red_lights->enable( GL_BLEND );
|
||||
rwy_red_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_red_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_red_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_red_lights );
|
||||
m->add_name("RWY_RED_LIGHTS");
|
||||
matlib["RWY_RED_LIGHTS"] = m;
|
||||
|
||||
// hard coded medium intensity runway red light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 235, 90, 90, 205 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 235, 90, 90, 205 );
|
||||
}
|
||||
ssgSimpleState *rwy_red_medium_lights = new ssgSimpleState();
|
||||
rwy_red_medium_lights->disable( GL_LIGHTING );
|
||||
rwy_red_medium_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_red_medium_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_red_medium_lights->enable( GL_BLEND );
|
||||
rwy_red_medium_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_red_medium_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_red_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_medium_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_red_medium_lights );
|
||||
m->add_name("RWY_RED_MEDIUM_LIGHTS");
|
||||
matlib["RWY_RED_MEDIUM_LIGHTS"] = m;
|
||||
|
||||
// hard coded low intensity runway red light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 235, 90, 90, 155 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 235, 90, 90, 155 );
|
||||
}
|
||||
ssgSimpleState *rwy_red_low_lights = new ssgSimpleState();
|
||||
rwy_red_low_lights->disable( GL_LIGHTING );
|
||||
rwy_red_low_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_red_low_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_red_low_lights->enable( GL_BLEND );
|
||||
rwy_red_low_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_red_low_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_red_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_low_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_red_low_lights );
|
||||
m->add_name("RWY_RED_LOW_LIGHTS");
|
||||
matlib["RWY_RED_LOW_LIGHTS"] = m;
|
||||
|
||||
// hard coded runway green light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 20, 235, 20, 255 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 20, 235, 20, 255 );
|
||||
}
|
||||
ssgSimpleState *rwy_green_lights = new ssgSimpleState();
|
||||
rwy_green_lights->disable( GL_LIGHTING );
|
||||
rwy_green_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_green_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_green_lights->enable( GL_BLEND );
|
||||
rwy_green_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_green_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_green_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_green_lights );
|
||||
m->add_name("RWY_GREEN_LIGHTS");
|
||||
matlib["RWY_GREEN_LIGHTS"] = m;
|
||||
|
||||
// hard coded medium intensity runway green light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 20, 235, 20, 205 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 20, 235, 20, 205 );
|
||||
}
|
||||
ssgSimpleState *rwy_green_medium_lights = new ssgSimpleState();
|
||||
rwy_green_medium_lights->disable( GL_LIGHTING );
|
||||
rwy_green_medium_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_green_medium_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_green_medium_lights->enable( GL_BLEND );
|
||||
rwy_green_medium_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_green_medium_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_green_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_medium_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_green_medium_lights );
|
||||
m->add_name("RWY_GREEN_MEDIUM_LIGHTS");
|
||||
matlib["RWY_GREEN_MEDIUM_LIGHTS"] = m;
|
||||
|
||||
// hard coded low intensity runway green light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 20, 235, 20, 155 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 20, 235, 20, 155 );
|
||||
}
|
||||
ssgSimpleState *rwy_green_low_lights = new ssgSimpleState();
|
||||
rwy_green_low_lights->disable( GL_LIGHTING );
|
||||
rwy_green_low_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_green_low_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_green_low_lights->enable( GL_BLEND );
|
||||
rwy_green_low_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_green_low_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_green_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_low_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_green_low_lights );
|
||||
m->add_name("RWY_GREEN_LOW_LIGHTS");
|
||||
matlib["RWY_GREEN_LOW_LIGHTS"] = m;
|
||||
m->add_name("RWY_GREEN_TAXIWAY_LIGHTS");
|
||||
matlib["RWY_GREEN_TAXIWAY_LIGHTS"] = m;
|
||||
|
||||
// hard coded low intensity taxiway blue light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 90, 90, 235, 205 );
|
||||
} else {
|
||||
tex_name = gen_taxiway_dir_light_map( 90, 90, 235, 205 );
|
||||
}
|
||||
ssgSimpleState *taxiway_blue_low_lights = new ssgSimpleState();
|
||||
taxiway_blue_low_lights->disable( GL_LIGHTING );
|
||||
taxiway_blue_low_lights->enable ( GL_CULL_FACE ) ;
|
||||
taxiway_blue_low_lights->enable( GL_TEXTURE_2D );
|
||||
taxiway_blue_low_lights->enable( GL_BLEND );
|
||||
taxiway_blue_low_lights->enable( GL_ALPHA_TEST );
|
||||
taxiway_blue_low_lights->enable( GL_COLOR_MATERIAL );
|
||||
taxiway_blue_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
taxiway_blue_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
taxiway_blue_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
taxiway_blue_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
taxiway_blue_low_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( taxiway_blue_low_lights );
|
||||
m->add_name("RWY_BLUE_TAXIWAY_LIGHTS");
|
||||
matlib["RWY_BLUE_TAXIWAY_LIGHTS"] = m;
|
||||
|
||||
// hard coded runway vasi light state
|
||||
if ( sprite_lighting ) {
|
||||
tex_name = gen_standard_light_sprite( 235, 235, 195, 255 );
|
||||
} else {
|
||||
tex_name = gen_standard_dir_light_map( 235, 235, 195, 255 );
|
||||
}
|
||||
ssgSimpleState *rwy_vasi_lights = new ssgSimpleState();
|
||||
rwy_vasi_lights->disable( GL_LIGHTING );
|
||||
rwy_vasi_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_vasi_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_vasi_lights->enable( GL_BLEND );
|
||||
rwy_vasi_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_vasi_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_vasi_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_vasi_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_vasi_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_vasi_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
// rwy_vasi_lights->setTexture( gen_vasi_light_map_old() );
|
||||
rwy_vasi_lights->setTexture( tex_name );
|
||||
m = new SGMaterial( rwy_vasi_lights );
|
||||
m->add_name("RWY_VASI_LIGHTS");
|
||||
matlib["RWY_VASI_LIGHTS"] = m;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -621,13 +140,13 @@ bool SGMaterialLib::add_item ( const string &mat_name, const string &full_path )
|
||||
|
||||
|
||||
// Load a library of material properties
|
||||
bool SGMaterialLib::add_item ( const string &mat_name, ssgSimpleState *state )
|
||||
bool SGMaterialLib::add_item ( const string &mat_name, osg::StateSet *state )
|
||||
{
|
||||
matlib[mat_name] = new SGMaterial( state );
|
||||
matlib[mat_name]->add_name(mat_name);
|
||||
|
||||
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material given a premade "
|
||||
<< "ssgSimpleState = " << mat_name );
|
||||
<< "osg::StateSet = " << mat_name );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -664,17 +183,18 @@ void SGMaterialLib::load_next_deferred() {
|
||||
}
|
||||
}
|
||||
|
||||
// Return the material from that given leaf
|
||||
const SGMaterial* SGMaterialLib::findMaterial(/*const*/ssgLeaf* leaf) const
|
||||
const SGMaterial*
|
||||
SGMaterialLib::findMaterial(const osg::StateSet* stateSet) const
|
||||
{
|
||||
if (!leaf)
|
||||
if (!stateSet)
|
||||
return 0;
|
||||
|
||||
ssgBase* base = leaf->getUserData();
|
||||
const osg::Referenced* base = stateSet->getUserData();
|
||||
if (!base)
|
||||
return 0;
|
||||
|
||||
SGMaterialUserData* matUserData = dynamic_cast<SGMaterialUserData*>(base);
|
||||
const SGMaterialUserData* matUserData
|
||||
= dynamic_cast<const SGMaterialUserData*>(base);
|
||||
if (!matUserData)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
#include <map> // STL associative "array"
|
||||
#include <vector> // STL "array"
|
||||
|
||||
#include <plib/ssg.h> // plib include
|
||||
|
||||
#include <osg/Node>
|
||||
#include <osg/StateSet>
|
||||
|
||||
class SGMaterial;
|
||||
|
||||
@@ -47,14 +47,13 @@ SG_USING_STD(map);
|
||||
SG_USING_STD(vector);
|
||||
SG_USING_STD(less);
|
||||
|
||||
|
||||
// Material management class
|
||||
class SGMaterialLib {
|
||||
|
||||
private:
|
||||
|
||||
// associative array of materials
|
||||
typedef map < string, SGSharedPtr<SGMaterial>, less<string> > material_map;
|
||||
typedef map < string, SGSharedPtr<SGMaterial> > material_map;
|
||||
typedef material_map::iterator material_map_iterator;
|
||||
typedef material_map::const_iterator const_material_map_iterator;
|
||||
|
||||
@@ -71,7 +70,7 @@ public:
|
||||
// Add the named texture with default properties
|
||||
bool add_item( const string &tex_path );
|
||||
bool add_item( const string &mat_name, const string &tex_path );
|
||||
bool add_item( const string &mat_name, ssgSimpleState *state );
|
||||
bool add_item( const string &mat_name, osg::StateSet *state );
|
||||
|
||||
// find a material record by material name
|
||||
SGMaterial *find( const string& material );
|
||||
@@ -87,7 +86,7 @@ public:
|
||||
material_map_iterator end() { return matlib.end(); }
|
||||
const_material_map_iterator end() const { return matlib.end(); }
|
||||
|
||||
const SGMaterial* findMaterial(/*const*/ssgLeaf* leaf) const;
|
||||
const SGMaterial* findMaterial(const osg::StateSet* stateSet) const;
|
||||
|
||||
// Destructor
|
||||
~SGMaterialLib ( void );
|
||||
|
||||
@@ -30,7 +30,11 @@
|
||||
#include <map>
|
||||
SG_USING_STD(map);
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/Group>
|
||||
#include <osg/LOD>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/Transform>
|
||||
|
||||
#ifdef SG_MATH_EXCEPTION_CLASH
|
||||
# include <math.h>
|
||||
@@ -120,22 +124,6 @@ SGMatModel::get_model_count( SGModelLib *modellib,
|
||||
return _models.size();
|
||||
}
|
||||
|
||||
static void
|
||||
setAlphaClampToBranch( ssgBranch *b, float clamp )
|
||||
{
|
||||
int nb = b->getNumKids();
|
||||
for (int i = 0; i<nb; i++) {
|
||||
ssgEntity *e = b->getKid(i);
|
||||
if (e->isAKindOf(ssgTypeLeaf())) {
|
||||
ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
|
||||
s->enable( GL_ALPHA_TEST );
|
||||
s->setAlphaClamp( clamp );
|
||||
} else if (e->isAKindOf(ssgTypeBranch())) {
|
||||
setAlphaClampToBranch( (ssgBranch*)e, clamp );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
SGMatModel::load_models ( SGModelLib *modellib,
|
||||
const string &fg_root,
|
||||
@@ -145,7 +133,7 @@ SGMatModel::load_models ( SGModelLib *modellib,
|
||||
// Load model only on demand
|
||||
if (!_models_loaded) {
|
||||
for (unsigned int i = 0; i < _paths.size(); i++) {
|
||||
ssgEntity *entity = modellib->load_model( fg_root, _paths[i],
|
||||
osg::Node *entity = modellib->load_model( fg_root, _paths[i],
|
||||
prop_root, sim_time_sec,
|
||||
/*cache_object*/ true );
|
||||
if (entity != 0) {
|
||||
@@ -153,23 +141,29 @@ SGMatModel::load_models ( SGModelLib *modellib,
|
||||
// in the XML wrapper as well (at least,
|
||||
// the billboarding should be handled
|
||||
// there).
|
||||
float ranges[] = {0, _range_m};
|
||||
ssgRangeSelector * lod = new ssgRangeSelector;
|
||||
lod->setRanges(ranges, 2);
|
||||
osg::LOD * lod = new osg::LOD;
|
||||
lod->setName("Model LOD");
|
||||
lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
|
||||
lod->setRange(0, 0, _range_m);
|
||||
if (_heading_type == HEADING_BILLBOARD) {
|
||||
// if the model is a billboard, it is likely :
|
||||
// 1. a branch with only leaves,
|
||||
// 2. a tree or a non rectangular shape faked by transparency
|
||||
// We add alpha clamp then
|
||||
if ( entity->isAKindOf(ssgTypeBranch()) ) {
|
||||
ssgBranch *b = (ssgBranch *)entity;
|
||||
setAlphaClampToBranch( b, 0.01f );
|
||||
}
|
||||
ssgCutout * cutout = new ssgCutout(false);
|
||||
cutout->addKid(entity);
|
||||
lod->addKid(cutout);
|
||||
osg::StateSet* stateSet = entity->getOrCreateStateSet();
|
||||
osg::AlphaFunc* alphaFunc =
|
||||
new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01f);
|
||||
stateSet->setAttributeAndModes(alphaFunc,
|
||||
osg::StateAttribute::OVERRIDE);
|
||||
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
|
||||
osg::Transform* transform = new osg::Transform;
|
||||
transform->setName("Model Billboard Transform");
|
||||
transform->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
transform->addChild(entity);
|
||||
lod->addChild(transform);
|
||||
} else {
|
||||
lod->addKid(entity);
|
||||
lod->addChild(entity);
|
||||
}
|
||||
_models.push_back(lod);
|
||||
} else {
|
||||
@@ -180,7 +174,7 @@ SGMatModel::load_models ( SGModelLib *modellib,
|
||||
_models_loaded = true;
|
||||
}
|
||||
|
||||
ssgEntity *
|
||||
osg::Node*
|
||||
SGMatModel::get_model( int index,
|
||||
SGModelLib *modellib,
|
||||
const string &fg_root,
|
||||
@@ -188,10 +182,10 @@ SGMatModel::get_model( int index,
|
||||
double sim_time_sec )
|
||||
{
|
||||
load_models( modellib, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
|
||||
return _models[index];
|
||||
return _models[index].get();
|
||||
}
|
||||
|
||||
ssgEntity *
|
||||
osg::Node*
|
||||
SGMatModel::get_random_model( SGModelLib *modellib,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
@@ -202,7 +196,7 @@ SGMatModel::get_random_model( SGModelLib *modellib,
|
||||
int index = int(sg_random() * nModels);
|
||||
if (index >= nModels)
|
||||
index = 0;
|
||||
return _models[index];
|
||||
return _models[index].get();
|
||||
}
|
||||
|
||||
double
|
||||
|
||||
@@ -32,12 +32,11 @@
|
||||
|
||||
#include STL_STRING // Standard C++ string library
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Node>
|
||||
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/structure/ssgSharedPtr.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
SG_USING_STD(string);
|
||||
@@ -86,7 +85,7 @@ public:
|
||||
* @param index The index of the model.
|
||||
* @return The model.
|
||||
*/
|
||||
ssgEntity *get_model( int index,
|
||||
osg::Node *get_model( int index,
|
||||
SGModelLib *modellib,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
@@ -98,7 +97,7 @@ public:
|
||||
*
|
||||
* @return A randomly select model from the variants.
|
||||
*/
|
||||
ssgEntity *get_random_model( SGModelLib *modellib,
|
||||
osg::Node *get_random_model( SGModelLib *modellib,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec );
|
||||
@@ -141,7 +140,7 @@ private:
|
||||
double sim_time_sec );
|
||||
|
||||
vector<string> _paths;
|
||||
mutable vector<ssgSharedPtr<ssgEntity> > _models;
|
||||
mutable vector<osg::ref_ptr<osg::Node> > _models;
|
||||
mutable bool _models_loaded;
|
||||
double _coverage_m2;
|
||||
double _range_m;
|
||||
@@ -198,7 +197,6 @@ private:
|
||||
|
||||
double _range_m;
|
||||
vector<SGSharedPtr<SGMatModel> > _objects;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -6,27 +6,31 @@ noinst_HEADERS =
|
||||
|
||||
include_HEADERS = \
|
||||
animation.hxx \
|
||||
custtrans.hxx \
|
||||
location.hxx \
|
||||
model.hxx \
|
||||
modellib.hxx \
|
||||
personality.hxx \
|
||||
persparam.hxx \
|
||||
placement.hxx \
|
||||
placementtrans.hxx \
|
||||
shadowvolume.hxx
|
||||
SGMaterialAnimation.hxx \
|
||||
SGOffsetTransform.hxx \
|
||||
SGRotateTransform.hxx \
|
||||
SGScaleTransform.hxx \
|
||||
SGTranslateTransform.hxx
|
||||
|
||||
libsgmodel_a_SOURCES = \
|
||||
animation.cxx \
|
||||
custtrans.cxx \
|
||||
location.cxx \
|
||||
model.cxx \
|
||||
modellib.cxx \
|
||||
personality.cxx \
|
||||
persparam.cxx \
|
||||
placement.cxx \
|
||||
placementtrans.cxx \
|
||||
shadowvolume.cxx \
|
||||
shadanim.cxx
|
||||
shadanim.cxx \
|
||||
SGMaterialAnimation.cxx \
|
||||
SGOffsetTransform.cxx \
|
||||
SGRotateTransform.cxx \
|
||||
SGScaleTransform.cxx \
|
||||
SGTranslateTransform.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
514
simgear/scene/model/SGMaterialAnimation.cxx
Normal file
514
simgear/scene/model/SGMaterialAnimation.cxx
Normal file
@@ -0,0 +1,514 @@
|
||||
// animation.cxx - classes to manage model animation.
|
||||
// Written by David Megginson, started 2002.
|
||||
//
|
||||
// This file is in the Public Domain, and comes with no warranty.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include "SGMaterialAnimation.hxx"
|
||||
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/Array>
|
||||
#include <osg/Drawable>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Material>
|
||||
#include <osg/StateSet>
|
||||
#include <osgDB/FileNameUtils>
|
||||
#include <osgDB/FileUtils>
|
||||
#include <osgDB/ReadFile>
|
||||
|
||||
#include <simgear/props/condition.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/scene/model/model.hxx>
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Get a color from properties.
|
||||
*/
|
||||
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;
|
||||
SGVec4f v;
|
||||
|
||||
ColorSpec(const SGPropertyNode* configNode, SGPropertyNode* modelRoot)
|
||||
{
|
||||
red = -1.0;
|
||||
green = -1.0;
|
||||
blue = -1.0;
|
||||
if (!configNode)
|
||||
return;
|
||||
|
||||
red = configNode->getFloatValue("red", -1.0);
|
||||
green = configNode->getFloatValue("green", -1.0);
|
||||
blue = configNode->getFloatValue("blue", -1.0);
|
||||
factor = configNode->getFloatValue("factor", 1.0);
|
||||
offset = configNode->getFloatValue("offset", 0.0);
|
||||
|
||||
if (!modelRoot)
|
||||
return;
|
||||
const SGPropertyNode *node;
|
||||
node = configNode->getChild("red-prop");
|
||||
if (node)
|
||||
red_prop = modelRoot->getNode(node->getStringValue(), true);
|
||||
node = configNode->getChild("green-prop");
|
||||
if (node)
|
||||
green_prop = modelRoot->getNode(node->getStringValue(), true);
|
||||
node = configNode->getChild("blue-prop");
|
||||
if (node)
|
||||
blue_prop = modelRoot->getNode(node->getStringValue(), true);
|
||||
node = configNode->getChild("factor-prop");
|
||||
if (node)
|
||||
factor_prop = modelRoot->getNode(node->getStringValue(), true);
|
||||
node = configNode->getChild("offset-prop");
|
||||
if (node)
|
||||
offset_prop = modelRoot->getNode(node->getStringValue(), true);
|
||||
}
|
||||
|
||||
bool dirty() {
|
||||
return red >= 0 || green >= 0 || blue >= 0;
|
||||
}
|
||||
bool live() {
|
||||
return red_prop || green_prop || blue_prop
|
||||
|| factor_prop || offset_prop;
|
||||
}
|
||||
SGVec4f &rgba() {
|
||||
if (red_prop)
|
||||
red = red_prop->getFloatValue();
|
||||
if (green_prop)
|
||||
green = green_prop->getFloatValue();
|
||||
if (blue_prop)
|
||||
blue = blue_prop->getFloatValue();
|
||||
if (factor_prop)
|
||||
factor = factor_prop->getFloatValue();
|
||||
if (offset_prop)
|
||||
offset = offset_prop->getFloatValue();
|
||||
v[0] = SGMiscf::clip(red*factor + offset, 0, 1);
|
||||
v[1] = SGMiscf::clip(green*factor + offset, 0, 1);
|
||||
v[2] = SGMiscf::clip(blue*factor + offset, 0, 1);
|
||||
v[3] = 1;
|
||||
return v;
|
||||
}
|
||||
|
||||
osg::Vec4& rgbaVec4()
|
||||
{
|
||||
return rgba().osg();
|
||||
}
|
||||
|
||||
SGVec4f &initialRgba() {
|
||||
v[0] = SGMiscf::clip(red*factor + offset, 0, 1);
|
||||
v[1] = SGMiscf::clip(green*factor + offset, 0, 1);
|
||||
v[2] = SGMiscf::clip(blue*factor + offset, 0, 1);
|
||||
v[3] = 1;
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a property value from a property.
|
||||
*/
|
||||
struct PropSpec {
|
||||
float value;
|
||||
float factor;
|
||||
float offset;
|
||||
float min;
|
||||
float max;
|
||||
SGPropertyNode_ptr value_prop;
|
||||
SGPropertyNode_ptr factor_prop;
|
||||
SGPropertyNode_ptr offset_prop;
|
||||
|
||||
PropSpec(const char* valueName, const char* valuePropName,
|
||||
const SGPropertyNode* configNode, SGPropertyNode* modelRoot)
|
||||
{
|
||||
value = -1;
|
||||
if (!configNode)
|
||||
return;
|
||||
|
||||
value = configNode->getFloatValue(valueName, -1);
|
||||
factor = configNode->getFloatValue("factor", 1);
|
||||
offset = configNode->getFloatValue("offset", 0);
|
||||
min = configNode->getFloatValue("min", 0);
|
||||
max = configNode->getFloatValue("max", 1);
|
||||
|
||||
if (!modelRoot)
|
||||
return;
|
||||
const SGPropertyNode *node;
|
||||
node = configNode->getChild(valuePropName);
|
||||
if (node)
|
||||
value_prop = modelRoot->getNode(node->getStringValue(), true);
|
||||
node = configNode->getChild("factor-prop");
|
||||
if (node)
|
||||
factor_prop = modelRoot->getNode(node->getStringValue(), true);
|
||||
node = configNode->getChild("offset-prop");
|
||||
if (node)
|
||||
offset_prop = modelRoot->getNode(node->getStringValue(), true);
|
||||
}
|
||||
bool dirty() { return value >= 0.0; }
|
||||
bool live() { return value_prop || factor_prop || offset_prop; }
|
||||
float getValue()
|
||||
{
|
||||
if (value_prop)
|
||||
value = value_prop->getFloatValue();
|
||||
if (offset_prop)
|
||||
offset = offset_prop->getFloatValue();
|
||||
if (factor_prop)
|
||||
factor = factor_prop->getFloatValue();
|
||||
return SGMiscf::clip(value*factor + offset, min, max);
|
||||
}
|
||||
float getInitialValue()
|
||||
{
|
||||
return SGMiscf::clip(value*factor + offset, min, max);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The possible color properties supplied by a material animation.
|
||||
*/
|
||||
enum SuppliedColor {
|
||||
DIFFUSE = 1,
|
||||
AMBIENT = 2,
|
||||
SPECULAR = 4,
|
||||
EMISSION = 8,
|
||||
SHININESS = 16,
|
||||
TRANSPARENCY = 32
|
||||
};
|
||||
|
||||
const unsigned AMBIENT_DIFFUSE = AMBIENT | DIFFUSE;
|
||||
|
||||
const int allMaterialColors = (DIFFUSE | AMBIENT | SPECULAR | EMISSION
|
||||
| SHININESS);
|
||||
|
||||
// Visitor for finding default material colors in the animation node's
|
||||
// subgraph. This makes some assumptions about the subgraph i.e.,
|
||||
// there will be one material and one color value found. This is
|
||||
// probably true for ac3d models and most uses of material animations,
|
||||
// but will break down if, for example, you animate the transparency
|
||||
// of a vertex colored model.
|
||||
class MaterialDefaultsVisitor : public osg::NodeVisitor {
|
||||
public:
|
||||
MaterialDefaultsVisitor()
|
||||
: osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
ambientDiffuse(-1.0f, -1.0f, -1.0f, -1.0f)
|
||||
{
|
||||
setVisitorType(osg::NodeVisitor::NODE_VISITOR);
|
||||
}
|
||||
|
||||
virtual void apply(osg::Node& node)
|
||||
{
|
||||
maybeGetMaterialValues(node.getStateSet());
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
virtual void apply(osg::Geode& node)
|
||||
{
|
||||
maybeGetMaterialValues(node.getStateSet());
|
||||
int numDrawables = node.getNumDrawables();
|
||||
for (int i = 0; i < numDrawables; i++) {
|
||||
osg::Geometry* geom = dynamic_cast<osg::Geometry*>(node.getDrawable(i));
|
||||
if (!geom || geom->getColorBinding() != osg::Geometry::BIND_OVERALL)
|
||||
continue;
|
||||
maybeGetMaterialValues(geom->getStateSet());
|
||||
osg::Array* colorArray = geom->getColorArray();
|
||||
osg::Vec4Array* colorVec4 = dynamic_cast<osg::Vec4Array*>(colorArray);
|
||||
if (colorVec4) {
|
||||
ambientDiffuse = (*colorVec4)[0];
|
||||
break;
|
||||
}
|
||||
osg::Vec3Array* colorVec3 = dynamic_cast<osg::Vec3Array*>(colorArray);
|
||||
if (colorVec3) {
|
||||
ambientDiffuse = osg::Vec4((*colorVec3)[0], 1.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void maybeGetMaterialValues(osg::StateSet* stateSet)
|
||||
{
|
||||
if (!stateSet)
|
||||
return;
|
||||
osg::Material* nodeMat
|
||||
= dynamic_cast<osg::Material*>(stateSet->getAttribute(osg::StateAttribute::MATERIAL));
|
||||
if (!nodeMat)
|
||||
return;
|
||||
material = nodeMat;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Material> material;
|
||||
osg::Vec4 ambientDiffuse;
|
||||
};
|
||||
|
||||
class UpdateCallback : public osg::NodeCallback {
|
||||
public:
|
||||
UpdateCallback(const osgDB::FilePathList& texturePathList,
|
||||
const SGCondition* condition,
|
||||
const SGPropertyNode* configNode, SGPropertyNode* modelRoot) :
|
||||
_condition(condition),
|
||||
_ambient(configNode->getChild("ambient"), modelRoot),
|
||||
_diffuse(configNode->getChild("diffuse"), modelRoot),
|
||||
_specular(configNode->getChild("specular"), modelRoot),
|
||||
_emission(configNode->getChild("emission"), modelRoot),
|
||||
_shininess("shininess", "shininess-prop",
|
||||
configNode->getChild("shininess"), modelRoot),
|
||||
_transparency("alpha", "alpha-prop",
|
||||
configNode->getChild("transparency"), modelRoot),
|
||||
_texturePathList(texturePathList)
|
||||
{
|
||||
const SGPropertyNode* node;
|
||||
|
||||
node = configNode->getChild("threshold-prop");
|
||||
if (node)
|
||||
_thresholdProp = modelRoot->getNode(node->getStringValue(), true);
|
||||
node = configNode->getChild("texture-prop");
|
||||
if (node)
|
||||
_textureProp = modelRoot->getNode(node->getStringValue(), true);
|
||||
}
|
||||
|
||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
osg::StateSet* stateSet = node->getStateSet();
|
||||
if ((!_condition || _condition->test()) && stateSet) {
|
||||
if (_textureProp) {
|
||||
std::string textureName = _textureProp->getStringValue();
|
||||
if (_textureName != textureName) {
|
||||
while (stateSet->getTextureAttribute(0,
|
||||
osg::StateAttribute::TEXTURE)) {
|
||||
stateSet->removeTextureAttribute(0, osg::StateAttribute::TEXTURE);
|
||||
}
|
||||
std::string textureFile;
|
||||
textureFile = osgDB::findFileInPath(textureName, _texturePathList);
|
||||
if (!textureFile.empty()) {
|
||||
osg::Texture2D* texture2D = SGLoadTexture2D(textureFile);
|
||||
if (texture2D) {
|
||||
stateSet->setTextureAttribute(0, texture2D,
|
||||
osg::StateAttribute::OVERRIDE);
|
||||
stateSet->setTextureMode(0, GL_TEXTURE_2D,
|
||||
osg::StateAttribute::ON);
|
||||
_textureName = textureName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_thresholdProp) {
|
||||
osg::StateSet* stateSet = node->getOrCreateStateSet();
|
||||
osg::StateAttribute* stateAttribute;
|
||||
stateAttribute = stateSet->getAttribute(osg::StateAttribute::ALPHAFUNC);
|
||||
osg::AlphaFunc* alphaFunc = dynamic_cast<osg::AlphaFunc*>(stateAttribute);
|
||||
assert(alphaFunc);
|
||||
alphaFunc->setReferenceValue(_thresholdProp->getFloatValue());
|
||||
}
|
||||
osg::StateAttribute* stateAttribute
|
||||
= stateSet->getAttribute(osg::StateAttribute::MATERIAL);
|
||||
osg::Material* material = dynamic_cast<osg::Material*>(stateAttribute);
|
||||
if (material) {
|
||||
if (_ambient.live())
|
||||
material->setAmbient(osg::Material::FRONT_AND_BACK,
|
||||
_ambient.rgbaVec4());
|
||||
if (_diffuse.live())
|
||||
material->setDiffuse(osg::Material::FRONT_AND_BACK,
|
||||
_diffuse.rgbaVec4());
|
||||
if (_specular.live())
|
||||
material->setSpecular(osg::Material::FRONT_AND_BACK,
|
||||
_specular.rgbaVec4());
|
||||
if (_emission.live())
|
||||
material->setEmission(osg::Material::FRONT_AND_BACK,
|
||||
_emission.rgbaVec4());
|
||||
if (_shininess.live())
|
||||
material->setShininess(osg::Material::FRONT_AND_BACK,
|
||||
_shininess.getValue());
|
||||
if (_transparency.live()) {
|
||||
float alpha = _transparency.getValue();
|
||||
material->setAlpha(osg::Material::FRONT_AND_BACK, alpha);
|
||||
if (alpha < 1.0f) {
|
||||
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
} else {
|
||||
stateSet->setRenderingHint(osg::StateSet::DEFAULT_BIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
traverse(node, nv);
|
||||
}
|
||||
private:
|
||||
SGSharedPtr<const SGCondition> _condition;
|
||||
SGSharedPtr<const SGPropertyNode> _textureProp;
|
||||
SGSharedPtr<const SGPropertyNode> _thresholdProp;
|
||||
std::string _textureName;
|
||||
ColorSpec _ambient;
|
||||
ColorSpec _diffuse;
|
||||
ColorSpec _specular;
|
||||
ColorSpec _emission;
|
||||
PropSpec _shininess;
|
||||
PropSpec _transparency;
|
||||
osgDB::FilePathList _texturePathList;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
||||
SGMaterialAnimation::SGMaterialAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot) :
|
||||
SGAnimation(configNode, modelRoot)
|
||||
{
|
||||
if (configNode->hasChild("global"))
|
||||
SG_LOG(SG_IO, SG_ALERT, "Use of <global> in material animation is "
|
||||
"no longer supported");
|
||||
}
|
||||
|
||||
osg::Group*
|
||||
SGMaterialAnimation::createAnimationGroup(osg::Group& parent)
|
||||
{
|
||||
osg::Group* group = new osg::Group;
|
||||
group->setName("material animation group");
|
||||
|
||||
SGPropertyNode* inputRoot = getModelRoot();
|
||||
const SGPropertyNode* node = getConfig()->getChild("property-base");
|
||||
if (node)
|
||||
inputRoot = getModelRoot()->getRootNode()->getNode(node->getStringValue(),
|
||||
true);
|
||||
|
||||
osgDB::FilePathList texturePathList = osgDB::getDataFilePathList();
|
||||
|
||||
if (getConfig()->hasChild("texture")) {
|
||||
std::string textureName = getConfig()->getStringValue("texture");
|
||||
std::string textureFile;
|
||||
textureFile = osgDB::findFileInPath(textureName, texturePathList);
|
||||
if (!textureFile.empty()) {
|
||||
osg::StateSet* stateSet = group->getOrCreateStateSet();
|
||||
osg::Texture2D* texture2D = SGLoadTexture2D(textureFile);
|
||||
if (texture2D) {
|
||||
stateSet->setTextureAttribute(0, texture2D,
|
||||
osg::StateAttribute::OVERRIDE);
|
||||
stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
|
||||
if (texture2D->getImage()->isImageTranslucent()) {
|
||||
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getConfig()->hasChild("threshold-prop") ||
|
||||
getConfig()->hasChild("threshold")) {
|
||||
osg::StateSet* stateSet = group->getOrCreateStateSet();
|
||||
osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
|
||||
alphaFunc->setFunction(osg::AlphaFunc::GREATER);
|
||||
float threshold = getConfig()->getFloatValue("threshold", 0);
|
||||
alphaFunc->setReferenceValue(threshold);
|
||||
stateSet->setAttribute(alphaFunc, osg::StateAttribute::OVERRIDE);
|
||||
}
|
||||
|
||||
unsigned suppliedColors = 0;
|
||||
if (getConfig()->hasChild("ambient"))
|
||||
suppliedColors |= AMBIENT;
|
||||
if (getConfig()->hasChild("diffuse"))
|
||||
suppliedColors |= DIFFUSE;
|
||||
if (getConfig()->hasChild("specular"))
|
||||
suppliedColors |= SPECULAR;
|
||||
if (getConfig()->hasChild("emission"))
|
||||
suppliedColors |= EMISSION;
|
||||
if (getConfig()->hasChild("shininess")
|
||||
|| getConfig()->hasChild("shininess-prop"))
|
||||
suppliedColors |= SHININESS;
|
||||
if (getConfig()->hasChild("transparency"))
|
||||
suppliedColors |= TRANSPARENCY;
|
||||
|
||||
if (suppliedColors != 0) {
|
||||
osg::StateSet* stateSet = group->getOrCreateStateSet();
|
||||
osg::Material* mat;
|
||||
|
||||
if (defaultMaterial.valid()) {
|
||||
mat = defaultMaterial.get();
|
||||
|
||||
} else {
|
||||
mat = new osg::Material;
|
||||
mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
}
|
||||
mat->setDataVariance(osg::Object::DYNAMIC);
|
||||
unsigned defaultColorModeMask = 0;
|
||||
mat->setUpdateCallback(0); // Just to make sure.
|
||||
switch (mat->getColorMode()) {
|
||||
case osg::Material::OFF:
|
||||
defaultColorModeMask = 0;
|
||||
break;
|
||||
case osg::Material::AMBIENT:
|
||||
defaultColorModeMask = AMBIENT;
|
||||
break;
|
||||
case osg::Material::DIFFUSE:
|
||||
defaultColorModeMask = DIFFUSE;
|
||||
break;
|
||||
case osg::Material::AMBIENT_AND_DIFFUSE:
|
||||
defaultColorModeMask = AMBIENT | DIFFUSE;
|
||||
break;
|
||||
case osg::Material::SPECULAR:
|
||||
defaultColorModeMask = SPECULAR;
|
||||
break;
|
||||
case osg::Material::EMISSION:
|
||||
defaultColorModeMask = EMISSION;
|
||||
break;
|
||||
}
|
||||
// Copy the color found by traversing geometry into the material
|
||||
// in case we need to specify it (e.g., transparency) and it is
|
||||
// not specified by the animation.
|
||||
if (defaultAmbientDiffuse.x() >= 0) {
|
||||
if (defaultColorModeMask & AMBIENT)
|
||||
mat->setAmbient(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
|
||||
if (defaultColorModeMask & DIFFUSE)
|
||||
mat->setDiffuse(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
|
||||
}
|
||||
// Compute which colors in the animation override colors set via
|
||||
// colorMode / glColor, and set the colorMode for the animation's
|
||||
// material accordingly.
|
||||
if (suppliedColors & TRANSPARENCY) {
|
||||
// All colors will be affected by the material. Hope all the
|
||||
// defaults are fine, if needed.
|
||||
mat->setColorMode(osg::Material::OFF);
|
||||
} else if ((suppliedColors & defaultColorModeMask) != 0) {
|
||||
// First deal with the complicated AMBIENT/DIFFUSE case.
|
||||
if ((defaultColorModeMask & AMBIENT_DIFFUSE) != 0) {
|
||||
// glColor can supply colors not specified by the animation.
|
||||
unsigned matColorModeMask = ((~suppliedColors & defaultColorModeMask)
|
||||
& AMBIENT_DIFFUSE);
|
||||
if ((matColorModeMask & DIFFUSE) != 0)
|
||||
mat->setColorMode(osg::Material::DIFFUSE);
|
||||
else if ((matColorModeMask & AMBIENT) != 0)
|
||||
mat->setColorMode(osg::Material::AMBIENT);
|
||||
else
|
||||
mat->setColorMode(osg::Material::OFF);
|
||||
} else {
|
||||
// The animation overrides the glColor color.
|
||||
mat->setColorMode(osg::Material::OFF);
|
||||
}
|
||||
} else {
|
||||
// No overlap between the animation and color mode, so leave
|
||||
// the color mode alone.
|
||||
}
|
||||
stateSet->setAttribute(mat,(osg::StateAttribute::ON
|
||||
| osg::StateAttribute::OVERRIDE));
|
||||
}
|
||||
group->setUpdateCallback(new UpdateCallback(texturePathList,
|
||||
getCondition(),
|
||||
getConfig(), inputRoot));
|
||||
parent.addChild(group);
|
||||
return group;
|
||||
}
|
||||
|
||||
void
|
||||
SGMaterialAnimation::install(osg::Node& node)
|
||||
{
|
||||
SGAnimation::install(node);
|
||||
|
||||
MaterialDefaultsVisitor defaultsVisitor;
|
||||
node.accept(defaultsVisitor);
|
||||
if (defaultsVisitor.material.valid()) {
|
||||
defaultMaterial
|
||||
= static_cast<osg::Material*>(defaultsVisitor.material->clone(osg::CopyOp::SHALLOW_COPY));
|
||||
}
|
||||
defaultAmbientDiffuse = defaultsVisitor.ambientDiffuse;
|
||||
}
|
||||
32
simgear/scene/model/SGMaterialAnimation.hxx
Normal file
32
simgear/scene/model/SGMaterialAnimation.hxx
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
// animation.hxx - classes to manage model animation.
|
||||
// Written by David Megginson, started 2002.
|
||||
//
|
||||
// This file is in the Public Domain, and comes with no warranty.
|
||||
|
||||
#ifndef _SG_MATERIALANIMATION_HXX
|
||||
#define _SG_MATERIALANIMATION_HXX 1
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <osg/Material>
|
||||
#include "animation.hxx"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Material animation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGMaterialAnimation : public SGAnimation {
|
||||
public:
|
||||
SGMaterialAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
virtual void install(osg::Node& node);
|
||||
private:
|
||||
osg::ref_ptr<osg::Material> defaultMaterial;
|
||||
osg::Vec4 defaultAmbientDiffuse;
|
||||
};
|
||||
|
||||
#endif // _SG_MATERIALANIMATION_HXX
|
||||
68
simgear/scene/model/SGOffsetTransform.cxx
Normal file
68
simgear/scene/model/SGOffsetTransform.cxx
Normal file
@@ -0,0 +1,68 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2006-2007 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include "SGOffsetTransform.hxx"
|
||||
|
||||
SGOffsetTransform::SGOffsetTransform(double scaleFactor) :
|
||||
_scaleFactor(scaleFactor),
|
||||
_rScaleFactor(1/scaleFactor)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
SGOffsetTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const
|
||||
{
|
||||
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) {
|
||||
osg::Vec3 center = nv->getEyePoint();
|
||||
osg::Matrix transform;
|
||||
transform(0,0) = _scaleFactor;
|
||||
transform(1,1) = _scaleFactor;
|
||||
transform(2,2) = _scaleFactor;
|
||||
transform(3,0) = center[0]*(1 - _scaleFactor);
|
||||
transform(3,1) = center[1]*(1 - _scaleFactor);
|
||||
transform(3,2) = center[2]*(1 - _scaleFactor);
|
||||
matrix.preMult(transform);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SGOffsetTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const
|
||||
{
|
||||
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) {
|
||||
osg::Vec3 center = nv->getEyePoint();
|
||||
osg::Matrix transform;
|
||||
transform(0,0) = _rScaleFactor;
|
||||
transform(1,1) = _rScaleFactor;
|
||||
transform(2,2) = _rScaleFactor;
|
||||
transform(3,0) = center[0]*(1 - _rScaleFactor);
|
||||
transform(3,1) = center[1]*(1 - _rScaleFactor);
|
||||
transform(3,2) = center[2]*(1 - _rScaleFactor);
|
||||
matrix.postMult(transform);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
39
simgear/scene/model/SGOffsetTransform.hxx
Normal file
39
simgear/scene/model/SGOffsetTransform.hxx
Normal file
@@ -0,0 +1,39 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2006-2007 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SG_OFFSET_TRASNFORM_HXX
|
||||
#define SG_OFFSET_TRASNFORM_HXX
|
||||
|
||||
#include <osg/Transform>
|
||||
|
||||
class SGOffsetTransform : public osg::Transform {
|
||||
public:
|
||||
SGOffsetTransform(double scaleFactor);
|
||||
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const;
|
||||
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const;
|
||||
private:
|
||||
double _scaleFactor;
|
||||
double _rScaleFactor;
|
||||
};
|
||||
|
||||
#endif
|
||||
122
simgear/scene/model/SGRotateTransform.cxx
Normal file
122
simgear/scene/model/SGRotateTransform.cxx
Normal file
@@ -0,0 +1,122 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2006-2007 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include "SGRotateTransform.hxx"
|
||||
|
||||
static void
|
||||
set_rotation (osg::Matrix &matrix, double position_rad,
|
||||
const SGVec3d ¢er, const SGVec3d &axis)
|
||||
{
|
||||
double temp_angle = -position_rad;
|
||||
|
||||
double s = sin(temp_angle);
|
||||
double c = cos(temp_angle);
|
||||
double t = 1 - c;
|
||||
|
||||
// axis was normalized at load time
|
||||
// hint to the compiler to put these into FP registers
|
||||
double x = axis[0];
|
||||
double y = axis[1];
|
||||
double z = axis[2];
|
||||
|
||||
matrix(0, 0) = t * x * x + c ;
|
||||
matrix(0, 1) = t * y * x - s * z ;
|
||||
matrix(0, 2) = t * z * x + s * y ;
|
||||
matrix(0, 3) = 0;
|
||||
|
||||
matrix(1, 0) = t * x * y + s * z ;
|
||||
matrix(1, 1) = t * y * y + c ;
|
||||
matrix(1, 2) = t * z * y - s * x ;
|
||||
matrix(1, 3) = 0;
|
||||
|
||||
matrix(2, 0) = t * x * z - s * y ;
|
||||
matrix(2, 1) = t * y * z + s * x ;
|
||||
matrix(2, 2) = t * z * z + c ;
|
||||
matrix(2, 3) = 0;
|
||||
|
||||
// hint to the compiler to put these into FP registers
|
||||
x = center[0];
|
||||
y = center[1];
|
||||
z = center[2];
|
||||
|
||||
matrix(3, 0) = x - x*matrix(0, 0) - y*matrix(1, 0) - z*matrix(2, 0);
|
||||
matrix(3, 1) = y - x*matrix(0, 1) - y*matrix(1, 1) - z*matrix(2, 1);
|
||||
matrix(3, 2) = z - x*matrix(0, 2) - y*matrix(1, 2) - z*matrix(2, 2);
|
||||
matrix(3, 3) = 1;
|
||||
}
|
||||
|
||||
SGRotateTransform::SGRotateTransform() :
|
||||
_center(0, 0, 0),
|
||||
_axis(0, 0, 0),
|
||||
_angleRad(0)
|
||||
{
|
||||
setReferenceFrame(RELATIVE_RF);
|
||||
}
|
||||
|
||||
bool
|
||||
SGRotateTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const
|
||||
{
|
||||
// This is the fast path, optimize a bit
|
||||
if (_referenceFrame == RELATIVE_RF) {
|
||||
// FIXME optimize
|
||||
osg::Matrix tmp;
|
||||
set_rotation(tmp, _angleRad, _center, _axis);
|
||||
matrix.preMult(tmp);
|
||||
} else {
|
||||
osg::Matrix tmp;
|
||||
set_rotation(tmp, _angleRad, _center, _axis);
|
||||
matrix = tmp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SGRotateTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const
|
||||
{
|
||||
if (_referenceFrame == RELATIVE_RF) {
|
||||
// FIXME optimize
|
||||
osg::Matrix tmp;
|
||||
set_rotation(tmp, -_angleRad, _center, _axis);
|
||||
matrix.postMult(tmp);
|
||||
} else {
|
||||
// FIXME optimize
|
||||
osg::Matrix tmp;
|
||||
set_rotation(tmp, -_angleRad, _center, _axis);
|
||||
matrix = tmp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
osg::BoundingSphere
|
||||
SGRotateTransform::computeBound() const
|
||||
{
|
||||
osg::BoundingSphere bs = osg::Group::computeBound();
|
||||
osg::BoundingSphere centerbs(_center.osg(), bs.radius());
|
||||
centerbs.expandBy(bs);
|
||||
return centerbs;
|
||||
}
|
||||
|
||||
69
simgear/scene/model/SGRotateTransform.hxx
Normal file
69
simgear/scene/model/SGRotateTransform.hxx
Normal file
@@ -0,0 +1,69 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2006-2007 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SG_ROTATE_TRANSFORM_HXX
|
||||
#define SG_ROTATE_TRANSFORM_HXX
|
||||
|
||||
#include <osg/Transform>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
class SGRotateTransform : public osg::Transform {
|
||||
public:
|
||||
SGRotateTransform();
|
||||
|
||||
void setCenter(const SGVec3f& center)
|
||||
{ setCenter(toVec3d(center)); }
|
||||
void setCenter(const SGVec3d& center)
|
||||
{ _center = center; dirtyBound(); }
|
||||
const SGVec3d& getCenter() const
|
||||
{ return _center; }
|
||||
|
||||
void setAxis(const SGVec3f& axis)
|
||||
{ setAxis(toVec3d(axis)); }
|
||||
void setAxis(const SGVec3d& axis)
|
||||
{ _axis = axis; dirtyBound(); }
|
||||
const SGVec3d& getAxis() const
|
||||
{ return _axis; }
|
||||
|
||||
void setAngleRad(double angle)
|
||||
{ _angleRad = angle; }
|
||||
double getAngleRad() const
|
||||
{ return _angleRad; }
|
||||
|
||||
void setAngleDeg(double angle)
|
||||
{ _angleRad = SGMiscd::deg2rad(angle); }
|
||||
double getAngleDeg() const
|
||||
{ return SGMiscd::rad2deg(_angleRad); }
|
||||
|
||||
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const;
|
||||
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const;
|
||||
|
||||
virtual osg::BoundingSphere computeBound() const;
|
||||
|
||||
private:
|
||||
SGVec3d _center;
|
||||
SGVec3d _axis;
|
||||
double _angleRad;
|
||||
};
|
||||
|
||||
#endif
|
||||
109
simgear/scene/model/SGScaleTransform.cxx
Normal file
109
simgear/scene/model/SGScaleTransform.cxx
Normal file
@@ -0,0 +1,109 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2006-2007 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2006-2007 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include "SGScaleTransform.hxx"
|
||||
|
||||
SGScaleTransform::SGScaleTransform() :
|
||||
_center(0, 0, 0),
|
||||
_scaleFactor(1, 1, 1),
|
||||
_boundScale(1)
|
||||
{
|
||||
setReferenceFrame(RELATIVE_RF);
|
||||
}
|
||||
|
||||
bool
|
||||
SGScaleTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const
|
||||
{
|
||||
osg::Matrix transform;
|
||||
transform(0,0) = _scaleFactor[0];
|
||||
transform(1,1) = _scaleFactor[1];
|
||||
transform(2,2) = _scaleFactor[2];
|
||||
transform(3,0) = _center[0]*(1 - _scaleFactor[0]);
|
||||
transform(3,1) = _center[1]*(1 - _scaleFactor[1]);
|
||||
transform(3,2) = _center[2]*(1 - _scaleFactor[2]);
|
||||
if (_referenceFrame == RELATIVE_RF)
|
||||
matrix.preMult(transform);
|
||||
else
|
||||
matrix = transform;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SGScaleTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const
|
||||
{
|
||||
if (fabs(_scaleFactor[0]) < SGLimitsd::min())
|
||||
return false;
|
||||
if (fabs(_scaleFactor[1]) < SGLimitsd::min())
|
||||
return false;
|
||||
if (fabs(_scaleFactor[2]) < SGLimitsd::min())
|
||||
return false;
|
||||
SGVec3d rScaleFactor(1/_scaleFactor[0],
|
||||
1/_scaleFactor[1],
|
||||
1/_scaleFactor[2]);
|
||||
osg::Matrix transform;
|
||||
transform(0,0) = rScaleFactor[0];
|
||||
transform(1,1) = rScaleFactor[1];
|
||||
transform(2,2) = rScaleFactor[2];
|
||||
transform(3,0) = _center[0]*(1 - rScaleFactor[0]);
|
||||
transform(3,1) = _center[1]*(1 - rScaleFactor[1]);
|
||||
transform(3,2) = _center[2]*(1 - rScaleFactor[2]);
|
||||
if (_referenceFrame == RELATIVE_RF)
|
||||
matrix.postMult(transform);
|
||||
else
|
||||
matrix = transform;
|
||||
return true;
|
||||
}
|
||||
|
||||
osg::BoundingSphere
|
||||
SGScaleTransform::computeBound() const
|
||||
{
|
||||
osg::BoundingSphere bs = osg::Group::computeBound();
|
||||
_boundScale = normI(_scaleFactor);
|
||||
bs.radius() *= _boundScale;
|
||||
return bs;
|
||||
}
|
||||
73
simgear/scene/model/SGScaleTransform.hxx
Normal file
73
simgear/scene/model/SGScaleTransform.hxx
Normal file
@@ -0,0 +1,73 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2006-2007 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SG_SCALE_TRANSFORM_HXX
|
||||
#define SG_SCALE_TRANSFORM_HXX
|
||||
|
||||
#include <osg/Transform>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
class SGScaleTransform : public osg::Transform {
|
||||
public:
|
||||
SGScaleTransform();
|
||||
|
||||
void setCenter(const SGVec3f& center)
|
||||
{ setCenter(toVec3d(center)); }
|
||||
void setCenter(const SGVec3d& center)
|
||||
{ _center = center; dirtyBound(); }
|
||||
const SGVec3d& getCenter() const
|
||||
{ return _center; }
|
||||
|
||||
void setScaleFactor(const SGVec3d& scaleFactor)
|
||||
{
|
||||
double boundScale = normI(scaleFactor);
|
||||
if (_boundScale < boundScale || 5*boundScale < _boundScale) {
|
||||
_boundScale = boundScale;
|
||||
dirtyBound();
|
||||
}
|
||||
_scaleFactor = scaleFactor;
|
||||
}
|
||||
void setScaleFactor(double scaleFactor)
|
||||
{
|
||||
double boundScale = fabs(scaleFactor);
|
||||
if (_boundScale < boundScale || 5*boundScale < _boundScale) {
|
||||
_boundScale = boundScale;
|
||||
dirtyBound();
|
||||
}
|
||||
_scaleFactor = SGVec3d(scaleFactor, scaleFactor, scaleFactor);
|
||||
}
|
||||
const SGVec3d& getScaleFactor() const
|
||||
{ return _scaleFactor; }
|
||||
|
||||
|
||||
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const;
|
||||
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const;
|
||||
virtual osg::BoundingSphere computeBound() const;
|
||||
|
||||
private:
|
||||
SGVec3d _center;
|
||||
SGVec3d _scaleFactor;
|
||||
mutable double _boundScale;
|
||||
};
|
||||
|
||||
#endif
|
||||
83
simgear/scene/model/SGTranslateTransform.cxx
Normal file
83
simgear/scene/model/SGTranslateTransform.cxx
Normal file
@@ -0,0 +1,83 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2006-2007 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include "SGTranslateTransform.hxx"
|
||||
|
||||
static inline void
|
||||
set_translation (osg::Matrix &matrix, double position_m, const SGVec3d &axis)
|
||||
{
|
||||
SGVec3d xyz = axis * position_m;
|
||||
matrix.makeIdentity();
|
||||
matrix(3, 0) = xyz[0];
|
||||
matrix(3, 1) = xyz[1];
|
||||
matrix(3, 2) = xyz[2];
|
||||
}
|
||||
|
||||
SGTranslateTransform::SGTranslateTransform() :
|
||||
_axis(0, 0, 0),
|
||||
_value(0)
|
||||
{
|
||||
setReferenceFrame(RELATIVE_RF);
|
||||
}
|
||||
|
||||
bool
|
||||
SGTranslateTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const
|
||||
{
|
||||
if (_referenceFrame == RELATIVE_RF) {
|
||||
osg::Matrix tmp;
|
||||
set_translation(tmp, _value, _axis);
|
||||
matrix.preMult(tmp);
|
||||
} else {
|
||||
osg::Matrix tmp;
|
||||
set_translation(tmp, _value, _axis);
|
||||
matrix = tmp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SGTranslateTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const
|
||||
{
|
||||
if (_referenceFrame == RELATIVE_RF) {
|
||||
osg::Matrix tmp;
|
||||
set_translation(tmp, -_value, _axis);
|
||||
matrix.postMult(tmp);
|
||||
} else {
|
||||
osg::Matrix tmp;
|
||||
set_translation(tmp, -_value, _axis);
|
||||
matrix = tmp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
osg::BoundingSphere
|
||||
SGTranslateTransform::computeBound() const
|
||||
{
|
||||
osg::BoundingSphere bs = osg::Group::computeBound();
|
||||
bs._center += _axis.osg()*_value;
|
||||
return bs;
|
||||
}
|
||||
53
simgear/scene/model/SGTranslateTransform.hxx
Normal file
53
simgear/scene/model/SGTranslateTransform.hxx
Normal file
@@ -0,0 +1,53 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2006-2007 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SG_TRANSLATE_TRANSFORM_HXX
|
||||
#define SG_TRANSLATE_TRANSFORM_HXX
|
||||
|
||||
#include <osg/Transform>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
class SGTranslateTransform : public osg::Transform {
|
||||
public:
|
||||
SGTranslateTransform();
|
||||
|
||||
void setAxis(const SGVec3d& axis)
|
||||
{ _axis = axis; dirtyBound(); }
|
||||
const SGVec3d& getAxis() const
|
||||
{ return _axis; }
|
||||
|
||||
void setValue(double value)
|
||||
{ _value = value; dirtyBound(); }
|
||||
double getValue() const
|
||||
{ return _value; }
|
||||
|
||||
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const;
|
||||
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const;
|
||||
virtual osg::BoundingSphere computeBound() const;
|
||||
|
||||
private:
|
||||
SGVec3d _axis;
|
||||
double _value;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,24 +14,34 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <osg/Vec3>
|
||||
#include <osg/Vec4>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/Group>
|
||||
#include <osg/Material>
|
||||
#include <osg/Node>
|
||||
#include <osg/NodeCallback>
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/TexMat>
|
||||
|
||||
#include <simgear/math/point3d.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <simgear/math/interpolater.hxx>
|
||||
#include <simgear/scene/model/persparam.hxx>
|
||||
#include <simgear/scene/util/SGNodeMasks.hxx>
|
||||
|
||||
|
||||
SG_USING_STD(vector);
|
||||
SG_USING_STD(map);
|
||||
|
||||
|
||||
// Don't pull in the headers, since we don't need them here.
|
||||
class SGInterpTable;
|
||||
class SGCondition;
|
||||
class SGPersonalityBranch;
|
||||
|
||||
|
||||
// Has anyone done anything *really* stupid, like making min and max macros?
|
||||
#ifdef min
|
||||
@@ -44,599 +54,323 @@ class SGPersonalityBranch;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Animation classes
|
||||
// Helper classes, FIXME: factor out
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Abstract base class for all animations.
|
||||
*/
|
||||
class SGAnimation : public ssgBase
|
||||
{
|
||||
class SGDoubleValue : public SGReferenced {
|
||||
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,
|
||||
INIT_TRANSLATE, FACTOR_TRANSLATE, OFFSET_TRANSLATE,
|
||||
INIT_BLEND, FACTOR_BLEND, OFFSET_BLEND,
|
||||
INIT_SCALE, X_FACTOR_SCALE, Y_FACTOR_SCALE, Z_FACTOR_SCALE,
|
||||
X_OFFSET_SCALE, Y_OFFSET_SCALE, Z_OFFSET_SCALE };
|
||||
virtual ~SGDoubleValue() {}
|
||||
virtual double getValue() const = 0;
|
||||
};
|
||||
|
||||
SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Base class for animation installers
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~SGAnimation ();
|
||||
class SGAnimation : protected osg::NodeVisitor {
|
||||
public:
|
||||
SGAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot);
|
||||
virtual ~SGAnimation();
|
||||
|
||||
/**
|
||||
* Get the SSG branch holding the animation.
|
||||
*/
|
||||
virtual ssgBranch * getBranch () { return _branch; }
|
||||
|
||||
/**
|
||||
* Initialize the animation, after children have been added.
|
||||
*/
|
||||
virtual void init ();
|
||||
|
||||
/**
|
||||
* Update the animation.
|
||||
*/
|
||||
virtual int update();
|
||||
|
||||
/**
|
||||
* Restore the state after the animation.
|
||||
*/
|
||||
virtual void restore();
|
||||
|
||||
/**
|
||||
* Set the value of sim_time_sec. This needs to be called every
|
||||
* frame in order for the time based animations to work correctly.
|
||||
*/
|
||||
static void set_sim_time_sec( double val ) { sim_time_sec = val; }
|
||||
|
||||
/**
|
||||
* Current personality branch : enable animation to behave differently
|
||||
* for similar objects
|
||||
*/
|
||||
static SGPersonalityBranch *current_object;
|
||||
|
||||
int get_animation_type(void) { return animation_type; }
|
||||
static bool animate(osg::Node* node, const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
|
||||
protected:
|
||||
void apply(osg::Node* node);
|
||||
|
||||
static double sim_time_sec;
|
||||
virtual void install(osg::Node& node);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
|
||||
ssgBranch * _branch;
|
||||
virtual void apply(osg::Group& group);
|
||||
|
||||
int animation_type;
|
||||
};
|
||||
void removeMode(osg::Node& node, osg::StateAttribute::GLMode mode);
|
||||
void removeAttribute(osg::Node& node, osg::StateAttribute::Type type);
|
||||
void removeTextureMode(osg::Node& node, unsigned unit,
|
||||
osg::StateAttribute::GLMode mode);
|
||||
void removeTextureAttribute(osg::Node& node, unsigned unit,
|
||||
osg::StateAttribute::Type type);
|
||||
void setRenderBinToInherit(osg::Node& node);
|
||||
void cloneDrawables(osg::Node& node);
|
||||
|
||||
std::string getType() const
|
||||
{ return std::string(_configNode->getStringValue("type", "")); }
|
||||
|
||||
/**
|
||||
* A no-op animation.
|
||||
*/
|
||||
class SGNullAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGNullAnimation (SGPropertyNode_ptr props);
|
||||
virtual ~SGNullAnimation ();
|
||||
};
|
||||
const SGPropertyNode* getConfig() const
|
||||
{ return _configNode; }
|
||||
SGPropertyNode* getModelRoot() const
|
||||
{ return _modelRoot; }
|
||||
|
||||
|
||||
/**
|
||||
* A range, or level-of-detail (LOD) animation.
|
||||
*/
|
||||
class SGRangeAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGRangeAnimation (SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props);
|
||||
virtual ~SGRangeAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _min_prop;
|
||||
SGPropertyNode_ptr _max_prop;
|
||||
float _min;
|
||||
float _max;
|
||||
float _min_factor;
|
||||
float _max_factor;
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Animation to turn and face the screen.
|
||||
*/
|
||||
class SGBillboardAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGBillboardAnimation (SGPropertyNode_ptr props);
|
||||
virtual ~SGBillboardAnimation ();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Animation to select alternative versions of the same object.
|
||||
*/
|
||||
class SGSelectAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGSelectAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGSelectAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Animation to spin an object around a center point.
|
||||
*
|
||||
* This animation rotates at a specific velocity.
|
||||
*/
|
||||
class SGSpinAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGSpinAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props,
|
||||
double sim_time_sec );
|
||||
virtual ~SGSpinAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
bool _use_personality;
|
||||
SGPropertyNode_ptr _prop;
|
||||
SGPersonalityParameter<double> _factor;
|
||||
SGPersonalityParameter<double> _position_deg;
|
||||
double _last_time_sec;
|
||||
sgMat4 _matrix;
|
||||
sgVec3 _center;
|
||||
sgVec3 _axis;
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Animation to draw objects for a specific amount of time each.
|
||||
*/
|
||||
class SGTimedAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGTimedAnimation (SGPropertyNode_ptr props);
|
||||
virtual ~SGTimedAnimation ();
|
||||
virtual void init();
|
||||
virtual int update();
|
||||
private:
|
||||
bool _use_personality;
|
||||
double _duration_sec;
|
||||
double _last_time_sec;
|
||||
double _total_duration_sec;
|
||||
int _step;
|
||||
struct DurationSpec {
|
||||
DurationSpec( double m = 0.0 ) : _min(m), _max(m) {}
|
||||
DurationSpec( double m1, double m2 ) : _min(m1), _max(m2) {}
|
||||
double _min, _max;
|
||||
};
|
||||
vector<DurationSpec> _branch_duration_specs;
|
||||
vector<double> _branch_duration_sec;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Animation to rotate an object around a center point.
|
||||
*
|
||||
* This animation rotates to a specific position.
|
||||
*/
|
||||
class SGRotateAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGRotateAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props );
|
||||
virtual ~SGRotateAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _prop;
|
||||
double _offset_deg;
|
||||
double _factor;
|
||||
SGInterpTable * _table;
|
||||
bool _has_min;
|
||||
double _min_deg;
|
||||
bool _has_max;
|
||||
double _max_deg;
|
||||
double _position_deg;
|
||||
sgMat4 _matrix;
|
||||
sgVec3 _center;
|
||||
sgVec3 _axis;
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Animation to slide along an axis.
|
||||
*/
|
||||
class SGTranslateAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGTranslateAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGTranslateAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
bool _use_personality;
|
||||
SGPropertyNode_ptr _prop;
|
||||
SGPersonalityParameter<double> _offset_m;
|
||||
SGPersonalityParameter<double> _factor;
|
||||
SGInterpTable * _table;
|
||||
bool _has_min;
|
||||
double _min_m;
|
||||
bool _has_max;
|
||||
double _max_m;
|
||||
double _position_m;
|
||||
sgMat4 _matrix;
|
||||
sgVec3 _axis;
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
/**
|
||||
* Animation to blend an object.
|
||||
*/
|
||||
class SGBlendAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGBlendAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGBlendAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
bool _use_personality;
|
||||
SGPropertyNode_ptr _prop;
|
||||
SGInterpTable * _table;
|
||||
double _prev_value;
|
||||
SGPersonalityParameter<double> _offset;
|
||||
SGPersonalityParameter<double> _factor;
|
||||
bool _has_min;
|
||||
double _min;
|
||||
bool _has_max;
|
||||
double _max;
|
||||
};
|
||||
|
||||
/**
|
||||
* Animation to scale an object.
|
||||
*/
|
||||
class SGScaleAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGScaleAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGScaleAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
bool _use_personality;
|
||||
SGPropertyNode_ptr _prop;
|
||||
SGPersonalityParameter<double> _x_factor;
|
||||
SGPersonalityParameter<double> _y_factor;
|
||||
SGPersonalityParameter<double> _z_factor;
|
||||
SGPersonalityParameter<double> _x_offset;
|
||||
SGPersonalityParameter<double> _y_offset;
|
||||
SGPersonalityParameter<double> _z_offset;
|
||||
SGInterpTable * _table;
|
||||
bool _has_min_x;
|
||||
bool _has_min_y;
|
||||
bool _has_min_z;
|
||||
double _min_x;
|
||||
double _min_y;
|
||||
double _min_z;
|
||||
bool _has_max_x;
|
||||
bool _has_max_y;
|
||||
bool _has_max_z;
|
||||
double _max_x;
|
||||
double _max_y;
|
||||
double _max_z;
|
||||
double _x_scale;
|
||||
double _y_scale;
|
||||
double _z_scale;
|
||||
sgMat4 _matrix;
|
||||
};
|
||||
|
||||
/**
|
||||
* Animation to rotate texture mappings around a center point.
|
||||
*
|
||||
* This animation rotates to a specific position.
|
||||
*/
|
||||
class SGTexRotateAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGTexRotateAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props );
|
||||
virtual ~SGTexRotateAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _prop;
|
||||
double _offset_deg;
|
||||
double _factor;
|
||||
SGInterpTable * _table;
|
||||
bool _has_min;
|
||||
double _min_deg;
|
||||
bool _has_max;
|
||||
double _max_deg;
|
||||
double _position_deg;
|
||||
sgMat4 _matrix;
|
||||
sgVec3 _center;
|
||||
sgVec3 _axis;
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Animation to slide texture mappings along an axis.
|
||||
*/
|
||||
class SGTexTranslateAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGTexTranslateAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGTexTranslateAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _prop;
|
||||
double _offset;
|
||||
double _factor;
|
||||
double _step;
|
||||
double _scroll;
|
||||
SGInterpTable * _table;
|
||||
bool _has_min;
|
||||
double _min;
|
||||
bool _has_max;
|
||||
double _max;
|
||||
double _position;
|
||||
sgMat4 _matrix;
|
||||
sgVec3 _axis;
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Classes for handling multiple types of Texture translations on one object
|
||||
*/
|
||||
|
||||
class SGTexMultipleAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGTexMultipleAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGTexMultipleAnimation ();
|
||||
virtual int update();
|
||||
private:
|
||||
class TexTransform
|
||||
{
|
||||
public:
|
||||
SGPropertyNode_ptr prop;
|
||||
int subtype; // 0=translation, 1=rotation
|
||||
double offset;
|
||||
double factor;
|
||||
double step;
|
||||
double scroll;
|
||||
SGInterpTable * table;
|
||||
bool has_min;
|
||||
double min;
|
||||
bool has_max;
|
||||
double max;
|
||||
double position;
|
||||
sgMat4 matrix;
|
||||
sgVec3 center;
|
||||
sgVec3 axis;
|
||||
};
|
||||
SGPropertyNode_ptr _prop;
|
||||
TexTransform* _transform;
|
||||
int _num_transforms;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An "animation" to enable the alpha test
|
||||
*/
|
||||
class SGAlphaTestAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGAlphaTestAnimation(SGPropertyNode_ptr props);
|
||||
virtual ~SGAlphaTestAnimation ();
|
||||
virtual void init();
|
||||
private:
|
||||
void setAlphaClampToBranch(ssgBranch *b, float clamp);
|
||||
float _alpha_clamp;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
bool _last_condition;
|
||||
SGPropertyNode_ptr _prop_root;
|
||||
string _prop_base;
|
||||
SGPath _texture_base;
|
||||
SGPath _texture;
|
||||
string _texture_str;
|
||||
ssgSimpleState* _cached_material;
|
||||
ssgSimpleState* _cloned_material;
|
||||
unsigned _read;
|
||||
unsigned _update;
|
||||
unsigned _static_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
|
||||
*/
|
||||
class SGFlashAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGFlashAnimation(SGPropertyNode_ptr props);
|
||||
virtual ~SGFlashAnimation ();
|
||||
|
||||
static void flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d );
|
||||
void flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m );
|
||||
const SGCondition* getCondition() const;
|
||||
|
||||
private:
|
||||
sgVec3 _axis, _center;
|
||||
float _power, _factor, _offset, _min_v, _max_v;
|
||||
bool _two_sides;
|
||||
void installInGroup(const std::string& name, osg::Group& group,
|
||||
osg::ref_ptr<osg::Group>& animationGroup);
|
||||
|
||||
class RemoveModeVisitor;
|
||||
class RemoveAttributeVisitor;
|
||||
class RemoveTextureModeVisitor;
|
||||
class RemoveTextureAttributeVisitor;
|
||||
class BinToInheritVisitor;
|
||||
class DrawableCloneVisitor;
|
||||
|
||||
bool _found;
|
||||
std::string _name;
|
||||
SGSharedPtr<SGPropertyNode const> _configNode;
|
||||
SGPropertyNode* _modelRoot;
|
||||
std::list<std::string> _objectNames;
|
||||
std::list<osg::ref_ptr<osg::Node> > _installedAnimations;
|
||||
bool _enableHOT;
|
||||
bool _disableShadow;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Null animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* An animation that compute a scale according to
|
||||
* the distance from a point and the viewer
|
||||
*/
|
||||
class SGDistScaleAnimation : public SGAnimation
|
||||
{
|
||||
class SGGroupAnimation : public SGAnimation {
|
||||
public:
|
||||
SGDistScaleAnimation(SGPropertyNode_ptr props);
|
||||
virtual ~SGDistScaleAnimation ();
|
||||
SGGroupAnimation(const SGPropertyNode*, SGPropertyNode*);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
};
|
||||
|
||||
static void distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d );
|
||||
void distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m );
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Translate animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGTranslateAnimation : public SGAnimation {
|
||||
public:
|
||||
SGTranslateAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
sgVec3 _center;
|
||||
float _factor, _offset, _min_v, _max_v;
|
||||
bool _has_min, _has_max;
|
||||
SGInterpTable * _table;
|
||||
class UpdateCallback;
|
||||
SGSharedPtr<const SGCondition> _condition;
|
||||
SGSharedPtr<const SGDoubleValue> _animationValue;
|
||||
SGVec3d _axis;
|
||||
double _initialValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* An animation to tell wich objects don't cast shadows.
|
||||
*/
|
||||
class SGShadowAnimation : public SGAnimation
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Rotate/Spin animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGRotateAnimation : public SGAnimation {
|
||||
public:
|
||||
SGShadowAnimation ( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGShadowAnimation ();
|
||||
virtual int update();
|
||||
bool get_condition_value(void);
|
||||
SGRotateAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
SGCondition * _condition;
|
||||
bool _condition_value;
|
||||
class UpdateCallback;
|
||||
class SpinUpdateCallback;
|
||||
SGSharedPtr<const SGCondition> _condition;
|
||||
SGSharedPtr<const SGDoubleValue> _animationValue;
|
||||
SGVec3d _axis;
|
||||
SGVec3d _center;
|
||||
double _initialValue;
|
||||
bool _isSpin;
|
||||
};
|
||||
|
||||
/**
|
||||
+ * An "animation" that replace fixed opengl pipeline by shaders
|
||||
+ */
|
||||
class SGShaderAnimation : public SGAnimation
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Scale animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGScaleAnimation : public SGAnimation {
|
||||
public:
|
||||
SGShaderAnimation ( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGShaderAnimation ();
|
||||
virtual void init();
|
||||
virtual int update();
|
||||
bool get_condition_value(void);
|
||||
SGScaleAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
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;
|
||||
class UpdateCallback;
|
||||
SGSharedPtr<const SGCondition> _condition;
|
||||
SGSharedPtr<const SGDoubleValue> _animationValue[3];
|
||||
SGVec3d _initialValue;
|
||||
SGVec3d _center;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// dist scale animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGDistScaleAnimation : public SGAnimation {
|
||||
public:
|
||||
SGDistScaleAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
class Transform;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// dist scale animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGFlashAnimation : public SGAnimation {
|
||||
public:
|
||||
SGFlashAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
class Transform;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// dist scale animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGBillboardAnimation : public SGAnimation {
|
||||
public:
|
||||
SGBillboardAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
class Transform;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Range animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGRangeAnimation : public SGAnimation {
|
||||
public:
|
||||
SGRangeAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
class UpdateCallback;
|
||||
SGSharedPtr<const SGCondition> _condition;
|
||||
SGSharedPtr<const SGDoubleValue> _minAnimationValue;
|
||||
SGSharedPtr<const SGDoubleValue> _maxAnimationValue;
|
||||
SGVec2d _initialValue;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Select animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGSelectAnimation : public SGAnimation {
|
||||
public:
|
||||
SGSelectAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
class UpdateCallback;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Alpha test animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGAlphaTestAnimation : public SGAnimation {
|
||||
public:
|
||||
SGAlphaTestAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual void install(osg::Node& node);
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Blend animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGBlendAnimation : public SGAnimation {
|
||||
public:
|
||||
SGBlendAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
virtual void install(osg::Node& node);
|
||||
private:
|
||||
class BlendVisitor;
|
||||
class UpdateCallback;
|
||||
SGSharedPtr<SGDoubleValue> _animationValue;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Timed animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGTimedAnimation : public SGAnimation {
|
||||
public:
|
||||
SGTimedAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
class UpdateCallback;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Shadow animation installer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGShadowAnimation : public SGAnimation {
|
||||
public:
|
||||
SGShadowAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
class UpdateCallback;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// TextureTransform animation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGTexTransformAnimation : public SGAnimation {
|
||||
public:
|
||||
SGTexTransformAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
class Transform;
|
||||
class Translation;
|
||||
class Rotation;
|
||||
class UpdateCallback;
|
||||
void appendTexTranslate(const SGPropertyNode* config,
|
||||
UpdateCallback* updateCallback);
|
||||
void appendTexRotate(const SGPropertyNode* config,
|
||||
UpdateCallback* updateCallback);
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Shader animation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGShaderAnimation : public SGAnimation {
|
||||
public:
|
||||
SGShaderAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
class UpdateCallback;
|
||||
osg::ref_ptr<osg::Texture2D> _effect_texture;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Pick animation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SGPickAnimation : public SGAnimation {
|
||||
public:
|
||||
SGPickAnimation(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot);
|
||||
virtual osg::Group* createAnimationGroup(osg::Group& parent);
|
||||
private:
|
||||
class PickCallback;
|
||||
};
|
||||
|
||||
#endif // _SG_ANIMATION_HXX
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include "custtrans.hxx"
|
||||
void _ssgPushMatrix ( sgMat4 m );
|
||||
void _ssgPopMatrix ();
|
||||
|
||||
void SGCustomTransform::copy_from( SGCustomTransform *src, int clone_flags )
|
||||
{
|
||||
ssgBranch::copy_from( src, clone_flags );
|
||||
_callback = src->_callback;
|
||||
_data = src->_data;
|
||||
}
|
||||
|
||||
ssgBase *SGCustomTransform::clone( int clone_flags )
|
||||
{
|
||||
SGCustomTransform *b = new SGCustomTransform;
|
||||
b -> copy_from( this, clone_flags );
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
SGCustomTransform::SGCustomTransform()
|
||||
: _callback(0),_data(0)
|
||||
{
|
||||
type = ssgTypeBranch();
|
||||
}
|
||||
|
||||
SGCustomTransform::~SGCustomTransform()
|
||||
{
|
||||
}
|
||||
|
||||
void SGCustomTransform::cull( sgFrustum *f, sgMat4 m, int test_needed )
|
||||
{
|
||||
if ( ! preTravTests( &test_needed, SSGTRAV_CULL ) )
|
||||
return;
|
||||
|
||||
if ( _callback ) {
|
||||
sgMat4 tmp;
|
||||
_callback( tmp, f, m, _data );
|
||||
|
||||
_ssgPushMatrix( tmp );
|
||||
glPushMatrix();
|
||||
glLoadMatrixf( (float *) tmp );
|
||||
|
||||
for ( ssgEntity *e = getKid ( 0 ); e != NULL; e = getNextKid() )
|
||||
e -> cull( f, tmp, test_needed );
|
||||
|
||||
glPopMatrix();
|
||||
_ssgPopMatrix();
|
||||
}
|
||||
postTravTests( SSGTRAV_CULL );
|
||||
}
|
||||
|
||||
|
||||
const char *SGCustomTransform::getTypeName (void) { return "SGCustomTransform"; }
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _SG_CUSTOM_TRANSFORM_HXX
|
||||
#define _SG_CUSTOM_TRANSFORM_HXX 1
|
||||
|
||||
#include "plib/ssg.h"
|
||||
|
||||
class SGCustomTransform : public ssgBranch
|
||||
{
|
||||
public:
|
||||
typedef void (*TransCallback)( sgMat4 r, sgFrustum *f, sgMat4 m, void *d );
|
||||
virtual ssgBase *clone( int clone_flags = 0 );
|
||||
SGCustomTransform();
|
||||
virtual ~SGCustomTransform(void);
|
||||
|
||||
void setTransCallback( TransCallback c, void *d ) {
|
||||
_callback = c;
|
||||
_data = d;
|
||||
}
|
||||
|
||||
virtual const char *getTypeName(void);
|
||||
virtual void cull( sgFrustum *f, sgMat4 m, int test_needed );
|
||||
|
||||
protected:
|
||||
virtual void copy_from( SGCustomTransform *src, int clone_flags );
|
||||
|
||||
private:
|
||||
TransCallback _callback;
|
||||
void *_data;
|
||||
};
|
||||
|
||||
#endif // _SG_CUSTOM_TRANSFORM_HXX
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user