quinta-feira, 30 de setembro de 2010

CSG operations in 2D

...or "Integrating a Polygon Boolean Operations Library"

I've been developing a prototype for a platform game, using the Chipmunk Physics library to handle the physics. The control mechanics are to be very simple, similar to Super Mario (with almost no inertia, no floor sliding), aiming to allow for precise and responsive control.

After designing the initial prototype, I started creating levels, using square blocks placed next to each other. This resulted in a (that I found later) known problem, where the object for the player will "bump" into the lines where the blocks meet and slow down or jump on them. Ok, so I'll just use continuous collision lines on top of a group of blocks instead of individual collision squares next to each other, so this doesn't happen.

From here, I needed a solution to ease the level creation process. The options were:

- place the blocks images by hand, and then create the collision lines also by hand (easiest to code, but would lead to boring level editing)

- place the blocks, and code an algorithm to find where the blocks were, outlining it with collision lines (would take some thinking, and would basically be a Constructive Solid Geometry problem)

- place the blocks, integrate an existing CSG solution, and join the individual blocks into a single object (most flexible solution, and I was interested in the potential of integrating CSG functionalities into my engine)

So I went to look for CSG algorithms, libraries, etc, and from what I gathered it's a pretty deep field, with several working solutions but with somewhat complicated implementations.
I looked around for CSG specifically for 2D, and found 3 libraries. From those, Clipper by Angus Johnson presented the best feature list and had a free license, so I looked at it.

It's pretty straightforward and I had a test working in a short time, which was great! This allowed me to integrate it easily into my level editor, and the outcome was great. Editing levels is now a lot of fun!

quarta-feira, 29 de setembro de 2010

IDE Switch: From CodeBlocks to CodeLite

Recently, I've been wanting something out of my IDE that CodeBlocks doesn't have: refactoring.

I've been following recent advice I got (from GoogleTalks, I believe) on code readability, on which the focus is on having short functions (short as in the total number of lines per function being small), which allows the coder to clearly and quickly understand what that function does just by glancing at it, without scrolling involved (I couple this with long function and variable names, which basically self-document my code).

Refactoring tools help this process.

In my opinion, coding is currently still much in it's infancy, it should be much clearer and easier to do, allowing any user to manipulate code in a "Lego" like fashion, assembling and moving blocks around with ease.

Refactoring is a beginning for this. Just create a new part of the code, which amounts to a few lines, select these lines and refactor them into a new function, and that code becomes a simple function invocation (with a nice long name like "GetPhysicsCollisionSegmentsAndInitializeSegmentList").

