BGE: Occlusion culling and other performance improvements.
authorBenoit Bolsee <benoit.bolsee@online.be>
Mon, 13 Apr 2009 20:08:33 +0000 (20:08 +0000)
committerBenoit Bolsee <benoit.bolsee@online.be>
Mon, 13 Apr 2009 20:08:33 +0000 (20:08 +0000)
Added occlusion culling capability in the BGE.
More info: http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.49/Game_Engine#BGE_Scenegraph_improvement
MSVC, scons, cmake, Makefile updated.

Other minor performance improvements:
- The rasterizer was computing the openGL model matrix of the objects too many times
- DBVT view frustrum culling was not properly culling behind the near plane:
  Large objects behind the camera were sent to the GPU
- Remove all references to mesh split/join feature as it is not yet functional

37 files changed:
projectfiles_vc9/blender/blender.vcproj
projectfiles_vc9/gameengine/gameplayer/ghost/GP_ghost.vcproj
projectfiles_vc9/gameengine/physics/PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj
source/blender/blenkernel/intern/world.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_actuator_types.h
source/blender/makesdna/DNA_object_types.h
source/blender/makesdna/DNA_world_types.h
source/blender/python/api2_2x/Object.c
source/blender/src/buttons_logic.c
source/blender/src/buttons_shading.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Converter/KX_BlenderSceneConverter.cpp
source/gameengine/Converter/KX_ConvertActuators.cpp
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Ketsji/KX_KetsjiEngine.cpp
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_Scene.h
source/gameengine/Ketsji/KX_VisibilityActuator.cpp
source/gameengine/Ketsji/KX_VisibilityActuator.h
source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h
source/gameengine/Physics/Bullet/CMakeLists.txt
source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
source/gameengine/Physics/Bullet/Makefile
source/gameengine/Physics/Bullet/SConscript
source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h
source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
source/gameengine/PyDoc/KX_GameObject.py
source/gameengine/PyDoc/KX_VisibilityActuator.py
source/gameengine/Rasterizer/RAS_MaterialBucket.cpp
source/gameengine/Rasterizer/RAS_MeshObject.cpp
source/gameengine/Rasterizer/RAS_Polygon.cpp
source/gameengine/Rasterizer/RAS_Polygon.h
source/gameengine/VideoTexture/ImageRender.cpp

index 03f57a9..2f1bf46 100644 (file)
@@ -81,6 +81,7 @@
                                AdditionalLibraryDirectories="..\..\..\lib\windows\sdl\lib;..\..\..\lib\windows\ode\lib;..\..\..\lib\windows\zlib\lib;..\..\..\lib\windows\png\lib;..\..\..\lib\windows\jpeg\lib;..\..\..\lib\windows\gettext\lib;..\..\..\lib\windows\python\lib\lib25_vs2008;..\..\..\lib\windows\freetype\lib;..\..\..\lib\windows\tiff\lib;..\..\..\lib\windows\pthreads\lib;..\..\..\lib\windows\openal\lib;..\..\..\lib\windows\openexr\lib_vs2008;..\..\..\lib\windows\QTDevWin\Libraries;..\..\..\build\msvc_9\libs\intern;..\..\..\build\msvc_9\libs\extern;..\..\..\lib\windows\ffmpeg\lib"\r
                                IgnoreAllDefaultLibraries="false"\r
                                IgnoreDefaultLibraryNames="msvcprt.lib;glut32.lib;libc.lib;libcd.lib;libcpd.lib;libcp.lib;libcmtd.lib;odbc32.lib;odbccp32.lib"\r
+                               GenerateDebugInformation="true"\r
                                ProgramDatabaseFile="..\..\..\build\msvc_9\libs\blender.pdb"\r
                                SubSystem="1"\r
                                RandomizedBaseAddress="1"\r
                        <Tool\r
                                Name="VCLinkerTool"\r
                                AdditionalOptions="/MACHINE:I386&#x0D;&#x0A;"\r
-                               AdditionalDependencies="SDL.lib freetype2ST.lib gnu_gettext.lib qtmlClient.lib openal_static.lib ws2_32.lib dxguid.lib opengl32.lib libjpeg.lib glu32.lib vfw32.lib winmm.lib libpng_st.lib zlib.lib python25_d.lib pthreadVSE2.lib pthreadVC2.lib libtiff.lib Half.lib Iex.lib Imath.lib IlmImf.lib IlmThread.lib avcodec-52.lib avformat-52.lib avdevice-52.lib avutil-50.lib swscale-0.lib"\r
+                               AdditionalDependencies="SDL.lib freetype2ST.lib gnu_gettext.lib qtmlClient.lib openal_static.lib ws2_32.lib dxguid.lib opengl32.lib libjpeg.lib glu32.lib vfw32.lib winmm.lib libpng_st.lib zlib.lib python25_d.lib pthreadVSE2.lib pthreadVC2.lib libtiff.lib Half_d.lib Iex_d.lib Imath_d.lib IlmImf_d.lib IlmThread_d.lib avcodec-52.lib avformat-52.lib avdevice-52.lib avutil-50.lib swscale-0.lib"\r
                                ShowProgress="0"\r
                                OutputFile="..\..\bin\debug\blender.exe"\r
                                LinkIncremental="2"\r
index 336c40e..01ccd91 100644 (file)
@@ -72,7 +72,7 @@
                        <Tool\r
                                Name="VCLinkerTool"\r
                                AdditionalOptions="/MACHINE:I386&#x0D;&#x0A;"\r
-                               AdditionalDependencies="odelib.lib fmodvc.lib ws2_32.lib vfw32.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib openal_static.lib libjpeg.lib dxguid.lib libeay32.lib libpng.lib libz.lib qtmlClient.lib SDL.lib freetype2ST.lib python25_d.lib pthreadVSE2.lib pthreadVC2.lib Half.lib Iex.lib IlmImf.lib IlmThread.lib Imath.lib avcodec-52.lib avformat-52.lib avutil-50.lib swscale-0.lib avdevice-52.lib"\r
+                               AdditionalDependencies="odelib.lib fmodvc.lib ws2_32.lib vfw32.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib openal_static.lib libjpeg.lib dxguid.lib libeay32.lib libpng.lib libz.lib qtmlClient.lib SDL.lib freetype2ST.lib python25_d.lib pthreadVSE2.lib pthreadVC2.lib Half_d.lib Iex_d.lib IlmImf_d.lib IlmThread_d.lib Imath_d.lib avcodec-52.lib avformat-52.lib avutil-50.lib swscale-0.lib avdevice-52.lib"\r
                                ShowProgress="0"\r
                                OutputFile="..\..\..\..\bin\debug\blenderplayer.exe"\r
                                LinkIncremental="2"\r
index c941704..e699159 100644 (file)
@@ -42,7 +42,7 @@
                        <Tool\r
                                Name="VCCLCompilerTool"\r
                                Optimization="0"\r
-                               AdditionalIncludeDirectories="..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
+                               AdditionalIncludeDirectories="..\..\..\..\..\..\lib\windows\python\include\python2.5;..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\..\build\msvc_9\extern\glew\include;..\..\..\..\..\..\build\msvc_9\intern\SoundSystem\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\gameengine\Ketsji;..\..\..\..\..\source\gameengine\Expressions;..\..\..\..\..\source\gameengine\GameLogic;..\..\..\..\..\source\gameengine\SceneGraph;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
                                PreprocessorDefinitions="WIN32;_DEBUG;_LIB"\r
                                MinimalRebuild="false"\r
                                BasicRuntimeChecks="3"\r
                        />\r
                        <Tool\r
                                Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories="..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
+                               AdditionalIncludeDirectories="..\..\..\..\..\..\lib\windows\python\include\python2.5;..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\..\build\msvc_9\extern\glew\include;..\..\..\..\..\..\build\msvc_9\intern\SoundSystem\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\gameengine\Ketsji;..\..\..\..\..\source\gameengine\Expressions;..\..\..\..\..\source\gameengine\GameLogic;..\..\..\..\..\source\gameengine\SceneGraph;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
                                PreprocessorDefinitions="WIN32;NDEBUG;_LIB"\r
                                RuntimeLibrary="0"\r
                                UsePrecompiledHeader="0"\r
                        />\r
                        <Tool\r
                                Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories="..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
+                               AdditionalIncludeDirectories="..\..\..\..\..\..\lib\windows\python\include\python2.5;..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\..\build\msvc_9\extern\glew\include;..\..\..\..\..\..\build\msvc_9\intern\SoundSystem\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\gameengine\Ketsji;..\..\..\..\..\source\gameengine\Expressions;..\..\..\..\..\source\gameengine\GameLogic;..\..\..\..\..\source\gameengine\SceneGraph;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
                                PreprocessorDefinitions="WIN32;NDEBUG;_LIB"\r
                                RuntimeLibrary="0"\r
                                UsePrecompiledHeader="0"\r
                        <Tool\r
                                Name="VCCLCompilerTool"\r
                                Optimization="0"\r
-                               AdditionalIncludeDirectories="..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
+                               AdditionalIncludeDirectories="..\..\..\..\..\..\lib\windows\python\include\python2.5;..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\..\build\msvc_9\extern\glew\include;..\..\..\..\..\..\build\msvc_9\intern\SoundSystem\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\gameengine\Ketsji;..\..\..\..\..\source\gameengine\Expressions;..\..\..\..\..\source\gameengine\GameLogic;..\..\..\..\..\source\gameengine\SceneGraph;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
                                PreprocessorDefinitions="WIN32;_DEBUG;_LIB"\r
                                MinimalRebuild="false"\r
                                BasicRuntimeChecks="3"\r
                        <Tool\r
                                Name="VCCLCompilerTool"\r
                                Optimization="0"\r
-                               AdditionalIncludeDirectories="..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
+                               AdditionalIncludeDirectories="..\..\..\..\..\..\lib\windows\python\include\python2.5;..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\..\build\msvc_9\extern\glew\include;..\..\..\..\..\..\build\msvc_9\intern\SoundSystem\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\gameengine\Ketsji;..\..\..\..\..\source\gameengine\Expressions;..\..\..\..\..\source\gameengine\GameLogic;..\..\..\..\..\source\gameengine\SceneGraph;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
                                PreprocessorDefinitions="WIN32;_DEBUG;_LIB"\r
                                MinimalRebuild="false"\r
                                BasicRuntimeChecks="3"\r
                        />\r
                        <Tool\r
                                Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories="..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
+                               AdditionalIncludeDirectories="..\..\..\..\..\..\lib\windows\python\include\python2.5;..\..\..\..\..\..\build\msvc_9\intern\moto\include;..\..\..\..\..\..\build\msvc_9\intern\string\include;..\..\..\..\..\..\build\msvc_9\extern\bullet\include;..\..\..\..\..\..\build\msvc_9\extern\glew\include;..\..\..\..\..\..\build\msvc_9\intern\SoundSystem\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\gameengine\Ketsji;..\..\..\..\..\source\gameengine\Expressions;..\..\..\..\..\source\gameengine\GameLogic;..\..\..\..\..\source\gameengine\SceneGraph;..\..\..\..\..\source\kernel\gen_system;..\..\..\..\..\source\blender\makesdna"\r
                                PreprocessorDefinitions="WIN32;NDEBUG;_LIB"\r
                                RuntimeLibrary="2"\r
                                UsePrecompiledHeader="0"\r
index 594d18f..6635ef2 100644 (file)
@@ -106,7 +106,8 @@ World *add_world(char *name)
        wrld->ao_approx_error= 0.25f;
        
        wrld->physicsEngine= WOPHY_BULLET;//WOPHY_SUMO; Bullet by default
-       wrld->mode = WO_DBVT_CAMERA_CULLING;    // DBVT culling by default
+       wrld->mode = WO_DBVT_CULLING;   // DBVT culling by default
+       wrld->occlusionRes = 128;
        wrld->preview = NULL;
 
        return wrld;
index 63dd1e8..c3a3551 100644 (file)
@@ -8057,7 +8057,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                }
                /* DBVT culling by default */
                for(wrld=main->world.first; wrld; wrld= wrld->id.next) {
-                       wrld->mode |= WO_DBVT_CAMERA_CULLING;
+                       wrld->mode |= WO_DBVT_CULLING;
+                       wrld->occlusionRes = 128;
                }
        }
 
