From 3c9520f92fc0fc69614a1eea37a1e2d72461e50d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 1 Nov 2008 22:04:41 +0000 Subject: [PATCH] svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r17236:HEAD --- config/darwin-config.py | 4 +- config/openbsd3-config.py | 4 +- config/sunos5-config.py | 4 +- config/win32-mingw-config.py | 2 +- config/win32-vc-config.py | 1 + doc/blender-scons.txt | 6 +- intern/ghost/intern/GHOST_WindowWin32.cpp | 2 +- projectfiles_vc7/blender/blender.sln | 17 + projectfiles_vc7/blender/blender.vcproj | 2 +- .../blender/blenlib/BLI_blenlib.vcproj | 6 + projectfiles_vc7/blender/src/BL_src.vcproj | 3 + source/blender/blenkernel/intern/CCGSubSurf.c | 16 +- source/blender/imbuf/intern/util.c | 2 + source/blender/python/api2_2x/matrix.c | 4 +- source/blender/render/intern/source/envmap.c | 9 +- source/blender/render/intern/source/sss.c | 24 +- source/blender/src/interface.c | 2 +- .../BlenderRoutines/BL_KetsjiEmbedStart.cpp | 1 + source/gameengine/CMakeLists.txt | 1 + source/gameengine/Ketsji/BL_Texture.h | 8 + source/gameengine/Ketsji/KX_BlenderMaterial.h | 3 + source/gameengine/Ketsji/KX_Camera.cpp | 2 +- source/gameengine/Ketsji/KX_GameObject.cpp | 8 +- source/gameengine/Ketsji/KX_KetsjiEngine.cpp | 9 +- source/gameengine/Ketsji/KX_KetsjiEngine.h | 5 + .../gameengine/Ketsji/KX_ParentActuator.cpp | 2 +- source/gameengine/Ketsji/KX_PythonInit.cpp | 9 +- source/gameengine/Ketsji/KX_PythonInit.h | 9 +- .../Rasterizer/RAS_2DFilterManager.cpp | 179 +++-- .../Rasterizer/RAS_2DFilterManager.h | 2 + source/gameengine/SConscript | 3 +- source/gameengine/VideoTexture/BlendType.h | 75 ++ source/gameengine/VideoTexture/CMakeLists.txt | 61 ++ source/gameengine/VideoTexture/Common.h | 55 ++ source/gameengine/VideoTexture/Exception.cpp | 209 +++++ source/gameengine/VideoTexture/Exception.h | 210 +++++ source/gameengine/VideoTexture/FilterBase.cpp | 150 ++++ source/gameengine/VideoTexture/FilterBase.h | 132 +++ .../VideoTexture/FilterBlueScreen.cpp | 178 +++++ .../VideoTexture/FilterBlueScreen.h | 98 +++ .../gameengine/VideoTexture/FilterColor.cpp | 350 ++++++++ source/gameengine/VideoTexture/FilterColor.h | 164 ++++ .../gameengine/VideoTexture/FilterNormal.cpp | 162 ++++ source/gameengine/VideoTexture/FilterNormal.h | 98 +++ .../gameengine/VideoTexture/FilterSource.cpp | 125 +++ source/gameengine/VideoTexture/FilterSource.h | 233 ++++++ source/gameengine/VideoTexture/ImageBase.cpp | 529 ++++++++++++ source/gameengine/VideoTexture/ImageBase.h | 349 ++++++++ source/gameengine/VideoTexture/ImageBuff.cpp | 166 ++++ source/gameengine/VideoTexture/ImageBuff.h | 51 ++ source/gameengine/VideoTexture/ImageMix.cpp | 205 +++++ source/gameengine/VideoTexture/ImageMix.h | 123 +++ .../gameengine/VideoTexture/ImageRender.cpp | 265 ++++++ source/gameengine/VideoTexture/ImageRender.h | 90 +++ .../gameengine/VideoTexture/ImageViewport.cpp | 298 +++++++ .../gameengine/VideoTexture/ImageViewport.h | 84 ++ source/gameengine/VideoTexture/Makefile | 65 ++ source/gameengine/VideoTexture/PyTypeList.cpp | 83 ++ source/gameengine/VideoTexture/PyTypeList.h | 85 ++ source/gameengine/VideoTexture/SConscript | 33 + source/gameengine/VideoTexture/Texture.cpp | 463 +++++++++++ source/gameengine/VideoTexture/Texture.h | 87 ++ source/gameengine/VideoTexture/VideoBase.cpp | 183 +++++ source/gameengine/VideoTexture/VideoBase.h | 185 +++++ .../gameengine/VideoTexture/VideoFFmpeg.cpp | 753 ++++++++++++++++++ source/gameengine/VideoTexture/VideoFFmpeg.h | 163 ++++ .../gameengine/VideoTexture/blendVideoTex.cpp | 207 +++++ 67 files changed, 6996 insertions(+), 120 deletions(-) create mode 100644 source/gameengine/VideoTexture/BlendType.h create mode 100644 source/gameengine/VideoTexture/CMakeLists.txt create mode 100644 source/gameengine/VideoTexture/Common.h create mode 100644 source/gameengine/VideoTexture/Exception.cpp create mode 100644 source/gameengine/VideoTexture/Exception.h create mode 100644 source/gameengine/VideoTexture/FilterBase.cpp create mode 100644 source/gameengine/VideoTexture/FilterBase.h create mode 100644 source/gameengine/VideoTexture/FilterBlueScreen.cpp create mode 100644 source/gameengine/VideoTexture/FilterBlueScreen.h create mode 100644 source/gameengine/VideoTexture/FilterColor.cpp create mode 100644 source/gameengine/VideoTexture/FilterColor.h create mode 100644 source/gameengine/VideoTexture/FilterNormal.cpp create mode 100644 source/gameengine/VideoTexture/FilterNormal.h create mode 100644 source/gameengine/VideoTexture/FilterSource.cpp create mode 100644 source/gameengine/VideoTexture/FilterSource.h create mode 100644 source/gameengine/VideoTexture/ImageBase.cpp create mode 100644 source/gameengine/VideoTexture/ImageBase.h create mode 100644 source/gameengine/VideoTexture/ImageBuff.cpp create mode 100644 source/gameengine/VideoTexture/ImageBuff.h create mode 100644 source/gameengine/VideoTexture/ImageMix.cpp create mode 100644 source/gameengine/VideoTexture/ImageMix.h create mode 100644 source/gameengine/VideoTexture/ImageRender.cpp create mode 100644 source/gameengine/VideoTexture/ImageRender.h create mode 100644 source/gameengine/VideoTexture/ImageViewport.cpp create mode 100644 source/gameengine/VideoTexture/ImageViewport.h create mode 100644 source/gameengine/VideoTexture/Makefile create mode 100644 source/gameengine/VideoTexture/PyTypeList.cpp create mode 100644 source/gameengine/VideoTexture/PyTypeList.h create mode 100644 source/gameengine/VideoTexture/SConscript create mode 100644 source/gameengine/VideoTexture/Texture.cpp create mode 100644 source/gameengine/VideoTexture/Texture.h create mode 100644 source/gameengine/VideoTexture/VideoBase.cpp create mode 100644 source/gameengine/VideoTexture/VideoBase.h create mode 100644 source/gameengine/VideoTexture/VideoFFmpeg.cpp create mode 100644 source/gameengine/VideoTexture/VideoFFmpeg.h create mode 100644 source/gameengine/VideoTexture/blendVideoTex.cpp diff --git a/config/darwin-config.py b/config/darwin-config.py index ccc3eb5a0d0..547d655b531 100644 --- a/config/darwin-config.py +++ b/config/darwin-config.py @@ -251,9 +251,9 @@ else: ## CC = 'gcc' CXX = 'g++' -C_WARN = ' -Wall -Wno-long-double -Wdeclaration-after-statement ' +C_WARN = ['-Wdeclaration-after-statement'] -CC_WARN = ' -Wall -Wno-long-double' +CC_WARN = ['-Wall', '-Wno-long-double'] ##FIX_STUBS_WARNINGS = -Wno-unused diff --git a/config/openbsd3-config.py b/config/openbsd3-config.py index b2112c84b98..0a4f75e3bcc 100644 --- a/config/openbsd3-config.py +++ b/config/openbsd3-config.py @@ -145,9 +145,9 @@ REL_CCFLAGS = ['-O2'] ## CC = 'gcc' CXX = 'g++' -C_WARN = '-Wall -Wdeclaration-after-statement' +C_WARN = ['-Wdeclaration-after-statement'] -CC_WARN = '-Wall' +CC_WARN = ['-Wall'] ##FIX_STUBS_WARNINGS = -Wno-unused diff --git a/config/sunos5-config.py b/config/sunos5-config.py index bb6c5d89e46..2343ce69060 100644 --- a/config/sunos5-config.py +++ b/config/sunos5-config.py @@ -159,9 +159,9 @@ REL_CCFLAGS = ['-O2'] ##ARFLAGS = ruv ##ARFLAGSQUIET = ru ## -C_WARN = '-Wall -Wno-char-subscripts -Wdeclaration-after-statement' +C_WARN = ['-Wno-char-subscripts', '-Wdeclaration-after-statement'] -CC_WARN = '-Wall' +CC_WARN = ['-Wall'] ##FIX_STUBS_WARNINGS = -Wno-unused diff --git a/config/win32-mingw-config.py b/config/win32-mingw-config.py index d7ecad33bca..bdeca1ddc91 100644 --- a/config/win32-mingw-config.py +++ b/config/win32-mingw-config.py @@ -153,7 +153,7 @@ CXXFLAGS = ['-pipe', '-mwindows', '-funsigned-char', '-fno-strict-aliasing' ] REL_CFLAGS = [ '-O2' ] REL_CCFLAGS = [ '-O2' ] -C_WARN = [ '-Wall' , '-Wno-char-subscripts', '-Wdeclaration-after-statement' ] +C_WARN = [ '-Wno-char-subscripts', '-Wdeclaration-after-statement' ] CC_WARN = [ '-Wall' ] diff --git a/config/win32-vc-config.py b/config/win32-vc-config.py index 6cc09748a10..a5aa76c2868 100644 --- a/config/win32-vc-config.py +++ b/config/win32-vc-config.py @@ -161,6 +161,7 @@ CC = 'cl.exe' CXX = 'cl.exe' CCFLAGS = ['/nologo', '/Ob1', '/J', '/W3', '/Gd', '/MT'] +CXXFLAGS = ['/EHsc'] BF_DEBUG_CCFLAGS = ['/Zi', '/FR${TARGET}.sbr'] diff --git a/doc/blender-scons.txt b/doc/blender-scons.txt index 8578d3f2fd4..f7ea7767441 100644 --- a/doc/blender-scons.txt +++ b/doc/blender-scons.txt @@ -1,9 +1,5 @@ $Id$ - Note: The current official release of SCons is 0.98, but - our system still works for 0.97. However, this will be fixed - soon. - Blenders SCons build scripts ============================ @@ -31,7 +27,7 @@ $Id$ To build Blender with the SCons scripts you need a full Python install, version 2.4 or later (http://www.python.org) and a SCons - installation, version v0.97 (http://www.scons.org). + installation, version v1.1.0 (http://www.scons.org). Check from the page http://www.blender.org/development/building-blender/getting-dependencies/ diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 6a06f4d715a..2094ae87c67 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -854,7 +854,7 @@ static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd) { static int EnumPixelFormats(HDC hdc) { int iPixelFormat; int i, n, w, weight = 0; - PIXELFORMATDESCRIPTOR pfd, pfd_fallback; + PIXELFORMATDESCRIPTOR pfd; /* we need a device context to do anything */ if(!hdc) return 0; diff --git a/projectfiles_vc7/blender/blender.sln b/projectfiles_vc7/blender/blender.sln index eb235531984..c1628614642 100644 --- a/projectfiles_vc7/blender/blender.sln +++ b/projectfiles_vc7/blender/blender.sln @@ -17,6 +17,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blender", "blender.vcproj", {138DD16C-CC78-4F6C-A898-C8DA68D89067} = {138DD16C-CC78-4F6C-A898-C8DA68D89067} {415BFD6E-64CF-422B-AF88-C07F040A7292} = {415BFD6E-64CF-422B-AF88-C07F040A7292} {106AE171-0083-41D6-A949-20DB0E8DC251} = {106AE171-0083-41D6-A949-20DB0E8DC251} + {670EC17A-0548-4BBF-A27B-636C7C188139} = {670EC17A-0548-4BBF-A27B-636C7C188139} {4C3AB78A-52CA-4276-A041-39776E52D8C8} = {4C3AB78A-52CA-4276-A041-39776E52D8C8} {6B801390-5F95-4F07-81A7-97FBA046AACC} = {6B801390-5F95-4F07-81A7-97FBA046AACC} {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} = {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} @@ -239,6 +240,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_gpu", "gpu\BL_gpu.vcproj ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TEX_Video", "..\gameengine\videotexture\TEX_Video.vcproj", "{670EC17A-0548-4BBF-A27B-636C7C188139}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution 3D Plugin Debug = 3D Plugin Debug @@ -815,6 +820,18 @@ Global {138DD16C-CC78-4F6C-A898-C8DA68D89067}.Debug.Build.0 = BlenderPlayer Debug|Win32 {138DD16C-CC78-4F6C-A898-C8DA68D89067}.Release.ActiveCfg = BlenderPlayer Release|Win32 {138DD16C-CC78-4F6C-A898-C8DA68D89067}.Release.Build.0 = BlenderPlayer Release|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.3D Plugin Debug.ActiveCfg = Debug|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.3D Plugin Release.ActiveCfg = Release|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.Blender Debug.ActiveCfg = Debug|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.Blender Debug.Build.0 = Debug|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.Blender Release.ActiveCfg = Release|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.Blender Release.Build.0 = Release|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.BlenderPlayer Debug.ActiveCfg = Debug|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.BlenderPlayer Debug.Build.0 = Debug|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.BlenderPlayer Release.ActiveCfg = Release|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.BlenderPlayer Release.Build.0 = Release|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.Debug.ActiveCfg = Debug|Win32 + {670EC17A-0548-4BBF-A27B-636C7C188139}.Release.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/projectfiles_vc7/blender/blender.vcproj b/projectfiles_vc7/blender/blender.vcproj index 26cb3fb79e1..ef6900b7b75 100644 --- a/projectfiles_vc7/blender/blender.vcproj +++ b/projectfiles_vc7/blender/blender.vcproj @@ -124,7 +124,7 @@ ECHO Done Name="VCLinkerTool" AdditionalOptions="/MACHINE:I386 " - AdditionalDependencies="SDL.lib freetype2ST.lib ftgl_static.lib gnu_gettext.lib qtmlClient.lib openal_static.lib libsoundsystem.lib libopenalsoundsystem.lib libdummysoundsystem.lib libguardedalloc.lib libbsp.lib libbmfont.lib libghost.lib libstring.lib ws2_32.lib dxguid.lib opengl32.lib libjpeg.lib glu32.lib vfw32.lib winmm.lib libdecimation.lib libiksolver.lib libpng_st.lib zlib.lib libmoto.lib solid.lib qhull.lib libopennl.lib Bullet.lib python25_d.lib libelbeem.lib libboolop.lib pthreadVSE2.lib pthreadVC2.lib libtiff.lib broad.lib complex.lib convex.lib memutil.lib verse.lib Half.lib Iex.lib Imath.lib IlmImf.lib IlmThread.lib avcodec-51.lib avformat-52.lib avutil-49.lib swscale-0.lib glew.lib" + AdditionalDependencies="SDL.lib freetype2ST.lib ftgl_static.lib gnu_gettext.lib qtmlClient.lib openal_static.lib libsoundsystem.lib libopenalsoundsystem.lib libdummysoundsystem.lib libguardedalloc.lib libbsp.lib libbmfont.lib libghost.lib libstring.lib ws2_32.lib dxguid.lib opengl32.lib libjpeg.lib glu32.lib vfw32.lib winmm.lib libdecimation.lib libiksolver.lib libpng_st.lib zlib.lib libmoto.lib solid.lib qhull.lib libopennl.lib Bullet.lib python25_d.lib libelbeem.lib libboolop.lib pthreadVSE2.lib pthreadVC2.lib libtiff.lib broad.lib complex.lib convex.lib memutil.lib verse.lib Half.lib Iex.lib Imath.lib IlmImf.lib IlmThread.lib avcodec-51.lib avformat-52.lib avdevice-52.lib avutil-49.lib swscale-0.lib glew.lib" ShowProgress="0" OutputFile="..\..\bin\debug\blender.exe" LinkIncremental="2" diff --git a/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj b/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj index 0dfbcaa5577..aadef58f84a 100644 --- a/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj +++ b/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj @@ -382,6 +382,9 @@ + + @@ -458,6 +461,9 @@ + + diff --git a/projectfiles_vc7/blender/src/BL_src.vcproj b/projectfiles_vc7/blender/src/BL_src.vcproj index 80694690107..d6e436635cb 100644 --- a/projectfiles_vc7/blender/src/BL_src.vcproj +++ b/projectfiles_vc7/blender/src/BL_src.vcproj @@ -121,6 +121,9 @@ + + diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index ce4458b4307..cee032f364e 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -1245,9 +1245,11 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) { } } - avgSharpness /= sharpCount; - if (avgSharpness>1.0) { - avgSharpness = 1.0; + if(sharpCount) { + avgSharpness /= sharpCount; + if (avgSharpness>1.0) { + avgSharpness = 1.0; + } } if (seam && seamEdges < 2) @@ -1543,9 +1545,11 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) { } } - avgSharpness /= sharpCount; - if (avgSharpness>1.0) { - avgSharpness = 1.0; + if(sharpCount) { + avgSharpness /= sharpCount; + if (avgSharpness>1.0) { + avgSharpness = 1.0; + } } if (seam && seamEdges < 2) diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index 4f6730db1f1..cd58d9e4e96 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -64,6 +64,7 @@ #ifdef WITH_FFMPEG #include #include +//#include #if LIBAVFORMAT_VERSION_INT < (49 << 16) #define FFMPEG_OLD_FRAME_RATE 1 @@ -236,6 +237,7 @@ void do_init_ffmpeg() if (!ffmpeg_init) { ffmpeg_init = 1; av_register_all(); + //avdevice_register_all(); } } diff --git a/source/blender/python/api2_2x/matrix.c b/source/blender/python/api2_2x/matrix.c index 79ca5e09b25..7802de822cb 100644 --- a/source/blender/python/api2_2x/matrix.c +++ b/source/blender/python/api2_2x/matrix.c @@ -246,8 +246,8 @@ PyObject *Matrix_Invert(MatrixObject * self) /*calculate the classical adjoint*/ if(self->rowSize == 2) { mat[0] = self->matrix[1][1]; - mat[1] = -self->matrix[1][0]; - mat[2] = -self->matrix[0][1]; + mat[1] = -self->matrix[0][1]; + mat[2] = -self->matrix[1][0]; mat[3] = self->matrix[0][0]; } else if(self->rowSize == 3) { Mat3Adj((float (*)[3]) mat,(float (*)[3]) *self->matrix); diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index d281ac9e5c8..13fa9b17b71 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -439,12 +439,19 @@ static void render_envmap(Render *re, EnvMap *env) if(re->test_break()==0) { RenderLayer *rl= envre->result->layers.first; + int y; + char *alpha; ibuf= IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect, 0); ibuf->rect_float= rl->rectf; IMB_rect_from_float(ibuf); ibuf->rect_float= NULL; - + + /* envmap renders without alpha */ + alpha= ((char *)ibuf->rect)+3; + for(y= ibuf->x*ibuf->y - 1; y>=0; y--, alpha+=4) + *alpha= 255; + env->cube[part]= ibuf; } diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c index 9fb48a08503..9bde6675798 100644 --- a/source/blender/render/intern/source/sss.c +++ b/source/blender/render/intern/source/sss.c @@ -451,13 +451,13 @@ static void compute_radiance(ScatterTree *tree, float *co, float *rad) VECCOPY(rdsum, result.rdsum); VECADD(backrdsum, result.rdsum, result.backrdsum); - if(rdsum[0] > 0.0f) rad[0]= tree->ss[0]->color*rad[0]/rdsum[0]; - if(rdsum[1] > 0.0f) rad[1]= tree->ss[1]->color*rad[1]/rdsum[1]; - if(rdsum[2] > 0.0f) rad[2]= tree->ss[2]->color*rad[2]/rdsum[2]; + if(rdsum[0] > 1e-16f) rad[0]= tree->ss[0]->color*rad[0]/rdsum[0]; + if(rdsum[1] > 1e-16f) rad[1]= tree->ss[1]->color*rad[1]/rdsum[1]; + if(rdsum[2] > 1e-16f) rad[2]= tree->ss[2]->color*rad[2]/rdsum[2]; - if(backrdsum[0] > 0.0f) backrad[0]= tree->ss[0]->color*backrad[0]/backrdsum[0]; - if(backrdsum[1] > 0.0f) backrad[1]= tree->ss[1]->color*backrad[1]/backrdsum[1]; - if(backrdsum[2] > 0.0f) backrad[2]= tree->ss[2]->color*backrad[2]/backrdsum[2]; + if(backrdsum[0] > 1e-16f) backrad[0]= tree->ss[0]->color*backrad[0]/backrdsum[0]; + if(backrdsum[1] > 1e-16f) backrad[1]= tree->ss[1]->color*backrad[1]/backrdsum[1]; + if(backrdsum[2] > 1e-16f) backrad[2]= tree->ss[2]->color*backrad[2]/backrdsum[2]; rad[0]= MAX2(rad[0], backrad[0]); rad[1]= MAX2(rad[1], backrad[1]); @@ -504,20 +504,20 @@ static void sum_leaf_radiance(ScatterTree *tree, ScatterNode *node) } } - if(node->area > 0) { + if(node->area > 1e-16f) { inv= 1.0/node->area; node->rad[0] *= inv; node->rad[1] *= inv; node->rad[2] *= inv; } - if(node->backarea > 0) { + if(node->backarea > 1e-16f) { inv= 1.0/node->backarea; node->backrad[0] *= inv; node->backrad[1] *= inv; node->backrad[2] *= inv; } - if(totrad > 0.0f) { + if(totrad > 1e-16f) { inv= 1.0/totrad; node->co[0] *= inv; node->co[1] *= inv; @@ -578,20 +578,20 @@ static void sum_branch_radiance(ScatterTree *tree, ScatterNode *node) node->backarea += subnode->backarea; } - if(node->area > 0) { + if(node->area > 1e-16f) { inv= 1.0/node->area; node->rad[0] *= inv; node->rad[1] *= inv; node->rad[2] *= inv; } - if(node->backarea > 0) { + if(node->backarea > 1e-16f) { inv= 1.0/node->backarea; node->backrad[0] *= inv; node->backrad[1] *= inv; node->backrad[2] *= inv; } - if(totrad > 0.0f) { + if(totrad > 1e-16f) { inv= 1.0/totrad; node->co[0] *= inv; node->co[1] *= inv; diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c index 28baf87baa1..9decbd9a1ce 100644 --- a/source/blender/src/interface.c +++ b/source/blender/src/interface.c @@ -1808,7 +1808,7 @@ static int ui_do_but_TEX(uiBut *but) ((G.qual & LR_COMMANDKEY) || (G.qual & LR_CTRLKEY)) && ((dev==XKEY) || (dev==CKEY) || (dev==VKEY)) ) { - char buf[UI_MAX_DRAW_STR]={0}; + char buf[UI_MAX_DRAW_STR+1]={0}; /* paste */ if (dev==VKEY) { diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 9fbdc3fa1c9..2d91bbcd7c1 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -364,6 +364,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, initGameKeys(); initPythonConstraintBinding(); initMathutils(); + initVideoTexture(); if (sceneconverter) { diff --git a/source/gameengine/CMakeLists.txt b/source/gameengine/CMakeLists.txt index 93de588ba00..3ea788791e2 100644 --- a/source/gameengine/CMakeLists.txt +++ b/source/gameengine/CMakeLists.txt @@ -40,6 +40,7 @@ SUBDIRS( SceneGraph Physics/Bullet Physics/Sumo + VideoTexture ) IF(WITH_PLAYER) diff --git a/source/gameengine/Ketsji/BL_Texture.h b/source/gameengine/Ketsji/BL_Texture.h index 0d0c7a277f2..830ffceb0f7 100644 --- a/source/gameengine/Ketsji/BL_Texture.h +++ b/source/gameengine/Ketsji/BL_Texture.h @@ -59,6 +59,14 @@ public: void SetMapping(int mode); void DisableUnit(); void setTexEnv(BL_Material *mat, bool modulate=false); + unsigned int swapTexture (unsigned int newTex) { + // swap texture codes + unsigned int tmp = mTexture; + mTexture = newTex; + // return original texture code + return tmp; + } + }; #endif//__BL_TEXTURE_H__ diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index 4ddf5a924df..b858fa3754c 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -67,6 +67,9 @@ public: MTFace* GetMTFace(void) const; unsigned int* GetMCol(void) const; + BL_Texture * getTex (unsigned int idx) { + return (idx < MAXTEX) ? mTextures + idx : NULL; + } // for ipos void UpdateIPO( diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp index 3830d422138..53b3e348a36 100644 --- a/source/gameengine/Ketsji/KX_Camera.cpp +++ b/source/gameengine/Ketsji/KX_Camera.cpp @@ -793,7 +793,7 @@ KX_PYMETHODDEF_DOC(KX_Camera, setOnTop, { class KX_Scene* scene; - scene = PHY_GetActiveScene(); + scene = KX_GetActiveScene(); MT_assert(scene); scene->SetCameraOnTop(this); Py_Return; diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 739c122a5ef..a168beb9a70 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -1027,7 +1027,7 @@ bool KX_GameObject::ConvertPythonVectorArgs(PyObject* args, PyObject* KX_GameObject::PyReplaceMesh(PyObject* self, PyObject* value) { - KX_Scene *scene = PHY_GetActiveScene(); + KX_Scene *scene = KX_GetActiveScene(); char* meshname; void* mesh_pt; @@ -1050,7 +1050,7 @@ PyObject* KX_GameObject::PyReplaceMesh(PyObject* self, PyObject* value) PyObject* KX_GameObject::PyEndObject(PyObject* self) { - KX_Scene *scene = PHY_GetActiveScene(); + KX_Scene *scene = KX_GetActiveScene(); scene->DelayedRemoveObject(this); Py_RETURN_NONE; @@ -1447,7 +1447,7 @@ PyObject* KX_GameObject::PySetParent(PyObject* self, PyObject* value) // The object we want to set as parent CValue *m_ob = (CValue*)value; KX_GameObject *obj = ((KX_GameObject*)m_ob); - KX_Scene *scene = PHY_GetActiveScene(); + KX_Scene *scene = KX_GetActiveScene(); this->SetParent(scene, obj); @@ -1456,7 +1456,7 @@ PyObject* KX_GameObject::PySetParent(PyObject* self, PyObject* value) PyObject* KX_GameObject::PyRemoveParent(PyObject* self) { - KX_Scene *scene = PHY_GetActiveScene(); + KX_Scene *scene = KX_GetActiveScene(); this->RemoveParent(scene); Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index b1ab8e3e7de..8bcda4479e1 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -470,7 +470,7 @@ else m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); // set Python hooks for each scene PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); - PHY_SetActiveScene(scene); + KX_SetActiveScene(scene); scene->GetPhysicsEnvironment()->endFrame(); @@ -568,7 +568,7 @@ else // set Python hooks for each scene PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); - PHY_SetActiveScene(scene); + KX_SetActiveScene(scene); m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); scene->UpdateParents(m_clockTime); @@ -1540,6 +1540,11 @@ double KX_KetsjiEngine::GetAnimFrameRate() return m_anim_framerate; } +double KX_KetsjiEngine::GetClockTime(void) const +{ + return m_clockTime; +} + void KX_KetsjiEngine::SetAnimFrameRate(double framerate) { m_anim_framerate = framerate; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 1aa067a9962..4184202c518 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -253,6 +253,11 @@ public: */ bool GetUseFixedTime(void) const; + /** + * Returns current render frame clock time + */ + double GetClockTime(void) const; + /** * Returns the difference between the local time of the scene (when it * was running and not suspended) and the "curtime" diff --git a/source/gameengine/Ketsji/KX_ParentActuator.cpp b/source/gameengine/Ketsji/KX_ParentActuator.cpp index eb56e8de679..89549ca6b57 100644 --- a/source/gameengine/Ketsji/KX_ParentActuator.cpp +++ b/source/gameengine/Ketsji/KX_ParentActuator.cpp @@ -119,7 +119,7 @@ bool KX_ParentActuator::Update() return false; // do nothing on negative events KX_GameObject *obj = (KX_GameObject*) GetParent(); - KX_Scene *scene = PHY_GetActiveScene(); + KX_Scene *scene = KX_GetActiveScene(); switch (m_mode) { case KX_PARENT_SET: if (m_ob) diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index a30d9f4022d..0032d83c2ff 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -1461,16 +1461,21 @@ PyObject* initMathutils() return Mathutils_Init("Mathutils"); // Use as a top level module in BGE } -void PHY_SetActiveScene(class KX_Scene* scene) +void KX_SetActiveScene(class KX_Scene* scene) { gp_KetsjiScene = scene; } -class KX_Scene* PHY_GetActiveScene() +class KX_Scene* KX_GetActiveScene() { return gp_KetsjiScene; } +class KX_KetsjiEngine* KX_GetActiveEngine() +{ + return gp_KetsjiEngine; +} + // utility function for loading and saving the globalDict int saveGamePythonConfig( char **marshal_buffer) { diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index 36e3db6ec35..57ee0be9400 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -45,6 +45,7 @@ PyObject* initGameKeys(); PyObject* initRasterizer(class RAS_IRasterizer* rasty,class RAS_ICanvas* canvas); PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level); PyObject* initMathutils(); +PyObject* initVideoTexture(void); void exitGamePlayerPythonScripting(); PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level); void exitGamePythonScripting(); @@ -54,8 +55,12 @@ void pathGamePythonConfig( char *path ); int saveGamePythonConfig( char **marshal_buffer); int loadGamePythonConfig(char *marshal_buffer, int marshal_length); -void PHY_SetActiveScene(class KX_Scene* scene); -class KX_Scene* PHY_GetActiveScene(); +class KX_KetsjiEngine; +class KX_Scene; + +void KX_SetActiveScene(class KX_Scene* scene); +class KX_Scene* KX_GetActiveScene(); +class KX_KetsjiEngine* KX_GetActiveEngine(); #include "MT_Vector3.h" void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color); diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp index 6e5553d4781..d2cfa7d07f9 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp @@ -78,6 +78,7 @@ numberoffilters(0) m_gameObjects[passindex] = NULL; } texname[0] = texname[1] = texname[2] = -1; + errorprinted= false; } RAS_2DFilterManager::~RAS_2DFilterManager() @@ -85,76 +86,107 @@ RAS_2DFilterManager::~RAS_2DFilterManager() FreeTextures(); } +void RAS_2DFilterManager::PrintShaderErrors(unsigned int shader, const char *task, const char *code) +{ + GLcharARB log[5000]; + GLsizei length = 0; + const char *c, *pos, *end; + int line = 1; + + if(errorprinted) + return; + + errorprinted= true; + + glGetInfoLogARB(shader, sizeof(log), &length, log); + end = code + strlen(code); + + printf("2D Filter GLSL Shader: %s error:\n", task); + + c = code; + while ((c < end) && (pos = strchr(c, '\n'))) { + printf("%2d ", line); + fwrite(c, (pos+1)-c, 1, stdout); + c = pos+1; + line++; + } + printf("%s", c); + + printf("%s\n", log); +} + unsigned int RAS_2DFilterManager::CreateShaderProgram(const char* shadersource) { - GLuint program = 0; - GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER); - GLint success; + GLuint program = 0; + GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER); + GLint success; - glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL); + glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL); - glCompileShaderARB(fShader); + glCompileShaderARB(fShader); - glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success); - if(!success) - { - /*Shader Comile Error*/ - std::cout << "2dFilters - Shader compile error" << std::endl; - return 0; - } - - program = glCreateProgramObjectARB(); - glAttachObjectARB(program, fShader); - glLinkProgramARB(program); - glGetObjectParameterivARB(program, GL_LINK_STATUS, &success); - if (!success) - { - /*Program Link Error*/ - std::cout << "2dFilters - Shader program link error" << std::endl; - return 0; - } - - glValidateProgramARB(program); - glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success); - if (!success) - { - /*Program Validation Error*/ - std::cout << "2dFilters - Shader program validation error" << std::endl; - return 0; - } + glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success); + if(!success) + { + /*Shader Comile Error*/ + PrintShaderErrors(fShader, "compile", shadersource); + return 0; + } + + program = glCreateProgramObjectARB(); + glAttachObjectARB(program, fShader); - return program; + glLinkProgramARB(program); + glGetObjectParameterivARB(program, GL_LINK_STATUS, &success); + if (!success) + { + /*Program Link Error*/ + PrintShaderErrors(fShader, "link", shadersource); + return 0; + } + + glValidateProgramARB(program); + glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success); + if (!success) + { + /*Program Validation Error*/ + PrintShaderErrors(fShader, "validate", shadersource); + return 0; + } + + return program; } unsigned int RAS_2DFilterManager::CreateShaderProgram(int filtermode) { - switch(filtermode) - { - case RAS_2DFILTER_BLUR: - return CreateShaderProgram(BlurFragmentShader); - case RAS_2DFILTER_SHARPEN: - return CreateShaderProgram(SharpenFragmentShader); - case RAS_2DFILTER_DILATION: - return CreateShaderProgram(DilationFragmentShader); - case RAS_2DFILTER_EROSION: - return CreateShaderProgram(ErosionFragmentShader); - case RAS_2DFILTER_LAPLACIAN: - return CreateShaderProgram(LaplacionFragmentShader); - case RAS_2DFILTER_SOBEL: - return CreateShaderProgram(SobelFragmentShader); - case RAS_2DFILTER_PREWITT: - return CreateShaderProgram(PrewittFragmentShader); - case RAS_2DFILTER_GRAYSCALE: - return CreateShaderProgram(GrayScaleFragmentShader); - case RAS_2DFILTER_SEPIA: - return CreateShaderProgram(SepiaFragmentShader); - case RAS_2DFILTER_INVERT: - return CreateShaderProgram(InvertFragmentShader); - } - return 0; + switch(filtermode) + { + case RAS_2DFILTER_BLUR: + return CreateShaderProgram(BlurFragmentShader); + case RAS_2DFILTER_SHARPEN: + return CreateShaderProgram(SharpenFragmentShader); + case RAS_2DFILTER_DILATION: + return CreateShaderProgram(DilationFragmentShader); + case RAS_2DFILTER_EROSION: + return CreateShaderProgram(ErosionFragmentShader); + case RAS_2DFILTER_LAPLACIAN: + return CreateShaderProgram(LaplacionFragmentShader); + case RAS_2DFILTER_SOBEL: + return CreateShaderProgram(SobelFragmentShader); + case RAS_2DFILTER_PREWITT: + return CreateShaderProgram(PrewittFragmentShader); + case RAS_2DFILTER_GRAYSCALE: + return CreateShaderProgram(GrayScaleFragmentShader); + case RAS_2DFILTER_SEPIA: + return CreateShaderProgram(SepiaFragmentShader); + case RAS_2DFILTER_INVERT: + return CreateShaderProgram(InvertFragmentShader); + } + return 0; } -void RAS_2DFilterManager::AnalyseShader(int passindex, vector& propNames) + +void RAS_2DFilterManager::AnalyseShader(int passindex, vector& propNames) { texflag[passindex] = 0; if(glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture") != -1) @@ -249,11 +281,11 @@ void RAS_2DFilterManager::EndShaderProgram() void RAS_2DFilterManager::FreeTextures() { - if(texname[0]!=-1) + if(texname[0]!=(unsigned int)-1) glDeleteTextures(1, (GLuint*)&texname[0]); - if(texname[1]!=-1) + if(texname[1]!=(unsigned int)-1) glDeleteTextures(1, (GLuint*)&texname[1]); - if(texname[2]!=-1) + if(texname[2]!=(unsigned int)-1) glDeleteTextures(1, (GLuint*)&texname[2]); } @@ -300,8 +332,8 @@ void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas) RAS_Rect canvas_rect = canvas->GetWindowArea(); canvaswidth = canvas->GetWidth(); canvasheight = canvas->GetHeight(); - texturewidth = canvaswidth + canvas_rect.GetLeft(); - textureheight = canvasheight + canvas_rect.GetBottom(); + texturewidth = canvaswidth; + textureheight = canvasheight; GLint i,j; i = 0; @@ -365,17 +397,17 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) if(need_depth){ glActiveTextureARB(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texname[1]); - glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, 0, 0, texturewidth,textureheight, 0); + glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, viewport[0], viewport[1], texturewidth,textureheight, 0); } if(need_luminance){ glActiveTextureARB(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, texname[2]); - glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0, 0 , texturewidth,textureheight, 0); + glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, viewport[0], viewport[1] , texturewidth,textureheight, 0); } glGetIntegerv(GL_VIEWPORT,(GLint *)viewport); - glViewport(0,0, texturewidth, textureheight); + glViewport(viewport[0],viewport[1], texturewidth, textureheight); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_TEXTURE); @@ -393,15 +425,20 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) glActiveTextureARB(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texname[0]); - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, texturewidth, textureheight, 0); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, viewport[0], viewport[1], texturewidth, textureheight, 0); glClear(GL_COLOR_BUFFER_BIT); + float canvascoordx, canvascoordy; + + canvascoordx = (GLfloat) texturewidth / canvaswidth; + canvascoordy = (GLfloat) textureheight / canvasheight; + glBegin(GL_QUADS); glColor4f(1.f, 1.f, 1.f, 1.f); - glTexCoord2f(1.0, 1.0); glVertex2f(1,1); - glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); - glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); - glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); + glTexCoord2f(1.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, canvascoordx, canvascoordy); glVertex2f(1,1); + glTexCoord2f(0.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, canvascoordy); glVertex2f(-1,1); + glTexCoord2f(0.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, 0.0); glVertex2f(-1,-1); + glTexCoord2f(1.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, canvascoordx, 0.0); glVertex2f(1,-1); glEnd(); } } diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.h b/source/gameengine/Rasterizer/RAS_2DFilterManager.h index c16bd41dd0e..454643a5077 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.h +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.h @@ -38,6 +38,7 @@ private: void AnalyseShader(int passindex, vector& propNames); void StartShaderProgram(int passindex); void EndShaderProgram(); + void PrintShaderErrors(unsigned int shader, const char *task, const char *code); void SetupTextures(bool depth, bool luminance); void FreeTextures(); @@ -58,6 +59,7 @@ private: short texflag[MAX_RENDER_PASS]; bool isshadersupported; + bool errorprinted; unsigned int m_filters[MAX_RENDER_PASS]; short m_enabled[MAX_RENDER_PASS]; diff --git a/source/gameengine/SConscript b/source/gameengine/SConscript index c2750d19706..e841f206eee 100644 --- a/source/gameengine/SConscript +++ b/source/gameengine/SConscript @@ -15,7 +15,8 @@ SConscript(['BlenderRoutines/SConscript', 'Rasterizer/RAS_OpenGLRasterizer/SConscript', 'SceneGraph/SConscript', 'Physics/Bullet/SConscript', - 'Physics/Sumo/SConscript' + 'Physics/Sumo/SConscript', + 'VideoTexture/SConscript' ]) if env['WITH_BF_PLAYER']: 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 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 diff --git a/source/gameengine/VideoTexture/Exception.cpp b/source/gameengine/VideoTexture/Exception.cpp new file mode 100644 index 00000000000..c576cebddc8 --- /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 +#include + +#include + +#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::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::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 = 10; + // delimit description + const char delimRslt[] = ": "; + // set text of description + char rsltTxt[rsltSize]; + std::ostrstream os(rsltTxt, rsltSize); + os << std::hex << m_hRslt << delimRslt; + // copy result to description + m_desc.insert(0, rsltTxt, rsltSize); + // 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 +#include +#include +#include + +#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 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..078a096aff7 --- /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 +#include + + +// 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(type->tp_alloc(type, 0)); + // initialize object structure + self->m_filter = NULL; + // return allocated object + return reinterpret_cast(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(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(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..1c9a2b46927 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterBase.h @@ -0,0 +1,132 @@ +/* $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 + +#include "PyTypeList.h" + + +// 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 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 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 static int Filter_init (PyObject * pySelf, PyObject * args, PyObject * kwds) +{ + PyFilter * self = reinterpret_cast(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..d911b1d7743 --- /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 +#include + +#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(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[] = +{ + {"color", (getter)getColor, (setter)setColor, "blue screen color", NULL}, + {"limits", (getter)getLimits, (setter)setLimits, "blue screen color limits", NULL}, + // attributes from FilterBase class + {"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, "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, /* 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..20660804f78 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterBlueScreen.h @@ -0,0 +1,98 @@ +/* $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 unsigned int tFilter (SRC src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + // calculate differences + int difRed = int((val >> 16) & 0xFF) - int(m_color[0]); + int difGreen = int((val >> 8) & 0xFF) - int(m_color[1]); + int difBlue = int(val & 0xFF) - 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 + //return 0xFF000000; + return val & 0x00FFFFFF; + // condition for fully opaque color + else if (m_squareLimits[1] <= dist) + // return normal colour + return val | 0xFF000000; + // otherwise calc alpha + else + return (val & 0x00FFFFFF) | ((((dist - m_squareLimits[0]) << 8) + / m_limitDist) << 24); + } + + /// 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..c45804caf9d --- /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 +#include + +#include "FilterColor.h" + +#include "FilterBase.h" +#include "PyTypeList.h" + +// implementation FilterGray + +// attributes structure +static PyGetSetDef filterGrayGetSets[] = +{ // attributes from FilterBase class + {"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, "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, /* 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(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[] = +{ + {"matrix", (getter)getMatrix, (setter)setMatrix, "matrix [4][5] for color calculation", NULL}, + // attributes from FilterBase class + {"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, "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, /* 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 << (r << 3); + 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] << (r << 3); + 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(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("((kk)(kk)(kk)(kk))", + lev[0][0], lev[0][1], lev[1][0] >> 8, lev[1][1] >> 8, + lev[2][0] >> 16, lev[2][1] >> 16, lev[3][0] >> 24, lev[3][1] >> 24); +} + +// 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 long)(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[] = +{ + {"levels", (getter)getLevels, (setter)setLevels, "levels matrix [4] (min, max)", NULL}, + // attributes from FilterBase class + {"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, "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, /* 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..ae2e98fa942 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterColor.h @@ -0,0 +1,164 @@ +/* $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 unsigned int tFilter (SRC src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + // calculate gray value + unsigned int gray = (28 * ((val >> 16) & 0xFF) + 151 * ((val >> 8) & 0xFF) + + 77 * (val & 0xFF)) & 0xFF00; + // return gray scale value + return (val & 0xFF000000) | gray << 8 | gray | gray >> 8; + } + + /// 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 int calcColor (unsigned int val, short idx) + { + return (((m_matrix[idx][0] * (val & 0xFF) + m_matrix[idx][1] * ((val >> 8) & 0xFF) + + m_matrix[idx][2] * ((val >> 16) & 0xFF) + m_matrix[idx][3] * ((val >> 24) & 0xFF) + + m_matrix[idx][4]) >> 8) & 0xFF) << (idx << 3); + } + + /// filter pixel template, source int buffer + template unsigned int tFilter (SRC src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + // return calculated color + return calcColor(val, 0) | calcColor(val, 1) | calcColor(val, 2) + | calcColor(val, 3); + } + + /// 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 long 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 = val & (0xFF << (idx << 3)); + if (col <= levels[idx][0]) col = 0; + else if (col >= levels[idx][1]) col = 0xFF << (idx << 3); + else if (idx < 3) col = (((col - levels[idx][0]) << 8) / levels[idx][2]) & (0xFF << (idx << 3)); + else col = (((col - levels[idx][0]) / levels[idx][2]) << 8) & (0xFF << (idx << 3)); + return col; + } + + /// filter pixel template, source int buffer + template unsigned int tFilter (SRC src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + // return calculated color + return calcColor(val, 0) | calcColor(val, 1) | calcColor(val, 2) + | calcColor(val, 3); + } + + /// 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..5eeb63b7128 --- /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 +#include + +#include "FilterNormal.h" + +#include "FilterBase.h" +#include "PyTypeList.h" + +// implementation FilterNormal + +// constructor +FilterNormal::FilterNormal (void) : m_colShift(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_colShift = colIdx << 3; +} + +// 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(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[] = +{ + {"colorIdx", (getter)getColor, (setter)setColor, "index of color used to calculate normal (0 - red, 1 - green, 2 - blue)", NULL}, + {"depth", (getter)getDepth, (setter)setDepth, "depth of relief", NULL}, + // attributes from FilterBase class + {"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, "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, /* 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..ec51ca39db9 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterNormal.h @@ -0,0 +1,98 @@ +/* $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_colShift >> 3; } + /// 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; + + /// shift to used color component + unsigned short m_colShift; + + /// filter pixel, source int buffer + template 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((val >> m_colShift) & 0xFF); + // get upper and left pixel from actual pixel + int upPix = y > 0 ? int((convertPrevious(src - pixSize * size[0], x, y - 1, + size, pixSize) >> m_colShift) & 0xFF) : actPix; + int leftPix = x > 0 ? int((convertPrevious(src - pixSize, x - 1, y, size, pixSize) + >> m_colShift) & 0xFF) : actPix; + // 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 + return 0xFF000000 | int(dz) << 16 | int(dy) << 8 | int(dx); + } + + /// 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..4b96a9792e2 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterSource.cpp @@ -0,0 +1,125 @@ +/* $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 +#include + +#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, /* 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, /* 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..7bed5c77a4d --- /dev/null +++ b/source/gameengine/VideoTexture/FilterSource.h @@ -0,0 +1,233 @@ +/* $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) + { return 0xFF000000 | src[0] << 16 | src[1] << 8 | src[2]; } +}; + + +/// 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) + { return 0xFF000000 | src[2] << 16 | src[1] << 8 | src[0]; } +}; + + +/// 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; + if (green > 0x10000) green = 0xFF00; + else if (green < 0) green = 0; + int blue = (298 * c + 516 * d + 128) << 8; + if (blue > 0x1000000) blue = 0xFF0000; + else if (blue < 0) blue = 0; + // return result + return 0xFF000000 | blue & 0xFF0000 | green & 0xFF00 + | red & 0xFF; + } +}; + + +#endif diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp new file mode 100644 index 00000000000..d2e980d979a --- /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 +#include + +#include +#include + +#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(type->tp_alloc(type, 0)); + // initialize object structure + self->m_image = NULL; + // return allocated object + return reinterpret_cast(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(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(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(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(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..2b923a06ee3 --- /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 +#include + +#include "PyTypeList.h" + +#include "FilterBase.h" + + +// forward declarations +struct PyImage; +class ImageSource; + + +/// type for list of image sources +typedef std::vector 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 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 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 static int Image_init (PyObject * pySelf, PyObject * args, PyObject * kwds) +{ + PyImage * self = reinterpret_cast(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..f09514a36f0 --- /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 +#include + +#include "ImageBuff.h" + +#include "ImageBase.h" +#include "FilterSource.h" + + +// default filter +FilterBGR24 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(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 + {"image", (getter)Image_getImage, NULL, "image data", NULL}, + {"size", (getter)Image_getSize, NULL, "image size", NULL}, + {"scale", (getter)Image_getScale, (setter)Image_setScale, "fast scale of image (near neighbour)", NULL}, + {"flip", (getter)Image_getFlip, (setter)Image_setFlip, "flip image vertically", NULL}, + {"filter", (getter)Image_getFilter, (setter)Image_setFilter, "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, /* 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..71250005129 --- /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 +#include + +#include "ImageMix.h" + +#include "ImageBase.h" + +#include "Exception.h" + + +// cast ImageSource pointer to ImageSourceMix +inline ImageSourceMix * getImageSourceMix (ImageSource * src) +{ return static_cast(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(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 + {"image", (getter)Image_getImage, NULL, "image data", NULL}, + {"size", (getter)Image_getSize, NULL, "image size", NULL}, + {"scale", (getter)Image_getScale, (setter)Image_setScale, "fast scale of image (near neighbour)", NULL}, + {"flip", (getter)Image_getFlip, (setter)Image_setFlip, "flip image vertically", NULL}, + {"filter", (getter)Image_getFilter, (setter)Image_setFilter, "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, /* 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(*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..ce27a24d35a --- /dev/null +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -0,0 +1,265 @@ +/* $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 +#include + +#include +#include +#include +#include +#include +#include + +#include "ImageRender.h" + +#include "ImageBase.h" +#include "BlendType.h" +#include "Exception.h" + + +// 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(self->m_image); } + + +// python methods + +// Blender Scene type +BlendType sceneType ("KX_Scene"); +// Blender Camera type +BlendType cameraType ("KX_Camera"); + + +ExceptionID SceneInvalid, CameraInvalid; +ExpDesc SceneInvalidDesc (SceneInvalid, "Scene object is invalid"); +ExpDesc CameraInvalidDesc (CameraInvalid, "Camera object is invalid"); + +// 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(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[] = +{ + {"background", (getter)getBackground, (setter)setBackground, "background color", NULL}, + // attributes from ImageBase class + {"image", (getter)Image_getImage, NULL, "image data", NULL}, + {"size", (getter)Image_getSize, NULL, "image size", NULL}, + {"scale", (getter)Image_getScale, (setter)Image_setScale, "fast scale of image (near neighbour)", NULL}, + {"flip", (getter)Image_getFlip, (setter)Image_setFlip, "flip image vertically", NULL}, + {"filter", (getter)Image_getFilter, (setter)Image_setFilter, "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 */ +}; + + 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 +#include +#include +#include +#include +#include + +#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..e1d3316a43e --- /dev/null +++ b/source/gameengine/VideoTexture/ImageViewport.cpp @@ -0,0 +1,298 @@ +/* $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 +#include + +#include "ImageViewport.h" + +#include + +#include "Texture.h" +#include "ImageBase.h" +#include "FilterSource.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] = 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 (int * 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], m_capSize[0], 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], m_capSize[0], m_capSize[1], GL_RGB, + GL_UNSIGNED_BYTE, m_viewportImage); + // filter loaded data + FilterBGR24 filt; + filterImage(filt, m_viewportImage, m_capSize); + } +} + + + +// cast Image pointer to ImageViewport +inline ImageViewport * getImageViewport (PyImage * self) +{ return static_cast(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 + int pos [] = { + int(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 0))), + int(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[] = +{ + {"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, "use whole viewport to capture", NULL}, + {"position", (getter)ImageViewport_getPosition, (setter)ImageViewport_setPosition, "upper left corner of captured area", NULL}, + {"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, "size of viewport area being captured", NULL}, + // attributes from ImageBase class + {"image", (getter)Image_getImage, NULL, "image data", NULL}, + {"size", (getter)Image_getSize, NULL, "image size", NULL}, + {"scale", (getter)Image_getScale, (setter)Image_setScale, "fast scale of image (near neighbour)", NULL}, + {"flip", (getter)Image_getFlip, (setter)Image_setFlip, "flip image vertically", NULL}, + {"filter", (getter)Image_getFilter, (setter)Image_setFilter, "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, /* 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..9fd3aeb7ba9 --- /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 + int * getPosition (void) { return m_position; } + /// set position in viewport + void setPosition (int * pos = NULL); + +protected: + /// frame buffer rectangle + int m_viewport[4]; + + /// size of captured area + short m_capSize[2]; + /// use whole viewport + bool m_whole; + + /// position of capture rectangle in viewport + int m_position[2]; + /// upper left point for capturing + int 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 + int * 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..b8c40052e81 --- /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 +#include + +#include + + +/// 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, (*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..736fc9aaefd --- /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 +#include + +#include + +// forward declaration +class PyTypeListItem; + +// type for list of types +typedef std::vector 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 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..bf8d7c133ff --- /dev/null +++ b/source/gameengine/VideoTexture/SConscript @@ -0,0 +1,33 @@ +#!/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/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'] + '/lib/python' + env['BF_PYTHON_VERSION'] + "/site-packages/numpy/core/include" +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..ea3f60b2775 --- /dev/null +++ b/source/gameengine/VideoTexture/Texture.cpp @@ -0,0 +1,463 @@ +/* $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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "KX_KetsjiEngine.h" +#include "KX_PythonInit.h" +#include "Texture.h" +#include "ImageBase.h" +#include "Exception.h" + +#include +#include + + +// macro for exception handling and logging +#define CATCH_EXCP catch (Exception & exp) \ +{ exp.report(); } + + +// are Blender materials used +bool blendMats = false; + +// Blender GameObject type +BlendType 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; + // if material name matches + if (strcmp(mat->GetMaterialName().ReadPtr(), name) == 0) + // matID is found + 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(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(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 + blendMats = (mat->GetFlag() & RAS_BLENDERMAT) != 0; + if (blendMats) + // get blender material texture + self->m_matTexture = static_cast(mat)->getTex(texID); + else + { + // get texture pointer from polygon material + MTFace * tface = static_cast(mat)->GetMTFace(); + self->m_imgTexture = (Image*)tface->tpage; + } + } + // 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(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 (blendMats) + 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", ¶m) || !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 (blendMats) + 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(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(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[] = +{ + {"source", (getter)Texture_getSource, (setter)Texture_setSource, "source of texture", NULL}, + {"mipmap", (getter)Texture_getMipmap, (setter)Texture_setMipmap, "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..f19f8da607d --- /dev/null +++ b/source/gameengine/VideoTexture/Texture.h @@ -0,0 +1,87 @@ +/* $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 +#include + +#include +#include +#include + +#include "ImageBase.h" +#include "BlendType.h" + + +// type Texture declaration +struct Texture +{ + PyObject_HEAD + + // 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; + +// usage of Blender materials +extern bool blendMats; + +// 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..038a04a55a8 --- /dev/null +++ b/source/gameengine/VideoTexture/VideoBase.cpp @@ -0,0 +1,183 @@ +/* $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 +#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 + FilterRGB24 filtRGB; + FilterYV12 filtYUV; + // convert video format to image + switch (m_format) + { + case RGB24: + // 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 + 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..78e8ba65909 --- /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 + +#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 }; + + +/// 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(self->m_image); } + + +extern ExceptionID SourceVideoCreation; + +// object initialization +template 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..272d2695c4b --- /dev/null +++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp @@ -0,0 +1,753 @@ +/* $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 "MEM_guardedalloc.h" +#include "PIL_time.h" + +#include + +#include "Exception.h" +#include "VideoFFmpeg.h" + +#ifdef WITH_FFMPEG + +// 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_frameBGR(NULL), m_imgConvertCtx(NULL), +m_deinterlace(false), m_preseek(0), m_videoStream(-1), m_baseFrameRate(25.0), +m_lastFrame(-1), m_curPosition(-1), m_startTime(0), +m_captWidth(0), m_captHeight(0), m_captRate(0.f) +{ + // 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); + } + if (m_formatCtx) + { + av_close_input_file(m_formatCtx); + } + if (m_frame) + { + av_free(m_frame); + } + if (m_frameDeinterlaced) + { + MEM_freeN(m_frameDeinterlaced->data[0]); + av_free(m_frameDeinterlaced); + } + if (m_frameBGR) + { + MEM_freeN(m_frameBGR->data[0]); + av_free(m_frameBGR); + } + if (m_imgConvertCtx) + { + sws_freeContext(m_imgConvertCtx); + } + + m_codec = NULL; + m_codecCtx = NULL; + m_formatCtx = NULL; + m_frame = NULL; + m_frame = NULL; + m_frameBGR = NULL; + m_imgConvertCtx = NULL; + + // object will be deleted after that + return true; +} + + +// set initial parameters +void VideoFFmpeg::initParams (short width, short height, float rate) +{ + m_captWidth = width; + m_captHeight = height; + m_captRate = rate; +} + +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; inb_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_frameBGR = 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); + + // allocate buffer to store final decoded frame + avpicture_fill((AVPicture*)m_frameBGR, + (uint8_t*)MEM_callocN(avpicture_get_size( + PIX_FMT_BGR24, + m_codecCtx->width, m_codecCtx->height), + "ffmpeg bgr"), + PIX_FMT_BGR24, 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_BGR24, + 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_frameBGR->data[0]); + av_free(m_frameBGR); + 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->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; + } +} + + +// 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: + // [][:] + // : 'v4l' for VideoForLinux, 'dv1394' for DV1394. By default 'v4l' + // : 'pal', 'secam' or 'ntsc'. By default 'ntsc' + // The driver name is constructed automatically from the device type: + // v4l : /dev/video + // dv1394: /dev/dv1394/ + // 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])); + } + } + } +} + + +// 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_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); + + av_seek_frame(m_formatCtx, -1, pos, AVSEEK_FLAG_BACKWARD); + // 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 BGR24 + sws_scale(m_imgConvertCtx, + input->data, + input->linesize, + 0, + m_codecCtx->height, + m_frameBGR->data, + m_frameBGR->linesize); + av_free_packet(&packet); + frameLoaded = true; + break; + } + } + av_free_packet(&packet); + } + if (frameLoaded) + m_curPosition = position; + return frameLoaded; +} + + +// python methods + + +// cast Image pointer to VideoFFmpeg +inline VideoFFmpeg * getVideoFFmpeg (PyImage * self) +{ return static_cast(self->m_image); } + + +// object initialization +static int VideoFFmpeg_init (PyObject * pySelf, PyObject * args, PyObject * kwds) +{ + PyImage * self = reinterpret_cast(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(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 + {"status", (getter)Video_getStatus, NULL, "video status", NULL}, + {"range", (getter)Video_getRange, (setter)Video_setRange, "replay range", NULL}, + {"repeat", (getter)Video_getRepeat, (setter)Video_setRepeat, "repeat count, -1 for infinite repeat", NULL}, + {"framerate", (getter)Video_getFrameRate, (setter)Video_setFrameRate, "frame rate", NULL}, + // attributes from ImageBase class + {"image", (getter)Image_getImage, NULL, "image data", NULL}, + {"size", (getter)Image_getSize, NULL, "image size", NULL}, + {"scale", (getter)Image_getScale, (setter)Image_setScale, "fast scale of image (near neighbour)", NULL}, + {"flip", (getter)Image_getFlip, (setter)Image_setFlip, "flip image vertically", NULL}, + {"filter", (getter)Image_getFilter, (setter)Image_setFilter, "pixel filter", NULL}, + {"preseek", (getter)VideoFFmpeg_getPreseek, (setter)VideoFFmpeg_setPreseek, "nb of frames of preseek", NULL}, + {"deinterlace", (getter)VideoFFmpeg_getDeinterlace, (setter)VideoFFmpeg_setDeinterlace, "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 */ +}; + + + +#endif //WITH_FFMPEG + + diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.h b/source/gameengine/VideoTexture/VideoFFmpeg.h new file mode 100644 index 00000000000..4720bef1841 --- /dev/null +++ b/source/gameengine/VideoTexture/VideoFFmpeg.h @@ -0,0 +1,163 @@ +/* $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 +#include +#include +#include +} + +#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); + /// open video 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; } + +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_frameBGR; + // 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; + + /// 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; + + /// 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_frameBGR; } +}; + +inline VideoFFmpeg * getFFmpeg (PyImage * self) +{ + return static_cast(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..d08762b1d7c --- /dev/null +++ b/source/gameengine/VideoTexture/blendVideoTex.cpp @@ -0,0 +1,207 @@ +/* $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. +----------------------------------------------------------------------------- +*/ + +#define PY_ARRAY_UNIQUE_SYMBOL numpyPtr + +#include + +#include + +#include + +#include + +//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); +} + + +// function to initialize numpy structures +static bool initNumpy (void) +{ + // init module and report failure + import_array1(false); + // report success + return true; +} + +// 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(pyImg); + // check initialization of numpy interface, and initialize it if needed + if (numpyPtr == NULL && !initNumpy()) Py_RETURN_NONE; + // create array object + npy_intp dim[1]; + dim[0] = img->m_image->getBuffSize() / sizeof(unsigned int); + unsigned int * imgBuff = img->m_image->getImage(); + // if image is available, convert it to array + if (imgBuff != NULL) + return PyArray_SimpleNewFromData(1, dim, NPY_UBYTE, imgBuff); + // 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; +#endif +extern PyTypeObject FilterBlueScreenType; +extern PyTypeObject FilterGrayType; +extern PyTypeObject FilterColorType; +extern PyTypeObject FilterLevelType; +extern PyTypeObject FilterNormalType; +extern PyTypeObject FilterRGB24Type; +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"); +#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(&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; + + // prepare numpy array + numpyPtr = NULL; + + // initialize classes + pyImageTypes.reg(m); + pyFilterTypes.reg(m); + + Py_INCREF(&TextureType); + PyModule_AddObject(m, "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