[Bf-committers] Patch to implement Blender.Draw.Image()
Jonathan Merritt
j.merritt at pgrad.unimelb.edu.au
Sat Nov 6 09:06:59 CET 2004
Hi Everyone,
I guess this might be very poor timing (because of the CVS freeze), but
attached is a patch to implement a new function, Blender.Draw.Image():
Blender.Draw.Image(image, x, y, zoomx, zoomy, clipx, clipy, clipw, cliph):
Draws a Blender.Image on the screen using raster operations.
(image) - Blender.Image to draw.
(x, y) - Raster coordinates of the lower-left corner of the image
(can be negative).
(zoomx, zoomy) - Horizontal and vertical zoom factors.
(clipx, clipy, clipw, cliph) - Image space clipping rectangle.
Let me know if I should re-submit for consideration after the freeze.
This method is one that I'd like very much to use from within my camera
calibration script. It allows for non-pixel-aligned image drawing,
which is something I can't achieve using BGL.
Thanks,
Jonathan Merritt.
-------------- next part --------------
Index: source/blender/python/api2_2x/Draw.c
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/python/api2_2x/Draw.c,v
retrieving revision 1.30
diff -u -r1.30 Draw.c
--- source/blender/python/api2_2x/Draw.c 25 Sep 2004 20:30:39 -0000 1.30
+++ source/blender/python/api2_2x/Draw.c 6 Nov 2004 08:02:54 -0000
@@ -55,6 +55,7 @@
#include "DNA_text_types.h"
#include "BKE_global.h"
+#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_object.h"
@@ -67,6 +68,10 @@
#include "BPI_script.h" /* script struct */
+#include "Image.h" /* for accessing Blender.Image objects */
+#include "IMB_imbuf_types.h" /* for the IB_rect define */
+#include "blendef.h" /* for the CLAMP() macro */
+
#include "interface.h"
#include "mydevice.h" /*@ for all the event constants */
@@ -112,6 +117,8 @@
static PyObject *Method_PupIntInput( PyObject * self, PyObject * args );
static PyObject *Method_PupFloatInput( PyObject * self, PyObject * args );
static PyObject *Method_PupStrInput( PyObject * self, PyObject * args );
+/* next by Jonathan Merritt (lancelet): */
+static PyObject *Method_Image( PyObject * self, PyObject * args);
static uiBlock *Get_uiBlock( void );
static void py_slider_update( void *butv, void *data2_unused );
@@ -267,6 +274,14 @@
the float value show.\n\
Return the user input value or None on user exit";
+static char Method_Image_doc[] =
+ "(image, x, y, zoomx = 1.0, zoomy = 1.0, [clipx, clipy, clipw, cliph])) \n\
+ - Draw an image.\n\
+(image) - Blender.Image to draw.\n\
+(x, y) - floats specifying the location of the image.\n\
+(zoomx, zoomy) - float zoom factors in horizontal and vertical directions.\n\
+(clipx, clipy, clipw, cliph) - integers specifying a clipping rectangle within the original image.";
+
static char Method_PupStrInput_doc[] =
"(text, default, max = 20) - Display a float pop-up input.\n\
(text) - text string to display on the button;\n\
@@ -304,6 +319,7 @@
MethodDef( PupIntInput ),
MethodDef( PupFloatInput ),
MethodDef( PupStrInput ),
+ MethodDef( Image ),
MethodDef( Exit ),
MethodDef( Redraw ),
MethodDef( Draw ),
@@ -1194,6 +1210,102 @@
"couldn't create a PyString" );
}
+/*****************************************************************************
+ * Function: Method_Image *
+ * Python equivalent: Blender.Draw.Image *
+ * *
+ * @author Jonathan Merritt <j.merritt at pgrad.unimelb.edu.au> *
+ ****************************************************************************/
+static PyObject *Method_Image( PyObject * self, PyObject * args )
+{
+ PyObject *pyObjImage;
+ BPy_Image *py_img;
+ Image *image;
+ float originX, originY;
+ float zoomX = 1.0, zoomY = 1.0;
+ int clipX = 0, clipY = 0, clipW = -1, clipH = -1;
+
+ /* parse the arguments passed-in from Python */
+ if( !PyArg_ParseTuple( args, "Off|ffiiii", &pyObjImage,
+ &originX, &originY, &zoomX, &zoomY,
+ &clipX, &clipY, &clipW, &clipH ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a Blender.Image and 2 floats, and " \
+ "optionally 2 floats and 4 ints as arguments" );
+ /* check that the first PyObject is actually a Blender.Image */
+ if( !Image_CheckPyObject( pyObjImage ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a Blender.Image and 2 floats, and " \
+ "optionally 2 floats and 4 ints as arguments" );
+ /* check for valid zoom */
+ if( ( zoomX <= 0.0 ) || ( zoomY <= 0.0 ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "invalid zoom factors - they must be >= 0.0" );
+
+ /* fetch a C Image pointer from the passed-in Python object */
+ py_img = ( BPy_Image * ) pyObjImage;
+ image = py_img->image;
+
+ /* load the image data if necessary */
+ if( !image->ibuf ) /* if no image data is available */
+ load_image( image, IB_rect, "", 0 ); /* load it */
+ if( !image->ibuf ) /* failed to load the image */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ /* set up a valid clipping rectangle. if no clip rectangle was
+ * given, this results in inclusion of the entire image. otherwise,
+ * the clipping is just checked against the bounds of the image.
+ * if clipW or clipH are less than zero then they include as much of
+ * the image as they can. */
+ CLAMP( clipX, 0, image->ibuf->x );
+ CLAMP( clipY, 0, image->ibuf->y );
+ if( ( clipW < 0 ) || ( clipW > ( image->ibuf->x - clipW ) ) )
+ clipW = image->ibuf->x - clipX;
+ if( ( clipH < 0 ) || ( clipH > ( image->ibuf->y - clipH ) ) )
+ clipH = image->ibuf->y - clipY;
+
+ /* -- we are "Go" to Draw! -- */
+
+ /* set the raster position.
+ *
+ * If the raster position is negative, then using glRasterPos2i() would
+ * cause it to be clipped. Instead, we set the raster position to
+ * (0,0), which is hopefully valid, and we then use the glBitmap()
+ * method to offset it. This results in a valid, unclipped raster
+ * position whether or not it is outside of the window.
+ *
+ * This particular technique is documented in the glRasterPos() man
+ * page, although I haven't seen it used elsewhere in Blender.
+ */
+ glRasterPos2i( 0, 0 );
+ glBitmap( 0, 0, 0.0, 0.0, originX, originY, NULL );
+
+ /* set the zoom */
+ glPixelZoom( zoomX, zoomY );
+
+ /* set the width of the image (ROW_LENGTH), and the offset to the
+ * clip origin within the image in x (SKIP_PIXELS) and
+ * y (SKIP_ROWS) */
+ glPixelStorei( GL_UNPACK_ROW_LENGTH, image->ibuf->x );
+ glPixelStorei( GL_UNPACK_SKIP_PIXELS, clipX );
+ glPixelStorei( GL_UNPACK_SKIP_ROWS, clipY );
+
+ /* draw the image */
+ glDrawPixels( clipW, clipH, GL_RGBA, GL_UNSIGNED_BYTE,
+ image->ibuf->rect );
+
+ /* restore the defaults for these parameters (could also use a
+ * glPushClientAttrib() and glPopClientAttrib() pair). */
+ glPixelZoom( 1.0, 1.0 );
+ glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
+ glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
+ glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
+
+ Py_INCREF( Py_None );
+ return Py_None;
+
+}
PyObject *Draw_Init( void )
{
Index: source/blender/python/api2_2x/doc/Draw.py
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/python/api2_2x/doc/Draw.py,v
retrieving revision 1.13
diff -u -r1.13 Draw.py
--- source/blender/python/api2_2x/doc/Draw.py 16 Jul 2004 03:08:43 -0000 1.13
+++ source/blender/python/api2_2x/doc/Draw.py 6 Nov 2004 08:02:58 -0000
@@ -594,6 +594,67 @@
@return: The width of I{string} drawn with the chosen I{fontsize}.
"""
+def Image(image, x, y, zoomx=1.0, zoomy=1.0, clipx=0, clipy=0, clipw=-1, cliph=-1):
+ """
+ Draw an image on the screen.
+
+ The image is drawn at the location specified by the coordinates (x,y). A
+ pair of optional zoom factors (in horizontal and vertical directions) can
+ be applied to the image as it is drawn, and an additional clipping rectangle
+ can be applied to extract a particular sub-region of the image to draw.
+
+ Note that the clipping rectangle is given in image space coordinates. In
+ image space, the origin is located at the bottom left, with x coordinates
+ increasing to the right and y coordinates increasing upwards. No matter
+ where the clipping rectangle is placed in image space, the lower-left pixel
+ drawn on the screen is always placed at the coordinates (x,y). The
+ clipping rectangle is itself clipped to the dimensions of the image. If
+ either the width or the height of the clipping rectangle are negative then
+ the corresponding dimension (width or height) is set to include as much of
+ the image as possible.
+
+ Example::
+ import Blender
+ from Blender import BGL, Image, Draw
+
+ myimage = Image.Load('myimage.png')
+
+ def gui():
+ Draw.Image(myimage, 50, 50)
+ def event(evt, val):
+ if evt == Draw.ESCKEY:
+ Draw.Exit()
+
+ Draw.Register(gui, event, None)
+
+ @type image: Blender.Image
+ @param image: The image to draw.
+ @type x: int
+ @param x: The lower left x (horizontal) position of the origin of the image.
+ @type y: int
+ @param y: The lower left y (vertical) position of the origin of the image.
+ @type zoomx: float
+ @param zoomx: The x (horizontal) zoom factor to use when drawing the image.
+ @type zoomy: float
+ @param zoomy: The y (vertical) zoom factor to use when drawing the image.
+ @type clipx: int
+ @param clipx: The lower left x (horizontal) origin of the clipping rectangle
+ within the image. A value of 0 indicates the left of the
+ image.
+ @type clipy: int
+ @param clipy: The lower left y (vertical) origin of the clipping rectangle
+ within the image. A value of 0 indicates the bottom of the
+ image.
+ @type clipw: int
+ @param clipw: The width of the clipping rectangle within the image. If this
+ value is negative then the clipping rectangle includes as much
+ of the image as possible in the x (horizontal) direction.
+ @type cliph: int
+ @param cliph: The height of the clipping rectangle within the image. If this
+ value is negative then the clipping rectangle includes as much
+ of the image as possible in the y (vertical) direction.
+ """
+
class Button:
"""
The Button object
More information about the Bf-committers
mailing list