diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/python/generic/BGL.c | 65 | ||||
-rw-r--r-- | source/blender/python/generic/BGL.h | 37 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/Exception.cpp | 2 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/Exception.h | 2 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/ImageBase.cpp | 170 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/ImageBase.h | 15 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/ImageBuff.cpp | 102 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/ImageMix.cpp | 3 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/ImageRender.cpp | 6 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/ImageViewport.cpp | 26 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/Makefile | 1 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/SConscript | 2 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/Texture.cpp | 2 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/VideoFFmpeg.cpp | 14 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/VideoFFmpeg.h | 3 | ||||
-rw-r--r-- | source/gameengine/VideoTexture/blendVideoTex.cpp | 16 |
17 files changed, 365 insertions, 102 deletions
diff --git a/source/blender/python/generic/BGL.c b/source/blender/python/generic/BGL.c index 2318549f2ec..340ebbe3dcd 100644 --- a/source/blender/python/generic/BGL.c +++ b/source/blender/python/generic/BGL.c @@ -36,9 +36,6 @@ #include <GL/glew.h> #include "MEM_guardedalloc.h" -static int type_size( int type ); -static Buffer *make_buffer( int type, int ndimensions, int *dimensions ); - static char Method_Buffer_doc[] = "(type, dimensions, [template]) - Create a new Buffer object\n\n\ (type) - The format to store data in\n\ @@ -82,7 +79,7 @@ static PyObject *Buffer_dimensions( PyObject * self ); static PyObject *Buffer_getattr( PyObject * self, char *name ); static PyObject *Buffer_repr( PyObject * self ); -PyTypeObject buffer_Type = { +PyTypeObject BGL_bufferType = { PyVarObject_HEAD_INIT(NULL, 0) "buffer", /*tp_name */ sizeof( Buffer ), /*tp_basicsize */ @@ -120,7 +117,7 @@ static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\ /* #endif */ /********/ -static int type_size(int type) +int BGL_typeSize(int type) { switch (type) { case GL_BYTE: @@ -137,7 +134,7 @@ static int type_size(int type) return -1; } -static Buffer *make_buffer(int type, int ndimensions, int *dimensions) +Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuffer) { Buffer *buffer; void *buf= NULL; @@ -147,39 +144,49 @@ static Buffer *make_buffer(int type, int ndimensions, int *dimensions) for (i=0; i<ndimensions; i++) length*= dimensions[i]; - size= type_size(type); + size= BGL_typeSize(type); buf= MEM_mallocN(length*size, "Buffer buffer"); - - buffer= (Buffer *) PyObject_NEW(Buffer, &buffer_Type); + + buffer= (Buffer *) PyObject_NEW(Buffer, &BGL_bufferType); buffer->parent= NULL; buffer->ndimensions= ndimensions; - buffer->dimensions= dimensions; + buffer->dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions"); + memcpy(buffer->dimensions, dimensions, ndimensions*sizeof(int)); buffer->type= type; buffer->buf.asvoid= buf; - for (i= 0; i<length; i++) { - if (type==GL_BYTE) - buffer->buf.asbyte[i]= 0; - else if (type==GL_SHORT) - buffer->buf.asshort[i]= 0; - else if (type==GL_INT) - buffer->buf.asint[i]= 0; - else if (type==GL_FLOAT) - buffer->buf.asfloat[i]= 0.0f; - else if (type==GL_DOUBLE) - buffer->buf.asdouble[i]= 0.0; + if (initbuffer) { + memcpy(buffer->buf.asvoid, initbuffer, length*size); + } else { + memset(buffer->buf.asvoid, 0, length*size); + /* + for (i= 0; i<length; i++) { + if (type==GL_BYTE) + buffer->buf.asbyte[i]= 0; + else if (type==GL_SHORT) + buffer->buf.asshort[i]= 0; + else if (type==GL_INT) + buffer->buf.asint[i]= 0; + else if (type==GL_FLOAT) + buffer->buf.asfloat[i]= 0.0f; + else if (type==GL_DOUBLE) + buffer->buf.asdouble[i]= 0.0; + } + */ } return buffer; } +#define MAX_DIMENSIONS 256 static PyObject *Method_Buffer (PyObject *self, PyObject *args) { PyObject *length_ob= NULL, *template= NULL; Buffer *buffer; + int dimensions[MAX_DIMENSIONS]; int i, type; - int *dimensions = 0, ndimensions = 0; + int ndimensions = 0; if (!PyArg_ParseTuple(args, "iO|O", &type, &length_ob, &template)) { PyErr_SetString(PyExc_AttributeError, "expected an int and one or two PyObjects"); @@ -192,11 +199,13 @@ static PyObject *Method_Buffer (PyObject *self, PyObject *args) if (PyNumber_Check(length_ob)) { ndimensions= 1; - dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions"); dimensions[0]= PyLong_AsLong(length_ob); } else if (PySequence_Check(length_ob)) { ndimensions= PySequence_Length(length_ob); - dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions"); + if (ndimensions > MAX_DIMENSIONS) { + PyErr_SetString(PyExc_AttributeError, "too many dimensions, max is 256"); + return NULL; + } for (i=0; i<ndimensions; i++) { PyObject *ob= PySequence_GetItem(length_ob, i); @@ -206,7 +215,7 @@ static PyObject *Method_Buffer (PyObject *self, PyObject *args) } } - buffer= make_buffer(type, ndimensions, dimensions); + buffer= BGL_MakeBuffer(type, ndimensions, dimensions, NULL); if (template && ndimensions) { if (Buffer_ass_slice((PyObject *) buffer, 0, dimensions[0], template)) { Py_DECREF(buffer); @@ -250,9 +259,9 @@ static PyObject *Buffer_item(PyObject *self, int i) for (j=1; j<buf->ndimensions; j++) { length*= buf->dimensions[j]; } - size= type_size(buf->type); + size= BGL_typeSize(buf->type); - newbuf= (Buffer *) PyObject_NEW(Buffer, &buffer_Type); + newbuf= (Buffer *) PyObject_NEW(Buffer, &BGL_bufferType); Py_INCREF(self); newbuf->parent= self; @@ -1104,7 +1113,7 @@ PyObject *BGL_Init(void) PyDict_SetItemString(PySys_GetObject("modules"), BGL_module_def.m_name, mod); dict= PyModule_GetDict(mod); - if( PyType_Ready( &buffer_Type) < 0) + if( PyType_Ready( &BGL_bufferType) < 0) return NULL; /* should never happen */ #define EXPP_ADDCONST(x) PyDict_SetItemString(dict, #x, item=PyLong_FromLong((int)x)); Py_DECREF(item) diff --git a/source/blender/python/generic/BGL.h b/source/blender/python/generic/BGL.h index 32076f4fba8..89bade930ce 100644 --- a/source/blender/python/generic/BGL.h +++ b/source/blender/python/generic/BGL.h @@ -44,9 +44,16 @@ PyObject *BGL_Init(void); +/*@ Create a buffer object */ +/*@ dimensions is an array of ndimensions integers representing the size of each dimension */ +/*@ initbuffer if not NULL holds a contiguous buffer with the correct format from which the buffer will be initialized */ +struct _Buffer *BGL_MakeBuffer( int type, int ndimensions, int *dimensions, void *initbuffer ); +/*@ Return the size of buffer element, type must be one of GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT or GL_DOUBLE */ +/*@ returns -1 otherwise */ +int BGL_typeSize( int type ); + /*@ Buffer Object */ /*@ For Python access to OpenGL functions requiring a pointer. */ - typedef struct _Buffer { PyObject_VAR_HEAD PyObject * parent; @@ -66,6 +73,8 @@ typedef struct _Buffer { } buf; } Buffer; +/*@ The type object */ +extern PyTypeObject BGL_bufferType; /*@ By golly George! It looks like fancy pants macro time!!! */ @@ -93,7 +102,7 @@ typedef struct _Buffer { #define buffer_str "O!" #define buffer_var(number) (bgl_buffer##number)->buf.asvoid -#define buffer_ref(number) &buffer_Type, &bgl_buffer##number +#define buffer_ref(number) &BGL_bufferType, &bgl_buffer##number #define buffer_def(number) Buffer *bgl_buffer##number /* GL Pointer fields, handled by buffer type */ @@ -101,62 +110,62 @@ typedef struct _Buffer { #define GLbooleanP_str "O!" #define GLbooleanP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLbooleanP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLbooleanP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLbooleanP_def(number) Buffer *bgl_buffer##number #define GLbyteP_str "O!" #define GLbyteP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLbyteP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLbyteP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLbyteP_def(number) Buffer *bgl_buffer##number #define GLubyteP_str "O!" #define GLubyteP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLubyteP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLubyteP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLubyteP_def(number) Buffer *bgl_buffer##number #define GLintP_str "O!" #define GLintP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLintP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLintP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLintP_def(number) Buffer *bgl_buffer##number #define GLuintP_str "O!" #define GLuintP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLuintP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLuintP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLuintP_def(number) Buffer *bgl_buffer##number #define GLshortP_str "O!" #define GLshortP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLshortP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLshortP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLshortP_def(number) Buffer *bgl_buffer##number #define GLushortP_str "O!" #define GLushortP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLushortP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLushortP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLushortP_def(number) Buffer *bgl_buffer##number #define GLfloatP_str "O!" #define GLfloatP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLfloatP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLfloatP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLfloatP_def(number) Buffer *bgl_buffer##number #define GLdoubleP_str "O!" #define GLdoubleP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLdoubleP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLdoubleP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLdoubleP_def(number) Buffer *bgl_buffer##number #define GLclampfP_str "O!" #define GLclampfP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLclampfP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLclampfP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLclampfP_def(number) Buffer *bgl_buffer##number #define GLvoidP_str "O!" #define GLvoidP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLvoidP_ref(number) &buffer_Type, &bgl_buffer##number +#define GLvoidP_ref(number) &BGL_bufferType, &bgl_buffer##number #define GLvoidP_def(number) Buffer *bgl_buffer##number #define buffer_str "O!" #define buffer_var(number) (bgl_buffer##number)->buf.asvoid -#define buffer_ref(number) &buffer_Type, &bgl_buffer##number +#define buffer_ref(number) &BGL_bufferType, &bgl_buffer##number #define buffer_def(number) Buffer *bgl_buffer##number /*@The standard GL typedefs are used as prototypes, we can't diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt index 1268d887eee..eaee00753ff 100644 --- a/source/gameengine/VideoTexture/CMakeLists.txt +++ b/source/gameengine/VideoTexture/CMakeLists.txt @@ -42,6 +42,7 @@ SET(INC ../../../source/blender/editors/include ../../../source/blender/imbuf ../../../source/blender/python + ../../../source/blender/python/generic ../../../source/blender/gpu ../../../source/kernel/gen_system ../../../intern/string diff --git a/source/gameengine/VideoTexture/Exception.cpp b/source/gameengine/VideoTexture/Exception.cpp index 8b4808ffbe9..124c8ae27d8 100644 --- a/source/gameengine/VideoTexture/Exception.cpp +++ b/source/gameengine/VideoTexture/Exception.cpp @@ -202,6 +202,8 @@ void registerAllExceptions(void) errNFoundDesc.registerDesc(); MaterialNotAvailDesc.registerDesc(); ImageSizesNotMatchDesc.registerDesc(); + ImageHasExportsDesc.registerDesc(); + InvalidColorChannelDesc.registerDesc(); SceneInvalidDesc.registerDesc(); CameraInvalidDesc.registerDesc(); ObserverInvalidDesc.registerDesc(); diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h index 4a57a7f20e4..74dc444c0a9 100644 --- a/source/gameengine/VideoTexture/Exception.h +++ b/source/gameengine/VideoTexture/Exception.h @@ -200,6 +200,8 @@ protected: extern ExpDesc MaterialNotAvailDesc; extern ExpDesc ImageSizesNotMatchDesc; +extern ExpDesc ImageHasExportsDesc; +extern ExpDesc InvalidColorChannelDesc; extern ExpDesc SceneInvalidDesc; extern ExpDesc CameraInvalidDesc; extern ExpDesc ObserverInvalidDesc; diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp index 1c5425c932c..908aa5ddd5e 100644 --- a/source/gameengine/VideoTexture/ImageBase.cpp +++ b/source/gameengine/VideoTexture/ImageBase.cpp @@ -21,6 +21,10 @@ http://www.gnu.org/copyleft/lesser.txt. */ #include "ImageBase.h" +extern "C" { +#include "BGL.h" +} +#include "GL/glew.h" #include <vector> #include <string.h> @@ -32,7 +36,9 @@ http://www.gnu.org/copyleft/lesser.txt. #include "Exception.h" - +#if (defined(WIN32) || defined(WIN64)) && !defined(FREE_WINDOWS) +#define strcasecmp _stricmp +#endif // ImageBase class implementation @@ -42,6 +48,7 @@ m_avail(false), m_scale(false), m_scaleChange(false), m_flip(false), m_staticSources(staticSrc), m_pyfilter(NULL) { m_size[0] = m_size[1] = 0; + m_exports = 0; } @@ -161,6 +168,11 @@ void ImageBase::setFilter (PyFilter * filt) m_pyfilter = filt; } +ExceptionID ImageHasExports; +ExceptionID InvalidColorChannel; + +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"); // initialize image data void ImageBase::init (short width, short height) @@ -175,6 +187,9 @@ void ImageBase::init (short width, short 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 @@ -352,6 +367,12 @@ 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; @@ -360,17 +381,88 @@ void Image_dealloc (PyImage * self) } // get image data -PyObject * Image_getImage (PyImage * self, void * closure) +PyObject * Image_getImage (PyImage * self, char * mode) { try { - // get image unsigned int * image = self->m_image->getImage(); - return Py_BuildValue("s#", image, self->m_image->getBuffSize()); + 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 + { + 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; } @@ -533,3 +625,73 @@ int Image_setFilter (PyImage * self, PyObject * value, void * closure) // return success return 0; } +PyObject * Image_valid(PyImage * self, void * closure) +{ + if (self->m_image->isImageAvailable()) + { + Py_RETURN_TRUE; + } + else + { + Py_RETURN_FALSE; + } +} + +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) + { + // cannot return -1, this creates a crash in Python, for now we will just return an empty buffer + //exp.report(); + //return -1; + goto error; + } + + if (!image) + { + // same remark, see above + //PyErr_SetString(PyExc_BufferError, "Image buffer is not available"); + //return -1; + goto error; + } + 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; + +error: + // Return a empty buffer to avoid a crash in Python 3.1 + // The bug is fixed in Python SVN 77916, as soon as the python revision used by Blender is + // updated, you can simply return -1 and set the error + static char* buf = ""; + ret = PyBuffer_FillInfo(view, (PyObject*)self, buf, 0, 0, flags); + if (ret >= 0) + self->m_image->m_exports++; + return ret; + +} + +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 index 70b1929b91d..43a56290bee 100644 --- a/source/gameengine/VideoTexture/ImageBase.h +++ b/source/gameengine/VideoTexture/ImageBase.h @@ -53,6 +53,9 @@ public: /// 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 @@ -85,6 +88,9 @@ public: /// calculate size (nearest power of 2) static short calcSize (short size); + /// number of buffer pointing to m_image, public because not handled by this class + int m_exports; + protected: /// image buffer unsigned int * m_image; @@ -295,8 +301,6 @@ private: ImageSource (void) {} }; - - // list of python image types extern PyTypeList pyImageTypes; @@ -320,7 +324,7 @@ PyObject * Image_allocNew (PyTypeObject * type, PyObject * args, PyObject * kwds void Image_dealloc (PyImage * self); // get image data -PyObject * Image_getImage (PyImage * self, void * closure); +PyObject * Image_getImage (PyImage * self, char * mode); // get image size PyObject * Image_getSize (PyImage * self, void * closure); // refresh image - invalidate current content @@ -344,6 +348,9 @@ PyObject * Image_setSource (PyImage * self, PyObject * args); 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 index eccac9d9f89..474a34b2f43 100644 --- a/source/gameengine/VideoTexture/ImageBuff.cpp +++ b/source/gameengine/VideoTexture/ImageBuff.cpp @@ -26,7 +26,7 @@ http://www.gnu.org/copyleft/lesser.txt. #include <structmember.h> #include "ImageBuff.h" - +#include "Exception.h" #include "ImageBase.h" #include "FilterSource.h" @@ -34,6 +34,7 @@ http://www.gnu.org/copyleft/lesser.txt. extern "C" { #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "BGL.h" }; // default filter @@ -137,7 +138,7 @@ static bool testPyBuffer(Py_buffer* buffer, int width, int height, unsigned int } if (buffer->len != width*height*pixsize) { - PyErr_SetString(PyExc_ValueError, "Buffer hasn't correct size"); + 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 @@ -160,43 +161,91 @@ static bool testPyBuffer(Py_buffer* buffer, int width, int height, unsigned int 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)) { - // report error - return NULL; + 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 buffer size else { - // calc proper buffer size - unsigned int pixSize; - // use pixel size from filter - if (self->m_image->getFilter() != NULL) - pixSize = self->m_image->getFilter()->m_filter->firstPixelSize(); - else - pixSize = defFilter.firstPixelSize(); // check if buffer size is correct if (testPyBuffer(&buffer, width, height, pixSize)) { - // if correct, load image - getImageBuff(self)->load((unsigned char*)buffer.buf, width, height); + 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; @@ -214,17 +263,31 @@ static PyObject * plot (PyImage * self, PyObject * args) 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)) + if (PyArg_ParseTuple(args, "O!hh|h:plot", &ImageBuffType, &other, &x, &y, &mode)) { - PyErr_SetString(PyExc_TypeError, "Expecting ImageBuff or string,width,height as first arguments, postion x, y and mode and last arguments"); + 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; } - getImageBuff(self)->plot(getImageBuff(other), x, y, mode); - Py_RETURN_NONE; + 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 @@ -237,6 +300,7 @@ static PyMethodDef imageBuffMethods[] = // 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 neighbour)", NULL}, @@ -267,7 +331,7 @@ PyTypeObject ImageBuffType = 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + &imageBufferProcs, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "Image source from image buffer", /* tp_doc */ 0, /* tp_traverse */ diff --git a/source/gameengine/VideoTexture/ImageMix.cpp b/source/gameengine/VideoTexture/ImageMix.cpp index a4a61e7f55a..7b304dda3ce 100644 --- a/source/gameengine/VideoTexture/ImageMix.cpp +++ b/source/gameengine/VideoTexture/ImageMix.cpp @@ -154,6 +154,7 @@ static PyMethodDef imageMixMethods[] = // 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 neighbour)", NULL}, @@ -184,7 +185,7 @@ PyTypeObject ImageMixType = 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + &imageBufferProcs, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "Image mixer", /* tp_doc */ 0, /* tp_traverse */ diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index 0a01ce11a0e..d654bc14114 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -365,6 +365,7 @@ static PyGetSetDef imageRenderGetSets[] = {(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 neighbour)", NULL}, @@ -395,7 +396,7 @@ PyTypeObject ImageRenderType = 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + &imageBufferProcs, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "Image source from render", /* tp_doc */ 0, /* tp_traverse */ @@ -526,6 +527,7 @@ static PyGetSetDef imageMirrorGetSets[] = {(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 neighbour)", NULL}, @@ -729,7 +731,7 @@ PyTypeObject ImageMirrorType = 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + &imageBufferProcs, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "Image source from mirror", /* tp_doc */ 0, /* tp_traverse */ diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp index c39173a96f9..5a4e8af1b0c 100644 --- a/source/gameengine/VideoTexture/ImageViewport.cpp +++ b/source/gameengine/VideoTexture/ImageViewport.cpp @@ -177,8 +177,16 @@ int ImageViewport_setWhole (PyImage * self, PyObject * value, void * closure) PyErr_SetString(PyExc_TypeError, "The value must be a bool"); return -1; } - // set whole - if (self->m_image != NULL) getImageViewport(self)->setWhole(value == Py_True); + 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; } @@ -257,7 +265,16 @@ int ImageViewport_setCaptureSize (PyImage * self, PyObject * value, void * closu short(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 0))), short(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 1))) }; - getImageViewport(self)->setCaptureSize(size); + try + { + // can throw in case of resize and buffer exports + getImageViewport(self)->setCaptureSize(size); + } + catch (Exception & exp) + { + exp.report(); + return -1; + } // success return 0; } @@ -277,6 +294,7 @@ static PyGetSetDef imageViewportGetSets[] = {(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 neighbour)", NULL}, @@ -307,7 +325,7 @@ PyTypeObject ImageViewportType = 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + &imageBufferProcs, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "Image source from viewport", /* tp_doc */ 0, /* tp_traverse */ diff --git a/source/gameengine/VideoTexture/Makefile b/source/gameengine/VideoTexture/Makefile index 90457df720f..1cb147860cd 100644 --- a/source/gameengine/VideoTexture/Makefile +++ b/source/gameengine/VideoTexture/Makefile @@ -41,6 +41,7 @@ CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) CPPFLAGS += -I../../blender/python +CPPFLAGS += -I../../blender/python/generic CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I../Rasterizer/RAS_OpenGLRasterizer diff --git a/source/gameengine/VideoTexture/SConscript b/source/gameengine/VideoTexture/SConscript index 59c311d5240..70c7dfc6d3a 100644 --- a/source/gameengine/VideoTexture/SConscript +++ b/source/gameengine/VideoTexture/SConscript @@ -10,7 +10,7 @@ incs += ' #source/gameengine/GameLogic #source/gameengine/SceneGraph #source/gam incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer' incs += ' #source/gameengine/BlenderRoutines' incs += ' #source/blender/editors/include #source/blender/blenlib #source/blender/blenkernel' -incs += ' #source/blender/makesdna #source/blender/imbuf #source/blender/python' +incs += ' #source/blender/makesdna #source/blender/imbuf #source/blender/python #source/blender/python/generic' incs += ' #source/blender/gpu #source/kernel/gen_system #intern/string #intern/moto/include' incs += ' #intern/guardedalloc #extern/glew/include' diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp index f59b92409f5..b8ed38c435d 100644 --- a/source/gameengine/VideoTexture/Texture.cpp +++ b/source/gameengine/VideoTexture/Texture.cpp @@ -455,7 +455,7 @@ PyTypeObject TextureType = 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + &imageBufferProcs, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "Texture objects", /* tp_doc */ 0, /* tp_traverse */ diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp index 4c87b1764d6..c33cb9a671d 100644 --- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp +++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp @@ -723,14 +723,8 @@ void VideoFFmpeg::setFrameRate (float rate) // image calculation -void VideoFFmpeg::calcImage (unsigned int texId, double ts) -{ - loadFrame(ts); -} - - // load frame from video -void VideoFFmpeg::loadFrame (double ts) +void VideoFFmpeg::calcImage (unsigned int texId, double ts) { if (m_status == SourcePlaying) { @@ -1162,6 +1156,7 @@ static PyGetSetDef videoGetSets[] = {(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 neighbour)", NULL}, @@ -1193,7 +1188,7 @@ PyTypeObject VideoFFmpegType = 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + &imageBufferProcs, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "FFmpeg video source", /* tp_doc */ 0, /* tp_traverse */ @@ -1282,6 +1277,7 @@ 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 neighbour)", NULL}, @@ -1311,7 +1307,7 @@ PyTypeObject ImageFFmpegType = 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ + &imageBufferProcs, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "FFmpeg image source", /* tp_doc */ 0, /* tp_traverse */ diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.h b/source/gameengine/VideoTexture/VideoFFmpeg.h index 355c58c496b..b9bf69039c7 100644 --- a/source/gameengine/VideoTexture/VideoFFmpeg.h +++ b/source/gameengine/VideoTexture/VideoFFmpeg.h @@ -159,9 +159,6 @@ protected: /// image calculation virtual void calcImage (unsigned int texId, double ts); - /// load frame from video - void loadFrame (double ts); - /// set actual position void setPositions (void); diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp index 998d63506b0..01e783edc10 100644 --- a/source/gameengine/VideoTexture/blendVideoTex.cpp +++ b/source/gameengine/VideoTexture/blendVideoTex.cpp @@ -86,7 +86,8 @@ static PyObject * imageToArray (PyObject * self, PyObject *args) { // parameter is Image object PyObject * pyImg; - if (!PyArg_ParseTuple(args, "O:imageToArray", &pyImg) || !pyImageTypes.in(pyImg->ob_type)) + char *mode = NULL; + if (!PyArg_ParseTuple(args, "O|s:imageToArray", &pyImg, &mode) || !pyImageTypes.in(pyImg->ob_type)) { // if object is incorect, report error PyErr_SetString(PyExc_TypeError, "VideoTexture.imageToArray(image): The value must be a image source object"); @@ -94,16 +95,7 @@ static PyObject * imageToArray (PyObject * self, PyObject *args) } // get image structure PyImage * img = reinterpret_cast<PyImage*>(pyImg); - // create array object - unsigned int * imgBuff = img->m_image->getImage(); - // if image is available, convert it to array - if (imgBuff != NULL) - // Nasty problem here: the image buffer is an array of integers - // in the processor endian format. The user must take care of that in the script. - // Need to find an elegant solution to this problem - return Py_BuildValue("s#", imgBuff, img->m_image->getBuffSize()); - // otherwise return None - Py_RETURN_NONE; + return Image_getImage(img, mode); } @@ -113,7 +105,7 @@ static PyMethodDef moduleMethods[] = {"materialID", getMaterialID, METH_VARARGS, "Gets object's Blender Material ID"}, {"getLastError", getLastError, METH_NOARGS, "Gets last error description"}, {"setLogFile", setLogFile, METH_VARARGS, "Sets log file name"}, - {"imageToArray", imageToArray, METH_VARARGS, "get array from image source"}, + {"imageToArray", imageToArray, METH_VARARGS, "get buffer from image source, color channels are selectable"}, {NULL} /* Sentinel */ }; |