So, after looking into a few possibilities (including parsing my own code and creating a plugin for CodeBlocks, or switching to Netbeans/Eclipse), I went on a tip I saw on "Stack Overflow" that CodeLite had great refactoring tools. CodeLite, while being a relatively young one-man project, is looking great and is actually more advanced than other (by example). Also, something that always irked me a bit is a slightly negative tone on the CodeBlocks forums, treating newbies harshly and demeaning them with the "that doesn't belong here" and locking the threads (on questions that are actually related, at least partially, with CodeBlocks, which contributes to just demotivating them from further learning C++ or using CodeBlocks), while the guy at the CodeLite (also the creator and main programmer for the tool) is patient and helpful for new guys asking stuff at the forum (which I've been one of :))

I've been migrating my game engine to CodeLite, migrating the libraries, etc. One thing that is missing is importing projects from CodeBlocks, which should be relatively easy to do, and is what is taking me more time. Also, the Shared / Dynamic Library compilation system doesn't create .def and lib*.a files, that I was used to using in CodeBlocks (but apparently they aren't mandatory for dynamic linking).

I've also been working on different projects at the same time, working a bit on each for a while and jumping to other when I complete a sub-goal. Keeps it interesting.

Also, focusing more on prototyping a game (the "puzzle platformer"): have a single room with the most amount of gameplay features, to play around with and tune the gameplay), which allows me to increasingly improve my engine by game requirements, instead of risking over-designing it by adding unnecessary or impractical stuff.

domingo, 12 de setembro de 2010

How to do masking in SFML (with OpenGL)

(if there's some problem with the code, you can find my original forum post here or my Wiki entry for masking in SFML)

Something that I think is very helpful in games is the ability to do masking: define a region, based on an image, a polygon, or some text, and "cut" an image based on that.

Also, I wanted to have non-rectangular masks, and allow masks to have variable alpha (transparency) information.

Currently, the SFML library (at the time, I'm using 1.6) had no support for that, and it's something that I wanted in the long run, so I went in to try to find out how to do it and add it (in OpenGL, which SFML is based on).

After doing some research, a few options surfaced on how to do masking in OpenGL:

Using multi-texturing: mapping several textures to a single polygon, blending them using distinct modes and then draw the polygon. Pros: supported by old hardware. Cons: complicated code :) (having to play around with texture coordinates to correctly translate/rotate/scale the images to overlap)

Using the stencil-buffer: the stencil buffer works like a stencil: you cut a shape and then when you draw to it, only the cut area is shown, the other hidden. OpenGL has an extension which allows you to write pixels to a buffer, and then only draw where that buffer has valid pixels. Pros: close to what I wanted, allowing masks based on pixel information, polygons or text. Cons: required graphic card extensions, which may limit the usage in older hardware or portable devices (if I ever decide to port my games to them), and it didn't allow to write alpha information to the buffer (it either takes full opaque or full transparent, not translucent pixels - at least to the extent of my research and tests).

Writing to the color buffer's alpha channel and then using blending: the image which OpenGL shows on the screen is composed of 4 channels: Red+Green+Blue+Alpha. By writing directly to the alpha channel (and not to the RGB channels), setting correct blending modes, and then drawing overlapping images on the masked area, images will blend with the alpha channel, using that channel's transparency information.

Having these options, I chose to implement the last one into SFML. I contacted the library's creator to request a change in the original source code, that would easily allow the integration of my code into SFML, but he did not agree to that change. Here I reveal the steps to adding this feature, but it involves altering one (1) word in SFML's original source code and recompiling it. Also, it will probably not be supported for SFML 2.0, which will change some inner workings. But for the near future, all good.

This change allows the use of Sprites, Shapes and Strings as/with masks.
NOTE: it hasn't been extensively tested so there may be the occasional bug.

Below i'll post the code for several new classes i've added, and then a few example programs on how to use each class.


Ok, to start, you'll have to change a line in the original SFML 1.6 code, and recompile sfml or the "sfml-graphics" lib.

Go to the SFML source root folder, and open "include/SFML/Graphics/Drawable.hpp".
Then find the function definition
void Draw(RenderTarget& Target) const;
(around line 335)
and replace it with
virtual void Draw(RenderTarget& Target) const;
(add "virtual" at the start).
And recompile sfml-graphics.

New files:
MaskTypes.h - has the several masking types that you can use. Define a MaskType by using "MaskTypes::Type" and set them using "MaskTypes::BlendWithPreviousMask". The mask types are the following:
  • MaskType::None - use the normal sf::BlendMode.
  • MaskType::Mask - use this Drawable's Alpha mask as a Mask (only drawing the Drawable's Alpha info, not any color). Will blend the mask with previous existing masks.
  • MaskType::MaskOverWritePreviousMask - similar to the previous, but will overwrite the previous mask instead of blending into it (allows to "cut" into an existing mask, and is used by example with "StringMask" - check the example)
  • MaskType::BlendWithPreviousMask - set this mask to have a Drawable blend with the mask previously drawn on its area (only draw where alpha > 0)
  • MaskType::BlendWithPreviousMaskReversed - set this mask to have a Drawable blend with the NEGATIVE of the mask previously drawn on its area (transparent areas become opaque and vice-versa).

MaskUtils.h - Internal class, no need to call this from your code.
Basically where all the magic happens, OpenGL calls are made, states are saved and restored, etc. Some code that was in "sf::Drawable" related to blend modes was pasted here.
RenderWindowMask.h - must be used instead of a regular sf::RenderWindow, inherits from it. Adds the "ClearMask()" function, which clears just the color buffer's alpha channel.
SpriteMasked.h - use this to draw a Sprite using masking, or to use a Sprite AS a mask. Inherits from sf::Sprite. Adds the "maskSetType/maskGetType" functions necessary to define the masking type.
ShapeMasked.h - use this to use a Shape as a mask or to mask a Shape. Inherits from sf::Shape. Adds the "maskSetType/maskGetType" functions necessary to define the masking type.
StringMasked.h - use this to use a String as a mask or to mask a String. Inherits from sf::String. Adds the "maskSetType/maskGetType" functions necessary to define the masking type.

P.S. no need to preserve states (use "App.PreserveOpenGLStates(true)"), it's all done internally.

MaskTypes.h

#ifndef MASKTYPES_H_INCLUDED
#define MASKTYPES_H_INCLUDED

class MaskTypes
{
public:
enum Type
{
None = 0,
Mask,
MaskOverWritePreviousMask,
BlendWithPreviousMask,
BlendWithPreviousMaskReversed
};
};

MaskUtils.h

#ifndef MASKUTILS_H_INCLUDED
#define MASKUTILS_H_INCLUDED

#include <sfml/graphics/drawable.hpp>

using namespace sf;

class MaskUtils
{
public:
MaskUtils()
{
reset();
}

void reset()
{
restoreColorBuffer = false;
restoreBlendMode = false;
}

void setBlendModesBasedOnMaskType(MaskTypes::Type maskType, Blend::Mode blendMode)
{
switch(maskType)
{
case MaskTypes::None:
{
restoreBlendMode = true;
blendModePreviouslyEnabled = glIsEnabled(GL_BLEND);

// Setup alpha-blending
Blend::Mode myBlendMode = blendMode;
if (myBlendMode == Blend::None)
{
glDisable(GL_BLEND);
}
else
{
glEnable(GL_BLEND);

switch (myBlendMode)
{
case Blend::Alpha :
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
case Blend::Add :
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
break;
case Blend::Multiply :
glBlendFunc(GL_DST_COLOR, GL_ZERO);
break;
default :
break;
}
}
}
break;

case MaskTypes::Mask:
{
blendModePreviouslyEnabled = glIsEnabled(GL_BLEND);
glEnable(GL_BLEND);
glColorMask(false, false, false, true);// we can just write the alpha info
glBlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA); // include the source (picture we are drawing) alpha, ignore the destination (info already in color buffer) alpha
restoreColorBuffer = true;
restoreBlendMode = true;
}
break;
case MaskTypes::MaskOverWritePreviousMask:
{
blendModePreviouslyEnabled = glIsEnabled(GL_BLEND);
glEnable(GL_BLEND);
glColorMask(false, false, false, true);// we can just write the alpha info
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // include the source (picture we are drawing) alpha, ignore the destination (info already in color buffer) alpha
restoreColorBuffer = true;
restoreBlendMode = true;
}
break;
case MaskTypes::BlendWithPreviousMask:
{
blendModePreviouslyEnabled = glIsEnabled(GL_BLEND);

// draw stuff inside window
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA); // blend with alpha info in color buffer, which was written by previous image
restoreBlendMode = true;
}
break;
case MaskTypes::BlendWithPreviousMaskReversed:
{
blendModePreviouslyEnabled = glIsEnabled(GL_BLEND);

// draw stuff inside window
glEnable(GL_BLEND);
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA); // blend with alpha info in color buffer, which was written by previous image
restoreBlendMode = true;
}
break;
}
}