index 2252126..aeabae4 100644 (file)
@@ -195,7 +195,8 @@ typedef struct bGameActuator {
 
 typedef struct bVisibilityActuator {
        /** bit 0: Is this object visible? 
-        ** bit 1: Apply recursively  */
+        ** bit 1: Apply recursively  
+        ** bit 2: Is this object an occluder? */
        int flag;
 } bVisibilityActuator;
 
@@ -458,6 +459,7 @@ typedef struct FreeCamera {
 /* Set means the object will become invisible */
 #define ACT_VISIBILITY_INVISIBLE       (1 << 0)
 #define ACT_VISIBILITY_RECURSIVE       (1 << 1)
+#define ACT_VISIBILITY_OCCLUSION       (1 << 2)
 
 /* twodfilter->type */
 #define ACT_2DFILTER_ENABLED                   -2
index b17896a..3a40840 100644 (file)
@@ -437,6 +437,7 @@ extern Object workob;
 
 #define OB_COLLISION   65536
 #define OB_SOFT_BODY   0x20000
+#define OB_OCCLUDER            0x40000
 
 /* ob->gameflag2 */
 #define OB_NEVER_DO_ACTIVITY_CULLING   1
@@ -455,6 +456,7 @@ extern Object workob;
 #define OB_BODY_TYPE_DYNAMIC           2
 #define OB_BODY_TYPE_RIGID                     3
 #define OB_BODY_TYPE_SOFT                      4
+#define OB_BODY_TYPE_OCCLUDER          5
 
 /* ob->scavisflag */
 #define OB_VIS_SENS            1
index a51e970..f599364 100644 (file)
@@ -88,7 +88,8 @@ typedef struct World {
         * bit 5: (gameengine) : enable Bullet DBVT tree for view frustrum culling 
         */
        short mode;
-       int physicsEngine;      /* here it's aligned */
+       short occlusionRes;             /* resolution of occlusion Z buffer in pixel */
+       short physicsEngine;    /* here it's aligned */
        
        float misi, miststa, mistdist, misthi;
        
@@ -135,7 +136,7 @@ typedef struct World {
 #define WO_DOF                 4
 #define WO_ACTIVITY_CULLING       8
 #define WO_AMB_OCC                       16
-#define WO_DBVT_CAMERA_CULLING  32
+#define WO_DBVT_CULLING                  32
 
 /* aomix */
 #define WO_AOADD       0
index fd2301b..2de2906 100644 (file)
@@ -3561,7 +3561,7 @@ static int Object_setRBMass( BPy_Object * self, PyObject * args )
 
 /* this is too low level, possible to add helper methods */
 
-#define GAMEFLAG_MASK ( OB_COLLISION | OB_DYNAMIC | OB_CHILD | OB_ACTOR | OB_DO_FH | \
+#define GAMEFLAG_MASK ( OB_OCCLUDER | OB_COLLISION | OB_DYNAMIC | OB_CHILD | OB_ACTOR | OB_DO_FH | \
                OB_ROT_FH | OB_ANISOTROPIC_FRICTION | OB_GHOST | OB_RIGID_BODY | OB_SOFT_BODY | \
                OB_BOUNDS | OB_COLLISION_RESPONSE | OB_SECTOR | OB_PROP | \
                OB_MAINACTOR )
@@ -5542,6 +5542,7 @@ static PyObject *M_Object_RBFlagsDict( void )
 
        if( M ) {
                BPy_constant *d = ( BPy_constant * ) M;
+               PyConstant_Insert( d, "OCCLUDER", PyInt_FromLong( OB_OCCLUDER ) );
                PyConstant_Insert( d, "COLLISION", PyInt_FromLong( OB_COLLISION ) );
                PyConstant_Insert( d, "DYNAMIC", PyInt_FromLong( OB_DYNAMIC ) );
                PyConstant_Insert( d, "CHILD", PyInt_FromLong( OB_CHILD ) );
index 97f07c7..2f68720 100644 (file)
@@ -2455,18 +2455,18 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
                          xco + 10, yco - 20, (width - 20)/3, 19, &visAct->flag,
                          0.0, 0.0, 0, 0,
                          "Set the objects visible. Initialized from the objects render restriction toggle (access in the outliner)");
-               uiDefButBitI(block, TOG, ACT_VISIBILITY_INVISIBLE, B_REDR,
-                         "Invisible",
+               uiDefButBitI(block, TOG, ACT_VISIBILITY_OCCLUSION, B_REDR,
+                         "Occlusion",
                          xco + 10 + ((width - 20)/3), yco - 20, (width - 20)/3, 19, &visAct->flag,
                          0.0, 0.0, 0, 0,
-                         "Set the object invisible. Initialized from the objects render restriction toggle (access in the outliner)");
+                         "Set the object to occlude objects behind it. Initialized from the object type in physics button");
                uiBlockEndAlign(block);
                
                uiDefButBitI(block, TOG, ACT_VISIBILITY_RECURSIVE, B_NOP,
                          "Children",
                          xco + 10 + (((width - 20)/3)*2)+10, yco - 20, ((width - 20)/3)-10, 19, &visAct->flag,
                          0.0, 0.0, 0, 0,
-                         "Sets all the children of this object to the same visibility recursively");
+                         "Sets all the children of this object to the same visibility/occlusion recursively");
 
                yco-= ysize;
 
@@ -3033,25 +3033,29 @@ static void check_body_type(void *arg1_but, void *arg2_object)
        Object *ob = arg2_object;
 
        switch (ob->body_type) {
+       case OB_BODY_TYPE_OCCLUDER:
+               ob->gameflag |= OB_OCCLUDER;
+               ob->gameflag &= ~(OB_COLLISION|OB_DYNAMIC);
+               break;
        case OB_BODY_TYPE_NO_COLLISION:
-               ob->gameflag &= ~OB_COLLISION;
+               ob->gameflag &= ~(OB_COLLISION|OB_OCCLUDER|OB_DYNAMIC);
                break;
        case OB_BODY_TYPE_STATIC:
                ob->gameflag |= OB_COLLISION;
-               ob->gameflag &= ~(OB_DYNAMIC|OB_RIGID_BODY|OB_SOFT_BODY);
+               ob->gameflag &= ~(OB_DYNAMIC|OB_RIGID_BODY|OB_SOFT_BODY|OB_OCCLUDER);
                break;
        case OB_BODY_TYPE_DYNAMIC:
                ob->gameflag |= OB_COLLISION|OB_DYNAMIC|OB_ACTOR;
-               ob->gameflag &= ~(OB_RIGID_BODY|OB_SOFT_BODY);
+               ob->gameflag &= ~(OB_RIGID_BODY|OB_SOFT_BODY|OB_OCCLUDER);
                break;
        case OB_BODY_TYPE_RIGID:
                ob->gameflag |= OB_COLLISION|OB_DYNAMIC|OB_RIGID_BODY|OB_ACTOR;
-               ob->gameflag &= ~(OB_SOFT_BODY);
+               ob->gameflag &= ~(OB_SOFT_BODY|OB_OCCLUDER);
                break;
        default:
        case OB_BODY_TYPE_SOFT:
                ob->gameflag |= OB_COLLISION|OB_DYNAMIC|OB_SOFT_BODY|OB_ACTOR;
-               ob->gameflag &= ~(OB_RIGID_BODY);
+               ob->gameflag &= ~(OB_RIGID_BODY|OB_OCCLUDER);
                
                /* assume triangle mesh, if no bounds chosen for soft body */
                if ((ob->gameflag & OB_BOUNDS) && (ob->boundtype<OB_BOUND_POLYH))
@@ -3216,7 +3220,7 @@ static void buttons_bullet(uiBlock *block, Object *ob)
 
        /* determine the body_type setting based on flags */
        if (!(ob->gameflag & OB_COLLISION))
-               ob->body_type = OB_BODY_TYPE_NO_COLLISION;
+               ob->body_type = (ob->gameflag & OB_OCCLUDER) ? OB_BODY_TYPE_OCCLUDER : OB_BODY_TYPE_NO_COLLISION;
        else if (!(ob->gameflag & OB_DYNAMIC))
                ob->body_type = OB_BODY_TYPE_STATIC;
        else if (!(ob->gameflag & (OB_RIGID_BODY|OB_SOFT_BODY)))
@@ -3234,7 +3238,7 @@ static void buttons_bullet(uiBlock *block, Object *ob)
 
        //only enable game soft body if Blender Soft Body exists
        but = uiDefButS(block, MENU, REDRAWVIEW3D, 
-                       "Object type%t|No collision%x0|Static%x1|Dynamic%x2|Rigid body%x3|Soft body%x4", 
+                       "Object type%t|Occluder%x5|No collision%x0|Static%x1|Dynamic%x2|Rigid body%x3|Soft body%x4", 
                        10, 205, 100, 19, &ob->body_type, 0, 0, 0, 0, "Selects the type of physical representation");
        uiButSetFunc(but, check_body_type, but, ob);
 
index e68c863..a129698 100644 (file)
@@ -2181,7 +2181,7 @@ static void world_panel_mistaph(World *wrld)
        uiSetButLock(wrld->id.lib!=0, ERROR_LIBDATA_MESSAGE);
 
 #if GAMEBLENDER == 1
-       uiDefButI(block, MENU, B_REDR, 
+       uiDefButS(block, MENU, B_REDR, 
 #ifdef USE_ODE
                          "Physics %t|None %x0|Sumo %x2|Ode %x4 |Bullet %x5",
 #else
@@ -2198,8 +2198,12 @@ static void world_panel_mistaph(World *wrld)
        
        /* Gravitation for the game worlds */
        uiDefButF(block, NUMSLI,0, "Grav ", 150,180,150,19,     &(wrld->gravity), 0.0, 25.0, 0, 0,  "Sets the gravitation constant of the game world");
-       if (wrld->physicsEngine == WOPHY_BULLET)
-               uiDefButBitS(block, TOG, WO_DBVT_CAMERA_CULLING, 0, "DBVT culling",     10,160,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles use of optimized Bullet DBVT tree for camera culling");
+       if (wrld->physicsEngine == WOPHY_BULLET) {
+               uiDefButBitS(block, TOG, WO_DBVT_CULLING, B_REDR, "DBVT culling",       10,160,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles use of optimized Bullet DBVT tree for view frustrum and occlusion culling");
+               if (wrld->mode & WO_DBVT_CULLING)
+                       uiDefButS(block, NUM, B_REDR, "Occlu Res:",
+                               150, 160, 150, 19, &wrld->occlusionRes, 128.0, 1024.0, 0, 0, "Sets the size of the occlusion buffer in pixel, use higher value for better precsion (slower)");
+       }
 #endif
 
        uiBlockSetCol(block, TH_BUT_SETTING1);
index 50a660e..5de2c4a 100644 (file)
@@ -843,6 +843,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools*
        
                {
                        bool visible = true;
+                       bool twoside = false;
                        RAS_IPolyMaterial* polymat = NULL;
                        BL_Material *bl_mat = NULL;
 
@@ -859,6 +860,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools*
 
                                visible = ((bl_mat->ras_mode & POLY_VIS)!=0);
                                collider = ((bl_mat->ras_mode & COLLIDER)!=0);
+                               twoside = ((bl_mat->mode & TF_TWOSIDE)!=0);
 
                                /* vertex colors and uv's were stored in bl_mat temporarily */
                                bl_mat->GetConversionRGB(rgb);
@@ -899,6 +901,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools*
                                        mode = tface->mode;
                                        
                                        visible = !((mface->flag & ME_HIDE)||(tface->mode & TF_INVISIBLE));
+                                       twoside = ((tface->mode & TF_TWOSIDE)!=0);
                                        
                                        uv0.setValue(tface->uv[0]);
                                        uv1.setValue(tface->uv[1]);
@@ -999,6 +1002,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools*
 
                        poly->SetVisible(visible);
                        poly->SetCollider(collider);
+                       poly->SetTwoside(twoside);
                        //poly->SetEdgeCode(mface->edcode);
 
                        meshobj->AddVertex(poly,0,pt0,uv0,uv20,tan0,rgb0,no0,flat,mface->v1);
@@ -1677,6 +1681,7 @@ static KX_GameObject *gameobject_from_blenderobject(
                bool ignoreActivityCulling =  
                        ((ob->gameflag2 & OB_NEVER_DO_ACTIVITY_CULLING)!=0);
                gameobj->SetIgnoreActivityCulling(ignoreActivityCulling);
+               gameobj->SetOccluder((ob->gameflag & OB_OCCLUDER) != 0, false);
        
                // two options exists for deform: shape keys and armature
                // only support relative shape key
@@ -1894,12 +1899,14 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
        if (blenderscene->world) {
                kxscene->SetActivityCulling( (blenderscene->world->mode & WO_ACTIVITY_CULLING) != 0);
                kxscene->SetActivityCullingRadius(blenderscene->world->activityBoxRadius);
-               kxscene->SetDbvtCameraCulling((blenderscene->world->mode & WO_DBVT_CAMERA_CULLING) != 0);
+               kxscene->SetDbvtCulling((blenderscene->world->mode & WO_DBVT_CULLING) != 0);
        } else {
                kxscene->SetActivityCulling(false);
-               kxscene->SetDbvtCameraCulling(false);
+               kxscene->SetDbvtCulling(false);
        }
-       
+       // no occlusion culling by default
+       kxscene->SetDbvtOcclusionRes(0);
+
        int activeLayerBitInfo = blenderscene->lay;
        
        // templist to find Root Parents (object with no parents)
@@ -2452,8 +2459,9 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
        }
        
        // create graphic controller for culling
-       if (kxscene->GetDbvtCameraCulling())
+       if (kxscene->GetDbvtCulling())
        {
+               bool occlusion = false;
                for (i=0; i<sumolist->GetCount();i++)
                {
                        KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
@@ -2464,8 +2472,12 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                                // box[0] is the min, box[1] is the max
                                bool isactive = objectlist->SearchValue(gameobj);
                                BL_CreateGraphicObjectNew(gameobj,box[0],box[1],kxscene,isactive,physics_engine);
+                               if (gameobj->GetOccluder())
+                                       occlusion = true;
                        }
                }
+               if (occlusion)
+                       kxscene->SetDbvtOcclusionRes(blenderscene->world->occlusionRes);
        }
        
        //set ini linearVel and int angularVel //rcruiz
index b0c676a..190f9db 100644 (file)
@@ -283,7 +283,7 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename,
                        case WOPHY_BULLET:
                                {
                                        physics_engine = UseBullet;
-                                       useDbvtCulling = (blenderscene->world->mode & WO_DBVT_CAMERA_CULLING) != 0;
+                                       useDbvtCulling = (blenderscene->world->mode & WO_DBVT_CULLING) != 0;
                                        break;
                                }
                                 
index f763585..eb2d0a1 100644 (file)
@@ -1008,9 +1008,10 @@ void BL_ConvertActuators(char* maggiename,
                        bVisibilityActuator *vis_act = (bVisibilityActuator *) bact->data;
                        KX_VisibilityActuator * tmp_vis_act = NULL;
                        bool v = ((vis_act->flag & ACT_VISIBILITY_INVISIBLE) != 0);
+                       bool o = ((vis_act->flag & ACT_VISIBILITY_OCCLUSION) != 0);
                        bool recursive = ((vis_act->flag & ACT_VISIBILITY_RECURSIVE) != 0);
 
-                       tmp_vis_act = new KX_VisibilityActuator(gameobj, !v, recursive);
+                       tmp_vis_act = new KX_VisibilityActuator(gameobj, !v, o, recursive);
                        
                        baseact = tmp_vis_act;
                }
index 817afed..16cf3d9 100644 (file)
@@ -92,6 +92,7 @@ KX_GameObject::KX_GameObject(
        m_bIsNegativeScaling(false),
        m_bVisible(true),
        m_bCulled(true),
+       m_bOccluder(false),
        m_pPhysicsController1(NULL),
        m_pGraphicController(NULL),
        m_pPhysicsEnvironment(NULL),
@@ -146,7 +147,12 @@ KX_GameObject::~KX_GameObject()
        }
 }
 
-
+KX_GameObject* KX_GameObject::GetClientObject(KX_ClientObjectInfo* info)
+{
+       if (!info)
+               return NULL;
+       return info->m_gameobject;
+}
 
 CValue* KX_GameObject::        Calc(VALUE_OPERATOR op, CValue *val) 
 {
@@ -435,7 +441,7 @@ static void UpdateBuckets_recursive(SG_Node* node)
 
 void KX_GameObject::UpdateBuckets( bool recursive )
 {
-       double* fl = GetOpenGLMatrix();
+       double* fl = GetOpenGLMatrixPtr()->getPointer();
 
        for (size_t i=0;i<m_meshes.size();i++)
                m_meshes[i]->UpdateBuckets(this, fl, m_bUseObjectColor, m_objectColor, m_bVisible, m_bCulled);
@@ -597,23 +603,34 @@ KX_GameObject::SetVisible(
                setVisible_recursive(m_pSGNode, v);
 }
 
-bool
-KX_GameObject::GetCulled(
-       void
-       )
+static void setOccluder_recursive(SG_Node* node, bool v)
 {
-       return m_bCulled;
+       NodeList& children = node->GetSGChildren();
+
+       for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit)
+       {
+               SG_Node* childnode = (*childit);
+               KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject());
+               if (clientgameobj != NULL) // This is a GameObject
+                       clientgameobj->SetOccluder(v, false);
+               
+               // if the childobj is NULL then this may be an inverse parent link
+               // so a non recursive search should still look down this node.
+               setOccluder_recursive(childnode, v);
+       }
 }
 
 void
-KX_GameObject::SetCulled(
-       bool c
+KX_GameObject::SetOccluder(
+       bool v,
+       bool recursive
        )
 {
-       m_bCulled = c;
+       m_bOccluder = v;
+       if (recursive)
+               setOccluder_recursive(m_pSGNode, v);
 }
 
-
 void
 KX_GameObject::SetLayer(
        int l
@@ -1036,6 +1053,7 @@ PyMethodDef KX_GameObject::Methods[] = {
        {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_O},
        {"setParent", (PyCFunction)KX_GameObject::sPySetParent,METH_O},
        {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS},
+       {"setOcclusion",(PyCFunction) KX_GameObject::sPySetOcclusion, METH_VARARGS},
        {"removeParent", (PyCFunction)KX_GameObject::sPyRemoveParent,METH_NOARGS},
        {"getChildren", (PyCFunction)KX_GameObject::sPyGetChildren,METH_NOARGS},
        {"getChildrenRecursive", (PyCFunction)KX_GameObject::sPyGetChildrenRecursive,METH_NOARGS},
@@ -1069,6 +1087,7 @@ PyAttributeDef KX_GameObject::Attributes[] = {
        KX_PYATTRIBUTE_RO_FUNCTION("parent",    KX_GameObject, pyattr_get_parent),
        KX_PYATTRIBUTE_RW_FUNCTION("mass",              KX_GameObject, pyattr_get_mass,         pyattr_set_mass),
        KX_PYATTRIBUTE_RW_FUNCTION("visible",   KX_GameObject, pyattr_get_visible,      pyattr_set_visible),
+       KX_PYATTRIBUTE_BOOL_RW    ("occlusion", KX_GameObject, m_bOccluder),
        KX_PYATTRIBUTE_RW_FUNCTION("position",  KX_GameObject, pyattr_get_position,     pyattr_set_position),
        KX_PYATTRIBUTE_RO_FUNCTION("localInertia",      KX_GameObject, pyattr_get_localInertia),
        KX_PYATTRIBUTE_RW_FUNCTION("orientation",KX_GameObject,pyattr_get_orientation,pyattr_set_orientation),
@@ -1746,6 +1765,16 @@ PyObject* KX_GameObject::PySetVisible(PyObject* self, PyObject* args)
        
 }
 
+PyObject* KX_GameObject::PySetOcclusion(PyObject* self, PyObject* args)
+{
+       int occlusion, recursive = 0;
+       if (!PyArg_ParseTuple(args,"i|i:setOcclusion",&occlusion, &recursive))
+               return NULL;
+       
+       SetOccluder(occlusion ? true:false, recursive ? true:false);
+       Py_RETURN_NONE;
+}
+
 PyObject* KX_GameObject::PyGetVisible(PyObject* self)
 {
        ShowDeprecationWarning("getVisible()", "the visible property");
index 1722721..c389d6c 100644 (file)
@@ -87,6 +87,7 @@ protected:
        // culled = while rendering, depending on camera
        bool                                                            m_bVisible; 
        bool                                                            m_bCulled; 
+       bool                                                            m_bOccluder;
 
        KX_IPhysicsController*                          m_pPhysicsController1;
        PHY_IGraphicController*                         m_pGraphicController;
@@ -103,6 +104,11 @@ protected:
 public:
        bool                                                            m_isDeformable;
 
+       /**
+        * Helper function for modules that can't include KX_ClientObjectInfo.h
+        */
+       static KX_GameObject* GetClientObject(KX_ClientObjectInfo* info);
+
        // Python attributes that wont convert into CValue
        // 
        // there are 2 places attributes can be stored, in the CValue,
@@ -118,11 +124,8 @@ public:
        // * if CValue conversion fails, use a PyObject in "m_attrlist"
        // * when assigning a value, first see if it can be a CValue, if it can remove the "m_attrlist" and set the CValue
        // 
-       
        PyObject*                                                       m_attrlist; 
 
-
-
        virtual void    /* This function should be virtual - derived classed override it */
        Relink(
                GEN_Map<GEN_HashedPtr, void*> *map
@@ -698,19 +701,36 @@ public:
        /**
         * Was this object culled?
         */
-               bool
+       inline bool
        GetCulled(
                void
-       );
+       ) { return m_bCulled; }
 
        /**
         * Set culled flag of this object
         */
-               void
+       inline void
        SetCulled(
                bool c
-       );
+       ) { m_bCulled = c; }
+       
+       /**
+        * Is this object an occluder?
+        */
+       inline bool
+       GetOccluder(
+               void
+       ) { return m_bOccluder; }
 
+       /**
+        * Set occluder flag of this object
+        */
+       void
+       SetOccluder(
+               bool v,
+               bool recursive
+       );
+       
        /**
         * Change the layer of the object (when it is added in another layer
         * than the original layer)
@@ -908,6 +928,7 @@ public:
        KX_PYMETHOD_O(KX_GameObject,SetOrientation);
        KX_PYMETHOD_NOARGS(KX_GameObject,GetVisible);
        KX_PYMETHOD_VARARGS(KX_GameObject,SetVisible);
+       KX_PYMETHOD_VARARGS(KX_GameObject,SetOcclusion);
        KX_PYMETHOD_NOARGS(KX_GameObject,GetState);
        KX_PYMETHOD_O(KX_GameObject,SetState);
        KX_PYMETHOD_VARARGS(KX_GameObject,AlignAxisToVect);
index aeb8080..83a2fa8 100644 (file)
@@ -294,8 +294,14 @@ void KX_KetsjiEngine::RenderDome()
        if (!BeginFrame())
                return;
 
-       int n_renders=m_dome->GetNumberRenders();// usually 4 or 6
        KX_SceneList::iterator sceneit;
+       for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
+       {
+               // do this only once per scene
+               (*sceneit)->UpdateMeshTransformations();
+       }
+
+       int n_renders=m_dome->GetNumberRenders();// usually 4 or 6
        for (int i=0;i<n_renders;i++){
                m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
                for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
@@ -311,7 +317,6 @@ void KX_KetsjiEngine::RenderDome()
                        // shadow buffers
                        if (i == 0){
                                RenderShadowBuffers(scene);
-                               scene->UpdateMeshTransformations();//I need to run it somewherelse, otherwise Im overrunning it
                        }
                        // Avoid drawing the scene with the active camera twice when it's viewport is enabled
                        if(cam && !cam->GetViewport())
@@ -812,6 +817,9 @@ void KX_KetsjiEngine::Render()
                // pass the scene's worldsettings to the rasterizer
                SetWorldSettings(scene->GetWorldInfo());
 
+               // do this only once per scene
+               scene->UpdateMeshTransformations();
+
                // shadow buffers
                RenderShadowBuffers(scene);
 
@@ -1140,7 +1148,6 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
                        light->BindShadowBuffer(m_rasterizer, cam, camtrans);
 
                        /* update scene */
-                       scene->UpdateMeshTransformations();
                        scene->CalculateVisibleMeshes(m_rasterizer, cam, light->GetShadowLayer());
 
                        /* render */
@@ -1245,7 +1252,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
                cam->GetCameraLocation(), cam->GetCameraOrientation());
        cam->SetModelviewMatrix(viewmat);
 
-       //redundant, already done in 
+       //redundant, already done in Render()
        //scene->UpdateMeshTransformations();
 
        // The following actually reschedules all vertices to be
index 2f7c1b7..98c129e 100644 (file)
@@ -138,6 +138,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
        m_suspendeddelta = 0.0;
 
        m_dbvt_culling = false;
+       m_dbvt_occlusion_res = 0;
        m_activity_culling = false;
        m_suspend = false;
        m_isclearingZbuffer = true;
@@ -1352,17 +1353,18 @@ void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int
        if (m_dbvt_culling) 
        {
                // test culling through Bullet
-               PHY__Vector4 planes[5];
+               PHY__Vector4 planes[6];
                // get the clip planes
                MT_Vector4* cplanes = cam->GetNormalizedClipPlanes();
                // and convert
-               planes[0].setValue(cplanes[0].getValue());
-               planes[1].setValue(cplanes[1].getValue());
-               planes[2].setValue(cplanes[2].getValue());
-               planes[3].setValue(cplanes[3].getValue());
-               planes[4].setValue(cplanes[5].getValue());
+               planes[0].setValue(cplanes[4].getValue());      // near
+               planes[1].setValue(cplanes[5].getValue());      // far
+               planes[2].setValue(cplanes[0].getValue());      // left
+               planes[3].setValue(cplanes[1].getValue());      // right
+               planes[4].setValue(cplanes[2].getValue());      // top
+               planes[5].setValue(cplanes[3].getValue());      // bottom
                CullingInfo info(layer);
-               dbvt_culling = m_physicsEnvironment->cullingTest(PhysicsCullingCallback,&info,planes,5);
+               dbvt_culling = m_physicsEnvironment->cullingTest(PhysicsCullingCallback,&info,planes,5,m_dbvt_occlusion_res);
        }
        if (!dbvt_culling) {
                // the physics engine couldn't help us, do it the hard way
index 55e7afa..e1e89e2 100644 (file)
@@ -264,6 +264,11 @@ protected:
         */
        bool m_dbvt_culling;
        
+       /**
+        * Occlusion culling resolution
+        */ 
+       int m_dbvt_occlusion_res;
+
        /**
         * The framing settings used by this scene
         */
@@ -545,8 +550,10 @@ public:
        bool IsClearingZBuffer();
        void EnableZBufferClearing(bool isclearingZbuffer);
        // use of DBVT tree for camera culling
-       void SetDbvtCameraCulling(bool b) { m_dbvt_culling = b; };
-       bool GetDbvtCameraCulling() { return m_dbvt_culling; };
+       void SetDbvtCulling(bool b) { m_dbvt_culling = b; };
+       bool GetDbvtCulling() { return m_dbvt_culling; };
+       void SetDbvtOcclusionRes(int i) { m_dbvt_occlusion_res = i; };
+       int GetDbvtOcclusionRes() { return m_dbvt_occlusion_res; };
        
        void SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter);
 
index 1ee2169..fceb0b5 100644 (file)
 KX_VisibilityActuator::KX_VisibilityActuator(
        SCA_IObject* gameobj,
        bool visible,
+       bool occlusion,
        bool recursive,
        PyTypeObject* T
        ) 
        : SCA_IActuator(gameobj,T),
          m_visible(visible),
+         m_occlusion(occlusion),
          m_recursive(recursive)
 {
        // intentionally empty
@@ -78,6 +80,7 @@ KX_VisibilityActuator::Update()
        KX_GameObject *obj = (KX_GameObject*) GetParent();
        
        obj->SetVisible(m_visible, m_recursive);
+       obj->SetOccluder(m_occlusion, m_recursive);
        obj->UpdateBuckets(m_recursive);
 
        return false;
@@ -130,6 +133,7 @@ KX_VisibilityActuator::Methods[] = {
 
 PyAttributeDef KX_VisibilityActuator::Attributes[] = {
        KX_PYATTRIBUTE_BOOL_RW("visibility", KX_VisibilityActuator, m_visible),
+       KX_PYATTRIBUTE_BOOL_RW("occlusion", KX_VisibilityActuator, m_occlusion),
        KX_PYATTRIBUTE_BOOL_RW("recursion", KX_VisibilityActuator, m_recursive),
        { NULL }        //Sentinel
 };
index fca3750..4269258 100644 (file)
@@ -39,6 +39,7 @@ class KX_VisibilityActuator : public SCA_IActuator
 
        /** Make visible? */
        bool m_visible;
+       bool m_occlusion;
        bool m_recursive;
 
  public:
@@ -46,6 +47,7 @@ class KX_VisibilityActuator : public SCA_IActuator
        KX_VisibilityActuator(
                SCA_IObject* gameobj,
                bool visible,
+               bool occlusion,
                bool recursive,
                PyTypeObject* T=&Type
                );
index e4aaef1..2e4709c 100644 (file)
@@ -55,7 +55,7 @@ public:
 
        virtual void            removeConstraint(void * constraintid);
        virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
-       virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes) { return false; }
+       virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes, int occlusionRes) { return false; }
 
 
        //gamelogic callbacks
index 6bab985..2cb2a54 100644 (file)
@@ -30,11 +30,18 @@ SET(INC
   .
   ../common
   ../../../../extern/bullet2/src
+  ../../../../extern/glew/include
   ../../../../intern/moto/include
   ../../../kernel/gen_system
   ../../../../intern/string
+  ../../../intern/SoundSystem 
   ../../Rasterizer
+  ../../Ketsji
+  ../../Expressions
+  ../../GameLogic
+  ../../SceneGraph
   ../../../../source/blender/makesdna
+  ${PYTHON_INC}
 )
 
 BLENDERLIB(bf_bullet "${SRC}" "${INC}")
index faf1ca4..858416b 100644 (file)
@@ -33,6 +33,10 @@ subject to the following restrictions:
 
 
 #include "PHY_IMotionState.h"
+#include "KX_GameObject.h"
+#include "RAS_MeshObject.h"
+#include "RAS_Polygon.h"
+#include "RAS_TexVert.h"
 
 #define CCD_CONSTRAINT_DISABLE_LINKED_COLLISION 0x80
 
@@ -47,7 +51,9 @@ btRaycastVehicle::btVehicleTuning     gTuning;
 
 #endif //NEW_BULLET_VEHICLE_SUPPORT
 #include "LinearMath/btAabbUtil2.h"
-
+#include "MT_Matrix4x4.h"
+#include "MT_Vector3.h"
+#include "GL/glew.h"
 
 #ifdef WIN32
 void DrawRasterizerLine(const float* from,const float* to,int color);
@@ -1189,17 +1195,492 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallbac
        return result.m_controller;
 }
 
+// Handles occlusion culling. 
+// The implementation is based on the CDTestFramework
+struct OcclusionBuffer
+{
+       struct WriteOCL
+       {
+               static inline bool Process(btScalar& q,btScalar v) { if(q<v) q=v;return(false); }
+               static inline void Occlusion(bool& flag) { flag = true; }
+       };
+       struct QueryOCL
+       {
+               static inline bool Process(btScalar& q,btScalar v) { return(q<=v); }
+               static inline void Occlusion(bool& flag) { }
+       };
+       btScalar*                                               m_buffer;
+       size_t                                                  m_bufferSize;
+       bool                                                    m_initialized;
+       bool                                                    m_occlusion;
+       int                                                             m_sizes[2];
+       btScalar                                                m_scales[2];
+       btScalar                                                m_offsets[2];
+       btScalar                                                m_wtc[16];              // world to clip transform
+       btScalar                                                m_mtc[16];              // model to clip transform
+       // constructor: size=largest dimension of the buffer. 
+       // Buffer size depends on aspect ratio
+       OcclusionBuffer()
+       {
+               m_initialized=false;
+               m_occlusion = false;
+               m_buffer == NULL;
+               m_bufferSize = 0;
+       }
+       // multiplication of column major matrices: m=m1*m2
+       template<typename T1, typename T2>
+       void            CMmat4mul(btScalar* m, const T1* m1, const T2* m2)
+       {
+               m[ 0] = btScalar(m1[ 0]*m2[ 0]+m1[ 4]*m2[ 1]+m1[ 8]*m2[ 2]+m1[12]*m2[ 3]);
+               m[ 1] = btScalar(m1[ 1]*m2[ 0]+m1[ 5]*m2[ 1]+m1[ 9]*m2[ 2]+m1[13]*m2[ 3]);
+               m[ 2] = btScalar(m1[ 2]*m2[ 0]+m1[ 6]*m2[ 1]+m1[10]*m2[ 2]+m1[14]*m2[ 3]);
+               m[ 3] = btScalar(m1[ 3]*m2[ 0]+m1[ 7]*m2[ 1]+m1[11]*m2[ 2]+m1[15]*m2[ 3]);
+
+               m[ 4] = btScalar(m1[ 0]*m2[ 4]+m1[ 4]*m2[ 5]+m1[ 8]*m2[ 6]+m1[12]*m2[ 7]);
+               m[ 5] = btScalar(m1[ 1]*m2[ 4]+m1[ 5]*m2[ 5]+m1[ 9]*m2[ 6]+m1[13]*m2[ 7]);
+               m[ 6] = btScalar(m1[ 2]*m2[ 4]+m1[ 6]*m2[ 5]+m1[10]*m2[ 6]+m1[14]*m2[ 7]);
+               m[ 7] = btScalar(m1[ 3]*m2[ 4]+m1[ 7]*m2[ 5]+m1[11]*m2[ 6]+m1[15]*m2[ 7]);
+
+               m[ 8] = btScalar(m1[ 0]*m2[ 8]+m1[ 4]*m2[ 9]+m1[ 8]*m2[10]+m1[12]*m2[11]);
+               m[ 9] = btScalar(m1[ 1]*m2[ 8]+m1[ 5]*m2[ 9]+m1[ 9]*m2[10]+m1[13]*m2[11]);
+               m[10] = btScalar(m1[ 2]*m2[ 8]+m1[ 6]*m2[ 9]+m1[10]*m2[10]+m1[14]*m2[11]);
+               m[11] = btScalar(m1[ 3]*m2[ 8]+m1[ 7]*m2[ 9]+m1[11]*m2[10]+m1[15]*m2[11]);
+
+               m[12] = btScalar(m1[ 0]*m2[12]+m1[ 4]*m2[13]+m1[ 8]*m2[14]+m1[12]*m2[15]);
+               m[13] = btScalar(m1[ 1]*m2[12]+m1[ 5]*m2[13]+m1[ 9]*m2[14]+m1[13]*m2[15]);
+               m[14] = btScalar(m1[ 2]*m2[12]+m1[ 6]*m2[13]+m1[10]*m2[14]+m1[14]*m2[15]);
+               m[15] = btScalar(m1[ 3]*m2[12]+m1[ 7]*m2[13]+m1[11]*m2[14]+m1[15]*m2[15]);
+       }
+       void            setup(int size)
+       {
+               m_initialized=false;
+               m_occlusion=false;
+               // compute the size of the buffer
+               GLint           v[4];
+               GLdouble        m[16],p[16];
+               int                     maxsize;
+               double          ratio;
+               glGetIntegerv(GL_VIEWPORT,v);
+               maxsize = (v[2] > v[3]) ? v[2] : v[3];
+               assert(maxsize > 0);
+               ratio = 1.0/(2*maxsize);
+               // ensure even number
+               m_sizes[0] = 2*((int)(size*v[2]*ratio+0.5));
+               m_sizes[1] = 2*((int)(size*v[3]*ratio+0.5));
+               m_scales[0]=btScalar(m_sizes[0]/2);
+               m_scales[1]=btScalar(m_sizes[1]/2);
+               m_offsets[0]=m_scales[0]+0.5f;
+               m_offsets[1]=m_scales[1]+0.5f;
+               // prepare matrix
+               // at this time of the rendering, the modelview matrix is the 
+               // world to camera transformation and the projection matrix is
+               // camera to clip transformation. combine both so that 
+               glGetDoublev(GL_MODELVIEW_MATRIX,m);
+               glGetDoublev(GL_PROJECTION_MATRIX,p);
+               CMmat4mul(m_wtc,p,m);
+       }
+       void            initialize()
+       {
+               size_t newsize = (m_sizes[0]*m_sizes[1])*sizeof(btScalar);
+               if (m_buffer)
+               {
+                       // see if we can reuse
+                       if (newsize > m_bufferSize)
+                       {
+                               free(m_buffer);
+                               m_buffer = NULL;
+                               m_bufferSize = 0;
+                       }
+               }
+               if (!m_buffer)
+               {
+                       m_buffer = (btScalar*)calloc(1, newsize);
+                       m_bufferSize = newsize;
+               } else
+               {
+                       // buffer exists already, just clears it
+                       memset(m_buffer, 0, newsize);
+               }
+               // memory allocate must succeed
+               assert(m_buffer != NULL);
+               m_initialized = true;
+               m_occlusion = false;
+       }
+       void            SetModelMatrix(double *fl)
+       {
+               CMmat4mul(m_mtc,m_wtc,fl);
+               if (!m_initialized)
+                       initialize();
+       }
+
+       // transform a segment in world coordinate to clip coordinate
+       void            transformW(const btVector3& x, btVector4& t)
+       {
+               t[0]    =       x[0]*m_wtc[0]+x[1]*m_wtc[4]+x[2]*m_wtc[8]+m_wtc[12];
+               t[1]    =       x[0]*m_wtc[1]+x[1]*m_wtc[5]+x[2]*m_wtc[9]+m_wtc[13];
+               t[2]    =       x[0]*m_wtc[2]+x[1]*m_wtc[6]+x[2]*m_wtc[10]+m_wtc[14];
+               t[3]    =       x[0]*m_wtc[3]+x[1]*m_wtc[7]+x[2]*m_wtc[11]+m_wtc[15];
+       }
+       void            transformM(const float* x, btVector4& t)
+       {
+               t[0]    =       x[0]*m_mtc[0]+x[1]*m_mtc[4]+x[2]*m_mtc[8]+m_mtc[12];
+               t[1]    =       x[0]*m_mtc[1]+x[1]*m_mtc[5]+x[2]*m_mtc[9]+m_mtc[13];
+               t[2]    =       x[0]*m_mtc[2]+x[1]*m_mtc[6]+x[2]*m_mtc[10]+m_mtc[14];
+               t[3]    =       x[0]*m_mtc[3]+x[1]*m_mtc[7]+x[2]*m_mtc[11]+m_mtc[15];
+       }
+       // convert polygon to device coordinates
+       static bool     project(btVector4* p,int n)
+       {
+               for(int i=0;i<n;++i)
+               {
+                       const btScalar iw=1/p[i][3];
+                       p[i][2]=1/p[i][3];
+                       p[i][0]*=p[i][2];
+                       p[i][1]*=p[i][2];
+               }
+               return(true);
+       }
+       // pi: closed polygon in clip coordinate, NP = number of segments
+       // po: same polygon with clipped segments removed
+       template <const int NP>
+       static int      clip(const btVector4* pi,btVector4* po)
+       {
+               btScalar        s[2*NP];
+               btVector4       pn[2*NP], *p;
+               int                     i, j, m, n, ni;
+               // deal with near clipping
+               for(i=0, m=0;i<NP;++i)
+               {
+                       s[i]=pi[i][2]+pi[i][3];
+                       if(s[i]<0) m+=1<<i;
+               }
+               if(m==((1<<NP)-1)) 
+                       return(0);
+               if(m!=0)
+               {
+                       for(i=NP-1,j=0,n=0;j<NP;i=j++)
+                       {
+                               const btVector4&        a=pi[i];
+                               const btVector4&        b=pi[j];
+                               const btScalar          t=s[i]/(a[3]+a[2]-b[3]-b[2]);
+                               if((t>0)&&(t<1))
+                               {
+                                       pn[n][0]        =       a[0]+(b[0]-a[0])*t;
+                                       pn[n][1]        =       a[1]+(b[1]-a[1])*t;
+                                       pn[n][2]        =       a[2]+(b[2]-a[2])*t;
+                                       pn[n][3]        =       a[3]+(b[3]-a[3])*t;
+                                       ++n;
+                               }
+                               if(s[j]>0) pn[n++]=b;
+                       }
+                       // ready to test far clipping, start from the modified polygon
+                       pi = pn;
+                       ni = n;
+               } else
+               {
+                       // no clipping on the near plane, keep same vector
+                       ni = NP;
+               }
+               // now deal with far clipping
+               for(i=0, m=0;i<ni;++i)
+               {
+                       s[i]=pi[i][2]-pi[i][3];
+                       if(s[i]>0) m+=1<<i;
+               }
+               if(m==((1<<ni)-1)) 
+                       return(0);
+               if(m!=0)
+               {
+                       for(i=ni-1,j=0,n=0;j<ni;i=j++)
+                       {
+                               const btVector4&        a=pi[i];
+                               const btVector4&        b=pi[j];
+                               const btScalar          t=s[i]/(a[2]-a[3]-b[2]+b[3]);
+                               if((t>0)&&(t<1))
+                               {
+                                       po[n][0]        =       a[0]+(b[0]-a[0])*t;
+                                       po[n][1]        =       a[1]+(b[1]-a[1])*t;
+                                       po[n][2]        =       a[2]+(b[2]-a[2])*t;
+                                       po[n][3]        =       a[3]+(b[3]-a[3])*t;
+                                       ++n;
+                               }
+                               if(s[j]<0) po[n++]=b;
+                       }
+                       return(n);
+               }
+               for(int i=0;i<ni;++i) po[i]=pi[i];
+               return(ni);
+       }
+       // write or check a triangle to buffer. a,b,c in device coordinates (-1,+1)
+       template <typename POLICY>
+       inline bool     draw(   const btVector4& a,
+                                               const btVector4& b,
+                                               const btVector4& c,
+                                               const float face,
+                                               const btScalar minarea)
+       {
+               const btScalar          a2=cross(b-a,c-a)[2];
+               if((face*a2)<0.f || btFabs(a2)<minarea)
+                       return false;
+               // further down we are normally going to write to the Zbuffer, mark it so
+               POLICY::Occlusion(m_occlusion);
+
+               int x[3], y[3], ib=1, ic=2;
+               btScalar z[3];
+               x[0]=(int)(a.x()*m_scales[0]+m_offsets[0]);
+               y[0]=(int)(a.y()*m_scales[1]+m_offsets[1]);
+               z[0]=a.z();
+               if (a2 < 0.f)
+               {
+                       // negative aire is possible with double face => must
+                       // change the order of b and c otherwise the algorithm doesn't work
+                       ib=2;
+                       ic=1;
+               }
+               x[ib]=(int)(b.x()*m_scales[0]+m_offsets[0]);
+               x[ic]=(int)(c.x()*m_scales[0]+m_offsets[0]);
+               y[ib]=(int)(b.y()*m_scales[1]+m_offsets[1]);
+               y[ic]=(int)(c.y()*m_scales[1]+m_offsets[1]);
+               z[ib]=b.z();
+               z[ic]=c.z();
+               const int               mix=btMax(0,btMin(x[0],btMin(x[1],x[2])));
+               const int               mxx=btMin(m_sizes[0],1+btMax(x[0],btMax(x[1],x[2])));
+               const int               miy=btMax(0,btMin(y[0],btMin(y[1],y[2])));
+               const int               mxy=btMin(m_sizes[1],1+btMax(y[0],btMax(y[1],y[2])));
+               const int               width=mxx-mix;
+               const int               height=mxy-miy;
+               if ((width*height) <= 1)
+               {
+                       // degenerated in at most one single pixel
+                       btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
+                       // use for loop to detect the case where width or height == 0
+                       for(int iy=miy;iy<mxy;++iy)
+                       {
+                               for(int ix=mix;ix<mxx;++ix)
+                               {
+                                       if(POLICY::Process(*scan,z[0])) 
+                                               return(true);
+                                       if(POLICY::Process(*scan,z[1])) 
+                                               return(true);
+                                       if(POLICY::Process(*scan,z[2])) 
+                                               return(true);
+                               }
+                       }
+               } else if (width == 1) 
+               {
+                       // Degenerated in at least 2 vertical lines
+                       // The algorithm below doesn't work when face has a single pixel width
+                       // We cannot use general formulas because the plane is degenerated. 
+                       // We have to interpolate along the 3 edges that overlaps and process each pixel.
+                       // sort the y coord to make formula simpler
+                       int ytmp;
+                       btScalar ztmp;
+                       if (y[0] > y[1]) { ytmp=y[1];y[1]=y[0];y[0]=ytmp;ztmp=z[1];z[1]=z[0];z[0]=ztmp; }
+                       if (y[0] > y[2]) { ytmp=y[2];y[2]=y[0];y[0]=ytmp;ztmp=z[2];z[2]=z[0];z[0]=ztmp; }
+                       if (y[1] > y[2]) { ytmp=y[2];y[2]=y[1];y[1]=ytmp;ztmp=z[2];z[2]=z[1];z[1]=ztmp; }
+                       int     dy[]={  y[0]-y[1],
+                                               y[1]-y[2],
+                                               y[2]-y[0]};
+                       btScalar dzy[3];
+                       dzy[0] = (dy[0]) ? (z[0]-z[1])/dy[0] : btScalar(0.f);
+                       dzy[1] = (dy[1]) ? (z[1]-z[2])/dy[1] : btScalar(0.f);
+                       dzy[2] = (dy[2]) ? (z[2]-z[0])/dy[2] : btScalar(0.f);
+                       btScalar v[3] = {       dzy[0]*(miy-y[0])+z[0],
+                                                               dzy[1]*(miy-y[1])+z[1],
+                                                               dzy[2]*(miy-y[2])+z[2] };
+                       dy[0] = y[1]-y[0];
+                       dy[1] = y[0]-y[1];
+                       dy[2] = y[2]-y[0];
+                       btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
+                       for(int iy=miy;iy<mxy;++iy)
+                       {
+                               if(dy[0] >= 0 && POLICY::Process(*scan,v[0])) 
+                                       return(true);
+                               if(dy[1] >= 0 && POLICY::Process(*scan,v[1])) 
+                                       return(true);
+                               if(dy[2] >= 0 && POLICY::Process(*scan,v[2])) 
+                                       return(true);
+                               scan+=m_sizes[0];
+                               v[0] += dzy[0]; v[1] += dzy[1]; v[2] += dzy[2];
+                               dy[0]--; dy[1]++, dy[2]--;
+                       }
+               } else if (height == 1)
+               {
+                       // Degenerated in at least 2 horizontal lines
+                       // The algorithm below doesn't work when face has a single pixel width
+                       // We cannot use general formulas because the plane is degenerated. 
+                       // We have to interpolate along the 3 edges that overlaps and process each pixel.
+                       int xtmp;
+                       btScalar ztmp;
+                       if (x[0] > x[1]) { xtmp=x[1];x[1]=x[0];x[0]=xtmp;ztmp=z[1];z[1]=z[0];z[0]=ztmp; }
+                       if (x[0] > x[2]) { xtmp=x[2];x[2]=x[0];x[0]=xtmp;ztmp=z[2];z[2]=z[0];z[0]=ztmp; }
+                       if (x[1] > x[2]) { xtmp=x[2];x[2]=x[1];x[1]=xtmp;ztmp=z[2];z[2]=z[1];z[1]=ztmp; }
+                       int     dx[]={  x[0]-x[1],
+                                               x[1]-x[2],
+                                               x[2]-x[0]};
+                       btScalar dzx[3];
+                       dzx[0] = (dx[0]) ? (z[0]-z[1])/dx[0] : btScalar(0.f);
+                       dzx[1] = (dx[1]) ? (z[1]-z[2])/dx[1] : btScalar(0.f);
+                       dzx[2] = (dx[2]) ? (z[2]-z[0])/dx[2] : btScalar(0.f);
+                       btScalar v[3] = { dzx[0]*(mix-x[0])+z[0],
+                                                         dzx[1]*(mix-x[1])+z[1],
+                                                         dzx[2]*(mix-x[2])+z[2] };
+                       dx[0] = x[1]-x[0];
+                       dx[1] = x[0]-x[1];
+                       dx[2] = x[2]-x[0];
+                       btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
+                       for(int ix=mix;ix<mxx;++ix)
+                       {
+                               if(dx[0] >= 0 && POLICY::Process(*scan,v[0])) 
+                                       return(true);
+                               if(dx[1] >= 0 && POLICY::Process(*scan,v[1])) 
+                                       return(true);
+                               if(dx[2] >= 0 && POLICY::Process(*scan,v[2])) 
+                                       return(true);
+                               scan++;
+                               v[0] += dzx[0]; v[1] += dzx[1]; v[2] += dzx[2];
+                               dx[0]--; dx[1]++, dx[2]--;
+                       }
+               } else
+               {
+                       // general case
+                       const int               dx[]={  y[0]-y[1],
+                                                                       y[1]-y[2],
+                                                                       y[2]-y[0]};
+                       const int               dy[]={  x[1]-x[0]-dx[0]*width,
+                                                                       x[2]-x[1]-dx[1]*width,
+                                                                       x[0]-x[2]-dx[2]*width};
+                       const int               a=x[2]*y[0]+x[0]*y[1]-x[2]*y[1]-x[0]*y[2]+x[1]*y[2]-x[1]*y[0];
+                       const btScalar  ia=1/(btScalar)a;
+                       const btScalar  dzx=ia*(y[2]*(z[1]-z[0])+y[1]*(z[0]-z[2])+y[0]*(z[2]-z[1]));
+                       const btScalar  dzy=ia*(x[2]*(z[0]-z[1])+x[0]*(z[1]-z[2])+x[1]*(z[2]-z[0]))-(dzx*width);                
+                       int                             c[]={   miy*x[1]+mix*y[0]-x[1]*y[0]-mix*y[1]+x[0]*y[1]-miy*x[0],
+                                                                       miy*x[2]+mix*y[1]-x[2]*y[1]-mix*y[2]+x[1]*y[2]-miy*x[1],
+                                                                       miy*x[0]+mix*y[2]-x[0]*y[2]-mix*y[0]+x[2]*y[0]-miy*x[2]};
+                       btScalar                v=ia*((z[2]*c[0])+(z[0]*c[1])+(z[1]*c[2]));
+                       btScalar*               scan=&m_buffer[miy*m_sizes[0]];
+                       for(int iy=miy;iy<mxy;++iy)
+                       {
+                               for(int ix=mix;ix<mxx;++ix)
+                               {
+                                       if((c[0]>=0)&&(c[1]>=0)&&(c[2]>=0))
+                                       {
+                                               if(POLICY::Process(scan[ix],v)) 
+                                                       return(true);
+                                       }
+                                       c[0]+=dx[0];c[1]+=dx[1];c[2]+=dx[2];v+=dzx;
+                               }
+                               c[0]+=dy[0];c[1]+=dy[1];c[2]+=dy[2];v+=dzy;
+                               scan+=m_sizes[0];
+                       }
+               }
+               return(false);
+       }
+       // clip than write or check a polygon 
+       template <const int NP,typename POLICY>
+       inline bool     clipDraw(       const btVector4* p,
+                                                       const float face,
+                                                       btScalar minarea)
+       {
+               btVector4       o[NP*2];
+               int                     n=clip<NP>(p,o);
+               bool            earlyexit=false;
+               if (n)
+               {
+                       project(o,n);
+                       for(int i=2;i<n && !earlyexit;++i)
+                       {
+                               earlyexit|=draw<POLICY>(o[0],o[i-1],o[i],face,minarea);
+                       }
+               }
+               return(earlyexit);
+       }
+       // add a triangle (in model coordinate)
+       // face =  0.f if face is double side, 
+       //      =  1.f if face is single sided and scale is positive
+       //      = -1.f if face is single sided and scale is negative
+       void            appendOccluderM(const float* a,
+                                                               const float* b,
+                                                               const float* c,
+                                                               const float face)
+       {
+               btVector4       p[3];
+               transformM(a,p[0]);
+               transformM(b,p[1]);
+               transformM(c,p[2]);
+               clipDraw<3,WriteOCL>(p,face,btScalar(0.f));
+       }
+       // add a quad (in model coordinate)
+       void            appendOccluderM(const float* a,
+                                                               const float* b,
+                                                               const float* c,
+                                                               const float* d,
+                                                               const float face)
+       {       
+               btVector4       p[4];
+               transformM(a,p[0]);
+               transformM(b,p[1]);
+               transformM(c,p[2]);
+               transformM(d,p[3]);
+               clipDraw<4,WriteOCL>(p,face,btScalar(0.f));
+       }
+       // query occluder for a box (c=center, e=extend) in world coordinate
+       inline bool     queryOccluderW( const btVector3& c,
+                                                               const btVector3& e)
+       {
+               if (!m_occlusion)
+                       // no occlusion yet, no need to check
+                       return true;
+               btVector4       x[8];
+               transformW(btVector3(c[0]-e[0],c[1]-e[1],c[2]-e[2]),x[0]);
+               transformW(btVector3(c[0]+e[0],c[1]-e[1],c[2]-e[2]),x[1]);
+               transformW(btVector3(c[0]+e[0],c[1]+e[1],c[2]-e[2]),x[2]);
+               transformW(btVector3(c[0]-e[0],c[1]+e[1],c[2]-e[2]),x[3]);
+               transformW(btVector3(c[0]-e[0],c[1]-e[1],c[2]+e[2]),x[4]);
+               transformW(btVector3(c[0]+e[0],c[1]-e[1],c[2]+e[2]),x[5]);
+               transformW(btVector3(c[0]+e[0],c[1]+e[1],c[2]+e[2]),x[6]);
+               transformW(btVector3(c[0]-e[0],c[1]+e[1],c[2]+e[2]),x[7]);
+               for(int i=0;i<8;++i)
+               {
+                       // the box is clipped, it's probably a large box, don't waste our time to check
+                       if((x[i][2]+x[i][3])<=0) return(true);
+               }
+               static const int        d[]={   1,0,3,2,
+                                                                       4,5,6,7,
+                                                                       4,7,3,0,
+                                                                       6,5,1,2,
+                                                                       7,6,2,3,
+                                                                       5,4,0,1};
+               for(int i=0;i<(sizeof(d)/sizeof(d[0]));)
+               {
+                       const btVector4 p[]={   x[d[i++]],
+                                                                       x[d[i++]],
+                                                                       x[d[i++]],
+                                                                       x[d[i++]]};
+                       if(clipDraw<4,QueryOCL>(p,1.f,0.f)) 
+                               return(true);
+               }
+               return(false);
+       }
+};
+
+
 struct DbvtCullingCallback : btDbvt::ICollide
 {
        PHY_CullingCallback m_clientCallback;
        void* m_userData;
+       OcclusionBuffer *m_ocb;
 
        DbvtCullingCallback(PHY_CullingCallback clientCallback, void* userData)
        {
                m_clientCallback = clientCallback;
                m_userData = userData;
+               m_ocb = NULL;
+       }
+       bool Descent(const btDbvtNode* node)
+       {
+               return(m_ocb->queryOccluderW(node->volume.Center(),node->volume.Extents()));
        }
-
        void Process(const btDbvtNode* node,btScalar depth)
        {
                Process(node);
@@ -1210,31 +1691,83 @@ struct  DbvtCullingCallback : btDbvt::ICollide
                // the client object is a graphic controller
                CcdGraphicController* ctrl = static_cast<CcdGraphicController*>(proxy->m_clientObject);
                KX_ClientObjectInfo* info = (KX_ClientObjectInfo*)ctrl->getNewClientInfo();
+               if (m_ocb)
+               {
+                       // means we are doing occlusion culling. Check if this object is an occluders
+                       KX_GameObject* gameobj = KX_GameObject::GetClientObject(info);
+                       if (gameobj && gameobj->GetOccluder())
+                       {
+                               double* fl = gameobj->GetOpenGLMatrixPtr()->getPointer();
+                               // this will create the occlusion buffer if not already done
+                               // and compute the transformation from model local space to clip space
+                               m_ocb->SetModelMatrix(fl);
+                               float face = (gameobj->IsNegativeScaling()) ? -1.0f : 1.0f;
+                               // walk through the meshes and for each add to buffer
+                               for (int i=0; i<gameobj->GetMeshCount(); i++)
+                               {
+                                       RAS_MeshObject* meshobj = gameobj->GetMesh(i);
+                                       const float *v1, *v2, *v3, *v4;
+
+                                       int polycount = meshobj->NumPolygons();
+                                       for (int j=0; j<polycount; j++)
+                                       {
+                                               RAS_Polygon* poly = meshobj->GetPolygon(j);
+                                               switch (poly->VertexCount())
+                                               {
+                                               case 3:
+                                                       v1 = poly->GetVertex(0)->getXYZ();
+                                                       v2 = poly->GetVertex(1)->getXYZ();
+                                                       v3 = poly->GetVertex(2)->getXYZ();
+                                                       m_ocb->appendOccluderM(v1,v2,v3,((poly->IsTwoside())?0.f:face));
+                                                       break;
+                                               case 4:
+                                                       v1 = poly->GetVertex(0)->getXYZ();
+                                                       v2 = poly->GetVertex(1)->getXYZ();
+                                                       v3 = poly->GetVertex(2)->getXYZ();
+                                                       v4 = poly->GetVertex(3)->getXYZ();
+                                                       m_ocb->appendOccluderM(v1,v2,v3,v4,((poly->IsTwoside())?0.f:face));
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
                if (info)
                        (*m_clientCallback)(info, m_userData);
        }
 };
 
-bool CcdPhysicsEnvironment::cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes)
+static OcclusionBuffer gOcb;
+bool CcdPhysicsEnvironment::cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes, int occlusionRes)
 {
        if (!m_cullingTree)
                return false;
        DbvtCullingCallback dispatcher(callback, userData);
-       btVector3 planes_n[5];
-       btScalar planes_o[5];
-       if (nplanes > 5)
-               nplanes = 5;
+       btVector3 planes_n[6];
+       btScalar planes_o[6];
+       if (nplanes > 6)
+               nplanes = 6;
        for (int i=0; i<nplanes; i++)
        {
                planes_n[i].setValue(planes[i][0], planes[i][1], planes[i][2]);
                planes_o[i] = planes[i][3];
        }
-       btDbvt::collideKDOP(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,nplanes,dispatcher);
-       btDbvt::collideKDOP(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,nplanes,dispatcher);              
+       // if occlusionRes != 0 => occlusion culling
+       if (occlusionRes)
+       {
+               gOcb.setup(occlusionRes);
+               dispatcher.m_ocb = &gOcb;
+               // occlusion culling, the direction of the view is taken from the first plan which MUST be the near plane
+               btDbvt::collideOCL(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,planes_n[0],nplanes,dispatcher);
+               btDbvt::collideOCL(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,planes_n[0],nplanes,dispatcher);           
+       }else 
+       {
+               btDbvt::collideKDOP(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,nplanes,dispatcher);
+               btDbvt::collideKDOP(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,nplanes,dispatcher);              
+       }
        return true;
 }
 
-
 int    CcdPhysicsEnvironment::getNumContactPoints()
 {
        return 0;
index ddbcbe6..f861621 100644 (file)
@@ -172,7 +172,7 @@ protected:
                btTypedConstraint*      getConstraintById(int constraintId);
 
                virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
-               virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes);
+               virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes, int occlusionRes);
 
 
                //Methods for gamelogic collision/physics callbacks
index bf35731..48e537b 100644 (file)
@@ -39,9 +39,16 @@ CPPFLAGS += -I$(NAN_BULLET2)/include
 CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
 CPPFLAGS += -I$(NAN_STRING)/include
 CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_GLEW)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) 
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include    
 CPPFLAGS += -I../../../kernel/gen_system
 CPPFLAGS += -I../../Physics/common
 CPPFLAGS += -I../../Physics/Dummy
 CPPFLAGS += -I../../Rasterizer
+CPPFLAGS += -I../../Ketsji
+CPPFLAGS += -I../../Expressions
+CPPFLAGS += -I../../GameLogic
+CPPFLAGS += -I../../SceneGraph
 CPPFLAGS += -I../../../../source/blender/makesdna
 
index f3b6549..115ab8b 100644 (file)
@@ -3,9 +3,21 @@ Import ('env')
 
 sources = 'CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp CcdGraphicController.cpp'
 
-incs = '. ../common #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Rasterizer #source/blender/makesdna'
+incs = '. ../common'
+incs += ' #source/kernel/gen_system'
+incs += ' #intern/string'
+incs += ' #intern/moto/include'
+incs += ' #extern/glew/include'
+incs += ' #source/gameengine/Rasterizer'
+incs += ' #source/gameengine/Ketsji'
+incs += ' #source/gameengine/Expressions'
+incs += ' #source/gameengine/GameLogic'
+incs += ' #source/gameengine/SceneGraph'
+incs += ' #source/blender/makesdna'
+incs += ' #intern/SoundSystem'
 
 incs += ' ' + env['BF_BULLET_INC']
+incs += ' ' + env['BF_PYTHON_INC']
 
 cxxflags = []
 if env['OURPLATFORM']=='win32-vc':
index fae1844..4e15e6e 100644 (file)
@@ -70,7 +70,7 @@ public:
        }
 
        virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
-       virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes) { return false; }
+       virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes, int occlusionRes) { return false; }
 
 
        //gamelogic callbacks
index 9942a36..418a361 100644 (file)
@@ -76,7 +76,7 @@ public:
        }
 
        virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
-       virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes) { return false; }
+       virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes, int occlusionRes) { return false; }
 
        
        //gamelogic callbacks
index 5edafe6..9a4500c 100644 (file)
@@ -143,7 +143,9 @@ class PHY_IPhysicsEnvironment
                virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ)=0;
 
                //culling based on physical broad phase
-               virtual bool cullingTest(PHY_CullingCallback callback, void *userData, PHY__Vector4* planeNormals, int planeNumber) = 0;
+               // the plane number must be set as follow: near, far, left, right, top, botton
+               // the near plane must be the first one and must always be present, it is used to get the direction of the view
+               virtual bool cullingTest(PHY_CullingCallback callback, void *userData, PHY__Vector4* planeNormals, int planeNumber, int occlusionRes) = 0;
 
                //Methods for gamelogic collision/physics callbacks
                //todo:
index fb1e099..fa4641c 100644 (file)
@@ -25,6 +25,8 @@ class KX_GameObject: # (SCA_IObject)
        @ivar visible: visibility flag.
                - note: Game logic will still run for invisible objects.
        @type visible: boolean
+       @ivar occlusion: occlusion capability flag.
+       @type occlusion: boolean
        @ivar position: The object's position. 
        @type position: list [x, y, z]
        @ivar orientation: The object's orientation. 3x3 Matrix. You can also write a Quaternion or Euler vector.
@@ -76,6 +78,14 @@ class KX_GameObject: # (SCA_IObject)
                @type recursive: boolean
                @param recursive: optional argument to set all childrens visibility flag too.
                """
+       def setOcclusion(occlusion, recursive):
+               """
+               Sets the game object's occlusion capability.
+               
+               @type visible: boolean
+               @type recursive: boolean
+               @param recursive: optional argument to set all childrens occlusion flag too.
+               """
        def getState():
                """
                Gets the game object's state bitmask. (B{deprecated})
