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