void restoreStates()
{
if(restoreColorBuffer)
glColorMask(true, true, true, true); // make sure that for further images that we are writing all colors

if(restoreBlendMode)
{
if(blendModePreviouslyEnabled)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
}
}

private:
bool restoreColorBuffer;
bool restoreBlendMode;
bool blendModePreviouslyEnabled;
};

#endif // MASKUTILS_H_INCLUDED


RenderWindowMask.h

#ifndef RENDERWINDOWMASK_H_INCLUDED
#define RENDERWINDOWMASK_H_INCLUDED

#include <SFML/Graphics.hpp>
#include "MaskTypes.h"

using namespace sf;

class RenderWindowMask : public RenderWindow
{
public:
RenderWindowMask(
VideoMode Mode,
const std::string& Title,
unsigned long WindowStyle = Style::Resize | Style::Close,
const WindowSettings& Params = WindowSettings())
{
Create(Mode, Title, WindowStyle, Params);
}

RenderWindowMask( WindowHandle Handle,
const WindowSettings& Params = WindowSettings())
{
Create(Handle, Params);
}

// clears the alpha channel
void ClearMask()
{
glColorMask(false, false, false, true); // disable messing with the rgb channels, just change the alpha
glClear(GL_COLOR_BUFFER_BIT); // clear the color buffer (just the alpha channel)
//glClearColor(FillColor.r / 255.f, FillColor.g / 255.f, FillColor.b / 255.f, FillColor.a / 255.f));
glColorMask(true, true, true, true); // enable messing with the rgb channels, just change the alpha
}
};

#endif // RENDERWINDOWMASK_H_INCLUDED


SpriteMasked.h

#ifndef SPRITEMASKED_H_INCLUDED
#define SPRITEMASKED_H_INCLUDED

#include <SFML/Graphics/Sprite.hpp>
#include "MaskTypes.h"
#include "MaskUtils.h"

using namespace sf;

class SpriteMasked : public Sprite
{
public:
SpriteMasked() :
Sprite(),
maskType(MaskTypes::None)
{
}

void Draw(RenderTarget& Target) const
{
// Save the current modelview matrix and set the new one
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf(GetMatrix().Get4x4Elements());

MaskUtils maskUtils;
maskUtils.setBlendModesBasedOnMaskType(this->maskType, GetBlendMode());

// Set color
Color myColor = GetColor();
glColor4f(myColor.r / 255.f, myColor.g / 255.f, myColor.b / 255.f, myColor.a / 255.f);

// Let the derived class render the object geometry
Render(Target);

maskUtils.restoreStates();

// Restore the previous modelview matrix
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}

void maskSetType(MaskTypes::Type maskType)
{
this->maskType = maskType;
}

MaskTypes::Type maskGetType()
{
return this->maskType;
}

private:
MaskTypes::Type maskType;

};

#endif // SPRITEMASKED_H_INCLUDED


ShapeMasked.h

#ifndef SHAPEMASKED_H_INCLUDED
#define SHAPEMASKED_H_INCLUDED

#include <SFML/Graphics/Shape.hpp>
#include "MaskTypes.h"
#include "MaskUtils.h"

using namespace sf;

class ShapeMasked : public Shape
{
public:
ShapeMasked() :
Shape(),
maskType(MaskTypes::None)
{}

ShapeMasked(sf::Shape& shape) :
Shape(),
maskType(MaskTypes::None)
{
// copy points
for(unsigned int idxPoint = 0; idxPoint < shape.GetNbPoints(); ++idxPoint)
{
this->AddPoint(shape.GetPointPosition(idxPoint), shape.GetPointColor(idxPoint), shape.GetPointOutlineColor(idxPoint));
}

this->SetOutlineWidth(shape.GetOutlineWidth());
this->SetColor(shape.GetColor());
}

void Draw(RenderTarget& Target) const
{
// Save the current modelview matrix and set the new one
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf(GetMatrix().Get4x4Elements());

MaskUtils maskUtils;
maskUtils.setBlendModesBasedOnMaskType(this->maskType, GetBlendMode());

// Set color
Color myColor = GetColor();
glColor4f(myColor.r / 255.f, myColor.g / 255.f, myColor.b / 255.f, myColor.a / 255.f);

// Let the derived class render the object geometry
Render(Target);

maskUtils.restoreStates();

// Restore the previous modelview matrix
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}

void maskSetType(MaskTypes::Type maskType)
{
this->maskType = maskType;
}

private:
MaskTypes::Type maskType;
};

