|
Blender
V2.59
|
00001 00004 /* $Id: ImageRender.cpp 35176 2011-02-25 13:39:34Z jesterking $ 00005 ----------------------------------------------------------------------------- 00006 This source file is part of VideoTexture library 00007 00008 Copyright (c) 2007 The Zdeno Ash Miklas 00009 00010 This program is free software; you can redistribute it and/or modify it under 00011 the terms of the GNU Lesser General Public License as published by the Free Software 00012 Foundation; either version 2 of the License, or (at your option) any later 00013 version. 00014 00015 This program is distributed in the hope that it will be useful, but WITHOUT 00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public License along with 00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple 00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to 00022 http://www.gnu.org/copyleft/lesser.txt. 00023 ----------------------------------------------------------------------------- 00024 */ 00025 00026 // implementation 00027 00028 #include <PyObjectPlus.h> 00029 #include <structmember.h> 00030 #include <float.h> 00031 #include <math.h> 00032 00033 00034 #include "GL/glew.h" 00035 00036 #include "KX_PythonInit.h" 00037 #include "DNA_scene_types.h" 00038 #include "RAS_CameraData.h" 00039 #include "RAS_MeshObject.h" 00040 #include "BLI_math.h" 00041 00042 #include "ImageRender.h" 00043 #include "ImageBase.h" 00044 #include "BlendType.h" 00045 #include "Exception.h" 00046 #include "Texture.h" 00047 00048 ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid; 00049 ExceptionID MirrorInvalid, MirrorSizeInvalid, MirrorNormalInvalid, MirrorHorizontal, MirrorTooSmall; 00050 ExpDesc SceneInvalidDesc (SceneInvalid, "Scene object is invalid"); 00051 ExpDesc CameraInvalidDesc (CameraInvalid, "Camera object is invalid"); 00052 ExpDesc ObserverInvalidDesc (ObserverInvalid, "Observer object is invalid"); 00053 ExpDesc MirrorInvalidDesc (MirrorInvalid, "Mirror object is invalid"); 00054 ExpDesc MirrorSizeInvalidDesc (MirrorSizeInvalid, "Mirror has no vertex or no size"); 00055 ExpDesc MirrorNormalInvalidDesc (MirrorNormalInvalid, "Cannot determine mirror plane"); 00056 ExpDesc MirrorHorizontalDesc (MirrorHorizontal, "Mirror is horizontal in local space"); 00057 ExpDesc MirrorTooSmallDesc (MirrorTooSmall, "Mirror is too small"); 00058 00059 // constructor 00060 ImageRender::ImageRender (KX_Scene * scene, KX_Camera * camera) : 00061 ImageViewport(), 00062 m_render(true), 00063 m_scene(scene), 00064 m_camera(camera), 00065 m_owncamera(false), 00066 m_observer(NULL), 00067 m_mirror(NULL), 00068 m_clip(100.f) 00069 { 00070 // initialize background color 00071 setBackground(0, 0, 255, 255); 00072 // retrieve rendering objects 00073 m_engine = KX_GetActiveEngine(); 00074 m_rasterizer = m_engine->GetRasterizer(); 00075 m_canvas = m_engine->GetCanvas(); 00076 m_rendertools = m_engine->GetRenderTools(); 00077 } 00078 00079 // destructor 00080 ImageRender::~ImageRender (void) 00081 { 00082 if (m_owncamera) 00083 m_camera->Release(); 00084 } 00085 00086 00087 // set background color 00088 void ImageRender::setBackground (int red, int green, int blue, int alpha) 00089 { 00090 m_background[0] = (red < 0) ? 0.f : (red > 255) ? 1.f : float(red)/255.f; 00091 m_background[1] = (green < 0) ? 0.f : (green > 255) ? 1.f : float(green)/255.f; 00092 m_background[2] = (blue < 0) ? 0.f : (blue > 255) ? 1.f : float(blue)/255.f; 00093 m_background[3] = (alpha < 0) ? 0.f : (alpha > 255) ? 1.f : float(alpha)/255.f; 00094 } 00095 00096 00097 // capture image from viewport 00098 void ImageRender::calcImage (unsigned int texId, double ts) 00099 { 00100 if (m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture 00101 m_camera->GetViewport() || // camera must be inactive 00102 m_camera == m_scene->GetActiveCamera()) 00103 { 00104 // no need to compute texture in non texture rendering 00105 m_avail = false; 00106 return; 00107 } 00108 // render the scene from the camera 00109 Render(); 00110 // get image from viewport 00111 ImageViewport::calcImage(texId, ts); 00112 // restore OpenGL state 00113 m_canvas->EndFrame(); 00114 } 00115 00116 void ImageRender::Render() 00117 { 00118 RAS_FrameFrustum frustrum; 00119 00120 if (!m_render) 00121 return; 00122 00123 if (m_mirror) 00124 { 00125 // mirror mode, compute camera frustrum, position and orientation 00126 // convert mirror position and normal in world space 00127 const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation(); 00128 const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition(); 00129 const MT_Vector3 & mirrorObjWorldScale = m_mirror->GetSGNode()->GetWorldScaling(); 00130 MT_Point3 mirrorWorldPos = 00131 mirrorObjWorldPos + mirrorObjWorldScale * (mirrorObjWorldOri * m_mirrorPos); 00132 MT_Vector3 mirrorWorldZ = mirrorObjWorldOri * m_mirrorZ; 00133 // get observer world position 00134 const MT_Point3 & observerWorldPos = m_observer->GetSGNode()->GetWorldPosition(); 00135 // get plane D term = mirrorPos . normal 00136 MT_Scalar mirrorPlaneDTerm = mirrorWorldPos.dot(mirrorWorldZ); 00137 // compute distance of observer to mirror = D - observerPos . normal 00138 MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ); 00139 // if distance < 0.01 => observer is on wrong side of mirror, don't render 00140 if (observerDistance < 0.01f) 00141 return; 00142 // set camera world position = observerPos + normal * 2 * distance 00143 MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ; 00144 m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos); 00145 // set camera orientation: z=normal, y=mirror_up in world space, x= y x z 00146 MT_Vector3 mirrorWorldY = mirrorObjWorldOri * m_mirrorY; 00147 MT_Vector3 mirrorWorldX = mirrorObjWorldOri * m_mirrorX; 00148 MT_Matrix3x3 cameraWorldOri( 00149 mirrorWorldX[0], mirrorWorldY[0], mirrorWorldZ[0], 00150 mirrorWorldX[1], mirrorWorldY[1], mirrorWorldZ[1], 00151 mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]); 00152 m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri); 00153 m_camera->GetSGNode()->UpdateWorldData(0.0); 00154 // compute camera frustrum: 00155 // get position of mirror relative to camera: offset = mirrorPos-cameraPos 00156 MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos; 00157 // convert to camera orientation 00158 mirrorOffset = mirrorOffset * cameraWorldOri; 00159 // scale mirror size to world scale: 00160 // get closest local axis for mirror Y and X axis and scale height and width by local axis scale 00161 MT_Scalar x, y; 00162 x = fabs(m_mirrorY[0]); 00163 y = fabs(m_mirrorY[1]); 00164 float height = (x > y) ? 00165 ((x > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): 00166 ((y > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); 00167 x = fabs(m_mirrorX[0]); 00168 y = fabs(m_mirrorX[1]); 00169 float width = (x > y) ? 00170 ((x > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): 00171 ((y > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); 00172 width *= m_mirrorHalfWidth; 00173 height *= m_mirrorHalfHeight; 00174 // left = offsetx-width 00175 // right = offsetx+width 00176 // top = offsety+height 00177 // bottom = offsety-height 00178 // near = -offsetz 00179 // far = near+100 00180 frustrum.x1 = mirrorOffset[0]-width; 00181 frustrum.x2 = mirrorOffset[0]+width; 00182 frustrum.y1 = mirrorOffset[1]-height; 00183 frustrum.y2 = mirrorOffset[1]+height; 00184 frustrum.camnear = -mirrorOffset[2]; 00185 frustrum.camfar = -mirrorOffset[2]+m_clip; 00186 } 00187 // Store settings to be restored later 00188 const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); 00189 RAS_Rect area = m_canvas->GetWindowArea(); 00190 00191 // The screen area that ImageViewport will copy is also the rendering zone 00192 m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1); 00193 m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]); 00194 m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); 00195 m_rasterizer->BeginFrame(RAS_IRasterizer::KX_TEXTURED,m_engine->GetClockTime()); 00196 m_rendertools->BeginFrame(m_rasterizer); 00197 m_engine->SetWorldSettings(m_scene->GetWorldInfo()); 00198 m_rendertools->SetAuxilaryClientInfo(m_scene); 00199 m_rasterizer->DisplayFog(); 00200 // matrix calculation, don't apply any of the stereo mode 00201 m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO); 00202 if (m_mirror) 00203 { 00204 // frustrum was computed above 00205 // get frustrum matrix and set projection matrix 00206 MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( 00207 frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); 00208 00209 m_camera->SetProjectionMatrix(projmat); 00210 } else if (m_camera->hasValidProjectionMatrix()) 00211 { 00212 m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix()); 00213 } else 00214 { 00215 float lens = m_camera->GetLens(); 00216 bool orthographic = !m_camera->GetCameraData()->m_perspective; 00217 float nearfrust = m_camera->GetCameraNear(); 00218 float farfrust = m_camera->GetCameraFar(); 00219 float aspect_ratio = 1.0f; 00220 Scene *blenderScene = m_scene->GetBlenderScene(); 00221 MT_Matrix4x4 projmat; 00222 00223 // compute the aspect ratio from frame blender scene settings so that render to texture 00224 // works the same in Blender and in Blender player 00225 if (blenderScene->r.ysch != 0) 00226 aspect_ratio = float(blenderScene->r.xsch*blenderScene->r.xasp) / float(blenderScene->r.ysch*blenderScene->r.yasp); 00227 00228 if (orthographic) { 00229 00230 RAS_FramingManager::ComputeDefaultOrtho( 00231 nearfrust, 00232 farfrust, 00233 m_camera->GetScale(), 00234 aspect_ratio, 00235 frustrum 00236 ); 00237 00238 projmat = m_rasterizer->GetOrthoMatrix( 00239 frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); 00240 } else 00241 { 00242 RAS_FramingManager::ComputeDefaultFrustum( 00243 nearfrust, 00244 farfrust, 00245 lens, 00246 aspect_ratio, 00247 frustrum); 00248 00249 projmat = m_rasterizer->GetFrustumMatrix( 00250 frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); 00251 } 00252 m_camera->SetProjectionMatrix(projmat); 00253 } 00254 00255 MT_Transform camtrans(m_camera->GetWorldToCamera()); 00256 MT_Matrix4x4 viewmat(camtrans); 00257 00258 m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective); 00259 m_camera->SetModelviewMatrix(viewmat); 00260 // restore the stereo mode now that the matrix is computed 00261 m_rasterizer->SetStereoMode(stereomode); 00262 00263 m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera); 00264 00265 m_scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); 00266 00267 // restore the canvas area now that the render is completed 00268 m_canvas->GetWindowArea() = area; 00269 } 00270 00271 00272 // cast Image pointer to ImageRender 00273 inline ImageRender * getImageRender (PyImage * self) 00274 { return static_cast<ImageRender*>(self->m_image); } 00275 00276 00277 // python methods 00278 00279 // Blender Scene type 00280 BlendType<KX_Scene> sceneType ("KX_Scene"); 00281 // Blender Camera type 00282 BlendType<KX_Camera> cameraType ("KX_Camera"); 00283 00284 00285 // object initialization 00286 static int ImageRender_init (PyObject * pySelf, PyObject * args, PyObject * kwds) 00287 { 00288 // parameters - scene object 00289 PyObject * scene; 00290 // camera object 00291 PyObject * camera; 00292 // parameter keywords 00293 static const char *kwlist[] = {"sceneObj", "cameraObj", NULL}; 00294 // get parameters 00295 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", 00296 const_cast<char**>(kwlist), &scene, &camera)) 00297 return -1; 00298 try 00299 { 00300 // get scene pointer 00301 KX_Scene * scenePtr (NULL); 00302 if (scene != NULL) scenePtr = sceneType.checkType(scene); 00303 // throw exception if scene is not available 00304 if (scenePtr == NULL) THRWEXCP(SceneInvalid, S_OK); 00305 00306 // get camera pointer 00307 KX_Camera * cameraPtr (NULL); 00308 if (camera != NULL) cameraPtr = cameraType.checkType(camera); 00309 // throw exception if camera is not available 00310 if (cameraPtr == NULL) THRWEXCP(CameraInvalid, S_OK); 00311 00312 // get pointer to image structure 00313 PyImage * self = reinterpret_cast<PyImage*>(pySelf); 00314 // create source object 00315 if (self->m_image != NULL) delete self->m_image; 00316 self->m_image = new ImageRender(scenePtr, cameraPtr); 00317 } 00318 catch (Exception & exp) 00319 { 00320 exp.report(); 00321 return -1; 00322 } 00323 // initialization succeded 00324 return 0; 00325 } 00326 00327 00328 // get background color 00329 PyObject * getBackground (PyImage * self, void * closure) 00330 { 00331 return Py_BuildValue("[BBBB]", 00332 getImageRender(self)->getBackground(0), 00333 getImageRender(self)->getBackground(1), 00334 getImageRender(self)->getBackground(2), 00335 getImageRender(self)->getBackground(3)); 00336 } 00337 00338 // set color 00339 static int setBackground (PyImage * self, PyObject * value, void * closure) 00340 { 00341 // check validity of parameter 00342 if (value == NULL || !PySequence_Check(value) || PySequence_Size(value) != 4 00343 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) 00344 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1)) 00345 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 2)) 00346 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 3))) 00347 { 00348 PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 4 integer between 0 and 255"); 00349 return -1; 00350 } 00351 // set background color 00352 getImageRender(self)->setBackground((unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 0))), 00353 (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 1))), 00354 (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 2))), 00355 (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 3)))); 00356 // success 00357 return 0; 00358 } 00359 00360 00361 // methods structure 00362 static PyMethodDef imageRenderMethods[] = 00363 { // methods from ImageBase class 00364 {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"}, 00365 {NULL} 00366 }; 00367 // attributes structure 00368 static PyGetSetDef imageRenderGetSets[] = 00369 { 00370 {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL}, 00371 // attribute from ImageViewport 00372 {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL}, 00373 {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, 00374 {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL}, 00375 // attributes from ImageBase class 00376 {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, 00377 {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, 00378 {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, 00379 {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL}, 00380 {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, 00381 {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, 00382 {NULL} 00383 }; 00384 00385 00386 // define python type 00387 PyTypeObject ImageRenderType = 00388 { 00389 PyVarObject_HEAD_INIT(NULL, 0) 00390 "VideoTexture.ImageRender", /*tp_name*/ 00391 sizeof(PyImage), /*tp_basicsize*/ 00392 0, /*tp_itemsize*/ 00393 (destructor)Image_dealloc, /*tp_dealloc*/ 00394 0, /*tp_print*/ 00395 0, /*tp_getattr*/ 00396 0, /*tp_setattr*/ 00397 0, /*tp_compare*/ 00398 0, /*tp_repr*/ 00399 0, /*tp_as_number*/ 00400 0, /*tp_as_sequence*/ 00401 0, /*tp_as_mapping*/ 00402 0, /*tp_hash */ 00403 0, /*tp_call*/ 00404 0, /*tp_str*/ 00405 0, /*tp_getattro*/ 00406 0, /*tp_setattro*/ 00407 &imageBufferProcs, /*tp_as_buffer*/ 00408 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 00409 "Image source from render", /* tp_doc */ 00410 0, /* tp_traverse */ 00411 0, /* tp_clear */ 00412 0, /* tp_richcompare */ 00413 0, /* tp_weaklistoffset */ 00414 0, /* tp_iter */ 00415 0, /* tp_iternext */ 00416 imageRenderMethods, /* tp_methods */ 00417 0, /* tp_members */ 00418 imageRenderGetSets, /* tp_getset */ 00419 0, /* tp_base */ 00420 0, /* tp_dict */ 00421 0, /* tp_descr_get */ 00422 0, /* tp_descr_set */ 00423 0, /* tp_dictoffset */ 00424 (initproc)ImageRender_init, /* tp_init */ 00425 0, /* tp_alloc */ 00426 Image_allocNew, /* tp_new */ 00427 }; 00428 00429 // object initialization 00430 static int ImageMirror_init (PyObject * pySelf, PyObject * args, PyObject * kwds) 00431 { 00432 // parameters - scene object 00433 PyObject * scene; 00434 // reference object for mirror 00435 PyObject * observer; 00436 // object holding the mirror 00437 PyObject * mirror; 00438 // material of the mirror 00439 short materialID = 0; 00440 // parameter keywords 00441 static const char *kwlist[] = {"scene", "observer", "mirror", "material", NULL}; 00442 // get parameters 00443 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|h", 00444 const_cast<char**>(kwlist), &scene, &observer, &mirror, &materialID)) 00445 return -1; 00446 try 00447 { 00448 // get scene pointer 00449 KX_Scene * scenePtr (NULL); 00450 if (scene != NULL && PyObject_TypeCheck(scene, &KX_Scene::Type)) 00451 scenePtr = static_cast<KX_Scene*>BGE_PROXY_REF(scene); 00452 else 00453 THRWEXCP(SceneInvalid, S_OK); 00454 00455 if(scenePtr==NULL) /* incase the python proxy reference is invalid */ 00456 THRWEXCP(SceneInvalid, S_OK); 00457 00458 // get observer pointer 00459 KX_GameObject * observerPtr (NULL); 00460 if (observer != NULL && PyObject_TypeCheck(observer, &KX_GameObject::Type)) 00461 observerPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(observer); 00462 else if (observer != NULL && PyObject_TypeCheck(observer, &KX_Camera::Type)) 00463 observerPtr = static_cast<KX_Camera*>BGE_PROXY_REF(observer); 00464 else 00465 THRWEXCP(ObserverInvalid, S_OK); 00466 00467 if(observerPtr==NULL) /* incase the python proxy reference is invalid */ 00468 THRWEXCP(ObserverInvalid, S_OK); 00469 00470 // get mirror pointer 00471 KX_GameObject * mirrorPtr (NULL); 00472 if (mirror != NULL && PyObject_TypeCheck(mirror, &KX_GameObject::Type)) 00473 mirrorPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(mirror); 00474 else 00475 THRWEXCP(MirrorInvalid, S_OK); 00476 00477 if(mirrorPtr==NULL) /* incase the python proxy reference is invalid */ 00478 THRWEXCP(MirrorInvalid, S_OK); 00479 00480 // locate the material in the mirror 00481 RAS_IPolyMaterial * material = getMaterial(mirror, materialID); 00482 if (material == NULL) 00483 THRWEXCP(MaterialNotAvail, S_OK); 00484 00485 // get pointer to image structure 00486 PyImage * self = reinterpret_cast<PyImage*>(pySelf); 00487 00488 // create source object 00489 if (self->m_image != NULL) 00490 { 00491 delete self->m_image; 00492 self->m_image = NULL; 00493 } 00494 self->m_image = new ImageRender(scenePtr, observerPtr, mirrorPtr, material); 00495 } 00496 catch (Exception & exp) 00497 { 00498 exp.report(); 00499 return -1; 00500 } 00501 // initialization succeded 00502 return 0; 00503 } 00504 00505 // get background color 00506 PyObject * getClip (PyImage * self, void * closure) 00507 { 00508 return PyFloat_FromDouble(getImageRender(self)->getClip()); 00509 } 00510 00511 // set clip 00512 static int setClip (PyImage * self, PyObject * value, void * closure) 00513 { 00514 // check validity of parameter 00515 double clip; 00516 if (value == NULL || !PyFloat_Check(value) || (clip = PyFloat_AsDouble(value)) < 0.01 || clip > 5000.0) 00517 { 00518 PyErr_SetString(PyExc_TypeError, "The value must be an float between 0.01 and 5000"); 00519 return -1; 00520 } 00521 // set background color 00522 getImageRender(self)->setClip(float(clip)); 00523 // success 00524 return 0; 00525 } 00526 00527 // attributes structure 00528 static PyGetSetDef imageMirrorGetSets[] = 00529 { 00530 {(char*)"clip", (getter)getClip, (setter)setClip, (char*)"clipping distance", NULL}, 00531 // attribute from ImageRender 00532 {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL}, 00533 // attribute from ImageViewport 00534 {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL}, 00535 {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, 00536 {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL}, 00537 // attributes from ImageBase class 00538 {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, 00539 {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, 00540 {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, 00541 {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL}, 00542 {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, 00543 {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, 00544 {NULL} 00545 }; 00546 00547 00548 // constructor 00549 ImageRender::ImageRender (KX_Scene * scene, KX_GameObject * observer, KX_GameObject * mirror, RAS_IPolyMaterial * mat) : 00550 ImageViewport(), 00551 m_render(false), 00552 m_scene(scene), 00553 m_observer(observer), 00554 m_mirror(mirror), 00555 m_clip(100.f) 00556 { 00557 // this constructor is used for automatic planar mirror 00558 // create a camera, take all data by default, in any case we will recompute the frustrum on each frame 00559 RAS_CameraData camdata; 00560 vector<RAS_TexVert*> mirrorVerts; 00561 vector<RAS_TexVert*>::iterator it; 00562 float mirrorArea = 0.f; 00563 float mirrorNormal[3] = {0.f, 0.f, 0.f}; 00564 float mirrorUp[3]; 00565 float dist, vec[3], axis[3]; 00566 float zaxis[3] = {0.f, 0.f, 1.f}; 00567 float yaxis[3] = {0.f, 1.f, 0.f}; 00568 float mirrorMat[3][3]; 00569 float left, right, top, bottom, back; 00570 // make sure this camera will delete its node 00571 m_camera= new KX_Camera(scene, KX_Scene::m_callbacks, camdata, true, true); 00572 m_camera->SetName("__mirror__cam__"); 00573 // don't add the camera to the scene object list, it doesn't need to be accessible 00574 m_owncamera = true; 00575 // retrieve rendering objects 00576 m_engine = KX_GetActiveEngine(); 00577 m_rasterizer = m_engine->GetRasterizer(); 00578 m_canvas = m_engine->GetCanvas(); 00579 m_rendertools = m_engine->GetRenderTools(); 00580 // locate the vertex assigned to mat and do following calculation in mesh coordinates 00581 for (int meshIndex = 0; meshIndex < mirror->GetMeshCount(); meshIndex++) 00582 { 00583 RAS_MeshObject* mesh = mirror->GetMesh(meshIndex); 00584 int numPolygons = mesh->NumPolygons(); 00585 for (int polygonIndex=0; polygonIndex < numPolygons; polygonIndex++) 00586 { 00587 RAS_Polygon* polygon = mesh->GetPolygon(polygonIndex); 00588 if (polygon->GetMaterial()->GetPolyMaterial() == mat) 00589 { 00590 RAS_TexVert *v1, *v2, *v3, *v4; 00591 float normal[3]; 00592 float area; 00593 // this polygon is part of the mirror, 00594 v1 = polygon->GetVertex(0); 00595 v2 = polygon->GetVertex(1); 00596 v3 = polygon->GetVertex(2); 00597 mirrorVerts.push_back(v1); 00598 mirrorVerts.push_back(v2); 00599 mirrorVerts.push_back(v3); 00600 if (polygon->VertexCount() == 4) 00601 { 00602 v4 = polygon->GetVertex(3); 00603 mirrorVerts.push_back(v4); 00604 area = normal_quad_v3( normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), (float*)v4->getXYZ()); 00605 } else 00606 { 00607 area = normal_tri_v3( normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ()); 00608 } 00609 area = fabs(area); 00610 mirrorArea += area; 00611 mul_v3_fl(normal, area); 00612 add_v3_v3v3(mirrorNormal, mirrorNormal, normal); 00613 } 00614 } 00615 } 00616 if (mirrorVerts.size() == 0 || mirrorArea < FLT_EPSILON) 00617 { 00618 // no vertex or zero size mirror 00619 THRWEXCP(MirrorSizeInvalid, S_OK); 00620 } 00621 // compute average normal of mirror faces 00622 mul_v3_fl(mirrorNormal, 1.0f/mirrorArea); 00623 if (normalize_v3(mirrorNormal) == 0.f) 00624 { 00625 // no normal 00626 THRWEXCP(MirrorNormalInvalid, S_OK); 00627 } 00628 // the mirror plane has an equation of the type ax+by+cz = d where (a,b,c) is the normal vector 00629 // if the mirror is more vertical then horizontal, the Z axis is the up direction. 00630 // otherwise the Y axis is the up direction. 00631 // If the mirror is not perfectly vertical(horizontal), the Z(Y) axis projection on the mirror 00632 // plan by the normal will be the up direction. 00633 if (fabs(mirrorNormal[2]) > fabs(mirrorNormal[1]) && 00634 fabs(mirrorNormal[2]) > fabs(mirrorNormal[0])) 00635 { 00636 // the mirror is more horizontal than vertical 00637 copy_v3_v3(axis, yaxis); 00638 } 00639 else 00640 { 00641 // the mirror is more vertical than horizontal 00642 copy_v3_v3(axis, zaxis); 00643 } 00644 dist = dot_v3v3(mirrorNormal, axis); 00645 if (fabs(dist) < FLT_EPSILON) 00646 { 00647 // the mirror is already fully aligned with up axis 00648 copy_v3_v3(mirrorUp, axis); 00649 } 00650 else 00651 { 00652 // projection of axis to mirror plane through normal 00653 copy_v3_v3(vec, mirrorNormal); 00654 mul_v3_fl(vec, dist); 00655 sub_v3_v3v3(mirrorUp, axis, vec); 00656 if (normalize_v3(mirrorUp) == 0.f) 00657 { 00658 // should not happen 00659 THRWEXCP(MirrorHorizontal, S_OK); 00660 return; 00661 } 00662 } 00663 // compute rotation matrix between local coord and mirror coord 00664 // to match camera orientation, we select mirror z = -normal, y = up, x = y x z 00665 negate_v3_v3(mirrorMat[2], mirrorNormal); 00666 copy_v3_v3(mirrorMat[1], mirrorUp); 00667 cross_v3_v3v3(mirrorMat[0], mirrorMat[1], mirrorMat[2]); 00668 // transpose to make it a orientation matrix from local space to mirror space 00669 transpose_m3(mirrorMat); 00670 // transform all vertex to plane coordinates and determine mirror position 00671 left = FLT_MAX; 00672 right = -FLT_MAX; 00673 bottom = FLT_MAX; 00674 top = -FLT_MAX; 00675 back = -FLT_MAX; // most backward vertex (=highest Z coord in mirror space) 00676 for (it = mirrorVerts.begin(); it != mirrorVerts.end(); it++) 00677 { 00678 copy_v3_v3(vec, (float*)(*it)->getXYZ()); 00679 mul_m3_v3(mirrorMat, vec); 00680 if (vec[0] < left) 00681 left = vec[0]; 00682 if (vec[0] > right) 00683 right = vec[0]; 00684 if (vec[1] < bottom) 00685 bottom = vec[1]; 00686 if (vec[1] > top) 00687 top = vec[1]; 00688 if (vec[2] > back) 00689 back = vec[2]; 00690 } 00691 // now store this information in the object for later rendering 00692 m_mirrorHalfWidth = (right-left)*0.5f; 00693 m_mirrorHalfHeight = (top-bottom)*0.5f; 00694 if (m_mirrorHalfWidth < 0.01f || m_mirrorHalfHeight < 0.01f) 00695 { 00696 // mirror too small 00697 THRWEXCP(MirrorTooSmall, S_OK); 00698 } 00699 // mirror position in mirror coord 00700 vec[0] = (left+right)*0.5f; 00701 vec[1] = (top+bottom)*0.5f; 00702 vec[2] = back; 00703 // convert it in local space: transpose again the matrix to get back to mirror to local transform 00704 transpose_m3(mirrorMat); 00705 mul_m3_v3(mirrorMat, vec); 00706 // mirror position in local space 00707 m_mirrorPos.setValue(vec[0], vec[1], vec[2]); 00708 // mirror normal vector (pointed towards the back of the mirror) in local space 00709 m_mirrorZ.setValue(-mirrorNormal[0], -mirrorNormal[1], -mirrorNormal[2]); 00710 m_mirrorY.setValue(mirrorUp[0], mirrorUp[1], mirrorUp[2]); 00711 m_mirrorX = m_mirrorY.cross(m_mirrorZ); 00712 m_render = true; 00713 00714 setBackground(0, 0, 255, 255); 00715 } 00716 00717 00718 00719 00720 // define python type 00721 PyTypeObject ImageMirrorType = 00722 { 00723 PyVarObject_HEAD_INIT(NULL, 0) 00724 "VideoTexture.ImageMirror", /*tp_name*/ 00725 sizeof(PyImage), /*tp_basicsize*/ 00726 0, /*tp_itemsize*/ 00727 (destructor)Image_dealloc, /*tp_dealloc*/ 00728 0, /*tp_print*/ 00729 0, /*tp_getattr*/ 00730 0, /*tp_setattr*/ 00731 0, /*tp_compare*/ 00732 0, /*tp_repr*/ 00733 0, /*tp_as_number*/ 00734 0, /*tp_as_sequence*/ 00735 0, /*tp_as_mapping*/ 00736 0, /*tp_hash */ 00737 0, /*tp_call*/ 00738 0, /*tp_str*/ 00739 0, /*tp_getattro*/ 00740 0, /*tp_setattro*/ 00741 &imageBufferProcs, /*tp_as_buffer*/ 00742 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 00743 "Image source from mirror", /* tp_doc */ 00744 0, /* tp_traverse */ 00745 0, /* tp_clear */ 00746 0, /* tp_richcompare */ 00747 0, /* tp_weaklistoffset */ 00748 0, /* tp_iter */ 00749 0, /* tp_iternext */ 00750 imageRenderMethods, /* tp_methods */ 00751 0, /* tp_members */ 00752 imageMirrorGetSets, /* tp_getset */ 00753 0, /* tp_base */ 00754 0, /* tp_dict */ 00755 0, /* tp_descr_get */ 00756 0, /* tp_descr_set */ 00757 0, /* tp_dictoffset */ 00758 (initproc)ImageMirror_init, /* tp_init */ 00759 0, /* tp_alloc */ 00760 Image_allocNew, /* tp_new */ 00761 }; 00762 00763