1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
#include <ClanLib/application.h>
#include <ClanLib/core.h>
#include <ClanLib/display.h>
#include <ClanLib/gl.h>
class Application : public CL_ClanApplication
{
public:
virtual int main(int argc, char** argv)
{
CL_ConsoleWindow debug_console("Debug console");
debug_console.redirect_stdio();
try
{
CL_SetupCore setup_core;
CL_SetupDisplay setup_display;
CL_SetupGL setup_gl;
CL_DisplayWindow window("ClanLib Stencil Demo", 800,600, false);
stencil_test(window);
}
catch (CL_Error error)
{
std::cout << "Uncaught error: " << error.message.c_str() << std::endl;
debug_console.display_close_message();
}
return 0;
}
void stencil_test(CL_DisplayWindow &window)
{
// load surfaces
CL_Surface wheel("images/wheel.png");
CL_Surface text("images/stencil_text.png");
CL_Surface highlight("images/clouds.png");
CL_Surface spot("images/spot.png");
// set alignment of surfaces to centered.
text.set_alignment(origin_center);
wheel.set_alignment(origin_center);
highlight.set_alignment(origin_center);
// set rotation hotspots to center.
wheel.set_rotation_hotspot(origin_center);
highlight.set_rotation_hotspot(origin_center);
// change blendfunc of highlight to additive
highlight.set_blend_func( blend_src_alpha, blend_one );
spot.set_alignment(origin_bottom_center);
spot.set_rotation_hotspot(origin_bottom_center);
// get graphics context handle
CL_GraphicContext *gc = window.get_gc();
int width = CL_Display::get_width();
int height = CL_Display::get_height();
float sin_count = 0;
int angle = 0;
int highlight_angle = 0;
while(!CL_Keyboard::get_keycode(CL_KEY_ESCAPE))
{
sin_count += (float) (M_PI/180.0);
angle += 2;
highlight_angle += 8;
int a=int(255.f*fabs(sin(sin_count))) - 30;
int b=int(255.f*fabs(sin(sin_count+(0.25*M_PI)))) - 30;
int c=int(255.f*fabs(sin(sin_count+(0.5*M_PI)))) - 30;
if( a < 0 ) a = 0;
if( b < 0 ) b = 0;
if( c < 0 ) c = 0;
// draw screen background: a blue shifting gradient.
CL_Display::fill_rect(CL_Rect(0,0,width,height),
CL_Gradient(
CL_Color(0,0,a,255),
CL_Color(0,0,c,255),
CL_Color(0,0,b,255),
CL_Color(0,0,a,255)));
/* Lower Text:
*
* This demonstrates the simplest use of stenciling.
*
* 1. Create the stencil mask.
* 1.1 Stencil buffer writing is enabled
* 1.2 A surface (or other graphics primitive) is drawn as usual
* 1.3 Stencil buffer writing is disabled
* 2. Draw, testing against the mask.
* 2.1 Stencil buffer testing is enabled
* 2.2 A surface is drawn as usual.
* 2.3 Stencil testing is disabled.
*
* This will clip the surface drawn in step 2.2 to the area covered by the surface(s)
* drawn to the stencil buffer in step 1.2.
*/
// erase old contents from the stencil buffer.
gc->clear_stencil();
// Enable drawing to the stencil buffer, disable color buffer writing
gc->enable_stencil_write(true, false);
// Draw into the stencil buffer.
text.set_scale(1.0f, 1.0f); // reset text size.
text.draw(width/2,height/2+height/4);
// Disable stencil writing.
gc->enable_stencil_write(false);
// Enable stencil testing.
gc->enable_stencil_test(true);
// Draw, testing each pixel against the stencil mask.
spot.set_angle(angle);
spot.draw(width/2,height);
// Disable stencil testing.
gc->enable_stencil_test(false);
/* Upper Text:
*
* Here is a bit more complicated example:
*
* Three spinning wheels are drawn inside the text. Each wheel
* is overlayed with 2 highlighting surfaces (a grayscale "cloud").
*
* here are the steps:
*
* 1. The text is drawn into the stencil buffer with color buf write off.
* - Where something is drawn the stencil gets the value 1.
* 2. The wheels are drawn on top of the text into the stencil (not color buf).
* - Stencil testing is also enabled. Only where the stencil
* contains a 1, do we modify the value. Each pixel, successfully drawn
* into the stencil buffer will increase the corresponding value in the stencil.
* Because there are overlapping parts, the parts overlapping the text
* will get the value 2, and the rest remain 1 or 0.
* 3. Enable Stencil testing and fill the text with a gradient.
* - the parameters specify that only stecil values equalling 1 get drawn over.
* That means the text, excluding the wheels.
* 4. Draw the wheels and their highlight surfaces
* - Stencil is tested for == 2, the value the wheels on top of text have.
*
* For further reading about stencil buffer operations search the web
* for "OpenGL red book", and the opengl man pages, which are also available
* online.
*/
wheel.set_angle(angle);
gc->clear_stencil();
text.set_scale(1.2f,1.9f);
// 1. write text into stencil.
gc->enable_stencil_write(true, false); // enable stencil write, disable color buf write
text.draw(width/2,height/2);
gc->enable_stencil_write(false);
// 2. draw stencil of wheels clipping to stencil of the text.
gc->set_stencil_operation( stencil_incr, stencil_keep, stencil_equal, 1);
gc->enable_stencil_write(true, false); // enable stencil write, disable color buf write
wheel.draw(width/2,height/2); // overdraw -> value in stencil is incremented
wheel.draw(width/2-256,height/2); // to 2 for the wheels over text
wheel.draw(width/2+256,height/2);
// reset to original settings.
gc->set_stencil_operation( stencil_incr, stencil_keep, stencil_always, 0 );
// disable stencil writing.
gc->enable_stencil_write(false);
// 3. Enable stencil testing and fill the font.
gc->enable_stencil_test(true, stencil_equal, 1); // pass stencil test if stencil == 1
CL_Display::fill_rect(CL_Rect(0,0,width,height),
CL_Gradient(
CL_Color(a,b,c,a),
CL_Color(b,c,a,b),
CL_Color(c,b,a,c),
CL_Color(c,a,b,a)));
gc->enable_stencil_test(false);
// 4. Draw wheels (where overlapping text).
gc->enable_stencil_test(true, stencil_equal, 2); // pass if stencil == 2
// Draw the wheels using stencil testing
wheel.draw(width/2,height/2);
wheel.draw(width/2-256,height/2);
wheel.draw(width/2+256,height/2);
// Draw highlight texture over wheels.
highlight.set_angle(angle);
highlight.draw(width/2,height/2);
highlight.draw(width/2+256,height/2);
highlight.draw(width/2-256,height/2);
highlight.set_angle(highlight_angle);
highlight.set_color(a,b,c,1.0f);
highlight.draw(width/2,height/2);
highlight.draw(width/2+256,height/2);
highlight.draw(width/2-256,height/2);
gc->enable_stencil_test(false);
window.flip();
CL_System::keep_alive(20);
}
}
} app;
|