diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-12-14 20:32:24 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-12-14 20:32:24 +0300 |
commit | ec00764dd2349f723ba22b45515ec34ee81edcc3 (patch) | |
tree | cf506e71af7172ec63b89aa3d284fab27a2085e6 /source/gameengine | |
parent | 131fa2e00c35ff78042a4f793891eaeb880d715c (diff) | |
parent | 8449f0d77640c466acbda7d6ceeb71bc48317b44 (diff) |
2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r17434:HEAD
Diffstat (limited to 'source/gameengine')
24 files changed, 939 insertions, 167 deletions
diff --git a/source/gameengine/BlenderRoutines/Makefile b/source/gameengine/BlenderRoutines/Makefile index 7ee825d186b..b1be56ac47f 100644 --- a/source/gameengine/BlenderRoutines/Makefile +++ b/source/gameengine/BlenderRoutines/Makefile @@ -35,6 +35,7 @@ include nan_compile.mk CCFLAGS += $(LEVEL_1_CPP_WARNINGS) +CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(NAN_SUMO)/include -I$(NAN_SOLID)/include CPPFLAGS += -I$(NAN_SOLID) CPPFLAGS += -I$(NAN_STRING)/include diff --git a/source/gameengine/GamePlayer/common/unix/Makefile b/source/gameengine/GamePlayer/common/unix/Makefile index a2bdb7225a0..3d44a41afee 100644 --- a/source/gameengine/GamePlayer/common/unix/Makefile +++ b/source/gameengine/GamePlayer/common/unix/Makefile @@ -35,6 +35,7 @@ include nan_compile.mk CCFLAGS += $(LEVEL_1_CPP_WARNINGS) +CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_STRING)/include diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp index bf838e60210..3a20bbfbb11 100644 --- a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp @@ -185,7 +185,8 @@ void KX_BulletPhysicsController::SuspendDynamics(bool ghost) m_savedMass = GetMass(); m_savedCollisionFilterGroup = handle->m_collisionFilterGroup; m_savedCollisionFilterMask = handle->m_collisionFilterMask; - body->setActivationState(DISABLE_SIMULATION); + m_savedActivationState = body->getActivationState(); + body->forceActivationState(DISABLE_SIMULATION); GetPhysicsEnvironment()->updateCcdPhysicsController(this, 0.0, btCollisionObject::CF_STATIC_OBJECT|((ghost)?btCollisionObject::CF_NO_CONTACT_RESPONSE:(m_savedCollisionFlags&btCollisionObject::CF_NO_CONTACT_RESPONSE)), @@ -204,7 +205,7 @@ void KX_BulletPhysicsController::RestoreDynamics() m_savedCollisionFlags, m_savedCollisionFilterGroup, m_savedCollisionFilterMask); - GetRigidBody()->forceActivationState(ACTIVE_TAG); + GetRigidBody()->forceActivationState(m_savedActivationState); } } diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.h b/source/gameengine/Ketsji/KX_BulletPhysicsController.h index cdcb82c87ca..d5fca4ec6d3 100644 --- a/source/gameengine/Ketsji/KX_BulletPhysicsController.h +++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.h @@ -9,6 +9,7 @@ class KX_BulletPhysicsController : public KX_IPhysicsController ,public CcdPhysi { private: int m_savedCollisionFlags; + int m_savedActivationState; short int m_savedCollisionFilterGroup; short int m_savedCollisionFilterMask; MT_Scalar m_savedMass; diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp index 53b3e348a36..fb91c793765 100644 --- a/source/gameengine/Ketsji/KX_Camera.cpp +++ b/source/gameengine/Ketsji/KX_Camera.cpp @@ -259,10 +259,75 @@ void KX_Camera::ExtractFrustumSphere() if (m_set_frustum_center) return; - // The most extreme points on the near and far plane. (normalized device coords) - MT_Vector4 hnear(1., 1., 0., 1.), hfar(1., 1., 1., 1.); + // compute sphere for the general case and not only symmetric frustum: + // the mirror code in ImageRender can use very asymmetric frustum. + // We will put the sphere center on the line that goes from origin to the center of the far clipping plane + // This is the optimal position if the frustum is symmetric or very asymmetric and probably close + // to optimal for the general case. The sphere center position is computed so that the distance to + // the near and far extreme frustum points are equal. + + // get the transformation matrix from device coordinate to camera coordinate MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix; clip_camcs_matrix.invert(); + + // detect which of the corner of the far clipping plane is the farthest to the origin + MT_Vector4 nfar; // far point in device normalized coordinate + MT_Point3 farpoint; // most extreme far point in camera coordinate + MT_Point3 nearpoint;// most extreme near point in camera coordinate + MT_Point3 farcenter(0.,0.,0.);// center of far cliping plane in camera coordinate + MT_Scalar F=1.0, N; // square distance of far and near point to origin + MT_Scalar f, n; // distance of far and near point to z axis. f is always > 0 but n can be < 0 + MT_Scalar e, s; // far and near clipping distance (<0) + MT_Scalar c; // slope of center line = distance of far clipping center to z axis / far clipping distance + MT_Scalar z; // projection of sphere center on z axis (<0) + // tmp value + MT_Vector4 npoint(1., 1., 1., 1.); + MT_Vector4 hpoint; + MT_Point3 point; + MT_Scalar len; + for (int i=0; i<4; i++) + { + hpoint = clip_camcs_matrix*npoint; + point.setValue(hpoint[0]/hpoint[3], hpoint[1]/hpoint[3], hpoint[2]/hpoint[3]); + len = point.dot(point); + if (len > F) + { + nfar = npoint; + farpoint = point; + F = len; + } + // rotate by 90 degree along the z axis to walk through the 4 extreme points of the far clipping plane + len = npoint[0]; + npoint[0] = -npoint[1]; + npoint[1] = len; + farcenter += point; + } + // the far center is the average of the far clipping points + farcenter *= 0.25; + // the extreme near point is the opposite point on the near clipping plane + nfar.setValue(-nfar[0], -nfar[1], -1., 1.); + nfar = clip_camcs_matrix*nfar; + nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]); + N = nearpoint.dot(nearpoint); + e = farpoint[2]; + s = nearpoint[2]; + // projection on XY plane for distance to axis computation + MT_Point2 farxy(farpoint[0], farpoint[1]); + // f is forced positive by construction + f = farxy.length(); + // get corresponding point on the near plane + farxy *= s/e; + // this formula preserve the sign of n + n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length(); + c = MT_Point2(farcenter[0], farcenter[1]).length()/e; + // the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case + z = (F-N)/(2.0*(e-s+c*(f-n))); + m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z); + m_frustum_radius = m_frustum_center.distance(farpoint); + +#if 0 + // The most extreme points on the near and far plane. (normalized device coords) + MT_Vector4 hnear(1., 1., 0., 1.), hfar(1., 1., 1., 1.); // Transform to hom camera local space hnear = clip_camcs_matrix*hnear; @@ -273,10 +338,12 @@ void KX_Camera::ExtractFrustumSphere() MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]); // Compute center + // don't use camera data in case the user specifies the matrix directly m_frustum_center = MT_Point3(0., 0., - (nearpoint.dot(nearpoint) - farpoint.dot(farpoint))/(2.0*(m_camdata.m_clipend - m_camdata.m_clipstart))); + (nearpoint.dot(nearpoint) - farpoint.dot(farpoint))/(2.0*(nearpoint[2]-farpoint[2] /*m_camdata.m_clipend - m_camdata.m_clipstart*/))); m_frustum_radius = m_frustum_center.distance(farpoint); - +#endif + // Transform to world space. m_frustum_center = GetCameraToWorld()(m_frustum_center); m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]); diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index a168beb9a70..e4a37b589a8 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -615,6 +615,7 @@ void KX_GameObject::setAngularVelocity(const MT_Vector3& ang_vel,bool local) m_pPhysicsController1->SetAngularVelocity(ang_vel,local); } + void KX_GameObject::ResolveCombinedVelocities( const MT_Vector3 & lin_vel, const MT_Vector3 & ang_vel, @@ -969,6 +970,10 @@ PyMethodDef KX_GameObject::Methods[] = { {"getPosition", (PyCFunction) KX_GameObject::sPyGetPosition, METH_NOARGS}, {"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_O}, {"setWorldPosition", (PyCFunction) KX_GameObject::sPySetWorldPosition, METH_O}, + {"applyForce", (PyCFunction) KX_GameObject::sPyApplyForce, METH_VARARGS}, + {"applyTorque", (PyCFunction) KX_GameObject::sPyApplyTorque, METH_VARARGS}, + {"applyRotation", (PyCFunction) KX_GameObject::sPyApplyRotation, METH_VARARGS}, + {"applyMovement", (PyCFunction) KX_GameObject::sPyApplyMovement, METH_VARARGS}, {"getLinearVelocity", (PyCFunction) KX_GameObject::sPyGetLinearVelocity, METH_VARARGS}, {"setLinearVelocity", (PyCFunction) KX_GameObject::sPySetLinearVelocity, METH_VARARGS}, {"getAngularVelocity", (PyCFunction) KX_GameObject::sPyGetAngularVelocity, METH_VARARGS}, @@ -1261,6 +1266,65 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr return SCA_IObject::_setattr(attr, value); } +PyObject* KX_GameObject::PyApplyForce(PyObject* self, PyObject* args) +{ + int local = 0; + PyObject* pyvect; + + if (PyArg_ParseTuple(args, "O|i", &pyvect, &local)) { + MT_Vector3 force; + if (PyVecTo(pyvect, force)) { + ApplyForce(force, (local!=0)); + Py_RETURN_NONE; + } + } + return NULL; +} + +PyObject* KX_GameObject::PyApplyTorque(PyObject* self, PyObject* args) +{ + int local = 0; + PyObject* pyvect; + + if (PyArg_ParseTuple(args, "O|i", &pyvect, &local)) { + MT_Vector3 torque; + if (PyVecTo(pyvect, torque)) { + ApplyTorque(torque, (local!=0)); + Py_RETURN_NONE; + } + } + return NULL; +} + +PyObject* KX_GameObject::PyApplyRotation(PyObject* self, PyObject* args) +{ + int local = 0; + PyObject* pyvect; + + if (PyArg_ParseTuple(args, "O|i", &pyvect, &local)) { + MT_Vector3 rotation; + if (PyVecTo(pyvect, rotation)) { + ApplyRotation(rotation, (local!=0)); + Py_RETURN_NONE; + } + } + return NULL; +} + +PyObject* KX_GameObject::PyApplyMovement(PyObject* self, PyObject* args) +{ + int local = 0; + PyObject* pyvect; + + if (PyArg_ParseTuple(args, "O|i", &pyvect, &local)) { + MT_Vector3 movement; + if (PyVecTo(pyvect, movement)) { + ApplyMovement(movement, (local!=0)); + Py_RETURN_NONE; + } + } + return NULL; +} PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, PyObject* args) { diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 20b15787d27..4f26031356f 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -772,6 +772,10 @@ public: KX_PYMETHOD_NOARGS(KX_GameObject,GetPosition); KX_PYMETHOD_O(KX_GameObject,SetPosition); KX_PYMETHOD_O(KX_GameObject,SetWorldPosition); + KX_PYMETHOD_VARARGS(KX_GameObject, ApplyForce); + KX_PYMETHOD_VARARGS(KX_GameObject, ApplyTorque); + KX_PYMETHOD_VARARGS(KX_GameObject, ApplyRotation); + KX_PYMETHOD_VARARGS(KX_GameObject, ApplyMovement); KX_PYMETHOD_VARARGS(KX_GameObject,GetLinearVelocity); KX_PYMETHOD_VARARGS(KX_GameObject,SetLinearVelocity); KX_PYMETHOD_VARARGS(KX_GameObject,GetAngularVelocity); diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 4184202c518..8516049f6d8 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -184,7 +184,6 @@ private: void RenderDebugProperties(); void RenderShadowBuffers(KX_Scene *scene); void SetBackGround(KX_WorldInfo* worldinfo); - void SetWorldSettings(KX_WorldInfo* worldinfo); void DoSound(KX_Scene* scene); public: @@ -193,6 +192,7 @@ public: virtual ~KX_KetsjiEngine(); // set the devices and stuff. the client must take care of creating these + void SetWorldSettings(KX_WorldInfo* worldinfo); void SetKeyboardDevice(SCA_IInputDevice* keyboarddevice); void SetMouseDevice(SCA_IInputDevice* mousedevice); void SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice); @@ -205,6 +205,8 @@ public: void SetGame2IpoMode(bool game2ipo,int startFrame); RAS_IRasterizer* GetRasterizer(){return m_rasterizer;}; + RAS_ICanvas* GetCanvas(){return m_canvas;}; + RAS_IRenderTools* GetRenderTools(){return m_rendertools;}; ///returns true if an update happened to indicate -> Render bool NextFrame(); diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index caa71441b1d..476a931355f 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -1249,7 +1249,7 @@ void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Cam // If the camera is inside this node, then the object is visible. if (!vis) { - vis = gameobj->GetSGNode()->inside( GetActiveCamera()->GetCameraLocation() ); + vis = gameobj->GetSGNode()->inside( cam->GetCameraLocation() ); } // Test the object's bound sphere against the view frustum. diff --git a/source/gameengine/PyDoc/KX_GameObject.py b/source/gameengine/PyDoc/KX_GameObject.py index 505ce253dd1..efeffab2eed 100644 --- a/source/gameengine/PyDoc/KX_GameObject.py +++ b/source/gameengine/PyDoc/KX_GameObject.py @@ -123,6 +123,50 @@ class KX_GameObject: @return: The game object's rotation matrix @note: When using this matrix with Blender.Mathutils.Matrix() types, it will need to be transposed. """ + def applyMovement(movement, local = 0): + """ + Sets the game object's movement. + + @type movement: 3d vector. + @param movement: movement vector. + @type local: boolean + @param local: - False: you get the "global" movement ie: relative to world orientation (default). + - True: you get the "local" movement ie: relative to object orientation. + """ + def applyRotation(movement, local = 0): + """ + Sets the game object's rotation. + + @type rotation: 3d vector. + @param rotation: rotation vector. + @type local: boolean + @param local: - False: you get the "global" rotation ie: relative to world orientation (default). + - True: you get the "local" rotation ie: relative to object orientation. + """ + def applyForce(force, local = 0): + """ + Sets the game object's force. + + This requires a dynamic object. + + @type force: 3d vector. + @param force: force vector. + @type local: boolean + @param local: - False: you get the "global" force ie: relative to world orientation (default). + - True: you get the "local" force ie: relative to object orientation. + """ + def applyTorque(torque, local = 0): + """ + Sets the game object's torque. + + This requires a dynamic object. + + @type torque: 3d vector. + @param torque: torque vector. + @type local: boolean + @param local: - False: you get the "global" torque ie: relative to world orientation (default). + - True: you get the "local" torque ie: relative to object orientation. + """ def getLinearVelocity(local = 0): """ Gets the game object's linear velocity. @@ -143,6 +187,8 @@ class KX_GameObject: This method sets game object's velocity through it's centre of mass, ie no angular velocity component. + This requires a dynamic object. + @type velocity: 3d vector. @param velocity: linear velocity vector. @type local: boolean @@ -163,6 +209,8 @@ class KX_GameObject: """ Sets the game object's angular velocity. + This requires a dynamic object. + @type velocity: 3d vector. @param velocity: angular velocity vector. @type local: boolean diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp index d2cfa7d07f9..282c7306285 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp @@ -58,7 +58,7 @@ RAS_2DFilterManager::RAS_2DFilterManager(): texturewidth(-1), textureheight(-1), canvaswidth(-1), canvasheight(-1), -numberoffilters(0) +numberoffilters(0), need_tex_update(true) { isshadersupported = GLEW_ARB_shader_objects && GLEW_ARB_fragment_shader && GLEW_ARB_multitexture; @@ -217,50 +217,50 @@ void RAS_2DFilterManager::StartShaderProgram(int passindex) glActiveTextureARB(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texname[0]); - if (uniformLoc != -1) - { + if (uniformLoc != -1) + { glUniform1iARB(uniformLoc, 0); - } + } - /* send depth texture to glsl program if it needs */ + /* send depth texture to glsl program if it needs */ if(texflag[passindex] & 0x1){ - uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture"); - glActiveTextureARB(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, texname[1]); + uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture"); + glActiveTextureARB(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texname[1]); - if (uniformLoc != -1) - { - glUniform1iARB(uniformLoc, 1); - } - } + if (uniformLoc != -1) + { + glUniform1iARB(uniformLoc, 1); + } + } - /* send luminance texture to glsl program if it needs */ + /* send luminance texture to glsl program if it needs */ if(texflag[passindex] & 0x2){ - uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture"); - glActiveTextureARB(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, texname[2]); - - if (uniformLoc != -1) - { - glUniform1iARB(uniformLoc, 2); - } + uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture"); + glActiveTextureARB(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, texname[2]); + + if (uniformLoc != -1) + { + glUniform1iARB(uniformLoc, 2); + } } uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_TextureCoordinateOffset"); - if (uniformLoc != -1) - { - glUniform2fvARB(uniformLoc, 9, textureoffsets); - } + if (uniformLoc != -1) + { + glUniform2fvARB(uniformLoc, 9, textureoffsets); + } uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureWidth"); - if (uniformLoc != -1) - { + if (uniformLoc != -1) + { glUniform1fARB(uniformLoc,texturewidth); - } + } uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureHeight"); - if (uniformLoc != -1) - { + if (uniformLoc != -1) + { glUniform1fARB(uniformLoc,textureheight); - } + } int i, objProperties = m_properties[passindex].size(); for(i=0; i<objProperties; i++) @@ -332,20 +332,20 @@ void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas) RAS_Rect canvas_rect = canvas->GetWindowArea(); canvaswidth = canvas->GetWidth(); canvasheight = canvas->GetHeight(); - texturewidth = canvaswidth; - textureheight = canvasheight; + texturewidth = canvaswidth + canvas_rect.GetLeft(); + textureheight = canvasheight + canvas_rect.GetBottom(); GLint i,j; i = 0; - while ((1 << i) <= texturewidth) - i++; - texturewidth = (1 << (i)); + while ((1 << i) <= texturewidth) + i++; + texturewidth = (1 << (i)); - // Now for height - i = 0; - while ((1 << i) <= textureheight) - i++; - textureheight = (1 << (i)); + // Now for height + i = 0; + while ((1 << i) <= textureheight) + i++; + textureheight = (1 << (i)); GLfloat xInc = 1.0f / (GLfloat)texturewidth; GLfloat yInc = 1.0f / (GLfloat)textureheight; @@ -360,6 +360,23 @@ void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas) } } +void RAS_2DFilterManager::UpdateCanvasTextureCoord(unsigned int * viewport) +{ + /* + This function update canvascoord[]. + These parameters are used to create texcoord[1] + That way we can access the texcoord relative to the canvas: + (0.0,0.0) bottom left, (1.0,1.0) top right, (0.5,0.5) center + */ + canvascoord[0] = (GLfloat) viewport[0] / viewport[2]; + canvascoord[0] *= -1; + canvascoord[1] = (GLfloat) (texturewidth - viewport[0]) / viewport[2]; + + canvascoord[2] = (GLfloat) viewport[1] / viewport[3]; + canvascoord[2] *= -1; + canvascoord[3] = (GLfloat)(textureheight - viewport[1]) / viewport[3]; +} + void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) { bool need_depth=false; @@ -387,27 +404,35 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) if(num_filters <= 0) return; + GLuint viewport[4]={0}; + glGetIntegerv(GL_VIEWPORT,(GLint *)viewport); + if(canvaswidth != canvas->GetWidth() || canvasheight != canvas->GetHeight()) { UpdateOffsetMatrix(canvas); + UpdateCanvasTextureCoord((unsigned int*)viewport); + need_tex_update = true; + } + + if(need_tex_update) + { SetupTextures(need_depth, need_luminance); + need_tex_update = false; } - GLuint viewport[4]={0}; if(need_depth){ glActiveTextureARB(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texname[1]); - glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, viewport[0], viewport[1], texturewidth,textureheight, 0); + glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, 0, 0, texturewidth,textureheight, 0); } if(need_luminance){ glActiveTextureARB(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, texname[2]); - glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, viewport[0], viewport[1] , texturewidth,textureheight, 0); + glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0, 0, texturewidth,textureheight, 0); } - glGetIntegerv(GL_VIEWPORT,(GLint *)viewport); - glViewport(viewport[0],viewport[1], texturewidth, textureheight); + glViewport(0,0, texturewidth, textureheight); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_TEXTURE); @@ -425,20 +450,15 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) glActiveTextureARB(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texname[0]); - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, viewport[0], viewport[1], texturewidth, textureheight, 0); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, texturewidth, textureheight, 0); glClear(GL_COLOR_BUFFER_BIT); - float canvascoordx, canvascoordy; - - canvascoordx = (GLfloat) texturewidth / canvaswidth; - canvascoordy = (GLfloat) textureheight / canvasheight; - glBegin(GL_QUADS); glColor4f(1.f, 1.f, 1.f, 1.f); - glTexCoord2f(1.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, canvascoordx, canvascoordy); glVertex2f(1,1); - glTexCoord2f(0.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, canvascoordy); glVertex2f(-1,1); - glTexCoord2f(0.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, 0.0); glVertex2f(-1,-1); - glTexCoord2f(1.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, canvascoordx, 0.0); glVertex2f(1,-1); + glTexCoord2f(1.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[3]); glVertex2f(1,1); + glTexCoord2f(0.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[3]); glVertex2f(-1,1); + glTexCoord2f(0.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[2]); glVertex2f(-1,-1); + glTexCoord2f(1.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[2]); glVertex2f(1,-1); glEnd(); } } @@ -454,7 +474,7 @@ void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* game return; if(pass<0 || pass>=MAX_RENDER_PASS) return; - + need_tex_update = true; if(mode == RAS_2DFILTER_DISABLED) { m_enabled[pass] = 0; diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.h b/source/gameengine/Rasterizer/RAS_2DFilterManager.h index 454643a5077..6a420a974d4 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.h +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.h @@ -44,7 +44,9 @@ private: void FreeTextures(); void UpdateOffsetMatrix(RAS_ICanvas* canvas); - + void UpdateCanvasTextureCoord(unsigned int * viewport); + + float canvascoord[4]; float textureoffsets[18]; float view[4]; /* texname[0] contains render to texture, texname[1] contains depth texture, texname[2] contains luminance texture*/ @@ -60,6 +62,7 @@ private: bool isshadersupported; bool errorprinted; + bool need_tex_update; unsigned int m_filters[MAX_RENDER_PASS]; short m_enabled[MAX_RENDER_PASS]; diff --git a/source/gameengine/Rasterizer/RAS_FramingManager.h b/source/gameengine/Rasterizer/RAS_FramingManager.h index 9cb59f300f7..610bd13ff12 100644 --- a/source/gameengine/Rasterizer/RAS_FramingManager.h +++ b/source/gameengine/Rasterizer/RAS_FramingManager.h @@ -212,9 +212,6 @@ public : RAS_FrameFrustum &frustum ); - -private : - static void ComputeDefaultFrustum( @@ -225,6 +222,8 @@ private : RAS_FrameFrustum & frustum ); +private : + static void ComputeBestFitViewRect( diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h index 411b28fa3b7..b4b90c3608b 100644 --- a/source/gameengine/Rasterizer/RAS_IRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h @@ -200,6 +200,7 @@ public: * @return true if stereo mode is enabled. */ virtual bool Stereo()=0; + virtual StereoMode GetStereoMode()=0; virtual bool InterlacedStereo()=0; /** * Sets which eye buffer subsequent primitives will be rendered to. diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index 87a0a1d8b9e..3cad5fe74f2 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -406,14 +406,16 @@ void RAS_OpenGLRasterizer::SetRenderArea() break; } } - void RAS_OpenGLRasterizer::SetStereoMode(const StereoMode stereomode) { m_stereomode = stereomode; } - +RAS_IRasterizer::StereoMode RAS_OpenGLRasterizer::GetStereoMode() +{ + return m_stereomode; +} bool RAS_OpenGLRasterizer::Stereo() { @@ -775,7 +777,7 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix( float frustnear, float frustfar, float focallength, - bool + bool ){ MT_Matrix4x4 result; double mat[16]; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h index 0717cce0ce8..d39fd642f86 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h @@ -137,6 +137,7 @@ public: virtual void SetRenderArea(); virtual void SetStereoMode(const StereoMode stereomode); + virtual RAS_IRasterizer::StereoMode GetStereoMode(); virtual bool Stereo(); virtual bool InterlacedStereo(); virtual void SetEye(const StereoEye eye); diff --git a/source/gameengine/VideoTexture/Exception.cpp b/source/gameengine/VideoTexture/Exception.cpp index 3f939de6bc2..8704d49f2a7 100644 --- a/source/gameengine/VideoTexture/Exception.cpp +++ b/source/gameengine/VideoTexture/Exception.cpp @@ -204,6 +204,12 @@ void registerAllExceptions(void) ImageSizesNotMatchDesc.registerDesc(); SceneInvalidDesc.registerDesc(); CameraInvalidDesc.registerDesc(); + ObserverInvalidDesc.registerDesc(); + MirrorInvalidDesc.registerDesc(); + MirrorSizeInvalidDesc.registerDesc(); + MirrorNormalInvalidDesc.registerDesc(); + MirrorHorizontalDesc.registerDesc(); + MirrorTooSmallDesc.registerDesc(); SourceVideoEmptyDesc.registerDesc(); SourceVideoCreationDesc.registerDesc(); } diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h index 5345e87f199..1a3c25071b1 100644 --- a/source/gameengine/VideoTexture/Exception.h +++ b/source/gameengine/VideoTexture/Exception.h @@ -202,6 +202,12 @@ extern ExpDesc MaterialNotAvailDesc; extern ExpDesc ImageSizesNotMatchDesc; extern ExpDesc SceneInvalidDesc; extern ExpDesc CameraInvalidDesc; +extern ExpDesc ObserverInvalidDesc; +extern ExpDesc MirrorInvalidDesc; +extern ExpDesc MirrorSizeInvalidDesc; +extern ExpDesc MirrorNormalInvalidDesc; +extern ExpDesc MirrorHorizontalDesc; +extern ExpDesc MirrorTooSmallDesc; extern ExpDesc SourceVideoEmptyDesc; extern ExpDesc SourceVideoCreationDesc; diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index a8f7871fa21..58697ed3cc7 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -24,96 +24,238 @@ http://www.gnu.org/copyleft/lesser.txt. #include <PyObjectPlus.h> #include <structmember.h> +#include <float.h> +#include <math.h> -#include <KX_BlenderCanvas.h> -#include <KX_BlenderRenderTools.h> -#include <RAS_IRasterizer.h> -#include <RAS_OpenGLRasterizer.h> -#include <KX_WorldInfo.h> -#include <KX_Light.h> -#include "ImageRender.h" +#include <BIF_gl.h> + +#include "KX_PythonInit.h" +#include "DNA_scene_types.h" +#include "RAS_CameraData.h" +#include "RAS_MeshObject.h" +#include "BLI_arithb.h" +#include "ImageRender.h" #include "ImageBase.h" #include "BlendType.h" #include "Exception.h" +#include "Texture.h" -ExceptionID SceneInvalid, CameraInvalid; +ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid; +ExceptionID MirrorInvalid, MirrorSizeInvalid, MirrorNormalInvalid, MirrorHorizontal, MirrorTooSmall; ExpDesc SceneInvalidDesc (SceneInvalid, "Scene object is invalid"); ExpDesc CameraInvalidDesc (CameraInvalid, "Camera object is invalid"); - -#if 0 // not yet supported +ExpDesc ObserverInvalidDesc (ObserverInvalid, "Observer object is invalid"); +ExpDesc MirrorInvalidDesc (MirrorInvalid, "Mirror object is invalid"); +ExpDesc MirrorSizeInvalidDesc (MirrorSizeInvalid, "Mirror has no vertex or no size"); +ExpDesc MirrorNormalInvalidDesc (MirrorNormalInvalid, "Cannot determine mirror plane"); +ExpDesc MirrorHorizontalDesc (MirrorHorizontal, "Mirror is horizontal in local space"); +ExpDesc MirrorTooSmallDesc (MirrorTooSmall, "Mirror is too small"); // constructor -ImageRender::ImageRender (KX_Scene * scene, KX_Camera * camera) : m_scene(scene), -m_camera(camera) +ImageRender::ImageRender (KX_Scene * scene, KX_Camera * camera) : + ImageViewport(), + m_render(true), + m_scene(scene), + m_camera(camera), + m_owncamera(false), + m_observer(NULL), + m_mirror(NULL), + m_clip(100.f) { - // create screen area - m_area.winrct.xmin = m_upLeft[0]; - m_area.winrct.ymin = m_upLeft[1]; - m_area.winx = m_size[0]; - m_area.winy = m_size[1]; - // create canvas - m_canvas = new KX_BlenderCanvas(&m_area); - // create render tools - m_rendertools = new KX_BlenderRenderTools(); - // create rasterizer - m_rasterizer = new RAS_OpenGLRasterizer(m_canvas); - m_rasterizer->Init(); // initialize background colour - setBackground(0, 0, 255); - // refresh lights - refreshLights(); + setBackground(0, 0, 255, 255); + // retrieve rendering objects + m_engine = KX_GetActiveEngine(); + m_rasterizer = m_engine->GetRasterizer(); + m_canvas = m_engine->GetCanvas(); + m_rendertools = m_engine->GetRenderTools(); } // destructor ImageRender::~ImageRender (void) { - // release allocated objects - delete m_rasterizer; - delete m_rendertools; - delete m_canvas; + if (m_owncamera) + m_camera->Release(); } // set background color -void ImageRender::setBackground (unsigned char red, unsigned char green, unsigned char blue) +void ImageRender::setBackground (int red, int green, int blue, int alpha) { - m_background[0] = red; - m_background[1] = green; - m_background[2] = blue; - m_rasterizer->SetBackColor(m_background[0], m_background[1], m_background[2], 1.0); + m_background[0] = (red < 0) ? 0.f : (red > 255) ? 1.f : float(red)/255.f; + m_background[1] = (green < 0) ? 0.f : (green > 255) ? 1.f : float(green)/255.f; + m_background[2] = (blue < 0) ? 0.f : (blue > 255) ? 1.f : float(blue)/255.f; + m_background[3] = (alpha < 0) ? 0.f : (alpha > 255) ? 1.f : float(alpha)/255.f; } // capture image from viewport void ImageRender::calcImage (unsigned int texId) { - // setup camera - bool cameraPasive = !m_camera->GetViewport(); - // render scene - Render(); - // reset camera - if (cameraPasive) m_camera->EnableViewport(false); + if (m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture + m_camera->GetViewport() || // camera must be inactive + m_camera == m_scene->GetActiveCamera()) + { + // no need to compute texture in non texture rendering + m_avail = false; + return; + } + // render the scene from the camera + Render(); // get image from viewport ImageViewport::calcImage(texId); + // restore OpenGL state + m_canvas->EndFrame(); } void ImageRender::Render() { - // -} + RAS_FrameFrustum frustrum; + + if (!m_render) + return; + + if (m_mirror) + { + // mirror mode, compute camera frustrum, position and orientation + // convert mirror position and normal in world space + const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation(); + const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition(); + const MT_Vector3 & mirrorObjWorldScale = m_mirror->GetSGNode()->GetWorldScaling(); + MT_Point3 mirrorWorldPos = + mirrorObjWorldPos + mirrorObjWorldScale * (mirrorObjWorldOri * m_mirrorPos); + MT_Vector3 mirrorWorldZ = mirrorObjWorldOri * m_mirrorZ; + // get observer world position + const MT_Point3 & observerWorldPos = m_observer->GetSGNode()->GetWorldPosition(); + // get plane D term = mirrorPos . normal + MT_Scalar mirrorPlaneDTerm = mirrorWorldPos.dot(mirrorWorldZ); + // compute distance of observer to mirror = D - observerPos . normal + MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ); + // if distance < 0.01 => observer is on wrong side of mirror, don't render + if (observerDistance < 0.01f) + return; + // set camera world position = observerPos + normal * 2 * distance + MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ; + m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos); + // set camera orientation: z=normal, y=mirror_up in world space, x= y x z + MT_Vector3 mirrorWorldY = mirrorObjWorldOri * m_mirrorY; + MT_Vector3 mirrorWorldX = mirrorObjWorldOri * m_mirrorX; + MT_Matrix3x3 cameraWorldOri( + mirrorWorldX[0], mirrorWorldY[0], mirrorWorldZ[0], + mirrorWorldX[1], mirrorWorldY[1], mirrorWorldZ[1], + mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]); + m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri); + m_camera->GetSGNode()->UpdateWorldData(0.0); + // compute camera frustrum: + // get position of mirror relative to camera: offset = mirrorPos-cameraPos + MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos; + // convert to camera orientation + mirrorOffset = mirrorOffset * cameraWorldOri; + // scale mirror size to world scale: + // get closest local axis for mirror Y and X axis and scale height and width by local axis scale + MT_Scalar x, y; + x = fabs(m_mirrorY[0]); + y = fabs(m_mirrorY[1]); + float height = (x > y) ? + ((x > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): + ((y > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); + x = fabs(m_mirrorX[0]); + y = fabs(m_mirrorX[1]); + float width = (x > y) ? + ((x > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): + ((y > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); + width *= m_mirrorHalfWidth; + height *= m_mirrorHalfHeight; + // left = offsetx-width + // right = offsetx+width + // top = offsety+height + // bottom = offsety-height + // near = -offsetz + // far = near+100 + frustrum.x1 = mirrorOffset[0]-width; + frustrum.x2 = mirrorOffset[0]+width; + frustrum.y1 = mirrorOffset[1]-height; + frustrum.y2 = mirrorOffset[1]+height; + frustrum.camnear = -mirrorOffset[2]; + frustrum.camfar = -mirrorOffset[2]+m_clip; + } + const float ortho = 100.0; + const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); + + // The screen area that ImageViewport will copy is also the rendering zone + m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1); + m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]); + m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); + m_rasterizer->BeginFrame(RAS_IRasterizer::KX_TEXTURED,m_engine->GetClockTime()); + m_rendertools->BeginFrame(m_rasterizer); + m_engine->SetWorldSettings(m_scene->GetWorldInfo()); + m_rendertools->SetAuxilaryClientInfo(m_scene); + m_rasterizer->DisplayFog(); + // matrix calculation, don't apply any of the stereo mode + m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO); + if (m_mirror) + { + // frustrum was computed above + // get frustrum matrix and set projection matrix + MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( + frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); + + m_camera->SetProjectionMatrix(projmat); + } else if (m_camera->hasValidProjectionMatrix()) + { + m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix()); + } else + { + float lens = m_camera->GetLens(); + bool orthographic = !m_camera->GetCameraData()->m_perspective; + float nearfrust = m_camera->GetCameraNear(); + float farfrust = m_camera->GetCameraFar(); + float aspect_ratio = 1.0f; + Scene *blenderScene = m_scene->GetBlenderScene(); + + if (orthographic) { + lens *= ortho; + nearfrust = (nearfrust + 1.0)*ortho; + farfrust *= ortho; + } + // compute the aspect ratio from frame blender scene settings so that render to texture + // works the same in Blender and in Blender player + if (blenderScene->r.ysch != 0) + aspect_ratio = float(blenderScene->r.xsch) / float(blenderScene->r.ysch); + + RAS_FramingManager::ComputeDefaultFrustum( + nearfrust, + farfrust, + lens, + aspect_ratio, + frustrum); + + MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( + frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); + + m_camera->SetProjectionMatrix(projmat); + } -// refresh lights -void ImageRender::refreshLights (void) -{ - // clear lights list - //m_rendertools->RemoveAllLights(); - // set lights - //for (int idx = 0; idx < scene->GetLightList()->GetCount(); ++idx) - // m_rendertools->AddLight(((KX_LightObject*)(scene->GetLightList()->GetValue(idx)))->GetLightData()); -} + MT_Transform camtrans(m_camera->GetWorldToCamera()); + if (!m_camera->GetCameraData()->m_perspective) + camtrans.getOrigin()[2] *= ortho; + MT_Matrix4x4 viewmat(camtrans); + + m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldPosition(), + m_camera->GetCameraLocation(), m_camera->GetCameraOrientation()); + m_camera->SetModelviewMatrix(viewmat); + // 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 + //m_scene->UpdateMeshTransformations(); + m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera); + + m_scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); +} // cast Image pointer to ImageRender @@ -174,26 +316,31 @@ static int ImageRender_init (PyObject * pySelf, PyObject * args, PyObject * kwds // get background color PyObject * getBackground (PyImage * self, void * closure) { - return Py_BuildValue("[BBB]", getImageRender(self)->getBackground()[0], - getImageRender(self)->getBackground()[1], getImageRender(self)->getBackground()[2]); + return Py_BuildValue("[BBBB]", + getImageRender(self)->getBackground(0), + getImageRender(self)->getBackground(1), + getImageRender(self)->getBackground(2), + getImageRender(self)->getBackground(3)); } // set color static int setBackground (PyImage * self, PyObject * value, void * closure) { // check validity of parameter - if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 3 + if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 4 || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 0)) || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 1)) - || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 2))) + || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 2)) + || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 3))) { - PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 3 ints"); + PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 4 integer between 0 and 255"); return -1; } // set background color getImageRender(self)->setBackground((unsigned char)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 0))), (unsigned char)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 1))), - (unsigned char)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 2)))); + (unsigned char)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 2))), + (unsigned char)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 3)))); // success return 0; } @@ -209,6 +356,10 @@ static PyMethodDef imageRenderMethods[] = static PyGetSetDef imageRenderGetSets[] = { {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL}, + // attribute from ImageViewport + {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL}, + {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, + {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL}, // attributes from ImageBase class {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, @@ -263,5 +414,329 @@ PyTypeObject ImageRenderType = Image_allocNew, /* tp_new */ }; +// object initialization +static int ImageMirror_init (PyObject * pySelf, PyObject * args, PyObject * kwds) +{ + // parameters - scene object + PyObject * scene; + // reference object for mirror + PyObject * observer; + // object holding the mirror + PyObject * mirror; + // material of the mirror + short materialID = 0; + // parameter keywords + static char *kwlist[] = {"scene", "observer", "mirror", "material", NULL}; + // get parameters + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|h", kwlist, &scene, &observer, &mirror, &materialID)) + return -1; + try + { + // get scene pointer + KX_Scene * scenePtr (NULL); + if (scene != NULL && PyObject_TypeCheck(scene, &KX_Scene::Type)) + scenePtr = static_cast<KX_Scene*>(scene); + else + THRWEXCP(SceneInvalid, S_OK); + + // get observer pointer + KX_GameObject * observerPtr (NULL); + if (observer != NULL && PyObject_TypeCheck(observer, &KX_GameObject::Type)) + observerPtr = static_cast<KX_GameObject*>(observer); + else if (observer != NULL && PyObject_TypeCheck(observer, &KX_Camera::Type)) + observerPtr = static_cast<KX_Camera*>(observer); + else + THRWEXCP(ObserverInvalid, S_OK); + + // get mirror pointer + KX_GameObject * mirrorPtr (NULL); + if (mirror != NULL && PyObject_TypeCheck(mirror, &KX_GameObject::Type)) + mirrorPtr = static_cast<KX_GameObject*>(mirror); + else + THRWEXCP(MirrorInvalid, S_OK); + + // locate the material in the mirror + RAS_IPolyMaterial * material = getMaterial(mirror, materialID); + if (material == NULL) + THRWEXCP(MaterialNotAvail, S_OK); + + // get pointer to image structure + PyImage * self = reinterpret_cast<PyImage*>(pySelf); + + // create source object + if (self->m_image != NULL) + { + delete self->m_image; + self->m_image = NULL; + } + self->m_image = new ImageRender(scenePtr, observerPtr, mirrorPtr, material); + } + catch (Exception & exp) + { + exp.report(); + return -1; + } + // initialization succeded + return 0; +} + +// get background color +PyObject * getClip (PyImage * self, void * closure) +{ + return PyFloat_FromDouble(getImageRender(self)->getClip()); +} + +// set clip +static int setClip (PyImage * self, PyObject * value, void * closure) +{ + // check validity of parameter + double clip; + if (value == NULL || !PyFloat_Check(value) || (clip = PyFloat_AsDouble(value)) < 0.01 || clip > 5000.0) + { + PyErr_SetString(PyExc_TypeError, "The value must be an float between 0.01 and 5000"); + return -1; + } + // set background color + getImageRender(self)->setClip(float(clip)); + // success + return 0; +} + +// attributes structure +static PyGetSetDef imageMirrorGetSets[] = +{ + {(char*)"clip", (getter)getClip, (setter)setClip, (char*)"clipping distance", NULL}, + // attribute from ImageRender + {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL}, + // attribute from ImageViewport + {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL}, + {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, + {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL}, + // attributes from ImageBase class + {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, + {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, + {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL}, + {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, + {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, + {NULL} +}; + + +// constructor +ImageRender::ImageRender (KX_Scene * scene, KX_GameObject * observer, KX_GameObject * mirror, RAS_IPolyMaterial * mat) : + ImageViewport(), + m_render(false), + m_scene(scene), + m_observer(observer), + m_mirror(mirror), + m_clip(100.f) +{ + // this constructor is used for automatic planar mirror + // create a camera, take all data by default, in any case we will recompute the frustrum on each frame + RAS_CameraData camdata; + vector<RAS_TexVert*> mirrorVerts; + vector<RAS_TexVert*>::iterator it; + float mirrorArea = 0.f; + float mirrorNormal[3] = {0.f, 0.f, 0.f}; + float mirrorUp[3]; + float dist, vec[3], axis[3]; + float zaxis[3] = {0.f, 0.f, 1.f}; + float yaxis[3] = {0.f, 1.f, 0.f}; + float mirrorMat[3][3]; + float left, right, top, bottom, back; + + m_camera= new KX_Camera(scene, KX_Scene::m_callbacks, camdata); + m_camera->SetName("__mirror__cam__"); + // don't add the camera to the scene object list, it doesn't need to be accessible + m_owncamera = true; + // retrieve rendering objects + m_engine = KX_GetActiveEngine(); + m_rasterizer = m_engine->GetRasterizer(); + m_canvas = m_engine->GetCanvas(); + m_rendertools = m_engine->GetRenderTools(); + // locate the vertex assigned to mat and do following calculation in mesh coordinates + for (int meshIndex = 0; meshIndex < mirror->GetMeshCount(); meshIndex++) + { + RAS_MeshObject* mesh = mirror->GetMesh(meshIndex); + int numPolygons = mesh->NumPolygons(); + for (int polygonIndex=0; polygonIndex < numPolygons; polygonIndex++) + { + RAS_Polygon* polygon = mesh->GetPolygon(polygonIndex); + if (polygon->GetMaterial()->GetPolyMaterial() == mat) + { + RAS_TexVert *v1, *v2, *v3, *v4; + float normal[3]; + float area; + // this polygon is part of the mirror, + v1 = polygon->GetVertex(0); + v2 = polygon->GetVertex(1); + v3 = polygon->GetVertex(2); + mirrorVerts.push_back(v1); + mirrorVerts.push_back(v2); + mirrorVerts.push_back(v3); + if (polygon->VertexCount() == 4) + { + v4 = polygon->GetVertex(3); + mirrorVerts.push_back(v4); + area = CalcNormFloat4((float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), (float*)v4->getXYZ(), normal); + } else + { + area = CalcNormFloat((float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), normal); + } + area = fabs(area); + mirrorArea += area; + VecMulf(normal, area); + VecAddf(mirrorNormal, mirrorNormal, normal); + } + } + } + if (mirrorVerts.size() == 0 || mirrorArea < FLT_EPSILON) + { + // no vertex or zero size mirror + THRWEXCP(MirrorSizeInvalid, S_OK); + } + // compute average normal of mirror faces + VecMulf(mirrorNormal, 1.0f/mirrorArea); + if (Normalize(mirrorNormal) == 0.f) + { + // no normal + THRWEXCP(MirrorNormalInvalid, S_OK); + } + // the mirror plane has an equation of the type ax+by+cz = d where (a,b,c) is the normal vector + // if the mirror is more vertical then horizontal, the Z axis is the up direction. + // otherwise the Y axis is the up direction. + // If the mirror is not perfectly vertical(horizontal), the Z(Y) axis projection on the mirror + // plan by the normal will be the up direction. + if (fabs(mirrorNormal[2]) > fabs(mirrorNormal[1]) && + fabs(mirrorNormal[2]) > fabs(mirrorNormal[0])) + { + // the mirror is more horizontal than vertical + VecCopyf(axis, yaxis); + } + else + { + // the mirror is more vertical than horizontal + VecCopyf(axis, zaxis); + } + dist = Inpf(mirrorNormal, axis); + if (fabs(dist) < FLT_EPSILON) + { + // the mirror is already fully aligned with up axis + VecCopyf(mirrorUp, axis); + } + else + { + // projection of axis to mirror plane through normal + VecCopyf(vec, mirrorNormal); + VecMulf(vec, dist); + VecSubf(mirrorUp, axis, vec); + if (Normalize(mirrorUp) == 0.f) + { + // should not happen + THRWEXCP(MirrorHorizontal, S_OK); + return; + } + } + // compute rotation matrix between local coord and mirror coord + // to match camera orientation, we select mirror z = -normal, y = up, x = y x z + VecCopyf(mirrorMat[2], mirrorNormal); + VecMulf(mirrorMat[2], -1.0f); + VecCopyf(mirrorMat[1], mirrorUp); + Crossf(mirrorMat[0], mirrorMat[1], mirrorMat[2]); + // transpose to make it a orientation matrix from local space to mirror space + Mat3Transp(mirrorMat); + // transform all vertex to plane coordinates and determine mirror position + left = FLT_MAX; + right = -FLT_MAX; + bottom = FLT_MAX; + top = -FLT_MAX; + back = -FLT_MAX; // most backward vertex (=highest Z coord in mirror space) + for (it = mirrorVerts.begin(); it != mirrorVerts.end(); it++) + { + VecCopyf(vec, (float*)(*it)->getXYZ()); + Mat3MulVecfl(mirrorMat, vec); + if (vec[0] < left) + left = vec[0]; + if (vec[0] > right) + right = vec[0]; + if (vec[1] < bottom) + bottom = vec[1]; + if (vec[1] > top) + top = vec[1]; + if (vec[2] > back) + back = vec[2]; + } + // now store this information in the object for later rendering + m_mirrorHalfWidth = (right-left)*0.5f; + m_mirrorHalfHeight = (top-bottom)*0.5f; + if (m_mirrorHalfWidth < 0.01f || m_mirrorHalfHeight < 0.01f) + { + // mirror too small + THRWEXCP(MirrorTooSmall, S_OK); + } + // mirror position in mirror coord + vec[0] = (left+right)*0.5f; + vec[1] = (top+bottom)*0.5f; + vec[2] = back; + // convert it in local space: transpose again the matrix to get back to mirror to local transform + Mat3Transp(mirrorMat); + Mat3MulVecfl(mirrorMat, vec); + // mirror position in local space + m_mirrorPos.setValue(vec[0], vec[1], vec[2]); + // mirror normal vector (pointed towards the back of the mirror) in local space + m_mirrorZ.setValue(-mirrorNormal[0], -mirrorNormal[1], -mirrorNormal[2]); + m_mirrorY.setValue(mirrorUp[0], mirrorUp[1], mirrorUp[2]); + m_mirrorX = m_mirrorY.cross(m_mirrorZ); + m_render = true; + + setBackground(0, 0, 255, 255); +} + + + + +// define python type +PyTypeObject ImageMirrorType = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "VideoTexture.ImageMirror", /*tp_name*/ + sizeof(PyImage), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Image_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Image source from mirror", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + imageRenderMethods, /* tp_methods */ + 0, /* tp_members */ + imageMirrorGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)ImageMirror_init, /* tp_init */ + 0, /* tp_alloc */ + Image_allocNew, /* tp_new */ +}; + -#endif // #if 0 diff --git a/source/gameengine/VideoTexture/ImageRender.h b/source/gameengine/VideoTexture/ImageRender.h index 66255f04d2c..c94e2f1e718 100644 --- a/source/gameengine/VideoTexture/ImageRender.h +++ b/source/gameengine/VideoTexture/ImageRender.h @@ -42,42 +42,56 @@ class ImageRender : public ImageViewport public: /// constructor ImageRender (KX_Scene * scene, KX_Camera * camera); + ImageRender (KX_Scene * scene, KX_GameObject * observer, KX_GameObject * mirror, RAS_IPolyMaterial * mat); /// destructor virtual ~ImageRender (void); /// get background color - unsigned char * getBackground (void) { return m_background; } + int getBackground (int idx) { return (idx < 0 || idx > 3) ? 0 : int(m_background[idx]*255.f); } /// set background color - void setBackground (unsigned char red, unsigned char green, unsigned char blue); + void setBackground (int red, int green, int blue, int alpha); + + /// clipping distance + float getClip (void) { return m_clip; } + /// set whole buffer use + void setClip (float clip) { m_clip = clip; } protected: + /// true if ready to render + bool m_render; /// rendered scene KX_Scene * m_scene; /// camera for render KX_Camera * m_camera; - - /// screen area for rendering - ScrArea m_area; - /// rendering device - RAS_ICanvas * m_canvas; - /// rasterizer - RAS_IRasterizer * m_rasterizer; - /// render tools - RAS_IRenderTools * m_rendertools; + /// do we own the camera? + bool m_owncamera; + /// for mirror operation + KX_GameObject * m_observer; + KX_GameObject * m_mirror; + float m_clip; // clipping distance + float m_mirrorHalfWidth; // mirror width in mirror space + float m_mirrorHalfHeight; // mirror height in mirror space + MT_Point3 m_mirrorPos; // mirror center position in local space + MT_Vector3 m_mirrorZ; // mirror Z axis in local space + MT_Vector3 m_mirrorY; // mirror Y axis in local space + MT_Vector3 m_mirrorX; // mirror X axis in local space + /// canvas + RAS_ICanvas* m_canvas; + /// rasterizer + RAS_IRasterizer* m_rasterizer; + /// render tools + RAS_IRenderTools* m_rendertools; + /// engine + KX_KetsjiEngine* m_engine; /// background colour - unsigned char m_background[3]; + float m_background[4]; /// render 3d scene to image virtual void calcImage (unsigned int texId); - /// refresh lights - void refreshLights (void); - /// methods from KX_KetsjiEngine - bool BeginFrame(); - void EndFrame(); void Render(); void SetupRenderFrame(KX_Scene *scene, KX_Camera* cam); void RenderFrame(KX_Scene* scene, KX_Camera* cam); diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp index deb66ffb6ba..4c2c81e2208 100644 --- a/source/gameengine/VideoTexture/ImageViewport.cpp +++ b/source/gameengine/VideoTexture/ImageViewport.cpp @@ -34,12 +34,12 @@ http://www.gnu.org/copyleft/lesser.txt. // constructor -ImageViewport::ImageViewport (void) : m_texInit(false) +ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false) { // get viewport rectangle glGetIntegerv(GL_VIEWPORT, m_viewport); // create buffer for viewport image - m_viewportImage = new BYTE [3 * getViewportSize()[0] * getViewportSize()[1]]; + m_viewportImage = new BYTE [4 * getViewportSize()[0] * getViewportSize()[1]]; // set attributes setWhole(false); } @@ -62,7 +62,7 @@ void ImageViewport::setWhole (bool whole) m_capSize[idx] = whole ? short(getViewportSize()[idx]) : calcSize(short(getViewportSize()[idx])); // position - m_position[idx] = whole ? 0 : (getViewportSize()[idx] - m_capSize[idx]) >> 1; + m_position[idx] = whole ? 0 : ((getViewportSize()[idx] - m_capSize[idx]) >> 1); } // init image init(m_capSize[0], m_capSize[1]); @@ -123,20 +123,31 @@ void ImageViewport::calcImage (unsigned int texId) && m_capSize[1] == calcSize(m_capSize[1]) && !m_flip) { // just copy current viewport to texture - glBindTexture(GL_TEXTURE_2D, texId); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1]); - // image is not available - m_avail = false; + glBindTexture(GL_TEXTURE_2D, texId); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1]); + // image is not available + m_avail = false; } // otherwise copy viewport to buffer, if image is not available else if (!m_avail) { // get frame buffer data - glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB, - GL_UNSIGNED_BYTE, m_viewportImage); - // filter loaded data - FilterRGB24 filt; - filterImage(filt, m_viewportImage, m_capSize); + if (m_alpha) + { + glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA, + GL_UNSIGNED_BYTE, m_viewportImage); + // filter loaded data + FilterRGBA32 filt; + filterImage(filt, m_viewportImage, m_capSize); + } + else + { + glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB, + GL_UNSIGNED_BYTE, m_viewportImage); + // filter loaded data + FilterRGB24 filt; + filterImage(filt, m_viewportImage, m_capSize); + } } } @@ -151,14 +162,14 @@ inline ImageViewport * getImageViewport (PyImage * self) // get whole -static PyObject * ImageViewport_getWhole (PyImage * self, void * closure) +PyObject * ImageViewport_getWhole (PyImage * self, void * closure) { if (self->m_image != NULL && getImageViewport(self)->getWhole()) Py_RETURN_TRUE; else Py_RETURN_FALSE; } // set whole -static int ImageViewport_setWhole (PyImage * self, PyObject * value, void * closure) +int ImageViewport_setWhole (PyImage * self, PyObject * value, void * closure) { // check parameter, report failure if (value == NULL || !PyBool_Check(value)) @@ -172,6 +183,28 @@ static int ImageViewport_setWhole (PyImage * self, PyObject * value, void * clos return 0; } +// get alpha +PyObject * ImageViewport_getAlpha (PyImage * self, void * closure) +{ + if (self->m_image != NULL && getImageViewport(self)->getAlpha()) Py_RETURN_TRUE; + else Py_RETURN_FALSE; +} + +// set whole +int ImageViewport_setAlpha (PyImage * self, PyObject * value, void * closure) +{ + // check parameter, report failure + if (value == NULL || !PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return -1; + } + // set alpha + if (self->m_image != NULL) getImageViewport(self)->setAlpha(value == Py_True); + // success + return 0; +} + // get position static PyObject * ImageViewport_getPosition (PyImage * self, void * closure) @@ -202,14 +235,14 @@ static int ImageViewport_setPosition (PyImage * self, PyObject * value, void * c } // get capture size -static PyObject * ImageViewport_getCaptureSize (PyImage * self, void * closure) +PyObject * ImageViewport_getCaptureSize (PyImage * self, void * closure) { return Py_BuildValue("(ii)", getImageViewport(self)->getCaptureSize()[0], getImageViewport(self)->getCaptureSize()[1]); } // set capture size -static int ImageViewport_setCaptureSize (PyImage * self, PyObject * value, void * closure) +int ImageViewport_setCaptureSize (PyImage * self, PyObject * value, void * closure) { // check validity of parameter if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2 @@ -242,6 +275,7 @@ static PyGetSetDef imageViewportGetSets[] = {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to capture", NULL}, {(char*)"position", (getter)ImageViewport_getPosition, (setter)ImageViewport_setPosition, (char*)"upper left corner of captured area", NULL}, {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of viewport area being captured", NULL}, + {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, // attributes from ImageBase class {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, diff --git a/source/gameengine/VideoTexture/ImageViewport.h b/source/gameengine/VideoTexture/ImageViewport.h index 4265906b8f5..0449249cf95 100644 --- a/source/gameengine/VideoTexture/ImageViewport.h +++ b/source/gameengine/VideoTexture/ImageViewport.h @@ -43,6 +43,12 @@ public: bool getWhole (void) { return m_whole; } /// set whole buffer use void setWhole (bool whole); + + /// is alpha channel used + bool getAlpha (void) { return m_alpha; } + /// set whole buffer use + void setAlpha (bool alpha) { m_alpha = alpha; } + /// get capture size in viewport short * getCaptureSize (void) { return m_capSize; } /// set capture size in viewport @@ -61,6 +67,8 @@ protected: short m_capSize[2]; /// use whole viewport bool m_whole; + /// use alpha channel + bool m_alpha; /// position of capture rectangle in viewport GLint m_position[2]; @@ -79,6 +87,12 @@ protected: GLint * getViewportSize (void) { return m_viewport + 2; } }; +PyObject * ImageViewport_getCaptureSize (PyImage * self, void * closure); +int ImageViewport_setCaptureSize (PyImage * self, PyObject * value, void * closure); +PyObject * ImageViewport_getWhole (PyImage * self, void * closure); +int ImageViewport_setWhole (PyImage * self, PyObject * value, void * closure); +PyObject * ImageViewport_getAlpha (PyImage * self, void * closure); +int ImageViewport_setAlpha (PyImage * self, PyObject * value, void * closure); #endif diff --git a/source/gameengine/VideoTexture/Texture.h b/source/gameengine/VideoTexture/Texture.h index 3c371e51537..1bbef8f0f9e 100644 --- a/source/gameengine/VideoTexture/Texture.h +++ b/source/gameengine/VideoTexture/Texture.h @@ -32,6 +32,7 @@ http://www.gnu.org/copyleft/lesser.txt. #include "ImageBase.h" #include "BlendType.h" +#include "Exception.h" // type Texture declaration @@ -82,5 +83,10 @@ RAS_IPolyMaterial * getMaterial (PyObject *obj, short matID); // get material ID short getMaterialID (PyObject * obj, char * name); +// Exceptions +extern ExceptionID MaterialNotAvail; + +// object type +extern BlendType<KX_GameObject> gameObjectType; #endif diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp index b38882f8164..ec066811a52 100644 --- a/source/gameengine/VideoTexture/blendVideoTex.cpp +++ b/source/gameengine/VideoTexture/blendVideoTex.cpp @@ -132,6 +132,7 @@ extern PyTypeObject FilterBGR24Type; extern PyTypeObject ImageBuffType; extern PyTypeObject ImageMixType; extern PyTypeObject ImageRenderType; +extern PyTypeObject ImageMirrorType; extern PyTypeObject ImageViewportType; extern PyTypeObject ImageViewportType; @@ -144,7 +145,8 @@ static void registerAllTypes(void) #endif pyImageTypes.add(&ImageBuffType, "ImageBuff"); pyImageTypes.add(&ImageMixType, "ImageMix"); - //pyImageTypes.add(&ImageRenderType, "ImageRender"); + pyImageTypes.add(&ImageRenderType, "ImageRender"); + pyImageTypes.add(&ImageMirrorType, "ImageMirror"); pyImageTypes.add(&ImageViewportType, "ImageViewport"); pyFilterTypes.add(&FilterBlueScreenType, "FilterBlueScreen"); |