index aca8d1c..36f25b2 100644 (file)
@@ -7,7 +7,9 @@ class KX_VisibilityActuator(SCA_IActuator):
        Visibility Actuator.
        @ivar visibility: whether the actuator makes its parent object visible or invisible
        @type visibility: boolean
-       @ivar recursion: whether the visibility/invisibility should be propagated to all children of the object
+       @ivar occlusion: whether the actuator makes its parent object an occluder or not
+       @type occlusion: boolean
+       @ivar recursion: whether the visibility/occlusion should be propagated to all children of the object
        @type recursion: boolean
        """
        def set(visible):
index 69f73c2..5ddcdd3 100644 (file)
@@ -62,10 +62,12 @@ RAS_MeshSlot::~RAS_MeshSlot()
 {
        vector<RAS_DisplayArray*>::iterator it;
 
+#ifdef USE_SPLIT
        Split(true);
 
        while(m_joinedSlots.size())
                m_joinedSlots.front()->Split(true);
+#endif
 
        for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) {
                (*it)->m_users--;
@@ -428,11 +430,11 @@ bool RAS_MeshSlot::IsCulled()
                return true;
        if(!m_bCulled)
                return false;
-       
+#ifdef USE_SPLIT       
        for(it=m_joinedSlots.begin(); it!=m_joinedSlots.end(); it++)
                if(!(*it)->m_bCulled)
                        return false;
-       
+#endif 
        return true;
 }
 
index a907994..162f9a8 100644 (file)
@@ -406,7 +406,9 @@ void RAS_MeshObject::UpdateBuckets(void* clientobj,
                ms->m_bCulled = culled || !visible;
 
                /* split if necessary */
+#ifdef USE_SPLIT
                ms->Split();
+#endif
        }
 }
 
index 66b14bb..eacc128 100644 (file)
@@ -97,6 +97,17 @@ void RAS_Polygon::SetCollider(bool visible)
        else m_polyflags &= ~COLLIDER;
 }
 
+bool RAS_Polygon::IsTwoside()
+{
+       return (m_polyflags & TWOSIDE) != 0;
+}
+
+void RAS_Polygon::SetTwoside(bool twoside)
+{
+       if(twoside) m_polyflags |= TWOSIDE;
+       else m_polyflags &= ~TWOSIDE;
+}
+
 RAS_MaterialBucket* RAS_Polygon::GetMaterial()
 {
        return m_bucket;
index 224a7e0..41eaa6b 100644 (file)
@@ -56,7 +56,8 @@ class RAS_Polygon
 public:
        enum {
                VISIBLE = 1,
-               COLLIDER = 2
+               COLLIDER = 2,
+               TWOSIDE = 4
        };
 
        RAS_Polygon(RAS_MaterialBucket* bucket, RAS_DisplayArray* darray, int numvert);
@@ -79,6 +80,9 @@ public:
        bool                            IsCollider();
        void                            SetCollider(bool collider);
 
+       bool                            IsTwoside();
+       void                            SetTwoside(bool twoside);
+
        RAS_MaterialBucket*     GetMaterial();
        RAS_DisplayArray*       GetDisplayArray();
 };
index 58697ed..6ef62f6 100644 (file)
@@ -249,7 +249,7 @@ void ImageRender::Render()
     // restore the stereo mode now that the matrix is computed
     m_rasterizer->SetStereoMode(stereomode);
 
-    // do not update the mesh, we don't want to do it more than once per frame
+    // do not update the mesh transform, we don't want to do it more than once per frame
     //m_scene->UpdateMeshTransformations();
 
        m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera);