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