Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2008-11-13 00:16:53 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2008-11-13 00:16:53 +0300
commitbdfe7d89e2f1292644577972c716931b4ce3c6c3 (patch)
treed00eb50b749cb001e2b08272c91791e66740b05d /source/gameengine/VideoTexture
parent78a1c27c4a6abe0ed31ca93ad21910f3df04da56 (diff)
parent7e4db234cee71ead34ee81a12e27da4bd548eb4b (diff)
Merge of trunk into blender 2.5:
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r12987:17416 Issues: * GHOST/X11 had conflicting changes. Some code was added in 2.5, which was later added in trunk also, but reverted partially, specifically revision 16683. I have left out this reversion in the 2.5 branch since I think it is needed there. http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16683 * Scons had various conflicting changes, I decided to go with trunk version for everything except priorities and some library renaming. * In creator.c, there were various fixes and fixes for fixes related to the -w -W and -p options. In 2.5 -w and -W is not coded yet, and -p is done differently. Since this is changed so much, and I don't think those fixes would be needed in 2.5, I've left them out. * Also in creator.c: there was code for a python bugfix where the screen was not initialized when running with -P. The code that initializes the screen there I had to disable, that can't work in 2.5 anymore but left it commented as a reminder. Further I had to disable some new function calls. using src/ and python/, as was done already in this branch, disabled function calls: * bpath.c: error reporting * BME_conversions.c: editmesh conversion functions. * SHD_dynamic: disabled almost completely, there is no python/. * KX_PythonInit.cpp and Ketsji/ build files: Mathutils is not there, disabled. * text.c: clipboard copy call. * object.c: OB_SUPPORT_MATERIAL. * DerivedMesh.c and subsurf_ccg, stipple_quarttone. Still to be done: * Go over files and functions that were moved to a different location but could still use changes that were done in trunk.
Diffstat (limited to 'source/gameengine/VideoTexture')
-rw-r--r--source/gameengine/VideoTexture/BlendType.h75
-rw-r--r--source/gameengine/VideoTexture/CMakeLists.txt61
-rw-r--r--source/gameengine/VideoTexture/Common.h55
-rw-r--r--source/gameengine/VideoTexture/Exception.cpp209
-rw-r--r--source/gameengine/VideoTexture/Exception.h210
-rw-r--r--source/gameengine/VideoTexture/FilterBase.cpp150
-rw-r--r--source/gameengine/VideoTexture/FilterBase.h138
-rw-r--r--source/gameengine/VideoTexture/FilterBlueScreen.cpp178
-rw-r--r--source/gameengine/VideoTexture/FilterBlueScreen.h97
-rw-r--r--source/gameengine/VideoTexture/FilterColor.cpp350
-rw-r--r--source/gameengine/VideoTexture/FilterColor.h168
-rw-r--r--source/gameengine/VideoTexture/FilterNormal.cpp162
-rw-r--r--source/gameengine/VideoTexture/FilterNormal.h107
-rw-r--r--source/gameengine/VideoTexture/FilterSource.cpp171
-rw-r--r--source/gameengine/VideoTexture/FilterSource.h258
-rw-r--r--source/gameengine/VideoTexture/ImageBase.cpp529
-rw-r--r--source/gameengine/VideoTexture/ImageBase.h349
-rw-r--r--source/gameengine/VideoTexture/ImageBuff.cpp166
-rw-r--r--source/gameengine/VideoTexture/ImageBuff.h51
-rw-r--r--source/gameengine/VideoTexture/ImageMix.cpp205
-rw-r--r--source/gameengine/VideoTexture/ImageMix.h123
-rw-r--r--source/gameengine/VideoTexture/ImageRender.cpp267
-rw-r--r--source/gameengine/VideoTexture/ImageRender.h90
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.cpp297
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.h84
-rw-r--r--source/gameengine/VideoTexture/Makefile65
-rw-r--r--source/gameengine/VideoTexture/PyTypeList.cpp83
-rw-r--r--source/gameengine/VideoTexture/PyTypeList.h85
-rw-r--r--source/gameengine/VideoTexture/SConscript32
-rw-r--r--source/gameengine/VideoTexture/Texture.cpp475
-rw-r--r--source/gameengine/VideoTexture/Texture.h86
-rw-r--r--source/gameengine/VideoTexture/VideoBase.cpp195
-rw-r--r--source/gameengine/VideoTexture/VideoBase.h185
-rw-r--r--source/gameengine/VideoTexture/VideoFFmpeg.cpp927
-rw-r--r--source/gameengine/VideoTexture/VideoFFmpeg.h173
-rw-r--r--source/gameengine/VideoTexture/blendVideoTex.cpp194
36 files changed, 7050 insertions, 0 deletions
diff --git a/source/gameengine/VideoTexture/BlendType.h b/source/gameengine/VideoTexture/BlendType.h
new file mode 100644
index 00000000000..ac3ed8812a6
--- /dev/null
+++ b/source/gameengine/VideoTexture/BlendType.h
@@ -0,0 +1,75 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2006 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined BLENDTYPE_H
+#define BLENDTYPE_H
+
+
+/// class allows check type of blender python object and access its contained object
+template <class PyObj> class BlendType
+{
+public:
+ /// constructor
+ BlendType (char * name) : m_name(name) {}
+
+ /// check blender type and return pointer to contained object or NULL (if type is not valid)
+ PyObj * checkType (PyObject * obj)
+ {
+ // if pointer to type isn't set
+ if (m_objType == NULL)
+ {
+ // compare names of type
+ if (strcmp(obj->ob_type->tp_name, m_name) == 0)
+ // if name of type match, save pointer to type
+ m_objType = obj->ob_type;
+ else
+ // if names of type don't match, return NULL
+ return NULL;
+ }
+ // if pointer to type is set and don't match to type of provided object, return NULL
+ else if (obj->ob_type != m_objType)
+ return NULL;
+ // return pointer to object
+ return (PyObj*)obj;
+ }
+
+ /// parse arguments to get object
+ PyObj * parseArg (PyObject * args)
+ {
+ // parse arguments
+ PyObject * obj;
+ if (PyArg_ParseTuple(args, "O", &obj))
+ // if successfully parsed, return pointer to object
+ return checkType(obj);
+ // otherwise return NULL
+ return NULL;
+ }
+
+protected:
+ /// name of Python type
+ char * m_name;
+ /// pointer to Python type
+ PyTypeObject * m_objType;
+};
+
+
+#endif
diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt
new file mode 100644
index 00000000000..1674602edd7
--- /dev/null
+++ b/source/gameengine/VideoTexture/CMakeLists.txt
@@ -0,0 +1,61 @@
+# $Id$
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+FILE(GLOB SRC *.cpp)
+
+SET(INC
+ .
+ ../../../source/gameengine/Ketsji
+ ../../../source/gameengine/Expressions
+ ../../../source/gameengine/GameLogic
+ ../../../source/gameengine/SceneGraph
+ ../../../source/gameengine/Rasterizer
+ ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer
+ ../../../source/gameengine/BlenderRoutines
+ ../../../source/blender/include
+ ../../../source/blender/blenlib
+ ../../../source/blender/blenkernel
+ ../../../source/blender/makesdna
+ ../../../source/blender/imbuf
+ ../../../source/blender/python
+ ../../../source/blender/gpu
+ ../../../source/kernel/gen_system
+ ../../../intern/string
+ ../../../intern/moto/include
+ ../../../intern/guardedalloc
+ ../../../intern/SoundSystem
+ ../../../extern/glew/include
+ ${PYTHON_INC}
+)
+
+IF(WITH_FFMPEG)
+ SET(INC ${INC} ${FFMPEG_INC})
+ ADD_DEFINITIONS(-DWITH_FFMPEG)
+ ADD_DEFINITIONS(-D__STDC_CONSTANT_MACROS)
+ENDIF(WITH_FFMPEG)
+
+BLENDERLIB(bf_videotex "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_videotex', sources, Split(incs), [], libtype=['game','player'], priority=[25, 72], compileflags = cflags )
diff --git a/source/gameengine/VideoTexture/Common.h b/source/gameengine/VideoTexture/Common.h
new file mode 100644
index 00000000000..f771077bbba
--- /dev/null
+++ b/source/gameengine/VideoTexture/Common.h
@@ -0,0 +1,55 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2006 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if defined WIN32
+#define WINDOWS_LEAN_AND_MEAN
+#endif
+
+#if !defined NULL
+#define NULL 0
+#endif
+
+#if !defined HRESULT
+#define HRESULT long
+#endif
+
+#if !defined DWORD
+#define DWORD unsigned long
+#endif
+
+#if !defined S_OK
+#define S_OK ((HRESULT)0L)
+#endif
+
+#if !defined BYTE
+#define BYTE unsigned char
+#endif
+
+#if !defined WIN32
+#define Sleep(time) sleep(time)
+#endif
+
+#if !defined FAILED
+#define FAILED(Status) ((HRESULT)(Status)<0)
+#endif
+
+#include <iostream>
diff --git a/source/gameengine/VideoTexture/Exception.cpp b/source/gameengine/VideoTexture/Exception.cpp
new file mode 100644
index 00000000000..3f939de6bc2
--- /dev/null
+++ b/source/gameengine/VideoTexture/Exception.cpp
@@ -0,0 +1,209 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2006 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+
+#include <strstream>
+#include <fstream>
+
+#include <PyObjectPlus.h>
+
+#include "Exception.h"
+
+
+// exception identificators
+ExceptionID ErrGeneral, ErrNotFound;
+
+// exception descriptions
+ExpDesc errGenerDesc (ErrGeneral, "General Error");
+ExpDesc errNFoundDesc (ErrNotFound, "Error description not found");
+
+
+
+// implementation of ExpDesc
+
+// constructor
+ExpDesc::ExpDesc (ExceptionID & exp, char * desc, RESULT hres)
+: m_expID(exp), m_hRslt(hres), m_description(desc)
+{
+}
+
+// destructor
+ExpDesc::~ExpDesc (void) {}
+
+// list of descriptions
+std::vector<ExpDesc*> ExpDesc::m_expDescs;
+
+
+// class Exception
+
+
+// last exception description
+std::string Exception::m_lastError;
+
+// log file name
+char * Exception::m_logFile = NULL;
+
+
+// basic constructor
+Exception::Exception ()
+{
+ // default values
+ m_expID = &ErrNotFound;
+ m_hRslt = S_OK;
+ m_line = 0;
+}
+
+
+// destructor
+Exception::~Exception () throw() { }
+
+
+// copy constructor
+Exception::Exception (const Exception & xpt)
+{ copy (xpt); }
+
+
+// assignment operator
+Exception & Exception::operator= (const Exception & xpt)
+{ copy (xpt); return *this; }
+
+
+// get exception description
+const char * Exception::what()
+{
+ // set exception description
+ setXptDesc();
+ // return c string
+ return m_desc.c_str();
+}
+
+
+// debug version - with file and line of exception
+Exception::Exception (ExceptionID & expID, RESULT rslt, char * fil, int lin)
+: m_expID (&expID), m_hRslt (rslt)
+{
+ // set file and line
+ if (strlen(fil) > 0 || lin > 0)
+ setFileLine (fil, lin);
+}
+
+
+// set file and line
+void Exception::setFileLine (char * fil, int lin)
+{
+ if (fil != NULL) m_fileName = fil;
+ m_line = lin;
+}
+
+
+// report exception
+void Exception::report(void)
+{
+ // set exception description
+ setXptDesc();
+ // set python error
+ PyErr_SetString(PyExc_RuntimeError, what());
+ // if log file is set
+ if (m_logFile != NULL)
+ {
+ // write description to log
+ std::ofstream logf (m_logFile, std::ios_base::app);
+ logf << m_fileName << ':' << m_line << ':' << m_desc << std::endl;
+ logf.flush();
+ logf.close();
+ }
+}
+
+
+// set exception description
+void Exception::setXptDesc (void)
+{
+ // if description is not set
+ if (m_desc.size() == 0)
+ {
+ // start of search -1
+ // found description "NotFound" 0
+ // found description without matching result 1
+ // found description with matching result 2
+ int best = -1;
+ // find exception description
+ for (std::vector<ExpDesc*>::iterator it = ExpDesc::m_expDescs.begin(); it != ExpDesc::m_expDescs.end(); ++it)
+ {
+ // use "NotFound", if there is not better
+ if (best < 0 && (*it)->isExp(&ErrNotFound) > 0)
+ {
+ (*it)->loadDesc(m_desc);
+ best = 0;
+ }
+ // match exception
+ int nBest = (*it)->isExp(m_expID, m_hRslt);
+ // if exception is matching better
+ if (nBest > 0 && best < nBest)
+ {
+ // set description
+ (*it)->loadDesc(m_desc);
+ best = nBest;
+ // if matching exactly, finish search
+ if (best == 2) break;
+ }
+ }
+ // add result code
+ // length of result code
+ const size_t rsltSize = 11;
+ // delimit description
+ const char delimRslt[] = ": ";
+ // set text of description
+ char rsltTxt[rsltSize];
+ std::ostrstream os(rsltTxt, rsltSize);
+ os << std::hex << m_hRslt << delimRslt << '\0';
+ // copy result to description
+ m_desc.insert(0, rsltTxt);
+ // copy exception description to last exception string
+ m_lastError = m_desc;
+ }
+}
+
+
+// copy exception data
+void Exception::copy (const Exception & xpt)
+{
+ // standard data
+ m_expID = xpt.m_expID;
+ m_hRslt = xpt.m_hRslt;
+ m_desc = xpt.m_desc;
+
+ // debug data
+ m_fileName = xpt.m_fileName;
+ m_line = xpt.m_line;
+}
+
+void registerAllExceptions(void)
+{
+ errGenerDesc.registerDesc();
+ errNFoundDesc.registerDesc();
+ MaterialNotAvailDesc.registerDesc();
+ ImageSizesNotMatchDesc.registerDesc();
+ SceneInvalidDesc.registerDesc();
+ CameraInvalidDesc.registerDesc();
+ SourceVideoEmptyDesc.registerDesc();
+ SourceVideoCreationDesc.registerDesc();
+}
diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h
new file mode 100644
index 00000000000..5345e87f199
--- /dev/null
+++ b/source/gameengine/VideoTexture/Exception.h
@@ -0,0 +1,210 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2006 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+
+#if !defined EXCEPTION_H
+#define EXCEPTION_H
+
+#include <exception>
+#include <vector>
+#include <string>
+#include <algorithm>
+
+#include "Common.h"
+
+
+#define CHCKHRSLTV(fnc,val,err) \
+{ \
+ HRESULT macroHRslt = (fnc); \
+ if (macroHRslt != val) \
+ throw Exception (err, macroHRslt, __FILE__, __LINE__); \
+}
+
+#define THRWEXCP(err,hRslt) throw Exception (err, hRslt, __FILE__, __LINE__);
+
+
+#if defined WIN32
+
+#define CHCKHRSLT(fnc,err) \
+{ \
+ HRESULT macroHRslt = (fnc); \
+ if (FAILED(macroHRslt)) \
+ throw Exception (err, macroHRslt, __FILE__, __LINE__); \
+}
+
+#else
+
+#define CHCKHRSLT(fnc,err) CHCKHRSLTV(fnc,S_OK,err)
+
+#endif
+
+
+// forward declarations
+class ExceptionID;
+class Exception;
+
+
+// exception identificators
+extern ExceptionID ErrGeneral, ErrNotFound;
+
+
+// result type
+typedef long RESULT;
+
+
+// class ExceptionID for exception identification
+class ExceptionID
+{
+public:
+ // constructor a destructor
+ ExceptionID (void) {}
+ ~ExceptionID (void) {}
+
+private:
+ // not allowed
+ ExceptionID (const ExceptionID & obj) throw() {}
+ ExceptionID & operator= (const ExceptionID & obj) throw() { return *this; }
+};
+
+
+// class ExpDesc for exception description
+class ExpDesc
+{
+public:
+ // constructor a destructor
+ ExpDesc (ExceptionID & exp, char * desc, RESULT hres = S_OK);
+ ~ExpDesc (void);
+
+ // comparision function
+ // returns 0, if exception identification don't match at all
+ // returns 1, if only exception identification is matching
+ // returns 2, if both exception identification and result are matching
+ int isExp (ExceptionID * exp, RESULT hres = S_OK) throw()
+ {
+ // check exception identification
+ if (&m_expID == exp)
+ {
+ // check result value
+ if (m_hRslt == hres) return 2;
+ // only identification match
+ if (m_hRslt == S_OK) return 1;
+ }
+ // no match
+ return 0;
+ }
+
+ // get exception description
+ void loadDesc (std::string & desc) throw()
+ {
+ desc = m_description;
+ }
+
+ void registerDesc(void)
+ {
+ if (std::find(m_expDescs.begin(), m_expDescs.end(), this) == m_expDescs.end())
+ m_expDescs.push_back(this);
+ }
+ // list of exception descriptions
+ static std::vector<ExpDesc*> m_expDescs;
+
+private:
+ // exception ID
+ ExceptionID & m_expID;
+ // result
+ RESULT m_hRslt;
+ // description
+ char * m_description;
+
+ // not allowed
+ ExpDesc (const ExpDesc & obj) : m_expID (ErrNotFound) {}
+ ExpDesc & operator= (const ExpDesc & obj) { return *this; }
+};
+
+
+
+// class Exception
+class Exception : public std::exception
+{
+public:
+ // constructor
+ Exception ();
+ // destructor
+ virtual ~Exception () throw();
+ // copy constructor
+ Exception (const Exception & xpt);
+ // assignment operator
+ Exception & operator= (const Exception & xpt);
+ // get exception description
+ virtual const char * what(void);
+
+ // debug version of constructor
+ Exception (ExceptionID & expID, RESULT rslt, char * fil, int lin);
+ // set source file and line of exception
+ void setFileLine (char * fil, int lin);
+
+ // get description in string
+ std::string & getDesc (void) throw() { return m_desc; }
+
+ // report exception
+ virtual void report (void);
+
+ // get exception id
+ ExceptionID * getID (void) throw() { return m_expID; }
+
+ /// last exception description
+ static std::string m_lastError;
+
+ /// log file name
+ static char * m_logFile;
+
+protected:
+ // exception identification
+ ExceptionID * m_expID;
+ // RESULT code
+ RESULT m_hRslt;
+
+ // exception description
+ std::string m_desc;
+
+ // set exception description
+ virtual void setXptDesc (void);
+
+ // copy exception
+ void copy (const Exception & xpt);
+
+ // file name where exception was thrown
+ std::string m_fileName;
+ // line number in file
+ int m_line;
+
+};
+
+extern ExpDesc MaterialNotAvailDesc;
+extern ExpDesc ImageSizesNotMatchDesc;
+extern ExpDesc SceneInvalidDesc;
+extern ExpDesc CameraInvalidDesc;
+extern ExpDesc SourceVideoEmptyDesc;
+extern ExpDesc SourceVideoCreationDesc;
+
+
+void registerAllExceptions(void);
+#endif
diff --git a/source/gameengine/VideoTexture/FilterBase.cpp b/source/gameengine/VideoTexture/FilterBase.cpp
new file mode 100644
index 00000000000..b0112cd355b
--- /dev/null
+++ b/source/gameengine/VideoTexture/FilterBase.cpp
@@ -0,0 +1,150 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#include "FilterBase.h"
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+
+// FilterBase class implementation
+
+// constructor
+FilterBase::FilterBase (void) : m_previous(NULL) {}
+
+
+// destructor
+FilterBase::~FilterBase (void)
+{
+ // release Python objects, if not released yet
+ release();
+}
+
+
+// release python objects
+void FilterBase::release (void)
+{
+ // release previous filter object
+ setPrevious(NULL);
+}
+
+
+// set new previous filter
+void FilterBase::setPrevious (PyFilter * filt, bool useRefCnt)
+{
+ // if reference counting has to be used
+ if (useRefCnt)
+ {
+ // reference new filter
+ if (filt != NULL) Py_INCREF(filt);
+ // release old filter
+ Py_XDECREF(m_previous);
+ }
+ // set new previous filter
+ m_previous = filt;
+}
+
+
+// find first filter
+FilterBase * FilterBase::findFirst (void)
+{
+ // find first filter in chain
+ FilterBase * frst;
+ for (frst = this; frst->m_previous != NULL; frst = frst->m_previous->m_filter);
+ // set first filter
+ return frst;
+}
+
+
+
+// list offilter types
+PyTypeList pyFilterTypes;
+
+
+
+// functions for python interface
+
+
+// object allocation
+PyObject * Filter_allocNew (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+ // allocate object
+ PyFilter * self = reinterpret_cast<PyFilter*>(type->tp_alloc(type, 0));
+ // initialize object structure
+ self->m_filter = NULL;
+ // return allocated object
+ return reinterpret_cast<PyObject*>(self);
+}
+
+// object deallocation
+void Filter_dealloc (PyFilter * self)
+{
+ // release object attributes
+ if (self->m_filter != NULL)
+ {
+ self->m_filter->release();
+ delete self->m_filter;
+ self->m_filter = NULL;
+ }
+}
+
+
+// get previous pixel filter object
+PyObject * Filter_getPrevious (PyFilter * self, void * closure)
+{
+ // if filter object is available
+ if (self->m_filter != NULL)
+ {
+ // pixel filter object
+ PyObject * filt = reinterpret_cast<PyObject*>(self->m_filter->getPrevious());
+ // if filter is present
+ if (filt != NULL)
+ {
+ // return it
+ Py_INCREF(filt);
+ return filt;
+ }
+ }
+ // otherwise return none
+ Py_RETURN_NONE;
+}
+
+
+// set previous pixel filter object
+int Filter_setPrevious (PyFilter * self, PyObject * value, void * closure)
+{
+ // if filter object is available
+ if (self->m_filter != NULL)
+ {
+ // check new value
+ if (value == NULL || !pyFilterTypes.in(value->ob_type))
+ {
+ // report value error
+ PyErr_SetString(PyExc_TypeError, "Invalid type of value");
+ return -1;
+ }
+ // set new value
+ self->m_filter->setPrevious(reinterpret_cast<PyFilter*>(value));
+ }
+ // return success
+ return 0;
+}
diff --git a/source/gameengine/VideoTexture/FilterBase.h b/source/gameengine/VideoTexture/FilterBase.h
new file mode 100644
index 00000000000..b6080f018d5
--- /dev/null
+++ b/source/gameengine/VideoTexture/FilterBase.h
@@ -0,0 +1,138 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined FILTERBASE_H
+#define FILTERBASE_H
+
+#include "Common.h"
+
+#include <PyObjectPlus.h>
+
+#include "PyTypeList.h"
+
+#define VT_C(v,idx) ((unsigned char*)&v)[idx]
+#define VT_R(v) ((unsigned char*)&v)[0]
+#define VT_G(v) ((unsigned char*)&v)[1]
+#define VT_B(v) ((unsigned char*)&v)[2]
+#define VT_A(v) ((unsigned char*)&v)[3]
+#define VT_RGBA(v,r,g,b,a) VT_R(v)=(unsigned char)r, VT_G(v)=(unsigned char)g, VT_B(v)=(unsigned char)b, VT_A(v)=(unsigned char)a
+
+// forward declaration
+class FilterBase;
+
+
+// python structure for filter
+struct PyFilter
+{
+ PyObject_HEAD
+ // source object
+ FilterBase * m_filter;
+};
+
+
+/// base class for pixel filters
+class FilterBase
+{
+public:
+ /// constructor
+ FilterBase (void);
+ /// destructor
+ virtual ~FilterBase (void);
+ // release python objects
+ virtual void release (void);
+
+ /// convert pixel
+ template <class SRC> unsigned int convert (SRC src, short x, short y,
+ short * size, unsigned int pixSize)
+ {
+ return filter(src, x, y, size, pixSize,
+ convertPrevious(src, x, y, size, pixSize));
+ }
+
+ /// get previous filter
+ PyFilter * getPrevious (void) { return m_previous; }
+ /// set previous filter
+ void setPrevious (PyFilter * filt, bool useRefCnt = true);
+
+ /// find first filter in chain
+ FilterBase * findFirst (void);
+
+ /// get first filter's source pixel size
+ unsigned int firstPixelSize (void) { return findFirst()->getPixelSize(); }
+
+protected:
+ /// previous pixel filter
+ PyFilter * m_previous;
+
+ /// filter pixel, source byte buffer
+ virtual unsigned int filter (unsigned char * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return val; }
+ /// filter pixel, source int buffer
+ virtual unsigned int filter (unsigned int * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return val; }
+
+ /// get source pixel size
+ virtual unsigned int getPixelSize (void) { return 1; }
+
+ /// get converted pixel from previous filters
+ template <class SRC> unsigned int convertPrevious (SRC src, short x, short y,
+ short * size, unsigned int pixSize)
+ {
+ // if previous filter doesn't exists, return source pixel
+ if (m_previous == NULL) return *src;
+ // otherwise return converted pixel
+ return m_previous->m_filter->convert(src, x, y, size, pixSize);
+ }
+};
+
+
+// list of python filter types
+extern PyTypeList pyFilterTypes;
+
+
+// functions for python interface
+
+// object initialization
+template <class T> static int Filter_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
+{
+ PyFilter * self = reinterpret_cast<PyFilter*>(pySelf);
+ // create filter object
+ if (self->m_filter != NULL) delete self->m_filter;
+ self->m_filter = new T();
+ // initialization succeded
+ return 0;
+}
+
+// object allocation
+PyObject * Filter_allocNew (PyTypeObject * type, PyObject * args, PyObject * kwds);
+// object deallocation
+void Filter_dealloc (PyFilter * self);
+
+// get previous pixel filter object
+PyObject * Filter_getPrevious (PyFilter * self, void * closure);
+// set previous pixel filter object
+int Filter_setPrevious (PyFilter * self, PyObject * value, void * closure);
+
+
+#endif
diff --git a/source/gameengine/VideoTexture/FilterBlueScreen.cpp b/source/gameengine/VideoTexture/FilterBlueScreen.cpp
new file mode 100644
index 00000000000..43d7566102a
--- /dev/null
+++ b/source/gameengine/VideoTexture/FilterBlueScreen.cpp
@@ -0,0 +1,178 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+#include "FilterBlueScreen.h"
+
+#include "FilterBase.h"
+#include "PyTypeList.h"
+
+// implementation FilterBlueScreen
+
+// constructor
+FilterBlueScreen::FilterBlueScreen (void)
+{
+ // set color to blue
+ setColor(0, 0, 255);
+ // set limits
+ setLimits(64, 64);
+}
+
+// set color
+void FilterBlueScreen::setColor (unsigned char red, unsigned char green, unsigned char blue)
+{
+ m_color[0] = red;
+ m_color[1] = green;
+ m_color[2] = blue;
+}
+
+// set limits for color variation
+void FilterBlueScreen::setLimits (unsigned short minLimit, unsigned short maxLimit)
+{
+ m_limits[0] = minLimit;
+ m_limits[1] = maxLimit > minLimit ? maxLimit : minLimit;
+ // calculate square values
+ for (short idx = 0; idx < 2; ++idx)
+ m_squareLimits[idx] = m_limits[idx] * m_limits[idx];
+ // limits distance
+ m_limitDist = m_squareLimits[1] - m_squareLimits[0];
+}
+
+
+
+// cast Filter pointer to FilterBlueScreen
+inline FilterBlueScreen * getFilter (PyFilter * self)
+{ return static_cast<FilterBlueScreen*>(self->m_filter); }
+
+
+// python methods and get/sets
+
+// get color
+static PyObject * getColor (PyFilter * self, void * closure)
+{
+ return Py_BuildValue("[BBB]", getFilter(self)->getColor()[0],
+ getFilter(self)->getColor()[1], getFilter(self)->getColor()[2]);
+}
+
+// set color
+static int setColor (PyFilter * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 3
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 0))
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 1))
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 2)))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 3 ints");
+ return -1;
+ }
+ // set color
+ getFilter(self)->setColor((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))));
+ // success
+ return 0;
+}
+
+// get limits
+static PyObject * getLimits (PyFilter * self, void * closure)
+{
+ return Py_BuildValue("[II]", getFilter(self)->getLimits()[0],
+ getFilter(self)->getLimits()[1]);
+}
+
+// set limit
+static int setLimits (PyFilter * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 0))
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 1)))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints");
+ return -1;
+ }
+ // set limits
+ getFilter(self)->setLimits((unsigned short)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 0))),
+ (unsigned short)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 1))));
+ // success
+ return 0;
+}
+
+
+// attributes structure
+static PyGetSetDef filterBSGetSets[] =
+{
+ {(char*)"color", (getter)getColor, (setter)setColor, (char*)"blue screen color", NULL},
+ {(char*)"limits", (getter)getLimits, (setter)setLimits, (char*)"blue screen color limits", NULL},
+ // attributes from FilterBase class
+ {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL},
+ {NULL}
+};
+
+// define python type
+PyTypeObject FilterBlueScreenType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.FilterBlueScreen", /*tp_name*/
+ sizeof(PyFilter), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Filter_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*/
+ "Filter for Blue Screen objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NULL, /* tp_methods */
+ 0, /* tp_members */
+ filterBSGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Filter_init<FilterBlueScreen>, /* tp_init */
+ 0, /* tp_alloc */
+ Filter_allocNew, /* tp_new */
+};
+
diff --git a/source/gameengine/VideoTexture/FilterBlueScreen.h b/source/gameengine/VideoTexture/FilterBlueScreen.h
new file mode 100644
index 00000000000..820e4a44501
--- /dev/null
+++ b/source/gameengine/VideoTexture/FilterBlueScreen.h
@@ -0,0 +1,97 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of blendTex library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined FILTERBLUESCREEN_H
+#define FILTERBLUESCREEN_H
+
+#include "Common.h"
+
+#include "FilterBase.h"
+
+
+/// pixel filter for blue screen
+class FilterBlueScreen : public FilterBase
+{
+public:
+ /// constructor
+ FilterBlueScreen (void);
+ /// destructor
+ virtual ~FilterBlueScreen (void) {}
+
+ /// get color
+ unsigned char * getColor (void) { return m_color; }
+ /// set color
+ void setColor (unsigned char red, unsigned char green, unsigned char blue);
+
+ /// get limits for color variation
+ unsigned short * getLimits (void) { return m_limits; }
+ /// set limits for color variation
+ void setLimits (unsigned short minLimit, unsigned short maxLimit);
+
+protected:
+ /// blue screen color (red component first)
+ unsigned char m_color[3];
+ /// limits for color variation - first defines, where ends fully transparent
+ /// color, second defines, where begins fully opaque color
+ unsigned short m_limits[2];
+ /// squared limits for color variation
+ unsigned int m_squareLimits[2];
+ /// distance between squared limits
+ unsigned int m_limitDist;
+
+ /// filter pixel template, source int buffer
+ template <class SRC> unsigned int tFilter (SRC src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val)
+ {
+ // calculate differences
+ int difRed = int(VT_R(val)) - int(m_color[0]);
+ int difGreen = int(VT_G(val)) - int(m_color[1]);
+ int difBlue = int(VT_B(val)) - int(m_color[2]);
+ // calc distance from "blue screen" color
+ unsigned int dist = (unsigned int)(difRed * difRed + difGreen * difGreen
+ + difBlue * difBlue);
+ // condition for fully transparent color
+ if (m_squareLimits[0] >= dist)
+ // return color with zero alpha
+ VT_A(val) = 0;
+ // condition for fully opaque color
+ else if (m_squareLimits[1] <= dist)
+ // return normal colour
+ VT_A(val) = 0xFF;
+ // otherwise calc alpha
+ else
+ VT_A(val) = (((dist - m_squareLimits[0]) << 8) / m_limitDist);
+ return val;
+ }
+
+ /// virtual filtering function for byte source
+ virtual unsigned int filter (unsigned char * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return tFilter(src, x, y, size, pixSize, val); }
+ /// virtual filtering function for unsigned int source
+ virtual unsigned int filter (unsigned int * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return tFilter(src, x, y, size, pixSize, val); }
+};
+
+
+#endif
diff --git a/source/gameengine/VideoTexture/FilterColor.cpp b/source/gameengine/VideoTexture/FilterColor.cpp
new file mode 100644
index 00000000000..22ee729b200
--- /dev/null
+++ b/source/gameengine/VideoTexture/FilterColor.cpp
@@ -0,0 +1,350 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+#include "FilterColor.h"
+
+#include "FilterBase.h"
+#include "PyTypeList.h"
+
+// implementation FilterGray
+
+// attributes structure
+static PyGetSetDef filterGrayGetSets[] =
+{ // attributes from FilterBase class
+ {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL},
+ {NULL}
+};
+
+// define python type
+PyTypeObject FilterGrayType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.FilterGray", /*tp_name*/
+ sizeof(PyFilter), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Filter_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*/
+ "Filter for gray scale effect", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NULL, /* tp_methods */
+ 0, /* tp_members */
+ filterGrayGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Filter_init<FilterGray>, /* tp_init */
+ 0, /* tp_alloc */
+ Filter_allocNew, /* tp_new */
+};
+
+
+// implementation FilterColor
+
+// constructor
+FilterColor::FilterColor (void)
+{
+ // reset color matrix to identity
+ for (int r = 0; r < 4; ++r)
+ for (int c = 0; c < 5; ++c)
+ m_matrix[r][c] = (r == c) ? 256 : 0;
+}
+
+// set color matrix
+void FilterColor::setMatrix (ColorMatrix & mat)
+{
+ // copy matrix
+ for (int r = 0; r < 4; ++r)
+ for (int c = 0; c < 5; ++c)
+ m_matrix[r][c] = mat[r][c];
+}
+
+
+
+// cast Filter pointer to FilterColor
+inline FilterColor * getFilterColor (PyFilter * self)
+{ return static_cast<FilterColor*>(self->m_filter); }
+
+
+// python methods and get/sets
+
+// get color matrix
+static PyObject * getMatrix (PyFilter * self, void * closure)
+{
+ ColorMatrix & mat = getFilterColor(self)->getMatrix();
+ return Py_BuildValue("((hhhhh)(hhhhh)(hhhhh)(hhhhh))",
+ mat[0][0], mat[0][1], mat[0][2], mat[0][3], mat[0][4],
+ mat[1][0], mat[1][1], mat[1][2], mat[1][3], mat[1][4],
+ mat[2][0], mat[2][1], mat[2][2], mat[2][3], mat[2][4],
+ mat[3][0], mat[3][1], mat[3][2], mat[3][3], mat[3][4]);
+}
+
+// set color matrix
+static int setMatrix (PyFilter * self, PyObject * value, void * closure)
+{
+ // matrix to store items
+ ColorMatrix mat;
+ // check validity of parameter
+ bool valid = value != NULL && PySequence_Check(value)
+ && PySequence_Length(value) == 4;
+ // check rows
+ for (int r = 0; valid && r < 4; ++r)
+ {
+ // get row object
+ PyObject * row = PySequence_Fast_GET_ITEM(value, r);
+ // check sequence
+ valid = PySequence_Check(row) && PySequence_Length(row) == 5;
+ // check items
+ for (int c = 0; valid && c < 5; ++c)
+ {
+ // item must be int
+ valid = PyInt_Check(PySequence_Fast_GET_ITEM(row, c));
+ // if it is valid, save it in matrix
+ if (valid)
+ mat[r][c] = short(PyInt_AsLong(PySequence_Fast_GET_ITEM(row, c)));
+ }
+ }
+ // if parameter is not valid, report error
+ if (!valid)
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a matrix [4][5] of ints");
+ return -1;
+ }
+ // set color matrix
+ getFilterColor(self)->setMatrix(mat);
+ // success
+ return 0;
+}
+
+
+// attributes structure
+static PyGetSetDef filterColorGetSets[] =
+{
+ {(char*)"matrix", (getter)getMatrix, (setter)setMatrix, (char*)"matrix [4][5] for color calculation", NULL},
+ // attributes from FilterBase class
+ {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL},
+ {NULL}
+};
+
+// define python type
+PyTypeObject FilterColorType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.FilterColor", /*tp_name*/
+ sizeof(PyFilter), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Filter_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*/
+ "Filter for color calculations", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NULL, /* tp_methods */
+ 0, /* tp_members */
+ filterColorGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Filter_init<FilterColor>, /* tp_init */
+ 0, /* tp_alloc */
+ Filter_allocNew, /* tp_new */
+};
+
+// implementation FilterLevel
+
+// constructor
+FilterLevel::FilterLevel (void)
+{
+ // reset color levels
+ for (int r = 0; r < 4; ++r)
+ {
+ levels[r][0] = 0;
+ levels[r][1] = 0xFF;
+ levels[r][2] = 0xFF;
+ }
+}
+
+// set color levels
+void FilterLevel::setLevels (ColorLevel & lev)
+{
+ // copy levels
+ for (int r = 0; r < 4; ++r)
+ {
+ for (int c = 0; c < 2; ++c)
+ levels[r][c] = lev[r][c];
+ levels[r][2] = lev[r][0] < lev[r][1] ? lev[r][1] - lev[r][0] : 1;
+ }
+}
+
+
+// cast Filter pointer to FilterLevel
+inline FilterLevel * getFilterLevel (PyFilter * self)
+{ return static_cast<FilterLevel*>(self->m_filter); }
+
+
+// python methods and get/sets
+
+// get color levels
+static PyObject * getLevels (PyFilter * self, void * closure)
+{
+ ColorLevel & lev = getFilterLevel(self)->getLevels();
+ return Py_BuildValue("((HH)(HH)(HH)(HH))",
+ lev[0][0], lev[0][1], lev[1][0], lev[1][1],
+ lev[2][0], lev[2][1], lev[3][0], lev[3][1]);
+}
+
+// set color levels
+static int setLevels (PyFilter * self, PyObject * value, void * closure)
+{
+ // matrix to store items
+ ColorLevel lev;
+ // check validity of parameter
+ bool valid = value != NULL && PySequence_Check(value)
+ && PySequence_Length(value) == 4;
+ // check rows
+ for (int r = 0; valid && r < 4; ++r)
+ {
+ // get row object
+ PyObject * row = PySequence_Fast_GET_ITEM(value, r);
+ // check sequence
+ valid = PySequence_Check(row) && PySequence_Length(row) == 2;
+ // check items
+ for (int c = 0; valid && c < 2; ++c)
+ {
+ // item must be int
+ valid = PyInt_Check(PySequence_Fast_GET_ITEM(row, c));
+ // if it is valid, save it in matrix
+ if (valid)
+ lev[r][c] = (unsigned short)(PyInt_AsLong(PySequence_Fast_GET_ITEM(row, c)));
+ }
+ }
+ // if parameter is not valid, report error
+ if (!valid)
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a matrix [4][2] of ints");
+ return -1;
+ }
+ // set color matrix
+ getFilterLevel(self)->setLevels(lev);
+ // success
+ return 0;
+}
+
+
+// attributes structure
+static PyGetSetDef filterLevelGetSets[] =
+{
+ {(char*)"levels", (getter)getLevels, (setter)setLevels, (char*)"levels matrix [4] (min, max)", NULL},
+ // attributes from FilterBase class
+ {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL},
+ {NULL}
+};
+
+// define python type
+PyTypeObject FilterLevelType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.FilterLevel", /*tp_name*/
+ sizeof(PyFilter), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Filter_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*/
+ "Filter for levels calculations", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NULL, /* tp_methods */
+ 0, /* tp_members */
+ filterLevelGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Filter_init<FilterLevel>, /* tp_init */
+ 0, /* tp_alloc */
+ Filter_allocNew, /* tp_new */
+};
+
diff --git a/source/gameengine/VideoTexture/FilterColor.h b/source/gameengine/VideoTexture/FilterColor.h
new file mode 100644
index 00000000000..b7e52c4521c
--- /dev/null
+++ b/source/gameengine/VideoTexture/FilterColor.h
@@ -0,0 +1,168 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of blendTex library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined FILTERCOLOR_H
+#define FILTERCOLOR_H
+
+#include "Common.h"
+
+#include "FilterBase.h"
+
+
+/// pixel filter for gray scale
+class FilterGray : public FilterBase
+{
+public:
+ /// constructor
+ FilterGray (void) {}
+ /// destructor
+ virtual ~FilterGray (void) {}
+
+protected:
+ /// filter pixel template, source int buffer
+ template <class SRC> unsigned int tFilter (SRC src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val)
+ {
+ // calculate gray value
+ unsigned int gray = (28 * (VT_B(val)) + 151 * (VT_G(val))
+ + 77 * (VT_R(val))) >> 8;
+ // return gray scale value
+ VT_R(val) = gray;
+ VT_G(val) = gray;
+ VT_B(val) = gray;
+ return val;
+ }
+
+ /// virtual filtering function for byte source
+ virtual unsigned int filter (unsigned char * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return tFilter(src, x, y, size, pixSize, val); }
+ /// virtual filtering function for unsigned int source
+ virtual unsigned int filter (unsigned int * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return tFilter(src, x, y, size, pixSize, val); }
+};
+
+
+/// type for color matrix
+typedef short ColorMatrix[4][5];
+
+/// pixel filter for color calculation
+class FilterColor : public FilterBase
+{
+public:
+ /// constructor
+ FilterColor (void);
+ /// destructor
+ virtual ~FilterColor (void) {}
+
+ /// get color matrix
+ ColorMatrix & getMatrix (void) { return m_matrix; }
+ /// set color matrix
+ void setMatrix (ColorMatrix & mat);
+
+protected:
+ /// color calculation matrix
+ ColorMatrix m_matrix;
+
+ /// calculate one color component
+ unsigned char calcColor (unsigned int val, short idx)
+ {
+ return (((m_matrix[idx][0] * (VT_R(val)) + m_matrix[idx][1] * (VT_G(val))
+ + m_matrix[idx][2] * (VT_B(val)) + m_matrix[idx][3] * (VT_A(val))
+ + m_matrix[idx][4]) >> 8) & 0xFF);
+ }
+
+ /// filter pixel template, source int buffer
+ template <class SRC> unsigned int tFilter (SRC src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val)
+ {
+ // return calculated color
+ int color;
+ VT_RGBA(color, calcColor(val, 0), calcColor(val, 1), calcColor(val, 2), calcColor(val, 3));
+ return color;
+ }
+
+ /// virtual filtering function for byte source
+ virtual unsigned int filter (unsigned char * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return tFilter(src, x, y, size, pixSize, val); }
+ /// virtual filtering function for unsigned int source
+ virtual unsigned int filter (unsigned int * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return tFilter(src, x, y, size, pixSize, val); }
+};
+
+
+/// type for color levels
+typedef unsigned short ColorLevel[4][3];
+
+/// pixel filter for color calculation
+class FilterLevel : public FilterBase
+{
+public:
+ /// constructor
+ FilterLevel (void);
+ /// destructor
+ virtual ~FilterLevel (void) {}
+
+ /// get color matrix
+ ColorLevel & getLevels (void) { return levels; }
+ /// set color matrix
+ void setLevels (ColorLevel & lev);
+
+protected:
+ /// color calculation matrix
+ ColorLevel levels;
+
+ /// calculate one color component
+ unsigned int calcColor (unsigned int val, short idx)
+ {
+ unsigned int col = VT_C(val,idx);;
+ if (col <= levels[idx][0]) col = 0;
+ else if (col >= levels[idx][1]) col = 0xFF;
+ else col = (((col - levels[idx][0]) << 8) / levels[idx][2]) & 0xFF;
+ return col;
+ }
+
+ /// filter pixel template, source int buffer
+ template <class SRC> unsigned int tFilter (SRC src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val)
+ {
+ // return calculated color
+ int color;
+ VT_RGBA(color, calcColor(val, 0), calcColor(val, 1), calcColor(val, 2), calcColor(val, 3));
+ return color;
+ }
+
+ /// virtual filtering function for byte source
+ virtual unsigned int filter (unsigned char * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return tFilter(src, x, y, size, pixSize, val); }
+ /// virtual filtering function for unsigned int source
+ virtual unsigned int filter (unsigned int * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return tFilter(src, x, y, size, pixSize, val); }
+};
+
+
+#endif
diff --git a/source/gameengine/VideoTexture/FilterNormal.cpp b/source/gameengine/VideoTexture/FilterNormal.cpp
new file mode 100644
index 00000000000..03a79c1c8ce
--- /dev/null
+++ b/source/gameengine/VideoTexture/FilterNormal.cpp
@@ -0,0 +1,162 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+#include "FilterNormal.h"
+
+#include "FilterBase.h"
+#include "PyTypeList.h"
+
+// implementation FilterNormal
+
+// constructor
+FilterNormal::FilterNormal (void) : m_colIdx(0)
+{
+ // set default depth
+ setDepth(4);
+}
+
+// set color shift
+void FilterNormal::setColor (unsigned short colIdx)
+{
+ // check validity of index
+ if (colIdx < 3)
+ // set color shift
+ m_colIdx = colIdx;
+}
+
+// set depth
+void FilterNormal::setDepth (float depth)
+{
+ m_depth = depth;
+ m_depthScale = depth / depthScaleKoef;
+}
+
+
+// cast Filter pointer to FilterNormal
+inline FilterNormal * getFilter (PyFilter * self)
+{ return static_cast<FilterNormal*>(self->m_filter); }
+
+
+// python methods and get/sets
+
+// get index of color used to calculate normal
+static PyObject * getColor (PyFilter * self, void * closure)
+{
+ return Py_BuildValue("H", getFilter(self)->getColor());
+}
+
+// set index of color used to calculate normal
+static int setColor (PyFilter * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ if (value == NULL || !PyInt_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a int");
+ return -1;
+ }
+ // set color index
+ getFilter(self)->setColor((unsigned short)(PyInt_AsLong(value)));
+ // success
+ return 0;
+}
+
+
+// get depth
+static PyObject * getDepth (PyFilter * self, void * closure)
+{
+ return Py_BuildValue("f", getFilter(self)->getDepth());
+}
+
+// set depth
+static int setDepth (PyFilter * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ if (value == NULL || !PyFloat_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a float");
+ return -1;
+ }
+ // set depth
+ getFilter(self)->setDepth(float(PyFloat_AsDouble(value)));
+ // success
+ return 0;
+}
+
+
+// attributes structure
+static PyGetSetDef filterNormalGetSets[] =
+{
+ {(char*)"colorIdx", (getter)getColor, (setter)setColor, (char*)"index of color used to calculate normal (0 - red, 1 - green, 2 - blue)", NULL},
+ {(char*)"depth", (getter)getDepth, (setter)setDepth, (char*)"depth of relief", NULL},
+ // attributes from FilterBase class
+ {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL},
+ {NULL}
+};
+
+// define python type
+PyTypeObject FilterNormalType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.FilterNormal", /*tp_name*/
+ sizeof(PyFilter), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Filter_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*/
+ "Filter for Blue Screen objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NULL, /* tp_methods */
+ 0, /* tp_members */
+ filterNormalGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Filter_init<FilterNormal>, /* tp_init */
+ 0, /* tp_alloc */
+ Filter_allocNew, /* tp_new */
+};
+
diff --git a/source/gameengine/VideoTexture/FilterNormal.h b/source/gameengine/VideoTexture/FilterNormal.h
new file mode 100644
index 00000000000..840043be9a1
--- /dev/null
+++ b/source/gameengine/VideoTexture/FilterNormal.h
@@ -0,0 +1,107 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of blendTex library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined FILTERNORMAL_H
+#define FILTERNORMAL_H
+
+#include "Common.h"
+
+#include "FilterBase.h"
+
+
+// scale constants for normals
+const float depthScaleKoef = 255.0;
+const float normScaleKoef = float(depthScaleKoef / 2.0);
+
+
+/// pixel filter for normal mapping
+class FilterNormal : public FilterBase
+{
+public:
+ /// constructor
+ FilterNormal (void);
+ /// destructor
+ virtual ~FilterNormal (void) {}
+
+ /// get index of color used to calculate normals
+ unsigned short getColor (void) { return m_colIdx; }
+ /// set index of color used to calculate normals
+ void setColor (unsigned short colIdx);
+
+ /// get depth
+ float getDepth (void) { return m_depth; }
+ /// set depth
+ void setDepth (float depth);
+
+protected:
+ /// depth of normal relief
+ float m_depth;
+ /// scale to calculate normals
+ float m_depthScale;
+
+ /// color index, 0=red, 1=green, 2=blue, 3=alpha
+ unsigned short m_colIdx;
+
+ /// filter pixel, source int buffer
+ template <class SRC> unsigned int tFilter (SRC * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ {
+ // get value of required color
+ int actPix = int(VT_C(val,m_colIdx));
+ int upPix = actPix;
+ int leftPix = actPix;
+ // get upper and left pixel from actual pixel
+ if (y > 0)
+ {
+ val = convertPrevious(src - pixSize * size[0], x, y - 1, size, pixSize);
+ upPix = VT_C(val,m_colIdx);
+ }
+ if (x > 0)
+ {
+ val = convertPrevious(src - pixSize, x - 1, y, size, pixSize);
+ leftPix = VT_C(val,m_colIdx);
+ }
+ // height differences (from blue color)
+ float dx = (actPix - leftPix) * m_depthScale;
+ float dy = (actPix - upPix) * m_depthScale;
+ // normalize vector
+ float dz = float(normScaleKoef / sqrt(dx * dx + dy * dy + 1.0));
+ dx = dx * dz + normScaleKoef;
+ dy = dy * dz + normScaleKoef;
+ dz += normScaleKoef;
+ // return normal vector converted to color
+ VT_RGBA(val, dx, dy, dz, 0xFF);
+ return val;
+ }
+
+ /// filter pixel, source byte buffer
+ virtual unsigned int filter (unsigned char * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return tFilter(src, x, y, size, pixSize, val); }
+ /// filter pixel, source int buffer
+ virtual unsigned int filter (unsigned int * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ { return tFilter(src, x, y, size, pixSize, val); }
+};
+
+
+#endif
diff --git a/source/gameengine/VideoTexture/FilterSource.cpp b/source/gameengine/VideoTexture/FilterSource.cpp
new file mode 100644
index 00000000000..f3676e93a6d
--- /dev/null
+++ b/source/gameengine/VideoTexture/FilterSource.cpp
@@ -0,0 +1,171 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+// implementation
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+#include "FilterSource.h"
+
+#include "FilterBase.h"
+#include "PyTypeList.h"
+
+
+// FilterRGB24
+
+// define python type
+PyTypeObject FilterRGB24Type =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.FilterRGB24", /*tp_name*/
+ sizeof(PyFilter), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Filter_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*/
+ "Source filter RGB24 objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NULL, /* tp_methods */
+ 0, /* tp_members */
+ NULL, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Filter_init<FilterRGB24>, /* tp_init */
+ 0, /* tp_alloc */
+ Filter_allocNew, /* tp_new */
+};
+
+// FilterRGBA32
+
+// define python type
+PyTypeObject FilterRGBA32Type =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.FilterRGBA32", /*tp_name*/
+ sizeof(PyFilter), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Filter_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*/
+ "Source filter RGBA32 objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NULL, /* tp_methods */
+ 0, /* tp_members */
+ NULL, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Filter_init<FilterRGBA32>, /* tp_init */
+ 0, /* tp_alloc */
+ Filter_allocNew, /* tp_new */
+};
+
+// FilterBGR24
+
+// define python type
+PyTypeObject FilterBGR24Type =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.FilterBGR24", /*tp_name*/
+ sizeof(PyFilter), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Filter_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*/
+ "Source filter BGR24 objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ NULL, /* tp_methods */
+ 0, /* tp_members */
+ NULL, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Filter_init<FilterBGR24>, /* tp_init */
+ 0, /* tp_alloc */
+ Filter_allocNew, /* tp_new */
+};
+
diff --git a/source/gameengine/VideoTexture/FilterSource.h b/source/gameengine/VideoTexture/FilterSource.h
new file mode 100644
index 00000000000..7e90747d252
--- /dev/null
+++ b/source/gameengine/VideoTexture/FilterSource.h
@@ -0,0 +1,258 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of blendTex library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined FILTERSOURCE_H
+#define FILTERSOURCE_H
+
+#include "Common.h"
+
+#include "FilterBase.h"
+
+
+/// class for RGB24 conversion
+class FilterRGB24 : public FilterBase
+{
+public:
+ /// constructor
+ FilterRGB24 (void) {}
+ /// destructor
+ virtual ~FilterRGB24 (void) {}
+
+ /// get source pixel size
+ virtual unsigned int getPixelSize (void) { return 3; }
+
+protected:
+ /// filter pixel, source byte buffer
+ virtual unsigned int filter (unsigned char * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val)
+ { VT_RGBA(val,src[0],src[1],src[2],0xFF); return val; }
+};
+
+/// class for RGBA32 conversion
+class FilterRGBA32 : public FilterBase
+{
+public:
+ /// constructor
+ FilterRGBA32 (void) {}
+ /// destructor
+ virtual ~FilterRGBA32 (void) {}
+
+ /// get source pixel size
+ virtual unsigned int getPixelSize (void) { return 4; }
+
+protected:
+ /// filter pixel, source byte buffer
+ virtual unsigned int filter (unsigned char * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val)
+ {
+ if ((intptr_t(src)&0x3) == 0)
+ return *(unsigned int*)src;
+ else
+ {
+ VT_RGBA(val,src[0],src[1],src[2],src[3]);
+ return val;
+ }
+ }
+};
+
+/// class for BGR24 conversion
+class FilterBGR24 : public FilterBase
+{
+public:
+ /// constructor
+ FilterBGR24 (void) {}
+ /// destructor
+ virtual ~FilterBGR24 (void) {}
+
+ /// get source pixel size
+ virtual unsigned int getPixelSize (void) { return 3; }
+
+protected:
+ /// filter pixel, source byte buffer
+ virtual unsigned int filter (unsigned char * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val)
+ { VT_RGBA(val,src[2],src[1],src[0],0xFF); return val; }
+};
+
+/// class for YV12 conversion
+class FilterYV12 : public FilterBase
+{
+public:
+ /// constructor
+ FilterYV12 (void) {}
+ /// destructor
+ virtual ~FilterYV12 (void) {}
+
+ /// get source pixel size
+ virtual unsigned int getPixelSize (void) { return 1; }
+
+ /// set pointers to color buffers
+ void setBuffs (unsigned char * buff, short * size)
+ {
+ unsigned int buffSize = size[0] * size[1];
+ m_buffV = buff + buffSize;
+ m_buffU = m_buffV + (buffSize >> 2);
+ m_pitchUV = size[0] >> 1;
+ }
+
+protected:
+ /// begin of V buffer
+ unsigned char * m_buffV;
+ /// begin of U buffer
+ unsigned char * m_buffU;
+ /// pitch for V & U buffers
+ short m_pitchUV;
+
+ /// interpolation function
+ int interpol (int a, int b, int c, int d)
+ { return (9 * (b + c) - a - d + 8) >> 4; }
+
+ /// common horizontal interpolation
+ int interpolH (unsigned char * src)
+ { return interpol(*(src-1), *src, *(src+1), *(src+2)); }
+
+ /// common vertical interpolation
+ int interpolV (unsigned char * src)
+ { return interpol(*(src-m_pitchUV), *src, *(src+m_pitchUV), *(src+2*m_pitchUV)); }
+
+ /// common joined vertical and horizontal interpolation
+ int interpolVH (unsigned char * src)
+ {
+ return interpol(interpolV(src-1), interpolV(src), interpolV(src+1),
+ interpolV(src+2));
+ }
+
+ /// is pixel on edge
+ bool isEdge (short x, short y, short * size)
+ { return x <= 1 || x >= size[0] - 4 || y <= 1 || y >= size[1] - 4; }
+
+ /// get the first parameter on the low edge
+ unsigned char * interParA (unsigned char * src, short x, short size, short shift)
+ { return x > 1 ? src - shift : src; }
+ /// get the third parameter on the high edge
+ unsigned char * interParC (unsigned char * src, short x, short size, short shift)
+ { return x < size - 2 ? src + shift : src; }
+ /// get the fourth parameter on the high edge
+ unsigned char * interParD (unsigned char * src, short x, short size, short shift)
+ { return x < size - 4 ? src + 2 * shift : x < size - 2 ? src + shift : src; }
+
+ /// horizontal interpolation on edges
+ int interpolEH (unsigned char * src, short x, short size)
+ {
+ return interpol(*interParA(src, x, size, 1), *src,
+ *interParC(src, x, size, 1), *interParD(src, x, size, 1));
+ }
+
+ /// vertical interpolation on edges
+ int interpolEV (unsigned char * src, short y, short size)
+ {
+ return interpol(*interParA(src, y, size, m_pitchUV), *src,
+ *interParC(src, y, size, m_pitchUV), *interParD(src, y, size, m_pitchUV));
+ }
+
+ /// joined vertical and horizontal interpolation on edges
+ int interpolEVH (unsigned char * src, short x, short y, short * size)
+ {
+ return interpol(interpolEV(interParA(src, x, size[0], 1), y, size[1]),
+ interpolEV(src, y, size[1]), interpolEV(interParC(src, x, size[0], 1), y, size[1]),
+ interpolEV(interParD(src, x, size[0], 1), y, size[1]));
+ }
+
+
+ /// filter pixel, source byte buffer
+ virtual unsigned int filter (unsigned char * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val)
+ {
+ // V & U offset
+ long offset = (x >> 1) + m_pitchUV * (y >> 1);
+ // get modified YUV -> CDE: C = Y - 16; D = U - 128; E = V - 128
+ int c = *src - 16;
+ int d = m_buffU[offset] - 128;
+ int e = m_buffV[offset] - 128;
+ // if horizontal interpolation is needed
+ if ((x & 1) == 1)
+ // if vertical interpolation is needed too
+ if ((y & 1) == 1)
+ // if this pixel is on the edge
+ if (isEdge(x, y, size))
+ {
+ // get U & V from edge
+ d = interpolEVH(m_buffU + offset, x, y, size) - 128;
+ e = interpolEVH(m_buffV + offset, x, y, size) - 128;
+ }
+ // otherwise get U & V from inner range
+ else
+ {
+ d = interpolVH(m_buffU + offset) - 128;
+ e = interpolVH(m_buffV + offset) - 128;
+ }
+ // otherwise use horizontal interpolation only
+ else
+ // if this pixel is on the edge
+ if (isEdge(x, y, size))
+ {
+ // get U & V from edge
+ d = interpolEH(m_buffU + offset, x, size[0]) - 128;
+ e = interpolEH(m_buffV + offset, x, size[0]) - 128;
+ }
+ // otherwise get U & V from inner range
+ else
+ {
+ d = interpolH(m_buffU + offset) - 128;
+ e = interpolH(m_buffV + offset) - 128;
+ }
+ // otherwise if only vertical interpolation is needed
+ else if ((y & 1) == 1)
+ // if this pixel is on the edge
+ if (isEdge(x, y, size))
+ {
+ // get U & V from edge
+ d = interpolEV(m_buffU + offset, y, size[1]) - 128;
+ e = interpolEV(m_buffV + offset, y, size[1]) - 128;
+ }
+ // otherwise get U & V from inner range
+ else
+ {
+ d = interpolV(m_buffU + offset) - 128;
+ e = interpolV(m_buffV + offset) - 128;
+ }
+ // convert to RGB
+ // R = clip(( 298 * C + 409 * E + 128) >> 8)
+ // G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
+ // B = clip(( 298 * C + 516 * D + 128) >> 8)
+ int red = (298 * c + 409 * e + 128) >> 8;
+ if (red >= 0x100) red = 0xFF;
+ else if (red < 0) red = 0;
+ int green = (298 * c - 100 * d - 208 * e) >> 8;
+ if (green >= 0x100) green = 0xFF;
+ else if (green < 0) green = 0;
+ int blue = (298 * c + 516 * d + 128) >> 8;
+ if (blue >= 0x100) blue = 0xFF;
+ else if (blue < 0) blue = 0;
+ // return result
+ VT_RGBA(val, red, green, blue, 0xFF);
+ return val;
+ }
+};
+
+
+#endif
diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp
new file mode 100644
index 00000000000..dcca20de24a
--- /dev/null
+++ b/source/gameengine/VideoTexture/ImageBase.cpp
@@ -0,0 +1,529 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#include "ImageBase.h"
+
+#include <vector>
+#include <string.h>
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+#include "FilterBase.h"
+
+#include "Exception.h"
+
+
+
+// ImageBase class implementation
+
+// constructor
+ImageBase::ImageBase (bool staticSrc) : m_image(NULL), m_imgSize(0),
+m_avail(false), m_scale(false), m_scaleChange(false), m_flip(false),
+m_staticSources(staticSrc), m_pyfilter(NULL)
+{
+ m_size[0] = m_size[1] = 0;
+}
+
+
+// destructor
+ImageBase::~ImageBase (void)
+{
+ // release image
+ delete [] m_image;
+}
+
+
+// release python objects
+bool ImageBase::release (void)
+{
+ // iterate sources
+ for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it)
+ {
+ // release source object
+ delete *it;
+ *it = NULL;
+ }
+ // release filter object
+ Py_XDECREF(m_pyfilter);
+ m_pyfilter = NULL;
+ return true;
+}
+
+
+// get image
+unsigned int * ImageBase::getImage (unsigned int texId)
+{
+ // if image is not available
+ if (!m_avail)
+ {
+ // if there are any sources
+ if (!m_sources.empty())
+ {
+ // get images from sources
+ for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it)
+ // get source image
+ (*it)->getImage();
+ // init image
+ init(m_sources[0]->getSize()[0], m_sources[0]->getSize()[1]);
+ }
+ // calculate new image
+ calcImage(texId);
+ }
+ // if image is available, return it, otherwise NULL
+ return m_avail ? m_image : NULL;
+}
+
+
+// refresh image source
+void ImageBase::refresh (void)
+{
+ // invalidate this image
+ m_avail = false;
+ // refresh all sources
+ for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it)
+ (*it)->refresh();
+}
+
+
+// get source object
+PyImage * ImageBase::getSource (const char * id)
+{
+ // find source
+ ImageSourceList::iterator src = findSource(id);
+ // return it, if found
+ return src != m_sources.end() ? (*src)->getSource() : NULL;
+}
+
+
+// set source object
+bool ImageBase::setSource (const char * id, PyImage * source)
+{
+ // find source
+ ImageSourceList::iterator src = findSource(id);
+ // check source loop
+ if (source != NULL && source->m_image->loopDetect(this))
+ return false;
+ // if found, set new object
+ if (src != m_sources.end())
+ // if new object is not empty or sources are static
+ if (source != NULL || m_staticSources)
+ // replace previous source
+ (*src)->setSource(source);
+ // otherwise delete source
+ else
+ m_sources.erase(src);
+ // if source is not found and adding is allowed
+ else
+ if (!m_staticSources)
+ {
+ // create new source
+ ImageSource * newSrc = newSource(id);
+ newSrc->setSource(source);
+ // if source was created, add it to source list
+ if (newSrc != NULL) m_sources.push_back(newSrc);
+ }
+ // otherwise source wasn't set
+ else
+ return false;
+ // source was set
+ return true;
+}
+
+
+// set pixel filter
+void ImageBase::setFilter (PyFilter * filt)
+{
+ // reference new filter
+ if (filt != NULL) Py_INCREF(filt);
+ // release previous filter
+ Py_XDECREF(m_pyfilter);
+ // set new filter
+ m_pyfilter = filt;
+}
+
+
+// initialize image data
+void ImageBase::init (short width, short height)
+{
+ // if image has to be scaled
+ if (m_scale)
+ {
+ // recalc sizes of image
+ width = calcSize(width);
+ height = calcSize(height);
+ }
+ // if sizes differ
+ if (width != m_size[0] || height != m_size[1])
+ {
+ // new buffer size
+ unsigned int newSize = width * height;
+ // if new buffer is larger than previous
+ if (newSize > m_imgSize)
+ {
+ // set new buffer size
+ m_imgSize = newSize;
+ // release previous and create new buffer
+ delete [] m_image;
+ m_image = new unsigned int[m_imgSize];
+ }
+ // new image size
+ m_size[0] = width;
+ m_size[1] = height;
+ // scale was processed
+ m_scaleChange = false;
+ }
+}
+
+
+// find source
+ImageSourceList::iterator ImageBase::findSource (const char * id)
+{
+ // iterate sources
+ ImageSourceList::iterator it;
+ for (it = m_sources.begin(); it != m_sources.end(); ++it)
+ // if id matches, return iterator
+ if ((*it)->is(id)) return it;
+ // source not found
+ return it;
+}
+
+
+// check sources sizes
+bool ImageBase::checkSourceSizes (void)
+{
+ // reference size
+ short * refSize = NULL;
+ // iterate sources
+ for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it)
+ {
+ // get size of current source
+ short * curSize = (*it)->getSize();
+ // if size is available and is not empty
+ if (curSize[0] != 0 && curSize[1] != 0)
+ // if reference size is not set
+ if (refSize == NULL)
+ // set current size as reference
+ refSize = curSize;
+ // otherwise check with current size
+ else if (curSize[0] != refSize[0] || curSize[1] != refSize[1])
+ // if they don't match, report it
+ return false;
+ }
+ // all sizes match
+ return true;
+}
+
+
+// compute nearest power of 2 value
+short ImageBase::calcSize (short size)
+{
+ // while there is more than 1 bit in size value
+ while ((size & (size - 1)) != 0)
+ // clear last bit
+ size = size & (size - 1);
+ // return result
+ return size;
+}
+
+
+// perform loop detection
+bool ImageBase::loopDetect (ImageBase * img)
+{
+ // if this object is the same as parameter, loop is detected
+ if (this == img) return true;
+ // check all sources
+ for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it)
+ // if source detected loop, return this result
+ if ((*it)->getSource() != NULL && (*it)->getSource()->m_image->loopDetect(img))
+ return true;
+ // no loop detected
+ return false;
+}
+
+
+// ImageSource class implementation
+
+// constructor
+ImageSource::ImageSource (const char * id) : m_source(NULL), m_image(NULL)
+{
+ // copy id
+ int idx;
+ for (idx = 0; id[idx] != '\0' && idx < SourceIdSize - 1; ++idx)
+ m_id[idx] = id[idx];
+ m_id[idx] = '\0';
+}
+
+// destructor
+ImageSource::~ImageSource (void)
+{
+ // release source
+ setSource(NULL);
+}
+
+
+// compare id
+bool ImageSource::is (const char * id)
+{
+ for (char * myId = m_id; *myId != '\0'; ++myId, ++id)
+ if (*myId != *id) return false;
+ return *id == '\0';
+}
+
+
+// set source object
+void ImageSource::setSource (PyImage * source)
+{
+ // reference new source
+ if (source != NULL) Py_INCREF(source);
+ // release previous source
+ Py_XDECREF(m_source);
+ // set new source
+ m_source = source;
+}
+
+
+// get image from source
+unsigned int * ImageSource::getImage (void)
+{
+ // if source is available
+ if (m_source != NULL)
+ // get image from source
+ m_image = m_source->m_image->getImage();
+ // otherwise reset buffer
+ else
+ m_image = NULL;
+ // return image
+ return m_image;
+}
+
+
+// refresh source
+void ImageSource::refresh (void)
+{
+ // if source is available, refresh it
+ if (m_source != NULL) m_source->m_image->refresh();
+}
+
+
+
+// list of image types
+PyTypeList pyImageTypes;
+
+
+
+// functions for python interface
+
+// object allocation
+PyObject * Image_allocNew (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+ // allocate object
+ PyImage * self = reinterpret_cast<PyImage*>(type->tp_alloc(type, 0));
+ // initialize object structure
+ self->m_image = NULL;
+ // return allocated object
+ return reinterpret_cast<PyObject*>(self);
+}
+
+// object deallocation
+void Image_dealloc (PyImage * self)
+{
+ // release object attributes
+ if (self->m_image != NULL)
+ {
+ // if release requires deleting of object, do it
+ if (self->m_image->release())
+ delete self->m_image;
+ self->m_image = NULL;
+ }
+}
+
+// get image data
+PyObject * Image_getImage (PyImage * self, void * closure)
+{
+ try
+ {
+ // get image
+ unsigned int * image = self->m_image->getImage();
+ return Py_BuildValue("s#", image, self->m_image->getBuffSize());
+ }
+ catch (Exception & exp)
+ {
+ exp.report();
+ }
+ Py_RETURN_NONE;
+}
+
+// get image size
+PyObject * Image_getSize (PyImage * self, void * closure)
+{
+ return Py_BuildValue("(hh)", self->m_image->getSize()[0],
+ self->m_image->getSize()[1]);
+}
+
+// refresh image
+PyObject * Image_refresh (PyImage * self)
+{
+ self->m_image->refresh();
+ Py_RETURN_NONE;
+}
+
+// get scale
+PyObject * Image_getScale (PyImage * self, void * closure)
+{
+ if (self->m_image != NULL && self->m_image->getScale()) Py_RETURN_TRUE;
+ else Py_RETURN_FALSE;
+}
+
+// set scale
+int Image_setScale (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 scale
+ if (self->m_image != NULL) self->m_image->setScale(value == Py_True);
+ // success
+ return 0;
+}
+
+// get flip
+PyObject * Image_getFlip (PyImage * self, void * closure)
+{
+ if (self->m_image != NULL && self->m_image->getFlip()) Py_RETURN_TRUE;
+ else Py_RETURN_FALSE;
+}
+
+// set flip
+int Image_setFlip (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 scale
+ if (self->m_image != NULL) self->m_image->setFlip(value == Py_True);
+ // success
+ return 0;
+}
+
+
+// get filter source object
+PyObject * Image_getSource (PyImage * self, PyObject * args)
+{
+ // get arguments
+ char * id;
+ if (self->m_image != NULL && PyArg_ParseTuple(args, "s", &id))
+ {
+ // get source object
+ PyObject * src = reinterpret_cast<PyObject*>(self->m_image->getSource(id));
+ // if source is available
+ if (src != NULL)
+ {
+ // return source
+ Py_INCREF(src);
+ return src;
+ }
+ }
+ // source was not found
+ Py_RETURN_NONE;
+}
+
+
+// set filter source object
+PyObject * Image_setSource (PyImage * self, PyObject * args)
+{
+ // get arguments
+ char * id;
+ PyObject * obj;
+ if (self->m_image != NULL && PyArg_ParseTuple(args, "sO", &id, &obj))
+ {
+ // check type of object
+ if (pyImageTypes.in(obj->ob_type))
+ {
+ // convert to image struct
+ PyImage * img = reinterpret_cast<PyImage*>(obj);
+ // set source
+ if (!self->m_image->setSource(id, img))
+ {
+ // if not set, retport error
+ PyErr_SetString(PyExc_RuntimeError, "Invalid source or id");
+ return NULL;
+ }
+ }
+ // else report error
+ else
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Invalid type of object");
+ return NULL;
+ }
+ }
+ // return none
+ Py_RETURN_NONE;
+}
+
+
+// get pixel filter object
+PyObject * Image_getFilter (PyImage * self, void * closure)
+{
+ // if image object is available
+ if (self->m_image != NULL)
+ {
+ // pixel filter object
+ PyObject * filt = reinterpret_cast<PyObject*>(self->m_image->getFilter());
+ // if filter is present
+ if (filt != NULL)
+ {
+ // return it
+ Py_INCREF(filt);
+ return filt;
+ }
+ }
+ // otherwise return none
+ Py_RETURN_NONE;
+}
+
+
+// set pixel filter object
+int Image_setFilter (PyImage * self, PyObject * value, void * closure)
+{
+ // if image object is available
+ if (self->m_image != NULL)
+ {
+ // check new value
+ if (value == NULL || !pyFilterTypes.in(value->ob_type))
+ {
+ // report value error
+ PyErr_SetString(PyExc_TypeError, "Invalid type of value");
+ return -1;
+ }
+ // set new value
+ self->m_image->setFilter(reinterpret_cast<PyFilter*>(value));
+ }
+ // return success
+ return 0;
+}
diff --git a/source/gameengine/VideoTexture/ImageBase.h b/source/gameengine/VideoTexture/ImageBase.h
new file mode 100644
index 00000000000..138580ce701
--- /dev/null
+++ b/source/gameengine/VideoTexture/ImageBase.h
@@ -0,0 +1,349 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of blendTex library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined IMAGEBASE_H
+#define IMAGEBASE_H
+
+#include "Common.h"
+
+#include <vector>
+#include <PyObjectPlus.h>
+
+#include "PyTypeList.h"
+
+#include "FilterBase.h"
+
+
+// forward declarations
+struct PyImage;
+class ImageSource;
+
+
+/// type for list of image sources
+typedef std::vector<ImageSource*> ImageSourceList;
+
+
+/// base class for image filters
+class ImageBase
+{
+public:
+ /// constructor
+ ImageBase (bool staticSrc = false);
+ /// destructor
+ virtual ~ImageBase (void);
+ /// release contained objects, if returns true, object should be deleted
+ virtual bool release (void);
+
+ /// get image
+ unsigned int * getImage (unsigned int texId = 0);
+ /// get image size
+ short * getSize (void) { return m_size; }
+ /// get image buffer size
+ unsigned long getBuffSize (void)
+ { return m_size[0] * m_size[1] * sizeof(unsigned int); }
+ /// refresh image - invalidate its current content
+ virtual void refresh (void);
+
+ /// get scale
+ bool getScale (void) { return m_scale; }
+ /// set scale
+ void setScale (bool scale) { m_scale = scale; m_scaleChange = true; }
+ /// get vertical flip
+ bool getFlip (void) { return m_flip; }
+ /// set vertical flip
+ void setFlip (bool flip) { m_flip = flip; }
+
+ /// get source object
+ PyImage * getSource (const char * id);
+ /// set source object, return true, if source was set
+ bool setSource (const char * id, PyImage * source);
+
+ /// get pixel filter
+ PyFilter * getFilter (void) { return m_pyfilter; }
+ /// set pixel filter
+ void setFilter (PyFilter * filt);
+
+ /// calculate size (nearest power of 2)
+ static short calcSize (short size);
+
+protected:
+ /// image buffer
+ unsigned int * m_image;
+ /// image buffer size
+ unsigned int m_imgSize;
+ /// image size
+ short m_size[2];
+ /// image is available
+ bool m_avail;
+
+ /// scale image to power 2 sizes
+ bool m_scale;
+ /// scale was changed
+ bool m_scaleChange;
+ /// flip image vertically
+ bool m_flip;
+
+ /// source image list
+ ImageSourceList m_sources;
+ /// flag for disabling addition and deletion of sources
+ bool m_staticSources;
+
+ /// pixel filter
+ PyFilter * m_pyfilter;
+
+ /// initialize image data
+ void init (short width, short height);
+
+ /// find source
+ ImageSourceList::iterator findSource (const char * id);
+
+ /// create new source
+ virtual ImageSource * newSource (const char * id) { return NULL; }
+
+ /// check source sizes
+ bool checkSourceSizes (void);
+
+ /// calculate image from sources and set its availability
+ virtual void calcImage (unsigned int texId) {}
+
+ /// perform loop detection
+ bool loopDetect (ImageBase * img);
+
+ /// template for image conversion
+ template<class FLT, class SRC> void convImage (FLT & filter, SRC srcBuff,
+ short * srcSize)
+ {
+ // destination buffer
+ unsigned int * dstBuff = m_image;
+ // pixel size from filter
+ unsigned int pixSize = filter.firstPixelSize();
+ // if no scaling is needed
+ if (srcSize[0] == m_size[0] && srcSize[1] == m_size[1])
+ // if flipping isn't required
+ if (!m_flip)
+ // copy bitmap
+ for (short y = 0; y < m_size[1]; ++y)
+ for (short x = 0; x < m_size[0]; ++x, ++dstBuff, srcBuff += pixSize)
+ // copy pixel
+ *dstBuff = filter.convert(srcBuff, x, y, srcSize, pixSize);
+ // otherwise flip image top to bottom
+ else
+ {
+ // go to last row of image
+ srcBuff += srcSize[0] * (srcSize[1] - 1) * pixSize;
+ // copy bitmap
+ for (short y = m_size[1] - 1; y >= 0; --y, srcBuff -= 2 * srcSize[0] * pixSize)
+ for (short x = 0; x < m_size[0]; ++x, ++dstBuff, srcBuff += pixSize)
+ // copy pixel
+ *dstBuff = filter.convert(srcBuff, x, y, srcSize, pixSize);
+ }
+ // else scale picture (nearest neighbour)
+ else
+ {
+ // interpolation accumulator
+ int accHeight = srcSize[1] >> 1;
+ // if flipping is required
+ if (m_flip)
+ // go to last row of image
+ srcBuff += srcSize[0] * (srcSize[1] - 1) * pixSize;
+ // process image rows
+ for (int y = 0; y < srcSize[1]; ++y)
+ {
+ // increase height accum
+ accHeight += m_size[1];
+ // if pixel row has to be drawn
+ if (accHeight >= srcSize[1])
+ {
+ // decrease accum
+ accHeight -= srcSize[1];
+ // width accum
+ int accWidth = srcSize[0] >> 1;
+ // process row
+ for (int x = 0; x < srcSize[0]; ++x)
+ {
+ // increase width accum
+ accWidth += m_size[0];
+ // if pixel has to be drawn
+ if (accWidth >= srcSize[0])
+ {
+ // decrease accum
+ accWidth -= srcSize[0];
+ // convert pixel
+ *dstBuff = filter.convert(srcBuff, x, m_flip ? srcSize[1] - y - 1 : y,
+ srcSize, pixSize);
+ // next pixel
+ ++dstBuff;
+ }
+ // shift source pointer
+ srcBuff += pixSize;
+ }
+ }
+ // if pixel row will not be drawn
+ else
+ // move source pointer to next row
+ srcBuff += pixSize * srcSize[0];
+ // if y flipping is required
+ if (m_flip)
+ // go to previous row of image
+ srcBuff -= 2 * pixSize * srcSize[0];
+ }
+ }
+ }
+
+ // template for specific filter preprocessing
+ template <class F, class SRC> void filterImage (F & filt, SRC srcBuff, short * srcSize)
+ {
+ // find first filter in chain
+ FilterBase * firstFilter = NULL;
+ if (m_pyfilter != NULL) firstFilter = m_pyfilter->m_filter->findFirst();
+ // if first filter is available
+ if (firstFilter != NULL)
+ {
+ // python wrapper for filter
+ PyFilter pyFilt;
+ pyFilt.m_filter = &filt;
+ // set specified filter as first in chain
+ firstFilter->setPrevious(&pyFilt, false);
+ // convert video image
+ convImage(*(m_pyfilter->m_filter), srcBuff, srcSize);
+ // delete added filter
+ firstFilter->setPrevious(NULL, false);
+ }
+ // otherwise use given filter for conversion
+ else convImage(filt, srcBuff, srcSize);
+ // source was processed
+ m_avail = true;
+ }
+};
+
+
+// python structure for image filter
+struct PyImage
+{
+ PyObject_HEAD
+ // source object
+ ImageBase * m_image;
+};
+
+
+// size of id
+const int SourceIdSize = 32;
+
+
+/// class for source of image
+class ImageSource
+{
+public:
+ /// constructor
+ ImageSource (const char * id);
+ /// destructor
+ virtual ~ImageSource (void);
+
+ /// get id
+ const char * getId (void) { return m_id; }
+ /// compare id to argument
+ bool is (const char * id);
+
+ /// get source object
+ PyImage * getSource (void) { return m_source; }
+ /// set source object
+ void setSource (PyImage * source);
+
+ /// get image from source
+ unsigned int * getImage (void);
+ /// get buffered image
+ unsigned int * getImageBuf (void) { return m_image; }
+ /// refresh source
+ void refresh (void);
+
+ /// get image size
+ short * getSize (void)
+ {
+ static short defSize [] = {0, 0};
+ return m_source != NULL ? m_source->m_image->getSize() : defSize;
+ }
+
+protected:
+ /// id of source
+ char m_id [SourceIdSize];
+ /// pointer to source structure
+ PyImage * m_source;
+ /// buffered image from source
+ unsigned int * m_image;
+
+private:
+ /// default constructor is forbidden
+ ImageSource (void) {}
+};
+
+
+
+// list of python image types
+extern PyTypeList pyImageTypes;
+
+
+// functions for python interface
+
+// object initialization
+template <class T> static int Image_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
+{
+ PyImage * self = reinterpret_cast<PyImage*>(pySelf);
+ // create source object
+ if (self->m_image != NULL) delete self->m_image;
+ self->m_image = new T();
+ // initialization succeded
+ return 0;
+}
+
+// object allocation
+PyObject * Image_allocNew (PyTypeObject * type, PyObject * args, PyObject * kwds);
+// object deallocation
+void Image_dealloc (PyImage * self);
+
+// get image data
+PyObject * Image_getImage (PyImage * self, void * closure);
+// get image size
+PyObject * Image_getSize (PyImage * self, void * closure);
+// refresh image - invalidate current content
+PyObject * Image_refresh (PyImage * self);
+
+// get scale
+PyObject * Image_getScale (PyImage * self, void * closure);
+// set scale
+int Image_setScale (PyImage * self, PyObject * value, void * closure);
+// get flip
+PyObject * Image_getFlip (PyImage * self, void * closure);
+// set flip
+int Image_setFlip (PyImage * self, PyObject * value, void * closure);
+
+// get filter source object
+PyObject * Image_getSource (PyImage * self, PyObject * args);
+// set filter source object
+PyObject * Image_setSource (PyImage * self, PyObject * args);
+
+// get pixel filter object
+PyObject * Image_getFilter (PyImage * self, void * closure);
+// set pixel filter object
+int Image_setFilter (PyImage * self, PyObject * value, void * closure);
+
+
+#endif
diff --git a/source/gameengine/VideoTexture/ImageBuff.cpp b/source/gameengine/VideoTexture/ImageBuff.cpp
new file mode 100644
index 00000000000..19ad17ac643
--- /dev/null
+++ b/source/gameengine/VideoTexture/ImageBuff.cpp
@@ -0,0 +1,166 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+// implementation
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+#include "ImageBuff.h"
+
+#include "ImageBase.h"
+#include "FilterSource.h"
+
+
+// default filter
+FilterRGB24 defFilter;
+
+
+// load image from buffer
+void ImageBuff::load (unsigned char * img, short width, short height)
+{
+ // initialize image buffer
+ init(width, height);
+ // original size
+ short orgSize[2] = {width, height};
+ // is filter available
+ if (m_pyfilter != NULL)
+ // use it to process image
+ convImage(*(m_pyfilter->m_filter), img, orgSize);
+ else
+ // otherwise use default filter
+ convImage(defFilter, img, orgSize);
+ // image is available
+ m_avail = true;
+}
+
+
+
+// cast Image pointer to ImageBuff
+inline ImageBuff * getImageBuff (PyImage * self)
+{ return static_cast<ImageBuff*>(self->m_image); }
+
+
+// python methods
+
+// load image
+static PyObject * load (PyImage * self, PyObject * args)
+{
+ // parameters: string image buffer, its size, width, height
+ unsigned char * buff;
+ unsigned int buffSize;
+ short width;
+ short height;
+ // parse parameters
+ if (!PyArg_ParseTuple(args, "s#hh", &buff, &buffSize, &width, &height))
+ {
+ // report error
+ PyErr_SetString(PyExc_TypeError, "Parameters are not correct");
+ return NULL;
+ }
+ // else check buffer size
+ else
+ {
+ // calc proper buffer size
+ unsigned int propSize = width * height;
+ // use pixel size from filter
+ if (self->m_image->getFilter() != NULL)
+ propSize *= self->m_image->getFilter()->m_filter->firstPixelSize();
+ else
+ propSize *= defFilter.firstPixelSize();
+ // check if buffer size is correct
+ if (propSize != buffSize)
+ {
+ // if not, report error
+ PyErr_SetString(PyExc_TypeError, "Buffer hasn't correct size");
+ return NULL;
+ }
+ else
+ // if correct, load image
+ getImageBuff(self)->load(buff, width, height);
+ }
+ Py_RETURN_NONE;
+}
+
+
+// methods structure
+static PyMethodDef imageBuffMethods[] =
+{
+ {"load", (PyCFunction)load, METH_VARARGS, "Load image from buffer"},
+ {NULL}
+};
+// attributes structure
+static PyGetSetDef imageBuffGetSets[] =
+{ // 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}
+};
+
+
+// define python type
+PyTypeObject ImageBuffType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.ImageBuff", /*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 image buffer", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ imageBuffMethods, /* tp_methods */
+ 0, /* tp_members */
+ imageBuffGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Image_init<ImageBuff>, /* tp_init */
+ 0, /* tp_alloc */
+ Image_allocNew, /* tp_new */
+};
+
diff --git a/source/gameengine/VideoTexture/ImageBuff.h b/source/gameengine/VideoTexture/ImageBuff.h
new file mode 100644
index 00000000000..fa2025fa8c4
--- /dev/null
+++ b/source/gameengine/VideoTexture/ImageBuff.h
@@ -0,0 +1,51 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined IMAGEBUFF_H
+#define IMAGEBUFF_H
+
+
+#include "Common.h"
+
+#include "ImageBase.h"
+
+
+/// class for image buffer
+class ImageBuff : public ImageBase
+{
+public:
+ /// constructor
+ ImageBuff (void) : ImageBase(true) {}
+
+ /// destructor
+ virtual ~ImageBuff (void) {}
+
+ /// load image from buffer
+ void load (unsigned char * img, short width, short height);
+
+ /// refresh image - do nothing
+ virtual void refresh (void) {}
+};
+
+
+#endif
+
diff --git a/source/gameengine/VideoTexture/ImageMix.cpp b/source/gameengine/VideoTexture/ImageMix.cpp
new file mode 100644
index 00000000000..b07b362818c
--- /dev/null
+++ b/source/gameengine/VideoTexture/ImageMix.cpp
@@ -0,0 +1,205 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+// implementation
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+#include "ImageMix.h"
+
+#include "ImageBase.h"
+
+#include "Exception.h"
+
+
+// cast ImageSource pointer to ImageSourceMix
+inline ImageSourceMix * getImageSourceMix (ImageSource * src)
+{ return static_cast<ImageSourceMix*>(src); }
+
+
+// get weight
+short ImageMix::getWeight (const char * id)
+{
+ // find source
+ ImageSourceList::iterator src = findSource(id);
+ // if found, return its weight
+ return src != m_sources.end() ? getImageSourceMix(*src)->getWeight() : 0;
+}
+
+// set weight
+bool ImageMix::setWeight (const char * id, short weight)
+{
+ // find source
+ ImageSourceList::iterator src = findSource(id);
+ // if source isn't found, report it
+ if (src == m_sources.end()) return false;
+ // set its weight
+ getImageSourceMix(*src)->setWeight(weight);
+ return true;
+}
+
+ExceptionID ImageSizesNotMatch;
+
+ExpDesc ImageSizesNotMatchDesc (ImageSizesNotMatch, "Image sizes of sources are different");
+
+// calculate image from sources and set its availability
+void ImageMix::calcImage (unsigned int texId)
+{
+ // check source sizes
+ if (!checkSourceSizes()) THRWEXCP(ImageSizesNotMatch, S_OK);
+ // set offsets to image buffers
+ for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it)
+ // if image buffer is available
+ if ((*it)->getImageBuf() != NULL)
+ // set its offset
+ getImageSourceMix(*it)->setOffset(m_sources[0]->getImageBuf());
+ // otherwise don't calculate image
+ else
+ return;
+ // if there is only single source
+ if (m_sources.size() == 1)
+ {
+ // use single filter
+ FilterBase mixFilt;
+ // fiter and convert image
+ filterImage(mixFilt, m_sources[0]->getImageBuf(), m_sources[0]->getSize());
+ }
+ // otherwise use mix filter to merge source images
+ else
+ {
+ FilterImageMix mixFilt (m_sources);
+ // fiter and convert image
+ filterImage(mixFilt, m_sources[0]->getImageBuf(), m_sources[0]->getSize());
+ }
+}
+
+
+
+// cast Image pointer to ImageMix
+inline ImageMix * getImageMix (PyImage * self)
+{ return static_cast<ImageMix*>(self->m_image); }
+
+
+// python methods
+
+// get source weight
+PyObject * getWeight (PyImage * self, PyObject * args)
+{
+ // weight
+ short weight = 0;
+ // get arguments
+ char * id;
+ if (self->m_image != NULL && PyArg_ParseTuple(args, "s", &id))
+ // get weight
+ weight = getImageMix(self)->getWeight(id);
+ // return weight
+ return Py_BuildValue("h", weight);
+}
+
+
+// set source weight
+PyObject * setWeight (PyImage * self, PyObject * args)
+{
+ // get arguments
+ char * id;
+ short weight = 0;
+ if (self->m_image != NULL && PyArg_ParseTuple(args, "sh", &id, &weight))
+ // set weight
+ if (!getImageMix(self)->setWeight(id, weight))
+ {
+ // if not set, report error
+ PyErr_SetString(PyExc_RuntimeError, "Invalid id of source");;
+ return NULL;
+ }
+ // return none
+ Py_RETURN_NONE;
+}
+
+
+// methods structure
+static PyMethodDef imageMixMethods[] =
+{
+ {"getSource", (PyCFunction)Image_getSource, METH_VARARGS, "get image source"},
+ {"setSource", (PyCFunction)Image_setSource, METH_VARARGS, "set image source"},
+ {"getWeight", (PyCFunction)getWeight, METH_VARARGS, "get image source weight"},
+ {"setWeight", (PyCFunction)setWeight, METH_VARARGS, "set image source weight"},
+ // methods from ImageBase class
+ {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
+ {NULL}
+};
+// attributes structure
+static PyGetSetDef imageMixGetSets[] =
+{ // 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}
+};
+
+
+// define python type
+PyTypeObject ImageMixType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.ImageMix", /*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 mixer", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ imageMixMethods, /* tp_methods */
+ 0, /* tp_members */
+ imageMixGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Image_init<ImageMix>, /* tp_init */
+ 0, /* tp_alloc */
+ Image_allocNew, /* tp_new */
+};
+
diff --git a/source/gameengine/VideoTexture/ImageMix.h b/source/gameengine/VideoTexture/ImageMix.h
new file mode 100644
index 00000000000..b4842bd6b40
--- /dev/null
+++ b/source/gameengine/VideoTexture/ImageMix.h
@@ -0,0 +1,123 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined IMAGEMIX_H
+#define IMAGEMIX_H
+
+
+#include "Common.h"
+
+#include "ImageBase.h"
+#include "FilterBase.h"
+
+
+/// class for source mixing
+class ImageSourceMix : public ImageSource
+{
+public:
+ /// constructor
+ ImageSourceMix (const char * id) : ImageSource(id), m_weight(0x100) {}
+ /// destructor
+ virtual ~ImageSourceMix (void) {}
+
+ /// get offset
+ long long getOffset (void) { return m_offset; }
+ /// set offset
+ void setOffset (unsigned int * firstImg) { m_offset = m_image - firstImg; }
+
+ /// get weight
+ short getWeight (void) { return m_weight; }
+ /// set weight
+ void setWeight (short weight) { m_weight = weight; }
+
+protected:
+ /// buffer offset to the first source buffer
+ long long m_offset;
+ /// source weight
+ short m_weight;
+};
+
+
+/// class for image mixer
+class ImageMix : public ImageBase
+{
+public:
+ /// constructor
+ ImageMix (void) : ImageBase(false) {}
+
+ /// destructor
+ virtual ~ImageMix (void) {}
+
+ /// get weight
+ short getWeight (const char * id);
+ /// set weight
+ bool setWeight (const char * id, short weight);
+
+protected:
+
+ /// create new source
+ virtual ImageSource * newSource (const char * id) { return new ImageSourceMix(id); }
+
+ /// calculate image from sources and set its availability
+ virtual void calcImage (unsigned int texId);
+};
+
+
+/// pixel filter for image mixer
+class FilterImageMix : public FilterBase
+{
+public:
+ /// constructor
+ FilterImageMix (ImageSourceList & sources) : m_sources(sources) {}
+ /// destructor
+ virtual ~FilterImageMix (void) {}
+
+protected:
+ /// source list
+ ImageSourceList & m_sources;
+
+ /// filter pixel, source int buffer
+ virtual unsigned int filter (unsigned int * src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val = 0)
+ {
+ // resulting pixel color
+ int color[] = {0, 0, 0, 0};
+ // iterate sources
+ for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it)
+ {
+ // get pointer to mixer source
+ ImageSourceMix * mixSrc = static_cast<ImageSourceMix*>(*it);
+ // add weighted source pixel to result
+ color[0] += mixSrc->getWeight() * (src[mixSrc->getOffset()] & 0xFF);
+ color[1] += mixSrc->getWeight() * ((src[mixSrc->getOffset()] >> 8) & 0xFF);
+ color[2] += mixSrc->getWeight() * ((src[mixSrc->getOffset()] >> 16) & 0xFF);
+ color[3] += mixSrc->getWeight() * ((src[mixSrc->getOffset()] >> 24) & 0xFF);
+ }
+ // return resulting color
+ return ((color[0] >> 8) & 0xFF) | (color[1] & 0xFF00)
+ | ((color[2] << 8) & 0xFF0000) | ((color[3] << 16) & 0xFF000000);
+ }
+};
+
+
+#endif
+
diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp
new file mode 100644
index 00000000000..a8f7871fa21
--- /dev/null
+++ b/source/gameengine/VideoTexture/ImageRender.cpp
@@ -0,0 +1,267 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+// implementation
+
+#include <PyObjectPlus.h>
+#include <structmember.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 "ImageBase.h"
+#include "BlendType.h"
+#include "Exception.h"
+
+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)
+{
+ // 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();
+}
+
+// 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)
+{
+ 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);
+}
+
+
+// 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);
+ // get image from viewport
+ ImageViewport::calcImage(texId);
+}
+
+void ImageRender::Render()
+{
+ //
+}
+
+// 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());
+}
+
+
+
+// cast Image pointer to ImageRender
+inline ImageRender * getImageRender (PyImage * self)
+{ return static_cast<ImageRender*>(self->m_image); }
+
+
+// python methods
+
+// Blender Scene type
+BlendType<KX_Scene> sceneType ("KX_Scene");
+// Blender Camera type
+BlendType<KX_Camera> cameraType ("KX_Camera");
+
+
+// object initialization
+static int ImageRender_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
+{
+ // parameters - scene object
+ PyObject * scene;
+ // camera object
+ PyObject * camera;
+ // parameter keywords
+ static char *kwlist[] = {"sceneObj", "cameraObj", NULL};
+ // get parameters
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &scene, &camera))
+ return -1;
+ try
+ {
+ // get scene pointer
+ KX_Scene * scenePtr (NULL);
+ if (scene != NULL) scenePtr = sceneType.checkType(scene);
+ // throw exception if scene is not available
+ if (scenePtr == NULL) THRWEXCP(SceneInvalid, S_OK);
+
+ // get camera pointer
+ KX_Camera * cameraPtr (NULL);
+ if (camera != NULL) cameraPtr = cameraType.checkType(camera);
+ // throw exception if camera is not available
+ if (cameraPtr == NULL) THRWEXCP(CameraInvalid, 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 = new ImageRender(scenePtr, cameraPtr);
+ }
+ catch (Exception & exp)
+ {
+ exp.report();
+ return -1;
+ }
+ // initialization succeded
+ return 0;
+}
+
+
+// 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]);
+}
+
+// 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
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 0))
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 1))
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 2)))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 3 ints");
+ 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))));
+ // success
+ return 0;
+}
+
+
+// methods structure
+static PyMethodDef imageRenderMethods[] =
+{ // methods from ImageBase class
+ {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
+ {NULL}
+};
+// attributes structure
+static PyGetSetDef imageRenderGetSets[] =
+{
+ {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", 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}
+};
+
+
+// define python type
+PyTypeObject ImageRenderType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.ImageRender", /*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 render", /* 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 */
+ imageRenderGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ImageRender_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
new file mode 100644
index 00000000000..66255f04d2c
--- /dev/null
+++ b/source/gameengine/VideoTexture/ImageRender.h
@@ -0,0 +1,90 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined IMAGERENDER_H
+#define IMAGERENDER_H
+
+
+#include "Common.h"
+
+#include <KX_Scene.h>
+#include <KX_Camera.h>
+#include <DNA_screen_types.h>
+#include <RAS_ICanvas.h>
+#include <RAS_IRasterizer.h>
+#include <RAS_IRenderTools.h>
+
+#include "ImageViewport.h"
+
+
+/// class for render 3d scene
+class ImageRender : public ImageViewport
+{
+public:
+ /// constructor
+ ImageRender (KX_Scene * scene, KX_Camera * camera);
+
+ /// destructor
+ virtual ~ImageRender (void);
+
+ /// get background color
+ unsigned char * getBackground (void) { return m_background; }
+ /// set background color
+ void setBackground (unsigned char red, unsigned char green, unsigned char blue);
+
+protected:
+ /// 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;
+
+ /// background colour
+ unsigned char m_background[3];
+
+
+ /// 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);
+ void SetBackGround(KX_WorldInfo* wi);
+ void SetWorldSettings(KX_WorldInfo* wi);
+};
+
+
+#endif
+
diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp
new file mode 100644
index 00000000000..deb66ffb6ba
--- /dev/null
+++ b/source/gameengine/VideoTexture/ImageViewport.cpp
@@ -0,0 +1,297 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+// implementation
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+#include <BIF_gl.h>
+
+#include "Texture.h"
+#include "ImageBase.h"
+#include "FilterSource.h"
+#include "ImageViewport.h"
+
+
+// constructor
+ImageViewport::ImageViewport (void) : 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]];
+ // set attributes
+ setWhole(false);
+}
+
+// destructor
+ImageViewport::~ImageViewport (void)
+{ delete m_viewportImage; }
+
+
+// use whole viewport to capture image
+void ImageViewport::setWhole (bool whole)
+{
+ // set whole
+ m_whole = whole;
+ // set capture size to viewport size, if whole,
+ // otherwise place area in the middle of viewport
+ for (int idx = 0; idx < 2; ++idx)
+ {
+ // capture size
+ m_capSize[idx] = whole ? short(getViewportSize()[idx])
+ : calcSize(short(getViewportSize()[idx]));
+ // position
+ m_position[idx] = whole ? 0 : (getViewportSize()[idx] - m_capSize[idx]) >> 1;
+ }
+ // init image
+ init(m_capSize[0], m_capSize[1]);
+ // set capture position
+ setPosition();
+}
+
+void ImageViewport::setCaptureSize (short * size)
+{
+ m_whole = false;
+ if (size == NULL)
+ size = m_capSize;
+ for (int idx = 0; idx < 2; ++idx)
+ {
+ if (size[idx] < 1)
+ m_capSize[idx] = 1;
+ else if (size[idx] > getViewportSize()[idx])
+ m_capSize[idx] = short(getViewportSize()[idx]);
+ else
+ m_capSize[idx] = size[idx];
+ }
+ init(m_capSize[0], m_capSize[1]);
+ // set capture position
+ setPosition();
+}
+
+// set position of capture rectangle
+void ImageViewport::setPosition (GLint * pos)
+{
+ // if new position is not provided, use existing position
+ if (pos == NULL) pos = m_position;
+ // save position
+ for (int idx = 0; idx < 2; ++idx)
+ m_position[idx] = pos[idx] < 0 ? 0 : pos[idx] >= getViewportSize()[idx]
+ - m_capSize[idx] ? getViewportSize()[idx] - m_capSize[idx] : pos[idx];
+ // recalc up left corner
+ for (int idx = 0; idx < 2; ++idx)
+ m_upLeft[idx] = m_position[idx] + m_viewport[idx];
+}
+
+
+// capture image from viewport
+void ImageViewport::calcImage (unsigned int texId)
+{
+ // if scale was changed
+ if (m_scaleChange)
+ // reset image
+ init(m_capSize[0], m_capSize[1]);
+ // if texture wasn't initialized
+ if (!m_texInit)
+ {
+ // initialize it
+ loadTexture(texId, m_image, m_size);
+ m_texInit = true;
+ }
+ // if texture can be directly created
+ if (texId != 0 && m_pyfilter == NULL && m_capSize[0] == calcSize(m_capSize[0])
+ && 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;
+ }
+ // 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);
+ }
+}
+
+
+
+// cast Image pointer to ImageViewport
+inline ImageViewport * getImageViewport (PyImage * self)
+{ return static_cast<ImageViewport*>(self->m_image); }
+
+
+// python methods
+
+
+// get whole
+static 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)
+{
+ // check parameter, report failure
+ if (value == NULL || !PyBool_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+ return -1;
+ }
+ // set whole
+ if (self->m_image != NULL) getImageViewport(self)->setWhole(value == Py_True);
+ // success
+ return 0;
+}
+
+
+// get position
+static PyObject * ImageViewport_getPosition (PyImage * self, void * closure)
+{
+ return Py_BuildValue("(ii)", getImageViewport(self)->getPosition()[0],
+ getImageViewport(self)->getPosition()[1]);
+}
+
+// set position
+static int ImageViewport_setPosition (PyImage * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 0))
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 1)))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints");
+ return -1;
+ }
+ // set position
+ GLint pos [] = {
+ GLint(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 0))),
+ GLint(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 1)))
+ };
+ getImageViewport(self)->setPosition(pos);
+ // success
+ return 0;
+}
+
+// get capture size
+static 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)
+{
+ // check validity of parameter
+ if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 0))
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 1)))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints");
+ return -1;
+ }
+ // set capture size
+ short size [] = {
+ short(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 0))),
+ short(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 1)))
+ };
+ getImageViewport(self)->setCaptureSize(size);
+ // success
+ return 0;
+}
+
+
+// methods structure
+static PyMethodDef imageViewportMethods[] =
+{ // methods from ImageBase class
+ {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
+ {NULL}
+};
+// attributes structure
+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},
+ // 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}
+};
+
+
+// define python type
+PyTypeObject ImageViewportType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.ImageViewport", /*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 viewport", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ imageViewportMethods, /* tp_methods */
+ 0, /* tp_members */
+ imageViewportGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Image_init<ImageViewport>, /* tp_init */
+ 0, /* tp_alloc */
+ Image_allocNew, /* tp_new */
+};
diff --git a/source/gameengine/VideoTexture/ImageViewport.h b/source/gameengine/VideoTexture/ImageViewport.h
new file mode 100644
index 00000000000..4265906b8f5
--- /dev/null
+++ b/source/gameengine/VideoTexture/ImageViewport.h
@@ -0,0 +1,84 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined IMAGEVIEWPORT_H
+#define IMAGEVIEWPORT_H
+
+
+#include "Common.h"
+
+#include "ImageBase.h"
+
+
+/// class for viewport access
+class ImageViewport : public ImageBase
+{
+public:
+ /// constructor
+ ImageViewport (void);
+
+ /// destructor
+ virtual ~ImageViewport (void);
+
+ /// is whole buffer used
+ bool getWhole (void) { return m_whole; }
+ /// set whole buffer use
+ void setWhole (bool whole);
+ /// get capture size in viewport
+ short * getCaptureSize (void) { return m_capSize; }
+ /// set capture size in viewport
+ void setCaptureSize (short * size = NULL);
+
+ /// get position in viewport
+ GLint * getPosition (void) { return m_position; }
+ /// set position in viewport
+ void setPosition (GLint * pos = NULL);
+
+protected:
+ /// frame buffer rectangle
+ GLint m_viewport[4];
+
+ /// size of captured area
+ short m_capSize[2];
+ /// use whole viewport
+ bool m_whole;
+
+ /// position of capture rectangle in viewport
+ GLint m_position[2];
+ /// upper left point for capturing
+ GLint m_upLeft[2];
+
+ /// buffer to copy viewport
+ BYTE * m_viewportImage;
+ /// texture is initialized
+ bool m_texInit;
+
+ /// capture image from viewport
+ virtual void calcImage (unsigned int texId);
+
+ /// get viewport size
+ GLint * getViewportSize (void) { return m_viewport + 2; }
+};
+
+
+#endif
+
diff --git a/source/gameengine/VideoTexture/Makefile b/source/gameengine/VideoTexture/Makefile
new file mode 100644
index 00000000000..bead176808b
--- /dev/null
+++ b/source/gameengine/VideoTexture/Makefile
@@ -0,0 +1,65 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = videotex
+DIR = $(OCGDIR)/gameengine/$(LIBNAME)
+SOURCEDIR = source/gameengine/VideoTexture
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += $(OGL_CPPFLAGS)
+CPPFLAGS += -I$(NAN_GLEW)/include
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+CPPFLAGS += -I../../blender/python
+CPPFLAGS += -I$(NAN_STRING)/include
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I../Rasterizer/RAS_OpenGLRasterizer
+CPPFLAGS += -I../Rasterizer -I../GameLogic -I../SceneGraph
+CPPFLAGS += -I../BlenderRoutines -I../Expressions -I../Ketsji
+CPPFLAGS += -I../../kernel/gen_system
+CPPFLAGS += -I.
+CPPFLAGS += -I../../blender/blenkernel
+CPPFLAGS += -I../../blender/blenlib
+CPPFLAGS += -I../../blender/include
+CPPFLAGS += -I../../blender/makesdna
+CPPFLAGS += -I../../blender/imbuf
+CPPFLAGS += -I../../blender/gpu
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
+ifeq ($(WITH_FFMPEG),true)
+ CPPFLAGS += -DWITH_FFMPEG
+ CPPFLAGS += $(NAN_FFMPEGCFLAGS)
+endif
+
+
diff --git a/source/gameengine/VideoTexture/PyTypeList.cpp b/source/gameengine/VideoTexture/PyTypeList.cpp
new file mode 100644
index 00000000000..6d2676dce09
--- /dev/null
+++ b/source/gameengine/VideoTexture/PyTypeList.cpp
@@ -0,0 +1,83 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of blendTex library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+
+#include "PyTypeList.h"
+
+#include <memory>
+#include <vector>
+
+#include <PyObjectPlus.h>
+
+
+/// check, if type is in list
+bool PyTypeList::in (PyTypeObject * type)
+{
+ // if list exists
+ if (m_list.get() != NULL)
+ // iterate items in list
+ for (PyTypeListType::iterator it = m_list->begin(); it != m_list->end(); ++it)
+ // if item is found, return with success
+ if ((*it)->getType() == type) return true;
+ // otherwise return not found
+ return false;
+}
+
+/// add type to list
+void PyTypeList::add (PyTypeObject * type, const char * name)
+{
+ PyTypeListItem * typeItem;
+ // if list doesn't exist, create it
+ if (m_list.get() == NULL)
+ m_list.reset(new PyTypeListType());
+ if (!in(type))
+ // add new item to list
+ m_list->push_back(new PyTypeListItem(type, name));
+}
+
+/// prepare types
+bool PyTypeList::ready (void)
+{
+ // if list exists
+ if (m_list.get() != NULL)
+ // iterate items in list
+ for (PyTypeListType::iterator it = m_list->begin(); it != m_list->end(); ++it)
+ // if preparation failed, report it
+ if (PyType_Ready((*it)->getType()) < 0) return false;
+ // success
+ return true;
+}
+
+/// register types to module
+void PyTypeList::reg (PyObject * module)
+{
+ // if list exists
+ if (m_list.get() != NULL)
+ // iterate items in list
+ for (PyTypeListType::iterator it = m_list->begin(); it != m_list->end(); ++it)
+ {
+ // increase ref count
+ Py_INCREF((*it)->getType());
+ // add type to module
+ PyModule_AddObject(module, (char*)(*it)->getName(), (PyObject*)(*it)->getType());
+ }
+}
diff --git a/source/gameengine/VideoTexture/PyTypeList.h b/source/gameengine/VideoTexture/PyTypeList.h
new file mode 100644
index 00000000000..4daf88bfa19
--- /dev/null
+++ b/source/gameengine/VideoTexture/PyTypeList.h
@@ -0,0 +1,85 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of blendTex library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined PYTYPELIST_H
+#define PYTYPELIST_H
+
+#include "Common.h"
+
+#include <memory>
+#include <vector>
+
+#include <PyObjectPlus.h>
+
+// forward declaration
+class PyTypeListItem;
+
+// type for list of types
+typedef std::vector<PyTypeListItem*> PyTypeListType;
+
+
+/// class to store list of python types
+class PyTypeList
+{
+public:
+ /// check, if type is in list
+ bool in (PyTypeObject * type);
+
+ /// add type to list
+ void add (PyTypeObject * type, const char * name);
+
+ /// prepare types
+ bool ready (void);
+
+ /// register types to module
+ void reg (PyObject * module);
+
+protected:
+ /// pointer to list of types
+ std::auto_ptr<PyTypeListType> m_list;
+};
+
+
+/// class for item of python type list
+class PyTypeListItem
+{
+public:
+ /// constructor adds type into list
+ PyTypeListItem (PyTypeObject * type, const char * name)
+ : m_type(type), m_name(name)
+ { }
+
+ /// does type match
+ PyTypeObject * getType (void) { return m_type; }
+
+ /// get name of type
+ const char * getName (void) { return m_name; }
+
+protected:
+ /// pointer to type object
+ PyTypeObject * m_type;
+ /// name of type
+ const char * m_name;
+};
+
+
+#endif
diff --git a/source/gameengine/VideoTexture/SConscript b/source/gameengine/VideoTexture/SConscript
new file mode 100644
index 00000000000..91a74516bc5
--- /dev/null
+++ b/source/gameengine/VideoTexture/SConscript
@@ -0,0 +1,32 @@
+#!/usr/bin/python
+import sys
+
+Import ('env')
+
+sources = env.Glob('*.cpp')
+
+incs = '. #source/gameengine/Ketsji #source/gameengine/Expressions'
+incs += ' #source/gameengine/GameLogic #source/gameengine/SceneGraph #source/gameengine/Rasterizer'
+incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer'
+incs += ' #source/gameengine/BlenderRoutines'
+incs += ' #source/blender/editors/include #source/blender/blenlib #source/blender/blenkernel'
+incs += ' #source/blender/makesdna #source/blender/imbuf #source/blender/python'
+incs += ' #source/blender/gpu #source/kernel/gen_system #intern/string #intern/moto/include'
+incs += ' #intern/guardedalloc #intern/SoundSystem'
+incs += ' #extern/glew/include'
+
+cflags = []
+defs = ''
+if env['OURPLATFORM'] == 'win32-vc':
+ cflags.append('/GR')
+ cflags.append('/Ox')
+
+incs += ' ' + env['BF_PYTHON_INC']
+#incs += ' ' + env['BF_OPENGL_INC']
+
+if env['WITH_BF_FFMPEG']:
+ defs += ' WITH_FFMPEG'
+ incs += ' ' + env['BF_FFMPEG_INC']
+ defs += ' __STDC_CONSTANT_MACROS'
+
+env.BlenderLib ( 'bf_videotex', sources, Split(incs), Split(defs), libtype=['game','player'], priority=[25, 72], compileflags = cflags )
diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp
new file mode 100644
index 00000000000..12d4e79ad89
--- /dev/null
+++ b/source/gameengine/VideoTexture/Texture.cpp
@@ -0,0 +1,475 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+// implementation
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+#include <KX_GameObject.h>
+#include <RAS_MeshObject.h>
+#include <DNA_mesh_types.h>
+#include <DNA_meshdata_types.h>
+#include <DNA_image_types.h>
+#include <IMB_imbuf_types.h>
+#include <KX_PolygonMaterial.h>
+
+#include <MEM_guardedalloc.h>
+
+#include <KX_BlenderMaterial.h>
+#include <BL_Texture.h>
+
+#include "KX_KetsjiEngine.h"
+#include "KX_PythonInit.h"
+#include "Texture.h"
+#include "ImageBase.h"
+#include "Exception.h"
+
+#include <memory.h>
+#include <BIF_gl.h>
+
+
+// macro for exception handling and logging
+#define CATCH_EXCP catch (Exception & exp) \
+{ exp.report(); }
+
+
+// Blender GameObject type
+BlendType<KX_GameObject> gameObjectType ("KX_GameObject");
+
+
+// load texture
+void loadTexture (unsigned int texId, unsigned int * texture, short * size,
+ bool mipmap)
+{
+ // load texture for rendering
+ glBindTexture(GL_TEXTURE_2D, texId);
+ if (mipmap)
+ {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, texture);
+ }
+ else
+ {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size[0], size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
+ }
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+
+// get pointer to material
+RAS_IPolyMaterial * getMaterial (PyObject *obj, short matID)
+{
+ // if object is available
+ if (obj != NULL)
+ {
+ // get pointer to texture image
+ KX_GameObject * gameObj = gameObjectType.checkType(obj);
+ if (gameObj != NULL && gameObj->GetMeshCount() > 0)
+ {
+ // get material from mesh
+ RAS_MeshObject * mesh = gameObj->GetMesh(0);
+ RAS_MeshMaterial *meshMat = mesh->GetMeshMaterial(matID);
+ if (meshMat != NULL && meshMat->m_bucket != NULL)
+ // return pointer to polygon or blender material
+ return meshMat->m_bucket->GetPolyMaterial();
+ }
+ }
+ // otherwise material was not found
+ return NULL;
+}
+
+
+// get material ID
+short getMaterialID (PyObject * obj, char * name)
+{
+ // search for material
+ for (short matID = 0;; ++matID)
+ {
+ // get material
+ RAS_IPolyMaterial * mat = getMaterial(obj, matID);
+ // if material is not available, report that no material was found
+ if (mat == NULL)
+ break;
+ // name is a material name if it starts with MA and a UV texture name if it starts with IM
+ if (name[0] == 'I' && name[1] == 'M')
+ {
+ // if texture name matches
+ if (strcmp(mat->GetTextureName().ReadPtr(), name) == 0)
+ return matID;
+ } else
+ {
+ // if material name matches
+ if (strcmp(mat->GetMaterialName().ReadPtr(), name) == 0)
+ return matID;
+ }
+ }
+ // material was not found
+ return -1;
+}
+
+
+// Texture object allocation
+PyObject * Texture_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ // allocate object
+ Texture * self = reinterpret_cast<Texture*>(type->tp_alloc(type, 0));
+ // initialize object structure
+ self->m_actTex = 0;
+ self->m_orgSaved = false;
+ self->m_imgTexture = NULL;
+ self->m_matTexture = NULL;
+ self->m_mipmap = false;
+ self->m_scaledImg = NULL;
+ self->m_scaledImgSize = 0;
+ self->m_source = NULL;
+ self->m_lastClock = 0.0;
+ // return allocated object
+ return reinterpret_cast<PyObject*>(self);
+}
+
+
+// forward declaration
+PyObject * Texture_close(Texture * self);
+int Texture_setSource (Texture * self, PyObject * value, void * closure);
+
+
+// Texture object deallocation
+void Texture_dealloc (Texture * self)
+{
+ // release renderer
+ Py_XDECREF(self->m_source);
+ // close texture
+ Texture_close(self);
+ // release scaled image buffer
+ delete [] self->m_scaledImg;
+ // release object
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+
+ExceptionID MaterialNotAvail;
+ExpDesc MaterialNotAvailDesc (MaterialNotAvail, "Texture material is not available");
+
+// Texture object initialization
+int Texture_init (Texture *self, PyObject *args, PyObject *kwds)
+{
+ // parameters - game object with video texture
+ PyObject * obj = NULL;
+ // material ID
+ short matID = 0;
+ // texture ID
+ short texID = 0;
+ // texture object with shared texture ID
+ Texture * texObj = NULL;
+
+ static char *kwlist[] = {"gameObj", "materialID", "textureID", "textureObj", NULL};
+
+ // get parameters
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|hhO!", kwlist, &obj, &matID,
+ &texID, &TextureType, &texObj))
+ return -1;
+
+ // if parameters are available
+ if (obj != NULL)
+ {
+ // process polygon material or blender material
+ try
+ {
+ // get pointer to texture image
+ RAS_IPolyMaterial * mat = getMaterial(obj, matID);
+ if (mat != NULL)
+ {
+ // is it blender material or polygon material
+ if (mat->GetFlag() & RAS_BLENDERGLSL)
+ {
+ self->m_imgTexture = static_cast<KX_BlenderMaterial*>(mat)->getImage(texID);
+ self->m_useMatTexture = false;
+ } else if (mat->GetFlag() & RAS_BLENDERMAT)
+ {
+ // get blender material texture
+ self->m_matTexture = static_cast<KX_BlenderMaterial*>(mat)->getTex(texID);
+ self->m_useMatTexture = true;
+ }
+ else
+ {
+ // get texture pointer from polygon material
+ MTFace * tface = static_cast<KX_PolygonMaterial*>(mat)->GetMTFace();
+ self->m_imgTexture = (Image*)tface->tpage;
+ self->m_useMatTexture = false;
+ }
+ }
+ // check if texture is available, if not, initialization failed
+ if (self->m_imgTexture == NULL && self->m_matTexture == NULL)
+ // throw exception if initialization failed
+ THRWEXCP(MaterialNotAvail, S_OK);
+
+ // if texture object is provided
+ if (texObj != NULL)
+ {
+ // copy texture code
+ self->m_actTex = texObj->m_actTex;
+ self->m_mipmap = texObj->m_mipmap;
+ if (texObj->m_source != NULL)
+ Texture_setSource(self, reinterpret_cast<PyObject*>(texObj->m_source), NULL);
+ }
+ else
+ // otherwise generate texture code
+ glGenTextures(1, (GLuint*)&self->m_actTex);
+ }
+ catch (Exception & exp)
+ {
+ exp.report();
+ return -1;
+ }
+ }
+ // initialization succeded
+ return 0;
+}
+
+
+// close added texture
+PyObject * Texture_close(Texture * self)
+{
+ // restore texture
+ if (self->m_orgSaved)
+ {
+ self->m_orgSaved = false;
+ // restore original texture code
+ if (self->m_useMatTexture)
+ self->m_matTexture->swapTexture(self->m_orgTex);
+ else
+ self->m_imgTexture->bindcode = self->m_orgTex;
+ // drop actual texture
+ if (self->m_actTex != 0)
+ {
+ glDeleteTextures(1, (GLuint *)&self->m_actTex);
+ self->m_actTex = 0;
+ }
+ }
+ Py_RETURN_NONE;
+}
+
+
+// refresh texture
+PyObject * Texture_refresh (Texture * self, PyObject * args)
+{
+ // get parameter - refresh source
+ PyObject * param;
+ if (!PyArg_ParseTuple(args, "O", &param) || !PyBool_Check(param))
+ {
+ // report error
+ PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+ return NULL;
+ }
+ // some trick here: we are in the business of loading a texture,
+ // no use to do it if we are still in the same rendering frame.
+ // We find this out by looking at the engine current clock time
+ KX_KetsjiEngine* engine = KX_GetActiveEngine();
+ if (engine->GetClockTime() != self->m_lastClock)
+ {
+ self->m_lastClock = engine->GetClockTime();
+ // set source refresh
+ bool refreshSource = (param == Py_True);
+ // try to proces texture from source
+ try
+ {
+ // if source is available
+ if (self->m_source != NULL)
+ {
+ // check texture code
+ if (!self->m_orgSaved)
+ {
+ self->m_orgSaved = true;
+ // save original image code
+ if (self->m_useMatTexture)
+ self->m_orgTex = self->m_matTexture->swapTexture(self->m_actTex);
+ else
+ {
+ self->m_orgTex = self->m_imgTexture->bindcode;
+ self->m_imgTexture->bindcode = self->m_actTex;
+ }
+ }
+
+ // get texture
+ unsigned int * texture = self->m_source->m_image->getImage(self->m_actTex);
+ // if texture is available
+ if (texture != NULL)
+ {
+ // get texture size
+ short * orgSize = self->m_source->m_image->getSize();
+ // calc scaled sizes
+ short size[] = {ImageBase::calcSize(orgSize[0]), ImageBase::calcSize(orgSize[1])};
+ // scale texture if needed
+ if (size[0] != orgSize[0] || size[1] != orgSize[1])
+ {
+ // if scaled image buffer is smaller than needed
+ if (self->m_scaledImgSize < (unsigned int)(size[0] * size[1]))
+ {
+ // new size
+ self->m_scaledImgSize = size[0] * size[1];
+ // allocate scaling image
+ delete [] self->m_scaledImg;
+ self->m_scaledImg = new unsigned int[self->m_scaledImgSize];
+ }
+ // scale texture
+ gluScaleImage(GL_RGBA, orgSize[0], orgSize[1], GL_UNSIGNED_BYTE, texture,
+ size[0], size[1], GL_UNSIGNED_BYTE, self->m_scaledImg);
+ // use scaled image instead original
+ texture = self->m_scaledImg;
+ }
+ // load texture for rendering
+ loadTexture (self->m_actTex, texture, size, self->m_mipmap);
+
+ // refresh texture source, if required
+ if (refreshSource) self->m_source->m_image->refresh();
+ }
+ }
+ }
+ CATCH_EXCP;
+ }
+ Py_RETURN_NONE;
+}
+
+
+// get mipmap value
+PyObject * Texture_getMipmap (Texture * self, void * closure)
+{
+ // return true if flag is set, otherwise false
+ if (self->m_mipmap) Py_RETURN_TRUE;
+ else Py_RETURN_FALSE;
+}
+
+// set mipmap value
+int Texture_setMipmap (Texture * 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 mipmap
+ self->m_mipmap = value == Py_True;
+ // success
+ return 0;
+}
+
+
+// get source object
+PyObject * Texture_getSource (Texture * self, PyObject * value, void * closure)
+{
+ // if source exists
+ if (self->m_source != NULL)
+ {
+ Py_INCREF(self->m_source);
+ return reinterpret_cast<PyObject*>(self->m_source);
+ }
+ // otherwise return None
+ Py_RETURN_NONE;
+}
+
+
+// set source object
+int Texture_setSource (Texture * self, PyObject * value, void * closure)
+{
+ // check new value
+ if (value == NULL || !pyImageTypes.in(value->ob_type))
+ {
+ // report value error
+ PyErr_SetString(PyExc_TypeError, "Invalid type of value");
+ return -1;
+ }
+ // increase ref count for new value
+ Py_INCREF(value);
+ // release previous
+ Py_XDECREF(self->m_source);
+ // set new value
+ self->m_source = reinterpret_cast<PyImage*>(value);
+ // return success
+ return 0;
+}
+
+
+// class Texture methods
+static PyMethodDef textureMethods[] =
+{
+ { "close", (PyCFunction)Texture_close, METH_NOARGS, "Close dynamic texture and restore original"},
+ { "refresh", (PyCFunction)Texture_refresh, METH_VARARGS, "Refresh texture from source"},
+ {NULL} /* Sentinel */
+};
+
+// class Texture attributes
+static PyGetSetDef textureGetSets[] =
+{
+ {(char*)"source", (getter)Texture_getSource, (setter)Texture_setSource, (char*)"source of texture", NULL},
+ {(char*)"mipmap", (getter)Texture_getMipmap, (setter)Texture_setMipmap, (char*)"mipmap texture", NULL},
+ {NULL}
+};
+
+
+// class Texture declaration
+PyTypeObject TextureType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.Texture", /*tp_name*/
+ sizeof(Texture), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Texture_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*/
+ "Texture objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ textureMethods, /* tp_methods */
+ 0, /* tp_members */
+ textureGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Texture_init, /* tp_init */
+ 0, /* tp_alloc */
+ Texture_new, /* tp_new */
+};
diff --git a/source/gameengine/VideoTexture/Texture.h b/source/gameengine/VideoTexture/Texture.h
new file mode 100644
index 00000000000..3c371e51537
--- /dev/null
+++ b/source/gameengine/VideoTexture/Texture.h
@@ -0,0 +1,86 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2006 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined TEXTURE_H
+#define TEXTURE_H
+
+#include <PyObjectPlus.h>
+#include <structmember.h>
+
+#include <DNA_image_types.h>
+#include <BL_Texture.h>
+#include <KX_BlenderMaterial.h>
+
+#include "ImageBase.h"
+#include "BlendType.h"
+
+
+// type Texture declaration
+struct Texture
+{
+ PyObject_HEAD
+
+ // texture is using blender material
+ bool m_useMatTexture;
+
+ // video texture bind code
+ unsigned int m_actTex;
+ // original texture bind code
+ unsigned int m_orgTex;
+ // original texture saved
+ bool m_orgSaved;
+
+ // texture image for game materials
+ Image * m_imgTexture;
+ // texture for blender materials
+ BL_Texture * m_matTexture;
+
+ // use mipmapping
+ bool m_mipmap;
+
+ // scaled image buffer
+ unsigned int * m_scaledImg;
+ // scaled image buffer size
+ unsigned int m_scaledImgSize;
+ // last refresh
+ double m_lastClock;
+
+ // image source
+ PyImage * m_source;
+};
+
+
+// Texture type description
+extern PyTypeObject TextureType;
+
+// load texture
+void loadTexture (unsigned int texId, unsigned int * texture, short * size,
+ bool mipmap = false);
+
+// get material
+RAS_IPolyMaterial * getMaterial (PyObject *obj, short matID);
+
+// get material ID
+short getMaterialID (PyObject * obj, char * name);
+
+
+#endif
diff --git a/source/gameengine/VideoTexture/VideoBase.cpp b/source/gameengine/VideoTexture/VideoBase.cpp
new file mode 100644
index 00000000000..10117c3af9e
--- /dev/null
+++ b/source/gameengine/VideoTexture/VideoBase.cpp
@@ -0,0 +1,195 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if defined WIN32
+#define WINDOWS_LEAN_AND_MEAN
+#include <Windows.h>
+#endif
+
+#include "VideoBase.h"
+
+#include "FilterSource.h"
+
+// VideoBase implementation
+
+
+// initialize image data
+void VideoBase::init(short width, short height)
+{
+ // save original sizes
+ m_orgSize[0] = width;
+ m_orgSize[1] = height;
+ // call base class initialization
+ ImageBase::init(width, height);
+}
+
+
+// process video frame
+void VideoBase::process (BYTE * sample)
+{
+ // if scale was changed
+ if (m_scaleChange)
+ // reset image
+ init(m_orgSize[0], m_orgSize[1]);
+ // if image is allocated and is able to store new image
+ if (m_image != NULL && !m_avail)
+ {
+ // filters used
+ // convert video format to image
+ switch (m_format)
+ {
+ case RGBA32:
+ {
+ FilterRGBA32 filtRGBA;
+ // use filter object for format to convert image
+ filterImage(filtRGBA, sample, m_orgSize);
+ // finish
+ break;
+ }
+ case RGB24:
+ {
+ FilterRGB24 filtRGB;
+ // use filter object for format to convert image
+ filterImage(filtRGB, sample, m_orgSize);
+ // finish
+ break;
+ }
+ case YV12:
+ {
+ // use filter object for format to convert image
+ FilterYV12 filtYUV;
+ filtYUV.setBuffs(sample, m_orgSize);
+ filterImage(filtYUV, sample, m_orgSize);
+ // finish
+ break;
+ }
+ }
+ }
+}
+
+
+// python functions
+
+
+// exceptions for video source initialization
+ExceptionID SourceVideoEmpty, SourceVideoCreation;
+ExpDesc SourceVideoEmptyDesc (SourceVideoEmpty, "Source Video is empty");
+ExpDesc SourceVideoCreationDesc (SourceVideoCreation, "SourceVideo object was not created");
+
+// open video source
+void Video_open (VideoBase * self, char * file, short captureID)
+{
+ // if file is empty, throw exception
+ if (file == NULL) THRWEXCP(SourceVideoEmpty, S_OK);
+
+ // open video file or capture device
+ if (captureID >= 0)
+ self->openCam(file, captureID);
+ else
+ self->openFile(file);
+}
+
+
+// play video
+PyObject * Video_play (PyImage * self)
+{ if (getVideo(self)->play()) Py_RETURN_TRUE; else Py_RETURN_FALSE; }
+
+// stop video
+PyObject * Video_stop (PyImage * self)
+{ if (getVideo(self)->stop()) Py_RETURN_TRUE; else Py_RETURN_FALSE; }
+
+// get status
+PyObject * Video_getStatus (PyImage * self, void * closure)
+{
+ return Py_BuildValue("h", getVideo(self)->getStatus());
+}
+
+// refresh video
+PyObject * Video_refresh (PyImage * self)
+{
+ getVideo(self)->refresh();
+ return Video_getStatus(self, NULL);
+}
+
+
+// get range
+PyObject * Video_getRange (PyImage * self, void * closure)
+{
+ return Py_BuildValue("[ff]", getVideo(self)->getRange()[0],
+ getVideo(self)->getRange()[1]);
+}
+
+// set range
+int Video_setRange (PyImage * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2
+ || !PyFloat_Check(PySequence_Fast_GET_ITEM(value, 0))
+ || !PyFloat_Check(PySequence_Fast_GET_ITEM(value, 1)))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 longs");
+ return -1;
+ }
+ // set range
+ getVideo(self)->setRange(PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)),
+ PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)));
+ // success
+ return 0;
+}
+
+// get repeat
+PyObject * Video_getRepeat (PyImage * self, void * closure)
+{ return Py_BuildValue("h", getVideo(self)->getRepeat()); }
+
+// set repeat
+int Video_setRepeat (PyImage * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ if (value == NULL || !PyInt_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be an int");
+ return -1;
+ }
+ // set repeat
+ getVideo(self)->setRepeat(int(PyInt_AsLong(value)));
+ // success
+ return 0;
+}
+
+// get frame rate
+PyObject * Video_getFrameRate (PyImage * self, void * closure)
+{ return Py_BuildValue("f", double(getVideo(self)->getFrameRate())); }
+
+// set frame rate
+int Video_setFrameRate (PyImage * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ if (value == NULL || !PyFloat_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a float");
+ return -1;
+ }
+ // set repeat
+ getVideo(self)->setFrameRate(float(PyFloat_AsDouble(value)));
+ // success
+ return 0;
+}
diff --git a/source/gameengine/VideoTexture/VideoBase.h b/source/gameengine/VideoTexture/VideoBase.h
new file mode 100644
index 00000000000..15ecb7a78f4
--- /dev/null
+++ b/source/gameengine/VideoTexture/VideoBase.h
@@ -0,0 +1,185 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#if !defined VIDEOBASE_H
+#define VIDEOBASE_H
+
+
+#include <PyObjectPlus.h>
+
+#include "ImageBase.h"
+
+#include "Exception.h"
+
+// source states
+const int SourceError = -1;
+const int SourceEmpty = 0;
+const int SourceReady = 1;
+const int SourcePlaying = 2;
+const int SourceStopped = 3;
+
+
+// video source formats
+enum VideoFormat { None, RGB24, YV12, RGBA32 };
+
+
+/// base class for video source
+class VideoBase : public ImageBase
+{
+public:
+ /// constructor
+ VideoBase (void) : ImageBase(true), m_format(None), m_status(SourceEmpty),
+ m_repeat(0), m_frameRate(1.0)
+ {
+ m_orgSize[0] = m_orgSize[1] = 0;
+ m_range[0] = m_range[1] = 0.0;
+ }
+
+ /// destructor
+ virtual ~VideoBase (void) {}
+
+ /// open video file
+ virtual void openFile (char * file)
+ {
+ m_isFile = true;
+ m_status = SourceReady;
+ }
+ /// open video capture device
+ virtual void openCam (char * file, short camIdx)
+ {
+ m_isFile = false;
+ m_status = SourceReady;
+ }
+
+ /// play video
+ virtual bool play (void)
+ {
+ if (m_status == SourceReady || m_status == SourceStopped)
+ {
+ m_status = SourcePlaying;
+ return true;
+ }
+ return false;
+ }
+ /// stop/pause video
+ virtual bool stop (void)
+ {
+ if (m_status == SourcePlaying)
+ {
+ m_status = SourceStopped;
+ return true;
+ }
+ return false;
+ }
+
+ // get video status
+ int getStatus (void) { return m_status; }
+
+ /// get play range
+ const double * getRange (void) { return m_range; }
+ /// set play range
+ virtual void setRange (double start, double stop)
+ {
+ if (m_isFile)
+ {
+ m_range[0] = start;
+ m_range[1] = stop;
+ }
+ }
+
+ // get video repeat
+ int getRepeat (void) { return m_repeat; }
+ /// set video repeat
+ virtual void setRepeat (int rep)
+ { if (m_isFile) m_repeat = rep; }
+
+ /// get frame rate
+ float getFrameRate (void) { return m_frameRate; }
+ /// set frame rate
+ virtual void setFrameRate (float rate)
+ { if (m_isFile) m_frameRate = rate > 0.0 ? rate : 1.0f; }
+
+protected:
+ /// video format
+ VideoFormat m_format;
+ /// original video size
+ short m_orgSize[2];
+
+ /// video status
+ int m_status;
+
+ /// is source file
+ bool m_isFile;
+
+ /// replay range
+ double m_range[2];
+ /// repeat count
+ int m_repeat;
+ /// frame rate
+ float m_frameRate;
+
+ /// initialize image data
+ void init (short width, short height);
+
+ /// process source data
+ void process (BYTE * sample);
+};
+
+
+
+// python fuctions
+
+
+// cast Image pointer to Video
+inline VideoBase * getVideo (PyImage * self)
+{ return static_cast<VideoBase*>(self->m_image); }
+
+
+extern ExceptionID SourceVideoCreation;
+
+// object initialization
+template <class T> void Video_init (PyImage * self)
+{
+ // create source video object
+ if (self->m_image != NULL) delete self->m_image;
+ HRESULT hRslt = S_OK;
+ self->m_image = new T(&hRslt);
+ CHCKHRSLT(hRslt, SourceVideoCreation);
+}
+
+
+// video functions
+void Video_open (VideoBase * self, char * file, short captureID);
+PyObject * Video_play (PyImage * self);
+PyObject * Video_stop (PyImage * self);
+PyObject * Video_refresh (PyImage * self);
+PyObject * Video_getStatus (PyImage * self, void * closure);
+PyObject * Video_getRange (PyImage * self, void * closure);
+int Video_setRange (PyImage * self, PyObject * value, void * closure);
+PyObject * Video_getRepeat (PyImage * self, void * closure);
+int Video_setRepeat (PyImage * self, PyObject * value, void * closure);
+PyObject * Video_getFrameRate (PyImage * self, void * closure);
+int Video_setFrameRate (PyImage * self, PyObject * value, void * closure);
+
+
+#endif
+
diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
new file mode 100644
index 00000000000..02798c7e596
--- /dev/null
+++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
@@ -0,0 +1,927 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#ifdef WITH_FFMPEG
+
+// INT64_C fix for some linux machines (C99ism)
+#define __STDC_CONSTANT_MACROS
+#include <stdint.h>
+
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include <string>
+
+#include "Exception.h"
+#include "VideoFFmpeg.h"
+
+
+// default framerate
+const double defFrameRate = 25.0;
+// time scale constant
+const long timeScale = 1000;
+
+// macro for exception handling and logging
+#define CATCH_EXCP catch (Exception & exp) \
+{ exp.report(); m_status = SourceError; }
+
+extern "C" void do_init_ffmpeg();
+
+// class RenderVideo
+
+// constructor
+VideoFFmpeg::VideoFFmpeg (HRESULT * hRslt) : VideoBase(),
+m_codec(NULL), m_formatCtx(NULL), m_codecCtx(NULL),
+m_frame(NULL), m_frameDeinterlaced(NULL), m_frameRGB(NULL), m_imgConvertCtx(NULL),
+m_deinterlace(false), m_preseek(0), m_videoStream(-1), m_baseFrameRate(25.0),
+m_lastFrame(-1), m_eof(false), m_curPosition(-1), m_startTime(0),
+m_captWidth(0), m_captHeight(0), m_captRate(0.f), m_isImage(false)
+{
+ // set video format
+ m_format = RGB24;
+ // force flip because ffmpeg always return the image in the wrong orientation for texture
+ setFlip(true);
+ // construction is OK
+ *hRslt = S_OK;
+}
+
+// destructor
+VideoFFmpeg::~VideoFFmpeg ()
+{
+}
+
+
+// release components
+bool VideoFFmpeg::release()
+{
+ // release
+ if (m_codecCtx)
+ {
+ avcodec_close(m_codecCtx);
+ m_codecCtx = NULL;
+ }
+ if (m_formatCtx)
+ {
+ av_close_input_file(m_formatCtx);
+ m_formatCtx = NULL;
+ }
+ if (m_frame)
+ {
+ av_free(m_frame);
+ m_frame = NULL;
+ }
+ if (m_frameDeinterlaced)
+ {
+ MEM_freeN(m_frameDeinterlaced->data[0]);
+ av_free(m_frameDeinterlaced);
+ m_frameDeinterlaced = NULL;
+ }
+ if (m_frameRGB)
+ {
+ MEM_freeN(m_frameRGB->data[0]);
+ av_free(m_frameRGB);
+ m_frameRGB = NULL;
+ }
+ if (m_imgConvertCtx)
+ {
+ sws_freeContext(m_imgConvertCtx);
+ m_imgConvertCtx = NULL;
+ }
+ m_codec = NULL;
+ m_status = SourceStopped;
+ return true;
+}
+
+
+// set initial parameters
+void VideoFFmpeg::initParams (short width, short height, float rate, bool image)
+{
+ m_captWidth = width;
+ m_captHeight = height;
+ m_captRate = rate;
+ m_isImage = image;
+}
+
+int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AVFormatParameters *formatParams)
+{
+ AVFormatContext *formatCtx;
+ int i, videoStream;
+ AVCodec *codec;
+ AVCodecContext *codecCtx;
+
+ if(av_open_input_file(&formatCtx, filename, inputFormat, 0, formatParams)!=0)
+ return -1;
+
+ if(av_find_stream_info(formatCtx)<0)
+ {
+ av_close_input_file(formatCtx);
+ return -1;
+ }
+
+ /* Find the first video stream */
+ videoStream=-1;
+ for(i=0; i<formatCtx->nb_streams; i++)
+ {
+ if(formatCtx->streams[i] &&
+ get_codec_from_stream(formatCtx->streams[i]) &&
+ (get_codec_from_stream(formatCtx->streams[i])->codec_type==CODEC_TYPE_VIDEO))
+ {
+ videoStream=i;
+ break;
+ }
+ }
+
+ if(videoStream==-1)
+ {
+ av_close_input_file(formatCtx);
+ return -1;
+ }
+
+ codecCtx = get_codec_from_stream(formatCtx->streams[videoStream]);
+
+ /* Find the decoder for the video stream */
+ codec=avcodec_find_decoder(codecCtx->codec_id);
+ if(codec==NULL)
+ {
+ av_close_input_file(formatCtx);
+ return -1;
+ }
+ codecCtx->workaround_bugs = 1;
+ if(avcodec_open(codecCtx, codec)<0)
+ {
+ av_close_input_file(formatCtx);
+ return -1;
+ }
+
+#ifdef FFMPEG_OLD_FRAME_RATE
+ if(codecCtx->frame_rate>1000 && codecCtx->frame_rate_base==1)
+ codecCtx->frame_rate_base=1000;
+ m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base;
+#else
+ m_baseFrameRate = av_q2d(formatCtx->streams[videoStream]->r_frame_rate);
+#endif
+ if (m_baseFrameRate <= 0.0)
+ m_baseFrameRate = defFrameRate;
+
+ m_codec = codec;
+ m_codecCtx = codecCtx;
+ m_formatCtx = formatCtx;
+ m_videoStream = videoStream;
+ m_frame = avcodec_alloc_frame();
+ m_frameDeinterlaced = avcodec_alloc_frame();
+ m_frameRGB = avcodec_alloc_frame();
+
+ // allocate buffer if deinterlacing is required
+ avpicture_fill((AVPicture*)m_frameDeinterlaced,
+ (uint8_t*)MEM_callocN(avpicture_get_size(
+ m_codecCtx->pix_fmt,
+ m_codecCtx->width, m_codecCtx->height),
+ "ffmpeg deinterlace"),
+ m_codecCtx->pix_fmt, m_codecCtx->width, m_codecCtx->height);
+
+ // check if the pixel format supports Alpha
+ if (m_codecCtx->pix_fmt == PIX_FMT_RGB32 ||
+ m_codecCtx->pix_fmt == PIX_FMT_BGR32 ||
+ m_codecCtx->pix_fmt == PIX_FMT_RGB32_1 ||
+ m_codecCtx->pix_fmt == PIX_FMT_BGR32_1)
+ {
+ // allocate buffer to store final decoded frame
+ m_format = RGBA32;
+ avpicture_fill((AVPicture*)m_frameRGB,
+ (uint8_t*)MEM_callocN(avpicture_get_size(
+ PIX_FMT_RGBA,
+ m_codecCtx->width, m_codecCtx->height),
+ "ffmpeg rgba"),
+ PIX_FMT_RGBA, m_codecCtx->width, m_codecCtx->height);
+ // allocate sws context
+ m_imgConvertCtx = sws_getContext(
+ m_codecCtx->width,
+ m_codecCtx->height,
+ m_codecCtx->pix_fmt,
+ m_codecCtx->width,
+ m_codecCtx->height,
+ PIX_FMT_RGBA,
+ SWS_FAST_BILINEAR,
+ NULL, NULL, NULL);
+ } else
+ {
+ // allocate buffer to store final decoded frame
+ m_format = RGB24;
+ avpicture_fill((AVPicture*)m_frameRGB,
+ (uint8_t*)MEM_callocN(avpicture_get_size(
+ PIX_FMT_RGB24,
+ m_codecCtx->width, m_codecCtx->height),
+ "ffmpeg rgb"),
+ PIX_FMT_RGB24, m_codecCtx->width, m_codecCtx->height);
+ // allocate sws context
+ m_imgConvertCtx = sws_getContext(
+ m_codecCtx->width,
+ m_codecCtx->height,
+ m_codecCtx->pix_fmt,
+ m_codecCtx->width,
+ m_codecCtx->height,
+ PIX_FMT_RGB24,
+ SWS_FAST_BILINEAR,
+ NULL, NULL, NULL);
+ }
+ if (!m_imgConvertCtx) {
+ avcodec_close(m_codecCtx);
+ av_close_input_file(m_formatCtx);
+ av_free(m_frame);
+ MEM_freeN(m_frameDeinterlaced->data[0]);
+ av_free(m_frameDeinterlaced);
+ MEM_freeN(m_frameRGB->data[0]);
+ av_free(m_frameRGB);
+ return -1;
+ }
+ return 0;
+}
+
+// open video file
+void VideoFFmpeg::openFile (char * filename)
+{
+ do_init_ffmpeg();
+
+ if (openStream(filename, NULL, NULL) != 0)
+ return;
+
+ if (m_codecCtx->gop_size)
+ m_preseek = (m_codecCtx->gop_size < 25) ? m_codecCtx->gop_size+1 : 25;
+ else if (m_codecCtx->has_b_frames)
+ m_preseek = 25; // should determine gopsize
+ else
+ m_preseek = 0;
+
+ // get video time range
+ m_range[0] = 0.0;
+ m_range[1] = (double)m_formatCtx->duration / AV_TIME_BASE;
+
+ // open base class
+ VideoBase::openFile(filename);
+
+ if (
+#ifdef FFMPEG_PB_IS_POINTER
+ m_formatCtx->pb && m_formatCtx->pb->is_streamed
+#else
+ m_formatCtx->pb.is_streamed
+#endif
+ )
+ {
+ // the file is in fact a streaming source, prevent seeking
+ m_isFile = false;
+ // for streaming it is important to do non blocking read
+ m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK;
+ }
+
+ if (m_isImage)
+ {
+ // the file is to be treated as an image, i.e. load the first frame only
+ m_isFile = false;
+ // in case of reload, the filename is taken from m_imageName, no need to change it
+ if (m_imageName.Ptr() != filename)
+ m_imageName = filename;
+ m_preseek = 0;
+ m_avail = false;
+ play();
+ }
+
+}
+
+
+// open video capture device
+void VideoFFmpeg::openCam (char * file, short camIdx)
+{
+ // open camera source
+ AVInputFormat *inputFormat;
+ AVFormatParameters formatParams;
+ AVRational frameRate;
+ char *p, filename[28], rateStr[20];
+
+ do_init_ffmpeg();
+
+ memset(&formatParams, 0, sizeof(formatParams));
+#ifdef WIN32
+ // video capture on windows only through Video For Windows driver
+ inputFormat = av_find_input_format("vfwcap");
+ if (!inputFormat)
+ // Video For Windows not supported??
+ return;
+ sprintf(filename, "%d", camIdx);
+#else
+ // In Linux we support two types of devices: VideoForLinux and DV1394.
+ // the user specify it with the filename:
+ // [<device_type>][:<standard>]
+ // <device_type> : 'v4l' for VideoForLinux, 'dv1394' for DV1394. By default 'v4l'
+ // <standard> : 'pal', 'secam' or 'ntsc'. By default 'ntsc'
+ // The driver name is constructed automatically from the device type:
+ // v4l : /dev/video<camIdx>
+ // dv1394: /dev/dv1394/<camIdx>
+ // If you have different driver name, you can specify the driver name explicitely
+ // instead of device type. Examples of valid filename:
+ // /dev/v4l/video0:pal
+ // /dev/ieee1394/1:ntsc
+ // dv1394:secam
+ // v4l:pal
+ if (file && strstr(file, "1394") != NULL)
+ {
+ // the user specifies a driver, check if it is v4l or d41394
+ inputFormat = av_find_input_format("dv1394");
+ sprintf(filename, "/dev/dv1394/%d", camIdx);
+ } else
+ {
+ inputFormat = av_find_input_format("video4linux");
+ sprintf(filename, "/dev/video%d", camIdx);
+ }
+ if (!inputFormat)
+ // these format should be supported, check ffmpeg compilation
+ return;
+ if (file && strncmp(file, "/dev", 4) == 0)
+ {
+ // user does not specify a driver
+ strncpy(filename, file, sizeof(filename));
+ filename[sizeof(filename)-1] = 0;
+ if ((p = strchr(filename, ':')) != 0)
+ *p = 0;
+ }
+ if (file && (p = strchr(file, ':')) != NULL)
+ formatParams.standard = p+1;
+#endif
+ //frame rate
+ if (m_captRate <= 0.f)
+ m_captRate = defFrameRate;
+ sprintf(rateStr, "%f", m_captRate);
+ av_parse_video_frame_rate(&frameRate, rateStr);
+ // populate format parameters
+ // need to specify the time base = inverse of rate
+ formatParams.time_base.num = frameRate.den;
+ formatParams.time_base.den = frameRate.num;
+ formatParams.width = m_captWidth;
+ formatParams.height = m_captHeight;
+
+ if (openStream(filename, inputFormat, &formatParams) != 0)
+ return;
+
+ // for video capture it is important to do non blocking read
+ m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK;
+ // open base class
+ VideoBase::openCam(file, camIdx);
+}
+
+// play video
+bool VideoFFmpeg::play (void)
+{
+ try
+ {
+ // if object is able to play
+ if (VideoBase::play())
+ {
+ // set video position
+ setPositions();
+ // return success
+ return true;
+ }
+ }
+ CATCH_EXCP;
+ return false;
+}
+
+
+// stop video
+bool VideoFFmpeg::stop (void)
+{
+ try
+ {
+ if (VideoBase::stop())
+ {
+ return true;
+ }
+ }
+ CATCH_EXCP;
+ return false;
+}
+
+
+// set video range
+void VideoFFmpeg::setRange (double start, double stop)
+{
+ try
+ {
+ // set range
+ VideoBase::setRange(start, stop);
+ // set range for video
+ setPositions();
+ }
+ CATCH_EXCP;
+}
+
+// set framerate
+void VideoFFmpeg::setFrameRate (float rate)
+{
+ VideoBase::setFrameRate(rate);
+}
+
+
+// image calculation
+void VideoFFmpeg::calcImage (unsigned int texId)
+{
+ loadFrame();
+}
+
+
+// load frame from video
+void VideoFFmpeg::loadFrame (void)
+{
+ // get actual time
+ double actTime = PIL_check_seconds_timer() - m_startTime;
+ // if video has ended
+ if (m_isFile && actTime * m_frameRate >= m_range[1])
+ {
+ // if repeats are set, decrease them
+ if (m_repeat > 0)
+ --m_repeat;
+ // if video has to be replayed
+ if (m_repeat != 0)
+ {
+ // reset its position
+ actTime -= (m_range[1] - m_range[0]) / m_frameRate;
+ m_startTime += (m_range[1] - m_range[0]) / m_frameRate;
+ }
+ // if video has to be stopped, stop it
+ else
+ m_status = SourceStopped;
+ }
+ // if video is playing
+ if (m_status == SourcePlaying)
+ {
+ // actual frame
+ long actFrame = m_isFile ? long(actTime * actFrameRate()) : m_lastFrame + 1;
+ // if actual frame differs from last frame
+ if (actFrame != m_lastFrame)
+ {
+ // get image
+ if(grabFrame(actFrame))
+ {
+ AVFrame* frame = getFrame();
+ // save actual frame
+ m_lastFrame = actFrame;
+ // init image, if needed
+ init(short(m_codecCtx->width), short(m_codecCtx->height));
+ // process image
+ process((BYTE*)(frame->data[0]));
+ // in case it is an image, automatically stop reading it
+ if (m_isImage)
+ {
+ m_status = SourceStopped;
+ // close the file as we don't need it anymore
+ release();
+ }
+ }
+ }
+ }
+}
+
+
+// set actual position
+void VideoFFmpeg::setPositions (void)
+{
+ // set video start time
+ m_startTime = PIL_check_seconds_timer();
+ // if file is played and actual position is before end position
+ if (m_isFile && !m_eof && m_lastFrame >= 0 && m_lastFrame < m_range[1] * actFrameRate())
+ // continue from actual position
+ m_startTime -= double(m_lastFrame) / actFrameRate();
+ else
+ m_startTime -= m_range[0];
+}
+
+// position pointer in file, position in second
+bool VideoFFmpeg::grabFrame(long position)
+{
+ AVPacket packet;
+ int frameFinished;
+ int posFound = 1;
+ bool frameLoaded = false;
+ long long targetTs = 0;
+
+ // first check if the position that we are looking for is in the preseek range
+ // if so, just read the frame until we get there
+ if (position > m_curPosition + 1
+ && m_preseek
+ && position - (m_curPosition + 1) < m_preseek)
+ {
+ while(av_read_frame(m_formatCtx, &packet)>=0)
+ {
+ if (packet.stream_index == m_videoStream)
+ {
+ avcodec_decode_video(
+ m_codecCtx,
+ m_frame, &frameFinished,
+ packet.data, packet.size);
+ if (frameFinished)
+ m_curPosition++;
+ }
+ av_free_packet(&packet);
+ if (position == m_curPosition+1)
+ break;
+ }
+ }
+ // if the position is not in preseek, do a direct jump
+ if (position != m_curPosition + 1)
+ {
+ double timeBase = av_q2d(m_formatCtx->streams[m_videoStream]->time_base);
+ long long pos = (long long)
+ ((long long) (position - m_preseek) * AV_TIME_BASE / m_baseFrameRate);
+ long long startTs = m_formatCtx->streams[m_videoStream]->start_time;
+
+ if (pos < 0)
+ pos = 0;
+
+ if (startTs != AV_NOPTS_VALUE)
+ pos += (long long)(startTs * AV_TIME_BASE * timeBase);
+
+ if (position <= m_curPosition || !m_eof)
+ {
+ // no need to seek past the end of the file
+ if (av_seek_frame(m_formatCtx, -1, pos, AVSEEK_FLAG_BACKWARD) >= 0)
+ {
+ // current position is now lost, guess a value.
+ // It's not important because it will be set at this end of this function
+ m_curPosition = position - m_preseek - 1;
+ }
+ }
+ // this is the timestamp of the frame we're looking for
+ targetTs = (long long)(((double) position) / m_baseFrameRate / timeBase);
+ if (startTs != AV_NOPTS_VALUE)
+ targetTs += startTs;
+
+ posFound = 0;
+ avcodec_flush_buffers(m_codecCtx);
+ }
+
+ while(av_read_frame(m_formatCtx, &packet)>=0)
+ {
+ if(packet.stream_index == m_videoStream)
+ {
+ avcodec_decode_video(m_codecCtx,
+ m_frame, &frameFinished,
+ packet.data, packet.size);
+
+ if (frameFinished && !posFound)
+ {
+ if (packet.dts >= targetTs)
+ posFound = 1;
+ }
+
+ if(frameFinished && posFound == 1)
+ {
+ AVFrame * input = m_frame;
+
+ /* This means the data wasnt read properly,
+ this check stops crashing */
+ if ( input->data[0]==0 && input->data[1]==0
+ && input->data[2]==0 && input->data[3]==0)
+ {
+ av_free_packet(&packet);
+ break;
+ }
+
+ if (m_deinterlace)
+ {
+ if (avpicture_deinterlace(
+ (AVPicture*) m_frameDeinterlaced,
+ (const AVPicture*) m_frame,
+ m_codecCtx->pix_fmt,
+ m_codecCtx->width,
+ m_codecCtx->height) >= 0)
+ {
+ input = m_frameDeinterlaced;
+ }
+ }
+ // convert to RGB24
+ sws_scale(m_imgConvertCtx,
+ input->data,
+ input->linesize,
+ 0,
+ m_codecCtx->height,
+ m_frameRGB->data,
+ m_frameRGB->linesize);
+ av_free_packet(&packet);
+ frameLoaded = true;
+ break;
+ }
+ }
+ av_free_packet(&packet);
+ }
+ m_eof = !frameLoaded;
+ if (frameLoaded)
+ m_curPosition = position;
+ return frameLoaded;
+}
+
+
+// python methods
+
+
+// cast Image pointer to VideoFFmpeg
+inline VideoFFmpeg * getVideoFFmpeg (PyImage * self)
+{ return static_cast<VideoFFmpeg*>(self->m_image); }
+
+
+// object initialization
+static int VideoFFmpeg_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
+{
+ PyImage * self = reinterpret_cast<PyImage*>(pySelf);
+ // parameters - video source
+ // file name or format type for capture (only for Linux: video4linux or dv1394)
+ char * file = NULL;
+ // capture device number
+ short capt = -1;
+ // capture width, only if capt is >= 0
+ short width = 0;
+ // capture height, only if capt is >= 0
+ short height = 0;
+ // capture rate, only if capt is >= 0
+ float rate = 25.f;
+
+ static char *kwlist[] = {"file", "capture", "rate", "width", "height", NULL};
+
+ // get parameters
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|hfhh", kwlist, &file, &capt,
+ &rate, &width, &height))
+ return -1;
+
+ try
+ {
+ // create video object
+ Video_init<VideoFFmpeg>(self);
+
+ // set thread usage
+ getVideoFFmpeg(self)->initParams(width, height, rate);
+
+ // open video source
+ Video_open(getVideo(self), file, capt);
+ }
+ catch (Exception & exp)
+ {
+ exp.report();
+ return -1;
+ }
+ // initialization succeded
+ return 0;
+}
+
+PyObject * VideoFFmpeg_getPreseek (PyImage *self, void * closure)
+{
+ return Py_BuildValue("h", getFFmpeg(self)->getPreseek());
+}
+
+// set range
+int VideoFFmpeg_setPreseek (PyImage * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ if (value == NULL || !PyInt_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be an integer");
+ return -1;
+ }
+ // set preseek
+ getFFmpeg(self)->setPreseek(PyInt_AsLong(value));
+ // success
+ return 0;
+}
+
+// get deinterlace
+PyObject * VideoFFmpeg_getDeinterlace (PyImage * self, void * closure)
+{
+ if (getFFmpeg(self)->getDeinterlace())
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+// set flip
+int VideoFFmpeg_setDeinterlace (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 deinterlace
+ getFFmpeg(self)->setDeinterlace(value == Py_True);
+ // success
+ return 0;
+}
+
+// methods structure
+static PyMethodDef videoMethods[] =
+{ // methods from VideoBase class
+ {"play", (PyCFunction)Video_play, METH_NOARGS, "Play video"},
+ {"stop", (PyCFunction)Video_stop, METH_NOARGS, "Stop (pause) video"},
+ {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh video - get its status"},
+ {NULL}
+};
+// attributes structure
+static PyGetSetDef videoGetSets[] =
+{ // methods from VideoBase class
+ {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL},
+ {(char*)"range", (getter)Video_getRange, (setter)Video_setRange, (char*)"replay range", NULL},
+ {(char*)"repeat", (getter)Video_getRepeat, (setter)Video_setRepeat, (char*)"repeat count, -1 for infinite repeat", NULL},
+ {(char*)"framerate", (getter)Video_getFrameRate, (setter)Video_setFrameRate, (char*)"frame rate", 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},
+ {(char*)"preseek", (getter)VideoFFmpeg_getPreseek, (setter)VideoFFmpeg_setPreseek, (char*)"nb of frames of preseek", NULL},
+ {(char*)"deinterlace", (getter)VideoFFmpeg_getDeinterlace, (setter)VideoFFmpeg_setDeinterlace, (char*)"deinterlace image", NULL},
+ {NULL}
+};
+
+// python type declaration
+PyTypeObject VideoFFmpegType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.VideoFFmpeg", /*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*/
+ "FFmpeg video source", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ videoMethods, /* tp_methods */
+ 0, /* tp_members */
+ videoGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)VideoFFmpeg_init, /* tp_init */
+ 0, /* tp_alloc */
+ Image_allocNew, /* tp_new */
+};
+
+// object initialization
+static int ImageFFmpeg_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
+{
+ PyImage * self = reinterpret_cast<PyImage*>(pySelf);
+ // parameters - video source
+ // file name or format type for capture (only for Linux: video4linux or dv1394)
+ char * file = NULL;
+
+ // get parameters
+ if (!PyArg_ParseTuple(args, "s", &file))
+ return -1;
+
+ try
+ {
+ // create video object
+ Video_init<VideoFFmpeg>(self);
+
+ getVideoFFmpeg(self)->initParams(0, 0, 1.0, true);
+
+ // open video source
+ Video_open(getVideo(self), file, -1);
+ }
+ catch (Exception & exp)
+ {
+ exp.report();
+ return -1;
+ }
+ // initialization succeded
+ return 0;
+}
+
+PyObject * Image_reload (PyImage * self, PyObject *args)
+{
+ char * newname = NULL;
+
+ if (self->m_image != NULL && PyArg_ParseTuple(args, "|s", &newname))
+ {
+ VideoFFmpeg* video = getFFmpeg(self);
+ // check type of object
+ if (!newname)
+ newname = video->getImageName();
+ if (!newname) {
+ // if not set, retport error
+ PyErr_SetString(PyExc_RuntimeError, "No image file name given");
+ return NULL;
+ }
+ // make sure the previous file is cleared
+ video->release();
+ // open the new file
+ video->openFile(newname);
+ }
+ Py_RETURN_NONE;
+}
+
+// methods structure
+static PyMethodDef imageMethods[] =
+{ // methods from VideoBase class
+ {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh image, i.e. load it"},
+ {"reload", (PyCFunction)Image_reload, METH_VARARGS, "Reload image, i.e. reopen it"},
+ {NULL}
+};
+// attributes structure
+static PyGetSetDef imageGetSets[] =
+{ // methods from VideoBase class
+ {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", 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}
+};
+
+// python type declaration
+PyTypeObject ImageFFmpegType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.ImageFFmpeg", /*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*/
+ "FFmpeg image source", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ imageMethods, /* tp_methods */
+ 0, /* tp_members */
+ imageGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ImageFFmpeg_init, /* tp_init */
+ 0, /* tp_alloc */
+ Image_allocNew, /* tp_new */
+};
+
+#endif //WITH_FFMPEG
+
+
diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.h b/source/gameengine/VideoTexture/VideoFFmpeg.h
new file mode 100644
index 00000000000..e60f1727aab
--- /dev/null
+++ b/source/gameengine/VideoTexture/VideoFFmpeg.h
@@ -0,0 +1,173 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+#if !defined VIDEOFFMPEG_H
+#define VIDEOFFMPEG_H
+
+#ifdef WITH_FFMPEG
+extern "C" {
+#include <ffmpeg/avformat.h>
+#include <ffmpeg/avcodec.h>
+#include <ffmpeg/rational.h>
+#include <ffmpeg/swscale.h>
+}
+
+#if LIBAVFORMAT_VERSION_INT < (49 << 16)
+#define FFMPEG_OLD_FRAME_RATE 1
+#else
+#define FFMPEG_CODEC_IS_POINTER 1
+#endif
+
+#if LIBAVFORMAT_VERSION_INT >= (52 << 16)
+#define FFMPEG_PB_IS_POINTER 1
+#endif
+
+#ifdef FFMPEG_CODEC_IS_POINTER
+static inline AVCodecContext* get_codec_from_stream(AVStream* stream)
+{
+ return stream->codec;
+}
+#else
+static inline AVCodecContext* get_codec_from_stream(AVStream* stream)
+{
+ return &stream->codec;
+}
+#endif
+
+#include "VideoBase.h"
+
+
+// type VideoFFmpeg declaration
+class VideoFFmpeg : public VideoBase
+{
+public:
+ /// constructor
+ VideoFFmpeg (HRESULT * hRslt);
+ /// destructor
+ virtual ~VideoFFmpeg ();
+
+ /// set initial parameters
+ void initParams (short width, short height, float rate, bool image=false);
+ /// open video/image file
+ virtual void openFile (char * file);
+ /// open video capture device
+ virtual void openCam (char * driver, short camIdx);
+
+ /// release video source
+ virtual bool release (void);
+
+ /// play video
+ virtual bool play (void);
+ /// stop/pause video
+ virtual bool stop (void);
+
+ /// set play range
+ virtual void setRange (double start, double stop);
+ /// set frame rate
+ virtual void setFrameRate (float rate);
+ // some specific getters and setters
+ int getPreseek(void) { return m_preseek; }
+ void setPreseek(int preseek) { if (preseek >= 0) m_preseek = preseek; }
+ bool getDeinterlace(void) { return m_deinterlace; }
+ void setDeinterlace(bool deinterlace) { m_deinterlace = deinterlace; }
+ char *getImageName(void) { return (m_isImage) ? m_imageName.Ptr() : NULL; }
+
+protected:
+
+ // format and codec information
+ AVCodec *m_codec;
+ AVFormatContext *m_formatCtx;
+ AVCodecContext *m_codecCtx;
+ // raw frame extracted from video file
+ AVFrame *m_frame;
+ // deinterlaced frame if codec requires it
+ AVFrame *m_frameDeinterlaced;
+ // decoded RGB24 frame if codec requires it
+ AVFrame *m_frameRGB;
+ // conversion from raw to RGB is done with sws_scale
+ struct SwsContext *m_imgConvertCtx;
+ // should the codec be deinterlaced?
+ bool m_deinterlace;
+ // number of frame of preseek
+ int m_preseek;
+ // order number of stream holding the video in format context
+ int m_videoStream;
+
+ // the actual frame rate
+ double m_baseFrameRate;
+
+ /// last displayed frame
+ long m_lastFrame;
+
+ /// end of file reached
+ bool m_eof;
+
+ /// current file pointer position in file expressed in frame number
+ long m_curPosition;
+
+ /// time of video play start
+ double m_startTime;
+
+ /// width of capture in pixel
+ short m_captWidth;
+
+ /// height of capture in pixel
+ short m_captHeight;
+
+ /// frame rate of capture in frames per seconds
+ float m_captRate;
+
+ /// is file an image?
+ bool m_isImage;
+
+ /// keep last image name
+ STR_String m_imageName;
+
+ /// image calculation
+ virtual void calcImage (unsigned int texId);
+
+ /// load frame from video
+ void loadFrame (void);
+
+ /// set actual position
+ void setPositions (void);
+
+ /// get actual framerate
+ double actFrameRate (void) { return m_frameRate * m_baseFrameRate; }
+
+ /// common function to video file and capture
+ int openStream(const char *filename, AVInputFormat *inputFormat, AVFormatParameters *formatParams);
+
+ /// check if a frame is available and load it in pFrame, return true if a frame could be retrieved
+ bool grabFrame(long frame);
+
+ /// return the frame in RGB24 format, the image data is found in AVFrame.data[0]
+ AVFrame* getFrame(void) { return m_frameRGB; }
+};
+
+inline VideoFFmpeg * getFFmpeg (PyImage * self)
+{
+ return static_cast<VideoFFmpeg*>(self->m_image);
+}
+
+#endif //WITH_FFMPEG
+
+#endif
diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp
new file mode 100644
index 00000000000..b38882f8164
--- /dev/null
+++ b/source/gameengine/VideoTexture/blendVideoTex.cpp
@@ -0,0 +1,194 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexure library
+
+Copyright (c) 2006 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#include <PyObjectPlus.h>
+
+#include <RAS_GLExtensionManager.h>
+
+#include <RAS_IPolygonMaterial.h>
+
+//Old API
+//#include "TexPlayer.h"
+//#include "TexImage.h"
+//#include "TexFrameBuff.h"
+
+//#include "TexPlayerGL.h"
+
+#include "ImageBase.h"
+#include "FilterBase.h"
+#include "Texture.h"
+
+#include "Exception.h"
+
+
+// get material id
+static PyObject * getMaterialID (PyObject *self, PyObject *args)
+{
+ // parameters - game object with video texture
+ PyObject * obj = NULL;
+ // material name
+ char * matName;
+
+ // get parameters
+ if (!PyArg_ParseTuple(args, "Os", &obj, &matName))
+ return NULL;
+ // get material id
+ short matID = getMaterialID(obj, matName);
+ // if material was not found, report errot
+ if (matID < 0)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "object doesn't have material with given name");
+ return NULL;
+ }
+ // return material ID
+ return Py_BuildValue("h", matID);
+}
+
+
+// get last error description
+static PyObject * getLastError (PyObject *self, PyObject *args)
+{
+ return Py_BuildValue("s", Exception::m_lastError.c_str());
+}
+
+// set log file
+static PyObject * setLogFile (PyObject *self, PyObject *args)
+{
+ // get parameters
+ if (!PyArg_ParseTuple(args, "s", &Exception::m_logFile))
+ return Py_BuildValue("i", -1);
+ // log file was loaded
+ return Py_BuildValue("i", 0);
+}
+
+
+// image to numpy array
+static PyObject * imageToArray (PyObject * self, PyObject *args)
+{
+ // parameter is Image object
+ PyObject * pyImg;
+ if (!PyArg_ParseTuple(args, "O", &pyImg) || !pyImageTypes.in(pyImg->ob_type))
+ {
+ // if object is incorect, report error
+ PyErr_SetString(PyExc_TypeError, "The value must be a image source object");
+ return NULL;
+ }
+ // get image structure
+ PyImage * img = reinterpret_cast<PyImage*>(pyImg);
+ // create array object
+ unsigned int * imgBuff = img->m_image->getImage();
+ // if image is available, convert it to array
+ if (imgBuff != NULL)
+ // Nasty problem here: the image buffer is an array of integers
+ // in the processor endian format. The user must take care of that in the script.
+ // Need to find an elegant solution to this problem
+ return Py_BuildValue("s#", imgBuff, img->m_image->getBuffSize());
+ // otherwise return None
+ Py_RETURN_NONE;
+}
+
+
+// metody modulu
+static PyMethodDef moduleMethods[] =
+{
+ {"materialID", getMaterialID, METH_VARARGS, "Gets object's Blender Material ID"},
+ {"getLastError", getLastError, METH_NOARGS, "Gets last error description"},
+ {"setLogFile", setLogFile, METH_VARARGS, "Sets log file name"},
+ {"imageToArray", imageToArray, METH_VARARGS, "get array from image source"},
+ {NULL} /* Sentinel */
+};
+
+#if WITH_FFMPEG
+extern PyTypeObject VideoFFmpegType;
+extern PyTypeObject ImageFFmpegType;
+#endif
+extern PyTypeObject FilterBlueScreenType;
+extern PyTypeObject FilterGrayType;
+extern PyTypeObject FilterColorType;
+extern PyTypeObject FilterLevelType;
+extern PyTypeObject FilterNormalType;
+extern PyTypeObject FilterRGB24Type;
+extern PyTypeObject FilterRGBA32Type;
+extern PyTypeObject FilterBGR24Type;
+extern PyTypeObject ImageBuffType;
+extern PyTypeObject ImageMixType;
+extern PyTypeObject ImageRenderType;
+extern PyTypeObject ImageViewportType;
+extern PyTypeObject ImageViewportType;
+
+
+static void registerAllTypes(void)
+{
+#if WITH_FFMPEG
+ pyImageTypes.add(&VideoFFmpegType, "VideoFFmpeg");
+ pyImageTypes.add(&ImageFFmpegType, "ImageFFmpeg");
+#endif
+ pyImageTypes.add(&ImageBuffType, "ImageBuff");
+ pyImageTypes.add(&ImageMixType, "ImageMix");
+ //pyImageTypes.add(&ImageRenderType, "ImageRender");
+ pyImageTypes.add(&ImageViewportType, "ImageViewport");
+
+ pyFilterTypes.add(&FilterBlueScreenType, "FilterBlueScreen");
+ pyFilterTypes.add(&FilterGrayType, "FilterGray");
+ pyFilterTypes.add(&FilterColorType, "FilterColor");
+ pyFilterTypes.add(&FilterLevelType, "FilterLevel");
+ pyFilterTypes.add(&FilterNormalType, "FilterNormal");
+ pyFilterTypes.add(&FilterRGB24Type, "FilterRGB24");
+ pyFilterTypes.add(&FilterRGBA32Type, "FilterRGBA32");
+ pyFilterTypes.add(&FilterBGR24Type, "FilterBGR24");
+}
+
+PyObject* initVideoTexture(void)
+{
+ // initialize GL extensions
+ //bgl::InitExtensions(0);
+
+ // prepare classes
+ registerAllTypes();
+ registerAllExceptions();
+
+ if (!pyImageTypes.ready())
+ return NULL;
+ if (!pyFilterTypes.ready())
+ return NULL;
+ if (PyType_Ready(&TextureType) < 0)
+ return NULL;
+
+ PyObject * m = Py_InitModule4("VideoTexture", moduleMethods,
+ "Module that allows to play video files on textures in GameBlender.",
+ (PyObject*)NULL,PYTHON_API_VERSION);
+ if (m == NULL)
+ return NULL;
+
+ // initialize classes
+ pyImageTypes.reg(m);
+ pyFilterTypes.reg(m);
+
+ Py_INCREF(&TextureType);
+ PyModule_AddObject(m, (char*)"Texture", (PyObject*)&TextureType);
+
+ // init last error description
+ Exception::m_lastError[0] = '\0';
+ return m;
+}
+
+// registration to Image types, put here because of silly linker bug