diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index a8f7871fa21..ba61f0c33f4 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -25,15 +25,12 @@ http://www.gnu.org/copyleft/lesser.txt. #include #include -#include -#include -#include -#include -#include -#include +#include + +#include "KX_PythonInit.h" +#include "DNA_scene_types.h" #include "ImageRender.h" - #include "ImageBase.h" #include "BlendType.h" #include "Exception.h" @@ -42,78 +39,126 @@ ExceptionID SceneInvalid, CameraInvalid; ExpDesc SceneInvalidDesc (SceneInvalid, "Scene object is invalid"); ExpDesc CameraInvalidDesc (CameraInvalid, "Camera object is invalid"); -#if 0 // not yet supported - // 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_scene(scene), + m_camera(camera) { - // 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; } // 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() { - // -} + const float ortho = 100.0; + const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); -// 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()); -} + // 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_camera->hasValidProjectionMatrix()) + { + m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix()); + } else + { + RAS_FrameFrustum frustrum; + 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); + } + + 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 +219,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 +259,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}, @@ -264,4 +318,3 @@ PyTypeObject ImageRenderType = }; -#endif // #if 0 diff --git a/source/gameengine/VideoTexture/ImageRender.h b/source/gameengine/VideoTexture/ImageRender.h index 66255f04d2c..6f22a0a6b03 100644 --- a/source/gameengine/VideoTexture/ImageRender.h +++ b/source/gameengine/VideoTexture/ImageRender.h @@ -47,9 +47,9 @@ public: 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); protected: /// rendered scene @@ -57,27 +57,22 @@ protected: /// 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; + /// 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/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp index b38882f8164..40c4caeac24 100644 --- a/source/gameengine/VideoTexture/blendVideoTex.cpp +++ b/source/gameengine/VideoTexture/blendVideoTex.cpp @@ -144,7 +144,7 @@ static void registerAllTypes(void) #endif pyImageTypes.add(&ImageBuffType, "ImageBuff"); pyImageTypes.add(&ImageMixType, "ImageMix"); - //pyImageTypes.add(&ImageRenderType, "ImageRender"); + pyImageTypes.add(&ImageRenderType, "ImageRender"); pyImageTypes.add(&ImageViewportType, "ImageViewport"); pyFilterTypes.add(&FilterBlueScreenType, "FilterBlueScreen");