Sophie

Sophie

distrib > Fedora > 15 > i386 > by-pkgid > c1088eb1b876a17e9a504ed383d0626b > files > 521

ClanLib-devel-2.1.2-2.fc15.i686.rpm

<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Drawing - ClanLib SDK</title>
<link rel="stylesheet" media="screen" type="text/css" href="clanlib.css"/>
<link rel="icon" href="gfx/favicon.png" type="image/png"/>
</head>
<body>
<div id="content">
<h1><a href="."><img src="gfx/clanlib.png" alt="ClanLib SDK" /></a></h1>
<!--
<div style="float: right;">
<a href="download.html">Download</a> :
<a href="docs.html">Documentation</a> :
<a href="development.html">Development</a> :
<a href="donations.html">Donations</a> :
<a href="http://www.rtsoft.com/clanlib">Forum</a> :
<a href="contributions.html">Contributions</a>
</div>
-->
<h2>
<img src="gfx/overview.png"/>Drawing
</h2>

<p>Drawing graphics in ClanLib is done by first acquiring an instance of the
<span class="code">CL_GraphicContext</span> interface.  Graphical contexts
can be provided by different sources, with <span
class="code">CL_DisplayWindow</span> being the common source.</p>

<p>A simple example of obtaining a graphic-context:</p>

<pre>
CL_DisplayWindow window(0, 0, 640, 480, "Hello World");
CL_GraphicContext gc = window.get_gc();
</pre>

<p>A graphic context is an interface which you can use to draw graphics and
create graphical objects like textures, shader objects and so on.  Each
graphic context has a number of states that determine how each drawing
command is to be executed.</p>

<p>If the graphic context comes from a <span
class="code">CL_DisplayWindow</span> object, it is normally written to an
off-screen buffer in order to avoid the user seeing your changes as they are being
made.  In order to change the content being drawn onto the screen, you need
to call <span class="code">CL_DisplayWindow::flip()</span> or <span
class="code">CL_DisplayWindow::update(rect)</span>.  The following example
shows how to make a ClanLib application drawing some graphics onto the
screen:</p>

<pre>
CL_SetupCore setup_core;
CL_SetupDisplay setup_display;
CL_SetupGL setup_gl;

CL_DisplayWindow window(640, 480, "Hello World");
CL_GraphicContext gc = window.get_gc();
CL_InputContext ic = window.get_ic();
CL_Font font_tahoma(gc, "Tahoma", 16);
CL_BlendMode blend_transparent;
blend_transparent.enable_blending(true);
while (ic.get_keyboard().get_keycode(CL_KEY_ESCAPE) == false)
{
	gc.clear(CL_Colord::smokewhite);
	gc.set_map_mode(cl_map_2d_upper_left);
	gc.set_blend_mode(blend_transparent);
	font_tahoma.draw_text(gc, 10, 10, "Hello There", CL_Colord::lemonchiffon);
	
	window.flip();
	CL_KeepAlive::process();
}
</pre>

<h3>High-level Rendering</h3>

<p>ClanLib provides a set of higher level classes to draw simple 2D graphics
easilly:</p>

<ul>
<li>CL_Draw</li>
<li>CL_Image</li>
<li>CL_Sprite</li>
<li>CL_Font</li>
<li>CL_SpanLayout</li>
</ul>

<p>Using these classes are fairly straight forward. In the following loop we
draw some text, show a simple image and render a gradient:</p>

<pre>
CL_Image image(gc, "image.png");
CL_Font font(gc, "Tahoma", 16);
while (ic.get_keyboard().get_keycode(CL_KEY_ESCAPE) == false)
{
	gc.clear(CL_Colord::smokewhite);
	CL_Gradient color(CL_Colorf::mediumspringgreen, CL_Colorf::honeydew);
	CL_Draw::gradient_fill(gc, 0.0f, 0.0f, 100.0f, 100.0f, color);
	image.draw(gc, 10.0f, 10.0f);
	font.draw_text(gc, 50.0f, 50.0f, "High level 2D drawing", CL_Colord::navy);
	
	window.flip();
	CL_KeepAlive::process();
}
</pre>

<p>For further information on each of these classes, see the overview
documentation dedicated to them or check the reference documentation.</p>

<h3>Low-level Rendering</h3>

<p>The graphic context class itself draws primitives, with each primitive
being a point, line segment, polygon or a rectangle of pixels. The
primitives are defined by a group of one or more vertices. A vertex defines
a point, an endpoint of an edge, or a corner of a polygon where two edges
meet. Additional data is associated with each vertex, such as colors,
normals and texture coordinates.</p>

<p>For example, a single line drawn is described as one
line-segment primitive using two vertices. The first vertex may have
position 10,10 using a red color, and the second vertex may have position
100,100 using a green color. The line drawn will then go from 10,10 to
100,100 and changing color from red to green along the line.</p>

<p>Data associated with a vertex is called a vertex attribute. In our line
drawing example the two attributes are <i>position</i> and <i>color</i> and
are assigned index 0 and 1 respectively. To draw the line we use the class <span
class="code">CL_PrimitivesArray</span> to describe our vertex data and then
we call <span class="code">draw_primitives</span> to render the line:</p>

<pre>
CL_Vec4f red_color(1.0f, 0.0f, 0.0f, 1.0f);
CL_Vec4f green_color(0.0f, 1.0f, 0.0f, 1.0f);

CL_Vec2i positions[] = { CL_Vec2i(10,10), CL_Vec2i(100,100) };
CL_Vec4f colors[] = { red_color, green_color };

CL_PrimitivesArray vertices(gc);
vertices.set_attribute(0, positions);
vertices.set_attribute(1, colors);

gc.set_program(cl_program_color_only);
gc.draw_primitives(cl_lines, 2, vertices);
</pre>

<p>The actual look and position of the line is determined by a <i>shader program</i>.
A shader program consists of two individual shaders called a vertex shader
and a fragment shader. Each shader is run at a different stage when
rendering the line. Consider the following pseudo-code for how a line is rendered:</p>

<pre>
struct Vertex
{
	VertexAttribute attributes[max_attributes];
};

struct ShadedVertex
{
	Vec2 position;
	VaryingVariable varyings[max_varyings];
};

void draw_line(Vertex v1, Vertex v2)
{
	ShadedVertex sv1 = vertex_shader(v1);
	ShadedVertex sv2 = vertex_shader(v2);
	foreach pixel covered by line (sv1.position,sv2.position)
	{
		VaryingVariable varyings[] = interpolate(pixel position, sv1, sv2);
		Color shaded_pixel = fragment_shader(varyings);
		framebuffer[pixel position] = blend_function(framebuffer_pixel, shaded_pixel);
	}
}
</pre>

<p>To do: Describe the process of rendering a primitive a lot better :)</p>



<!--




<p>The details of the first two steps can be either described by writing a
shader program, or by using the fixed function pipeline. A shader program is
a small piece of code (handled by <span
class="code">CL_ProgramObject</span>) that is compiled and uploaded to the
graphics card's processing unit (GPU), which then executes the details of the
above steps.</p>

<h3>Rendering Primitives</h3>

<p>To draw one or more primitives, you have to first construct some vertex
data, then describe your vertex data to ClanLib and finally tell the graphic
context how many vertices you got and what type of primitive you want to
render.  The following example does this to draw a rectangle:</p>

<pre>
void draw_rectangle(CL_GraphicContext &gc, const CL_Rect &rect, const CL_Colord &color)
{
	CL_Vec2i positions[] =
	{
		CL_Vec2i(rect.left, rect.top),
		CL_Vec2i(rect.right, rect.top),
		CL_Vec2i(rect.right, rect.bottom),
		CL_Vec2i(rect.left, rect.bottom)
	}
	
	CL_PrimitivesArray vertex_data(gc);
	vertex_data.set_positions(positions);
	vertex_data.set_primary_color(color);
	gc.draw_primitives(cl_polygon, 4, vertex_data);
}
</pre>

<p>As mentioned earlier, each vertex defines a point and can have additional
data associated with it.  In traditional (fixed function pipeline)
rendering, the vertex data attributes are:</p>

<div style="margin-left: 32px;">
<table>
<tr><th width=180 align=left>Attribute</th><th width=180 align=left>Shader Variable</th><th width=180 align=left>Attribute Bind Index</th></tr>
<tr><td>Position</li></td><td>gl_Vertex</td><td>0</td></tr>
<tr><td>Normal</td><td>gl_Normal</td><td>2</td></tr>
<tr><td>Primary color</td><td>gl_Color</td><td>3</td></tr>
<tr><td>Secondary color</td><td>gl_SecondaryColor</td><td>4</td></tr>
<tr><td>Fog coordinate</td><td>gl_FogCoord</td><td>5</td></tr>
<tr><td>Texture coordinates</td><td>gl_MultiTexCoord0-7</td><td>8 to 15</td></tr>
</table>
</div>

