diff options
author | Dalai Felinto <dfelinto@gmail.com> | 2018-04-16 15:07:42 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2018-04-17 18:51:28 +0300 |
commit | 159806140fd33e6ddab951c0f6f180cfbf927d38 (patch) | |
tree | da076be3baa4d987fb5935e220a3d901c926e0e7 /source/gameengine/VideoTexture | |
parent | 28b996a9d2090efdd74115a653629ef9d7d871f7 (diff) |
Removing Blender Game Engine from Blender 2.8
Folders removed entirely:
* //extern/recastnavigation
* //intern/decklink
* //intern/moto
* //source/blender/editors/space_logic
* //source/blenderplayer
* //source/gameengine
This includes DNA data and any reference to the BGE code in Blender itself.
We are bumping the subversion.
Pending tasks:
* Tile/clamp code in image editor draw code.
* Viewport drawing code (so much of this will go away because of BI removal
that we can wait until then to remove this.
Diffstat (limited to 'source/gameengine/VideoTexture')
38 files changed, 0 insertions, 11978 deletions
diff --git a/source/gameengine/VideoTexture/BlendType.h b/source/gameengine/VideoTexture/BlendType.h deleted file mode 100644 index 561c6e8768f..00000000000 --- a/source/gameengine/VideoTexture/BlendType.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2006 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file BlendType.h - * \ingroup bgevideotex - */ - -#ifndef __BLENDTYPE_H__ -#define __BLENDTYPE_H__ - - -/// class allows check type of blender python object and access its contained object -/// MUST ONLY BE USED FOR KX classes that are descendent of PyObjectPlus -template <class PyObj> class BlendType -{ -public: - /// constructor - BlendType (const char * name) : m_name(name), m_objType(NULL) {} - - /// 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(Py_TYPE(obj)->tp_name, m_name) == 0) - // if name of type match, save pointer to type - m_objType = Py_TYPE(obj); - 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 (Py_TYPE(obj) != m_objType) - return NULL; - // return pointer to object, this class can only be used for KX object => - // the Py object is actually a proxy - return (PyObj *)BGE_PROXY_REF(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 - const 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 deleted file mode 100644 index 1eb09b02e05..00000000000 --- a/source/gameengine/VideoTexture/CMakeLists.txt +++ /dev/null @@ -1,119 +0,0 @@ -# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 ***** - -set(INC - . - ../BlenderRoutines - ../Expressions - ../GameLogic - ../Ketsji - ../Rasterizer - ../Rasterizer/RAS_OpenGLRasterizer - ../SceneGraph - ../../blender/blenkernel - ../../blender/blenlib - ../../blender/editors/include - ../../blender/gpu - ../../blender/imbuf - ../../blender/makesdna - ../../blender/python - ../../blender/python/generic - ../../../intern/container - ../../../intern/ffmpeg - ../../../intern/glew-mx - ../../../intern/guardedalloc - ../../../intern/string - ../../../intern/decklink - ../../../intern/gpudirect - ../../../intern/atomic -) - -set(INC_SYS - ../../../intern/moto/include - ${GLEW_INCLUDE_PATH} -) - -add_definitions(${GL_DEFINITIONS}) - -set(SRC - Exception.cpp - FilterBase.cpp - FilterBlueScreen.cpp - FilterColor.cpp - FilterNormal.cpp - FilterSource.cpp - ImageBase.cpp - ImageBuff.cpp - ImageMix.cpp - ImageRender.cpp - ImageViewport.cpp - PyTypeList.cpp - Texture.cpp - DeckLink.cpp - VideoBase.cpp - VideoFFmpeg.cpp - VideoDeckLink.cpp - blendVideoTex.cpp - - BlendType.h - Common.h - Exception.h - FilterBase.h - FilterBlueScreen.h - FilterColor.h - FilterNormal.h - FilterSource.h - ImageBase.h - ImageBuff.h - ImageMix.h - ImageRender.h - ImageViewport.h - PyTypeList.h - Texture.h - DeckLink.h - VideoBase.h - VideoFFmpeg.h - VideoDeckLink.h -) - -if(WITH_CODEC_FFMPEG) - list(APPEND INC_SYS - ${FFMPEG_INCLUDE_DIRS} - ${PTHREADS_INCLUDE_DIRS} - ) - add_definitions(-DWITH_FFMPEG) - - remove_strict_flags_file( - VideoFFmpeg.cpp - VideoDeckLink - DeckLink - ) -endif() - -if(WITH_GAMEENGINE_DECKLINK) - add_definitions(-DWITH_GAMEENGINE_DECKLINK) -endif() - -blender_add_lib(ge_videotex "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/VideoTexture/Common.h b/source/gameengine/VideoTexture/Common.h deleted file mode 100644 index 22ea177addc..00000000000 --- a/source/gameengine/VideoTexture/Common.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2006 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file VideoTexture/Common.h - * \ingroup bgevideotex - */ - -#if defined WIN32 -#define WINDOWS_LEAN_AND_MEAN -#endif - -#ifndef NULL -#define NULL 0 -#endif - -#ifndef _HRESULT_DEFINED -#define _HRESULT_DEFINED -#define HRESULT long -#endif - -#ifndef DWORD -#define DWORD unsigned long -#endif - -#ifndef S_OK -#define S_OK ((HRESULT)0L) -#endif - -#ifndef BYTE -#define BYTE unsigned char -#endif - -#ifndef WIN32 -#define Sleep(time) sleep(time) -#endif - -#ifndef FAILED -#define FAILED(Status) ((HRESULT)(Status)<0) -#endif - -#include <iostream> diff --git a/source/gameengine/VideoTexture/DeckLink.cpp b/source/gameengine/VideoTexture/DeckLink.cpp deleted file mode 100644 index fa8ab8c641c..00000000000 --- a/source/gameengine/VideoTexture/DeckLink.cpp +++ /dev/null @@ -1,813 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2015, Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Blender Foundation. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/Texture.cpp - * \ingroup bgevideotex - */ - -#ifdef WITH_GAMEENGINE_DECKLINK - -// implementation - -// FFmpeg defines its own version of stdint.h on Windows. -// Decklink needs FFmpeg, so it uses its version of stdint.h -// this is necessary for INT64_C macro -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif -// this is necessary for UINTPTR_MAX (used by atomic-ops) -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#endif - -#include "atomic_ops.h" - -#include "EXP_PyObjectPlus.h" -#include "KX_KetsjiEngine.h" -#include "KX_PythonInit.h" -#include "DeckLink.h" - -#include <memory.h> - -// macro for exception handling and logging -#define CATCH_EXCP catch (Exception & exp) \ -{ exp.report(); return NULL; } - -static struct -{ - const char *name; - BMDDisplayMode mode; -} sModeStringTab[] = { - { "NTSC", bmdModeNTSC }, - { "NTSC2398", bmdModeNTSC2398 }, - { "PAL", bmdModePAL }, - { "NTSCp", bmdModeNTSCp }, - { "PALp", bmdModePALp }, - - /* HD 1080 Modes */ - - { "HD1080p2398", bmdModeHD1080p2398 }, - { "HD1080p24", bmdModeHD1080p24 }, - { "HD1080p25", bmdModeHD1080p25 }, - { "HD1080p2997", bmdModeHD1080p2997 }, - { "HD1080p30", bmdModeHD1080p30 }, - { "HD1080i50", bmdModeHD1080i50 }, - { "HD1080i5994", bmdModeHD1080i5994 }, - { "HD1080i6000", bmdModeHD1080i6000 }, - { "HD1080p50", bmdModeHD1080p50 }, - { "HD1080p5994", bmdModeHD1080p5994 }, - { "HD1080p6000", bmdModeHD1080p6000 }, - - /* HD 720 Modes */ - - { "HD720p50", bmdModeHD720p50 }, - { "HD720p5994", bmdModeHD720p5994 }, - { "HD720p60", bmdModeHD720p60 }, - - /* 2k Modes */ - - { "2k2398", bmdMode2k2398 }, - { "2k24", bmdMode2k24 }, - { "2k25", bmdMode2k25 }, - - /* DCI Modes (output only) */ - - { "2kDCI2398", bmdMode2kDCI2398 }, - { "2kDCI24", bmdMode2kDCI24 }, - { "2kDCI25", bmdMode2kDCI25 }, - - /* 4k Modes */ - - { "4K2160p2398", bmdMode4K2160p2398 }, - { "4K2160p24", bmdMode4K2160p24 }, - { "4K2160p25", bmdMode4K2160p25 }, - { "4K2160p2997", bmdMode4K2160p2997 }, - { "4K2160p30", bmdMode4K2160p30 }, - { "4K2160p50", bmdMode4K2160p50 }, - { "4K2160p5994", bmdMode4K2160p5994 }, - { "4K2160p60", bmdMode4K2160p60 }, - // sentinel - { NULL } -}; - -static struct -{ - const char *name; - BMDPixelFormat format; -} sFormatStringTab[] = { - { "8BitYUV", bmdFormat8BitYUV }, - { "10BitYUV", bmdFormat10BitYUV }, - { "8BitARGB", bmdFormat8BitARGB }, - { "8BitBGRA", bmdFormat8BitBGRA }, - { "10BitRGB", bmdFormat10BitRGB }, - { "12BitRGB", bmdFormat12BitRGB }, - { "12BitRGBLE", bmdFormat12BitRGBLE }, - { "10BitRGBXLE", bmdFormat10BitRGBXLE }, - { "10BitRGBX", bmdFormat10BitRGBX }, - // sentinel - { NULL } -}; - -ExceptionID DeckLinkBadDisplayMode, DeckLinkBadPixelFormat; -ExpDesc DeckLinkBadDisplayModeDesc(DeckLinkBadDisplayMode, "Invalid or unsupported display mode"); -ExpDesc DeckLinkBadPixelFormatDesc(DeckLinkBadPixelFormat, "Invalid or unsupported pixel format"); - -HRESULT decklink_ReadDisplayMode(const char *format, size_t len, BMDDisplayMode *displayMode) -{ - int i; - - if (len == 0) - len = strlen(format); - for (i = 0; sModeStringTab[i].name != NULL; i++) { - if (strlen(sModeStringTab[i].name) == len && - !strncmp(sModeStringTab[i].name, format, len)) - { - *displayMode = sModeStringTab[i].mode; - return S_OK; - } - } - if (len != 4) - THRWEXCP(DeckLinkBadDisplayMode, S_OK); - // assume the user entered directly the mode value as a 4 char string - *displayMode = (BMDDisplayMode)((((uint32_t)format[0]) << 24) + (((uint32_t)format[1]) << 16) + (((uint32_t)format[2]) << 8) + ((uint32_t)format[3])); - return S_OK; -} - -HRESULT decklink_ReadPixelFormat(const char *format, size_t len, BMDPixelFormat *pixelFormat) -{ - int i; - - if (!len) - len = strlen(format); - for (i = 0; sFormatStringTab[i].name != NULL; i++) { - if (strlen(sFormatStringTab[i].name) == len && - !strncmp(sFormatStringTab[i].name, format, len)) - { - *pixelFormat = sFormatStringTab[i].format; - return S_OK; - } - } - if (len != 4) - THRWEXCP(DeckLinkBadPixelFormat, S_OK); - // assume the user entered directly the mode value as a 4 char string - *pixelFormat = (BMDPixelFormat)((((uint32_t)format[0]) << 24) + (((uint32_t)format[1]) << 16) + (((uint32_t)format[2]) << 8) + ((uint32_t)format[3])); - return S_OK; -} - -class DeckLink3DFrameWrapper : public IDeckLinkVideoFrame, IDeckLinkVideoFrame3DExtensions -{ -public: - // IUnknown - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) - { - if (!memcmp(&iid, &IID_IDeckLinkVideoFrame3DExtensions, sizeof(iid))) { - if (mpRightEye) { - *ppv = (IDeckLinkVideoFrame3DExtensions*)this; - return S_OK; - } - } - return E_NOTIMPL; - } - virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 1U; } - virtual ULONG STDMETHODCALLTYPE Release(void) { return 1U; } - // IDeckLinkVideoFrame - virtual long STDMETHODCALLTYPE GetWidth(void) { return mpLeftEye->GetWidth(); } - virtual long STDMETHODCALLTYPE GetHeight(void) { return mpLeftEye->GetHeight(); } - virtual long STDMETHODCALLTYPE GetRowBytes(void) { return mpLeftEye->GetRowBytes(); } - virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat(void) { return mpLeftEye->GetPixelFormat(); } - virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags(void) { return mpLeftEye->GetFlags(); } - virtual HRESULT STDMETHODCALLTYPE GetBytes(void **buffer) { return mpLeftEye->GetBytes(buffer); } - virtual HRESULT STDMETHODCALLTYPE GetTimecode(BMDTimecodeFormat format,IDeckLinkTimecode **timecode) - { return mpLeftEye->GetTimecode(format, timecode); } - virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary) - { return mpLeftEye->GetAncillaryData(ancillary); } - // IDeckLinkVideoFrame3DExtensions - virtual BMDVideo3DPackingFormat STDMETHODCALLTYPE Get3DPackingFormat(void) - { - return bmdVideo3DPackingLeftOnly; - } - virtual HRESULT STDMETHODCALLTYPE GetFrameForRightEye( - /* [out] */ IDeckLinkVideoFrame **rightEyeFrame) - { - mpRightEye->AddRef(); - *rightEyeFrame = mpRightEye; - return S_OK; - } - // Constructor - DeckLink3DFrameWrapper(IDeckLinkVideoFrame *leftEye, IDeckLinkVideoFrame *rightEye) - { - mpLeftEye = leftEye; - mpRightEye = rightEye; - } - // no need for a destructor, it's just a wrapper -private: - IDeckLinkVideoFrame *mpLeftEye; - IDeckLinkVideoFrame *mpRightEye; -}; - -static void decklink_Reset(DeckLink *self) -{ - self->m_lastClock = 0.0; - self->mDLOutput = NULL; - self->mUse3D = false; - self->mDisplayMode = bmdModeUnknown; - self->mKeyingSupported = false; - self->mHDKeyingSupported = false; - self->mSize[0] = 0; - self->mSize[1] = 0; - self->mFrameSize = 0; - self->mLeftFrame = NULL; - self->mRightFrame = NULL; - self->mKeyer = NULL; - self->mUseKeying = false; - self->mKeyingLevel = 255; - self->mUseExtend = false; -} - -#ifdef __BIG_ENDIAN__ -#define CONV_PIXEL(i) ((((i)>>16)&0xFF00)+(((i)&0xFF00)<<16)+((i)&0xFF00FF)) -#else -#define CONV_PIXEL(i) ((((i)&0xFF)<<16)+(((i)>>16)&0xFF)+((i)&0xFF00FF00)) -#endif - -// adapt the pixel format and picture size from VideoTexture (RGBA) to DeckLink (BGRA) -static void decklink_ConvImage(uint32_t *dest, const short *destSize, const uint32_t *source, const short *srcSize, bool extend) -{ - short w, h, x, y; - const uint32_t *s; - uint32_t *d, p; - bool sameSize = (destSize[0] == srcSize[0] && destSize[1] == srcSize[1]); - - if (sameSize || !extend) { - // here we convert pixel by pixel - w = (destSize[0] < srcSize[0]) ? destSize[0] : srcSize[0]; - h = (destSize[1] < srcSize[1]) ? destSize[1] : srcSize[1]; - for (y = 0; y < h; ++y) { - s = source + y*srcSize[0]; - d = dest + y*destSize[0]; - for (x = 0; x < w; ++x, ++s, ++d) { - *d = CONV_PIXEL(*s); - } - } - } - else { - // here we scale - // interpolation accumulator - int accHeight = srcSize[1] >> 1; - d = dest; - s = source; - // process image rows - for (y = 0; y < srcSize[1]; ++y) { - // increase height accum - accHeight += destSize[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 (x = 0; x < srcSize[0]; ++x, ++s) { - // increase width accum - accWidth += destSize[0]; - // convert pixel - p = CONV_PIXEL(*s); - // if pixel has to be drown one or more times - while (accWidth >= srcSize[0]) { - // decrease accum - accWidth -= srcSize[0]; - *d++ = p; - } - } - // if there should be more identical lines - while (accHeight >= srcSize[1]) { - accHeight -= srcSize[1]; - // copy previous line - memcpy(d, d - destSize[0], 4 * destSize[0]); - d += destSize[0]; - } - } - else { - // if we skip a source line - s += srcSize[0]; - } - } - } -} - -// DeckLink object allocation -static PyObject *DeckLink_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - // allocate object - DeckLink * self = reinterpret_cast<DeckLink*>(type->tp_alloc(type, 0)); - // initialize object structure - decklink_Reset(self); - // m_leftEye is a python object, it's handled by python - self->m_leftEye = NULL; - self->m_rightEye = NULL; - // return allocated object - return reinterpret_cast<PyObject*>(self); -} - - -// forward declaration -PyObject *DeckLink_close(DeckLink *self); -int DeckLink_setSource(DeckLink *self, PyObject *value, void *closure); - - -// DeckLink object deallocation -static void DeckLink_dealloc(DeckLink *self) -{ - // release renderer - Py_XDECREF(self->m_leftEye); - // close decklink - PyObject *ret = DeckLink_close(self); - Py_DECREF(ret); - // release object - Py_TYPE((PyObject *)self)->tp_free((PyObject *)self); -} - - -ExceptionID AutoDetectionNotAvail, DeckLinkOpenCard, DeckLinkBadFormat, DeckLinkInternalError; -ExpDesc AutoDetectionNotAvailDesc(AutoDetectionNotAvail, "Auto detection not yet available"); -ExpDesc DeckLinkOpenCardDesc(DeckLinkOpenCard, "Cannot open card for output"); -ExpDesc DeckLinkBadFormatDesc(DeckLinkBadFormat, "Invalid or unsupported output format, use <mode>[/3D]"); -ExpDesc DeckLinkInternalErrorDesc(DeckLinkInternalError, "DeckLink API internal error, please report"); - -// DeckLink object initialization -static int DeckLink_init(DeckLink *self, PyObject *args, PyObject *kwds) -{ - IDeckLinkIterator* pIterator; - IDeckLinkAttributes* pAttributes; - IDeckLinkDisplayModeIterator* pDisplayModeIterator; - IDeckLinkDisplayMode* pDisplayMode; - IDeckLink* pDL; - char* p3D; - BOOL flag; - size_t len; - int i; - uint32_t displayFlags; - BMDVideoOutputFlags outputFlags; - BMDDisplayModeSupport support; - uint32_t* bytes; - - - // material ID - short cardIdx = 0; - // texture ID - char *format = NULL; - - static const char *kwlist[] = {"cardIdx", "format", NULL}; - // get parameters - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|hs", - const_cast<char**>(kwlist), &cardIdx, &format)) - return -1; - - try { - if (format == NULL) { - THRWEXCP(AutoDetectionNotAvail, S_OK); - } - - if ((p3D = strchr(format, '/')) != NULL && strcmp(p3D, "/3D")) - THRWEXCP(DeckLinkBadFormat, S_OK); - self->mUse3D = (p3D) ? true : false; - // read the mode - len = (p3D) ? (size_t)(p3D - format) : strlen(format); - // throws if bad mode - decklink_ReadDisplayMode(format, len, &self->mDisplayMode); - - pIterator = BMD_CreateDeckLinkIterator(); - pDL = NULL; - if (pIterator) { - i = 0; - while (pIterator->Next(&pDL) == S_OK) { - if (i == cardIdx) { - break; - } - i++; - pDL->Release(); - pDL = NULL; - } - pIterator->Release(); - } - - if (!pDL) { - THRWEXCP(DeckLinkOpenCard, S_OK); - } - // detect the capabilities - if (pDL->QueryInterface(IID_IDeckLinkAttributes, (void**)&pAttributes) == S_OK) { - if (pAttributes->GetFlag(BMDDeckLinkSupportsInternalKeying, &flag) == S_OK && flag) { - self->mKeyingSupported = true; - if (pAttributes->GetFlag(BMDDeckLinkSupportsHDKeying, &flag) == S_OK && flag) { - self->mHDKeyingSupported = true; - } - } - pAttributes->Release(); - } - - if (pDL->QueryInterface(IID_IDeckLinkOutput, (void**)&self->mDLOutput) != S_OK) { - self->mDLOutput = NULL; - } - if (self->mKeyingSupported) { - pDL->QueryInterface(IID_IDeckLinkKeyer, (void **)&self->mKeyer); - } - // we don't need the device anymore, release to avoid leaking - pDL->Release(); - - if (!self->mDLOutput) - THRWEXCP(DeckLinkOpenCard, S_OK); - - if (self->mDLOutput->GetDisplayModeIterator(&pDisplayModeIterator) != S_OK) - THRWEXCP(DeckLinkInternalError, S_OK); - - displayFlags = (self->mUse3D) ? bmdDisplayModeSupports3D : 0; - outputFlags = (self->mUse3D) ? bmdVideoOutputDualStream3D : bmdVideoOutputFlagDefault; - pDisplayMode = NULL; - i = 0; - while (pDisplayModeIterator->Next(&pDisplayMode) == S_OK) { - if (pDisplayMode->GetDisplayMode() == self->mDisplayMode - && (pDisplayMode->GetFlags() & displayFlags) == displayFlags) { - if (self->mDLOutput->DoesSupportVideoMode(self->mDisplayMode, bmdFormat8BitBGRA, outputFlags, &support, NULL) != S_OK || - support == bmdDisplayModeNotSupported) - { - printf("Warning: DeckLink card %d reports no BGRA support, proceed anyway\n", cardIdx); - } - break; - } - pDisplayMode->Release(); - pDisplayMode = NULL; - i++; - } - pDisplayModeIterator->Release(); - - if (!pDisplayMode) - THRWEXCP(DeckLinkBadFormat, S_OK); - self->mSize[0] = pDisplayMode->GetWidth(); - self->mSize[1] = pDisplayMode->GetHeight(); - self->mFrameSize = 4*self->mSize[0]*self->mSize[1]; - pDisplayMode->Release(); - if (self->mDLOutput->EnableVideoOutput(self->mDisplayMode, outputFlags) != S_OK) - // this shouldn't fail - THRWEXCP(DeckLinkOpenCard, S_OK); - - if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, &self->mLeftFrame) != S_OK) - THRWEXCP(DeckLinkInternalError, S_OK); - // clear alpha channel in the frame buffer - self->mLeftFrame->GetBytes((void **)&bytes); - memset(bytes, 0, self->mFrameSize); - if (self->mUse3D) { - if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, &self->mRightFrame) != S_OK) - THRWEXCP(DeckLinkInternalError, S_OK); - // clear alpha channel in the frame buffer - self->mRightFrame->GetBytes((void **)&bytes); - memset(bytes, 0, self->mFrameSize); - } - } - catch (Exception & exp) - { - printf("DeckLink: exception when opening card %d: %s\n", cardIdx, exp.what()); - exp.report(); - // normally, the object should be deallocated - return -1; - } - // initialization succeeded - return 0; -} - - -// close added decklink -PyObject *DeckLink_close(DeckLink * self) -{ - if (self->mLeftFrame) - self->mLeftFrame->Release(); - if (self->mRightFrame) - self->mRightFrame->Release(); - if (self->mKeyer) - self->mKeyer->Release(); - if (self->mDLOutput) - self->mDLOutput->Release(); - decklink_Reset(self); - Py_RETURN_NONE; -} - - -// refresh decklink key frame -static PyObject *DeckLink_refresh(DeckLink *self, PyObject *args) -{ - // get parameter - refresh source - PyObject *param; - double ts = -1.0; - - if (!PyArg_ParseTuple(args, "O|d:refresh", ¶m, &ts) || !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 key frame in decklink, - // 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); - uint32_t *leftEye = NULL; - uint32_t *rightEye = NULL; - // try to process key frame from source - try { - // check if optimization is possible - if (self->m_leftEye != NULL) { - ImageBase *leftImage = self->m_leftEye->m_image; - short * srcSize = leftImage->getSize(); - self->mLeftFrame->GetBytes((void **)&leftEye); - if (srcSize[0] == self->mSize[0] && srcSize[1] == self->mSize[1]) - { - // buffer has same size, can load directly - if (!leftImage->loadImage(leftEye, self->mFrameSize, GL_BGRA, ts)) - leftEye = NULL; - } - else { - // scaling is required, go the hard way - unsigned int *src = leftImage->getImage(0, ts); - if (src != NULL) - decklink_ConvImage(leftEye, self->mSize, src, srcSize, self->mUseExtend); - else - leftEye = NULL; - } - } - if (leftEye) { - if (self->mUse3D && self->m_rightEye != NULL) { - ImageBase *rightImage = self->m_rightEye->m_image; - short * srcSize = rightImage->getSize(); - self->mRightFrame->GetBytes((void **)&rightEye); - if (srcSize[0] == self->mSize[0] && srcSize[1] == self->mSize[1]) - { - // buffer has same size, can load directly - rightImage->loadImage(rightEye, self->mFrameSize, GL_BGRA, ts); - } - else { - // scaling is required, go the hard way - unsigned int *src = rightImage->getImage(0, ts); - if (src != NULL) - decklink_ConvImage(rightEye, self->mSize, src, srcSize, self->mUseExtend); - } - } - if (self->mUse3D) { - DeckLink3DFrameWrapper frame3D( - (IDeckLinkVideoFrame*)self->mLeftFrame, - (IDeckLinkVideoFrame*)self->mRightFrame); - self->mDLOutput->DisplayVideoFrameSync(&frame3D); - } - else { - self->mDLOutput->DisplayVideoFrameSync((IDeckLinkVideoFrame*)self->mLeftFrame); - } - } - // refresh texture source, if required - if (refreshSource) { - if (self->m_leftEye) - self->m_leftEye->m_image->refresh(); - if (self->m_rightEye) - self->m_rightEye->m_image->refresh(); - } - } - CATCH_EXCP; - } - Py_RETURN_NONE; -} - -// get source object -static PyObject *DeckLink_getSource(DeckLink *self, PyObject *value, void *closure) -{ - // if source exists - if (self->m_leftEye != NULL) { - Py_INCREF(self->m_leftEye); - return reinterpret_cast<PyObject*>(self->m_leftEye); - } - // otherwise return None - Py_RETURN_NONE; -} - - -// set source object -int DeckLink_setSource(DeckLink *self, PyObject *value, void *closure) -{ - // check new value - if (value == NULL || !pyImageTypes.in(Py_TYPE(value))) { - // 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_leftEye); - // set new value - self->m_leftEye = reinterpret_cast<PyImage*>(value); - // return success - return 0; -} - -// get source object -static PyObject *DeckLink_getRight(DeckLink *self, PyObject *value, void *closure) -{ - // if source exists - if (self->m_rightEye != NULL) - { - Py_INCREF(self->m_rightEye); - return reinterpret_cast<PyObject*>(self->m_rightEye); - } - // otherwise return None - Py_RETURN_NONE; -} - - -// set source object -static int DeckLink_setRight(DeckLink *self, PyObject *value, void *closure) -{ - // check new value - if (value == NULL || !pyImageTypes.in(Py_TYPE(value))) - { - // 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_rightEye); - // set new value - self->m_rightEye = reinterpret_cast<PyImage*>(value); - // return success - return 0; -} - - -static PyObject *DeckLink_getKeying(DeckLink *self, PyObject *value, void *closure) -{ - if (self->mUseKeying) Py_RETURN_TRUE; - else Py_RETURN_FALSE; -} - -static int DeckLink_setKeying(DeckLink *self, PyObject *value, void *closure) -{ - if (value == NULL || !PyBool_Check(value)) - { - PyErr_SetString(PyExc_TypeError, "The value must be a bool"); - return -1; - } - if (self->mKeyer != NULL) - { - if (value == Py_True) - { - if (self->mKeyer->Enable(false) != S_OK) - { - PyErr_SetString(PyExc_RuntimeError, "Error enabling keyer"); - return -1; - } - self->mUseKeying = true; - self->mKeyer->SetLevel(self->mKeyingLevel); - } - else - { - self->mKeyer->Disable(); - self->mUseKeying = false; - } - } - // success - return 0; -} - -static PyObject *DeckLink_getLevel(DeckLink *self, PyObject *value, void *closure) -{ - return Py_BuildValue("h", self->mKeyingLevel); -} - -static int DeckLink_setLevel(DeckLink *self, PyObject *value, void *closure) -{ - long level; - if (value == NULL || !PyLong_Check(value)) { - PyErr_SetString(PyExc_TypeError, "The value must be an integer from 0 to 255"); - return -1; - } - level = PyLong_AsLong(value); - if (level > 255) - level = 255; - else if (level < 0) - level = 0; - self->mKeyingLevel = (uint8_t)level; - if (self->mUseKeying) { - if (self->mKeyer->SetLevel(self->mKeyingLevel) != S_OK) { - PyErr_SetString(PyExc_RuntimeError, "Error changin level of keyer"); - return -1; - } - } - // success - return 0; -} - -static PyObject *DeckLink_getExtend(DeckLink *self, PyObject *value, void *closure) -{ - if (self->mUseExtend) Py_RETURN_TRUE; - else Py_RETURN_FALSE; -} - -static int DeckLink_setExtend(DeckLink *self, PyObject *value, void *closure) -{ - if (value == NULL || !PyBool_Check(value)) - { - PyErr_SetString(PyExc_TypeError, "The value must be a bool"); - return -1; - } - self->mUseExtend = (value == Py_True); - return 0; -} - -// class DeckLink methods -static PyMethodDef decklinkMethods[] = -{ - { "close", (PyCFunction)DeckLink_close, METH_NOARGS, "Close dynamic decklink and restore original"}, - { "refresh", (PyCFunction)DeckLink_refresh, METH_VARARGS, "Refresh decklink from source"}, - {NULL} /* Sentinel */ -}; - -// class DeckLink attributes -static PyGetSetDef decklinkGetSets[] = -{ - { (char*)"source", (getter)DeckLink_getSource, (setter)DeckLink_setSource, (char*)"source of decklink (left eye)", NULL}, - { (char*)"right", (getter)DeckLink_getRight, (setter)DeckLink_setRight, (char*)"source of decklink (right eye)", NULL }, - { (char*)"keying", (getter)DeckLink_getKeying, (setter)DeckLink_setKeying, (char*)"whether keying is enabled (frame is alpha-composited with passthrough output)", NULL }, - { (char*)"level", (getter)DeckLink_getLevel, (setter)DeckLink_setLevel, (char*)"change the level of keying (overall alpha level of key frame, 0 to 255)", NULL }, - { (char*)"extend", (getter)DeckLink_getExtend, (setter)DeckLink_setExtend, (char*)"whether image should stretched to fit frame", NULL }, - { NULL } -}; - - -// class DeckLink declaration -PyTypeObject DeckLinkType = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.DeckLink", /*tp_name*/ - sizeof(DeckLink), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)DeckLink_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*/ - &imageBufferProcs, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "DeckLink objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - decklinkMethods, /* tp_methods */ - 0, /* tp_members */ - decklinkGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)DeckLink_init, /* tp_init */ - 0, /* tp_alloc */ - DeckLink_new, /* tp_new */ -}; - -#endif /* WITH_GAMEENGINE_DECKLINK */ diff --git a/source/gameengine/VideoTexture/DeckLink.h b/source/gameengine/VideoTexture/DeckLink.h deleted file mode 100644 index 4528fe7cec0..00000000000 --- a/source/gameengine/VideoTexture/DeckLink.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2015, Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Blender Foundation. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file VideoTexture/DeckLink.h - * \ingroup bgevideotex - */ - -#ifndef __DECKLINK_H__ -#define __DECKLINK_H__ - -#ifdef WITH_GAMEENGINE_DECKLINK - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "DNA_image_types.h" - -#include "DeckLinkAPI.h" - -#include "ImageBase.h" -#include "BlendType.h" -#include "Exception.h" - - -// type DeckLink declaration -struct DeckLink -{ - PyObject_HEAD - - // last refresh - double m_lastClock; - // decklink card to which we output - IDeckLinkOutput * mDLOutput; - IDeckLinkKeyer * mKeyer; - IDeckLinkMutableVideoFrame *mLeftFrame; - IDeckLinkMutableVideoFrame *mRightFrame; - bool mUse3D; - bool mUseKeying; - bool mUseExtend; - bool mKeyingSupported; - bool mHDKeyingSupported; - uint8_t mKeyingLevel; - BMDDisplayMode mDisplayMode; - short mSize[2]; - uint32_t mFrameSize; - - // image source - PyImage * m_leftEye; - PyImage * m_rightEye; -}; - - -// DeckLink type description -extern PyTypeObject DeckLinkType; - -// helper function -HRESULT decklink_ReadDisplayMode(const char *format, size_t len, BMDDisplayMode *displayMode); -HRESULT decklink_ReadPixelFormat(const char *format, size_t len, BMDPixelFormat *displayMode); - -#endif /* WITH_GAMEENGINE_DECKLINK */ - -#endif /* __DECKLINK_H__ */ diff --git a/source/gameengine/VideoTexture/Exception.cpp b/source/gameengine/VideoTexture/Exception.cpp deleted file mode 100644 index 9f82987ea62..00000000000 --- a/source/gameengine/VideoTexture/Exception.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2006 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/Exception.cpp - * \ingroup bgevideotex - */ - -#include <sstream> -#include <fstream> - -#include "EXP_PyObjectPlus.h" - -#include "Exception.h" - - -// exception identificators -ExceptionID ErrGeneral, ErrNotFound; - -// exception descriptions -ExpDesc errGenerDesc(ErrGeneral, "General Error"); -ExpDesc errNFoundDesc(ErrNotFound, "Error description not found"); - - - -// implementation of ExpDesc - -// constructor -ExpDesc::ExpDesc (ExceptionID & exp, const char *desc, RESULT hres) -: m_expID(exp), m_hRslt(hres), m_description(desc) -{ -} - -// destructor -ExpDesc::~ExpDesc (void) {} - -// list of descriptions -std::vector<ExpDesc*> ExpDesc::m_expDescs; - - -// class Exception - - -// last exception description -std::string Exception::m_lastError; - -// log file name -const 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, const char *fil, int lin) -: m_expID (&expID), m_hRslt (rslt) -{ - // set file and line - if (fil[0] != '\0' || lin > 0) - setFileLine (fil, lin); - else - m_line = -1; -} - - -// set file and line -void Exception::setFileLine (const char *fil, int lin) -{ - if (fil != NULL) m_fileName = fil; - m_line = lin; -} - - -// report exception -void Exception::report(void) -{ - // set exception description - setXptDesc(); - // set python error - PyErr_SetString(PyExc_RuntimeError, what()); - // if log file is set - if (m_logFile != NULL) - { - // write description to log - std::ofstream logf (m_logFile, std::ios_base::app); - logf << m_fileName << ':' << m_line << ':' << m_desc << std::endl; - logf.flush(); - logf.close(); - } -} - - -// set exception description -void Exception::setXptDesc (void) -{ - // if description is not set - if (m_desc.size() == 0) - { - // start of search -1 - // found description "NotFound" 0 - // found description without matching result 1 - // found description with matching result 2 - int best = -1; - // find exception description - for (std::vector<ExpDesc*>::iterator it = ExpDesc::m_expDescs.begin(); it != ExpDesc::m_expDescs.end(); ++it) - { - // use "NotFound", if there is not better - if (best < 0 && (*it)->isExp(&ErrNotFound) > 0) - { - (*it)->loadDesc(m_desc); - best = 0; - } - // match exception - int nBest = (*it)->isExp(m_expID, m_hRslt); - // if exception is matching better - if (nBest > 0 && best < nBest) - { - // set description - (*it)->loadDesc(m_desc); - best = nBest; - // if matching exactly, finish search - if (best == 2) break; - } - } - // add result code - // length of result code - const size_t rsltSize = 11; - // delimit description - //const char delimRslt[] = ": "; - // set text of description - char rsltTxt[rsltSize]; - std::ostringstream os; - os << std::hex << m_hRslt << ": " << '\0'; - // copy result to description - m_desc.insert(0, rsltTxt); - // copy exception description to last exception string - m_lastError = m_desc; - } -} - - -// copy exception data -void Exception::copy (const Exception & xpt) -{ - // standard data - m_expID = xpt.m_expID; - m_hRslt = xpt.m_hRslt; - m_desc = xpt.m_desc; - - // debug data - m_fileName = xpt.m_fileName; - m_line = xpt.m_line; -} - -void registerAllExceptions(void) -{ - errGenerDesc.registerDesc(); - errNFoundDesc.registerDesc(); - MaterialNotAvailDesc.registerDesc(); - ImageSizesNotMatchDesc.registerDesc(); - ImageHasExportsDesc.registerDesc(); - InvalidColorChannelDesc.registerDesc(); - InvalidImageModeDesc.registerDesc(); - SceneInvalidDesc.registerDesc(); - CameraInvalidDesc.registerDesc(); - ObserverInvalidDesc.registerDesc(); - MirrorInvalidDesc.registerDesc(); - MirrorSizeInvalidDesc.registerDesc(); - MirrorNormalInvalidDesc.registerDesc(); - MirrorHorizontalDesc.registerDesc(); - MirrorTooSmallDesc.registerDesc(); - SourceVideoEmptyDesc.registerDesc(); - SourceVideoCreationDesc.registerDesc(); - OffScreenInvalidDesc.registerDesc(); -#ifdef WITH_GAMEENGINE_DECKLINK - AutoDetectionNotAvailDesc.registerDesc(); - DeckLinkBadDisplayModeDesc.registerDesc(); - DeckLinkBadPixelFormatDesc.registerDesc(); - DeckLinkOpenCardDesc.registerDesc(); - DeckLinkBadFormatDesc.registerDesc(); - DeckLinkInternalErrorDesc.registerDesc(); - SourceVideoOnlyCaptureDesc.registerDesc(); - VideoDeckLinkBadFormatDesc.registerDesc(); - VideoDeckLinkOpenCardDesc.registerDesc(); - VideoDeckLinkDvpInternalErrorDesc.registerDesc(); - VideoDeckLinkPinMemoryErrorDesc.registerDesc(); -#endif -} diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h deleted file mode 100644 index c4de85ff34d..00000000000 --- a/source/gameengine/VideoTexture/Exception.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2006 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/Exception.h - * \ingroup bgevideotex - */ - -#ifndef __EXCEPTION_H__ -#define __EXCEPTION_H__ - -#include <exception> -#include <vector> -#include <string> -#include <algorithm> - -#include "Common.h" - - -#define CHCKHRSLTV(fnc,val,err) \ -{ \ - HRESULT macroHRslt = (fnc); \ - if (macroHRslt != val) \ - throw Exception (err, macroHRslt, __FILE__, __LINE__); \ -} - -#define THRWEXCP(err,hRslt) throw Exception (err, hRslt, __FILE__, __LINE__) - - -#if defined WIN32 - -#define CHCKHRSLT(fnc,err) \ -{ \ - HRESULT macroHRslt = (fnc); \ - if (FAILED(macroHRslt)) \ - throw Exception (err, macroHRslt, __FILE__, __LINE__); \ -} - -#else - -#define CHCKHRSLT(fnc,err) CHCKHRSLTV(fnc,S_OK,err) - -#endif - - -// forward declarations -class ExceptionID; -class Exception; - - -// exception identificators -extern ExceptionID ErrGeneral, ErrNotFound; - - -// result type -typedef long RESULT; - - -// class ExceptionID for exception identification -class ExceptionID -{ -public: - // constructor a destructor - ExceptionID (void) {} - ~ExceptionID (void) {} - -private: - // not allowed - ExceptionID (const ExceptionID & obj) throw() {} - ExceptionID & operator= (const ExceptionID & obj) throw() { return *this; } -}; - - -// class ExpDesc for exception description -class ExpDesc -{ -public: - // constructor a destructor - ExpDesc (ExceptionID & exp, const char * desc, RESULT hres = S_OK); - ~ExpDesc (void); - - // comparision function - // returns 0, if exception identification don't match at all - // returns 1, if only exception identification is matching - // returns 2, if both exception identification and result are matching - int isExp (ExceptionID *exp, RESULT hres = S_OK) throw() - { - // check exception identification - if (&m_expID == exp) - { - // check result value - if (m_hRslt == hres) return 2; - // only identification match - if (m_hRslt == S_OK) return 1; - } - // no match - return 0; - } - - // get exception description - void loadDesc (std::string & desc) throw() - { - desc = m_description; - } - - void registerDesc(void) - { - if (std::find(m_expDescs.begin(), m_expDescs.end(), this) == m_expDescs.end()) - m_expDescs.push_back(this); - } - // list of exception descriptions - static std::vector<ExpDesc*> m_expDescs; - -private: - // exception ID - ExceptionID & m_expID; - // result - RESULT m_hRslt; - // description - const 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, const char * fil, int lin); - // set source file and line of exception - void setFileLine (const 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 const 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 ImageHasExportsDesc; -extern ExpDesc InvalidColorChannelDesc; -extern ExpDesc InvalidImageModeDesc; -extern ExpDesc SceneInvalidDesc; -extern ExpDesc CameraInvalidDesc; -extern ExpDesc ObserverInvalidDesc; -extern ExpDesc OffScreenInvalidDesc; -extern ExpDesc MirrorInvalidDesc; -extern ExpDesc MirrorSizeInvalidDesc; -extern ExpDesc MirrorNormalInvalidDesc; -extern ExpDesc MirrorHorizontalDesc; -extern ExpDesc MirrorTooSmallDesc; -extern ExpDesc SourceVideoEmptyDesc; -extern ExpDesc SourceVideoCreationDesc; -extern ExpDesc DeckLinkBadDisplayModeDesc; -extern ExpDesc DeckLinkBadPixelFormatDesc; -extern ExpDesc AutoDetectionNotAvailDesc; -extern ExpDesc DeckLinkOpenCardDesc; -extern ExpDesc DeckLinkBadFormatDesc; -extern ExpDesc DeckLinkInternalErrorDesc; -extern ExpDesc SourceVideoOnlyCaptureDesc; -extern ExpDesc VideoDeckLinkBadFormatDesc; -extern ExpDesc VideoDeckLinkOpenCardDesc; -extern ExpDesc VideoDeckLinkDvpInternalErrorDesc; -extern ExpDesc VideoDeckLinkPinMemoryErrorDesc; - -extern ExceptionID InvalidImageMode; - -void registerAllExceptions(void); -#endif diff --git a/source/gameengine/VideoTexture/FilterBase.cpp b/source/gameengine/VideoTexture/FilterBase.cpp deleted file mode 100644 index b41a2095890..00000000000 --- a/source/gameengine/VideoTexture/FilterBase.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/FilterBase.cpp - * \ingroup bgevideotex - */ - - -#include "FilterBase.h" - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - - -// FilterBase class implementation - -// constructor -FilterBase::FilterBase (void) : m_previous(NULL) {} - - -// destructor -FilterBase::~FilterBase (void) -{ - // release Python objects, if not released yet - release(); -} - - -// release python objects -void FilterBase::release (void) -{ - // release previous filter object - setPrevious(NULL); -} - - -// set new previous filter -void FilterBase::setPrevious(PyFilter *filt, bool useRefCnt) -{ - // if reference counting has to be used - if (useRefCnt) - { - // reference new filter - if (filt != NULL) Py_INCREF(filt); - // release old filter - Py_XDECREF(m_previous); - } - // set new previous filter - m_previous = filt; -} - - -// find first filter -FilterBase * FilterBase::findFirst (void) -{ - // find first filter in chain - FilterBase * frst; - for (frst = this; frst->m_previous != NULL; frst = frst->m_previous->m_filter) {}; - // set first filter - return frst; -} - - - -// list offilter types -PyTypeList pyFilterTypes; - - - -// functions for python interface - - -// object allocation -PyObject *Filter_allocNew (PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - // allocate object - PyFilter *self = reinterpret_cast<PyFilter*>(type->tp_alloc(type, 0)); - // initialize object structure - self->m_filter = NULL; - // return allocated object - return reinterpret_cast<PyObject*>(self); -} - -// object deallocation -void Filter_dealloc(PyFilter *self) -{ - // release object attributes - if (self->m_filter != NULL) - { - self->m_filter->release(); - delete self->m_filter; - self->m_filter = NULL; - } - Py_TYPE((PyObject *)self)->tp_free((PyObject *)self); -} - - -// get previous pixel filter object -PyObject *Filter_getPrevious (PyFilter *self, void *closure) -{ - // if filter object is available - if (self->m_filter != NULL) - { - // pixel filter object - PyObject *filt = reinterpret_cast<PyObject*>(self->m_filter->getPrevious()); - // if filter is present - if (filt != NULL) - { - // return it - Py_INCREF(filt); - return filt; - } - } - // otherwise return none - Py_RETURN_NONE; -} - - -// set previous pixel filter object -int Filter_setPrevious(PyFilter *self, PyObject *value, void *closure) -{ - // if filter object is available - if (self->m_filter != NULL) - { - // check new value - if (value == NULL || !pyFilterTypes.in(Py_TYPE(value))) - { - // report value error - PyErr_SetString(PyExc_TypeError, "Invalid type of value"); - return -1; - } - // set new value - self->m_filter->setPrevious(reinterpret_cast<PyFilter*>(value)); - } - // return success - return 0; -} diff --git a/source/gameengine/VideoTexture/FilterBase.h b/source/gameengine/VideoTexture/FilterBase.h deleted file mode 100644 index db688d551d0..00000000000 --- a/source/gameengine/VideoTexture/FilterBase.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file FilterBase.h - * \ingroup bgevideotex - */ - -#ifndef __FILTERBASE_H__ -#define __FILTERBASE_H__ - -#include "Common.h" - -#include "EXP_PyObjectPlus.h" - -#include "PyTypeList.h" - -#define VT_C(v,idx) ((unsigned char*)&v)[idx] -#define VT_R(v) ((unsigned char*)&v)[0] -#define VT_G(v) ((unsigned char*)&v)[1] -#define VT_B(v) ((unsigned char*)&v)[2] -#define VT_A(v) ((unsigned char*)&v)[3] -#define VT_RGBA(v,r,g,b,a) VT_R(v)=(unsigned char)r, VT_G(v)=(unsigned char)g, VT_B(v)=(unsigned char)b, VT_A(v)=(unsigned char)a - -#ifdef __BIG_ENDIAN__ -# define VT_SWAPBR(i) ((((i) >> 16) & 0xFF00) + (((i) & 0xFF00) << 16) + ((i) & 0xFF00FF)) -#else -# define VT_SWAPBR(i) ((((i) & 0xFF) << 16) + (((i) >> 16) & 0xFF) + ((i) & 0xFF00FF00)) -#endif - - -// forward declaration -class FilterBase; - - -// python structure for filter -struct PyFilter -{ - PyObject_HEAD - // source object - FilterBase * m_filter; -}; - - -/// base class for pixel filters -class FilterBase -{ -public: - /// constructor - FilterBase (void); - /// destructor - virtual ~FilterBase (void); - // release python objects - virtual void release (void); - - /// convert pixel - template <class SRC> unsigned int convert (SRC src, short x, short y, - short * size, unsigned int pixSize) - { - return filter(src, x, y, size, pixSize, - convertPrevious(src, x, y, size, pixSize)); - } - - /// get previous filter - PyFilter * getPrevious (void) { return m_previous; } - /// set previous filter - void setPrevious (PyFilter *filt, bool useRefCnt = true); - - /// find first filter in chain - FilterBase * findFirst (void); - - /// get first filter's source pixel size - unsigned int firstPixelSize (void) { return findFirst()->getPixelSize(); } - -protected: - /// previous pixel filter - PyFilter * m_previous; - - /// filter pixel, source byte buffer - virtual unsigned int filter(unsigned char *src, short x, short y, - short *size, unsigned int pixSize, unsigned int val = 0) - { return val; } - /// filter pixel, source int buffer - virtual unsigned int filter(unsigned int *src, short x, short y, - short *size, unsigned int pixSize, unsigned int val = 0) - { return val; } - /// filter pixel, source float buffer - virtual unsigned int filter(float *src, short x, short y, - short *size, unsigned int pixSize, unsigned int val = 0) - { return val; } - - /// get source pixel size - virtual unsigned int getPixelSize(void) { return 1; } - - /// get converted pixel from previous filters - template <class SRC> unsigned int convertPrevious (SRC src, short x, short y, - short * size, unsigned int pixSize) - { - // if previous filter doesn't exists, return source pixel - if (m_previous == NULL) return *src; - // otherwise return converted pixel - return m_previous->m_filter->convert(src, x, y, size, pixSize); - } - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:FilterBase") -#endif -}; - - -// list of python filter types -extern PyTypeList pyFilterTypes; - - -// functions for python interface - -// object initialization -template <class T> static int Filter_init (PyObject *pySelf, PyObject *args, PyObject *kwds) -{ - PyFilter *self = reinterpret_cast<PyFilter*>(pySelf); - // create filter object - if (self->m_filter != NULL) delete self->m_filter; - self->m_filter = new T(); - // initialization succeded - return 0; -} - -// object allocation -PyObject *Filter_allocNew(PyTypeObject *type, PyObject *args, PyObject *kwds); -// object deallocation -void Filter_dealloc(PyFilter *self); - -// get previous pixel filter object -PyObject *Filter_getPrevious(PyFilter *self, void *closure); -// set previous pixel filter object -int Filter_setPrevious(PyFilter *self, PyObject *value, void *closure); - - -#endif diff --git a/source/gameengine/VideoTexture/FilterBlueScreen.cpp b/source/gameengine/VideoTexture/FilterBlueScreen.cpp deleted file mode 100644 index a25d09e1eee..00000000000 --- a/source/gameengine/VideoTexture/FilterBlueScreen.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/FilterBlueScreen.cpp - * \ingroup bgevideotex - */ - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "FilterBlueScreen.h" - -#include "FilterBase.h" -#include "PyTypeList.h" - -// implementation FilterBlueScreen - -// constructor -FilterBlueScreen::FilterBlueScreen (void) -{ - // set color to blue - setColor(0, 0, 255); - // set limits - setLimits(64, 64); -} - -// set color -void FilterBlueScreen::setColor (unsigned char red, unsigned char green, unsigned char blue) -{ - m_color[0] = red; - m_color[1] = green; - m_color[2] = blue; -} - -// set limits for color variation -void FilterBlueScreen::setLimits (unsigned short minLimit, unsigned short maxLimit) -{ - m_limits[0] = minLimit; - m_limits[1] = maxLimit > minLimit ? maxLimit : minLimit; - // calculate square values - for (short idx = 0; idx < 2; ++idx) - m_squareLimits[idx] = m_limits[idx] * m_limits[idx]; - // limits distance - m_limitDist = m_squareLimits[1] - m_squareLimits[0]; -} - - - -// cast Filter pointer to FilterBlueScreen -inline FilterBlueScreen * getFilter (PyFilter *self) -{ return static_cast<FilterBlueScreen*>(self->m_filter); } - - -// python methods and get/sets - -// get color -static PyObject *getColor (PyFilter *self, void *closure) -{ - return Py_BuildValue("[BBB]", getFilter(self)->getColor()[0], - getFilter(self)->getColor()[1], getFilter(self)->getColor()[2]); -} - -// set color -static int setColor(PyFilter *self, PyObject *value, void *closure) -{ - // check validity of parameter - if (value == NULL || - !(PyTuple_Check(value) || PyList_Check(value)) || - PySequence_Fast_GET_SIZE(value) != 3 || - !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) || - !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1)) || - !PyLong_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)(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 0))), - (unsigned char)(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 1))), - (unsigned char)(PyLong_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 || - !(PyTuple_Check(value) || PyList_Check(value)) || - PySequence_Fast_GET_SIZE(value) != 2 || - !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) || - !PyLong_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)(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 0))), - (unsigned short)(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 1)))); - // success - return 0; -} - - -// attributes structure -static PyGetSetDef filterBSGetSets[] = -{ - {(char*)"color", (getter)getColor, (setter)setColor, (char*)"blue screen color", NULL}, - {(char*)"limits", (getter)getLimits, (setter)setLimits, (char*)"blue screen color limits", NULL}, - // attributes from FilterBase class - {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL}, - {NULL} -}; - -// define python type -PyTypeObject FilterBlueScreenType = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.FilterBlueScreen", /*tp_name*/ - sizeof(PyFilter), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Filter_dealloc,/*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Filter for Blue Screen objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NULL, /* tp_methods */ - 0, /* tp_members */ - filterBSGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Filter_init<FilterBlueScreen>, /* tp_init */ - 0, /* tp_alloc */ - Filter_allocNew, /* tp_new */ -}; - diff --git a/source/gameengine/VideoTexture/FilterBlueScreen.h b/source/gameengine/VideoTexture/FilterBlueScreen.h deleted file mode 100644 index cf74a6705b7..00000000000 --- a/source/gameengine/VideoTexture/FilterBlueScreen.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of blendTex library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file FilterBlueScreen.h - * \ingroup bgevideotex - */ - -#ifndef __FILTERBLUESCREEN_H__ -#define __FILTERBLUESCREEN_H__ - -#include "Common.h" - -#include "FilterBase.h" - - -/// pixel filter for blue screen -class FilterBlueScreen : public FilterBase -{ -public: - /// constructor - FilterBlueScreen (void); - /// destructor - virtual ~FilterBlueScreen (void) {} - - /// get color - unsigned char * getColor (void) { return m_color; } - /// set color - void setColor (unsigned char red, unsigned char green, unsigned char blue); - - /// get limits for color variation - unsigned short * getLimits (void) { return m_limits; } - /// set limits for color variation - void setLimits (unsigned short minLimit, unsigned short maxLimit); - -protected: - /// blue screen color (red component first) - unsigned char m_color[3]; - /// limits for color variation - first defines, where ends fully transparent - /// color, second defines, where begins fully opaque color - unsigned short m_limits[2]; - /// squared limits for color variation - unsigned int m_squareLimits[2]; - /// distance between squared limits - unsigned int m_limitDist; - - /// filter pixel template, source int buffer - template <class SRC> unsigned int tFilter (SRC src, short x, short y, - short * size, unsigned int pixSize, unsigned int val) - { - // calculate differences - int difRed = int(VT_R(val)) - int(m_color[0]); - int difGreen = int(VT_G(val)) - int(m_color[1]); - int difBlue = int(VT_B(val)) - int(m_color[2]); - // calc distance from "blue screen" color - unsigned int dist = (unsigned int)(difRed * difRed + difGreen * difGreen - + difBlue * difBlue); - // condition for fully transparent color - if (m_squareLimits[0] >= dist) - // return color with zero alpha - VT_A(val) = 0; - // condition for fully opaque color - else if (m_squareLimits[1] <= dist) - // return normal color - VT_A(val) = 0xFF; - // otherwise calc alpha - else - VT_A(val) = (((dist - m_squareLimits[0]) << 8) / m_limitDist); - return val; - } - - /// virtual filtering function for byte source - virtual unsigned int filter (unsigned char *src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { return tFilter(src, x, y, size, pixSize, val); } - /// virtual filtering function for unsigned int source - virtual unsigned int filter (unsigned int *src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { return tFilter(src, x, y, size, pixSize, val); } -}; - - -#endif diff --git a/source/gameengine/VideoTexture/FilterColor.cpp b/source/gameengine/VideoTexture/FilterColor.cpp deleted file mode 100644 index 15a7e9e4cd1..00000000000 --- a/source/gameengine/VideoTexture/FilterColor.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/FilterColor.cpp - * \ingroup bgevideotex - */ - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "FilterColor.h" - -#include "FilterBase.h" -#include "PyTypeList.h" - -// implementation FilterGray - -// attributes structure -static PyGetSetDef filterGrayGetSets[] = -{ // attributes from FilterBase class - {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL}, - {NULL} -}; - -// define python type -PyTypeObject FilterGrayType = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "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 grayscale effect", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NULL, /* tp_methods */ - 0, /* tp_members */ - filterGrayGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Filter_init<FilterGray>, /* tp_init */ - 0, /* tp_alloc */ - Filter_allocNew, /* tp_new */ -}; - - -// implementation FilterColor - -// constructor -FilterColor::FilterColor (void) -{ - // reset color matrix to identity - for (int r = 0; r < 4; ++r) - for (int c = 0; c < 5; ++c) - m_matrix[r][c] = (r == c) ? 256 : 0; -} - -// set color matrix -void FilterColor::setMatrix (ColorMatrix & mat) -{ - // copy matrix - for (int r = 0; r < 4; ++r) - for (int c = 0; c < 5; ++c) - m_matrix[r][c] = mat[r][c]; -} - - - -// cast Filter pointer to FilterColor -inline FilterColor * getFilterColor (PyFilter *self) -{ return static_cast<FilterColor*>(self->m_filter); } - - -// python methods and get/sets - -// get color matrix -static PyObject *getMatrix (PyFilter *self, void *closure) -{ - ColorMatrix & mat = getFilterColor(self)->getMatrix(); - return Py_BuildValue("((hhhhh)(hhhhh)(hhhhh)(hhhhh))", - mat[0][0], mat[0][1], mat[0][2], mat[0][3], mat[0][4], - mat[1][0], mat[1][1], mat[1][2], mat[1][3], mat[1][4], - mat[2][0], mat[2][1], mat[2][2], mat[2][3], mat[2][4], - mat[3][0], mat[3][1], mat[3][2], mat[3][3], mat[3][4]); -} - -// set color matrix -static int setMatrix(PyFilter *self, PyObject *value, void *closure) -{ - // matrix to store items - ColorMatrix mat; - // check validity of parameter - bool valid = value != NULL && PySequence_Check(value) - && PySequence_Size(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_Size(row) == 5; - // check items - for (int c = 0; valid && c < 5; ++c) - { - // item must be int - valid = PyLong_Check(PySequence_Fast_GET_ITEM(row, c)); - // if it is valid, save it in matrix - if (valid) - mat[r][c] = short(PyLong_AsLong(PySequence_Fast_GET_ITEM(row, c))); - } - } - // if parameter is not valid, report error - if (!valid) - { - PyErr_SetString(PyExc_TypeError, "The value must be a matrix [4][5] of ints"); - return -1; - } - // set color matrix - getFilterColor(self)->setMatrix(mat); - // success - return 0; -} - - -// attributes structure -static PyGetSetDef filterColorGetSets[] = -{ - {(char*)"matrix", (getter)getMatrix, (setter)setMatrix, (char*)"matrix [4][5] for color calculation", NULL}, - // attributes from FilterBase class - {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL}, - {NULL} -}; - -// define python type -PyTypeObject FilterColorType = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.FilterColor", /*tp_name*/ - sizeof(PyFilter), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Filter_dealloc,/*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Filter for color calculations", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NULL, /* tp_methods */ - 0, /* tp_members */ - filterColorGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Filter_init<FilterColor>, /* tp_init */ - 0, /* tp_alloc */ - Filter_allocNew, /* tp_new */ -}; - -// implementation FilterLevel - -// constructor -FilterLevel::FilterLevel (void) -{ - // reset color levels - for (int r = 0; r < 4; ++r) - { - levels[r][0] = 0; - levels[r][1] = 0xFF; - levels[r][2] = 0xFF; - } -} - -// set color levels -void FilterLevel::setLevels (ColorLevel & lev) -{ - // copy levels - for (int r = 0; r < 4; ++r) - { - for (int c = 0; c < 2; ++c) - levels[r][c] = lev[r][c]; - levels[r][2] = lev[r][0] < lev[r][1] ? lev[r][1] - lev[r][0] : 1; - } -} - - -// cast Filter pointer to FilterLevel -inline FilterLevel * getFilterLevel (PyFilter *self) -{ return static_cast<FilterLevel*>(self->m_filter); } - - -// python methods and get/sets - -// get color levels -static PyObject *getLevels (PyFilter *self, void *closure) -{ - ColorLevel & lev = getFilterLevel(self)->getLevels(); - return Py_BuildValue("((HH)(HH)(HH)(HH))", - lev[0][0], lev[0][1], lev[1][0], lev[1][1], - lev[2][0], lev[2][1], lev[3][0], lev[3][1]); -} - -// set color levels -static int setLevels(PyFilter *self, PyObject *value, void *closure) -{ - // matrix to store items - ColorLevel lev; - // check validity of parameter - bool valid = value != NULL && PySequence_Check(value) - && PySequence_Size(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_Size(row) == 2; - // check items - for (int c = 0; valid && c < 2; ++c) - { - // item must be int - valid = PyLong_Check(PySequence_Fast_GET_ITEM(row, c)); - // if it is valid, save it in matrix - if (valid) - lev[r][c] = (unsigned short)(PyLong_AsLong(PySequence_Fast_GET_ITEM(row, c))); - } - } - // if parameter is not valid, report error - if (!valid) - { - PyErr_SetString(PyExc_TypeError, "The value must be a matrix [4][2] of ints"); - return -1; - } - // set color matrix - getFilterLevel(self)->setLevels(lev); - // success - return 0; -} - - -// attributes structure -static PyGetSetDef filterLevelGetSets[] = -{ - {(char*)"levels", (getter)getLevels, (setter)setLevels, (char*)"levels matrix [4] (min, max)", NULL}, - // attributes from FilterBase class - {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL}, - {NULL} -}; - -// define python type -PyTypeObject FilterLevelType = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.FilterLevel", /*tp_name*/ - sizeof(PyFilter), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Filter_dealloc,/*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Filter for levels calculations", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NULL, /* tp_methods */ - 0, /* tp_members */ - filterLevelGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Filter_init<FilterLevel>, /* tp_init */ - 0, /* tp_alloc */ - Filter_allocNew, /* tp_new */ -}; - diff --git a/source/gameengine/VideoTexture/FilterColor.h b/source/gameengine/VideoTexture/FilterColor.h deleted file mode 100644 index d042863d7e8..00000000000 --- a/source/gameengine/VideoTexture/FilterColor.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of blendTex library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file FilterColor.h - * \ingroup bgevideotex - */ - -#ifndef __FILTERCOLOR_H__ -#define __FILTERCOLOR_H__ - -#include "Common.h" - -#include "FilterBase.h" - - -/// pixel filter for grayscale -class FilterGray : public FilterBase -{ -public: - /// constructor - FilterGray (void) {} - /// destructor - virtual ~FilterGray (void) {} - -protected: - /// filter pixel template, source int buffer - template <class SRC> unsigned int tFilter (SRC src, short x, short y, - short * size, unsigned int pixSize, unsigned int val) - { - // calculate gray value - unsigned int gray = (28 * (VT_B(val)) + 151 * (VT_G(val)) - + 77 * (VT_R(val))) >> 8; - // return grayscale value - VT_R(val) = gray; - VT_G(val) = gray; - VT_B(val) = gray; - return val; - } - - /// virtual filtering function for byte source - virtual unsigned int filter (unsigned char * src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { return tFilter(src, x, y, size, pixSize, val); } - /// virtual filtering function for unsigned int source - virtual unsigned int filter (unsigned int * src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { return tFilter(src, x, y, size, pixSize, val); } -}; - - -/// type for color matrix -typedef short ColorMatrix[4][5]; - -/// pixel filter for color calculation -class FilterColor : public FilterBase -{ -public: - /// constructor - FilterColor (void); - /// destructor - virtual ~FilterColor (void) {} - - /// get color matrix - ColorMatrix & getMatrix (void) { return m_matrix; } - /// set color matrix - void setMatrix (ColorMatrix & mat); - -protected: - /// color calculation matrix - ColorMatrix m_matrix; - - /// calculate one color component - unsigned char calcColor (unsigned int val, short idx) - { - return (((m_matrix[idx][0] * (VT_R(val)) + m_matrix[idx][1] * (VT_G(val)) + - m_matrix[idx][2] * (VT_B(val)) + m_matrix[idx][3] * (VT_A(val)) + - m_matrix[idx][4]) >> 8) & 0xFF); - } - - /// filter pixel template, source int buffer - template <class SRC> unsigned int tFilter (SRC src, short x, short y, - short * size, unsigned int pixSize, unsigned int val) - { - // return calculated color - int color; - VT_RGBA(color, calcColor(val, 0), calcColor(val, 1), calcColor(val, 2), calcColor(val, 3)); - return color; - } - - /// virtual filtering function for byte source - virtual unsigned int filter (unsigned char * src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { return tFilter(src, x, y, size, pixSize, val); } - /// virtual filtering function for unsigned int source - virtual unsigned int filter (unsigned int * src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { return tFilter(src, x, y, size, pixSize, val); } -}; - - -/// type for color levels -typedef unsigned short ColorLevel[4][3]; - -/// pixel filter for color calculation -class FilterLevel : public FilterBase -{ -public: - /// constructor - FilterLevel (void); - /// destructor - virtual ~FilterLevel (void) {} - - /// get color matrix - ColorLevel & getLevels (void) { return levels; } - /// set color matrix - void setLevels (ColorLevel & lev); - -protected: - /// color calculation matrix - ColorLevel levels; - - /// calculate one color component - unsigned int calcColor (unsigned int val, short idx) - { - unsigned int col = VT_C(val,idx); - if (col <= levels[idx][0]) col = 0; - else if (col >= levels[idx][1]) col = 0xFF; - else col = (((col - levels[idx][0]) << 8) / levels[idx][2]) & 0xFF; - return col; - } - - /// filter pixel template, source int buffer - template <class SRC> unsigned int tFilter (SRC src, short x, short y, - short * size, unsigned int pixSize, unsigned int val) - { - // return calculated color - int color; - VT_RGBA(color, calcColor(val, 0), calcColor(val, 1), calcColor(val, 2), calcColor(val, 3)); - return color; - } - - /// virtual filtering function for byte source - virtual unsigned int filter (unsigned char * src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { return tFilter(src, x, y, size, pixSize, val); } - /// virtual filtering function for unsigned int source - virtual unsigned int filter (unsigned int * src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { return tFilter(src, x, y, size, pixSize, val); } -}; - - -#endif diff --git a/source/gameengine/VideoTexture/FilterNormal.cpp b/source/gameengine/VideoTexture/FilterNormal.cpp deleted file mode 100644 index 3a5333710fd..00000000000 --- a/source/gameengine/VideoTexture/FilterNormal.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/FilterNormal.cpp - * \ingroup bgevideotex - */ - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "FilterNormal.h" - -#include "FilterBase.h" -#include "PyTypeList.h" - -// implementation FilterNormal - -// constructor -FilterNormal::FilterNormal (void) : m_colIdx(0) -{ - // set default depth - setDepth(4); -} - -// set color shift -void FilterNormal::setColor (unsigned short colIdx) -{ - // check validity of index - if (colIdx < 3) - // set color shift - m_colIdx = colIdx; -} - -// set depth -void FilterNormal::setDepth (float depth) -{ - m_depth = depth; - m_depthScale = depth / depthScaleKoef; -} - - -// cast Filter pointer to FilterNormal -inline FilterNormal * getFilter (PyFilter *self) -{ return static_cast<FilterNormal*>(self->m_filter); } - - -// python methods and get/sets - -// get index of color used to calculate normal -static PyObject *getColor (PyFilter *self, void *closure) -{ - return Py_BuildValue("H", getFilter(self)->getColor()); -} - -// set index of color used to calculate normal -static int setColor(PyFilter *self, PyObject *value, void *closure) -{ - // check validity of parameter - if (value == NULL || !PyLong_Check(value)) - { - PyErr_SetString(PyExc_TypeError, "filt.colorIdx = int: VideoTexture.FilterNormal, expected the value must be a int"); - return -1; - } - // set color index - getFilter(self)->setColor((unsigned short)(PyLong_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) - { - float depth= (float)PyFloat_AsDouble(value); - if ((depth==-1 && PyErr_Occurred()) == 0) /* no error converting to a float? */ - { - // set depth - getFilter(self)->setDepth(depth); - // success - return 0; - } - } - - PyErr_SetString(PyExc_TypeError, "filt.depth = float: VideoTexture.FilterNormal, expected the value must be a float"); - return -1; -} - - -// attributes structure -static PyGetSetDef filterNormalGetSets[] = -{ - {(char*)"colorIdx", (getter)getColor, (setter)setColor, (char*)"index of color used to calculate normal (0 - red, 1 - green, 2 - blue)", NULL}, - {(char*)"depth", (getter)getDepth, (setter)setDepth, (char*)"depth of relief", NULL}, - // attributes from FilterBase class - {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL}, - {NULL} -}; - -// define python type -PyTypeObject FilterNormalType = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.FilterNormal", /*tp_name*/ - sizeof(PyFilter), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Filter_dealloc,/*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Filter for Blue Screen objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NULL, /* tp_methods */ - 0, /* tp_members */ - filterNormalGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Filter_init<FilterNormal>, /* tp_init */ - 0, /* tp_alloc */ - Filter_allocNew, /* tp_new */ -}; - diff --git a/source/gameengine/VideoTexture/FilterNormal.h b/source/gameengine/VideoTexture/FilterNormal.h deleted file mode 100644 index 951ecb84d9d..00000000000 --- a/source/gameengine/VideoTexture/FilterNormal.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of blendTex library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file FilterNormal.h - * \ingroup bgevideotex - */ - -#ifndef __FILTERNORMAL_H__ -#define __FILTERNORMAL_H__ - -#include "Common.h" - -#include "FilterBase.h" - - -// scale constants for normals -const float depthScaleKoef = 255.0; -const float normScaleKoef = float(depthScaleKoef / 2.0); - - -/// pixel filter for normal mapping -class FilterNormal : public FilterBase -{ -public: - /// constructor - FilterNormal (void); - /// destructor - virtual ~FilterNormal (void) {} - - /// get index of color used to calculate normals - unsigned short getColor (void) { return m_colIdx; } - /// set index of color used to calculate normals - void setColor (unsigned short colIdx); - - /// get depth - float getDepth (void) { return m_depth; } - /// set depth - void setDepth (float depth); - -protected: - /// depth of normal relief - float m_depth; - /// scale to calculate normals - float m_depthScale; - - /// color index, 0=red, 1=green, 2=blue, 3=alpha - unsigned short m_colIdx; - - /// filter pixel, source int buffer - template <class SRC> unsigned int tFilter (SRC *src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { - // get value of required color - int actPix = int(VT_C(val,m_colIdx)); - int upPix = actPix; - int leftPix = actPix; - // get upper and left pixel from actual pixel - if (y > 0) - { - val = convertPrevious(src - pixSize * size[0], x, y - 1, size, pixSize); - upPix = VT_C(val,m_colIdx); - } - if (x > 0) - { - val = convertPrevious(src - pixSize, x - 1, y, size, pixSize); - leftPix = VT_C(val,m_colIdx); - } - // height differences (from blue color) - float dx = (actPix - leftPix) * m_depthScale; - float dy = (actPix - upPix) * m_depthScale; - // normalize vector - float dz = float(normScaleKoef / sqrt(dx * dx + dy * dy + 1.0)); - dx = dx * dz + normScaleKoef; - dy = dy * dz + normScaleKoef; - dz += normScaleKoef; - // return normal vector converted to color - VT_RGBA(val, dx, dy, dz, 0xFF); - return val; - } - - /// filter pixel, source byte buffer - virtual unsigned int filter (unsigned char * src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { return tFilter(src, x, y, size, pixSize, val); } - /// filter pixel, source int buffer - virtual unsigned int filter (unsigned int * src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { return tFilter(src, x, y, size, pixSize, val); } -}; - - -#endif diff --git a/source/gameengine/VideoTexture/FilterSource.cpp b/source/gameengine/VideoTexture/FilterSource.cpp deleted file mode 100644 index c8faa1f9f07..00000000000 --- a/source/gameengine/VideoTexture/FilterSource.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/FilterSource.cpp - * \ingroup bgevideotex - */ - -// implementation - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "FilterSource.h" - -#include "FilterBase.h" -#include "PyTypeList.h" - - -// FilterRGB24 - -// define python type -PyTypeObject FilterRGB24Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.FilterRGB24", /*tp_name*/ - sizeof(PyFilter), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Filter_dealloc,/*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Source filter RGB24 objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NULL, /* tp_methods */ - 0, /* tp_members */ - NULL, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Filter_init<FilterRGB24>, /* tp_init */ - 0, /* tp_alloc */ - Filter_allocNew, /* tp_new */ -}; - -// FilterRGBA32 - -// define python type -PyTypeObject FilterRGBA32Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.FilterRGBA32", /*tp_name*/ - sizeof(PyFilter), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Filter_dealloc,/*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Source filter RGBA32 objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NULL, /* tp_methods */ - 0, /* tp_members */ - NULL, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Filter_init<FilterRGBA32>, /* tp_init */ - 0, /* tp_alloc */ - Filter_allocNew, /* tp_new */ -}; - -// FilterBGR24 - -// define python type -PyTypeObject FilterBGR24Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.FilterBGR24", /*tp_name*/ - sizeof(PyFilter), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Filter_dealloc,/*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Source filter BGR24 objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NULL, /* tp_methods */ - 0, /* tp_members */ - NULL, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Filter_init<FilterBGR24>, /* tp_init */ - 0, /* tp_alloc */ - Filter_allocNew, /* tp_new */ -}; - diff --git a/source/gameengine/VideoTexture/FilterSource.h b/source/gameengine/VideoTexture/FilterSource.h deleted file mode 100644 index 820576dfff9..00000000000 --- a/source/gameengine/VideoTexture/FilterSource.h +++ /dev/null @@ -1,352 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of blendTex library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file FilterSource.h - * \ingroup bgevideotex - */ - -#ifndef __FILTERSOURCE_H__ -#define __FILTERSOURCE_H__ - -#include "Common.h" - -#include "FilterBase.h" - -/// class for RGB24 conversion -class FilterRGB24 : public FilterBase -{ -public: - /// constructor - FilterRGB24 (void) {} - /// destructor - virtual ~FilterRGB24 (void) {} - - /// get source pixel size - virtual unsigned int getPixelSize (void) { return 3; } - -protected: - /// filter pixel, source byte buffer - virtual unsigned int filter (unsigned char *src, short x, short y, - short * size, unsigned int pixSize, unsigned int val) - { VT_RGBA(val,src[0],src[1],src[2],0xFF); return val; } -}; - -/// class for RGBA32 conversion -class FilterRGBA32 : public FilterBase -{ -public: - /// constructor - FilterRGBA32 (void) {} - /// destructor - virtual ~FilterRGBA32 (void) {} - - /// get source pixel size - virtual unsigned int getPixelSize (void) { return 4; } - -protected: - /// filter pixel, source byte buffer - virtual unsigned int filter (unsigned char *src, short x, short y, - short * size, unsigned int pixSize, unsigned int val) - { - if ((intptr_t(src)&0x3) == 0) - return *(unsigned int*)src; - else - { - VT_RGBA(val,src[0],src[1],src[2],src[3]); - return val; - } - } -}; - -/// class for BGRA32 conversion -class FilterBGRA32 : public FilterBase -{ -public: - /// constructor - FilterBGRA32 (void) {} - /// destructor - virtual ~FilterBGRA32 (void) {} - - /// get source pixel size - virtual unsigned int getPixelSize (void) { return 4; } - -protected: - /// filter pixel, source byte buffer - virtual unsigned int filter( - unsigned char *src, short x, short y, - short * size, unsigned int pixSize, unsigned int val) - { - VT_RGBA(val,src[2],src[1],src[0],src[3]); - return val; - } -}; - - -/// class for BGR24 conversion -class FilterBGR24 : public FilterBase -{ -public: - /// constructor - FilterBGR24 (void) {} - /// destructor - virtual ~FilterBGR24 (void) {} - - /// get source pixel size - virtual unsigned int getPixelSize (void) { return 3; } - -protected: - /// filter pixel, source byte buffer - virtual unsigned int filter (unsigned char *src, short x, short y, - short * size, unsigned int pixSize, unsigned int val) - { VT_RGBA(val,src[2],src[1],src[0],0xFF); return val; } -}; - -/// class for Z_buffer conversion -class FilterZZZA : public FilterBase -{ -public: - /// constructor - FilterZZZA (void) {} - /// destructor - virtual ~FilterZZZA (void) {} - - /// get source pixel size - virtual unsigned int getPixelSize (void) { return 1; } - -protected: - /// filter pixel, source float buffer - virtual unsigned int filter (float *src, short x, short y, - short * size, unsigned int pixSize, unsigned int val) - { - // calculate gray value - // convert float to unsigned char - unsigned int depth = int(src[0] * 255); - // return depth scale value - VT_R(val) = depth; - VT_G(val) = depth; - VT_B(val) = depth; - VT_A(val) = 0xFF; - - return val; - } -}; - - -/// class for Z_buffer conversion -class FilterDEPTH : public FilterBase -{ -public: - /// constructor - FilterDEPTH (void) {} - /// destructor - virtual ~FilterDEPTH (void) {} - - /// get source pixel size - virtual unsigned int getPixelSize (void) { return 1; } - -protected: - /// filter pixel, source float buffer - virtual unsigned int filter (float *src, short x, short y, - short *size, unsigned int pixSize, unsigned int val) - { - /* Copy the float value straight away - * The user can retrieve the original float value by using - * 'F' mode in BGL buffer */ - memcpy(&val, src, sizeof (unsigned int)); - return val; - } -}; - - - - -/// class for YV12 conversion -class FilterYV12 : public FilterBase -{ -public: - /// constructor - FilterYV12 (void): m_buffV(NULL), m_buffU(NULL), m_pitchUV(0) {} - /// 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, const short size[2]) - { return x <= 1 || x >= size[0] - 4 || y <= 1 || y >= size[1] - 4; } - - /// get the first parameter on the low edge - unsigned char * interParA (unsigned char *src, short x, short size, short shift) - { return x > 1 ? src - shift : src; } - /// get the third parameter on the high edge - unsigned char * interParC (unsigned char *src, short x, short size, short shift) - { return x < size - 2 ? src + shift : src; } - /// get the fourth parameter on the high edge - unsigned char * interParD (unsigned char *src, short x, short size, short shift) - { return x < size - 4 ? src + 2 * shift : x < size - 2 ? src + shift : src; } - - /// horizontal interpolation on edges - int interpolEH (unsigned char *src, short x, short size) - { - return interpol(*interParA(src, x, size, 1), *src, - *interParC(src, x, size, 1), *interParD(src, x, size, 1)); - } - - /// vertical interpolation on edges - int interpolEV (unsigned char *src, short y, short size) - { - return interpol(*interParA(src, y, size, m_pitchUV), *src, - *interParC(src, y, size, m_pitchUV), *interParD(src, y, size, m_pitchUV)); - } - - /// joined vertical and horizontal interpolation on edges - int interpolEVH (unsigned char *src, short x, short y, short * size) - { - return interpol(interpolEV(interParA(src, x, size[0], 1), y, size[1]), - interpolEV(src, y, size[1]), interpolEV(interParC(src, x, size[0], 1), y, size[1]), - interpolEV(interParD(src, x, size[0], 1), y, size[1])); - } - - - /// filter pixel, source byte buffer - virtual unsigned int filter (unsigned char *src, short x, short y, - short * size, unsigned int pixSize, unsigned int val) - { - // V & U offset - long offset = (x >> 1) + m_pitchUV * (y >> 1); - // get modified YUV -> CDE: C = Y - 16; D = U - 128; E = V - 128 - int c = *src - 16; - int d = m_buffU[offset] - 128; - int e = m_buffV[offset] - 128; - // if horizontal interpolation is needed - if ((x & 1) == 1) { - // if vertical interpolation is needed too - if ((y & 1) == 1) - { - // if this pixel is on the edge - if (isEdge(x, y, size)) - { - // get U & V from edge - d = interpolEVH(m_buffU + offset, x, y, size) - 128; - e = interpolEVH(m_buffV + offset, x, y, size) - 128; - } - // otherwise get U & V from inner range - else - { - d = interpolVH(m_buffU + offset) - 128; - e = interpolVH(m_buffV + offset) - 128; - } - // otherwise use horizontal interpolation only - } - else { - // if this pixel is on the edge - if (isEdge(x, y, size)) - { - // get U & V from edge - d = interpolEH(m_buffU + offset, x, size[0]) - 128; - e = interpolEH(m_buffV + offset, x, size[0]) - 128; - } - // otherwise get U & V from inner range - else - { - d = interpolH(m_buffU + offset) - 128; - e = interpolH(m_buffV + offset) - 128; - } - // otherwise if only vertical interpolation is needed - } - } - else if ((y & 1) == 1) { - // if this pixel is on the edge - if (isEdge(x, y, size)) - { - // get U & V from edge - d = interpolEV(m_buffU + offset, y, size[1]) - 128; - e = interpolEV(m_buffV + offset, y, size[1]) - 128; - } - // otherwise get U & V from inner range - else - { - d = interpolV(m_buffU + offset) - 128; - e = interpolV(m_buffV + offset) - 128; - } - } - // convert to RGB - // R = clip(( 298 * C + 409 * E + 128) >> 8) - // G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8) - // B = clip(( 298 * C + 516 * D + 128) >> 8) - int red = (298 * c + 409 * e + 128) >> 8; - if (red >= 0x100) red = 0xFF; - else if (red < 0) red = 0; - int green = (298 * c - 100 * d - 208 * e) >> 8; - if (green >= 0x100) green = 0xFF; - else if (green < 0) green = 0; - int blue = (298 * c + 516 * d + 128) >> 8; - if (blue >= 0x100) blue = 0xFF; - else if (blue < 0) blue = 0; - // return result - VT_RGBA(val, red, green, blue, 0xFF); - return val; - } -}; - -#endif /* __FILTERSOURCE_H__ */ diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp deleted file mode 100644 index a547d2a7a85..00000000000 --- a/source/gameengine/VideoTexture/ImageBase.cpp +++ /dev/null @@ -1,834 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/ImageBase.cpp - * \ingroup bgevideotex - */ - -#include "ImageBase.h" -extern "C" { -#include "bgl.h" -} - -#include <vector> -#include <string.h> - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "FilterBase.h" - -#include "Exception.h" - -#if (defined(WIN32) || defined(WIN64)) -#define strcasecmp _stricmp -#endif - -// ImageBase class implementation - -ExceptionID ImageHasExports; -ExceptionID InvalidColorChannel; -ExceptionID InvalidImageMode; - -ExpDesc ImageHasExportsDesc(ImageHasExports, "Image has exported buffers, cannot resize"); -ExpDesc InvalidColorChannelDesc(InvalidColorChannel, "Invalid or too many color channels specified. At most 4 values within R, G, B, A, 0, 1"); -ExpDesc InvalidImageModeDesc(InvalidImageMode, "Invalid image mode, only RGBA and BGRA are supported"); - -// constructor -ImageBase::ImageBase (bool staticSrc) : m_image(NULL), m_imgSize(0), -m_avail(false), m_scale(false), m_scaleChange(false), m_flip(false), -m_zbuff(false), -m_depth(false), -m_staticSources(staticSrc), m_pyfilter(NULL) -{ - m_size[0] = m_size[1] = 0; - m_exports = 0; -} - - -// destructor -ImageBase::~ImageBase (void) -{ - // release image - if (m_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, double ts) -{ - // 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(ts); - // init image - init(m_sources[0]->getSize()[0], m_sources[0]->getSize()[1]); - } - // calculate new image - calcImage(texId, ts); - } - // if image is available, return it, otherwise NULL - return m_avail ? m_image : NULL; -} - -bool ImageBase::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts) -{ - unsigned int *d, *s, v, len; - if (getImage(0, ts) != NULL && size >= getBuffSize()) { - switch (format) { - case GL_RGBA: - memcpy(buffer, m_image, getBuffSize()); - break; - case GL_BGRA: - len = (unsigned int)m_size[0] * m_size[1]; - for (s=m_image, d=buffer; len; len--) { - v = *s++; - *d++ = VT_SWAPBR(v); - } - break; - default: - THRWEXCP(InvalidImageMode,S_OK); - } - return true; - } - return false; -} - -// 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; -} - -void ImageBase::swapImageBR() -{ - unsigned int size, v, *s; - - if (m_avail) { - size = 1 * m_size[0] * m_size[1]; - for (s=m_image; size; size--) { - v = *s; - *s++ = VT_SWAPBR(v); - } - } -} - -// 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]) - { - if (m_exports > 0) - THRWEXCP(ImageHasExports,S_OK); - - // 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 - if (m_image) - 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 (double ts) -{ - // if source is available - if (m_source != NULL) - // get image from source - m_image = m_source->m_image->getImage(0, ts); - // otherwise reset buffer - else - m_image = NULL; - // return image - return m_image; -} - - -// refresh source -void ImageSource::refresh (void) -{ - // if source is available, refresh it - if (m_source != NULL) m_source->m_image->refresh(); -} - - - -// list of image types -PyTypeList pyImageTypes; - - - -// functions for python interface - -// object allocation -PyObject *Image_allocNew(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - // allocate object - PyImage *self = reinterpret_cast<PyImage*>(type->tp_alloc(type, 0)); - // initialize object structure - self->m_image = NULL; - // return allocated object - return reinterpret_cast<PyObject*>(self); -} - -// object deallocation -void Image_dealloc(PyImage *self) -{ - // release object attributes - if (self->m_image != NULL) - { - if (self->m_image->m_exports > 0) - { - PyErr_SetString(PyExc_SystemError, - "deallocated Image object has exported buffers"); - PyErr_Print(); - } - // if release requires deleting of object, do it - if (self->m_image->release()) - delete self->m_image; - self->m_image = NULL; - } - Py_TYPE((PyObject *)self)->tp_free((PyObject *)self); -} - -// get image data -PyObject *Image_getImage(PyImage *self, char *mode) -{ - try - { - unsigned int * image = self->m_image->getImage(); - if (image) - { - // build BGL buffer - int dimensions = self->m_image->getBuffSize(); - Buffer * buffer; - if (mode == NULL || !strcasecmp(mode, "RGBA")) - { - buffer = BGL_MakeBuffer( GL_BYTE, 1, &dimensions, image); - } - else if (!strcasecmp(mode, "F")) - { - // this mode returns the image as an array of float. - // This makes sense ONLY for the depth buffer: - // source = VideoTexture.ImageViewport() - // source.depth = True - // depth = VideoTexture.imageToArray(source, 'F') - - // adapt dimension from byte to float - dimensions /= sizeof(float); - buffer = BGL_MakeBuffer( GL_FLOAT, 1, &dimensions, image); - } - else - { - int i, c, ncolor, pixels; - int offset[4]; - unsigned char *s, *d; - // scan the mode to get the channels requested, no more than 4 - for (i=ncolor=0; mode[i] != 0 && ncolor < 4; i++) - { - switch (toupper(mode[i])) - { - case 'R': - offset[ncolor++] = 0; - break; - case 'G': - offset[ncolor++] = 1; - break; - case 'B': - offset[ncolor++] = 2; - break; - case 'A': - offset[ncolor++] = 3; - break; - case '0': - offset[ncolor++] = -1; - break; - case '1': - offset[ncolor++] = -2; - break; - // if you add more color code, change the switch further down - default: - THRWEXCP(InvalidColorChannel,S_OK); - } - } - if (mode[i] != 0) { - THRWEXCP(InvalidColorChannel,S_OK); - } - // first get the number of pixels - pixels = dimensions / 4; - // multiple by the number of channels, each is one byte - dimensions = pixels * ncolor; - // get an empty buffer - buffer = BGL_MakeBuffer( GL_BYTE, 1, &dimensions, NULL); - // and fill it - for (i = 0, d = (unsigned char *)buffer->buf.asbyte, s = (unsigned char *)image; - i < pixels; - i++, d += ncolor, s += 4) - { - for (c=0; c<ncolor; c++) - { - switch (offset[c]) - { - case 0: d[c] = s[0]; break; - case 1: d[c] = s[1]; break; - case 2: d[c] = s[2]; break; - case 3: d[c] = s[3]; break; - case -1: d[c] = 0; break; - case -2: d[c] = 0xFF; break; - } - } - } - } - return (PyObject *)buffer; - } - } - catch (Exception & exp) - { - exp.report(); - return NULL; - } - 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, PyObject *args) -{ - Py_buffer buffer; - bool done = true; - char *mode = NULL; - double ts = -1.0; - unsigned int format; - - memset(&buffer, 0, sizeof(buffer)); - if (PyArg_ParseTuple(args, "|s*sd:refresh", &buffer, &mode, &ts)) { - if (buffer.buf) { - // a target buffer is provided, verify its format - if (buffer.readonly) { - PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be writable"); - } - else if (!PyBuffer_IsContiguous(&buffer, 'C')) { - PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be contiguous in memory"); - } - else if (((intptr_t)buffer.buf & 3) != 0) { - PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be aligned to 4 bytes boundary"); - } - else { - // ready to get the image into our buffer - try { - if (mode == NULL || !strcmp(mode, "RGBA")) - format = GL_RGBA; - else if (!strcmp(mode, "BGRA")) - format = GL_BGRA; - else - THRWEXCP(InvalidImageMode,S_OK); - - done = self->m_image->loadImage((unsigned int *)buffer.buf, buffer.len, format, ts); - } - catch (Exception & exp) { - exp.report(); - } - } - PyBuffer_Release(&buffer); - if (PyErr_Occurred()) { - return NULL; - } - } - } - else { - return NULL; - } - - self->m_image->refresh(); - if (done) - Py_RETURN_TRUE; - Py_RETURN_FALSE; -} - -// 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 zbuff -PyObject *Image_getZbuff(PyImage *self, void *closure) -{ - if (self->m_image != NULL && self->m_image->getZbuff()) Py_RETURN_TRUE; - else Py_RETURN_FALSE; -} - -// set zbuff -int Image_setZbuff(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->setZbuff(value == Py_True); - // success - return 0; -} - -// get depth -PyObject *Image_getDepth(PyImage *self, void *closure) -{ - if (self->m_image != NULL && self->m_image->getDepth()) Py_RETURN_TRUE; - else Py_RETURN_FALSE; -} - -// set depth -int Image_setDepth(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->setDepth(value == Py_True); - // success - return 0; -} - - - - -// get filter source object -PyObject *Image_getSource(PyImage *self, PyObject *args) -{ - // get arguments - char *id; - if (!PyArg_ParseTuple(args, "s:getSource", &id)) - return NULL; - if (self->m_image != NULL) - { - // get source object - PyObject *src = reinterpret_cast<PyObject*>(self->m_image->getSource(id)); - // if source is available - if (src != NULL) - { - // return source - Py_INCREF(src); - return src; - } - } - // source was not found - Py_RETURN_NONE; -} - - -// set filter source object -PyObject *Image_setSource(PyImage *self, PyObject *args) -{ - // get arguments - char *id; - PyObject *obj; - if (!PyArg_ParseTuple(args, "sO:setSource", &id, &obj)) - return NULL; - if (self->m_image != NULL) - { - // check type of object - if (pyImageTypes.in(Py_TYPE(obj))) - { - // convert to image struct - PyImage * img = reinterpret_cast<PyImage*>(obj); - // set source - if (!self->m_image->setSource(id, img)) - { - // if not set, retport error - PyErr_SetString(PyExc_RuntimeError, "Invalid source or id"); - return NULL; - } - } - // else report error - else - { - PyErr_SetString(PyExc_RuntimeError, "Invalid type of object"); - return NULL; - } - } - // return none - Py_RETURN_NONE; -} - - -// get pixel filter object -PyObject *Image_getFilter(PyImage *self, void *closure) -{ - // if image object is available - if (self->m_image != NULL) - { - // pixel filter object - PyObject *filt = reinterpret_cast<PyObject*>(self->m_image->getFilter()); - // if filter is present - if (filt != NULL) - { - // return it - Py_INCREF(filt); - return filt; - } - } - // otherwise return none - Py_RETURN_NONE; -} - - -// set pixel filter object -int Image_setFilter(PyImage *self, PyObject *value, void *closure) -{ - // if image object is available - if (self->m_image != NULL) - { - // check new value - if (value == NULL || !pyFilterTypes.in(Py_TYPE(value))) - { - // report value error - PyErr_SetString(PyExc_TypeError, "Invalid type of value"); - return -1; - } - // set new value - self->m_image->setFilter(reinterpret_cast<PyFilter*>(value)); - } - // return success - return 0; -} -PyObject *Image_valid(PyImage *self, void *closure) -{ - if (self->m_image->isImageAvailable()) - { - Py_RETURN_TRUE; - } - else - { - Py_RETURN_FALSE; - } -} - -static int Image_getbuffer(PyImage *self, Py_buffer *view, int flags) -{ - unsigned int * image; - int ret; - - try { - // can throw in case of resize - image = self->m_image->getImage(); - } - catch (Exception & exp) { - exp.report(); - return -1; - } - - if (!image) { - PyErr_SetString(PyExc_BufferError, "Image buffer is not available"); - return -1; - } - if (view == NULL) - { - self->m_image->m_exports++; - return 0; - } - ret = PyBuffer_FillInfo(view, (PyObject *)self, image, self->m_image->getBuffSize(), 0, flags); - if (ret >= 0) - self->m_image->m_exports++; - return ret; -} - -static void Image_releaseBuffer(PyImage *self, Py_buffer *buffer) -{ - self->m_image->m_exports--; -} - -PyBufferProcs imageBufferProcs = -{ - (getbufferproc)Image_getbuffer, - (releasebufferproc)Image_releaseBuffer -}; - diff --git a/source/gameengine/VideoTexture/ImageBase.h b/source/gameengine/VideoTexture/ImageBase.h deleted file mode 100644 index 5a09c9a67b3..00000000000 --- a/source/gameengine/VideoTexture/ImageBase.h +++ /dev/null @@ -1,392 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of blendTex library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file ImageBase.h - * \ingroup bgevideotex - */ - -#ifndef __IMAGEBASE_H__ -#define __IMAGEBASE_H__ - -#include "Common.h" - -#include <vector> -#include "EXP_PyObjectPlus.h" - -#include "PyTypeList.h" - -#include "FilterBase.h" - -#include "GPU_glew.h" - -// forward declarations -struct PyImage; -class ImageSource; - - -/// type for list of image sources -typedef std::vector<ImageSource*> ImageSourceList; - - -/// base class for image filters -class ImageBase -{ -public: - /// constructor - ImageBase (bool staticSrc = false); - /// destructor - virtual ~ImageBase(void); - /// release contained objects, if returns true, object should be deleted - virtual bool release(void); - - /// is an image available - bool isImageAvailable(void) - { return m_avail; } - /// get image - unsigned int *getImage(unsigned int texId = 0, double timestamp=-1.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 Z buffer - bool getZbuff(void) { return m_zbuff; } - /// set Z buffer - void setZbuff(bool zbuff) { m_zbuff = zbuff; } - /// get depth - bool getDepth(void) { return m_depth; } - /// set depth - void setDepth(bool depth) { m_depth = depth; } - - /// 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); - - /// calculate image from sources and send it to a target buffer instead of a texture - /// format is GL_RGBA or GL_BGRA - virtual bool loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts); - - /// swap the B and R channel in-place in the image buffer - void swapImageBR(); - - /// number of buffer pointing to m_image, public because not handled by this class - int m_exports; - -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; - /// use the Z buffer as a texture - bool m_zbuff; - /// extract the Z buffer with unisgned int precision - bool m_depth; - - /// 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, double ts) {} - - /// perform loop detection - bool loopDetect(ImageBase * img); - - /// template for image conversion - template<class FLT, class SRC> void convImage(FLT & filter, SRC srcBuff, - short * srcSize) - { - // destination buffer - unsigned int * dstBuff = m_image; - // pixel size from filter - unsigned int pixSize = filter.firstPixelSize(); - // if no scaling is needed - if (srcSize[0] == m_size[0] && srcSize[1] == m_size[1]) - // if flipping isn't required - if (!m_flip) - // copy bitmap - for (short y = 0; y < m_size[1]; ++y) - for (short x = 0; x < m_size[0]; ++x, ++dstBuff, srcBuff += pixSize) - // copy pixel - *dstBuff = filter.convert(srcBuff, x, y, srcSize, pixSize); - // otherwise flip image top to bottom - else - { - // go to last row of image - srcBuff += srcSize[0] * (srcSize[1] - 1) * pixSize; - // copy bitmap - for (short y = m_size[1] - 1; y >= 0; --y, srcBuff -= 2 * srcSize[0] * pixSize) - for (short x = 0; x < m_size[0]; ++x, ++dstBuff, srcBuff += pixSize) - // copy pixel - *dstBuff = filter.convert(srcBuff, x, y, srcSize, pixSize); - } - // else scale picture (nearest neighbor) - else - { - // interpolation accumulator - int accHeight = srcSize[1] >> 1; - // if flipping is required - if (m_flip) - // go to last row of image - srcBuff += srcSize[0] * (srcSize[1] - 1) * pixSize; - // process image rows - for (int y = 0; y < srcSize[1]; ++y) - { - // increase height accum - accHeight += m_size[1]; - // if pixel row has to be drawn - if (accHeight >= srcSize[1]) - { - // decrease accum - accHeight -= srcSize[1]; - // width accum - int accWidth = srcSize[0] >> 1; - // process row - for (int x = 0; x < srcSize[0]; ++x) - { - // increase width accum - accWidth += m_size[0]; - // if pixel has to be drawn - if (accWidth >= srcSize[0]) - { - // decrease accum - accWidth -= srcSize[0]; - // convert pixel - *dstBuff = filter.convert(srcBuff, x, m_flip ? srcSize[1] - y - 1 : y, - srcSize, pixSize); - // next pixel - ++dstBuff; - } - // shift source pointer - srcBuff += pixSize; - } - } - // if pixel row will not be drawn - else - // move source pointer to next row - srcBuff += pixSize * srcSize[0]; - // if y flipping is required - if (m_flip) - // go to previous row of image - srcBuff -= 2 * pixSize * srcSize[0]; - } - } - } - - // template for specific filter preprocessing - template <class F, class SRC> void filterImage (F & filt, SRC srcBuff, short *srcSize) - { - // find first filter in chain - FilterBase * firstFilter = NULL; - if (m_pyfilter != NULL) firstFilter = m_pyfilter->m_filter->findFirst(); - // if first filter is available - if (firstFilter != NULL) - { - // python wrapper for filter - PyFilter pyFilt; - pyFilt.m_filter = &filt; - // set specified filter as first in chain - firstFilter->setPrevious(&pyFilt, false); - // convert video image - convImage(*(m_pyfilter->m_filter), srcBuff, srcSize); - // delete added filter - firstFilter->setPrevious(NULL, false); - } - // otherwise use given filter for conversion - else convImage(filt, srcBuff, srcSize); - // source was processed - m_avail = true; - } -}; - - -// python structure for image filter -struct PyImage -{ - PyObject_HEAD - // source object - ImageBase * m_image; -}; - - -// size of id -const int SourceIdSize = 32; - - -/// class for source of image -class ImageSource -{ -public: - /// constructor - ImageSource (const char *id); - /// destructor - virtual ~ImageSource (void); - - /// get id - const char * getId (void) { return m_id; } - /// compare id to argument - bool is (const char *id); - - /// get source object - PyImage * getSource (void) { return m_source; } - /// set source object - void setSource (PyImage *source); - - /// get image from source - unsigned int * getImage (double ts=-1.0); - /// get buffered image - unsigned int * getImageBuf (void) { return m_image; } - /// refresh source - void refresh (void); - - /// get image size - short * getSize (void) - { - static short defSize [] = {0, 0}; - return m_source != NULL ? m_source->m_image->getSize() : defSize; - } - -protected: - /// id of source - char m_id [SourceIdSize]; - /// pointer to source structure - PyImage * m_source; - /// buffered image from source - unsigned int * m_image; - -private: - /// default constructor is forbidden - ImageSource (void) {} -}; - -// list of python image types -extern PyTypeList pyImageTypes; - - -// functions for python interface - -// object initialization -template <class T> static int Image_init(PyObject *pySelf, PyObject *args, PyObject *kwds) -{ - PyImage *self = reinterpret_cast<PyImage *>(pySelf); - // create source object - if (self->m_image != NULL) delete self->m_image; - self->m_image = new T(); - // initialization succeded - return 0; -} - -// object allocation -PyObject *Image_allocNew(PyTypeObject *type, PyObject *args, PyObject *kwds); -// object deallocation -void Image_dealloc(PyImage *self); - -// get image data -PyObject *Image_getImage(PyImage *self, char *mode); -// get image size -PyObject *Image_getSize(PyImage *self, void *closure); -// refresh image - invalidate current content -PyObject *Image_refresh(PyImage *self, PyObject *args); - -// 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 Z buffer -PyObject *Image_getZbuff(PyImage *self, void *closure); -// set Z buffer -int Image_setZbuff(PyImage *self, PyObject *value, void *closure); -// get depth -PyObject *Image_getDepth(PyImage *self, void *closure); -// set depth -int Image_setDepth(PyImage *self, PyObject *value, void *closure); - -// get pixel filter object -PyObject *Image_getFilter(PyImage *self, void *closure); -// set pixel filter object -int Image_setFilter(PyImage *self, PyObject *value, void *closure); -// check if a buffer can be extracted -PyObject *Image_valid(PyImage *self, void *closure); -// for buffer access to PyImage objects -extern PyBufferProcs imageBufferProcs; - -#endif diff --git a/source/gameengine/VideoTexture/ImageBuff.cpp b/source/gameengine/VideoTexture/ImageBuff.cpp deleted file mode 100644 index 77270865b17..00000000000 --- a/source/gameengine/VideoTexture/ImageBuff.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/ImageBuff.cpp - * \ingroup bgevideotex - */ - -// implementation - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "ImageBuff.h" -#include "Exception.h" -#include "ImageBase.h" -#include "FilterSource.h" - -// use ImBuf API for image manipulation -extern "C" { -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" -#include "bgl.h" -}; - -// default filter -FilterRGB24 defFilter; - -// forward declaration; -extern PyTypeObject ImageBuffType; - -static int ImageBuff_init(PyObject *pySelf, PyObject *args, PyObject *kwds) -{ - short width = -1; - short height = -1; - unsigned char color = 0; - PyObject *py_scale = Py_False; - ImageBuff *image; - - PyImage *self = reinterpret_cast<PyImage*>(pySelf); - // create source object - if (self->m_image != NULL) - delete self->m_image; - image = new ImageBuff(); - self->m_image = image; - - if (PyArg_ParseTuple(args, "hh|bO!:ImageBuff", &width, &height, &color, &PyBool_Type, &py_scale)) - { - // initialize image buffer - image->setScale(py_scale == Py_True); - image->clear(width, height, color); - } - else - { - // check if at least one argument was passed - if (width != -1 || height != -1) - // yes and they didn't match => it's an error - return -1; - // empty argument list is okay - PyErr_Clear(); - } - // initialization succeded - return 0; - -} - -ImageBuff::~ImageBuff (void) -{ - if (m_imbuf) - IMB_freeImBuf(m_imbuf); -} - - -// load image from buffer -void ImageBuff::load(unsigned char *img, short width, short height) -{ - // loading a new buffer implies to reset the imbuf if any, because the size may change - if (m_imbuf) - { - IMB_freeImBuf(m_imbuf); - m_imbuf = NULL; - } - // 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; -} - -void ImageBuff::clear(short width, short height, unsigned char color) -{ - unsigned char *p; - int size; - - // loading a new buffer implies to reset the imbuf if any, because the size may change - if (m_imbuf) - { - IMB_freeImBuf(m_imbuf); - m_imbuf = NULL; - } - // initialize image buffer - init(width, height); - // the width/height may be different due to scaling - size = (m_size[0] * m_size[1]); - // initialize memory with color for all channels - memset(m_image, color, size*4); - // and change the alpha channel - p = &((unsigned char*)m_image)[3]; - for (; size>0; size--) - { - *p = 0xFF; - p += 4; - } - // image is available - m_avail = true; -} - -// img must point to a array of RGBA data of size width*height -void ImageBuff::plot(unsigned char *img, short width, short height, short x, short y, short mode) -{ - struct ImBuf *tmpbuf; - - if (m_size[0] == 0 || m_size[1] == 0 || width <= 0 || height <= 0) - return; - - if (!m_imbuf) { - // allocate most basic imbuf, we will assign the rect buffer on the fly - m_imbuf = IMB_allocImBuf(m_size[0], m_size[1], 0, 0); - } - - tmpbuf = IMB_allocImBuf(width, height, 0, 0); - - // assign temporarily our buffer to the ImBuf buffer, we use the same format - tmpbuf->rect = (unsigned int*)img; - m_imbuf->rect = m_image; - IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, NULL, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode, false); - // remove so that MB_freeImBuf will free our buffer - m_imbuf->rect = NULL; - tmpbuf->rect = NULL; - IMB_freeImBuf(tmpbuf); -} - -void ImageBuff::plot(ImageBuff *img, short x, short y, short mode) -{ - if (m_size[0] == 0 || m_size[1] == 0 || img->m_size[0] == 0 || img->m_size[1] == 0) - return; - - if (!m_imbuf) { - // allocate most basic imbuf, we will assign the rect buffer on the fly - m_imbuf = IMB_allocImBuf(m_size[0], m_size[1], 0, 0); - } - if (!img->m_imbuf) { - // allocate most basic imbuf, we will assign the rect buffer on the fly - img->m_imbuf = IMB_allocImBuf(img->m_size[0], img->m_size[1], 0, 0); - } - // assign temporarily our buffer to the ImBuf buffer, we use the same format - img->m_imbuf->rect = img->m_image; - m_imbuf->rect = m_image; - IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, NULL, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode, false); - // remove so that MB_freeImBuf will free our buffer - m_imbuf->rect = NULL; - img->m_imbuf->rect = NULL; -} - - -// cast Image pointer to ImageBuff -inline ImageBuff *getImageBuff(PyImage *self) -{ return static_cast<ImageBuff *>(self->m_image); } - - -// python methods - -static bool testPyBuffer(Py_buffer *buffer, int width, int height, unsigned int pixsize) -{ - if (buffer->itemsize != 1) - { - PyErr_SetString(PyExc_ValueError, "Buffer must be an array of bytes"); - return false; - } - if (buffer->len != width*height*pixsize) - { - PyErr_SetString(PyExc_ValueError, "Buffer hasn't the correct size"); - return false; - } - // multi dimension are ok as long as there is no hole in the memory - Py_ssize_t size = buffer->itemsize; - for (int i=buffer->ndim-1; i>=0 ; i--) - { - if (buffer->suboffsets != NULL && buffer->suboffsets[i] >= 0) - { - PyErr_SetString(PyExc_ValueError, "Buffer must be of one block"); - return false; - } - if (buffer->strides != NULL && buffer->strides[i] != size) - { - PyErr_SetString(PyExc_ValueError, "Buffer must be of one block"); - return false; - } - if (i > 0) - size *= buffer->shape[i]; - } - return true; -} - -static bool testBGLBuffer(Buffer *buffer, int width, int height, unsigned int pixsize) -{ - unsigned int size = BGL_typeSize(buffer->type); - for (int i=0; i<buffer->ndimensions; i++) - { - size *= buffer->dimensions[i]; - } - if (size != width*height*pixsize) - { - PyErr_SetString(PyExc_ValueError, "Buffer hasn't the correct size"); - return false; - } - return true; -} - - -// load image -static PyObject *load(PyImage *self, PyObject *args) -{ - // parameters: string image buffer, its size, width, height - Py_buffer buffer; - Buffer *bglBuffer; - short width; - short height; - unsigned int pixSize; - - // calc proper buffer size - // use pixel size from filter - if (self->m_image->getFilter() != NULL) - pixSize = self->m_image->getFilter()->m_filter->firstPixelSize(); - else - pixSize = defFilter.firstPixelSize(); - - // parse parameters - if (!PyArg_ParseTuple(args, "s*hh:load", &buffer, &width, &height)) - { - PyErr_Clear(); - // check if it is BGL buffer - if (!PyArg_ParseTuple(args, "O!hh:load", &BGL_bufferType, &bglBuffer, &width, &height)) - { - // report error - return NULL; - } - else - { - if (testBGLBuffer(bglBuffer, width, height, pixSize)) - { - try - { - // if correct, load image - getImageBuff(self)->load((unsigned char*)bglBuffer->buf.asvoid, width, height); - } - catch (Exception & exp) - { - exp.report(); - } - } - } - } - else - { - // check if buffer size is correct - if (testPyBuffer(&buffer, width, height, pixSize)) - { - try - { - // if correct, load image - getImageBuff(self)->load((unsigned char*)buffer.buf, width, height); - } - catch (Exception & exp) - { - exp.report(); - } - } - PyBuffer_Release(&buffer); - } - if (PyErr_Occurred()) - return NULL; - Py_RETURN_NONE; -} - -static PyObject *plot(PyImage *self, PyObject *args) -{ - PyImage * other; - Buffer* bglBuffer; - Py_buffer buffer; - //unsigned char * buff; - //unsigned int buffSize; - short width; - short height; - short x, y; - short mode = IMB_BLEND_COPY; - - if (PyArg_ParseTuple(args, "s*hhhh|h:plot", &buffer, &width, &height, &x, &y, &mode)) - { - // correct decoding, verify that buffer size is correct - // we need a continuous memory buffer - if (testPyBuffer(&buffer, width, height, 4)) - { - getImageBuff(self)->plot((unsigned char*)buffer.buf, width, height, x, y, mode); - } - PyBuffer_Release(&buffer); - if (PyErr_Occurred()) - return NULL; - Py_RETURN_NONE; - } - PyErr_Clear(); - // try the other format - if (PyArg_ParseTuple(args, "O!hh|h:plot", &ImageBuffType, &other, &x, &y, &mode)) - { - getImageBuff(self)->plot(getImageBuff(other), x, y, mode); - Py_RETURN_NONE; - } - PyErr_Clear(); - // try the last format (BGL buffer) - if (!PyArg_ParseTuple(args, "O!hhhh|h:plot", &BGL_bufferType, &bglBuffer, &width, &height, &x, &y, &mode)) - { - PyErr_SetString(PyExc_TypeError, "Expecting ImageBuff or Py buffer or BGL buffer as first argument; width, height next; postion x, y and mode as last arguments"); - return NULL; - } - if (testBGLBuffer(bglBuffer, width, height, 4)) - { - getImageBuff(self)->plot((unsigned char*)bglBuffer->buf.asvoid, width, height, x, y, mode); - } - if (PyErr_Occurred()) - return NULL; - Py_RETURN_NONE; -} - -// methods structure -static PyMethodDef imageBuffMethods[] = { - {"load", (PyCFunction)load, METH_VARARGS, "Load image from buffer"}, - {"plot", (PyCFunction)plot, METH_VARARGS, "update image buffer"}, - {NULL} -}; -// attributes structure -static PyGetSetDef imageBuffGetSets[] = { - // attributes from ImageBase class - {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, - {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, - {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, - {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL}, - {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, - {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, - {NULL} -}; - - -// define python type -PyTypeObject ImageBuffType = { - PyVarObject_HEAD_INIT(NULL, 0) - "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*/ - &imageBufferProcs, /*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)ImageBuff_init, /* tp_init */ - 0, /* tp_alloc */ - Image_allocNew, /* tp_new */ -}; - diff --git a/source/gameengine/VideoTexture/ImageBuff.h b/source/gameengine/VideoTexture/ImageBuff.h deleted file mode 100644 index 19299506747..00000000000 --- a/source/gameengine/VideoTexture/ImageBuff.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file ImageBuff.h - * \ingroup bgevideotex - */ - -#ifndef __IMAGEBUFF_H__ -#define __IMAGEBUFF_H__ - - -#include "Common.h" - -#include "ImageBase.h" - -struct ImBuf; - -/// class for image buffer -class ImageBuff : public ImageBase -{ -private: - struct ImBuf *m_imbuf; // temporary structure for buffer manipulation -public: - /// constructor - ImageBuff (void) : ImageBase(true), m_imbuf(NULL) {} - - /// destructor - virtual ~ImageBuff (void); - - /// load image from buffer - void load (unsigned char * img, short width, short height); - /// clear image with color set on RGB channels and 0xFF on alpha channel - void clear (short width, short height, unsigned char color); - - /// plot image from extern RGBA buffer to image at position x,y using one of IMB_BlendMode - void plot (unsigned char * img, short width, short height, short x, short y, short mode); - /// plot image from other ImageBuf to image at position x,y using one of IMB_BlendMode - void plot (ImageBuff* img, short x, short y, short mode); - - /// refresh image - do nothing - virtual void refresh (void) {} -}; - - -#endif - diff --git a/source/gameengine/VideoTexture/ImageMix.cpp b/source/gameengine/VideoTexture/ImageMix.cpp deleted file mode 100644 index 2de00f5ba05..00000000000 --- a/source/gameengine/VideoTexture/ImageMix.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/ImageMix.cpp - * \ingroup bgevideotex - */ - - -// implementation - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "ImageMix.h" - -#include "ImageBase.h" - -#include "Exception.h" - - -// cast ImageSource pointer to ImageSourceMix -inline ImageSourceMix *getImageSourceMix(ImageSource *src) -{ return static_cast<ImageSourceMix*>(src); } - - -// get weight -short ImageMix::getWeight(const char *id) -{ - // find source - ImageSourceList::iterator src = findSource(id); - // if found, return its weight - return src != m_sources.end() ? getImageSourceMix(*src)->getWeight() : 0; -} - -// set weight -bool ImageMix::setWeight(const char *id, short weight) -{ - // find source - ImageSourceList::iterator src = findSource(id); - // if source isn't found, report it - if (src == m_sources.end()) return false; - // set its weight - getImageSourceMix(*src)->setWeight(weight); - return true; -} - -ExceptionID ImageSizesNotMatch; - -ExpDesc ImageSizesNotMatchDesc(ImageSizesNotMatch, "Image sizes of sources are different"); - -// calculate image from sources and set its availability -void ImageMix::calcImage(unsigned int texId, double ts) -{ - // check source sizes - if (!checkSourceSizes()) THRWEXCP(ImageSizesNotMatch, S_OK); - // set offsets to image buffers - for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it) - // if image buffer is available - if ((*it)->getImageBuf() != NULL) - // set its offset - getImageSourceMix(*it)->setOffset(m_sources[0]->getImageBuf()); - // otherwise don't calculate image - else - return; - // if there is only single source - if (m_sources.size() == 1) - { - // use single filter - FilterBase mixFilt; - // fiter and convert image - filterImage(mixFilt, m_sources[0]->getImageBuf(), m_sources[0]->getSize()); - } - // otherwise use mix filter to merge source images - else - { - FilterImageMix mixFilt (m_sources); - // fiter and convert image - filterImage(mixFilt, m_sources[0]->getImageBuf(), m_sources[0]->getSize()); - } -} - - - -// cast Image pointer to ImageMix -inline ImageMix * getImageMix(PyImage *self) -{ return static_cast<ImageMix*>(self->m_image); } - - -// python methods - -// get source weight -static PyObject *getWeight(PyImage *self, PyObject *args) -{ - // weight - short weight = 0; - // get arguments - char *id; - if (!PyArg_ParseTuple(args, "s:getWeight", &id)) - return NULL; - if (self->m_image != NULL) - // get weight - weight = getImageMix(self)->getWeight(id); - // return weight - return Py_BuildValue("h", weight); -} - - -// set source weight -static PyObject *setWeight(PyImage *self, PyObject *args) -{ - // get arguments - char *id; - short weight = 0; - if (!PyArg_ParseTuple(args, "sh:setWeight", &id, &weight)) - return NULL; - if (self->m_image != NULL) - // 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_VARARGS, "Refresh image - invalidate its current content"}, - {NULL} -}; -// attributes structure -static PyGetSetDef imageMixGetSets[] = { - // attributes from ImageBase class - {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, - {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, - {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, - {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL}, - {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, - {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, - {NULL} -}; - - -// define python type -PyTypeObject ImageMixType = { - PyVarObject_HEAD_INIT(NULL, 0) - "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*/ - &imageBufferProcs, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Image mixer", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - imageMixMethods, /* tp_methods */ - 0, /* tp_members */ - imageMixGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Image_init<ImageMix>, /* tp_init */ - 0, /* tp_alloc */ - Image_allocNew, /* tp_new */ -}; - diff --git a/source/gameengine/VideoTexture/ImageMix.h b/source/gameengine/VideoTexture/ImageMix.h deleted file mode 100644 index 161a8b375ea..00000000000 --- a/source/gameengine/VideoTexture/ImageMix.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file ImageMix.h - * \ingroup bgevideotex - */ - -#ifndef __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_offset(0), 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, double ts); -}; - - -/// pixel filter for image mixer -class FilterImageMix : public FilterBase -{ -public: - /// constructor - FilterImageMix (ImageSourceList & sources) : m_sources(sources) {} - /// destructor - virtual ~FilterImageMix (void) {} - -protected: - /// source list - ImageSourceList & m_sources; - - /// filter pixel, source int buffer - virtual unsigned int filter (unsigned int * src, short x, short y, - short * size, unsigned int pixSize, unsigned int val = 0) - { - // resulting pixel color - int color[] = {0, 0, 0, 0}; - // iterate sources - for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it) - { - // get pointer to mixer source - ImageSourceMix * mixSrc = static_cast<ImageSourceMix*>(*it); - // add weighted source pixel to result - color[0] += mixSrc->getWeight() * (src[mixSrc->getOffset()] & 0xFF); - color[1] += mixSrc->getWeight() * ((src[mixSrc->getOffset()] >> 8) & 0xFF); - color[2] += mixSrc->getWeight() * ((src[mixSrc->getOffset()] >> 16) & 0xFF); - color[3] += mixSrc->getWeight() * ((src[mixSrc->getOffset()] >> 24) & 0xFF); - } - // return resulting color - return ((color[0] >> 8) & 0xFF) | (color[1] & 0xFF00) - | ((color[2] << 8) & 0xFF0000) | ((color[3] << 16) & 0xFF000000); - } -}; - - -#endif - diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp deleted file mode 100644 index 57062343b67..00000000000 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ /dev/null @@ -1,946 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/ImageRender.cpp - * \ingroup bgevideotex - */ - -// implementation - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> -#include <float.h> -#include <math.h> - - -#include "GPU_glew.h" - -#include "KX_PythonInit.h" -#include "DNA_scene_types.h" -#include "RAS_CameraData.h" -#include "RAS_MeshObject.h" -#include "RAS_Polygon.h" -#include "RAS_IOffScreen.h" -#include "RAS_ISync.h" -#include "BLI_math.h" - -#include "ImageRender.h" -#include "ImageBase.h" -#include "BlendType.h" -#include "Exception.h" -#include "Texture.h" - -ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid, OffScreenInvalid; -ExceptionID MirrorInvalid, MirrorSizeInvalid, MirrorNormalInvalid, MirrorHorizontal, MirrorTooSmall; -ExpDesc SceneInvalidDesc(SceneInvalid, "Scene object is invalid"); -ExpDesc CameraInvalidDesc(CameraInvalid, "Camera object is invalid"); -ExpDesc ObserverInvalidDesc(ObserverInvalid, "Observer object is invalid"); -ExpDesc OffScreenInvalidDesc(OffScreenInvalid, "Offscreen object is invalid"); -ExpDesc MirrorInvalidDesc(MirrorInvalid, "Mirror object is invalid"); -ExpDesc MirrorSizeInvalidDesc(MirrorSizeInvalid, "Mirror has no vertex or no size"); -ExpDesc MirrorNormalInvalidDesc(MirrorNormalInvalid, "Cannot determine mirror plane"); -ExpDesc MirrorHorizontalDesc(MirrorHorizontal, "Mirror is horizontal in local space"); -ExpDesc MirrorTooSmallDesc(MirrorTooSmall, "Mirror is too small"); - -// constructor -ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera, PyRASOffScreen * offscreen) : - ImageViewport(offscreen), - m_render(true), - m_done(false), - m_scene(scene), - m_camera(camera), - m_owncamera(false), - m_offscreen(offscreen), - m_sync(NULL), - m_observer(NULL), - m_mirror(NULL), - m_clip(100.f), - m_mirrorHalfWidth(0.f), - m_mirrorHalfHeight(0.f) -{ - // initialize background color to scene background color as default - setBackgroundFromScene(m_scene); - // retrieve rendering objects - m_engine = KX_GetActiveEngine(); - m_rasterizer = m_engine->GetRasterizer(); - m_canvas = m_engine->GetCanvas(); - // keep a reference to the offscreen buffer - if (m_offscreen) { - Py_INCREF(m_offscreen); - } -} - -// destructor -ImageRender::~ImageRender (void) -{ - if (m_owncamera) - m_camera->Release(); - if (m_sync) - delete m_sync; - Py_XDECREF(m_offscreen); -} - -// get background color -float ImageRender::getBackground (int idx) -{ - return (idx < 0 || idx > 3) ? 0.0f : m_background[idx] * 255.0f; -} - -// set background color -void ImageRender::setBackground (float red, float green, float blue, float alpha) -{ - m_background[0] = (red < 0.0f) ? 0.0f : (red > 255.0f) ? 1.0f : red / 255.0f; - m_background[1] = (green < 0.0f) ? 0.0f : (green > 255.0f) ? 1.0f : green / 255.0f; - m_background[2] = (blue < 0.0f) ? 0.0f : (blue > 255.0f) ? 1.0f : blue / 255.0f; - m_background[3] = (alpha < 0.0f) ? 0.0f : (alpha > 255.0f) ? 1.0f : alpha / 255.0f; -} - -// set background color from scene -void ImageRender::setBackgroundFromScene (KX_Scene *scene) -{ - if (scene) { - const float *background_color = scene->GetWorldInfo()->getBackColorConverted(); - copy_v3_v3(m_background, background_color); - m_background[3] = 1.0f; - } - else { - const float blue_color[] = {0.0f, 0.0f, 1.0f, 1.0f}; - copy_v4_v4(m_background, blue_color); - } -} - - -// capture image from viewport -void ImageRender::calcViewport (unsigned int texId, double ts, unsigned int format) -{ - // render the scene from the camera - if (!m_done) { - if (!Render()) { - return; - } - } - else if (m_offscreen) { - m_offscreen->ofs->Bind(RAS_IOffScreen::RAS_OFS_BIND_READ); - } - // wait until all render operations are completed - WaitSync(); - // get image from viewport (or FBO) - ImageViewport::calcViewport(texId, ts, format); - if (m_offscreen) { - m_offscreen->ofs->Unbind(); - } -} - -bool ImageRender::Render() -{ - RAS_FrameFrustum frustum; - - if (!m_render || - m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture - m_camera->GetViewport() || // camera must be inactive - m_camera == m_scene->GetActiveCamera()) - { - // no need to compute texture in non texture rendering - return false; - } - - if (!m_scene->IsShadowDone()) - m_engine->RenderShadowBuffers(m_scene); - - if (m_mirror) - { - // mirror mode, compute camera frustum, position and orientation - // convert mirror position and normal in world space - const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation(); - const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition(); - const MT_Vector3 & mirrorObjWorldScale = m_mirror->GetSGNode()->GetWorldScaling(); - MT_Point3 mirrorWorldPos = - mirrorObjWorldPos + mirrorObjWorldScale * (mirrorObjWorldOri * m_mirrorPos); - MT_Vector3 mirrorWorldZ = mirrorObjWorldOri * m_mirrorZ; - // get observer world position - const MT_Point3 & observerWorldPos = m_observer->GetSGNode()->GetWorldPosition(); - // get plane D term = mirrorPos . normal - MT_Scalar mirrorPlaneDTerm = mirrorWorldPos.dot(mirrorWorldZ); - // compute distance of observer to mirror = D - observerPos . normal - MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ); - // if distance < 0.01 => observer is on wrong side of mirror, don't render - if (observerDistance < 0.01) - return false; - // set camera world position = observerPos + normal * 2 * distance - MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ; - m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos); - // set camera orientation: z=normal, y=mirror_up in world space, x= y x z - MT_Vector3 mirrorWorldY = mirrorObjWorldOri * m_mirrorY; - MT_Vector3 mirrorWorldX = mirrorObjWorldOri * m_mirrorX; - MT_Matrix3x3 cameraWorldOri( - mirrorWorldX[0], mirrorWorldY[0], mirrorWorldZ[0], - mirrorWorldX[1], mirrorWorldY[1], mirrorWorldZ[1], - mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]); - m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri); - m_camera->GetSGNode()->UpdateWorldData(0.0); - // compute camera frustum: - // get position of mirror relative to camera: offset = mirrorPos-cameraPos - MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos; - // convert to camera orientation - mirrorOffset = mirrorOffset * cameraWorldOri; - // scale mirror size to world scale: - // get closest local axis for mirror Y and X axis and scale height and width by local axis scale - MT_Scalar x, y; - x = fabs(m_mirrorY[0]); - y = fabs(m_mirrorY[1]); - float height = (x > y) ? - ((x > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): - ((y > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); - x = fabs(m_mirrorX[0]); - y = fabs(m_mirrorX[1]); - float width = (x > y) ? - ((x > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): - ((y > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); - width *= m_mirrorHalfWidth; - height *= m_mirrorHalfHeight; - // left = offsetx-width - // right = offsetx+width - // top = offsety+height - // bottom = offsety-height - // near = -offsetz - // far = near+100 - frustum.x1 = mirrorOffset[0]-width; - frustum.x2 = mirrorOffset[0]+width; - frustum.y1 = mirrorOffset[1]-height; - frustum.y2 = mirrorOffset[1]+height; - frustum.camnear = -mirrorOffset[2]; - frustum.camfar = -mirrorOffset[2]+m_clip; - } - // Store settings to be restored later - const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); - RAS_Rect area = m_canvas->GetWindowArea(); - - // The screen area that ImageViewport will copy is also the rendering zone - if (m_offscreen) { - // bind the fbo and set the viewport to full size - m_offscreen->ofs->Bind(RAS_IOffScreen::RAS_OFS_BIND_RENDER); - // this is needed to stop crashing in canvas check - m_canvas->UpdateViewPort(0, 0, m_offscreen->ofs->GetWidth(), m_offscreen->ofs->GetHeight()); - } - else { - m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1); - } - m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]); - m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); - m_rasterizer->BeginFrame(m_engine->GetClockTime()); - m_scene->GetWorldInfo()->UpdateWorldSettings(); - m_rasterizer->SetAuxilaryClientInfo(m_scene); - m_rasterizer->DisplayFog(); - // matrix calculation, don't apply any of the stereo mode - m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO); - if (m_mirror) - { - // frustum was computed above - // get frustum matrix and set projection matrix - MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( - frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); - - m_camera->SetProjectionMatrix(projmat); - } - else if (m_camera->hasValidProjectionMatrix()) { - m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix()); - } - else { - float lens = m_camera->GetLens(); - float sensor_x = m_camera->GetSensorWidth(); - float sensor_y = m_camera->GetSensorHeight(); - float shift_x = m_camera->GetShiftHorizontal(); - float shift_y = m_camera->GetShiftVertical(); - bool orthographic = !m_camera->GetCameraData()->m_perspective; - float nearfrust = m_camera->GetCameraNear(); - float farfrust = m_camera->GetCameraFar(); - float aspect_ratio = 1.0f; - Scene *blenderScene = m_scene->GetBlenderScene(); - MT_Matrix4x4 projmat; - - // compute the aspect ratio from frame blender scene settings so that render to texture - // works the same in Blender and in Blender player - if (blenderScene->r.ysch != 0) - aspect_ratio = float(blenderScene->r.xsch*blenderScene->r.xasp) / float(blenderScene->r.ysch*blenderScene->r.yasp); - - if (orthographic) { - - RAS_FramingManager::ComputeDefaultOrtho( - nearfrust, - farfrust, - m_camera->GetScale(), - aspect_ratio, - m_camera->GetSensorFit(), - shift_x, - shift_y, - frustum - ); - - projmat = m_rasterizer->GetOrthoMatrix( - frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); - } - else { - RAS_FramingManager::ComputeDefaultFrustum( - nearfrust, - farfrust, - lens, - sensor_x, - sensor_y, - RAS_SENSORFIT_AUTO, - shift_x, - shift_y, - aspect_ratio, - frustum); - - projmat = m_rasterizer->GetFrustumMatrix( - frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); - } - m_camera->SetProjectionMatrix(projmat); - } - - MT_Transform camtrans(m_camera->GetWorldToCamera()); - MT_Matrix4x4 viewmat(camtrans); - - m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->NodeGetLocalScaling(), m_camera->GetCameraData()->m_perspective); - m_camera->SetModelviewMatrix(viewmat); - // restore the stereo mode now that the matrix is computed - m_rasterizer->SetStereoMode(stereomode); - - if (m_rasterizer->Stereo()) { - // stereo mode change render settings that disturb this render, cancel them all - // we don't need to restore them as they are set before each frame render. - glDrawBuffer(GL_BACK_LEFT); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glDisable(GL_POLYGON_STIPPLE); - } - - m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera); - - m_engine->UpdateAnimations(m_scene); - - m_scene->RenderBuckets(camtrans, m_rasterizer); - - m_scene->RenderFonts(); - - // restore the canvas area now that the render is completed - m_canvas->GetWindowArea() = area; - m_canvas->EndFrame(); - - // In case multisample is active, blit the FBO - if (m_offscreen) - m_offscreen->ofs->Blit(); - // end of all render operations, let's create a sync object just in case - if (m_sync) { - // a sync from a previous render, should not happen - delete m_sync; - m_sync = NULL; - } - m_sync = m_rasterizer->CreateSync(RAS_ISync::RAS_SYNC_TYPE_FENCE); - // remember that we have done render - m_done = true; - // the image is not available at this stage - m_avail = false; - return true; -} - -void ImageRender::Unbind() -{ - if (m_offscreen) - { - m_offscreen->ofs->Unbind(); - } -} - -void ImageRender::WaitSync() -{ - if (m_sync) { - m_sync->Wait(); - // done with it, deleted it - delete m_sync; - m_sync = NULL; - } - if (m_offscreen) { - // this is needed to finalize the image if the target is a texture - m_offscreen->ofs->MipMap(); - } - // all rendered operation done and complete, invalidate render for next time - m_done = false; -} - -// cast Image pointer to ImageRender -inline ImageRender * getImageRender (PyImage *self) -{ return static_cast<ImageRender*>(self->m_image); } - - -// python methods - -// Blender Scene type -static BlendType<KX_Scene> sceneType ("KX_Scene"); -// Blender Camera type -static BlendType<KX_Camera> cameraType ("KX_Camera"); - - -// object initialization -static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds) -{ - // parameters - scene object - PyObject *scene; - // camera object - PyObject *camera; - // offscreen buffer object - PyRASOffScreen *offscreen = NULL; - // parameter keywords - static const char *kwlist[] = {"sceneObj", "cameraObj", "ofsObj", NULL}; - // get parameters - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", - const_cast<char**>(kwlist), &scene, &camera, &offscreen)) - 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); - - if (offscreen) { - if (Py_TYPE(offscreen) != &PyRASOffScreen_Type) { - THRWEXCP(OffScreenInvalid, S_OK); - } - } - // get pointer to image structure - PyImage *self = reinterpret_cast<PyImage*>(pySelf); - // create source object - if (self->m_image != NULL) delete self->m_image; - self->m_image = new ImageRender(scenePtr, cameraPtr, offscreen); - } - catch (Exception & exp) - { - exp.report(); - return -1; - } - // initialization succeded - return 0; -} - -static PyObject *ImageRender_refresh(PyImage *self, PyObject *args) -{ - ImageRender *imageRender = getImageRender(self); - - if (!imageRender) { - PyErr_SetString(PyExc_TypeError, "Incomplete ImageRender() object"); - return NULL; - } - if (PyArg_ParseTuple(args, "")) { - // refresh called with no argument. - // For other image objects it simply invalidates the image buffer - // For ImageRender it triggers a render+sync - // Note that this only makes sense when doing offscreen render on texture - if (!imageRender->isDone()) { - if (!imageRender->Render()) { - Py_RETURN_FALSE; - } - // as we are not trying to read the pixels, just unbind - imageRender->Unbind(); - } - // wait until all render operations are completed - // this will also finalize the texture - imageRender->WaitSync(); - Py_RETURN_TRUE; - } - else { - // fallback on standard processing - PyErr_Clear(); - return Image_refresh(self, args); - } -} - -// refresh image -static PyObject *ImageRender_render(PyImage *self) -{ - ImageRender *imageRender = getImageRender(self); - - if (!imageRender) { - PyErr_SetString(PyExc_TypeError, "Incomplete ImageRender() object"); - return NULL; - } - if (!imageRender->Render()) { - Py_RETURN_FALSE; - } - // we are not reading the pixels now, unbind - imageRender->Unbind(); - Py_RETURN_TRUE; -} - - -// get background color -static PyObject *getBackground (PyImage *self, void *closure) -{ - return Py_BuildValue("[ffff]", - getImageRender(self)->getBackground(0), - getImageRender(self)->getBackground(1), - getImageRender(self)->getBackground(2), - getImageRender(self)->getBackground(3)); -} - -// set color -static int setBackground(PyImage *self, PyObject *value, void *closure) -{ - // check validity of parameter - if (value == NULL || !PySequence_Check(value) || PySequence_Size(value) != 4 - || (!PyFloat_Check(PySequence_Fast_GET_ITEM(value, 0)) && !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0))) - || (!PyFloat_Check(PySequence_Fast_GET_ITEM(value, 1)) && !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1))) - || (!PyFloat_Check(PySequence_Fast_GET_ITEM(value, 2)) && !PyLong_Check(PySequence_Fast_GET_ITEM(value, 2))) - || (!PyFloat_Check(PySequence_Fast_GET_ITEM(value, 3)) && !PyLong_Check(PySequence_Fast_GET_ITEM(value, 3)))) { - - PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 4 floats or ints between 0.0 and 255.0"); - return -1; - } - // set background color - getImageRender(self)->setBackground( - PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)), - PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)), - PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 2)), - PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 3))); - // success - return 0; -} - - -// methods structure -static PyMethodDef imageRenderMethods[] = -{ // methods from ImageBase class - {"refresh", (PyCFunction)ImageRender_refresh, METH_VARARGS, "Refresh image - invalidate its current content after optionally transferring its content to a target buffer"}, - {"render", (PyCFunction)ImageRender_render, METH_NOARGS, "Render scene - run before refresh() to performs asynchronous render"}, - {NULL} -}; -// attributes structure -static PyGetSetDef imageRenderGetSets[] = -{ - {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL}, - // attribute from ImageViewport - {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL}, - {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, - {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL}, - // attributes from ImageBase class - {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, - {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, - {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, - {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL}, - {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, - {(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL}, - {(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer using unsigned int precision", NULL}, - {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, - {NULL} -}; - - -// define python type -PyTypeObject ImageRenderType = { - PyVarObject_HEAD_INIT(NULL, 0) - "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*/ - &imageBufferProcs, /*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 */ -}; - -// object initialization -static int ImageMirror_init(PyObject *pySelf, PyObject *args, PyObject *kwds) -{ - // parameters - scene object - PyObject *scene; - // reference object for mirror - PyObject *observer; - // object holding the mirror - PyObject *mirror; - // material of the mirror - short materialID = 0; - // parameter keywords - static const char *kwlist[] = {"scene", "observer", "mirror", "material", NULL}; - // get parameters - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|h", - const_cast<char**>(kwlist), &scene, &observer, &mirror, &materialID)) - return -1; - try - { - // get scene pointer - KX_Scene * scenePtr (NULL); - if (scene != NULL && PyObject_TypeCheck(scene, &KX_Scene::Type)) - scenePtr = static_cast<KX_Scene*>BGE_PROXY_REF(scene); - else - THRWEXCP(SceneInvalid, S_OK); - - if (scenePtr==NULL) /* in case the python proxy reference is invalid */ - THRWEXCP(SceneInvalid, S_OK); - - // get observer pointer - KX_GameObject * observerPtr (NULL); - if (observer != NULL && PyObject_TypeCheck(observer, &KX_GameObject::Type)) - observerPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(observer); - else if (observer != NULL && PyObject_TypeCheck(observer, &KX_Camera::Type)) - observerPtr = static_cast<KX_Camera*>BGE_PROXY_REF(observer); - else - THRWEXCP(ObserverInvalid, S_OK); - - if (observerPtr==NULL) /* in case the python proxy reference is invalid */ - THRWEXCP(ObserverInvalid, S_OK); - - // get mirror pointer - KX_GameObject * mirrorPtr (NULL); - if (mirror != NULL && PyObject_TypeCheck(mirror, &KX_GameObject::Type)) - mirrorPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(mirror); - else - THRWEXCP(MirrorInvalid, S_OK); - - if (mirrorPtr==NULL) /* in case the python proxy reference is invalid */ - THRWEXCP(MirrorInvalid, S_OK); - - // locate the material in the mirror - RAS_IPolyMaterial * material = getMaterial(mirror, materialID); - if (material == NULL) - THRWEXCP(MaterialNotAvail, S_OK); - - // get pointer to image structure - PyImage *self = reinterpret_cast<PyImage*>(pySelf); - - // create source object - if (self->m_image != NULL) - { - delete self->m_image; - self->m_image = NULL; - } - self->m_image = new ImageRender(scenePtr, observerPtr, mirrorPtr, material); - } - catch (Exception & exp) - { - exp.report(); - return -1; - } - // initialization succeeded - return 0; -} - -// get background color -static PyObject *getClip (PyImage *self, void *closure) -{ - return PyFloat_FromDouble(getImageRender(self)->getClip()); -} - -// set clip -static int setClip(PyImage *self, PyObject *value, void *closure) -{ - // check validity of parameter - double clip; - if (value == NULL || !PyFloat_Check(value) || (clip = PyFloat_AsDouble(value)) < 0.01 || clip > 5000.0) - { - PyErr_SetString(PyExc_TypeError, "The value must be an float between 0.01 and 5000"); - return -1; - } - // set background color - getImageRender(self)->setClip(float(clip)); - // success - return 0; -} - -// attributes structure -static PyGetSetDef imageMirrorGetSets[] = -{ - {(char*)"clip", (getter)getClip, (setter)setClip, (char*)"clipping distance", NULL}, - // attribute from ImageRender - {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL}, - // attribute from ImageViewport - {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL}, - {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, - {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL}, - // attributes from ImageBase class - {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, - {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, - {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, - {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL}, - {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, - {(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL}, - {(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer using unsigned int precision", NULL}, - {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, - {NULL} -}; - - -// constructor -ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObject *mirror, RAS_IPolyMaterial *mat) : - ImageViewport(), - m_render(false), - m_done(false), - m_scene(scene), - m_offscreen(NULL), - m_sync(NULL), - m_observer(observer), - m_mirror(mirror), - m_clip(100.f) -{ - // this constructor is used for automatic planar mirror - // create a camera, take all data by default, in any case we will recompute the frustum on each frame - RAS_CameraData camdata; - vector<RAS_TexVert*> mirrorVerts; - vector<RAS_TexVert*>::iterator it; - float mirrorArea = 0.f; - float mirrorNormal[3] = {0.f, 0.f, 0.f}; - float mirrorUp[3]; - float dist, vec[3], axis[3]; - float zaxis[3] = {0.f, 0.f, 1.f}; - float yaxis[3] = {0.f, 1.f, 0.f}; - float mirrorMat[3][3]; - float left, right, top, bottom, back; - // make sure this camera will delete its node - m_camera= new KX_Camera(scene, KX_Scene::m_callbacks, camdata, true, true); - m_camera->SetName("__mirror__cam__"); - // don't add the camera to the scene object list, it doesn't need to be accessible - m_owncamera = true; - // retrieve rendering objects - m_engine = KX_GetActiveEngine(); - m_rasterizer = m_engine->GetRasterizer(); - m_canvas = m_engine->GetCanvas(); - // locate the vertex assigned to mat and do following calculation in mesh coordinates - for (int meshIndex = 0; meshIndex < mirror->GetMeshCount(); meshIndex++) - { - RAS_MeshObject* mesh = mirror->GetMesh(meshIndex); - int numPolygons = mesh->NumPolygons(); - for (int polygonIndex=0; polygonIndex < numPolygons; polygonIndex++) - { - RAS_Polygon* polygon = mesh->GetPolygon(polygonIndex); - if (polygon->GetMaterial()->GetPolyMaterial() == mat) - { - RAS_TexVert *v1, *v2, *v3, *v4; - float normal[3]; - float area; - // this polygon is part of the mirror - v1 = polygon->GetVertex(0); - v2 = polygon->GetVertex(1); - v3 = polygon->GetVertex(2); - mirrorVerts.push_back(v1); - mirrorVerts.push_back(v2); - mirrorVerts.push_back(v3); - if (polygon->VertexCount() == 4) { - v4 = polygon->GetVertex(3); - mirrorVerts.push_back(v4); - area = normal_quad_v3(normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), (float*)v4->getXYZ()); - } - else { - area = normal_tri_v3(normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ()); - } - area = fabs(area); - mirrorArea += area; - mul_v3_fl(normal, area); - add_v3_v3v3(mirrorNormal, mirrorNormal, normal); - } - } - } - if (mirrorVerts.size() == 0 || mirrorArea < FLT_EPSILON) - { - // no vertex or zero size mirror - THRWEXCP(MirrorSizeInvalid, S_OK); - } - // compute average normal of mirror faces - mul_v3_fl(mirrorNormal, 1.0f/mirrorArea); - if (normalize_v3(mirrorNormal) == 0.f) - { - // no normal - THRWEXCP(MirrorNormalInvalid, S_OK); - } - // the mirror plane has an equation of the type ax+by+cz = d where (a,b,c) is the normal vector - // if the mirror is more vertical then horizontal, the Z axis is the up direction. - // otherwise the Y axis is the up direction. - // If the mirror is not perfectly vertical(horizontal), the Z(Y) axis projection on the mirror - // plan by the normal will be the up direction. - if (fabsf(mirrorNormal[2]) > fabsf(mirrorNormal[1]) && - fabsf(mirrorNormal[2]) > fabsf(mirrorNormal[0])) - { - // the mirror is more horizontal than vertical - copy_v3_v3(axis, yaxis); - } - else - { - // the mirror is more vertical than horizontal - copy_v3_v3(axis, zaxis); - } - dist = dot_v3v3(mirrorNormal, axis); - if (fabsf(dist) < FLT_EPSILON) - { - // the mirror is already fully aligned with up axis - copy_v3_v3(mirrorUp, axis); - } - else - { - // projection of axis to mirror plane through normal - copy_v3_v3(vec, mirrorNormal); - mul_v3_fl(vec, dist); - sub_v3_v3v3(mirrorUp, axis, vec); - if (normalize_v3(mirrorUp) == 0.f) - { - // should not happen - THRWEXCP(MirrorHorizontal, S_OK); - return; - } - } - // compute rotation matrix between local coord and mirror coord - // to match camera orientation, we select mirror z = -normal, y = up, x = y x z - negate_v3_v3(mirrorMat[2], mirrorNormal); - copy_v3_v3(mirrorMat[1], mirrorUp); - cross_v3_v3v3(mirrorMat[0], mirrorMat[1], mirrorMat[2]); - // transpose to make it a orientation matrix from local space to mirror space - transpose_m3(mirrorMat); - // transform all vertex to plane coordinates and determine mirror position - left = FLT_MAX; - right = -FLT_MAX; - bottom = FLT_MAX; - top = -FLT_MAX; - back = -FLT_MAX; // most backward vertex (=highest Z coord in mirror space) - for (it = mirrorVerts.begin(); it != mirrorVerts.end(); it++) - { - copy_v3_v3(vec, (float*)(*it)->getXYZ()); - mul_m3_v3(mirrorMat, vec); - if (vec[0] < left) - left = vec[0]; - if (vec[0] > right) - right = vec[0]; - if (vec[1] < bottom) - bottom = vec[1]; - if (vec[1] > top) - top = vec[1]; - if (vec[2] > back) - back = vec[2]; - } - // now store this information in the object for later rendering - m_mirrorHalfWidth = (right-left)*0.5f; - m_mirrorHalfHeight = (top-bottom)*0.5f; - if (m_mirrorHalfWidth < 0.01f || m_mirrorHalfHeight < 0.01f) - { - // mirror too small - THRWEXCP(MirrorTooSmall, S_OK); - } - // mirror position in mirror coord - vec[0] = (left+right)*0.5f; - vec[1] = (top+bottom)*0.5f; - vec[2] = back; - // convert it in local space: transpose again the matrix to get back to mirror to local transform - transpose_m3(mirrorMat); - mul_m3_v3(mirrorMat, vec); - // mirror position in local space - m_mirrorPos.setValue(vec[0], vec[1], vec[2]); - // mirror normal vector (pointed towards the back of the mirror) in local space - m_mirrorZ.setValue(-mirrorNormal[0], -mirrorNormal[1], -mirrorNormal[2]); - m_mirrorY.setValue(mirrorUp[0], mirrorUp[1], mirrorUp[2]); - m_mirrorX = m_mirrorY.cross(m_mirrorZ); - m_render = true; - - // set mirror background color to scene background color as default - setBackgroundFromScene(m_scene); -} - - - - -// define python type -PyTypeObject ImageMirrorType = { - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.ImageMirror", /*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*/ - &imageBufferProcs, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Image source from mirror", /* 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 */ - imageMirrorGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)ImageMirror_init, /* tp_init */ - 0, /* tp_alloc */ - Image_allocNew, /* tp_new */ -}; - - diff --git a/source/gameengine/VideoTexture/ImageRender.h b/source/gameengine/VideoTexture/ImageRender.h deleted file mode 100644 index d062db44348..00000000000 --- a/source/gameengine/VideoTexture/ImageRender.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file ImageRender.h - * \ingroup bgevideotex - */ - -#ifndef __IMAGERENDER_H__ -#define __IMAGERENDER_H__ - - -#include "Common.h" - -#include "KX_Scene.h" -#include "KX_Camera.h" -#include "DNA_screen_types.h" -#include "RAS_ICanvas.h" -#include "RAS_IRasterizer.h" -#include "RAS_IOffScreen.h" -#include "RAS_ISync.h" - -#include "ImageViewport.h" - - -/// class for render 3d scene -class ImageRender : public ImageViewport -{ -public: - /// constructor - ImageRender(KX_Scene *scene, KX_Camera *camera, PyRASOffScreen *offscreen); - ImageRender(KX_Scene *scene, KX_GameObject *observer, KX_GameObject *mirror, RAS_IPolyMaterial * mat); - - /// destructor - virtual ~ImageRender (void); - - /// get background color - float getBackground (int idx); - /// set background color - void setBackground (float red, float green, float blue, float alpha); - - /// clipping distance - float getClip (void) { return m_clip; } - /// set whole buffer use - void setClip (float clip) { m_clip = clip; } - /// render status - bool isDone() { return m_done; } - /// render frame (public so that it is accessible from python) - bool Render(); - /// in case fbo is used, method to unbind - void Unbind(); - /// wait for render to complete - void WaitSync(); - -protected: - /// true if ready to render - bool m_render; - /// is render done already? - bool m_done; - /// rendered scene - KX_Scene * m_scene; - /// camera for render - KX_Camera * m_camera; - /// do we own the camera? - bool m_owncamera; - /// if offscreen render - PyRASOffScreen *m_offscreen; - /// object to synchronize render even if no buffer transfer - RAS_ISync *m_sync; - /// for mirror operation - KX_GameObject * m_observer; - KX_GameObject * m_mirror; - float m_clip; // clipping distance - float m_mirrorHalfWidth; // mirror width in mirror space - float m_mirrorHalfHeight; // mirror height in mirror space - MT_Point3 m_mirrorPos; // mirror center position in local space - MT_Vector3 m_mirrorZ; // mirror Z axis in local space - MT_Vector3 m_mirrorY; // mirror Y axis in local space - MT_Vector3 m_mirrorX; // mirror X axis in local space - /// canvas - RAS_ICanvas* m_canvas; - /// rasterizer - RAS_IRasterizer* m_rasterizer; - /// engine - KX_KetsjiEngine* m_engine; - - /// background color - float m_background[4]; - - - /// render 3d scene to image - virtual void calcImage (unsigned int texId, double ts) { calcViewport(texId, ts, GL_RGBA); } - - /// render 3d scene to image - virtual void calcViewport (unsigned int texId, double ts, unsigned int format); - - void setBackgroundFromScene(KX_Scene *scene); - void SetWorldSettings(KX_WorldInfo* wi); -}; - - -#endif - diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp deleted file mode 100644 index ad3d8875e28..00000000000 --- a/source/gameengine/VideoTexture/ImageViewport.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/ImageViewport.cpp - * \ingroup bgevideotex - */ - -// implementation - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "GPU_glew.h" - -#include "KX_PythonInit.h" -#include "RAS_ICanvas.h" -#include "Texture.h" -#include "ImageBase.h" -#include "VideoBase.h" -#include "FilterSource.h" -#include "ImageViewport.h" - - -// constructor -ImageViewport::ImageViewport (PyRASOffScreen *offscreen) : m_alpha(false), m_texInit(false) -{ - // get viewport rectangle - if (offscreen) { - m_viewport[0] = 0; - m_viewport[1] = 0; - m_viewport[2] = offscreen->ofs->GetWidth(); - m_viewport[3] = offscreen->ofs->GetHeight(); - } - else { - RAS_Rect rect = KX_GetActiveEngine()->GetCanvas()->GetWindowArea(); - m_viewport[0] = rect.GetLeft(); - m_viewport[1] = rect.GetBottom(); - m_viewport[2] = rect.GetWidth(); - m_viewport[3] = rect.GetHeight(); - } - - //glGetIntegerv(GL_VIEWPORT, m_viewport); - // create buffer for viewport image - // Warning: this buffer is also used to get the depth buffer as an array of - // float (1 float = 4 bytes per pixel) - m_viewportImage = new BYTE [4 * getViewportSize()[0] * getViewportSize()[1]]; - // set attributes - setWhole((offscreen) ? true : 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[2]) -{ - m_whole = false; - if (size == NULL) - size = m_capSize; - for (int idx = 0; idx < 2; ++idx) - { - if (size[idx] < 1) - m_capSize[idx] = 1; - else if (size[idx] > getViewportSize()[idx]) - m_capSize[idx] = short(getViewportSize()[idx]); - else - m_capSize[idx] = size[idx]; - } - init(m_capSize[0], m_capSize[1]); - // set capture position - setPosition(); -} - -// set position of capture rectangle -void ImageViewport::setPosition (GLint pos[2]) -{ - // 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::calcViewport (unsigned int texId, double ts, unsigned int format) -{ - // if scale was changed - if (m_scaleChange) - // reset image - init(m_capSize[0], m_capSize[1]); - // if texture wasn't initialized - if (!m_texInit && texId != 0) { - // initialize it - loadTexture(texId, m_image, m_size); - m_texInit = true; - } - // if texture can be directly created - if (texId != 0 && m_pyfilter == NULL && m_size[0] == m_capSize[0] && - m_size[1] == m_capSize[1] && !m_flip && !m_zbuff && !m_depth) - { - // just copy current viewport to texture - glBindTexture(GL_TEXTURE_2D, texId); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1]); - glBindTexture(GL_TEXTURE_2D, 0); - // image is not available - m_avail = false; - } - // otherwise copy viewport to buffer, if image is not available - else if (!m_avail) { - if (m_zbuff) { - // Use read pixels with the depth buffer - // *** misusing m_viewportImage here, but since it has the correct size - // (4 bytes per pixel = size of float) and we just need it to apply - // the filter, it's ok - glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], - GL_DEPTH_COMPONENT, GL_FLOAT, m_viewportImage); - // filter loaded data - FilterZZZA filt; - filterImage(filt, (float *)m_viewportImage, m_capSize); - } - else { - - if (m_depth) { - // Use read pixels with the depth buffer - // See warning above about m_viewportImage. - glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], - GL_DEPTH_COMPONENT, GL_FLOAT, m_viewportImage); - // filter loaded data - FilterDEPTH filt; - filterImage(filt, (float *)m_viewportImage, m_capSize); - } - else { - - // get frame buffer data - if (m_alpha) { - // as we are reading the pixel in the native format, we can read directly in the image buffer - // if we are sure that no processing is needed on the image - if (m_size[0] == m_capSize[0] && - m_size[1] == m_capSize[1] && - !m_flip && - !m_pyfilter) - { - glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], format, - GL_UNSIGNED_BYTE, m_image); - m_avail = true; - } - else if (!m_pyfilter) { - glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], format, - GL_UNSIGNED_BYTE, m_viewportImage); - FilterRGBA32 filt; - filterImage(filt, m_viewportImage, m_capSize); - } - else { - glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA, - GL_UNSIGNED_BYTE, m_viewportImage); - FilterRGBA32 filt; - filterImage(filt, m_viewportImage, m_capSize); - if (format == GL_BGRA) { - // in place byte swapping - swapImageBR(); - } - } - } - else { - glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB, - GL_UNSIGNED_BYTE, m_viewportImage); - // filter loaded data - FilterRGB24 filt; - filterImage(filt, m_viewportImage, m_capSize); - if (format == GL_BGRA) { - // in place byte swapping - swapImageBR(); - } - } - } - } - } -} - -bool ImageViewport::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts) -{ - unsigned int *tmp_image; - bool ret; - - // if scale was changed - if (m_scaleChange) { - // reset image - init(m_capSize[0], m_capSize[1]); - } - - // size must be identical - if (size < getBuffSize()) - return false; - - if (m_avail) { - // just copy - return ImageBase::loadImage(buffer, size, format, ts); - } - else { - tmp_image = m_image; - m_image = buffer; - calcViewport(0, ts, format); - ret = m_avail; - m_image = tmp_image; - // since the image was not loaded to our buffer, it's not valid - m_avail = false; - } - return ret; -} - - -// cast Image pointer to ImageViewport -inline ImageViewport * getImageViewport (PyImage *self) -{ return static_cast<ImageViewport*>(self->m_image); } - - -// python methods - - -// get whole -PyObject *ImageViewport_getWhole (PyImage *self, void *closure) -{ - if (self->m_image != NULL && getImageViewport(self)->getWhole()) Py_RETURN_TRUE; - else Py_RETURN_FALSE; -} - -// set whole -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; - } - try - { - // set whole, can throw in case of resize and buffer exports - if (self->m_image != NULL) getImageViewport(self)->setWhole(value == Py_True); - } - catch (Exception & exp) - { - exp.report(); - return -1; - } - // success - return 0; -} - -// get alpha -PyObject *ImageViewport_getAlpha (PyImage *self, void *closure) -{ - if (self->m_image != NULL && getImageViewport(self)->getAlpha()) Py_RETURN_TRUE; - else Py_RETURN_FALSE; -} - -// set whole -int ImageViewport_setAlpha(PyImage *self, PyObject *value, void *closure) -{ - // check parameter, report failure - if (value == NULL || !PyBool_Check(value)) - { - PyErr_SetString(PyExc_TypeError, "The value must be a bool"); - return -1; - } - // set alpha - if (self->m_image != NULL) getImageViewport(self)->setAlpha(value == Py_True); - // success - return 0; -} - - -// get position -static PyObject *ImageViewport_getPosition (PyImage *self, void *closure) -{ - GLint *pos = getImageViewport(self)->getPosition(); - PyObject *ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, PyLong_FromLong(pos[0])); - PyTuple_SET_ITEM(ret, 1, PyLong_FromLong(pos[1])); - return ret; -} - -// set position -static int ImageViewport_setPosition(PyImage *self, PyObject *value, void *closure) -{ - // check validity of parameter - if (value == NULL || - !(PyTuple_Check(value) || PyList_Check(value)) || - PySequence_Fast_GET_SIZE(value) != 2 || - !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) || - !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1))) - { - PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints"); - return -1; - } - // set position - GLint pos[2] = { - GLint(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 0))), - GLint(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 1))) - }; - getImageViewport(self)->setPosition(pos); - // success - return 0; -} - -// get capture size -PyObject *ImageViewport_getCaptureSize (PyImage *self, void *closure) -{ - short *size = getImageViewport(self)->getCaptureSize(); - PyObject *ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, PyLong_FromLong(size[0])); - PyTuple_SET_ITEM(ret, 1, PyLong_FromLong(size[1])); - return ret; -} - -// set capture size -int ImageViewport_setCaptureSize(PyImage *self, PyObject *value, void *closure) -{ - // check validity of parameter - if (value == NULL || - !(PyTuple_Check(value) || PyList_Check(value)) || - PySequence_Fast_GET_SIZE(value) != 2 || - !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) || - !PyLong_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[2] = { - short(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 0))), - short(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 1))) - }; - try - { - // can throw in case of resize and buffer exports - getImageViewport(self)->setCaptureSize(size); - } - catch (Exception & exp) - { - exp.report(); - return -1; - } - // success - return 0; -} - - -// methods structure -static PyMethodDef imageViewportMethods[] = -{ // methods from ImageBase class - {"refresh", (PyCFunction)Image_refresh, METH_VARARGS, "Refresh image - invalidate its current content"}, - {NULL} -}; -// attributes structure -static PyGetSetDef imageViewportGetSets[] = -{ - {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to capture", NULL}, - {(char*)"position", (getter)ImageViewport_getPosition, (setter)ImageViewport_setPosition, (char*)"upper left corner of captured area", NULL}, - {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of viewport area being captured", NULL}, - {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, - // attributes from ImageBase class - {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, - {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, - {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, - {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL}, - {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, - {(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL}, - {(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer as array of float", NULL}, - {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, - {NULL} -}; - - -// define python type -PyTypeObject ImageViewportType = { - PyVarObject_HEAD_INIT(NULL, 0) - "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*/ - &imageBufferProcs, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Image source from viewport", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - imageViewportMethods, /* tp_methods */ - 0, /* tp_members */ - imageViewportGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Image_init<ImageViewport>, /* tp_init */ - 0, /* tp_alloc */ - Image_allocNew, /* tp_new */ -}; diff --git a/source/gameengine/VideoTexture/ImageViewport.h b/source/gameengine/VideoTexture/ImageViewport.h deleted file mode 100644 index 8a7e9cfd2ba..00000000000 --- a/source/gameengine/VideoTexture/ImageViewport.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file ImageViewport.h - * \ingroup bgevideotex - */ - -#ifndef __IMAGEVIEWPORT_H__ -#define __IMAGEVIEWPORT_H__ - - -#include "Common.h" - -#include "ImageBase.h" -#include "RAS_IOffScreen.h" - - -/// class for viewport access -class ImageViewport : public ImageBase -{ -public: - /// constructor - ImageViewport (PyRASOffScreen *offscreen=NULL); - - /// destructor - virtual ~ImageViewport (void); - - /// is whole buffer used - bool getWhole (void) { return m_whole; } - /// set whole buffer use - void setWhole (bool whole); - - /// is alpha channel used - bool getAlpha (void) { return m_alpha; } - /// set whole buffer use - void setAlpha (bool alpha) { m_alpha = alpha; } - - /// get capture size in viewport - short * getCaptureSize (void) { return m_capSize; } - /// set capture size in viewport - void setCaptureSize (short size[2] = NULL); - - /// get position in viewport - GLint * getPosition (void) { return m_position; } - /// set position in viewport - void setPosition (GLint pos[2] = NULL); - - /// capture image from viewport to user buffer - virtual bool loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts); - -protected: - /// frame buffer rectangle - GLint m_viewport[4]; - - /// size of captured area - short m_capSize[2]; - /// use whole viewport - bool m_whole; - /// use alpha channel - bool m_alpha; - - /// position of capture rectangle in viewport - GLint m_position[2]; - /// upper left point for capturing - GLint m_upLeft[2]; - - /// buffer to copy viewport - BYTE * m_viewportImage; - /// texture is initialized - bool m_texInit; - - /// capture image from viewport - virtual void calcImage (unsigned int texId, double ts) { calcViewport(texId, ts, GL_RGBA); } - - /// capture image from viewport - virtual void calcViewport (unsigned int texId, double ts, unsigned int format); - - /// get viewport size - GLint * getViewportSize (void) { return m_viewport + 2; } -}; - -PyObject *ImageViewport_getCaptureSize(PyImage *self, void *closure); -int ImageViewport_setCaptureSize(PyImage *self, PyObject *value, void *closure); -PyObject *ImageViewport_getWhole(PyImage *self, void *closure); -int ImageViewport_setWhole(PyImage *self, PyObject *value, void *closure); -PyObject *ImageViewport_getAlpha(PyImage *self, void *closure); -int ImageViewport_setAlpha(PyImage *self, PyObject *value, void *closure); - -#endif - diff --git a/source/gameengine/VideoTexture/PyTypeList.cpp b/source/gameengine/VideoTexture/PyTypeList.cpp deleted file mode 100644 index 18f477f6178..00000000000 --- a/source/gameengine/VideoTexture/PyTypeList.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of blendTex library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/PyTypeList.cpp - * \ingroup bgevideotex - */ - -#include "PyTypeList.h" - -#include <memory> -#include <vector> - -#include "EXP_PyObjectPlus.h" - -/// destructor -PyTypeList::~PyTypeList() -{ - // if list exists - if (m_list.get() != NULL) - for (PyTypeListType::iterator it = m_list->begin(); it != m_list->end(); ++it) - delete *it; -} - -/// 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) -{ - // 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 deleted file mode 100644 index ce0eb81e656..00000000000 --- a/source/gameengine/VideoTexture/PyTypeList.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of blendTex library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file PyTypeList.h - * \ingroup bgevideotex - */ - -#ifndef __PYTYPELIST_H__ -#define __PYTYPELIST_H__ - -#include "Common.h" - -#include <memory> -#include <vector> - -#include "EXP_PyObjectPlus.h" - -// forward declaration -class PyTypeListItem; - -// type for list of types -typedef std::vector<PyTypeListItem*> PyTypeListType; - - -/// class to store list of python types -class PyTypeList -{ -public: - /// destructor - ~PyTypeList(); - - /// 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 -#if (__cplusplus > 199711L) /* || (defined(_MSC_VER) && _MSC_VER >= 1800) */ - std::unique_ptr<PyTypeListType> m_list; -#else - std::auto_ptr<PyTypeListType> m_list; -#endif -}; - - -/// 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/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp deleted file mode 100644 index 48dc4c705bf..00000000000 --- a/source/gameengine/VideoTexture/Texture.cpp +++ /dev/null @@ -1,533 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/Texture.cpp - * \ingroup bgevideotex - */ - -// implementation - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "KX_GameObject.h" -#include "KX_Light.h" -#include "RAS_MeshObject.h" -#include "RAS_ILightObject.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_image_types.h" -#include "IMB_imbuf_types.h" -#include "BKE_image.h" - -#include "MEM_guardedalloc.h" - -#include "KX_BlenderMaterial.h" -#include "BL_Texture.h" - -#include "KX_KetsjiEngine.h" -#include "KX_PythonInit.h" -#include "Texture.h" -#include "ImageBase.h" -#include "Exception.h" - -#include <memory.h> -#include "GPU_glew.h" - -extern "C" { - #include "IMB_imbuf.h" -} - -// macro for exception handling and logging -#define CATCH_EXCP catch (Exception & exp) \ -{ exp.report(); return NULL; } - - -// Blender GameObject type -static BlendType<KX_GameObject> gameObjectType ("KX_GameObject"); -static BlendType<KX_LightObject> lightObjectType ("KX_LightObject"); - - -// 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) - { - int i; - ImBuf *ibuf; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - ibuf = IMB_allocFromBuffer(texture, NULL, size[0], size[1]); - - IMB_makemipmap(ibuf, true); - - for (i = 0; i < ibuf->miptot; i++) { - ImBuf *mip = IMB_getmipmap(ibuf, i); - - glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect); - } - IMB_freeImBuf(ibuf); - } - 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 pointer to a lamp -static KX_LightObject *getLamp(PyObject *obj) -{ - // if object is available - if (obj == NULL) return NULL; - - // returns NULL if obj is not a KX_LightObject - return lightObjectType.checkType(obj); -} - - -// get material ID -short getMaterialID(PyObject *obj, const char *name) -{ - // search for material - for (short matID = 0;; ++matID) - { - // get material - RAS_IPolyMaterial * mat = getMaterial(obj, matID); - // if material is not available, report that no material was found - if (mat == NULL) - break; - // name is a material name if it starts with MA and a UV texture name if it starts with IM - if (name[0] == 'I' && name[1] == 'M') { - // if texture name matches - if (strcmp(mat->GetTextureName().ReadPtr(), name) == 0) - return matID; - } - else { - // if material name matches - if (strcmp(mat->GetMaterialName().ReadPtr(), name) == 0) - return matID; - } - } - // material was not found - return -1; -} - - -// Texture object allocation -static PyObject *Texture_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - // allocate object - Texture * self = reinterpret_cast<Texture*>(type->tp_alloc(type, 0)); - // initialize object structure - self->m_actTex = 0; - self->m_orgSaved = false; - self->m_imgBuf = NULL; - self->m_imgTexture = NULL; - self->m_matTexture = NULL; - self->m_mipmap = false; - self->m_scaledImBuf = NULL; - self->m_source = NULL; - self->m_lastClock = 0.0; - // return allocated object - return reinterpret_cast<PyObject*>(self); -} - - -// forward declaration -PyObject *Texture_close(Texture *self); -int Texture_setSource(Texture *self, PyObject *value, void *closure); - - -// Texture object deallocation -static void Texture_dealloc(Texture *self) -{ - // release renderer - Py_XDECREF(self->m_source); - // close texture - PyObject *ret = Texture_close(self); - Py_DECREF(ret); - // release scaled image buffer - IMB_freeImBuf(self->m_scaledImBuf); - // release object - Py_TYPE((PyObject *)self)->tp_free((PyObject *)self); -} - - -ExceptionID MaterialNotAvail; -ExpDesc MaterialNotAvailDesc(MaterialNotAvail, "Texture material is not available"); - -// Texture object initialization -static 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 const char *kwlist[] = {"gameObj", "materialID", "textureID", "textureObj", NULL}; - - // get parameters - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|hhO!", - const_cast<char**>(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); - KX_LightObject * lamp = getLamp(obj); - if (mat != NULL) - { - // is it blender material or polygon material - if (mat->GetFlag() & RAS_BLENDERGLSL) - { - self->m_imgTexture = static_cast<KX_BlenderMaterial*>(mat)->getImage(texID); - self->m_useMatTexture = false; - } else - { - // get blender material texture - self->m_matTexture = static_cast<KX_BlenderMaterial*>(mat)->getTex(texID); - self->m_useMatTexture = true; - } - } - else if (lamp != NULL) - { - self->m_imgTexture = lamp->GetLightData()->GetTextureImage(texID); - self->m_useMatTexture = false; - } - - // check if texture is available, if not, initialization failed - if (self->m_imgTexture == NULL && self->m_matTexture == NULL) - // throw exception if initialization failed - THRWEXCP(MaterialNotAvail, S_OK); - - // if texture object is provided - if (texObj != NULL) - { - // copy texture code - self->m_actTex = texObj->m_actTex; - self->m_mipmap = texObj->m_mipmap; - if (texObj->m_source != NULL) - Texture_setSource(self, reinterpret_cast<PyObject*>(texObj->m_source), NULL); - } - else - // otherwise generate texture code - glGenTextures(1, (GLuint*)&self->m_actTex); - } - catch (Exception & exp) - { - exp.report(); - return -1; - } - } - // initialization succeded - return 0; -} - - -// close added texture -PyObject *Texture_close(Texture * self) -{ - // restore texture - if (self->m_orgSaved) - { - self->m_orgSaved = false; - // restore original texture code - if (self->m_useMatTexture) - self->m_matTexture->swapTexture(self->m_orgTex); - else - { - self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D] = self->m_orgTex; - BKE_image_release_ibuf(self->m_imgTexture, self->m_imgBuf, NULL); - self->m_imgBuf = NULL; - } - // drop actual texture - if (self->m_actTex != 0) - { - glDeleteTextures(1, (GLuint *)&self->m_actTex); - self->m_actTex = 0; - } - } - Py_RETURN_NONE; -} - - -// refresh texture -static PyObject *Texture_refresh(Texture *self, PyObject *args) -{ - // get parameter - refresh source - PyObject *param; - double ts = -1.0; - - if (!PyArg_ParseTuple(args, "O|d:refresh", ¶m, &ts) || !PyBool_Check(param)) - { - // report error - PyErr_SetString(PyExc_TypeError, "The value must be a bool"); - return NULL; - } - // some trick here: we are in the business of loading a texture, - // no use to do it if we are still in the same rendering frame. - // We find this out by looking at the engine current clock time - KX_KetsjiEngine* engine = KX_GetActiveEngine(); - if (engine->GetClockTime() != self->m_lastClock) - { - self->m_lastClock = engine->GetClockTime(); - // set source refresh - bool refreshSource = (param == Py_True); - // try to proces texture from source - try - { - // if source is available - if (self->m_source != NULL) - { - // check texture code - if (!self->m_orgSaved) - { - self->m_orgSaved = true; - // save original image code - if (self->m_useMatTexture) - self->m_orgTex = self->m_matTexture->swapTexture(self->m_actTex); - else - { - // Swapping will work only if the GPU has already loaded the image. - // If not, it will delete and overwrite our texture on next render. - // To avoid that, we acquire the image buffer now. - // WARNING: GPU has a ImageUser to pass, we don't. Using NULL - // works on image file, not necessarily on other type of image. - self->m_imgBuf = BKE_image_acquire_ibuf(self->m_imgTexture, NULL, NULL); - self->m_orgTex = self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D]; - self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D] = self->m_actTex; - } - } - - // get texture - unsigned int * texture = self->m_source->m_image->getImage(self->m_actTex, ts); - // if texture is available - if (texture != NULL) - { - // get texture size - short * orgSize = self->m_source->m_image->getSize(); - // calc scaled sizes - short size[2]; - if (GLEW_ARB_texture_non_power_of_two) - { - size[0] = orgSize[0]; - size[1] = orgSize[1]; - } - else - { - size[0] = ImageBase::calcSize(orgSize[0]); - size[1] = ImageBase::calcSize(orgSize[1]); - } - // scale texture if needed - if (size[0] != orgSize[0] || size[1] != orgSize[1]) - { - IMB_freeImBuf(self->m_scaledImBuf); - self->m_scaledImBuf = IMB_allocFromBuffer(texture, NULL, orgSize[0], orgSize[1]); - IMB_scaleImBuf(self->m_scaledImBuf, size[0], size[1]); - - // use scaled image instead original - texture = self->m_scaledImBuf->rect; - } - // 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 OpenGL Bind Id -static PyObject *Texture_getBindId(Texture *self, void *closure) -{ - unsigned int id = self->m_actTex; - return Py_BuildValue("h", id); -} - -// get mipmap value -static 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 -static 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 -static PyObject *Texture_getSource(Texture *self, PyObject *value, void *closure) -{ - // if source exists - if (self->m_source != NULL) - { - Py_INCREF(self->m_source); - return reinterpret_cast<PyObject*>(self->m_source); - } - // otherwise return None - Py_RETURN_NONE; -} - - -// set source object -int Texture_setSource(Texture *self, PyObject *value, void *closure) -{ - // check new value - if (value == NULL || !pyImageTypes.in(Py_TYPE(value))) - { - // report value error - PyErr_SetString(PyExc_TypeError, "Invalid type of value"); - return -1; - } - // increase ref count for new value - Py_INCREF(value); - // release previous - Py_XDECREF(self->m_source); - // set new value - self->m_source = reinterpret_cast<PyImage*>(value); - // return success - return 0; -} - - -// class Texture methods -static PyMethodDef textureMethods[] = -{ - { "close", (PyCFunction)Texture_close, METH_NOARGS, "Close dynamic texture and restore original"}, - { "refresh", (PyCFunction)Texture_refresh, METH_VARARGS, "Refresh texture from source"}, - {NULL} /* Sentinel */ -}; - -// class Texture attributes -static PyGetSetDef textureGetSets[] = -{ - {(char*)"source", (getter)Texture_getSource, (setter)Texture_setSource, (char*)"source of texture", NULL}, - {(char*)"mipmap", (getter)Texture_getMipmap, (setter)Texture_setMipmap, (char*)"mipmap texture", NULL}, - {(char*)"bindId", (getter)Texture_getBindId, NULL, (char*)"OpenGL Bind Name", NULL}, - {NULL} -}; - - -// class Texture declaration -PyTypeObject TextureType = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "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*/ - &imageBufferProcs, /*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 deleted file mode 100644 index dc38b4181bb..00000000000 --- a/source/gameengine/VideoTexture/Texture.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2006 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file VideoTexture/Texture.h - * \ingroup bgevideotex - */ - -#ifndef __TEXTURE_H__ -#define __TEXTURE_H__ - -#include "EXP_PyObjectPlus.h" -#include <structmember.h> - -#include "DNA_image_types.h" -#include "BL_Texture.h" -#include "KX_BlenderMaterial.h" - -#include "ImageBase.h" -#include "BlendType.h" -#include "Exception.h" - - -struct ImBuf; - -// type Texture declaration -struct Texture -{ - PyObject_HEAD - - // texture is using blender material - bool m_useMatTexture; - - // video texture bind code - unsigned int m_actTex; - // original texture bind code - unsigned int m_orgTex; - // original texture saved - bool m_orgSaved; - - // kernel image buffer, to make sure the image is loaded before we swap the bindcode - struct ImBuf *m_imgBuf; - // texture image for game materials - Image * m_imgTexture; - // texture for blender materials - BL_Texture * m_matTexture; - - // use mipmapping - bool m_mipmap; - - // scaled image buffer - ImBuf * m_scaledImBuf; - // last refresh - double m_lastClock; - - // image source - PyImage * m_source; -}; - - -// Texture type description -extern PyTypeObject TextureType; - -// load texture -void loadTexture(unsigned int texId, unsigned int *texture, short *size, - bool mipmap = false); - -// get material -RAS_IPolyMaterial *getMaterial(PyObject *obj, short matID); - -// get material ID -short getMaterialID(PyObject *obj, const char *name); - -// Exceptions -extern ExceptionID MaterialNotAvail; - -#endif diff --git a/source/gameengine/VideoTexture/VideoBase.cpp b/source/gameengine/VideoTexture/VideoBase.cpp deleted file mode 100644 index d373055b5df..00000000000 --- a/source/gameengine/VideoTexture/VideoBase.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/VideoBase.cpp - * \ingroup bgevideotex - */ - -#if defined WIN32 -#define WINDOWS_LEAN_AND_MEAN -#include <windows.h> -#endif - -#include "VideoBase.h" - -#include "FilterSource.h" - -// VideoBase implementation - - -// initialize image data -void VideoBase::init(short width, short height) -{ - // save original sizes - m_orgSize[0] = width; - m_orgSize[1] = height; - // call base class initialization - ImageBase::init(width, height); -} - - -// process video frame -void VideoBase::process (BYTE *sample) -{ - // if scale was changed - if (m_scaleChange) - // reset image - init(m_orgSize[0], m_orgSize[1]); - // if image is allocated and is able to store new image - if (m_image != NULL && !m_avail) - { - // filters used - // convert video format to image - switch (m_format) - { - case RGBA32: - { - FilterRGBA32 filtRGBA; - // use filter object for format to convert image - filterImage(filtRGBA, sample, m_orgSize); - // finish - break; - } - case RGB24: - { - FilterRGB24 filtRGB; - // use filter object for format to convert image - filterImage(filtRGB, sample, m_orgSize); - // finish - break; - } - case YV12: - { - // use filter object for format to convert image - FilterYV12 filtYUV; - filtYUV.setBuffs(sample, m_orgSize); - filterImage(filtYUV, sample, m_orgSize); - // finish - break; - } - case None: - break; /* assert? */ - } - } -} - - -// 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; } - -// pause video -PyObject *Video_pause(PyImage *self) -{ if (getVideo(self)->pause()) Py_RETURN_TRUE; else Py_RETURN_FALSE; } - -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, PyObject *args) -{ - Py_buffer buffer; - char *mode = NULL; - unsigned int format; - double ts = -1.0; - - memset(&buffer, 0, sizeof(buffer)); - if (PyArg_ParseTuple(args, "|s*sd:refresh", &buffer, &mode, &ts)) { - if (buffer.buf) { - // a target buffer is provided, verify its format - if (buffer.readonly) { - PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be writable"); - } - else if (!PyBuffer_IsContiguous(&buffer, 'C')) { - PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be contiguous in memory"); - } - else if (((intptr_t)buffer.buf & 3) != 0) { - PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be aligned to 4 bytes boundary"); - } - else { - // ready to get the image into our buffer - try { - if (mode == NULL || !strcmp(mode, "RGBA")) - format = GL_RGBA; - else if (!strcmp(mode, "BGRA")) - format = GL_BGRA; - else - THRWEXCP(InvalidImageMode,S_OK); - - if (!self->m_image->loadImage((unsigned int *)buffer.buf, buffer.len, format, ts)) { - PyErr_SetString(PyExc_TypeError, "Could not load the buffer, perhaps size is not compatible"); - } - } - catch (Exception & exp) { - exp.report(); - } - } - PyBuffer_Release(&buffer); - if (PyErr_Occurred()) - return NULL; - } - } - else - { - return NULL; - } - 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_Size(value) != 2 || - /* XXX - this is incorrect if the sequence is not a list/tuple! */ - !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 float"); - 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 || !PyLong_Check(value)) - { - PyErr_SetString(PyExc_TypeError, "The value must be an int"); - return -1; - } - // set repeat - getVideo(self)->setRepeat(int(PyLong_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 deleted file mode 100644 index 77f46fdccd8..00000000000 --- a/source/gameengine/VideoTexture/VideoBase.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file VideoBase.h - * \ingroup bgevideotex - */ - -#ifndef __VIDEOBASE_H__ -#define __VIDEOBASE_H__ - - -#include "EXP_PyObjectPlus.h" - -#include "ImageBase.h" - -#include "Exception.h" - -// source states -const int SourceError = -1; -const int SourceEmpty = 0; -const int SourceReady = 1; -const int SourcePlaying = 2; -const int SourceStopped = 3; - - -// video source formats -enum VideoFormat { None, RGB24, YV12, RGBA32 }; - - -/// base class for video source -class VideoBase : public ImageBase -{ -public: - /// constructor - VideoBase (void) : ImageBase(true), m_format(None), m_status(SourceEmpty), - m_repeat(0), m_frameRate(1.0) - { - m_orgSize[0] = m_orgSize[1] = 0; - m_range[0] = m_range[1] = 0.0; - } - - /// destructor - virtual ~VideoBase (void) {} - - /// open video file - virtual void openFile(char *file) - { - m_isFile = true; - m_status = SourceReady; - } - /// open video capture device - virtual void openCam(char *file, short camIdx) - { - m_isFile = false; - m_status = SourceReady; - } - - /// play video - virtual bool play (void) - { - if (m_status == SourceReady || m_status == SourceStopped) - { - m_status = SourcePlaying; - return true; - } - return false; - } - /// pause video - virtual bool pause (void) - { - if (m_status == SourcePlaying) - { - m_status = SourceStopped; - return true; - } - return false; - } - /// stop 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.0f ? rate : 1.0f; } - -protected: - /// video format - VideoFormat m_format; - /// original video size - short m_orgSize[2]; - - /// video status - int m_status; - - /// is source file - bool m_isFile; - - /// replay range - double m_range[2]; - /// repeat count - int m_repeat; - /// frame rate - float m_frameRate; - - /// initialize image data - void init (short width, short height); - - /// process source data - void process (BYTE * sample); -}; - - - -// python fuctions - - -// cast Image pointer to Video -inline VideoBase *getVideo(PyImage *self) -{ return static_cast<VideoBase*>(self->m_image); } - - -extern ExceptionID SourceVideoCreation; - -// object initialization -template <class T> void Video_init(PyImage *self) -{ - // create source video object - if (self->m_image != NULL) delete self->m_image; - HRESULT hRslt = S_OK; - self->m_image = new T(&hRslt); - CHCKHRSLT(hRslt, SourceVideoCreation); -} - - -// video functions -void Video_open(VideoBase *self, char *file, short captureID); -PyObject *Video_play(PyImage *self); -PyObject *Video_pause(PyImage *self); -PyObject *Video_stop(PyImage *self); -PyObject *Video_refresh(PyImage *self, PyObject *args); -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); - -/* py api */ -extern PyTypeObject ImageRenderType; -extern PyTypeObject ImageMirrorType; -extern PyTypeObject ImageViewportType; - -#endif /* __VIDEOBASE_H__ */ diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp deleted file mode 100644 index c588a4b33cf..00000000000 --- a/source/gameengine/VideoTexture/VideoDeckLink.cpp +++ /dev/null @@ -1,1228 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2015, Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Blender Foundation. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/VideoDeckLink.cpp - * \ingroup bgevideotex - */ - -#ifdef WITH_GAMEENGINE_DECKLINK - -// FFmpeg defines its own version of stdint.h on Windows. -// Decklink needs FFmpeg, so it uses its version of stdint.h -// this is necessary for INT64_C macro -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif -// this is necessary for UINTPTR_MAX (used by atomic-ops) -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#ifdef __STDC_LIMIT_MACROS /* else it may be unused */ -#endif -#endif -#include <stdint.h> -#include <string.h> -#ifndef WIN32 -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/mman.h> -#endif - -#include "atomic_ops.h" - -#include "MEM_guardedalloc.h" -#include "PIL_time.h" -#include "VideoDeckLink.h" -#include "DeckLink.h" -#include "Exception.h" -#include "KX_KetsjiEngine.h" -#include "KX_PythonInit.h" - -extern ExceptionID DeckLinkInternalError; -ExceptionID SourceVideoOnlyCapture, VideoDeckLinkBadFormat, VideoDeckLinkOpenCard, VideoDeckLinkDvpInternalError, VideoDeckLinkPinMemoryError; -ExpDesc SourceVideoOnlyCaptureDesc(SourceVideoOnlyCapture, "This video source only allows live capture"); -ExpDesc VideoDeckLinkBadFormatDesc(VideoDeckLinkBadFormat, "Invalid or unsupported capture format, should be <mode>/<pixel>[/3D]"); -ExpDesc VideoDeckLinkOpenCardDesc(VideoDeckLinkOpenCard, "Cannot open capture card, check if driver installed"); -ExpDesc VideoDeckLinkDvpInternalErrorDesc(VideoDeckLinkDvpInternalError, "DVP API internal error, please report"); -ExpDesc VideoDeckLinkPinMemoryErrorDesc(VideoDeckLinkPinMemoryError, "Error pinning memory"); - - -#ifdef WIN32 -//////////////////////////////////////////// -// SynInfo -// -// Sets up a semaphore which is shared between the GPU and CPU and used to -// synchronise access to DVP buffers. -#define DVP_CHECK(cmd) if ((cmd) != DVP_STATUS_OK) THRWEXCP(VideoDeckLinkDvpInternalError, S_OK) - -struct SyncInfo -{ - SyncInfo(uint32_t semaphoreAllocSize, uint32_t semaphoreAddrAlignment) - { - mSemUnaligned = (uint32_t*)malloc(semaphoreAllocSize + semaphoreAddrAlignment - 1); - - // Apply alignment constraints - uint64_t val = (uint64_t)mSemUnaligned; - val += semaphoreAddrAlignment - 1; - val &= ~((uint64_t)semaphoreAddrAlignment - 1); - mSem = (uint32_t*)val; - - // Initialise - mSem[0] = 0; - mReleaseValue = 0; - mAcquireValue = 0; - - // Setup DVP sync object and import it - DVPSyncObjectDesc syncObjectDesc; - syncObjectDesc.externalClientWaitFunc = NULL; - syncObjectDesc.sem = (uint32_t*)mSem; - - DVP_CHECK(dvpImportSyncObject(&syncObjectDesc, &mDvpSync)); - - } - ~SyncInfo() - { - dvpFreeSyncObject(mDvpSync); - free((void*)mSemUnaligned); - } - - volatile uint32_t* mSem; - volatile uint32_t* mSemUnaligned; - volatile uint32_t mReleaseValue; - volatile uint32_t mAcquireValue; - DVPSyncObjectHandle mDvpSync; -}; - -//////////////////////////////////////////// -// TextureTransferDvp: transfer with GPUDirect -//////////////////////////////////////////// - -class TextureTransferDvp : public TextureTransfer -{ -public: - TextureTransferDvp(DVPBufferHandle dvpTextureHandle, TextureDesc *pDesc, void *address, uint32_t allocatedSize) - { - DVPSysmemBufferDesc sysMemBuffersDesc; - - mExtSync = NULL; - mGpuSync = NULL; - mDvpSysMemHandle = 0; - mDvpTextureHandle = 0; - mTextureHeight = 0; - mAllocatedSize = 0; - mBuffer = NULL; - - if (!_PinBuffer(address, allocatedSize)) - THRWEXCP(VideoDeckLinkPinMemoryError, S_OK); - mAllocatedSize = allocatedSize; - mBuffer = address; - - try { - if (!mBufferAddrAlignment) { - DVP_CHECK(dvpGetRequiredConstantsGLCtx(&mBufferAddrAlignment, &mBufferGpuStrideAlignment, - &mSemaphoreAddrAlignment, &mSemaphoreAllocSize, - &mSemaphorePayloadOffset, &mSemaphorePayloadSize)); - } - mExtSync = new SyncInfo(mSemaphoreAllocSize, mSemaphoreAddrAlignment); - mGpuSync = new SyncInfo(mSemaphoreAllocSize, mSemaphoreAddrAlignment); - sysMemBuffersDesc.width = pDesc->width; - sysMemBuffersDesc.height = pDesc->height; - sysMemBuffersDesc.stride = pDesc->stride; - switch (pDesc->format) { - case GL_RED_INTEGER: - sysMemBuffersDesc.format = DVP_RED_INTEGER; - break; - default: - sysMemBuffersDesc.format = DVP_BGRA; - break; - } - switch (pDesc->type) { - case GL_UNSIGNED_BYTE: - sysMemBuffersDesc.type = DVP_UNSIGNED_BYTE; - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - sysMemBuffersDesc.type = DVP_UNSIGNED_INT_2_10_10_10_REV; - break; - case GL_UNSIGNED_INT_8_8_8_8: - sysMemBuffersDesc.type = DVP_UNSIGNED_INT_8_8_8_8; - break; - case GL_UNSIGNED_INT_10_10_10_2: - sysMemBuffersDesc.type = DVP_UNSIGNED_INT_10_10_10_2; - break; - default: - sysMemBuffersDesc.type = DVP_UNSIGNED_INT; - break; - } - sysMemBuffersDesc.size = pDesc->width * pDesc->height * 4; - sysMemBuffersDesc.bufAddr = mBuffer; - DVP_CHECK(dvpCreateBuffer(&sysMemBuffersDesc, &mDvpSysMemHandle)); - DVP_CHECK(dvpBindToGLCtx(mDvpSysMemHandle)); - mDvpTextureHandle = dvpTextureHandle; - mTextureHeight = pDesc->height; - } - catch (Exception &) { - clean(); - throw; - } - } - ~TextureTransferDvp() - { - clean(); - } - - virtual void PerformTransfer() - { - // perform the transfer - // tell DVP that the old texture buffer will no longer be used - dvpMapBufferEndAPI(mDvpTextureHandle); - // do we need this? - mGpuSync->mReleaseValue++; - dvpBegin(); - // Copy from system memory to GPU texture - dvpMapBufferWaitDVP(mDvpTextureHandle); - dvpMemcpyLined(mDvpSysMemHandle, mExtSync->mDvpSync, mExtSync->mAcquireValue, DVP_TIMEOUT_IGNORED, - mDvpTextureHandle, mGpuSync->mDvpSync, mGpuSync->mReleaseValue, 0, mTextureHeight); - dvpMapBufferEndDVP(mDvpTextureHandle); - dvpEnd(); - dvpMapBufferWaitAPI(mDvpTextureHandle); - // the transfer is now complete and the texture is ready for use - } - -private: - static uint32_t mBufferAddrAlignment; - static uint32_t mBufferGpuStrideAlignment; - static uint32_t mSemaphoreAddrAlignment; - static uint32_t mSemaphoreAllocSize; - static uint32_t mSemaphorePayloadOffset; - static uint32_t mSemaphorePayloadSize; - - void clean() - { - if (mDvpSysMemHandle) { - dvpUnbindFromGLCtx(mDvpSysMemHandle); - dvpDestroyBuffer(mDvpSysMemHandle); - } - if (mExtSync) - delete mExtSync; - if (mGpuSync) - delete mGpuSync; - if (mBuffer) - _UnpinBuffer(mBuffer, mAllocatedSize); - } - SyncInfo* mExtSync; - SyncInfo* mGpuSync; - DVPBufferHandle mDvpSysMemHandle; - DVPBufferHandle mDvpTextureHandle; - uint32_t mTextureHeight; - uint32_t mAllocatedSize; - void* mBuffer; -}; - -uint32_t TextureTransferDvp::mBufferAddrAlignment; -uint32_t TextureTransferDvp::mBufferGpuStrideAlignment; -uint32_t TextureTransferDvp::mSemaphoreAddrAlignment; -uint32_t TextureTransferDvp::mSemaphoreAllocSize; -uint32_t TextureTransferDvp::mSemaphorePayloadOffset; -uint32_t TextureTransferDvp::mSemaphorePayloadSize; - -#endif - -//////////////////////////////////////////// -// TextureTransferOGL: transfer using standard OGL buffers -//////////////////////////////////////////// - -class TextureTransferOGL : public TextureTransfer -{ -public: - TextureTransferOGL(GLuint texId, TextureDesc *pDesc, void *address) - { - memcpy(&mDesc, pDesc, sizeof(mDesc)); - mTexId = texId; - mBuffer = address; - - // as we cache transfer object, we will create one texture to hold the buffer - glGenBuffers(1, &mUnpinnedTextureBuffer); - // create a storage for it - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer); - glBufferData(GL_PIXEL_UNPACK_BUFFER, pDesc->size, NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } - ~TextureTransferOGL() - { - glDeleteBuffers(1, &mUnpinnedTextureBuffer); - } - - virtual void PerformTransfer() - { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer); - glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, mDesc.size, mBuffer); - glBindTexture(GL_TEXTURE_2D, mTexId); - // NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } -private: - // intermediate texture to receive the buffer - GLuint mUnpinnedTextureBuffer; - // target texture to receive the image - GLuint mTexId; - // buffer - void *mBuffer; - // characteristic of the image - TextureDesc mDesc; -}; - -//////////////////////////////////////////// -// TextureTransferPMB: transfer using pinned memory buffer -//////////////////////////////////////////// - -class TextureTransferPMD : public TextureTransfer -{ -public: - TextureTransferPMD(GLuint texId, TextureDesc *pDesc, void *address, uint32_t allocatedSize) - { - memcpy(&mDesc, pDesc, sizeof(mDesc)); - mTexId = texId; - mBuffer = address; - mAllocatedSize = allocatedSize; - - _PinBuffer(address, allocatedSize); - - // as we cache transfer object, we will create one texture to hold the buffer - glGenBuffers(1, &mPinnedTextureBuffer); - // create a storage for it - glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, mPinnedTextureBuffer); - glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, pDesc->size, address, GL_STREAM_DRAW); - glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0); - } - ~TextureTransferPMD() - { - glDeleteBuffers(1, &mPinnedTextureBuffer); - if (mBuffer) - _UnpinBuffer(mBuffer, mAllocatedSize); - } - - virtual void PerformTransfer() - { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPinnedTextureBuffer); - glBindTexture(GL_TEXTURE_2D, mTexId); - // NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL); - // wait for the trasnfer to complete - GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 40 * 1000 * 1000); // timeout in nanosec - glDeleteSync(fence); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } -private: - // intermediate texture to receive the buffer - GLuint mPinnedTextureBuffer; - // target texture to receive the image - GLuint mTexId; - // buffer - void *mBuffer; - // the allocated size - uint32_t mAllocatedSize; - // characteristic of the image - TextureDesc mDesc; -}; - -bool TextureTransfer::_PinBuffer(void *address, uint32_t size) -{ -#ifdef WIN32 - return VirtualLock(address, size); -#elif defined(_POSIX_MEMLOCK_RANGE) - return !mlock(address, size); -#endif -} - -void TextureTransfer::_UnpinBuffer(void* address, uint32_t size) -{ -#ifdef WIN32 - VirtualUnlock(address, size); -#elif defined(_POSIX_MEMLOCK_RANGE) - munlock(address, size); -#endif -} - - - -//////////////////////////////////////////// -// PinnedMemoryAllocator -//////////////////////////////////////////// - - -// static members -bool PinnedMemoryAllocator::mGPUDirectInitialized = false; -bool PinnedMemoryAllocator::mHasDvp = false; -bool PinnedMemoryAllocator::mHasAMDPinnedMemory = false; -size_t PinnedMemoryAllocator::mReservedProcessMemory = 0; - -bool PinnedMemoryAllocator::ReserveMemory(size_t size) -{ -#ifdef WIN32 - // Increase the process working set size to allow pinning of memory. - if (size <= mReservedProcessMemory) - return true; - SIZE_T dwMin = 0, dwMax = 0; - HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SET_QUOTA, FALSE, GetCurrentProcessId()); - if (!hProcess) - return false; - - // Retrieve the working set size of the process. - if (!dwMin && !GetProcessWorkingSetSize(hProcess, &dwMin, &dwMax)) - return false; - - BOOL res = SetProcessWorkingSetSize(hProcess, (size - mReservedProcessMemory) + dwMin, (size - mReservedProcessMemory) + dwMax); - if (!res) - return false; - mReservedProcessMemory = size; - CloseHandle(hProcess); - return true; -#else - struct rlimit rlim; - if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) { - if (rlim.rlim_cur < size) { - if (rlim.rlim_max < size) - rlim.rlim_max = size; - rlim.rlim_cur = size; - return !setrlimit(RLIMIT_MEMLOCK, &rlim); - } - } - return false; -#endif -} - -PinnedMemoryAllocator::PinnedMemoryAllocator(unsigned cacheSize, size_t memSize) : -mRefCount(1U), -#ifdef WIN32 -mDvpCaptureTextureHandle(0), -#endif -mTexId(0), -mBufferCacheSize(cacheSize) -{ - pthread_mutex_init(&mMutex, NULL); - // do it once - if (!mGPUDirectInitialized) { -#ifdef WIN32 - // In windows, AMD_pinned_memory option is not available, - // we must use special DVP API only available for Quadro cards - const char* renderer = (const char *)glGetString(GL_RENDERER); - mHasDvp = (strstr(renderer, "Quadro") != NULL); - - if (mHasDvp) { - // In case the DLL is not in place, don't fail, just fallback on OpenGL - if (dvpInitGLContext(DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT) != DVP_STATUS_OK) { - printf("Warning: Could not initialize DVP context, fallback on OpenGL transfer.\nInstall dvp.dll to take advantage of nVidia GPUDirect.\n"); - mHasDvp = false; - } - } -#endif - if (GLEW_AMD_pinned_memory) - mHasAMDPinnedMemory = true; - - mGPUDirectInitialized = true; - } - if (mHasDvp || mHasAMDPinnedMemory) { - ReserveMemory(memSize); - } -} - -PinnedMemoryAllocator::~PinnedMemoryAllocator() -{ - void *address; - // first clean the cache if not already done - while (!mBufferCache.empty()) { - address = mBufferCache.back(); - mBufferCache.pop_back(); - _ReleaseBuffer(address); - } - // clean preallocated buffers - while (!mAllocatedSize.empty()) { - address = mAllocatedSize.begin()->first; - _ReleaseBuffer(address); - } - -#ifdef WIN32 - if (mDvpCaptureTextureHandle) - dvpDestroyBuffer(mDvpCaptureTextureHandle); -#endif -} - -void PinnedMemoryAllocator::TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId) -{ - uint32_t allocatedSize = 0; - TextureTransfer *pTransfer = NULL; - - Lock(); - if (mAllocatedSize.count(address) > 0) - allocatedSize = mAllocatedSize[address]; - Unlock(); - if (!allocatedSize) - // internal error!! - return; - if (mTexId != texId) - { - // first time we try to send data to the GPU, allocate a buffer for the texture - glBindTexture(GL_TEXTURE_2D, texId); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexImage2D(GL_TEXTURE_2D, 0, texDesc->internalFormat, texDesc->width, texDesc->height, 0, texDesc->format, texDesc->type, NULL); - glBindTexture(GL_TEXTURE_2D, 0); - mTexId = texId; - } -#ifdef WIN32 - if (mHasDvp) - { - if (!mDvpCaptureTextureHandle) - { - // bind DVP to the OGL texture - DVP_CHECK(dvpCreateGPUTextureGL(texId, &mDvpCaptureTextureHandle)); - } - } -#endif - Lock(); - if (mPinnedBuffer.count(address) > 0) - { - pTransfer = mPinnedBuffer[address]; - } - Unlock(); - if (!pTransfer) - { -#ifdef WIN32 - if (mHasDvp) - pTransfer = new TextureTransferDvp(mDvpCaptureTextureHandle, texDesc, address, allocatedSize); - else -#endif - if (mHasAMDPinnedMemory) { - pTransfer = new TextureTransferPMD(texId, texDesc, address, allocatedSize); - } - else { - pTransfer = new TextureTransferOGL(texId, texDesc, address); - } - if (pTransfer) - { - Lock(); - mPinnedBuffer[address] = pTransfer; - Unlock(); - } - } - if (pTransfer) - pTransfer->PerformTransfer(); -} - -// IUnknown methods -HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/, LPVOID* /*ppv*/) -{ - return E_NOTIMPL; -} - -ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void) -{ - return atomic_add_and_fetch_uint32(&mRefCount, 1U); -} - -ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void) -{ - uint32_t newCount = atomic_sub_and_fetch_uint32(&mRefCount, 1U); - if (newCount == 0) - delete this; - return (ULONG)newCount; -} - -// IDeckLinkMemoryAllocator methods -HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::AllocateBuffer(dl_size_t bufferSize, void* *allocatedBuffer) -{ - Lock(); - if (mBufferCache.empty()) - { - // Allocate memory on a page boundary - // Note: aligned alloc exist in Blender but only for small alignment, use direct allocation then. - // Note: the DeckLink API tries to allocate up to 65 buffer in advance, we will limit this to 3 - // because we don't need any caching - if (mAllocatedSize.size() >= mBufferCacheSize) - *allocatedBuffer = NULL; - else { -#ifdef WIN32 - *allocatedBuffer = VirtualAlloc(NULL, bufferSize, MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE); -#else - if (posix_memalign(allocatedBuffer, 4096, bufferSize) != 0) - *allocatedBuffer = NULL; -#endif - mAllocatedSize[*allocatedBuffer] = bufferSize; - } - } - else { - // Re-use most recently ReleaseBuffer'd address - *allocatedBuffer = mBufferCache.back(); - mBufferCache.pop_back(); - } - Unlock(); - return (*allocatedBuffer) ? S_OK : E_OUTOFMEMORY; -} - -HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::ReleaseBuffer(void* buffer) -{ - HRESULT result = S_OK; - Lock(); - if (mBufferCache.size() < mBufferCacheSize) { - mBufferCache.push_back(buffer); - } - else { - result = _ReleaseBuffer(buffer); - } - Unlock(); - return result; -} - - -HRESULT PinnedMemoryAllocator::_ReleaseBuffer(void* buffer) -{ - TextureTransfer *pTransfer; - if (mAllocatedSize.count(buffer) == 0) { - // Internal error!! - return S_OK; - } - else { - // No room left in cache, so un-pin (if it was pinned) and free this buffer - if (mPinnedBuffer.count(buffer) > 0) { - pTransfer = mPinnedBuffer[buffer]; - mPinnedBuffer.erase(buffer); - delete pTransfer; - } -#ifdef WIN32 - VirtualFree(buffer, 0, MEM_RELEASE); -#else - free(buffer); -#endif - mAllocatedSize.erase(buffer); - } - return S_OK; -} - -HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::Commit() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::Decommit() -{ - void *buffer; - Lock(); - while (!mBufferCache.empty()) { - // Cleanup any frames allocated and pinned in AllocateBuffer() but not freed in ReleaseBuffer() - buffer = mBufferCache.back(); - mBufferCache.pop_back(); - _ReleaseBuffer(buffer); - } - Unlock(); - return S_OK; -} - - -//////////////////////////////////////////// -// Capture Delegate Class -//////////////////////////////////////////// - -CaptureDelegate::CaptureDelegate(VideoDeckLink* pOwner) : mpOwner(pOwner) -{ -} - -HRESULT CaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* inputFrame, IDeckLinkAudioInputPacket* /*audioPacket*/) -{ - if (!inputFrame) { - // It's possible to receive a NULL inputFrame, but a valid audioPacket. Ignore audio-only frame. - return S_OK; - } - if ((inputFrame->GetFlags() & bmdFrameHasNoInputSource) == bmdFrameHasNoInputSource) { - // let's not bother transferring frames if there is no source - return S_OK; - } - mpOwner->VideoFrameArrived(inputFrame); - return S_OK; -} - -HRESULT CaptureDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags) -{ - return S_OK; -} - - - - -// macro for exception handling and logging -#define CATCH_EXCP catch (Exception & exp) \ -{ exp.report(); m_status = SourceError; } - -// class VideoDeckLink - - -// constructor -VideoDeckLink::VideoDeckLink (HRESULT * hRslt) : VideoBase(), -mDLInput(NULL), -mUse3D(false), -mFrameWidth(0), -mFrameHeight(0), -mpAllocator(NULL), -mpCaptureDelegate(NULL), -mpCacheFrame(NULL), -mClosing(false) -{ - mDisplayMode = (BMDDisplayMode)0; - mPixelFormat = (BMDPixelFormat)0; - pthread_mutex_init(&mCacheMutex, NULL); -} - -// destructor -VideoDeckLink::~VideoDeckLink () -{ - LockCache(); - mClosing = true; - if (mpCacheFrame) - { - mpCacheFrame->Release(); - mpCacheFrame = NULL; - } - UnlockCache(); - if (mDLInput != NULL) - { - // Cleanup for Capture - mDLInput->StopStreams(); - mDLInput->SetCallback(NULL); - mDLInput->DisableVideoInput(); - mDLInput->DisableAudioInput(); - mDLInput->FlushStreams(); - if (mDLInput->Release() != 0) { - printf("Reference count not NULL on DeckLink device when closing it, please report!\n"); - } - mDLInput = NULL; - } - - if (mpAllocator) - { - // if the device was properly cleared, this should be 0 - if (mpAllocator->Release() != 0) { - printf("Reference count not NULL on Allocator when closing it, please report!\n"); - } - mpAllocator = NULL; - } - if (mpCaptureDelegate) - { - delete mpCaptureDelegate; - mpCaptureDelegate = NULL; - } -} - -void VideoDeckLink::refresh(void) -{ - m_avail = false; -} - -// release components -bool VideoDeckLink::release() -{ - // release - return true; -} - -// open video file -void VideoDeckLink::openFile (char *filename) -{ - // only live capture on this device - THRWEXCP(SourceVideoOnlyCapture, S_OK); -} - - -// open video capture device -void VideoDeckLink::openCam (char *format, short camIdx) -{ - IDeckLinkDisplayModeIterator* pDLDisplayModeIterator; - BMDDisplayModeSupport modeSupport; - IDeckLinkDisplayMode* pDLDisplayMode; - IDeckLinkIterator* pIterator; - BMDTimeValue frameDuration; - BMDTimeScale frameTimescale; - IDeckLink* pDL; - uint32_t displayFlags, inputFlags; - char *pPixel, *p3D, *pEnd, *pSize; - size_t len; - int i, modeIdx, cacheSize; - - // format is constructed as <displayMode>/<pixelFormat>[/3D][:<cacheSize>] - // <displayMode> takes the form of BMDDisplayMode identifier minus the 'bmdMode' prefix. - // This implementation understands all the modes defined in SDK 10.3.1 but you can alternatively - // use the 4 characters internal representation of the mode (e.g. 'HD1080p24' == '24ps') - // <pixelFormat> takes the form of BMDPixelFormat identifier minus the 'bmdFormat' prefix. - // This implementation understand all the formats defined in SDK 10.32.1 but you can alternatively - // use the 4 characters internal representation of the format (e.g. '10BitRGB' == 'r210') - // Not all combinations of mode and pixel format are possible and it also depends on the card! - // Use /3D postfix if you are capturing a 3D stream with frame packing - // Example: To capture FullHD 1920x1080@24Hz with 3D packing and 4:4:4 10 bits RGB pixel format, use - // "HD1080p24/10BitRGB/3D" (same as "24ps/r210/3D") - // (this will be the normal capture format for FullHD on the DeckLink 4k extreme) - - if ((pSize = strchr(format, ':')) != NULL) { - cacheSize = strtol(pSize+1, &pEnd, 10); - } - else { - cacheSize = 8; - pSize = format + strlen(format); - } - if ((pPixel = strchr(format, '/')) == NULL || - ((p3D = strchr(pPixel + 1, '/')) != NULL && strncmp(p3D, "/3D", pSize-p3D))) - THRWEXCP(VideoDeckLinkBadFormat, S_OK); - mUse3D = (p3D) ? true : false; - // to simplify pixel format parsing - if (!p3D) - p3D = pSize; - - // read the mode - len = (size_t)(pPixel - format); - // accept integer display mode - - try { - // throws if bad mode - decklink_ReadDisplayMode(format, len, &mDisplayMode); - // found a valid mode, remember that we do not look for an index - modeIdx = -1; - } - catch (Exception &) { - // accept also purely numerical mode as a mode index - modeIdx = strtol(format, &pEnd, 10); - if (pEnd != pPixel || modeIdx < 0) - // not a pure number, give up - throw; - } - - // skip / - pPixel++; - len = (size_t)(p3D - pPixel); - // throws if bad format - decklink_ReadPixelFormat(pPixel, len, &mPixelFormat); - - // Caution: DeckLink API used from this point, make sure entity are released before throwing - // open the card - pIterator = BMD_CreateDeckLinkIterator(); - if (pIterator) { - i = 0; - while (pIterator->Next(&pDL) == S_OK) { - if (i == camIdx) { - if (pDL->QueryInterface(IID_IDeckLinkInput, (void**)&mDLInput) != S_OK) - mDLInput = NULL; - pDL->Release(); - break; - } - i++; - pDL->Release(); - } - pIterator->Release(); - } - if (!mDLInput) - THRWEXCP(VideoDeckLinkOpenCard, S_OK); - - - // check if display mode and pixel format are supported - if (mDLInput->GetDisplayModeIterator(&pDLDisplayModeIterator) != S_OK) - THRWEXCP(DeckLinkInternalError, S_OK); - - pDLDisplayMode = NULL; - displayFlags = (mUse3D) ? bmdDisplayModeSupports3D : 0; - inputFlags = (mUse3D) ? bmdVideoInputDualStream3D : bmdVideoInputFlagDefault; - while (pDLDisplayModeIterator->Next(&pDLDisplayMode) == S_OK) - { - if (modeIdx == 0 || pDLDisplayMode->GetDisplayMode() == mDisplayMode) { - // in case we get here because of modeIdx, make sure we have mDisplayMode set - mDisplayMode = pDLDisplayMode->GetDisplayMode(); - if ((pDLDisplayMode->GetFlags() & displayFlags) == displayFlags && - mDLInput->DoesSupportVideoMode(mDisplayMode, mPixelFormat, inputFlags, &modeSupport, NULL) == S_OK && - modeSupport == bmdDisplayModeSupported) - { - break; - } - } - pDLDisplayMode->Release(); - pDLDisplayMode = NULL; - if (modeIdx-- == 0) { - // reached the correct mode index but it does not meet the pixel format, give up - break; - } - } - pDLDisplayModeIterator->Release(); - - if (pDLDisplayMode == NULL) - THRWEXCP(VideoDeckLinkBadFormat, S_OK); - - mFrameWidth = pDLDisplayMode->GetWidth(); - mFrameHeight = pDLDisplayMode->GetHeight(); - mTextureDesc.height = (mUse3D) ? 2 * mFrameHeight : mFrameHeight; - pDLDisplayMode->GetFrameRate(&frameDuration, &frameTimescale); - pDLDisplayMode->Release(); - // for information, in case the application wants to know - m_size[0] = mFrameWidth; - m_size[1] = mTextureDesc.height; - m_frameRate = (float)frameTimescale / (float)frameDuration; - - switch (mPixelFormat) - { - case bmdFormat8BitYUV: - // 2 pixels per word - mTextureDesc.stride = mFrameWidth * 2; - mTextureDesc.width = mFrameWidth / 2; - mTextureDesc.internalFormat = GL_RGBA; - mTextureDesc.format = GL_BGRA; - mTextureDesc.type = GL_UNSIGNED_BYTE; - break; - case bmdFormat10BitYUV: - // 6 pixels in 4 words, rounded to 48 pixels - mTextureDesc.stride = ((mFrameWidth + 47) / 48) * 128; - mTextureDesc.width = mTextureDesc.stride/4; - mTextureDesc.internalFormat = GL_RGB10_A2; - mTextureDesc.format = GL_BGRA; - mTextureDesc.type = GL_UNSIGNED_INT_2_10_10_10_REV; - break; - case bmdFormat8BitARGB: - mTextureDesc.stride = mFrameWidth * 4; - mTextureDesc.width = mFrameWidth; - mTextureDesc.internalFormat = GL_RGBA; - mTextureDesc.format = GL_BGRA; - mTextureDesc.type = GL_UNSIGNED_INT_8_8_8_8; - break; - case bmdFormat8BitBGRA: - mTextureDesc.stride = mFrameWidth * 4; - mTextureDesc.width = mFrameWidth; - mTextureDesc.internalFormat = GL_RGBA; - mTextureDesc.format = GL_BGRA; - mTextureDesc.type = GL_UNSIGNED_BYTE; - break; - case bmdFormat10BitRGBXLE: - // 1 pixel per word, rounded to 64 pixels - mTextureDesc.stride = ((mFrameWidth + 63) / 64) * 256; - mTextureDesc.width = mTextureDesc.stride/4; - mTextureDesc.internalFormat = GL_RGB10_A2; - mTextureDesc.format = GL_RGBA; - mTextureDesc.type = GL_UNSIGNED_INT_10_10_10_2; - break; - case bmdFormat10BitRGBX: - case bmdFormat10BitRGB: - // 1 pixel per word, rounded to 64 pixels - mTextureDesc.stride = ((mFrameWidth + 63) / 64) * 256; - mTextureDesc.width = mTextureDesc.stride/4; - mTextureDesc.internalFormat = GL_R32UI; - mTextureDesc.format = GL_RED_INTEGER; - mTextureDesc.type = GL_UNSIGNED_INT; - break; - case bmdFormat12BitRGB: - case bmdFormat12BitRGBLE: - // 8 pixels in 9 word - mTextureDesc.stride = (mFrameWidth * 36) / 8; - mTextureDesc.width = mTextureDesc.stride/4; - mTextureDesc.internalFormat = GL_R32UI; - mTextureDesc.format = GL_RED_INTEGER; - mTextureDesc.type = GL_UNSIGNED_INT; - break; - default: - // for unknown pixel format, this will be resolved when a frame arrives - mTextureDesc.format = GL_RED_INTEGER; - mTextureDesc.type = GL_UNSIGNED_INT; - break; - } - // reserve memory for cache frame + 1 to accomodate for pixel format that we don't know yet - // note: we can't use stride as it is not yet known if the pixel format is unknown - // use instead the frame width as in worst case it's not much different (e.g. HD720/10BITYUV: 1296 pixels versus 1280) - // note: some pixel format take more than 4 bytes take that into account (9/8 versus 1) - mpAllocator = new PinnedMemoryAllocator(cacheSize, mFrameWidth*mTextureDesc.height * 4 * (1+cacheSize*9/8)); - - if (mDLInput->SetVideoInputFrameMemoryAllocator(mpAllocator) != S_OK) - THRWEXCP(DeckLinkInternalError, S_OK); - - mpCaptureDelegate = new CaptureDelegate(this); - if (mDLInput->SetCallback(mpCaptureDelegate) != S_OK) - THRWEXCP(DeckLinkInternalError, S_OK); - - if (mDLInput->EnableVideoInput(mDisplayMode, mPixelFormat, ((mUse3D) ? bmdVideoInputDualStream3D : bmdVideoInputFlagDefault)) != S_OK) - // this shouldn't failed, we tested above - THRWEXCP(DeckLinkInternalError, S_OK); - - // just in case it is needed to capture from certain cards, we don't check error because we don't need audio - mDLInput->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2); - - // open base class - VideoBase::openCam(format, camIdx); - - // ready to capture, will start when application calls play() -} - -// play video -bool VideoDeckLink::play (void) -{ - try - { - // if object is able to play - if (VideoBase::play()) - { - mDLInput->FlushStreams(); - return (mDLInput->StartStreams() == S_OK); - } - } - CATCH_EXCP; - return false; -} - - -// pause video -bool VideoDeckLink::pause (void) -{ - try - { - if (VideoBase::pause()) - { - mDLInput->PauseStreams(); - return true; - } - } - CATCH_EXCP; - return false; -} - -// stop video -bool VideoDeckLink::stop (void) -{ - try - { - VideoBase::stop(); - mDLInput->StopStreams(); - return true; - } - CATCH_EXCP; - return false; -} - - -// set video range -void VideoDeckLink::setRange (double start, double stop) -{ -} - -// set framerate -void VideoDeckLink::setFrameRate (float rate) -{ -} - - -// image calculation -// send cache frame directly to GPU -void VideoDeckLink::calcImage (unsigned int texId, double ts) -{ - IDeckLinkVideoInputFrame* pFrame; - LockCache(); - pFrame = mpCacheFrame; - mpCacheFrame = NULL; - UnlockCache(); - if (pFrame) { - // BUG: the dvpBindToGLCtx function fails the first time it is used, don't know why. - // This causes an exception to be thrown. - // This should be fixed but in the meantime we will catch the exception because - // it is crucial that we release the frame to keep the reference count right on the DeckLink device - try { - uint32_t rowSize = pFrame->GetRowBytes(); - uint32_t textureSize = rowSize * pFrame->GetHeight(); - void* videoPixels = NULL; - void* rightEyePixels = NULL; - if (!mTextureDesc.stride) { - // we could not compute the texture size earlier (unknown pixel size) - // let's do it now - mTextureDesc.stride = rowSize; - mTextureDesc.width = mTextureDesc.stride / 4; - } - if (mTextureDesc.stride != rowSize) { - // unexpected frame size, ignore - // TBD: print a warning - } - else { - pFrame->GetBytes(&videoPixels); - if (mUse3D) { - IDeckLinkVideoFrame3DExtensions *if3DExtensions = NULL; - IDeckLinkVideoFrame *rightEyeFrame = NULL; - if (pFrame->QueryInterface(IID_IDeckLinkVideoFrame3DExtensions, (void **)&if3DExtensions) == S_OK && - if3DExtensions->GetFrameForRightEye(&rightEyeFrame) == S_OK) { - rightEyeFrame->GetBytes(&rightEyePixels); - textureSize += ((uint64_t)rightEyePixels - (uint64_t)videoPixels); - } - if (rightEyeFrame) - rightEyeFrame->Release(); - if (if3DExtensions) - if3DExtensions->Release(); - } - mTextureDesc.size = mTextureDesc.width * mTextureDesc.height * 4; - if (mTextureDesc.size == textureSize) { - // this means that both left and right frame are contiguous and that there is no padding - // do the transfer - mpAllocator->TransferBuffer(videoPixels, &mTextureDesc, texId); - } - } - } - catch (Exception &) { - pFrame->Release(); - throw; - } - // this will trigger PinnedMemoryAllocator::RealaseBuffer - pFrame->Release(); - } - // currently we don't pass the image to the application - m_avail = false; -} - -// A frame is available from the board -// Called from an internal thread, just pass the frame to the main thread -void VideoDeckLink::VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame) -{ - IDeckLinkVideoInputFrame* pOldFrame = NULL; - LockCache(); - if (!mClosing) - { - pOldFrame = mpCacheFrame; - mpCacheFrame = inputFrame; - inputFrame->AddRef(); - } - UnlockCache(); - // old frame no longer needed, just release it - if (pOldFrame) - pOldFrame->Release(); -} - -// python methods - -// object initialization -static int VideoDeckLink_init(PyObject *pySelf, PyObject *args, PyObject *kwds) -{ - static const char *kwlist[] = { "format", "capture", NULL }; - PyImage *self = reinterpret_cast<PyImage*>(pySelf); - // see openCam for a description of format - char * format = NULL; - // capture device number, i.e. DeckLink card number, default first one - short capt = 0; - - if (!GLEW_VERSION_1_5) { - PyErr_SetString(PyExc_RuntimeError, "VideoDeckLink requires at least OpenGL 1.5"); - return -1; - } - // get parameters - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|h", - const_cast<char**>(kwlist), &format, &capt)) - return -1; - - try { - // create video object - Video_init<VideoDeckLink>(self); - - // open video source, control comes back to VideoDeckLink::openCam - Video_open(getVideo(self), format, capt); - } - catch (Exception & exp) { - exp.report(); - return -1; - } - // initialization succeded - return 0; -} - -// methods structure -static PyMethodDef videoMethods[] = -{ // methods from VideoBase class - {"play", (PyCFunction)Video_play, METH_NOARGS, "Play (restart) video"}, - {"pause", (PyCFunction)Video_pause, METH_NOARGS, "pause video"}, - {"stop", (PyCFunction)Video_stop, METH_NOARGS, "stop video (play will replay it from start)"}, - {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh video - get its status"}, - {NULL} -}; -// attributes structure -static PyGetSetDef videoGetSets[] = -{ // methods from VideoBase class - {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL}, - {(char*)"framerate", (getter)Video_getFrameRate, NULL, (char*)"frame rate", NULL}, - // attributes from ImageBase class - {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, - {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, - {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, - {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL}, - {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, - {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, - {NULL} -}; - -// python type declaration -PyTypeObject VideoDeckLinkType = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.VideoDeckLink", /*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*/ - &imageBufferProcs, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "DeckLink 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)VideoDeckLink_init, /* tp_init */ - 0, /* tp_alloc */ - Image_allocNew, /* tp_new */ -}; - - - -//////////////////////////////////////////// -// DeckLink Capture Delegate Class -//////////////////////////////////////////// - -#endif // WITH_GAMEENGINE_DECKLINK - diff --git a/source/gameengine/VideoTexture/VideoDeckLink.h b/source/gameengine/VideoTexture/VideoDeckLink.h deleted file mode 100644 index d5419176691..00000000000 --- a/source/gameengine/VideoTexture/VideoDeckLink.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2015, Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Blender Foundation. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file VideoDeckLink.h - * \ingroup bgevideotex - */ - -#ifndef __VIDEODECKLINK_H__ -#define __VIDEODECKLINK_H__ - -#ifdef WITH_GAMEENGINE_DECKLINK - -/* this needs to be parsed with __cplusplus defined before included through DeckLink_compat.h */ -#if defined(__FreeBSD__) -# include <inttypes.h> -#endif -#include <map> -#include <set> - -extern "C" { -#include <pthread.h> -#include "DNA_listBase.h" -#include "BLI_threads.h" -#include "BLI_blenlib.h" -} -#include "GPU_glew.h" -#ifdef WIN32 -#include "dvpapi.h" -#endif -#include "DeckLinkAPI.h" -#include "VideoBase.h" - -class PinnedMemoryAllocator; - -struct TextureDesc -{ - uint32_t width; - uint32_t height; - uint32_t stride; - uint32_t size; - GLenum internalFormat; - GLenum format; - GLenum type; - TextureDesc() - { - width = 0; - height = 0; - stride = 0; - size = 0; - internalFormat = 0; - format = 0; - type = 0; - } -}; - -class CaptureDelegate; - -// type VideoDeckLink declaration -class VideoDeckLink : public VideoBase -{ - friend class CaptureDelegate; -public: - /// constructor - VideoDeckLink (HRESULT * hRslt); - /// destructor - virtual ~VideoDeckLink (); - - /// open video/image file - virtual void openFile(char *file); - /// open video capture device - virtual void openCam(char *driver, short camIdx); - - /// release video source - virtual bool release (void); - /// overwrite base refresh to handle fixed image - virtual void refresh(void); - /// play video - virtual bool play (void); - /// pause video - virtual bool pause (void); - /// stop video - virtual bool stop (void); - /// set play range - virtual void setRange (double start, double stop); - /// set frame rate - virtual void setFrameRate (float rate); - -protected: - // format and codec information - /// image calculation - virtual void calcImage (unsigned int texId, double ts); - -private: - void VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame); - void LockCache() - { - pthread_mutex_lock(&mCacheMutex); - } - void UnlockCache() - { - pthread_mutex_unlock(&mCacheMutex); - } - - IDeckLinkInput* mDLInput; - BMDDisplayMode mDisplayMode; - BMDPixelFormat mPixelFormat; - bool mUse3D; - uint32_t mFrameWidth; - uint32_t mFrameHeight; - TextureDesc mTextureDesc; - PinnedMemoryAllocator* mpAllocator; - CaptureDelegate* mpCaptureDelegate; - - // cache frame in transit between the callback thread and the main BGE thread - // keep only one frame in cache because we just want to keep up with real time - pthread_mutex_t mCacheMutex; - IDeckLinkVideoInputFrame* mpCacheFrame; - bool mClosing; - -}; - -inline VideoDeckLink *getDeckLink(PyImage *self) -{ - return static_cast<VideoDeckLink*>(self->m_image); -} - -//////////////////////////////////////////// -// TextureTransfer : Abstract class to perform a transfer to GPU memory using fast transfer if available -//////////////////////////////////////////// -class TextureTransfer -{ -public: - TextureTransfer() {} - virtual ~TextureTransfer() { } - - virtual void PerformTransfer() = 0; -protected: - static bool _PinBuffer(void *address, uint32_t size); - static void _UnpinBuffer(void* address, uint32_t size); -}; - -//////////////////////////////////////////// -// PinnedMemoryAllocator -//////////////////////////////////////////// - -// PinnedMemoryAllocator implements the IDeckLinkMemoryAllocator interface and can be used instead of the -// built-in frame allocator, by setting with SetVideoInputFrameMemoryAllocator() or SetVideoOutputFrameMemoryAllocator(). -// -// For this sample application a custom frame memory allocator is used to ensure each address -// of frame memory is aligned on a 4kB boundary required by the OpenGL pinned memory extension. -// If the pinned memory extension is not available, this allocator will still be used and -// demonstrates how to cache frame allocations for efficiency. -// -// The frame cache delays the releasing of buffers until the cache fills up, thereby avoiding an -// allocate plus pin operation for every frame, followed by an unpin and deallocate on every frame. - - -class PinnedMemoryAllocator : public IDeckLinkMemoryAllocator -{ -public: - PinnedMemoryAllocator(unsigned cacheSize, size_t memSize); - virtual ~PinnedMemoryAllocator(); - - void TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId); - - // IUnknown methods - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv); - virtual ULONG STDMETHODCALLTYPE AddRef(void); - virtual ULONG STDMETHODCALLTYPE Release(void); - - // IDeckLinkMemoryAllocator methods - virtual HRESULT STDMETHODCALLTYPE AllocateBuffer(dl_size_t bufferSize, void* *allocatedBuffer); - virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(void* buffer); - virtual HRESULT STDMETHODCALLTYPE Commit(); - virtual HRESULT STDMETHODCALLTYPE Decommit(); - -private: - static bool mGPUDirectInitialized; - static bool mHasDvp; - static bool mHasAMDPinnedMemory; - static size_t mReservedProcessMemory; - static bool ReserveMemory(size_t size); - - void Lock() - { - pthread_mutex_lock(&mMutex); - } - void Unlock() - { - pthread_mutex_unlock(&mMutex); - } - HRESULT _ReleaseBuffer(void* buffer); - - uint32_t mRefCount; - // protect the cache and the allocated map, - // not the pinnedBuffer map as it is only used from main thread - pthread_mutex_t mMutex; - std::map<void*, uint32_t> mAllocatedSize; - std::vector<void*> mBufferCache; - std::map<void *, TextureTransfer*> mPinnedBuffer; -#ifdef WIN32 - DVPBufferHandle mDvpCaptureTextureHandle; -#endif - // target texture in GPU - GLuint mTexId; - uint32_t mBufferCacheSize; -}; - -//////////////////////////////////////////// -// Capture Delegate Class -//////////////////////////////////////////// - -class CaptureDelegate : public IDeckLinkInputCallback -{ - VideoDeckLink* mpOwner; - -public: - CaptureDelegate(VideoDeckLink* pOwner); - - // IUnknown needs only a dummy implementation - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } - virtual ULONG STDMETHODCALLTYPE AddRef() { return 1; } - virtual ULONG STDMETHODCALLTYPE Release() { return 1; } - - virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioPacket); - virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags); -}; - - -#endif /* WITH_GAMEENGINE_DECKLINK */ - -#endif /* __VIDEODECKLINK_H__ */ diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp deleted file mode 100644 index 11ec97ca5f8..00000000000 --- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp +++ /dev/null @@ -1,1392 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/VideoFFmpeg.cpp - * \ingroup bgevideotex - */ - - -#ifdef WITH_FFMPEG - -// INT64_C fix for some linux machines (C99ism) -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#ifdef __STDC_CONSTANT_MACROS /* quiet warning */ -#endif -#endif - -#include <stdint.h> - - -#include "MEM_guardedalloc.h" -#include "PIL_time.h" - -#include <string> - -#include "VideoFFmpeg.h" -#include "Exception.h" - - -// default framerate -const double defFrameRate = 25.0; - -// macro for exception handling and logging -#define CATCH_EXCP catch (Exception & exp) \ -{ exp.report(); m_status = SourceError; } - -// class RenderVideo - -// constructor -VideoFFmpeg::VideoFFmpeg (HRESULT * hRslt) : VideoBase(), -m_codec(NULL), m_formatCtx(NULL), m_codecCtx(NULL), -m_frame(NULL), m_frameDeinterlaced(NULL), m_frameRGB(NULL), m_imgConvertCtx(NULL), -m_deinterlace(false), m_preseek(0), m_videoStream(-1), m_baseFrameRate(25.0), -m_lastFrame(-1), m_eof(false), m_externTime(false), m_curPosition(-1), m_startTime(0), -m_captWidth(0), m_captHeight(0), m_captRate(0.f), m_isImage(false), -m_isThreaded(false), m_isStreaming(false), m_stopThread(false), m_cacheStarted(false) -{ - // set video format - m_format = RGB24; - // force flip because ffmpeg always return the image in the wrong orientation for texture - setFlip(true); - // construction is OK - *hRslt = S_OK; - BLI_listbase_clear(&m_thread); - pthread_mutex_init(&m_cacheMutex, NULL); - BLI_listbase_clear(&m_frameCacheFree); - BLI_listbase_clear(&m_frameCacheBase); - BLI_listbase_clear(&m_packetCacheFree); - BLI_listbase_clear(&m_packetCacheBase); -} - -// destructor -VideoFFmpeg::~VideoFFmpeg () -{ -} - -void VideoFFmpeg::refresh(void) -{ - // a fixed image will not refresh because it is loaded only once at creation - if (m_isImage) - return; - m_avail = false; -} - -// release components -bool VideoFFmpeg::release() -{ - // release - stopCache(); - if (m_codecCtx) - { - avcodec_close(m_codecCtx); - m_codecCtx = NULL; - } - if (m_formatCtx) - { - avformat_close_input(&m_formatCtx); - m_formatCtx = NULL; - } - if (m_frame) - { - av_free(m_frame); - m_frame = NULL; - } - if (m_frameDeinterlaced) - { - MEM_freeN(m_frameDeinterlaced->data[0]); - av_free(m_frameDeinterlaced); - m_frameDeinterlaced = NULL; - } - if (m_frameRGB) - { - MEM_freeN(m_frameRGB->data[0]); - av_free(m_frameRGB); - m_frameRGB = NULL; - } - if (m_imgConvertCtx) - { - sws_freeContext(m_imgConvertCtx); - m_imgConvertCtx = NULL; - } - m_codec = NULL; - m_status = SourceStopped; - m_lastFrame = -1; - return true; -} - -AVFrame *VideoFFmpeg::allocFrameRGB() -{ - AVFrame *frame; - frame = av_frame_alloc(); - if (m_format == RGBA32) - { - avpicture_fill((AVPicture*)frame, - (uint8_t*)MEM_callocN(avpicture_get_size( - AV_PIX_FMT_RGBA, - m_codecCtx->width, m_codecCtx->height), - "ffmpeg rgba"), - AV_PIX_FMT_RGBA, m_codecCtx->width, m_codecCtx->height); - } else - { - avpicture_fill((AVPicture*)frame, - (uint8_t*)MEM_callocN(avpicture_get_size( - AV_PIX_FMT_RGB24, - m_codecCtx->width, m_codecCtx->height), - "ffmpeg rgb"), - AV_PIX_FMT_RGB24, m_codecCtx->width, m_codecCtx->height); - } - return frame; -} - -// set initial parameters -void VideoFFmpeg::initParams (short width, short height, float rate, bool image) -{ - m_captWidth = width; - m_captHeight = height; - m_captRate = rate; - m_isImage = image; -} - - -int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AVDictionary **formatParams) -{ - AVFormatContext *formatCtx = NULL; - int i, videoStream; - AVCodec *codec; - AVCodecContext *codecCtx; - - if (avformat_open_input(&formatCtx, filename, inputFormat, formatParams)!=0) - return -1; - - if (avformat_find_stream_info(formatCtx, NULL) < 0) - { - avformat_close_input(&formatCtx); - return -1; - } - - /* Find the first video stream */ - videoStream=-1; - for (i=0; i<formatCtx->nb_streams; i++) - { - if (formatCtx->streams[i] && - get_codec_from_stream(formatCtx->streams[i]) && - (get_codec_from_stream(formatCtx->streams[i])->codec_type==AVMEDIA_TYPE_VIDEO)) - { - videoStream=i; - break; - } - } - - if (videoStream==-1) - { - avformat_close_input(&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) - { - avformat_close_input(&formatCtx); - return -1; - } - codecCtx->workaround_bugs = 1; - if (avcodec_open2(codecCtx, codec, NULL) < 0) - { - avformat_close_input(&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(av_get_r_frame_rate_compat(formatCtx, formatCtx->streams[videoStream])); -#endif - if (m_baseFrameRate <= 0.0) - m_baseFrameRate = defFrameRate; - - m_codec = codec; - m_codecCtx = codecCtx; - m_formatCtx = formatCtx; - m_videoStream = videoStream; - m_frame = av_frame_alloc(); - m_frameDeinterlaced = av_frame_alloc(); - - // allocate buffer if deinterlacing is required - avpicture_fill((AVPicture*)m_frameDeinterlaced, - (uint8_t*)MEM_callocN(avpicture_get_size( - m_codecCtx->pix_fmt, - m_codecCtx->width, m_codecCtx->height), - "ffmpeg deinterlace"), - m_codecCtx->pix_fmt, m_codecCtx->width, m_codecCtx->height); - - // check if the pixel format supports Alpha - if (m_codecCtx->pix_fmt == AV_PIX_FMT_RGB32 || - m_codecCtx->pix_fmt == AV_PIX_FMT_BGR32 || - m_codecCtx->pix_fmt == AV_PIX_FMT_RGB32_1 || - m_codecCtx->pix_fmt == AV_PIX_FMT_BGR32_1) - { - // allocate buffer to store final decoded frame - m_format = RGBA32; - // allocate sws context - m_imgConvertCtx = sws_getContext( - m_codecCtx->width, - m_codecCtx->height, - m_codecCtx->pix_fmt, - m_codecCtx->width, - m_codecCtx->height, - AV_PIX_FMT_RGBA, - SWS_FAST_BILINEAR, - NULL, NULL, NULL); - } else - { - // allocate buffer to store final decoded frame - m_format = RGB24; - // allocate sws context - m_imgConvertCtx = sws_getContext( - m_codecCtx->width, - m_codecCtx->height, - m_codecCtx->pix_fmt, - m_codecCtx->width, - m_codecCtx->height, - AV_PIX_FMT_RGB24, - SWS_FAST_BILINEAR, - NULL, NULL, NULL); - } - m_frameRGB = allocFrameRGB(); - - if (!m_imgConvertCtx) { - avcodec_close(m_codecCtx); - m_codecCtx = NULL; - avformat_close_input(&m_formatCtx); - m_formatCtx = NULL; - av_free(m_frame); - m_frame = NULL; - MEM_freeN(m_frameDeinterlaced->data[0]); - av_free(m_frameDeinterlaced); - m_frameDeinterlaced = NULL; - MEM_freeN(m_frameRGB->data[0]); - av_free(m_frameRGB); - m_frameRGB = NULL; - return -1; - } - return 0; -} - -/* - * This thread is used to load video frame asynchronously. - * It provides a frame caching service. - * The main thread is responsible for positioning the frame pointer in the - * file correctly before calling startCache() which starts this thread. - * The cache is organized in two layers: 1) a cache of 20-30 undecoded packets to keep - * memory and CPU low 2) a cache of 5 decoded frames. - * If the main thread does not find the frame in the cache (because the video has restarted - * or because the GE is lagging), it stops the cache with StopCache() (this is a synchronous - * function: it sends a signal to stop the cache thread and wait for confirmation), then - * change the position in the stream and restarts the cache thread. - */ -void *VideoFFmpeg::cacheThread(void *data) -{ - VideoFFmpeg* video = (VideoFFmpeg*)data; - // holds the frame that is being decoded - CacheFrame *currentFrame = NULL; - CachePacket *cachePacket; - bool endOfFile = false; - int frameFinished = 0; - double timeBase = av_q2d(video->m_formatCtx->streams[video->m_videoStream]->time_base); - int64_t startTs = video->m_formatCtx->streams[video->m_videoStream]->start_time; - - if (startTs == AV_NOPTS_VALUE) - startTs = 0; - - while (!video->m_stopThread) - { - // packet cache is used solely by this thread, no need to lock - // In case the stream/file contains other stream than the one we are looking for, - // allow a bit of cycling to get rid quickly of those frames - frameFinished = 0; - while ( !endOfFile - && (cachePacket = (CachePacket *)video->m_packetCacheFree.first) != NULL - && frameFinished < 25) - { - // free packet => packet cache is not full yet, just read more - if (av_read_frame(video->m_formatCtx, &cachePacket->packet)>=0) - { - if (cachePacket->packet.stream_index == video->m_videoStream) - { - // make sure fresh memory is allocated for the packet and move it to queue - av_dup_packet(&cachePacket->packet); - BLI_remlink(&video->m_packetCacheFree, cachePacket); - BLI_addtail(&video->m_packetCacheBase, cachePacket); - break; - } else { - // this is not a good packet for us, just leave it on free queue - // Note: here we could handle sound packet - av_free_packet(&cachePacket->packet); - frameFinished++; - } - - } else { - if (video->m_isFile) - // this mark the end of the file - endOfFile = true; - // if we cannot read a packet, no need to continue - break; - } - } - // frame cache is also used by main thread, lock - if (currentFrame == NULL) - { - // no current frame being decoded, take free one - pthread_mutex_lock(&video->m_cacheMutex); - if ((currentFrame = (CacheFrame *)video->m_frameCacheFree.first) != NULL) - BLI_remlink(&video->m_frameCacheFree, currentFrame); - pthread_mutex_unlock(&video->m_cacheMutex); - } - if (currentFrame != NULL) - { - // this frame is out of free and busy queue, we can manipulate it without locking - frameFinished = 0; - while (!frameFinished && (cachePacket = (CachePacket *)video->m_packetCacheBase.first) != NULL) - { - BLI_remlink(&video->m_packetCacheBase, cachePacket); - // use m_frame because when caching, it is not used in main thread - // we can't use currentFrame directly because we need to convert to RGB first - avcodec_decode_video2(video->m_codecCtx, - video->m_frame, &frameFinished, - &cachePacket->packet); - if (frameFinished) - { - AVFrame * input = video->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) - { - if (video->m_deinterlace) - { - if (avpicture_deinterlace( - (AVPicture*) video->m_frameDeinterlaced, - (const AVPicture*) video->m_frame, - video->m_codecCtx->pix_fmt, - video->m_codecCtx->width, - video->m_codecCtx->height) >= 0) - { - input = video->m_frameDeinterlaced; - } - } - // convert to RGB24 - sws_scale(video->m_imgConvertCtx, - input->data, - input->linesize, - 0, - video->m_codecCtx->height, - currentFrame->frame->data, - currentFrame->frame->linesize); - // move frame to queue, this frame is necessarily the next one - video->m_curPosition = (long)((cachePacket->packet.dts-startTs) * (video->m_baseFrameRate*timeBase) + 0.5); - currentFrame->framePosition = video->m_curPosition; - pthread_mutex_lock(&video->m_cacheMutex); - BLI_addtail(&video->m_frameCacheBase, currentFrame); - pthread_mutex_unlock(&video->m_cacheMutex); - currentFrame = NULL; - } - } - av_free_packet(&cachePacket->packet); - BLI_addtail(&video->m_packetCacheFree, cachePacket); - } - if (currentFrame && endOfFile) - { - // no more packet and end of file => put a special frame that indicates that - currentFrame->framePosition = -1; - pthread_mutex_lock(&video->m_cacheMutex); - BLI_addtail(&video->m_frameCacheBase, currentFrame); - pthread_mutex_unlock(&video->m_cacheMutex); - currentFrame = NULL; - // no need to stay any longer in this thread - break; - } - } - // small sleep to avoid unnecessary looping - PIL_sleep_ms(10); - } - // before quitting, put back the current frame to queue to allow freeing - if (currentFrame) - { - pthread_mutex_lock(&video->m_cacheMutex); - BLI_addtail(&video->m_frameCacheFree, currentFrame); - pthread_mutex_unlock(&video->m_cacheMutex); - } - return 0; -} - -// start thread to cache video frame from file/capture/stream -// this function should be called only when the position in the stream is set for the -// first frame to cache -bool VideoFFmpeg::startCache() -{ - if (!m_cacheStarted && m_isThreaded) - { - m_stopThread = false; - for (int i=0; i<CACHE_FRAME_SIZE; i++) - { - CacheFrame *frame = new CacheFrame(); - frame->frame = allocFrameRGB(); - BLI_addtail(&m_frameCacheFree, frame); - } - for (int i=0; i<CACHE_PACKET_SIZE; i++) - { - CachePacket *packet = new CachePacket(); - BLI_addtail(&m_packetCacheFree, packet); - } - BLI_threadpool_init(&m_thread, cacheThread, 1); - BLI_threadpool_insert(&m_thread, this); - m_cacheStarted = true; - } - return m_cacheStarted; -} - -void VideoFFmpeg::stopCache() -{ - if (m_cacheStarted) - { - m_stopThread = true; - BLI_threadpool_end(&m_thread); - // now delete the cache - CacheFrame *frame; - CachePacket *packet; - while ((frame = (CacheFrame *)m_frameCacheBase.first) != NULL) - { - BLI_remlink(&m_frameCacheBase, frame); - MEM_freeN(frame->frame->data[0]); - av_free(frame->frame); - delete frame; - } - while ((frame = (CacheFrame *)m_frameCacheFree.first) != NULL) - { - BLI_remlink(&m_frameCacheFree, frame); - MEM_freeN(frame->frame->data[0]); - av_free(frame->frame); - delete frame; - } - while ((packet = (CachePacket *)m_packetCacheBase.first) != NULL) - { - BLI_remlink(&m_packetCacheBase, packet); - av_free_packet(&packet->packet); - delete packet; - } - while ((packet = (CachePacket *)m_packetCacheFree.first) != NULL) - { - BLI_remlink(&m_packetCacheFree, packet); - delete packet; - } - m_cacheStarted = false; - } -} - -void VideoFFmpeg::releaseFrame(AVFrame *frame) -{ - if (frame == m_frameRGB) - { - // this is not a frame from the cache, ignore - return; - } - // this frame MUST be the first one of the queue - pthread_mutex_lock(&m_cacheMutex); - CacheFrame *cacheFrame = (CacheFrame *)m_frameCacheBase.first; - assert (cacheFrame != NULL && cacheFrame->frame == frame); - BLI_remlink(&m_frameCacheBase, cacheFrame); - BLI_addtail(&m_frameCacheFree, cacheFrame); - pthread_mutex_unlock(&m_cacheMutex); -} - -// open video file -void VideoFFmpeg::openFile (char *filename) -{ - 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 ( - // ffmpeg reports that http source are actually non stream - // but it is really not desirable to seek on http file, so force streaming. - // It would be good to find this information from the context but there are no simple indication - !strncmp(filename, "http://", 7) || - !strncmp(filename, "rtsp://", 7) || - (m_formatCtx->pb && !m_formatCtx->pb->seekable) - ) - { - // the file is in fact a streaming source, treat as cam to prevent seeking - m_isFile = false; - // but it's not handled exactly like a camera. - m_isStreaming = true; - // for streaming it is important to do non blocking read - m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK; - } - - if (m_isImage) - { - // the file is to be treated as an image, i.e. load the first frame only - m_isFile = false; - // in case of reload, the filename is taken from m_imageName, no need to change it - if (m_imageName.Ptr() != filename) - m_imageName = filename; - m_preseek = 0; - m_avail = false; - play(); - } - // check if we should do multi-threading? - if (!m_isImage && BLI_system_thread_count() > 1) - { - // never thread image: there are no frame to read ahead - // no need to thread if the system has a single core - m_isThreaded = true; - } -} - - -// open video capture device -void VideoFFmpeg::openCam (char *file, short camIdx) -{ - // open camera source - AVInputFormat *inputFormat; - AVDictionary *formatParams = NULL; - char filename[28], rateStr[20]; - -#ifdef WIN32 - // video capture on windows only through Video For Windows driver - inputFormat = av_find_input_format("vfwcap"); - if (!inputFormat) - // Video For Windows not supported?? - return; - sprintf(filename, "%d", camIdx); -#else - // In Linux we support two types of devices: VideoForLinux and DV1394. - // the user specify it with the filename: - // [<device_type>][:<standard>] - // <device_type> : 'v4l' for VideoForLinux, 'dv1394' for DV1394. By default 'v4l' - // <standard> : 'pal', 'secam' or 'ntsc'. By default 'ntsc' - // The driver name is constructed automatically from the device type: - // v4l : /dev/video<camIdx> - // dv1394: /dev/dv1394/<camIdx> - // If you have different driver name, you can specify the driver name explicitly - // instead of device type. Examples of valid filename: - // /dev/v4l/video0:pal - // /dev/ieee1394/1:ntsc - // dv1394:secam - // v4l:pal - char *p; - - 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 - { - const char *formats[] = {"video4linux2,v4l2", "video4linux2", "video4linux"}; - int i, formatsCount = sizeof(formats) / sizeof(char*); - for (i = 0; i < formatsCount; i++) { - inputFormat = av_find_input_format(formats[i]); - if (inputFormat) - break; - } - 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) { - av_dict_set(&formatParams, "standard", p+1, 0); - } -#endif - //frame rate - if (m_captRate <= 0.f) - m_captRate = defFrameRate; - sprintf(rateStr, "%f", m_captRate); - - av_dict_set(&formatParams, "framerate", rateStr, 0); - - if (m_captWidth > 0 && m_captHeight > 0) { - char video_size[64]; - BLI_snprintf(video_size, sizeof(video_size), "%dx%d", m_captWidth, m_captHeight); - av_dict_set(&formatParams, "video_size", video_size, 0); - } - - 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); - // check if we should do multi-threading? - if (BLI_system_thread_count() > 1) - { - // no need to thread if the system has a single core - m_isThreaded = true; - } - - av_dict_free(&formatParams); -} - -// play video -bool VideoFFmpeg::play (void) -{ - try - { - // if object is able to play - if (VideoBase::play()) - { - // set video position - setPositions(); - - if (m_isStreaming) - { - av_read_play(m_formatCtx); - } - - // return success - return true; - } - } - CATCH_EXCP; - return false; -} - - -// pause video -bool VideoFFmpeg::pause (void) -{ - try - { - if (VideoBase::pause()) - { - if (m_isStreaming) - { - av_read_pause(m_formatCtx); - } - return true; - } - } - CATCH_EXCP; - return false; -} - -// stop video -bool VideoFFmpeg::stop (void) -{ - try - { - VideoBase::stop(); - // force restart when play - m_lastFrame = -1; - return true; - } - CATCH_EXCP; - return false; -} - - -// set video range -void VideoFFmpeg::setRange (double start, double stop) -{ - try - { - // set range - if (m_isFile) - { - VideoBase::setRange(start, stop); - // set range for video - setPositions(); - } - } - CATCH_EXCP; -} - -// set framerate -void VideoFFmpeg::setFrameRate (float rate) -{ - VideoBase::setFrameRate(rate); -} - - -// image calculation -// load frame from video -void VideoFFmpeg::calcImage (unsigned int texId, double ts) -{ - if (m_status == SourcePlaying) - { - // get actual time - double startTime = PIL_check_seconds_timer(); - double actTime; - // timestamp passed from audio actuators can sometimes be slightly negative - if (m_isFile && ts >= -0.5) - { - // allow setting timestamp only when not streaming - actTime = ts; - if (actTime * actFrameRate() < m_lastFrame) - { - // user is asking to rewind, force a cache clear to make sure we will do a seek - // note that this does not decrement m_repeat if ts didn't reach m_range[1] - stopCache(); - } - } - else - { - if (m_lastFrame == -1 && !m_isFile) - m_startTime = startTime; - actTime = startTime - m_startTime; - } - // if video has ended - if (m_isFile && actTime * m_frameRate >= m_range[1]) - { - // in any case, this resets the cache - stopCache(); - // 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; - return; - } - } - // actual frame - long actFrame = (m_isImage) ? m_lastFrame+1 : long(actTime * actFrameRate()); - // if actual frame differs from last frame - if (actFrame != m_lastFrame) - { - AVFrame* frame; - // get image - if ((frame = grabFrame(actFrame)) != NULL) - { - if (!m_isFile && !m_cacheStarted) - { - // streaming without cache: detect synchronization problem - double execTime = PIL_check_seconds_timer() - startTime; - if (execTime > 0.005) - { - // exec time is too long, it means that the function was blocking - // resynchronize the stream from this time - m_startTime += execTime; - } - } - // 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])); - // finished with the frame, release it so that cache can reuse it - releaseFrame(frame); - // in case it is an image, automatically stop reading it - if (m_isImage) - { - m_status = SourceStopped; - // close the file as we don't need it anymore - release(); - } - } else if (m_isStreaming) - { - // we didn't get a frame and we are streaming, this may be due to - // a delay in the network or because we are getting the frame too fast. - // In the later case, shift time by a small amount to compensate for a drift - m_startTime += 0.001; - } - } - } -} - - -// 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_eof && m_lastFrame >= 0 && (!m_isFile || m_lastFrame < m_range[1] * actFrameRate())) - // continue from actual position - m_startTime -= double(m_lastFrame) / actFrameRate(); - else { - m_startTime -= m_range[0]; - // start from beginning, stop cache just in case - stopCache(); - } -} - -// position pointer in file, position in second -AVFrame *VideoFFmpeg::grabFrame(long position) -{ - AVPacket packet; - int frameFinished; - int posFound = 1; - bool frameLoaded = false; - int64_t targetTs = 0; - CacheFrame *frame; - int64_t dts = 0; - - if (m_cacheStarted) - { - // when cache is active, we must not read the file directly - do { - pthread_mutex_lock(&m_cacheMutex); - frame = (CacheFrame *)m_frameCacheBase.first; - pthread_mutex_unlock(&m_cacheMutex); - // no need to remove the frame from the queue: the cache thread does not touch the head, only the tail - if (frame == NULL) - { - // no frame in cache, in case of file it is an abnormal situation - if (m_isFile) - { - // go back to no threaded reading - stopCache(); - break; - } - return NULL; - } - if (frame->framePosition == -1) - { - // this frame mark the end of the file (only used for file) - // leave in cache to make sure we don't miss it - m_eof = true; - return NULL; - } - // for streaming, always return the next frame, - // that's what grabFrame does in non cache mode anyway. - if (m_isStreaming || frame->framePosition == position) - { - return frame->frame; - } - // for cam, skip old frames to keep image realtime. - // There should be no risk of clock drift since it all happens on the same CPU - if (frame->framePosition > position) - { - // this can happen after rewind if the seek didn't find the first frame - // the frame in the buffer is ahead of time, just leave it there - return NULL; - } - // this frame is not useful, release it - pthread_mutex_lock(&m_cacheMutex); - BLI_remlink(&m_frameCacheBase, frame); - BLI_addtail(&m_frameCacheFree, frame); - pthread_mutex_unlock(&m_cacheMutex); - } while (true); - } - double timeBase = av_q2d(m_formatCtx->streams[m_videoStream]->time_base); - int64_t startTs = m_formatCtx->streams[m_videoStream]->start_time; - if (startTs == AV_NOPTS_VALUE) - startTs = 0; - - // come here when there is no cache or cache has been stopped - // locate the frame, by seeking if necessary (seeking is only possible for files) - if (m_isFile) - { - // 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_video2( - m_codecCtx, - m_frame, &frameFinished, - &packet); - if (frameFinished) - { - m_curPosition = (long)((packet.dts-startTs) * (m_baseFrameRate*timeBase) + 0.5); - } - } - 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) - { - int64_t pos = (int64_t)((position - m_preseek) / (m_baseFrameRate*timeBase)); - - if (pos < 0) - pos = 0; - - pos += startTs; - - if (position <= m_curPosition || !m_eof) - { -#if 0 - // Tried to make this work but couldn't: seeking on byte is ignored by the - // format plugin and it will generally continue to read from last timestamp. - // Too bad because frame seek is not always able to get the first frame - // of the file. - if (position <= m_preseek) - { - // we can safely go the beginning of the file - if (av_seek_frame(m_formatCtx, m_videoStream, 0, AVSEEK_FLAG_BYTE) >= 0) - { - // binary seek does not reset the timestamp, must do it now - av_update_cur_dts(m_formatCtx, m_formatCtx->streams[m_videoStream], startTs); - m_curPosition = 0; - } - } - else -#endif - { - // current position is now lost, guess a value. - if (av_seek_frame(m_formatCtx, m_videoStream, pos, AVSEEK_FLAG_BACKWARD) >= 0) - { - // current position is now lost, guess a value. - // It's not important because it will be set at this end of this function - m_curPosition = position - m_preseek - 1; - } - } - } - // this is the timestamp of the frame we're looking for - targetTs = (int64_t)(position / (m_baseFrameRate * timeBase)) + startTs; - - posFound = 0; - avcodec_flush_buffers(m_codecCtx); - } - } else if (m_isThreaded) - { - // cache is not started but threading is possible - // better not read the stream => make take some time, better start caching - if (startCache()) - return NULL; - // Abnormal!!! could not start cache, fall back on direct read - m_isThreaded = false; - } - - // find the correct frame, in case of streaming and no cache, it means just - // return the next frame. This is not quite correct, may need more work - while (av_read_frame(m_formatCtx, &packet) >= 0) - { - if (packet.stream_index == m_videoStream) - { - AVFrame *input = m_frame; - short counter = 0; - - /* If m_isImage, while the data is not read properly (png, tiffs, etc formats may need several pass), else don't need while loop*/ - do { - avcodec_decode_video2(m_codecCtx, m_frame, &frameFinished, &packet); - counter++; - } while ((input->data[0] == 0 && input->data[1] == 0 && input->data[2] == 0 && input->data[3] == 0) && counter < 10 && m_isImage); - - // remember dts to compute exact frame number - dts = packet.dts; - if (frameFinished && !posFound) - { - if (dts >= targetTs) - { - posFound = 1; - } - } - - if (frameFinished && posFound == 1) - { - AVFrame * input = m_frame; - - /* This means the data wasnt read properly, - * this check stops crashing */ - if ( input->data[0]==0 && input->data[1]==0 - && input->data[2]==0 && input->data[3]==0) - { - av_free_packet(&packet); - break; - } - - if (m_deinterlace) - { - if (avpicture_deinterlace( - (AVPicture*) m_frameDeinterlaced, - (const AVPicture*) m_frame, - m_codecCtx->pix_fmt, - m_codecCtx->width, - m_codecCtx->height) >= 0) - { - input = m_frameDeinterlaced; - } - } - // convert to RGB24 - sws_scale(m_imgConvertCtx, - input->data, - input->linesize, - 0, - m_codecCtx->height, - m_frameRGB->data, - m_frameRGB->linesize); - av_free_packet(&packet); - frameLoaded = true; - break; - } - } - av_free_packet(&packet); - } - m_eof = m_isFile && !frameLoaded; - if (frameLoaded) - { - m_curPosition = (long)((dts-startTs) * (m_baseFrameRate*timeBase) + 0.5); - if (m_isThreaded) - { - // normal case for file: first locate, then start cache - if (!startCache()) - { - // Abnormal!! could not start cache, return to non-cache mode - m_isThreaded = false; - } - } - return m_frameRGB; - } - return NULL; -} - - -// python methods - - -// cast Image pointer to VideoFFmpeg -inline VideoFFmpeg * getVideoFFmpeg (PyImage *self) -{ return static_cast<VideoFFmpeg*>(self->m_image); } - - -// object initialization -static int VideoFFmpeg_init(PyObject *pySelf, PyObject *args, PyObject *kwds) -{ - PyImage *self = reinterpret_cast<PyImage*>(pySelf); - // parameters - video source - // file name or format type for capture (only for Linux: video4linux or dv1394) - char * file = NULL; - // capture device number - short capt = -1; - // capture width, only if capt is >= 0 - short width = 0; - // capture height, only if capt is >= 0 - short height = 0; - // capture rate, only if capt is >= 0 - float rate = 25.f; - - static const char *kwlist[] = {"file", "capture", "rate", "width", "height", NULL}; - - // get parameters - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|hfhh", - const_cast<char**>(kwlist), &file, &capt, &rate, &width, &height)) - return -1; - - try - { - // create video object - Video_init<VideoFFmpeg>(self); - - // set thread usage - getVideoFFmpeg(self)->initParams(width, height, rate); - - // open video source - Video_open(getVideo(self), file, capt); - } - catch (Exception & exp) - { - exp.report(); - return -1; - } - // initialization succeded - return 0; -} - -static PyObject *VideoFFmpeg_getPreseek(PyImage *self, void *closure) -{ - return Py_BuildValue("h", getFFmpeg(self)->getPreseek()); -} - -// set range -static int VideoFFmpeg_setPreseek(PyImage *self, PyObject *value, void *closure) -{ - // check validity of parameter - if (value == NULL || !PyLong_Check(value)) - { - PyErr_SetString(PyExc_TypeError, "The value must be an integer"); - return -1; - } - // set preseek - getFFmpeg(self)->setPreseek(PyLong_AsLong(value)); - // success - return 0; -} - -// get deinterlace -static PyObject *VideoFFmpeg_getDeinterlace(PyImage *self, void *closure) -{ - if (getFFmpeg(self)->getDeinterlace()) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - -// set flip -static 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 (restart) video"}, - {"pause", (PyCFunction)Video_pause, METH_NOARGS, "pause video"}, - {"stop", (PyCFunction)Video_stop, METH_NOARGS, "stop video (play will replay it from start)"}, - {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh video - get its status"}, - {NULL} -}; -// attributes structure -static PyGetSetDef videoGetSets[] = -{ // methods from VideoBase class - {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL}, - {(char*)"range", (getter)Video_getRange, (setter)Video_setRange, (char*)"replay range", NULL}, - {(char*)"repeat", (getter)Video_getRepeat, (setter)Video_setRepeat, (char*)"repeat count, -1 for infinite repeat", NULL}, - {(char*)"framerate", (getter)Video_getFrameRate, (setter)Video_setFrameRate, (char*)"frame rate", NULL}, - // attributes from ImageBase class - {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, - {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, - {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, - {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL}, - {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, - {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, - {(char*)"preseek", (getter)VideoFFmpeg_getPreseek, (setter)VideoFFmpeg_setPreseek, (char*)"nb of frames of preseek", NULL}, - {(char*)"deinterlace", (getter)VideoFFmpeg_getDeinterlace, (setter)VideoFFmpeg_setDeinterlace, (char*)"deinterlace image", NULL}, - {NULL} -}; - -// python type declaration -PyTypeObject VideoFFmpegType = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "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*/ - &imageBufferProcs, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "FFmpeg video source", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - videoMethods, /* tp_methods */ - 0, /* tp_members */ - videoGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)VideoFFmpeg_init, /* tp_init */ - 0, /* tp_alloc */ - Image_allocNew, /* tp_new */ -}; - -// object initialization -static int ImageFFmpeg_init(PyObject *pySelf, PyObject *args, PyObject *kwds) -{ - PyImage *self = reinterpret_cast<PyImage*>(pySelf); - // parameters - video source - // file name or format type for capture (only for Linux: video4linux or dv1394) - char * file = NULL; - - // get parameters - if (!PyArg_ParseTuple(args, "s:ImageFFmpeg", &file)) - return -1; - - try - { - // create video object - Video_init<VideoFFmpeg>(self); - - getVideoFFmpeg(self)->initParams(0, 0, 1.0, true); - - // open video source - Video_open(getVideo(self), file, -1); - } - catch (Exception & exp) - { - exp.report(); - return -1; - } - // initialization succeded - return 0; -} - -static PyObject *Image_reload(PyImage *self, PyObject *args) -{ - char * newname = NULL; - if (!PyArg_ParseTuple(args, "|s:reload", &newname)) - return NULL; - if (self->m_image != NULL) - { - VideoFFmpeg* video = getFFmpeg(self); - // check type of object - if (!newname) - newname = video->getImageName(); - if (!newname) { - // if not set, retport error - PyErr_SetString(PyExc_RuntimeError, "No image file name given"); - return NULL; - } - // make sure the previous file is cleared - video->release(); - // open the new file - video->openFile(newname); - } - Py_RETURN_NONE; -} - -// methods structure -static PyMethodDef imageMethods[] = -{ // methods from VideoBase class - {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh image, i.e. load it"}, - {"reload", (PyCFunction)Image_reload, METH_VARARGS, "Reload image, i.e. reopen it"}, - {NULL} -}; -// attributes structure -static PyGetSetDef imageGetSets[] = -{ // methods from VideoBase class - {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL}, - // attributes from ImageBase class - {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, - {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, - {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, - {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL}, - {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, - {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, - {NULL} -}; - -// python type declaration -PyTypeObject ImageFFmpegType = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "VideoTexture.ImageFFmpeg", /*tp_name*/ - sizeof(PyImage), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Image_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - &imageBufferProcs, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "FFmpeg image source", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - imageMethods, /* tp_methods */ - 0, /* tp_members */ - imageGetSets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)ImageFFmpeg_init, /* tp_init */ - 0, /* tp_alloc */ - Image_allocNew, /* tp_new */ -}; - -#endif //WITH_FFMPEG - - diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.h b/source/gameengine/VideoTexture/VideoFFmpeg.h deleted file mode 100644 index 0a49a0b19bb..00000000000 --- a/source/gameengine/VideoTexture/VideoFFmpeg.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2007 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file VideoFFmpeg.h - * \ingroup bgevideotex - */ - -#ifndef __VIDEOFFMPEG_H__ -#define __VIDEOFFMPEG_H__ - -#ifdef WITH_FFMPEG -/* this needs to be parsed with __cplusplus defined before included through ffmpeg_compat.h */ -#if defined(__FreeBSD__) -# include <inttypes.h> -#endif -extern "C" { -#include <pthread.h> -#include "ffmpeg_compat.h" -#include "DNA_listBase.h" -#include "BLI_threads.h" -#include "BLI_blenlib.h" -} - -#if LIBAVFORMAT_VERSION_INT < (49 << 16) -# define FFMPEG_OLD_FRAME_RATE 1 -#else -# define FFMPEG_CODEC_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" - -#define CACHE_FRAME_SIZE 10 -#define CACHE_PACKET_SIZE 30 - -// type VideoFFmpeg declaration -class VideoFFmpeg : public VideoBase -{ -public: - /// constructor - VideoFFmpeg (HRESULT * hRslt); - /// destructor - virtual ~VideoFFmpeg (); - - /// set initial parameters - void initParams (short width, short height, float rate, bool image=false); - /// open video/image file - virtual void openFile(char *file); - /// open video capture device - virtual void openCam(char *driver, short camIdx); - - /// release video source - virtual bool release (void); - /// overwrite base refresh to handle fixed image - virtual void refresh(void); - /// play video - virtual bool play (void); - /// pause video - virtual bool pause (void); - /// stop video - virtual bool stop (void); - /// set play range - virtual void setRange (double start, double stop); - /// set frame rate - virtual void setFrameRate (float rate); - // some specific getters and setters - int getPreseek(void) { return m_preseek; } - void setPreseek(int preseek) { if (preseek >= 0) m_preseek = preseek; } - bool getDeinterlace(void) { return m_deinterlace; } - void setDeinterlace(bool deinterlace) { m_deinterlace = deinterlace; } - char *getImageName(void) { return (m_isImage) ? m_imageName.Ptr() : NULL; } - -protected: - // format and codec information - AVCodec *m_codec; - AVFormatContext *m_formatCtx; - AVCodecContext *m_codecCtx; - // raw frame extracted from video file - AVFrame *m_frame; - // deinterlaced frame if codec requires it - AVFrame *m_frameDeinterlaced; - // decoded RGB24 frame if codec requires it - AVFrame *m_frameRGB; - // conversion from raw to RGB is done with sws_scale - struct SwsContext *m_imgConvertCtx; - // should the codec be deinterlaced? - bool m_deinterlace; - // number of frame of preseek - int m_preseek; - // order number of stream holding the video in format context - int m_videoStream; - - // the actual frame rate - double m_baseFrameRate; - - /// last displayed frame - long m_lastFrame; - - /// end of file reached - bool m_eof; - - /// flag to indicate that time is coming from application - bool m_externTime; - - /// current file pointer position in file expressed in frame number - long m_curPosition; - - /// time of video play start - double m_startTime; - - /// width of capture in pixel - short m_captWidth; - - /// height of capture in pixel - short m_captHeight; - - /// frame rate of capture in frames per seconds - float m_captRate; - - /// is file an image? - bool m_isImage; - - /// is image loading done in a separate thread? - bool m_isThreaded; - - /// is streaming or camera? - bool m_isStreaming; - - /// keep last image name - STR_String m_imageName; - - /// image calculation - virtual void calcImage (unsigned int texId, double ts); - - /// 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, AVDictionary **formatParams); - - /// check if a frame is available and load it in pFrame, return true if a frame could be retrieved - AVFrame* grabFrame(long frame); - - /// in case of caching, put the frame back in free queue - void releaseFrame(AVFrame* frame); - - /// start thread to load the video file/capture/stream - bool startCache(); - void stopCache(); - -private: - typedef struct { - Link link; - long framePosition; - AVFrame *frame; - } CacheFrame; - typedef struct { - Link link; - AVPacket packet; - } CachePacket; - - bool m_stopThread; - bool m_cacheStarted; - ListBase m_thread; - ListBase m_frameCacheBase; // list of frames that are ready - ListBase m_frameCacheFree; // list of frames that are unused - ListBase m_packetCacheBase; // list of packets that are ready for decoding - ListBase m_packetCacheFree; // list of packets that are unused - pthread_mutex_t m_cacheMutex; - - AVFrame *allocFrameRGB(); - static void *cacheThread(void *); -}; - -inline VideoFFmpeg *getFFmpeg(PyImage *self) -{ - return static_cast<VideoFFmpeg*>(self->m_image); -} - -#endif /* WITH_FFMPEG */ - -#endif /* __VIDEOFFMPEG_H__ */ diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp deleted file mode 100644 index 9b046d46412..00000000000 --- a/source/gameengine/VideoTexture/blendVideoTex.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright (c) 2006 The Zdeno Ash Miklas - * - * This source file is part of VideoTexture library - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/VideoTexture/blendVideoTex.cpp - * \ingroup bgevideotex - */ - -#include "EXP_PyObjectPlus.h" - -#include "KX_PythonInit.h" - -#include <RAS_IPolygonMaterial.h> - -//Old API -//#include "TexPlayer.h" -//#include "TexImage.h" -//#include "TexFrameBuff.h" - -//#include "TexPlayerGL.h" - -#include "ImageBase.h" -#include "VideoBase.h" -#include "FilterBase.h" -#include "Texture.h" - -#include "Exception.h" - -// access to IMB_BLEND_* constants -extern "C" -{ -#include "IMB_imbuf.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:materialID", &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, "VideoTexture.materialID(ob, string): 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 PyUnicode_FromString(Exception::m_lastError.c_str()); -} - -// set log file -static PyObject *setLogFile (PyObject *self, PyObject *args) -{ - // get parameters - if (!PyArg_ParseTuple(args, "s:setLogFile", &Exception::m_logFile)) - return Py_BuildValue("i", -1); - // log file was loaded - return Py_BuildValue("i", 0); -} - - -// image to numpy array -static PyObject *imageToArray(PyObject *self, PyObject *args) -{ - // parameter is Image object - PyObject *pyImg; - char *mode = NULL; - if (!PyArg_ParseTuple(args, "O|s:imageToArray", &pyImg, &mode) || !pyImageTypes.in(Py_TYPE(pyImg))) - { - // if object is incorect, report error - PyErr_SetString(PyExc_TypeError, "VideoTexture.imageToArray(image): The value must be a image source object"); - return NULL; - } - // get image structure - PyImage * img = reinterpret_cast<PyImage*>(pyImg); - return Image_getImage(img, mode); -} - - -// 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 buffer from image source, color channels are selectable"}, - {NULL} /* Sentinel */ -}; - -#ifdef WITH_FFMPEG -extern PyTypeObject VideoFFmpegType; -extern PyTypeObject ImageFFmpegType; -#endif -#ifdef WITH_GAMEENGINE_DECKLINK -extern PyTypeObject VideoDeckLinkType; -extern PyTypeObject DeckLinkType; -#endif -extern PyTypeObject FilterBlueScreenType; -extern PyTypeObject FilterGrayType; -extern PyTypeObject FilterColorType; -extern PyTypeObject FilterLevelType; -extern PyTypeObject FilterNormalType; -extern PyTypeObject FilterRGB24Type; -extern PyTypeObject FilterRGBA32Type; -extern PyTypeObject FilterBGR24Type; -extern PyTypeObject ImageBuffType; -extern PyTypeObject ImageMixType; - -static void registerAllTypes(void) -{ -#ifdef WITH_FFMPEG - pyImageTypes.add(&VideoFFmpegType, "VideoFFmpeg"); - pyImageTypes.add(&ImageFFmpegType, "ImageFFmpeg"); -#endif -#ifdef WITH_GAMEENGINE_DECKLINK - pyImageTypes.add(&VideoDeckLinkType, "VideoDeckLink"); -#endif - pyImageTypes.add(&ImageBuffType, "ImageBuff"); - pyImageTypes.add(&ImageMixType, "ImageMix"); - pyImageTypes.add(&ImageRenderType, "ImageRender"); - pyImageTypes.add(&ImageMirrorType, "ImageMirror"); - pyImageTypes.add(&ImageViewportType, "ImageViewport"); - - pyFilterTypes.add(&FilterBlueScreenType, "FilterBlueScreen"); - pyFilterTypes.add(&FilterGrayType, "FilterGray"); - pyFilterTypes.add(&FilterColorType, "FilterColor"); - pyFilterTypes.add(&FilterLevelType, "FilterLevel"); - pyFilterTypes.add(&FilterNormalType, "FilterNormal"); - pyFilterTypes.add(&FilterRGB24Type, "FilterRGB24"); - pyFilterTypes.add(&FilterRGBA32Type, "FilterRGBA32"); - pyFilterTypes.add(&FilterBGR24Type, "FilterBGR24"); -} - -PyDoc_STRVAR(VideoTexture_module_documentation, -"Module that allows to play video files on textures in GameBlender." -); - -static struct PyModuleDef VideoTexture_module_def = { - PyModuleDef_HEAD_INIT, - "VideoTexture", /* m_name */ - VideoTexture_module_documentation, /* m_doc */ - 0, /* m_size */ - moduleMethods, /* m_methods */ - 0, /* m_reload */ - 0, /* m_traverse */ - 0, /* m_clear */ - 0, /* m_free */ -}; - -PyMODINIT_FUNC initVideoTexturePythonBinding(void) -{ - PyObject *m; - - // 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; -#ifdef WITH_GAMEENGINE_DECKLINK - if (PyType_Ready(&DeckLinkType) < 0) - return NULL; -#endif - - m = PyModule_Create(&VideoTexture_module_def); - PyDict_SetItemString(PySys_GetObject("modules"), VideoTexture_module_def.m_name, m); - - if (m == NULL) - return NULL; - - // initialize classes - pyImageTypes.reg(m); - pyFilterTypes.reg(m); - - Py_INCREF(&TextureType); - PyModule_AddObject(m, "Texture", (PyObject *)&TextureType); -#ifdef WITH_GAMEENGINE_DECKLINK - Py_INCREF(&DeckLinkType); - PyModule_AddObject(m, "DeckLink", (PyObject *)&DeckLinkType); -#endif - PyModule_AddIntConstant(m, "SOURCE_ERROR", SourceError); - PyModule_AddIntConstant(m, "SOURCE_EMPTY", SourceEmpty); - PyModule_AddIntConstant(m, "SOURCE_READY", SourceReady); - PyModule_AddIntConstant(m, "SOURCE_PLAYING", SourcePlaying); - PyModule_AddIntConstant(m, "SOURCE_STOPPED", SourceStopped); - - PyModule_AddIntConstant(m, "IMB_BLEND_MIX", IMB_BLEND_MIX); - PyModule_AddIntConstant(m, "IMB_BLEND_ADD", IMB_BLEND_ADD); - PyModule_AddIntConstant(m, "IMB_BLEND_SUB", IMB_BLEND_SUB); - PyModule_AddIntConstant(m, "IMB_BLEND_MUL", IMB_BLEND_MUL); - PyModule_AddIntConstant(m, "IMB_BLEND_LIGHTEN", IMB_BLEND_LIGHTEN); - PyModule_AddIntConstant(m, "IMB_BLEND_DARKEN", IMB_BLEND_DARKEN); - PyModule_AddIntConstant(m, "IMB_BLEND_ERASE_ALPHA", IMB_BLEND_ERASE_ALPHA); - PyModule_AddIntConstant(m, "IMB_BLEND_ADD_ALPHA", IMB_BLEND_ADD_ALPHA); - PyModule_AddIntConstant(m, "IMB_BLEND_OVERLAY", IMB_BLEND_OVERLAY); - PyModule_AddIntConstant(m, "IMB_BLEND_HARDLIGHT", IMB_BLEND_HARDLIGHT); - PyModule_AddIntConstant(m, "IMB_BLEND_COLORBURN", IMB_BLEND_COLORBURN); - PyModule_AddIntConstant(m, "IMB_BLEND_LINEARBURN", IMB_BLEND_LINEARBURN); - PyModule_AddIntConstant(m, "IMB_BLEND_COLORDODGE", IMB_BLEND_COLORDODGE); - PyModule_AddIntConstant(m, "IMB_BLEND_SCREEN", IMB_BLEND_SCREEN); - PyModule_AddIntConstant(m, "IMB_BLEND_SOFTLIGHT", IMB_BLEND_SOFTLIGHT); - PyModule_AddIntConstant(m, "IMB_BLEND_PINLIGHT", IMB_BLEND_PINLIGHT); - PyModule_AddIntConstant(m, "IMB_BLEND_VIVIDLIGHT", IMB_BLEND_VIVIDLIGHT); - PyModule_AddIntConstant(m, "IMB_BLEND_LINEARLIGHT", IMB_BLEND_LINEARLIGHT); - PyModule_AddIntConstant(m, "IMB_BLEND_DIFFERENCE", IMB_BLEND_DIFFERENCE); - PyModule_AddIntConstant(m, "IMB_BLEND_EXCLUSION", IMB_BLEND_EXCLUSION); - PyModule_AddIntConstant(m, "IMB_BLEND_HUE", IMB_BLEND_HUE); - PyModule_AddIntConstant(m, "IMB_BLEND_SATURATION", IMB_BLEND_SATURATION); - PyModule_AddIntConstant(m, "IMB_BLEND_LUMINOSITY", IMB_BLEND_LUMINOSITY); - PyModule_AddIntConstant(m, "IMB_BLEND_COLOR", IMB_BLEND_COLOR); - - PyModule_AddIntConstant(m, "IMB_BLEND_COPY", IMB_BLEND_COPY); - PyModule_AddIntConstant(m, "IMB_BLEND_COPY_RGB", IMB_BLEND_COPY_RGB); - PyModule_AddIntConstant(m, "IMB_BLEND_COPY_ALPHA", IMB_BLEND_COPY_ALPHA); - - // init last error description - Exception::m_lastError = ""; - - return m; -} - -// registration to Image types, put here because of silly linker bug |