4ed1cd9e80132011ee9ca9559c700fd3d5dcd73f
[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 <BIF_gl.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_texInit(false)
38 {
39         // get viewport rectangle
40         glGetIntegerv(GL_VIEWPORT, m_viewport);
41         // create buffer for viewport image
42         m_viewportImage = new BYTE [3 * 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                 glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB,
136                         GL_UNSIGNED_BYTE, m_viewportImage);
137                 // filter loaded data
138                 FilterBGR24 filt;
139                 filterImage(filt, m_viewportImage, m_capSize);
140         }
141 }
142
143
144
145 // cast Image pointer to ImageViewport
146 inline ImageViewport * getImageViewport (PyImage * self)
147 { return static_cast<ImageViewport*>(self->m_image); }
148
149
150 // python methods
151
152
153 // get whole
154 static PyObject * ImageViewport_getWhole (PyImage * self, void * closure)
155 {
156         if (self->m_image != NULL && getImageViewport(self)->getWhole()) Py_RETURN_TRUE;
157         else Py_RETURN_FALSE;
158 }
159
160 // set whole
161 static int ImageViewport_setWhole (PyImage * self, PyObject * value, void * closure)
162 {
163         // check parameter, report failure
164         if (value == NULL || !PyBool_Check(value))
165         {
166                 PyErr_SetString(PyExc_TypeError, "The value must be a bool");
167                 return -1;
168         }
169         // set whole
170         if (self->m_image != NULL) getImageViewport(self)->setWhole(value == Py_True);
171         // success
172         return 0;
173 }
174
175
176 // get position
177 static PyObject * ImageViewport_getPosition (PyImage * self, void * closure)
178 {
179         return Py_BuildValue("(ii)", getImageViewport(self)->getPosition()[0],
180                 getImageViewport(self)->getPosition()[1]);
181 }
182
183 // set position
184 static int ImageViewport_setPosition (PyImage * self, PyObject * value, void * closure)
185 {
186         // check validity of parameter
187         if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2
188                 || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 0))
189                 || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 1)))
190         {
191                 PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints");
192                 return -1;
193         }
194         // set position
195         GLint pos [] = {
196                 GLint(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 0))),
197                         GLint(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 1)))
198         };
199         getImageViewport(self)->setPosition(pos);
200         // success
201         return 0;
202 }
203
204 // get capture size
205 static PyObject * ImageViewport_getCaptureSize (PyImage * self, void * closure)
206 {
207         return Py_BuildValue("(ii)", getImageViewport(self)->getCaptureSize()[0],
208                 getImageViewport(self)->getCaptureSize()[1]);
209 }
210
211 // set capture size
212 static int ImageViewport_setCaptureSize (PyImage * self, PyObject * value, void * closure)
213 {
214         // check validity of parameter
215         if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2
216                 || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 0))
217                 || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 1)))
218         {
219                 PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints");
220                 return -1;
221         }
222         // set capture size
223         short size [] = {
224                 short(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 0))),
225                         short(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 1)))
226         };
227         getImageViewport(self)->setCaptureSize(size);
228         // success
229         return 0;
230 }
231
232
233 // methods structure
234 static PyMethodDef imageViewportMethods[] =
235 { // methods from ImageBase class
236         {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
237         {NULL}
238 };
239 // attributes structure
240 static PyGetSetDef imageViewportGetSets[] =
241
242         {"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, "use whole viewport to capture", NULL},
243         {"position", (getter)ImageViewport_getPosition, (setter)ImageViewport_setPosition, "upper left corner of captured area", NULL},
244         {"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, "size of viewport area being captured", NULL},
245         // attributes from ImageBase class
246         {"image", (getter)Image_getImage, NULL, "image data", NULL},
247         {"size", (getter)Image_getSize, NULL, "image size", NULL},
248         {"scale", (getter)Image_getScale, (setter)Image_setScale, "fast scale of image (near neighbour)", NULL},
249         {"flip", (getter)Image_getFlip, (setter)Image_setFlip, "flip image vertically", NULL},
250         {"filter", (getter)Image_getFilter, (setter)Image_setFilter, "pixel filter", NULL},
251         {NULL}
252 };
253
254
255 // define python type
256 PyTypeObject ImageViewportType =
257
258         PyObject_HEAD_INIT(NULL)
259         0,                         /*ob_size*/
260         "VideoTexture.ImageViewport",   /*tp_name*/
261         sizeof(PyImage),          /*tp_basicsize*/
262         0,                         /*tp_itemsize*/
263         (destructor)Image_dealloc, /*tp_dealloc*/
264         0,                         /*tp_print*/
265         0,                         /*tp_getattr*/
266         0,                         /*tp_setattr*/
267         0,                         /*tp_compare*/
268         0,                         /*tp_repr*/
269         0,                         /*tp_as_number*/
270         0,                         /*tp_as_sequence*/
271         0,                         /*tp_as_mapping*/
272         0,                         /*tp_hash */
273         0,                         /*tp_call*/
274         0,                         /*tp_str*/
275         0,                         /*tp_getattro*/
276         0,                         /*tp_setattro*/
277         0,                         /*tp_as_buffer*/
278         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
279         "Image source from viewport",       /* tp_doc */
280         0,                             /* tp_traverse */
281         0,                             /* tp_clear */
282         0,                             /* tp_richcompare */
283         0,                             /* tp_weaklistoffset */
284         0,                             /* tp_iter */
285         0,                             /* tp_iternext */
286         imageViewportMethods,    /* tp_methods */
287         0,                   /* tp_members */
288         imageViewportGetSets,          /* tp_getset */
289         0,                         /* tp_base */
290         0,                         /* tp_dict */
291         0,                         /* tp_descr_get */
292         0,                         /* tp_descr_set */
293         0,                         /* tp_dictoffset */
294         (initproc)Image_init<ImageViewport>,     /* tp_init */
295         0,                         /* tp_alloc */
296         Image_allocNew,           /* tp_new */
297 };