<p>You can either specify a vertex attribute by supplying an array of
values, or you can specify one single value to be applied to all vertices. 
In the above example, <span class="code">set_positions</span> specifies an
array of <span class="code">CL_Vec2i</span> values, while <span
class="code">set_primary_color</span> specifies a single value to be used
for all vertices.</p>

<p>Vertex attributes, however, are not limited to only the above listed
types.  If you write your own shader programs, the shaders can define new
attributes which you supply using <span
class="code">CL_PrimitivesArray::set_attributes</span>. The officially
defined attributes above basically just cover the types of data which the
fixed function pipeline uses - you do not have to use any of them if your
vertex shader does not.</p>

<p>The following example only uses our own special vertex attribute:</p>

<pre>
// vertex.glsl:
attribute vec1 angle;
void main()
{
	gl_Position = vec2(200+cos(radians(angle))*100.0, 200+sin(radians(angle)*100.0);
	gl_TexCoord0 = gl_Position.xy;
}

// fragment.glsl:
uniform shader2D texture;
void main()
{
	gl_FragColor = texture2D(texture, gl_TexCoord0.st);
}

// ClanLib code:
void draw_circle(CL_GraphicContext &gc, CL_Texture &texture)
{
	CL_ProgramObject program = CL_ProgramObject::load(
		gc, "vertex.glsl", "fragment.glsl");
	int angle_index = 0;
	program.bind_attribute_location(angle_index, "angle");
	program.link();
	
	int texture_index = 0;
	program.set_uniform("texture", texture_index);

	CL_Vec2i angles[360];
	for (int i = 0; i < 360; i++)
		angles[i].x = i;
	
	CL_PrimitivesArray vertex_data(gc);
	vertex_data.set_attributes(angle_index, angles);
	
	gc.set_program_object(program);
	gc.set_texture(texture_index, texture);
	gc.draw_primitives(cl_polygon, 360, vertex_data);
	gc.reset_texture(texture_index);
	gc.reset_program_object();
}
</pre>

<p>If you mix your own attributes with built-in attributes, make sure that
you do not bind the attributes to indexes already used by the built-in
attributes you use.  For example, you cannot bind <span
class="code">angle</span> in the above example to index 0 if you also use
<span class="code">gl_Vertex</span>, since gl_Vertex always uses index
0.</p>

<h3>Buffer Objects</h3>

<p>To do: introduce CL_VertexArrayBuffer and other methods to store data in
GPU memory.</p>

<h3>The Fixed Function Pipeline</h3>

<p>The fixed function pipeline can be considered a pre-written shader
program that is configured by a number of states you can set on <span
class="code">CL_GraphicContext</span> using functions such as <span
class="code">set_modelview</span>, <span
class="code">set_texture_unit</span>, <span class="code">set_light</span>,
etc.</p>

<h4>Vertex Shading</h4>

<p>The vertex transformation sequence of the fixed function pipeline is as
follows:</p>

<ul>
<li>Object coordinates -> Model-view matrix -> Eye coordinates</li>
<li>Eye coordinates -> Projection matrix -> Clip coordinates</li>
<li>Clip coordinates -> Perspective division -> Normalized (-1.0 to 1.0)
coordinates</li>
<li>Normalized coordinates -> Viewport transformation -> Window
coordinates</li>
</ul>

<p>The vertex coordinates passed along with the line-segment primitive
command are first multiplied with the model-view matrix.  This produces what
is called eye coordinates.  This set of coordinates are then multiplied with
the projection matrix, which creates clip coordinates.  A perspective
division is performed and finally the coordinates are scaled up to fit the
size of the window, i.e. (0.0,0.0) in normalized coordinates maps to the
center of the window.</p>

<p>The above transformation sequence is mostly useful for drawing 3D and can
be somewhat complicated to work with when doing 2D drawing operations.
ClanLib therefore offers a function on the graphic context, <span
class="code">CL_GraphicContext::set_map_mode</span>, which preconfigures
certain parts of the sequence.  If the mapping mode is set to <span
class="code">cl_map_2d_upper_left</span> then the projection matrix and
viewport transformation will be configured to let eye coordinates map to
window coordinates.  So eye coordinates of (0,0) will map to the upper left
corner, and (100,100) will map to 100 pixels down and 100 pixels to the
right. Likewise, <span class="code">cl_map_2d_lower_left</span> will do the
same but with (0,0) being lower left corner and the y-axis going
upwards.</p>

<p>Each vertex have two colors, the primary and secondary color.  If
lighting is enabled in the pipeline, the primary and secondary color is
calculated by applying all active <span class="code">CL_LightSource</span>
objects. The colors are set by using the currently active <span
class="code">CL_Material</span> object, the position of the light sources
and the position of the vertex itself. For further detail on how light is
applied, see the OpenGL specification.</p>

<h4>Fragment Shading</h4>

<p>After the vertices have been processed, the primitive being drawn (a line
in our example) is realized by generating fragments for each pixel the line
covers. For example, a fragment for (10,10), one for (11,11), another for
(12,12), etc.</p>

<p>Each of these fragments go through the following steps which determine what
color the fragment gets:</p>

<ul>
<li>Texturing</li>
<li>Color Sum</li>
<li>Fog</li>
</ul>

<p>Texturing maps a portion of one or more specified images onto each
primitive for which texturing is enabled. The mapping is accomplished by
using the color of an image at the location indicated by texture
coordinates.  Each vertex carries multiple sets of texture coordinates, one
for each active texture unit.  If we take the line segment example again,
the first vertex at (10,10) may have a texture coordinate for texture unit 1
saying (0.0,0.0) and at second vertex at (100,100) it might say (1.0,1.0).
The fragment located at (50,50) will then have the texture coordinate of
(0.5,0.5). Likewise it might have another set for texture unit 2, going from
(1.0,1.0) to (0.0,0.0)</p>

<p>The color in the image located at the texture coordinate position is
called a texel. The texel and the primary color of the fragment is blended
by the texturing unit based on the currently active texture function. When
using several texture units, the result of the first texturing unit is
passed into the next texture unit. A texture unit's texture function can be
described as a function with the following syntax:</p>

<pre>
color = texture_function(
		fragment_primary_color,
		texel_color,
		result_color_from_previous_unit);
</pre>

<p>The result returned by the last of the active texture units will be the new
primary color of the fragment.</p>

<p>After the texturing step, a color sum between the fragment primary color
and secondary color is applied. The resulting color of the fragment will
then be <span class="code">normalize(primary_color+secondary_color)</span>.
Finally fog coloring is applied to the fragment color, if enabled.</p>

<h4>Blending Fragments with the Frame Buffer</h4>

<p>The last step of rendering a primitive is to apply the fragments to the
frame buffer. This is done by running a few tests on the fragment and then a
blending operation with the pixel in the frame buffer.  The steps are as
follows:</p>

<ul>
<li>Scissor (Clipping) Test</li>
<li>Alpha Test</li>
<li>Stencil Test</li>
<li>Depth Buffer Test</li>
<li>Blending</li>
<li>Dithering</li>
<li>Logical Operation</li>
</ul>

<p>The scissor test checks if the fragment is inside the clipping rectangle
of the graphic context.  The alpha test, if enabled, checks if the alpha
part of the fragment color is above, equal or below a specified value.  The
stencil test discards a fragment based on the outcome of a comparison
between the value in the stencil buffer and the fragment.  Likewise, the
depth buffer test compares the fragment to the value in the depth buffer. 
All these tests are configured by the <span class="code">CL_BufferControl</span>
states in the graphic context.  If the fragment fails any of these tests,
the fragment is dropped.</p>

<p>If blending is enabled (<span class="code">CL_BlendMode</span>), the
color of the fragment will be changed to a value calculated by the blending
function. The blending functions use the color of the fragment
and the current color of the pixel in the frame buffer beneath the fragment. 
If blending is not enabled, the fragment color will always become the new
color in the frame buffer, no matter what value the alpha part of the color
is.</p>

<p>Finally, a logical operation is applied between the incoming fragment's
color and the color in the frame buffer. The result of this operation
becomes the new color in the frame buffer.</p>
-->
</div>

</body>
</html>