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