#endif // SHAPEMASKED_H_INCLUDED


StringMasked.h

#ifndef TEXTMASKED_H_INCLUDED
#define TEXTMASKED_H_INCLUDED

#include <SFML/Graphics.hpp>
#include "MaskTypes.h"
#include "MaskUtils.h"

using namespace sf;

class StringMasked : public sf::String
{
public:
StringMasked() :
String(),
maskType(MaskTypes::None)
{}

StringMasked(sf::Shape& shape) :
String(),
maskType(MaskTypes::None)
{
}

void Draw(RenderTarget& Target) const
{
// Save the current modelview matrix and set the new one
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf(GetMatrix().Get4x4Elements());

bool restoreColorBuffer = false;
bool restoreBlendMode = false;
bool blendModePreviouslyEnabled;

MaskUtils maskUtils;
maskUtils.setBlendModesBasedOnMaskType(this->maskType, GetBlendMode());

// Set color
Color myColor = GetColor();
glColor4f(myColor.r / 255.f, myColor.g / 255.f, myColor.b / 255.f, myColor.a / 255.f);

// Let the derived class render the object geometry
Render(Target);

maskUtils.restoreStates();

// Restore the previous modelview matrix
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}

void maskSetType(MaskTypes::Type maskType)
{
this->maskType = maskType;
}

MaskTypes::Type maskGetType()
{
return this->maskType;
}

private:
MaskTypes::Type maskType;
};

#endif // TEXTMASKED_H_INCLUDED



Example programs:

SpriteMask example:

(actually, shows two examples: on the left, we can see a simple masking example. On the right, a way to do sub-windowing, by combining overlapping masked elements).

#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
#include <fstream>

#include "SpriteMasked.h"
#include "RenderWindowMask.h"

