Veiva Posted December 8, 2010 Share Posted December 8, 2010 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: So, what tricks have you done? Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now