Jump to content

Interesting Tricks / Shortcuts / Etc


Veiva

Recommended Posts

I thought it would be an interesting idea to discuss interesting tricks you've discovered on your own (doesn't matter if the tricks were known about by others beforehand). For example, a neat algorithm that is easier to implement over another or a quick shortcut in a programming language.

 

I'll start off! I am developing a game using OpenGL, and it exclusively uses vector graphics (such as those made in InkScape or Adobe Illustrator). However, the shapes created in InkScape are merely a list of various points that form concave or convex polygons. Not only that, but these polygons can have holes in them (such as the letter "O"). OpenGL has little-to-no facilities for drawing convex polygons (depending on the version of OpenGL you're using; I am using 1.4 with some extensions), let alone concave ones. Now, I knew I could implement the difficult ear-clipping algorithm, which would be suitable for cases such as static graphics, like fonts. However, much of my graphics are going to be dynamic, and recalculating the triangulated mesh each and every frame is assuredly going to be slower than intended. Plus I don't feel like implementing the ear-clipping algorithm.

 

So, I had the brilliant idea of using the stencil buffer. The stencil buffer basically masks parts of the image depending on how you set up the graphics device. Anyway, if I did a basic triangulation in that each vertex connects to two others to form a triangle, I could exploit the fact that an even amount of potential pixels means that the area has nothing to be drawn, while and odd amount means that something should be drawn. Therefore, after some jiggling around with different ways using the stencil buffer, I figured it out. In any case, I can render some hundreds of polygons relatively fast on a netbook, which is all I really need. When it comes to my desktop I am sure I can render some thousands. Here is the code, basically, for fonts:

 

static void bsFontVertexCache_Draw(bsFontVertexCache * cache)
{
glVertexPointer(2, GL_FLOAT, sizeof(bsFontVertex) - sizeof(bsSingle) * 2,
	cache->vertices);

glDrawElements(GL_TRIANGLES, cache->indexCount,
	GL_UNSIGNED_SHORT, cache->indices);
}

static void bsFontGlyph_DrawCharacter(bsFontGlyph * glyph, bsPaint * paint)
{
bsInt i = 0;

glColorMask(bsFalse, bsFalse, bsFalse, bsFalse);
glStencilMask(1);

glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
glStencilFunc(GL_ALWAYS, 0, 0);


for (i = 0; i < glyph->cacheCount; i++)
	bsFontVertexCache_Draw(glyph->caches[i]);

glColorMask(bsTrue, bsTrue, bsTrue, bsTrue);

if (paint)
	bsPaint_Fill(paint, glyph->dimensions.x, glyph->dimensions.y,
		glyph->dimensions.width, glyph->dimensions.height);
}

void bsFont_DrawText(const bsFont * font, bsPaint * paint, bsSingle x,
bsSingle y, bsInt flags, const char * text)
{
bsInt i, stringLength = strlen(text);
bsMatrix translation;

glPushMatrix();
bsMatrix_CreateTranslation(&translation, x, y, 0);
glMultMatrixf(translation.matrix);

glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glEnableClientState(GL_VERTEX_ARRAY);

glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glDepthMask(bsFalse);
glDepthFunc(GL_ALWAYS);

for (i = 0; i < stringLength; i++)
{
	bsInt glyphIndex = bsFont_CharacterToIndex(font, text[i]);
	bsSingle width;
	bsFontGlyph * glyph;

	if (glyphIndex < 0)
		continue;

	glyph = font->glyphs[glyphIndex];

	if (glyph->dimensions.width != 0.0f)
	{
		width = glyph->advance + glyph->advance * font->characterSpacing;
		bsFontGlyph_DrawCharacter(glyph, paint);
	}
	else
		width = font->spaceMultiplier;

	bsMatrix_CreateTranslation(&translation, width, 0, 0);
	glMultMatrixf(translation.matrix);
}

glPopAttrib();
glPopClientAttrib();
glPopMatrix();
}

void bsPaint_Fill(bsPaint * paint, bsSingle x, bsSingle y,
bsSingle width, bsSingle height)
{
if (paint && paint->flags & BS_PAINT_FLAG_COMPLETE)
{
	GLenum drawMode;
	bsMatrix scale, translation, final;

	glPushMatrix();
	bsMatrix_CreateScale(&scale, width, height, 1);
	bsMatrix_CreateTranslation(&translation, x, y, 0);
	bsMatrix_Multiply(&translation, &scale, &final);
	glMultMatrixf(final.matrix);

	glPushAttrib(GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT | GL_TEXTURE_BIT |
		GL_STENCIL_BUFFER_BIT);
	glShadeModel(GL_SMOOTH);
	glDepthMask(bsFalse);
	glDepthFunc(GL_ALWAYS);
	glStencilOp(GL_KEEP, GL_ZERO, GL_ZERO);
	glStencilFunc(GL_EQUAL, 1, 1);

	glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	if (paint->paintMode == BS_PAINT_MODE_TEXTURED ||
		paint->paintMode == BS_PAINT_MODE_TEXTURED_TINTED)
	{
		glBindTexture(GL_TEXTURE_2D, paint->texture);
		glEnable(GL_TEXTURE_2D);
	}

	glVertexPointer(2, GL_FLOAT, sizeof(bsPaintVertex),
		&paint->cache->vertices[0].x);
	glTexCoordPointer(2, GL_FLOAT, sizeof(bsPaintVertex),
		&paint->cache->vertices[0].u);
	glColorPointer(4, GL_FLOAT, sizeof(bsPaintVertex),
		&paint->cache->vertices[0].r);

	if (paint->paintMode == BS_PAINT_MODE_RADIAL_GRADIENT)
		drawMode = GL_TRIANGLES;
	else
		drawMode = GL_TRIANGLE_STRIP;

	glDrawElements(drawMode, paint->cache->indexCount,
		GL_UNSIGNED_SHORT, paint->cache->indices);

	glPopClientAttrib();
	glPopAttrib();
	glPopMatrix();
}
}

 

It's not the whole bunch of code obviously, but enough to give an idea of what I'm doing. This is the output:

 

36728716.png

 

27705339.png

 

So, what tricks have you done?

ozXHe7P.png

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.