?? z186.html
字號:
To understand <tt class="FUNCTION"> gnome_canvas_render_svp()</tt>, or to do your own RGB buffer drawing (without using <tt class="APPLICATION"> libart_lgpl</tt>), you will need to know what a <span class="STRUCTNAME">GnomeCanvasBuf</span> is: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> typedef struct { guchar *buf; int buf_rowstride; ArtIRect rect; guint32 bg_color; unsigned int is_bg : 1; unsigned int is_buf : 1;} GnomeCanvasBuf; </pre> </td> </tr> </table> <p> The <span class="STRUCTNAME">buf</span> member is an RGB buffer, as explained in <a href="z132.html#SEC-GDKRGB"> the section called <i>RGB Buffers</i> in the chapter called <i>GDK Basics</i></a>. The <span class= "STRUCTNAME">buf_rowstride</span> is the buffer's rowstride, also explained in <a href= "z132.html#SEC-GDKRGB">the section called <i>RGB Buffers</i> in the chapter called <i>GDK Basics</i></a>. An <span class="STRUCTNAME">ArtIRect</span> is an integer rectangle; <span class="STRUCTNAME">rect</span> defines the redraw region in canvas pixel coordinates that this buffer represents. <span class="STRUCTNAME"> rect.x0</span> and <span class="STRUCTNAME"> rect.y0</span> are the buffer offsets and correspond to row 0, column 0 in the RGB buffer; you can convert from canvas pixel coordinates to RGB buffer coordinates by subtracting these values. </p> <p> As an optimization, the canvas does not initialize the RGB buffer with the background color, because the first canvas item might cover the entire background anyway. Thus, if your canvas item is the first one to render, you must put some pixel value in every pixel of the redraw region defined by the buffer's <span class="STRUCTNAME"> rect</span>. If your item does not cover a pixel, you should fill that pixel with the <span class="STRUCTNAME"> bg_color</span>; <span class="STRUCTNAME">bg_color</span> is a packed RGB value (no alpha). If you do this manually, unpack an RGB value <span class="STRUCTNAME"> rgb</span> like this: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> guchar r, g, b; r = (rgb >> 16) & 0xff; g = (rgb >> 8) & 0xff; b = rgb & 0xff; </pre> </td> </tr> </table> <p> However, a convenience function is provided to fill a <span class="STRUCTNAME">GnomeCanvasBuf</span> with its <span class="STRUCTNAME">bg_color</span>: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> voidgnome_canvas_buf_ensure_buf (GnomeCanvasBuf *buf){ guchar *bufptr; int y; if (!buf->is_buf) { bufptr = buf->buf; for (y = buf->rect.y0; y < buf->rect.y1; y++) { art_rgb_fill_run (bufptr, buf->bg_color >> 16, (buf->bg_color >> 8) & 0xff, buf->bg_color & 0xff, buf->rect.x1 - buf->rect.x0); bufptr += buf->buf_rowstride; } buf->is_buf = 1; }} </pre> </td> </tr> </table> <p> As you can see from the implementation of <tt class= "FUNCTION">gnome_canvas_buf_ensure_buf()</tt>, <span class="STRUCTNAME">is_bg</span> is a flag indicating that the RGB buffer still contains random memory garbage; it has not been initialized with RGB pixels. <span class= "STRUCTNAME">is_buf</span> indicates that the buffer <i class="EMPHASIS">has</i> been initialized, and subsequent items should only draw themselves, ignoring background pixels. These two flags are mutually exclusive; if your item receives a buffer with <span class="STRUCTNAME"> is_bg</span> set, it should take steps to fill the buffer, unset <span class="STRUCTNAME">is_bg</span>, and set <span class="STRUCTNAME">is_buf</span>: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> if (buf->is_bg) { gnome_canvas_buf_ensure_buf(buf); buf->is_bg = FALSE; } </pre> </td> </tr> </table> <div class="SECT3"> <h3 class="SECT3"> <a name="Z190">Speed and RGB Rendering</a> </h3> <p> If you have a large number of objects, RGB mode can be faster than GDK mode. Drawing to an RGB buffer is a simple matter of assigning to an array, which is much, much faster than making a GDK call (since GDK has to contact the X server and ask it to do the actual drawing). The expensive part is copying the RGB buffer to the X server when you're done. However, the copy takes the same amount of time no matter how many canvas items you have, since it is done only once, when all the items have been rendered. </p> <p> This is a big win in an application called "Guppi" I'm in the process of writing. Guppi is a plot program. One of the things it has to do is render a scatter plot with tens of thousands of points. Each point is a small colored shape; if I called GDK to render each, there would be tens of thousands of trips to the X server, possibly across a network. Instead, I use the canvas in RGB mode, with a custom canvas item representing the scatter plot. This allows me to do all the rendering on the client side, and then the canvas copies the RGB buffer to the server in a single burst. It's quite fast and responsive. For less speed-intensive elements of the plot, such as the legend, I can save time and use the built-in canvas items. </p> <p> The one difficulty with direct-to-RGB rendering is that you need a rasterization library comparable to the GDK drawing primitives if you want to draw anything interesting. <tt class="APPLICATION">libart_lgpl</tt> is a very high-quality antialiased rasterization library, used by the default canvas items. You can use it in your custom items as well, and it is the best choice if you will only be drawing hundreds of shapes. If you're drawing thousands of shapes, however, you'll quickly see the need for something faster. Fortunately, this is available; the maintainers of a package called GNU Plotutils extracted the rasterization library from the X distribution, and during the development of Guppi I extracted it from Plotutils and hacked it to work with the canvas's RGB buffers. I also added alpha transparency support. The resulting library allows you to draw on an RGB buffer much as you would draw using GDK. The library is distributed under the same license as the X Window System, and is free for anyone to include with their application. </p> <p> Raph Levien, author of <span class="STRUCTNAME"> libart_lgpl</span> and the GdkRGB module, tells me that still faster routines could be written; if you need more speed, consider this a challenge. </p> </div> </div> <div class="SECT2"> <h2 class="SECT2"> <a name="Z191">The Draw Method (GDK Mode)</a> </h2> <p> Drawing with GDK is much less complicated than drawing with <tt class="APPLICATION">libart_lgpl</tt>, though it is also less flexible and produces lower-quality results. Here is the <span class="STRUCTNAME"> GnomeCanvasRect</span> implementation of the draw method: </p> <table border="0" bgcolor="#E0E0E0" width="100%"> <tr> <td><pre class="PROGRAMLISTING"> static voidgnome_canvas_rect_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height){ GnomeCanvasRE *re; double i2w[6], w2c[6], i2c[6]; int x1, y1, x2, y2; ArtPoint i1, i2; ArtPoint c1, c2; re = GNOME_CANVAS_RE (item); /* Get canvas pixel coordinates */ gnome_canvas_item_i2w_affine (item, i2w); gnome_canvas_w2c_affine (item->canvas, w2c); art_affine_multiply (i2c, i2w, w2c); i1.x = re->x1; i1.y = re->y1; i2.x = re->x2; i2.y = re->y2; art_affine_point (&c1, &i1, i2c); art_affine_point (&c2, &i2, i2c); x1 = c1.x; y1 = c1.y; x2 = c2.x; y2 = c2.y; if (re->fill_set) { if (re->fill_stipple) gnome_canvas_set_stipple_origin (item->canvas, re->fill_gc); gdk_draw_rectangle (drawable, re->fill_gc, TRUE, x1 - x, y1 - y, x2 - x1 + 1, y2 - y1 + 1); } if (re->outline_set) { if (re->outline_stipple) gnome_canvas_set_stipple_origin (item->canvas, re->outline_gc); gdk_draw_rectangle (drawable, re->outline_gc, FALSE, x1 - x, y1 - y, x2 - x1, y2 - y1); }} </pre> </td> </tr> </table> <p> The draw method receives a drawable (the buffer), the buffer offsets (<span class="STRUCTNAME">x</span> and <span class="STRUCTNAME">y</span>---the canvas pixel coordinates of the buffer), and the buffer's size (<span class="STRUCTNAME">width</span> and <span class= "STRUCTNAME">height</span>). <span class="STRUCTNAME"> GnomeCanvasRect</span>'s draw method obtains the item-to-world and world-to-canvas affines, then composes (multiplies) them to create an item-to-canvas affine. (See <a href="z174.html#SEC-AFFINES">the section called <i>Affine Transformations</i> in the chapter called <i> <tt class="CLASSNAME">GnomeCanvas</tt></i></a> for more on affines.) Using this affine, it converts the rectangle's corner points to canvas pixel coordinates; then it draws the rectangle, converting the canvas coordinates to buffer coordinates by subtracting the buffer offsets. </p> </div> </div> <div class="NAVFOOTER"> <br> <br> <table width="100%" border="0" bgcolor="#ffffff" cellpadding= "1" cellspacing="0"> <tr> <td width="25%" bgcolor="#ffffff" align="left"> <a href="cha-canvasitem.html"><font color="#0000ff" size="2"><b><<< Previous</b></font></a> </td> <td width="25%" colspan="2" bgcolor="#ffffff" align= "center"> <font color="#0000ff" size="2"><b><a href="ggad.html"> <font color="#0000ff" size="2"><b> Home</b></font></a></b></font> </td> <td width="25%" bgcolor="#ffffff" align="right"> <a href="z192.html"><font color="#0000ff" size="2"><b> Next >>></b></font></a> </td> </tr> <tr> <td colspan="2" align="left"> <font color="#000000" size="2"><b>Writing a <span class="STRUCTNAME">GnomeCanvasItem</span></b></font> </td> <td colspan="2" align="right"> <font color="#000000" size="2"><b>Other Methods</b></font> </td> </tr> </table> </div> </body></html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -