Merging r39717 through r39983 from trunk into soc-2011-tomato

This commit is contained in:
Sergey Sharybin
2011-09-07 07:49:46 +00:00
825 changed files with 81449 additions and 32276 deletions

View File

@@ -65,29 +65,29 @@ ImageRender::ImageRender (KX_Scene * scene, KX_Camera * camera) :
m_owncamera(false),
m_observer(NULL),
m_mirror(NULL),
m_clip(100.f)
m_clip(100.f)
{
// initialize background color
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();
// 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)
{
if (m_owncamera)
m_camera->Release();
if (m_owncamera)
m_camera->Release();
}
// set background color
void ImageRender::setBackground (int red, int green, int blue, int alpha)
{
m_background[0] = (red < 0) ? 0.f : (red > 255) ? 1.f : float(red)/255.f;
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;
@@ -97,159 +97,159 @@ void ImageRender::setBackground (int red, int green, int blue, int alpha)
// capture image from viewport
void ImageRender::calcImage (unsigned int texId, double ts)
{
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();
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, ts);
// restore OpenGL state
m_canvas->EndFrame();
// restore OpenGL state
m_canvas->EndFrame();
}
void ImageRender::Render()
{
RAS_FrameFrustum frustrum;
if (!m_render)
return;
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;
}
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;
}
// Store settings to be restored later
const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode();
const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode();
RAS_Rect area = m_canvas->GetWindowArea();
// 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
// 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);
frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
m_camera->SetProjectionMatrix(projmat);
} else if (m_camera->hasValidProjectionMatrix())
} else if (m_camera->hasValidProjectionMatrix())
{
m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix());
} else
{
} else
{
float lens = m_camera->GetLens();
float sensor_x = m_camera->GetSensorWidth();
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();
float aspect_ratio = 1.0f;
Scene *blenderScene = m_scene->GetBlenderScene();
MT_Matrix4x4 projmat;
// 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*blenderScene->r.xasp) / float(blenderScene->r.ysch*blenderScene->r.yasp);
// works the same in Blender and in Blender player
if (blenderScene->r.ysch != 0)
aspect_ratio = float(blenderScene->r.xsch*blenderScene->r.xasp) / float(blenderScene->r.ysch*blenderScene->r.yasp);
if (orthographic) {
RAS_FramingManager::ComputeDefaultOrtho(
nearfrust,
farfrust,
m_camera->GetScale(),
aspect_ratio,
frustrum
);
nearfrust,
farfrust,
m_camera->GetScale(),
aspect_ratio,
frustrum
);
projmat = m_rasterizer->GetOrthoMatrix(
frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
} else
frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
} else
{
RAS_FramingManager::ComputeDefaultFrustum(
nearfrust,
farfrust,
lens,
sensor_x,
aspect_ratio,
frustrum);
nearfrust,
farfrust,
lens,
sensor_x,
aspect_ratio,
frustrum);
projmat = m_rasterizer->GetFrustumMatrix(
frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
}
m_camera->SetProjectionMatrix(projmat);
}
@@ -259,8 +259,8 @@ void ImageRender::Render()
m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective);
m_camera->SetModelviewMatrix(viewmat);
// restore the stereo mode now that the matrix is computed
m_rasterizer->SetStereoMode(stereomode);
// restore the stereo mode now that the matrix is computed
m_rasterizer->SetStereoMode(stereomode);
m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera);
@@ -330,11 +330,11 @@ static int ImageRender_init (PyObject * pySelf, PyObject * args, PyObject * kwds
// get background color
PyObject * getBackground (PyImage * self, void * closure)
{
return Py_BuildValue("[BBBB]",
getImageRender(self)->getBackground(0),
getImageRender(self)->getBackground(1),
getImageRender(self)->getBackground(2),
getImageRender(self)->getBackground(3));
return Py_BuildValue("[BBBB]",
getImageRender(self)->getBackground(0),
getImageRender(self)->getBackground(1),
getImageRender(self)->getBackground(2),
getImageRender(self)->getBackground(3));
}
// set color
@@ -435,24 +435,24 @@ static int ImageMirror_init (PyObject * pySelf, PyObject * args, PyObject * kwds
PyObject * scene;
// reference object for mirror
PyObject * observer;
// object holding the mirror
PyObject * mirror;
// material of the mirror
short materialID = 0;
// object holding the mirror
PyObject * mirror;
// material of the mirror
short materialID = 0;
// parameter keywords
static const char *kwlist[] = {"scene", "observer", "mirror", "material", NULL};
// get parameters
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|h",
const_cast<char**>(kwlist), &scene, &observer, &mirror, &materialID))
const_cast<char**>(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*>BGE_PROXY_REF(scene);
if (scene != NULL && PyObject_TypeCheck(scene, &KX_Scene::Type))
scenePtr = static_cast<KX_Scene*>BGE_PROXY_REF(scene);
else
THRWEXCP(SceneInvalid, S_OK);
THRWEXCP(SceneInvalid, S_OK);
if(scenePtr==NULL) /* incase the python proxy reference is invalid */
THRWEXCP(SceneInvalid, S_OK);
@@ -460,11 +460,11 @@ static int ImageMirror_init (PyObject * pySelf, PyObject * args, PyObject * kwds
// get observer pointer
KX_GameObject * observerPtr (NULL);
if (observer != NULL && PyObject_TypeCheck(observer, &KX_GameObject::Type))
observerPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(observer);
else if (observer != NULL && PyObject_TypeCheck(observer, &KX_Camera::Type))
observerPtr = static_cast<KX_Camera*>BGE_PROXY_REF(observer);
observerPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(observer);
else if (observer != NULL && PyObject_TypeCheck(observer, &KX_Camera::Type))
observerPtr = static_cast<KX_Camera*>BGE_PROXY_REF(observer);
else
THRWEXCP(ObserverInvalid, S_OK);
THRWEXCP(ObserverInvalid, S_OK);
if(observerPtr==NULL) /* incase the python proxy reference is invalid */
THRWEXCP(ObserverInvalid, S_OK);
@@ -472,27 +472,27 @@ static int ImageMirror_init (PyObject * pySelf, PyObject * args, PyObject * kwds
// get mirror pointer
KX_GameObject * mirrorPtr (NULL);
if (mirror != NULL && PyObject_TypeCheck(mirror, &KX_GameObject::Type))
mirrorPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(mirror);
mirrorPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(mirror);
else
THRWEXCP(MirrorInvalid, S_OK);
THRWEXCP(MirrorInvalid, S_OK);
if(mirrorPtr==NULL) /* incase the python proxy reference is invalid */
THRWEXCP(MirrorInvalid, S_OK);
// locate the material in the mirror
// locate the material in the mirror
RAS_IPolyMaterial * material = getMaterial(mirror, materialID);
if (material == NULL)
THRWEXCP(MaterialNotAvail, S_OK);
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;
}
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)
@@ -532,7 +532,7 @@ 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
// 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},
@@ -554,164 +554,164 @@ ImageRender::ImageRender (KX_Scene * scene, KX_GameObject * observer, KX_GameObj
m_scene(scene),
m_observer(observer),
m_mirror(mirror),
m_clip(100.f)
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
// 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;
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;
// make sure this camera will delete its node
m_camera= new KX_Camera(scene, KX_Scene::m_callbacks, camdata, true, true);
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 = normal_quad_v3( normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), (float*)v4->getXYZ());
} else
{
area = normal_tri_v3( normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ());
}
area = fabs(area);
mirrorArea += area;
mul_v3_fl(normal, area);
add_v3_v3v3(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
mul_v3_fl(mirrorNormal, 1.0f/mirrorArea);
if (normalize_v3(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
// 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 = normal_quad_v3( normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), (float*)v4->getXYZ());
} else
{
area = normal_tri_v3( normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ());
}
area = fabs(area);
mirrorArea += area;
mul_v3_fl(normal, area);
add_v3_v3v3(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
mul_v3_fl(mirrorNormal, 1.0f/mirrorArea);
if (normalize_v3(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]))
fabs(mirrorNormal[2]) > fabs(mirrorNormal[0]))
{
// the mirror is more horizontal than vertical
copy_v3_v3(axis, yaxis);
copy_v3_v3(axis, yaxis);
}
else
{
// the mirror is more vertical than horizontal
copy_v3_v3(axis, zaxis);
copy_v3_v3(axis, zaxis);
}
dist = dot_v3v3(mirrorNormal, axis);
if (fabs(dist) < FLT_EPSILON)
{
// the mirror is already fully aligned with up axis
copy_v3_v3(mirrorUp, axis);
}
else
{
// projection of axis to mirror plane through normal
copy_v3_v3(vec, mirrorNormal);
mul_v3_fl(vec, dist);
sub_v3_v3v3(mirrorUp, axis, vec);
if (normalize_v3(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
negate_v3_v3(mirrorMat[2], mirrorNormal);
copy_v3_v3(mirrorMat[1], mirrorUp);
cross_v3_v3v3(mirrorMat[0], mirrorMat[1], mirrorMat[2]);
// transpose to make it a orientation matrix from local space to mirror space
transpose_m3(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++)
{
copy_v3_v3(vec, (float*)(*it)->getXYZ());
mul_m3_v3(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
transpose_m3(mirrorMat);
mul_m3_v3(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;
dist = dot_v3v3(mirrorNormal, axis);
if (fabs(dist) < FLT_EPSILON)
{
// the mirror is already fully aligned with up axis
copy_v3_v3(mirrorUp, axis);
}
else
{
// projection of axis to mirror plane through normal
copy_v3_v3(vec, mirrorNormal);
mul_v3_fl(vec, dist);
sub_v3_v3v3(mirrorUp, axis, vec);
if (normalize_v3(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
negate_v3_v3(mirrorMat[2], mirrorNormal);
copy_v3_v3(mirrorMat[1], mirrorUp);
cross_v3_v3v3(mirrorMat[0], mirrorMat[1], mirrorMat[2]);
// transpose to make it a orientation matrix from local space to mirror space
transpose_m3(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++)
{
copy_v3_v3(vec, (float*)(*it)->getXYZ());
mul_m3_v3(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
transpose_m3(mirrorMat);
mul_m3_v3(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);
}