5fc388bdefb6ea54e90cf8316d80d2c3380e9883
[blender.git] / source / gameengine / VideoTexture / ImageViewport.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software  Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Copyright (c) 2007 The Zdeno Ash Miklas
19  *
20  * This source file is part of VideoTexture library
21  *
22  * Contributor(s):
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file gameengine/VideoTexture/ImageViewport.cpp
28  *  \ingroup bgevideotex
29  */
30
31 // implementation
32
33 #include "PyObjectPlus.h"
34 #include <structmember.h>
35
36 #include "GL/glew.h"
37
38 #include "KX_PythonInit.h"
39 #include "Texture.h"
40 #include "ImageBase.h"
41 #include "FilterSource.h"
42 #include "ImageViewport.h"
43
44
45 // constructor
46 ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false)
47 {
48         // get viewport rectangle
49         RAS_Rect rect = KX_GetActiveEngine()->GetCanvas()->GetWindowArea();
50         m_viewport[0] = rect.GetLeft();
51         m_viewport[1] = rect.GetBottom();
52         m_viewport[2] = rect.GetWidth();
53         m_viewport[3] = rect.GetHeight();
54         
55         //glGetIntegerv(GL_VIEWPORT, m_viewport);
56         // create buffer for viewport image
57         // Warning: this buffer is also used to get the depth buffer as an array of
58         //          float (1 float = 4 bytes per pixel)
59         m_viewportImage = new BYTE [4 * getViewportSize()[0] * getViewportSize()[1]];
60         // set attributes
61         setWhole(false);
62 }
63
64 // destructor
65 ImageViewport::~ImageViewport (void)
66 {
67         delete [] m_viewportImage;
68 }
69
70
71 // use whole viewport to capture image
72 void ImageViewport::setWhole (bool whole)
73 {
74         // set whole
75         m_whole = whole;
76         // set capture size to viewport size, if whole,
77         // otherwise place area in the middle of viewport
78         for (int idx = 0; idx < 2; ++idx)
79         {
80                 // capture size
81                 m_capSize[idx] = whole ? short(getViewportSize()[idx])
82                         : calcSize(short(getViewportSize()[idx]));
83                 // position
84                 m_position[idx] = whole ? 0 : ((getViewportSize()[idx] - m_capSize[idx]) >> 1);
85         }
86         // init image
87         init(m_capSize[0], m_capSize[1]);
88         // set capture position
89         setPosition();
90 }
91
92 void ImageViewport::setCaptureSize (short size[2])
93 {
94         m_whole = false;
95         if (size == NULL) 
96                 size = m_capSize;
97         for (int idx = 0; idx < 2; ++idx)
98         {
99                 if (size[idx] < 1)
100                         m_capSize[idx] = 1;
101                 else if (size[idx] > getViewportSize()[idx])
102                         m_capSize[idx] = short(getViewportSize()[idx]);
103                 else
104                         m_capSize[idx] = size[idx];
105         }
106         init(m_capSize[0], m_capSize[1]);
107         // set capture position
108         setPosition();
109 }
110
111 // set position of capture rectangle
112 void ImageViewport::setPosition (GLint pos[2])
113 {
114         // if new position is not provided, use existing position
115         if (pos == NULL) pos = m_position;
116         // save position
117         for (int idx = 0; idx < 2; ++idx)
118                 m_position[idx] = pos[idx] < 0 ? 0 : pos[idx] >= getViewportSize()[idx]
119                 - m_capSize[idx] ? getViewportSize()[idx] - m_capSize[idx] : pos[idx];
120         // recalc up left corner
121         for (int idx = 0; idx < 2; ++idx)
122                 m_upLeft[idx] = m_position[idx] + m_viewport[idx];
123 }
124
125
126 // capture image from viewport
127 void ImageViewport::calcImage (unsigned int texId, double ts)
128 {
129         // if scale was changed
130         if (m_scaleChange)
131                 // reset image
132                 init(m_capSize[0], m_capSize[1]);
133         // if texture wasn't initialized
134         if (!m_texInit) {
135                 // initialize it
136                 loadTexture(texId, m_image, m_size);
137                 m_texInit = true;
138         }
139         // if texture can be directly created
140         if (texId != 0 && m_pyfilter == NULL && m_capSize[0] == calcSize(m_capSize[0])
141             && m_capSize[1] == calcSize(m_capSize[1]) && !m_flip && !m_zbuff && !m_depth)
142         {
143                 // just copy current viewport to texture
144                 glBindTexture(GL_TEXTURE_2D, texId);
145                 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1]);
146                 // image is not available
147                 m_avail = false;
148         }
149         // otherwise copy viewport to buffer, if image is not available
150         else if (!m_avail) {
151                 if (m_zbuff) {
152                         // Use read pixels with the depth buffer
153                         // *** misusing m_viewportImage here, but since it has the correct size
154                         //     (4 bytes per pixel = size of float) and we just need it to apply
155                         //     the filter, it's ok
156                         glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
157                                 GL_DEPTH_COMPONENT, GL_FLOAT, m_viewportImage);
158                         // filter loaded data
159                         FilterZZZA filt;
160                         filterImage(filt, (float *)m_viewportImage, m_capSize);
161                 }
162                 else {
163
164                         if (m_depth) {
165                                 // Use read pixels with the depth buffer
166                                 // See warning above about m_viewportImage.
167                                 glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
168                                         GL_DEPTH_COMPONENT, GL_FLOAT, m_viewportImage);
169                                 // filter loaded data
170                                 FilterDEPTH filt;
171                                 filterImage(filt, (float *)m_viewportImage, m_capSize);
172                         }
173                         else {
174
175                                 // get frame buffer data
176                                 if (m_alpha) {
177                                         glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA,
178                                                 GL_UNSIGNED_BYTE, m_viewportImage);
179                                         // filter loaded data
180                                         FilterRGBA32 filt;
181                                         filterImage(filt, m_viewportImage, m_capSize);
182                                 }
183                                 else {
184                                         glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB,
185                                                 GL_UNSIGNED_BYTE, m_viewportImage);
186                                         // filter loaded data
187                                         FilterRGB24 filt;
188                                         filterImage(filt, m_viewportImage, m_capSize);
189                                 }
190                         }
191                 }
192         }
193 }
194
195
196
197 // cast Image pointer to ImageViewport
198 inline ImageViewport * getImageViewport (PyImage *self)
199 { return static_cast<ImageViewport*>(self->m_image); }
200
201
202 // python methods
203
204
205 // get whole
206 PyObject *ImageViewport_getWhole (PyImage *self, void *closure)
207 {
208         if (self->m_image != NULL && getImageViewport(self)->getWhole()) Py_RETURN_TRUE;
209         else Py_RETURN_FALSE;
210 }
211
212 // set whole
213 int ImageViewport_setWhole (PyImage *self, PyObject *value, void *closure)
214 {
215         // check parameter, report failure
216         if (value == NULL || !PyBool_Check(value))
217         {
218                 PyErr_SetString(PyExc_TypeError, "The value must be a bool");
219                 return -1;
220         }
221         try
222         {
223                 // set whole, can throw in case of resize and buffer exports
224                 if (self->m_image != NULL) getImageViewport(self)->setWhole(value == Py_True);
225         }
226         catch (Exception & exp)
227         {
228                 exp.report();
229                 return -1;
230         }
231         // success
232         return 0;
233 }
234
235 // get alpha
236 PyObject *ImageViewport_getAlpha (PyImage *self, void *closure)
237 {
238         if (self->m_image != NULL && getImageViewport(self)->getAlpha()) Py_RETURN_TRUE;
239         else Py_RETURN_FALSE;
240 }
241
242 // set whole
243 int ImageViewport_setAlpha (PyImage *self, PyObject *value, void *closure)
244 {
245         // check parameter, report failure
246         if (value == NULL || !PyBool_Check(value))
247         {
248                 PyErr_SetString(PyExc_TypeError, "The value must be a bool");
249                 return -1;
250         }
251         // set alpha
252         if (self->m_image != NULL) getImageViewport(self)->setAlpha(value == Py_True);
253         // success
254         return 0;
255 }
256
257
258 // get position
259 static PyObject *ImageViewport_getPosition (PyImage *self, void *closure)
260 {
261         GLint *pos = getImageViewport(self)->getPosition();
262         PyObject *ret = PyTuple_New(2);
263         PyTuple_SET_ITEM(ret, 0, PyLong_FromLong(pos[0]));
264         PyTuple_SET_ITEM(ret, 1, PyLong_FromLong(pos[1]));
265         return ret;
266 }
267
268 // set position
269 static int ImageViewport_setPosition (PyImage *self, PyObject *value, void *closure)
270 {
271         // check validity of parameter
272         if (value == NULL ||
273             !(PyTuple_Check(value) || PyList_Check(value)) ||
274             PySequence_Fast_GET_SIZE(value) != 2 ||
275             !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) ||
276             !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1)))
277         {
278                 PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints");
279                 return -1;
280         }
281         // set position
282         GLint pos[2] = {
283             GLint(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 0))),
284             GLint(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 1)))
285         };
286         getImageViewport(self)->setPosition(pos);
287         // success
288         return 0;
289 }
290
291 // get capture size
292 PyObject *ImageViewport_getCaptureSize (PyImage *self, void *closure)
293 {
294         short *size = getImageViewport(self)->getCaptureSize();
295         PyObject *ret = PyTuple_New(2);
296         PyTuple_SET_ITEM(ret, 0, PyLong_FromLong(size[0]));
297         PyTuple_SET_ITEM(ret, 1, PyLong_FromLong(size[1]));
298         return ret;
299 }
300
301 // set capture size
302 int ImageViewport_setCaptureSize (PyImage *self, PyObject *value, void *closure)
303 {
304         // check validity of parameter
305         if (value == NULL ||
306             !(PyTuple_Check(value) || PyList_Check(value)) ||
307             PySequence_Fast_GET_SIZE(value) != 2 ||
308             !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) ||
309             !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1)))
310         {
311                 PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints");
312                 return -1;
313         }
314         // set capture size
315         short size[2] = {
316             short(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 0))),
317             short(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 1)))
318         };
319         try
320         {
321                 // can throw in case of resize and buffer exports
322                 getImageViewport(self)->setCaptureSize(size);
323         }
324         catch (Exception & exp)
325         {
326                 exp.report();
327                 return -1;
328         }
329         // success
330         return 0;
331 }
332
333
334 // methods structure
335 static PyMethodDef imageViewportMethods[] =
336 { // methods from ImageBase class
337         {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
338         {NULL}
339 };
340 // attributes structure
341 static PyGetSetDef imageViewportGetSets[] =
342
343         {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to capture", NULL},
344         {(char*)"position", (getter)ImageViewport_getPosition, (setter)ImageViewport_setPosition, (char*)"upper left corner of captured area", NULL},
345         {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of viewport area being captured", NULL},
346         {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL},
347         // attributes from ImageBase class
348         {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
349         {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
350         {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
351         {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL},
352         {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
353         {(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL},
354         {(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer as array of float", NULL},
355         {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
356         {NULL}
357 };
358
359
360 // define python type
361 PyTypeObject ImageViewportType =
362
363         PyVarObject_HEAD_INIT(NULL, 0)
364         "VideoTexture.ImageViewport",   /*tp_name*/
365         sizeof(PyImage),          /*tp_basicsize*/
366         0,                         /*tp_itemsize*/
367         (destructor)Image_dealloc, /*tp_dealloc*/
368         0,                         /*tp_print*/
369         0,                         /*tp_getattr*/
370         0,                         /*tp_setattr*/
371         0,                         /*tp_compare*/
372         0,                         /*tp_repr*/
373         0,                         /*tp_as_number*/
374         0,                         /*tp_as_sequence*/
375         0,                         /*tp_as_mapping*/
376         0,                         /*tp_hash */
377         0,                         /*tp_call*/
378         0,                         /*tp_str*/
379         0,                         /*tp_getattro*/
380         0,                         /*tp_setattro*/
381         &imageBufferProcs,         /*tp_as_buffer*/
382         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
383         "Image source from viewport",       /* tp_doc */
384         0,                             /* tp_traverse */
385         0,                             /* tp_clear */
386         0,                             /* tp_richcompare */
387         0,                             /* tp_weaklistoffset */
388         0,                             /* tp_iter */
389         0,                             /* tp_iternext */
390         imageViewportMethods,    /* tp_methods */
391         0,                   /* tp_members */
392         imageViewportGetSets,          /* tp_getset */
393         0,                         /* tp_base */
394         0,                         /* tp_dict */
395         0,                         /* tp_descr_get */
396         0,                         /* tp_descr_set */
397         0,                         /* tp_dictoffset */
398         (initproc)Image_init<ImageViewport>,     /* tp_init */
399         0,                         /* tp_alloc */
400         Image_allocNew,           /* tp_new */
401 };