int main()
{
//sf::RenderWindow App(sf::VideoMode(800, 600, 32), "SFML Graphics");
RenderWindowMask App(sf::VideoMode(800, 600, 32), "SFML Graphics");
//App.PreserveOpenGLStates(true);

sf::Clock Clock;

sf::Image Image;
Image.LoadFromFile("northeast.jpg");


sf::Image ImageMask;
ImageMask.LoadFromFile("images/window.tga");

SpriteMasked spriteMask;
spriteMask.SetImage(ImageMask);
spriteMask.SetPosition(200, 200);
spriteMask.maskSetType(MaskTypes::Mask);


sf::Image ImageInsideWindow;
ImageInsideWindow.LoadFromFile("images/image.tga");
SpriteMasked spriteInsideWindow;
spriteInsideWindow.SetImage(ImageInsideWindow);
spriteInsideWindow.SetPosition(200, 200);


const sf::Input& Input = App.GetInput();
int mouseXPrev = Input.GetMouseX(),
mouseYPrev = Input.GetMouseY(),
mouseX, mouseY;

float timeSinceLastUpdate;

int a = 0;


// Start game loop
while (App.IsOpened())
{
// Process events
sf::Event Event;
while (App.GetEvent(Event))
{
// Close window : exit
if (Event.Type == sf::Event::Closed)
App.Close();
if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
App.Close();
}

timeSinceLastUpdate = Clock.GetElapsedTime();
Clock.Reset();

mouseX = Input.GetMouseX();
mouseY = Input.GetMouseY();
float mouseMoveX = (float)(mouseXPrev - mouseX) * timeSinceLastUpdate * 6.0f;
float mouseMoveY = (float)(mouseYPrev - mouseY) * timeSinceLastUpdate * 6.0f;
mouseXPrev = mouseX;
mouseYPrev = mouseY;

App.Clear(sf::Color(200,0,0,255));


/////
///// Example 1: simple mask
/////
// draw sprite to use as mask
spriteMask.SetScale(1, 1);
spriteMask.SetPosition(100, 250);
spriteMask.maskSetType(MaskTypes::Mask);
App.Draw(spriteMask);

// draw normal sprite
spriteInsideWindow.maskSetType(MaskTypes::BlendWithPreviousMask);
spriteInsideWindow.SetScale(1, 1);
spriteInsideWindow.SetPosition(100, 250);
App.Draw(spriteInsideWindow);


/////
///// Example 2: use masking to do sub-windowing
/////

// how to draw sub-windows:
// 1) draw window contents first
// 2) draw stuff outside afterwards
// details:
// 1) draw window contents - background to foreground
// a) draw window bg (don't care about mask)
// b) draw mask
// c) draw "negative" image (BlendWithPreviousMaskReversed)
// d) draw other stuff on top of it
// e) draw parent mask on top of it
// 2) draw stuff outside
// a) draw "positive" other stuff over it (BlendWithPreviousMask)
// ( b) draw mask again if necessary for every new image to draw? dunno)


// 1) draw window contents - background to foreground
// a) draw window bg (don't care about mask)
// b) draw mask for next element
// c) draw "negative" image (BlendWithPreviousMaskReversed)
// d) draw other stuff on top of it
// e) draw parent mask on top of it

// a) draw window bg (don't care about mask)
spriteInsideWindow.SetScale(1,1);
spriteInsideWindow.maskSetType(MaskTypes::None);
spriteInsideWindow.SetPosition(500, 250);
App.Draw(spriteInsideWindow);


// b) draw mask for next element (1)
spriteMask.SetScale(0.4, 0.4);
spriteMask.SetPosition(550, 250);
spriteMask.maskSetType(MaskTypes::Mask);
App.Draw(spriteMask);


// c) draw "negative" image (BlendWithPreviousMaskReversed) (1)
spriteInsideWindow.maskSetType(MaskTypes::BlendWithPreviousMask);
spriteInsideWindow.SetScale(0.4, 0.4);
spriteInsideWindow.SetPosition(550, 250);
App.Draw(spriteInsideWindow);


// b) draw mask for next element (2)
spriteMask.SetScale(0.4, 0.4);
spriteMask.SetPosition(590, 250);
spriteMask.maskSetType(MaskTypes::Mask);
App.Draw(spriteMask);

// c) draw "negative" image (BlendWithPreviousMaskReversed) (2)
spriteInsideWindow.maskSetType(MaskTypes::BlendWithPreviousMask);
spriteInsideWindow.SetScale(0.4, 0.4);
spriteInsideWindow.SetPosition(590, 250);
App.Draw(spriteInsideWindow);



// e) draw parent mask on top of it
spriteMask.SetScale(1.0, 1.0);
spriteMask.SetPosition(500, 200);
spriteMask.maskSetType(MaskTypes::Mask);
App.Draw(spriteMask);


// 2) draw stuff outside
// a) draw "positive" other stuff over it (BlendWithPreviousMask)
spriteInsideWindow.maskSetType(MaskTypes::BlendWithPreviousMaskReversed);
spriteInsideWindow.SetPosition(350,150);
spriteInsideWindow.SetScale(2,2);
App.Draw(spriteInsideWindow);

// Display window contents on screen
App.Display();
}

return 0;
}


ShapeMask example:
(masking using a sf::Circle)


#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
#include <fstream>

#include "SpriteMasked.h"
#include "ShapeMasked.h"
#include "RenderWindowMask.h"



