copy of docs from 2.4x for python modules that have been kept
[blender.git] / source / gameengine / VideoTexture / ImageBuff.cpp
1 /* $Id$
2 -----------------------------------------------------------------------------
3 This source file is part of VideoTexture library
4
5 Copyright (c) 2007 The Zdeno Ash Miklas
6
7 This program is free software; you can redistribute it and/or modify it under
8 the terms of the GNU Lesser General Public License as published by the Free Software
9 Foundation; either version 2 of the License, or (at your option) any later
10 version.
11
12 This program is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License along with
17 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
19 http://www.gnu.org/copyleft/lesser.txt.
20 -----------------------------------------------------------------------------
21 */
22
23 // implementation
24
25 #include <PyObjectPlus.h>
26 #include <structmember.h>
27
28 #include "ImageBuff.h"
29
30 #include "ImageBase.h"
31 #include "FilterSource.h"
32
33 // use ImBuf API for image manipulation
34 extern "C" {
35 #include "IMB_imbuf_types.h"
36 #include "IMB_imbuf.h"
37 };
38
39 // default filter
40 FilterRGB24 defFilter;
41
42 // forward declaration;
43 extern PyTypeObject ImageBuffType;
44
45 ImageBuff::~ImageBuff (void)
46 {
47         if (m_imbuf)
48                 IMB_freeImBuf(m_imbuf);
49 }
50
51
52 // load image from buffer
53 void ImageBuff::load (unsigned char * img, short width, short height)
54 {
55         // loading a new buffer implies to reset the imbuf if any, because the size may change
56         if (m_imbuf)
57         {
58                 IMB_freeImBuf(m_imbuf);
59                 m_imbuf = NULL;
60         }
61         // initialize image buffer
62         init(width, height);
63         // original size
64         short orgSize[2] = {width, height};
65         // is filter available
66         if (m_pyfilter != NULL)
67                 // use it to process image
68                 convImage(*(m_pyfilter->m_filter), img, orgSize);
69         else
70                 // otherwise use default filter
71                 convImage(defFilter, img, orgSize);
72         // image is available
73         m_avail = true;
74 }
75
76 // img must point to a array of RGBA data of size width*height
77 void ImageBuff::plot (unsigned char * img, short width, short height, short x, short y, short mode)
78 {
79         struct ImBuf* tmpbuf;
80
81         if (m_size[0] == 0 || m_size[1] == 0 || width <= 0 || height <= 0)
82                 return;
83
84         if (!m_imbuf) {
85                 // allocate most basic imbuf, we will assign the rect buffer on the fly
86                 m_imbuf = IMB_allocImBuf(m_size[0], m_size[1], 0, 0, 0);
87         }
88
89         tmpbuf = IMB_allocImBuf(width, height, 0, 0, 0);
90
91         // assign temporarily our buffer to the ImBuf buffer, we use the same format
92         tmpbuf->rect = (unsigned int*)img;
93         m_imbuf->rect = m_image;
94         IMB_rectblend(m_imbuf, tmpbuf, x, y, 0, 0, width, height, (IMB_BlendMode)mode);
95         // remove so that MB_freeImBuf will free our buffer
96         m_imbuf->rect = NULL;
97         tmpbuf->rect = NULL;
98         IMB_freeImBuf(tmpbuf);
99 }
100
101 void ImageBuff::plot (ImageBuff* img, short x, short y, short mode)
102 {
103         if (m_size[0] == 0 || m_size[1] == 0 || img->m_size[0] == 0 || img->m_size[1] == 0)
104                 return;
105
106         if (!m_imbuf) {
107                 // allocate most basic imbuf, we will assign the rect buffer on the fly
108                 m_imbuf = IMB_allocImBuf(m_size[0], m_size[1], 0, 0, 0);
109         }
110         if (!img->m_imbuf) {
111                 // allocate most basic imbuf, we will assign the rect buffer on the fly
112                 img->m_imbuf = IMB_allocImBuf(img->m_size[0], img->m_size[1], 0, 0, 0);
113         }
114         // assign temporarily our buffer to the ImBuf buffer, we use the same format
115         img->m_imbuf->rect = img->m_image;
116         m_imbuf->rect = m_image;
117         IMB_rectblend(m_imbuf, img->m_imbuf, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode);
118         // remove so that MB_freeImBuf will free our buffer
119         m_imbuf->rect = NULL;
120         img->m_imbuf->rect = NULL;
121 }
122
123
124 // cast Image pointer to ImageBuff
125 inline ImageBuff * getImageBuff (PyImage * self)
126 { return static_cast<ImageBuff*>(self->m_image); }
127
128
129 // python methods
130
131 static bool testPyBuffer(Py_buffer* buffer, int width, int height, unsigned int pixsize)
132 {
133         if (buffer->itemsize != 1)
134         {
135                 PyErr_SetString(PyExc_ValueError, "Buffer must be an array of bytes");
136                 return false;
137         } 
138         if (buffer->len != width*height*pixsize)
139         {
140                 PyErr_SetString(PyExc_ValueError, "Buffer hasn't correct size");
141                 return false;
142         } 
143         // multi dimension are ok as long as there is no hole in the memory
144         Py_ssize_t size = buffer->itemsize;
145         for (int i=buffer->ndim-1; i>=0 ; i--)
146         {
147                 if (buffer->suboffsets != NULL && buffer->suboffsets[i] >= 0)
148                 {
149                         PyErr_SetString(PyExc_ValueError, "Buffer must be of one block");
150                         return false;
151                 }
152                 if (buffer->strides != NULL && buffer->strides[i] != size)
153                 {
154                         PyErr_SetString(PyExc_ValueError, "Buffer must be of one block");
155                         return false;
156                 }
157                 if (i > 0)
158                         size *= buffer->shape[i];
159         }
160         return true;
161 }
162
163 // load image
164 static PyObject * load (PyImage * self, PyObject * args)
165 {
166         // parameters: string image buffer, its size, width, height
167         Py_buffer buffer;
168         short width;
169         short height;
170         // parse parameters
171         if (!PyArg_ParseTuple(args, "s*hh:load", &buffer, &width, &height))
172         {
173                 // report error
174                 return NULL;
175         }
176         // else check buffer size
177         else
178         {
179                 // calc proper buffer size
180                 unsigned int pixSize;
181                 // use pixel size from filter
182                 if (self->m_image->getFilter() != NULL)
183                         pixSize = self->m_image->getFilter()->m_filter->firstPixelSize();
184                 else
185                         pixSize = defFilter.firstPixelSize();
186                 // check if buffer size is correct
187                 if (testPyBuffer(&buffer, width, height, pixSize))
188                 {
189                         // if correct, load image
190                         getImageBuff(self)->load((unsigned char*)buffer.buf, width, height);
191                 }
192                 PyBuffer_Release(&buffer);
193         }
194         Py_RETURN_NONE; 
195 }
196
197 static PyObject * plot (PyImage * self, PyObject * args)
198 {
199         PyImage * other;
200         Py_buffer buffer;
201         //unsigned char * buff;
202         //unsigned int buffSize;
203         short width;
204         short height;
205         short x, y;
206         short mode = IMB_BLEND_COPY;
207
208         if (PyArg_ParseTuple(args, "s*hhhh|h:plot", &buffer, &width, &height, &x, &y, &mode))
209         {
210                 // correct decoding, verify that buffer size is correct
211                 // we need a continous memory buffer
212                 if (testPyBuffer(&buffer, width, height, 4))
213                 {
214                         getImageBuff(self)->plot((unsigned char*)buffer.buf, width, height, x, y, mode);
215                 }
216                 PyBuffer_Release(&buffer);
217                 Py_RETURN_NONE; 
218         }
219         PyErr_Clear();
220         // try the other format
221         if (!PyArg_ParseTuple(args, "O!hh|h:plot", &ImageBuffType, &other, &x, &y, &mode))
222         {
223                 PyErr_SetString(PyExc_TypeError, "Expecting ImageBuff or string,width,height as first arguments, postion x, y and mode and last arguments");
224                 return NULL;
225         }
226         getImageBuff(self)->plot(getImageBuff(other), x, y, mode);
227         Py_RETURN_NONE;
228 }
229
230 // methods structure
231 static PyMethodDef imageBuffMethods[] =
232
233         {"load", (PyCFunction)load, METH_VARARGS, "Load image from buffer"},
234         {"plot", (PyCFunction)plot, METH_VARARGS, "update image buffer"},
235         {NULL}
236 };
237 // attributes structure
238 static PyGetSetDef imageBuffGetSets[] =
239 {       // attributes from ImageBase class
240         {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
241         {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
242         {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
243         {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
244         {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
245         {NULL}
246 };
247
248
249 // define python type
250 PyTypeObject ImageBuffType =
251
252         PyVarObject_HEAD_INIT(NULL, 0)
253         "VideoTexture.ImageBuff",   /*tp_name*/
254         sizeof(PyImage),          /*tp_basicsize*/
255         0,                         /*tp_itemsize*/
256         (destructor)Image_dealloc, /*tp_dealloc*/
257         0,                         /*tp_print*/
258         0,                         /*tp_getattr*/
259         0,                         /*tp_setattr*/
260         0,                         /*tp_compare*/
261         0,                         /*tp_repr*/
262         0,                         /*tp_as_number*/
263         0,                         /*tp_as_sequence*/
264         0,                         /*tp_as_mapping*/
265         0,                         /*tp_hash */
266         0,                         /*tp_call*/
267         0,                         /*tp_str*/
268         0,                         /*tp_getattro*/
269         0,                         /*tp_setattro*/
270         0,                         /*tp_as_buffer*/
271         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
272         "Image source from image buffer",       /* tp_doc */
273         0,                             /* tp_traverse */
274         0,                             /* tp_clear */
275         0,                             /* tp_richcompare */
276         0,                             /* tp_weaklistoffset */
277         0,                             /* tp_iter */
278         0,                             /* tp_iternext */
279         imageBuffMethods,    /* tp_methods */
280         0,                   /* tp_members */
281         imageBuffGetSets,          /* tp_getset */
282         0,                         /* tp_base */
283         0,                         /* tp_dict */
284         0,                         /* tp_descr_get */
285         0,                         /* tp_descr_set */
286         0,                         /* tp_dictoffset */
287         (initproc)Image_init<ImageBuff>,     /* tp_init */
288         0,                         /* tp_alloc */
289         Image_allocNew,           /* tp_new */
290 };
291