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