int main()
{
//sf::RenderWindow App(sf::VideoMode(800, 600, 32), "SFML Graphics");
RenderWindowMask App(sf::VideoMode(800, 600, 32), "SFML Graphics");

sf::Clock Clock;


sf::Image ImageInsideWindow;
ImageInsideWindow.LoadFromFile("images/image.tga");
SpriteMasked spriteInsideWindow;
spriteInsideWindow.SetImage(ImageInsideWindow);
spriteInsideWindow.SetPosition(200, 200);
spriteInsideWindow.maskSetType(MaskTypes::BlendWithPreviousMask);


const sf::Input& Input = App.GetInput();
int mouseXPrev = Input.GetMouseX(),
mouseYPrev = Input.GetMouseY(),
mouseX, mouseY;

float timeSinceLastUpdate;


// masking for shapes
sf::Shape circle = sf::Shape::Circle(0, 0, 100, sf::Color(255,255,255,0)); // note: zero alpha
ShapeMasked shapeMask(circle);
shapeMask.maskSetType(MaskTypes::Mask);

// Start game loop
while (App.IsOpened())
{
// Process events
sf::Event Event;
while (App.GetEvent(Event))
{
// Close window : exit
if (Event.Type == sf::Event::Closed)
App.Close();
if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
App.Close();
}

timeSinceLastUpdate = Clock.GetElapsedTime();
Clock.Reset();

App.Clear(sf::Color(200,0,0,255));


// draw shape mask
shapeMask.SetPosition(500,300);
App.Draw(shapeMask);

// draw masked image
spriteInsideWindow.SetPosition(450, 200);
App.Draw(spriteInsideWindow);


// Display window contents on screen
App.Display();
}

}



StringMask example:


#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
#include <fstream>

#include "StringMasked.h"
#include "SpriteMasked.h"
#include "RenderWindowMask.h"


int main()
{
//sf::RenderWindow App(sf::VideoMode(800, 600, 32), "SFML Graphics");
RenderWindowMask App(sf::VideoMode(800, 600, 32), "SFML Graphics"); // we'll need to use our RenderWindow to have access to "ClearMask" function
//App.PreserveOpenGLStates(true);

//std::ofstream myfile;
//myfile.open ("pixels.txt");

sf::Clock Clock;

sf::Image Image;
Image.LoadFromFile("northeast.jpg");

sf::Image ImageInsideText;
ImageInsideText.LoadFromFile("images/image.tga");

SpriteMasked spriteInsideText;
spriteInsideText.SetImage(ImageInsideText);

float timeSinceLastUpdate;


// masking for text
// Create a graphical string
StringMasked stringMask;
stringMask.SetText("Hello !\nHow are you ?");
stringMask.SetFont(sf::Font::GetDefaultFont());
stringMask.SetPosition(100,50);

stringMask.maskSetType(MaskTypes::Mask);
stringMask.SetColor(sf::Color(0,0,0,255));

// Start game loop
while (App.IsOpened())
{
// Process events
sf::Event Event;
while (App.GetEvent(Event))
{
// Close window : exit
if (Event.Type == sf::Event::Closed)
App.Close();
if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
App.Close();
}

timeSinceLastUpdate = Clock.GetElapsedTime();
Clock.Reset();


App.Clear(sf::Color(200,0,0,255)); // clear the background to red

//// How to correctly draw a String to Mask/MaskReverse a sprite:
//// 1. clear the Window Alpha Mask before drawing the text (or the sprite may appear where you drew previous masks)
//// 2. draw the SPRITE as the mask (masking everywhere where the sprite would be)
//// 3. draw the STRING using the mask type "MaskOverWritePreviousMask" (thus "cutting" into the mask the previous sprite left)
//// 4. draw the Sprite again, normally, using the mask type "BlendWithPreviousMask"

App.ClearMask(); // 1. clears just the Window's alpha channel

// 2. use sprite to draw as mask
spriteInsideText.SetPosition(100,10);

// save the sprite mask and color state (may be necessary if you reuse this sprite elsewhere)
MaskTypes::Type prevMaskType = spriteInsideText.maskGetType();
sf::Color prevSpriteColor = spriteInsideText.GetColor();

spriteInsideText.SetColor(sf::Color(0,0,0,0)); // set the sprite's alpha to 0
spriteInsideText.maskSetType(MaskTypes::Mask); // set the sprite to act as a mask
App.Draw(spriteInsideText);

// restore sprite mask+color state
spriteInsideText.maskSetType(prevMaskType);
spriteInsideText.SetColor(prevSpriteColor);


// 3. draw text mask
stringMask.SetPosition(100,50);
stringMask.maskSetType(MaskTypes::MaskOverWritePreviousMask);
App.Draw(stringMask);

// 4. draw the masked sprite
spriteInsideText.SetPosition(100,10);
// using this blending mode, the sprite will be drawn normally and the text area will be "cut" from the sprite
spriteInsideText.maskSetType(MaskTypes::BlendWithPreviousMask);

App.Draw(spriteInsideText);




// Example 2:
App.ClearMask(); // 1. clears just the Window's alpha channel

// 2. use sprite to draw as mask
spriteInsideText.SetPosition(500,10);

// save the sprite mask and color state (may be necessary if you reuse this sprite elsewhere)
prevMaskType = spriteInsideText.maskGetType();
prevSpriteColor = spriteInsideText.GetColor();

spriteInsideText.SetColor(sf::Color(0,0,0,0)); // set the sprite's alpha to 0
spriteInsideText.maskSetType(MaskTypes::Mask); // set the sprite to act as a mask
App.Draw(spriteInsideText);

// restore sprite mask+color state
spriteInsideText.maskSetType(prevMaskType);
spriteInsideText.SetColor(prevSpriteColor);


// 3. draw text mask
stringMask.SetPosition(500,50);
stringMask.maskSetType(MaskTypes::MaskOverWritePreviousMask);
App.Draw(stringMask);

// 4. draw the masked sprite
spriteInsideText.SetPosition(500,10);

// using this blending mode, the sprite will be drawn "inside" the text's characters
spriteInsideText.maskSetType(MaskTypes::BlendWithPreviousMaskReversed);

App.Draw(spriteInsideText);


App.Display(); // Display window contents on screen
}

//myfile.close();
return 0;
}


This method has a few inconveniences, such as having the overhead of redrawing polygons, and Strings have some boring extra work needed and work the other way around than sprites and shapes, but I think it's altogether a good and flexible solution, and all-encompassing, technology-wise (supporting older hardware).


Plus, here's a little function for debugging, that saves the current alpha buffer to a file named "imageAlpha.png" (upside down, OpenGL stuff). May help you debug if you run into problems.

void GetGLPixels()
{
unsigned int startX = 0, startY = 0;
unsigned int width = 800, height = 600;

GLubyte* pixels = new GLubyte[width * height * 4];

glReadPixels(startX, startY, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);


for(unsigned int idxPixelRow = 0; idxPixelRow < height; idxPixelRow++)
{
for(unsigned int idxPixelColumn = 0; idxPixelColumn < width; idxPixelColumn++)
{
unsigned int index = ((idxPixelRow * width) + idxPixelColumn) * 4;
unsigned int indexAlpha = ((idxPixelRow * width) + idxPixelColumn);

float valueRed = pixels[index + 0];
float valueGreen = pixels[index + 1];
float valueBlue = pixels[index + 2];
float valueAlpha = pixels[index + 3];

pixels[index] = pixels[index + 1] = pixels[index + 2] = 0;
}
}


// create and save image
sf::Image imageAlpha;
imageAlpha.LoadFromPixels(width, height, pixels);
imageAlpha.SaveToFile("imageAlpha.png");


delete pixels;
}


I hope this is helpful to others. I spent too much time looking for how to do this, longer than I thought should be for something as useful and old (masking is used on old arcade games to great effect, remember those big scrolling letters which masked the game going on behind it?)