• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

swinchen

Members
  • Content count

    128
  • Joined

  • Last visited

Community Reputation

224 Neutral

About swinchen

  • Rank
    Member
  1. OK, one more post and then I should probably let this thread drift into the depths of the forum. Now that I have a reasonable first attempt at a texture manager (even though I want to try to make it more generic in the future) I am back to the problem that was the reason for this whole thread. In a game you might have multiple game objects that not only share the same texture, but are drawn exactly the same way. (think a room full of crates, or in my case a volume filled with snowflakes) Using display lists (I am a linux/OpenGL user, so I know nothing of DirectX) it is possible to compile the commands used to draw the snowflakes. For each identically drawn game object I can't simply load the texture and create a display list because that leads to redundancy... Does this imply I also need a display list manager? It almost seems like there should be a pattern for "Lots of objects use a single object." I guess what I really would like to know is what are some common methods for storing and representing game data? I have heard the term scenegraph before, perhaps that is worth looking into. There seems to be some rather significant challenges with drawing a scene. For example all objects that use alpha blending must be drawn last from furthest away, to the closest. So making an educated guess here, I would have to say that game objects (or at least pointers to an game object interface) are stored in multiple locations. Objects using alpha blending being stored in a container that can be sorted. Then again, all objects could be stored in a vector (or other sequential container) and then use std::partition to place all alpha objects at the end of the draw vector and then sort only that portion of the vector? At this point I may be talking about how to implement the renderer. I may be getting ahead of myself, but these sorts of things keep me awake at night... and I space out in the shower thinking about it and come out looking like a prune [smile] Thank you for your patience!
  2. Thanks for the code hoLogramm, the TextureManager makes more sense to me conceptually. Using the shared_ and weak_ ptrs, here is what I have so far. It is important to note that it isn't actually loading a texture yet... just creating empty objects for testing. Right now there is a major hack in the code. The weak_ptrs are only getting removed from the map when something tries to reference them after the texture has been destroyed. So far this approach seems much much more simple than anything I would have thought of before this discussion! #include <map> #include <string> #include <iostream> #include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> #include <GL/gl.h> class Texture { private: std::string m_filename; GLuint m_id; GLuint m_width; GLuint m_height; protected: public: Texture(const std::string& filename, GLuint id, GLuint width, GLuint height): m_filename(filename), m_id(id), m_width(width), m_height(height) { } virtual ~Texture() { if ( glIsTexture(m_id) == GL_TRUE ) glDeleteTextures(1, &m_id); } std::string& getFilename() { return m_filename; } GLuint getID() { return m_id; } GLuint getWidth() { return m_width; } GLuint getHeight() { return m_height; } }; class TextureManager { private: typedef boost::weak_ptr<Texture> WeakTexturePtr; typedef std::map< std::string, WeakTexturePtr > TextureMap; TextureMap m_texture_map; class deleter { public: void operator()(Texture* p) { std::cout << "Deleting..." << std::endl; //I need to find a way to remove the m_texture_map entry.. //Difficult seeing this isn't really an instance of a class. //Need to find some way to gain access to access to private //member functions and/or private data in the TextureManager //from here. delete p; } }; protected: public: typedef boost::shared_ptr< Texture > TexturePtr; TexturePtr getTexturePtr(const std::string& filename); }; TextureManager::TexturePtr TextureManager::getTexturePtr(const std::string& filename) { TextureMap::iterator mapped_ptr = m_texture_map.find(filename); if ( mapped_ptr != m_texture_map.end() ) { std::cout << "I found: " << filename << std::endl; //This work around seems a bit like a hack. The texture should be //removed from the map when it is deleted. See comment above. if ( !mapped_ptr->second.expired() ) { TexturePtr p(mapped_ptr->second); return p; } else { std::cout << "unfortunately this pointer is no longer valid... removing from map!" << std::endl; m_texture_map.erase(filename); } } //Yeah, I need to create the texture better than this! :) //Trying to decide if I should put the code to load the texture //Here, or if I should put it in the Texture class itself. //Not sure if I need the custom deleter function or not, the texture //itself should be able to take care of deleting the GL texture. //Actually, if I do need a custom deleter, I will have to put it in //the texture so that I can get access to private data. Also I would //need to a factory function in the texture to create the shared_ptr. std::cout << "creating: " << filename << std::endl; TexturePtr p(new Texture(filename,0,0,0), TextureManager::deleter()); WeakTexturePtr wp(p); m_texture_map.insert(std::make_pair(filename, wp)); return p; //Not sure what to return if unable to load the texture... hrmm. } int main(int argc, char* argv[]) { // A quick and dirty little test. TextureManager tm; { TextureManager::TexturePtr tp1 = tm.getTexturePtr("HelloThere.tga"); } TextureManager::TexturePtr tp2 = tm.getTexturePtr("HelloThere.tga"); TextureManager::TexturePtr tp3 = tm.getTexturePtr("HelloThere.tga"); //creating: HelloThere.tga //Deleting... //I found: HelloThere.tga //unfortunately this pointer is no longer valid... removing from map! (HACK!) //creating: HelloThere.tga //I found: HelloThere.tga //Deleting... return 0; }
  3. Thanks for the words of encouragement, they really keep the drive going [smile] Now back to business: hoLogramm, you recommend storing the texture in the object that uses it but what if more than one object uses the same texture? My understanding (and it may be incorrect) that a texture manager stores all textures, and everything associated with textures so that the application would never (well maybe not never [smile]) have redundant data. Perhaps my definition of texture is off. To me a texture is little more than a GLuint that is created when you load a image file. I am sure there is a lot more to it than that... but if each object called "loadFromFile()" it seems like unless the manager pooled the textures then I would quickly fill the video memory with redundant texture information. Using shared pointers looks promising, the only potential problem that I see is that the texturemanager would reference the texture therefore preventing the texture from being deleted. I guess there are these two functions: bool unique() const; // never throws long use_count() const; // never throws so I could periodically? check to see if there is only one reference to a texture and if so delete it, swap it out, or anything I saw fit to do. It seems like it would be much better if this was handled automatically for me though. Perhaps this is my inexperience with shared pointers showing through. The only problem I see with raw pointers is that I would need to do the reference counting myself. Otherwise I would never know when all objects were done with the texture. hrmmm. Oh yeah, here is the game I am working on (yeah, yeah... there are texture, but right now they are.. ugh... hard coded in [disturbed] ):
  4. To Emmanuel: Thank you for the code snippet, that is quite enlightening. I have a couple of quick questions though... Where are the textures actually stored? It appears as though they are stored in the xxx_texture_loader classes. This is very interesting, what factors did you consider when you designed it this way? Why do you return a pointer to the texture and not a reference? (just to clarify... I am NOT attacking your design, I am just trying to learn...) Next is a more general question... It would be nice to be able to keep track of references to a texture so the manager could delete the texture automatically. Texture::incRef and Texture::decRef is where I would start but a problem arises if I return a pointer or a reference to the object... the user can increment the reference! that isn't so good. Maybe make the TextureManager a friend of the Texture and make those private? The texture can not delete itself unless there is some way to inform the class the manages the texture and I would like to avoid circular dependencies. I guess another way would be to store the reference count with the texture in the manager and make the copy, and assignment operators private? I don't know if I am describing the problem clearly, if not please let me know! I hope I am not bothering people, it really helps for me to talk this out and I feel like I am learning a lot. Thanks to everyone so far who has helped me out. Sam.
  5. I think I am a much more visual learner, so I have sort of formed some questions in a UML diagram (perhaps poorly done) I am starting with a TextureManager because it seems like it should be one of the more straight forward portions of the game, plus it seems critical. Thanks! Sam.
  6. *sigh* I think the purpose of this post has gotten greatly distorted.
  7. Thanks all for the tips! r++ to all those who helped :) To add to the analogy, with the knowledge of design patterns (small snippets of the blueprint) and knowing the basics of C++ syntax (tools), I should be able to go to the construction site and build stairs, a roof, the front porch, some walls, etc. So seeing that I don't know the difference between a TextureManager and a ResourceManager it appears as though I don't really know what "stairs" and "walls" are so it would be impossible to take those components and build a "house." So I guess I need to ask what a good way to learn the major players are in a game-oriented framework? I think having a fundamental understanding of the components would make it much much easier to design and use them :) Thanks for the book suggestions, I might put in a book pool order soon. Any suggestions for a good STL book/website? I have effective STL by Scott Myers, but I think I need a good introduction first because a lot of the stuff he goes over seems more advanced. Directed to Julian90, or any who can answer: Thanks for the code snippet, I have a couple of quick questions... 1) template<class Texture = Texture, class Resource = ResourceManager<>::Resource> class Texture = Texture <--- what is going on here? I haven't seen this before... is Texture also a class you have defined somewhere? 2) typedef Texture Texture; <--- I think I understand this... it just looks strange. You are doing this so that you can always use "Texture" as a type, even if change it from something other than "Texture"? As always thanks for the help, this seems like a very interesting topic to me and I look forward to the learning process.
  8. Oh yeah, I should also mention that I learn quickly from example... so if you know of any code fragments (or entire open source projects) that demonstrate a good usage of C++ that would wonderful! Thanks.
  9. Hello all, For the impatient here are the questions: I recently bought Design Patterns by the gang of four, and was just wondering what patterns I should pay close attention to in game programming? Are there patterns that show up in game development that are no listed? Are there certain patterns that I should try to avoid? What references do you suggest for C++ design, including advanced C++ usage such a template meta programming? What references do you suggest for good STL usage? Now for a little back ground: I am fairly comfortable with C++ syntax, and I have some decent reference material for when I get stuck. Admittedly my STL knowledge is quite limited... but I feel like I have a decent grasp on the language. I have quickly learned that knowing the syntax does know make you effective at using the language. A good analogy would be this: I have spent a lot of time learning to use individual tools from a work shop... hammers, saws, drills, etc. And I am comfortable with each tool. Now I am dropped in the middle of a construction site and am told I should build a house. I do not know how to effectively use the tools to form a final product. In C++ here is what I am trying to do: I am trying to design a CTextureManager... I am sure that if I could figure out generic programming it would be a CResourceManager. Each image can have multiple textures and I am trying to find a good way to store, search, describe the texture system. I am not sure I explained this real well, but it is the fuel for this entire post. If you have any insight, it would be greatly appreciated! Thanks!
  10. Something like the following? it is very crude I know, and probably poor use of C++ but I am just trying to get it working first, and then make it correct! Thanks! #include <SDL/SDL.h> #include <SDL/SDL_image.h> #include <GL/gl.h> #include <GL/glu.h> #include <vector> class CCamera { private: protected: public: CCamera(){} ~CCamera(){} GLdouble m_x, m_y, m_z; GLdouble m_near, m_far, m_fovy, m_aspect; GLdouble m_pan_deg; //Pan angle in degrees (clockwise from -z) GLdouble m_tile_deg; //Tilt angle in degrees (up from -z) }; class CRectangle { private: protected: public: CRectangle(){} ~CRectangle(){} GLdouble m_rx, m_ry, m_rz; //Axis of rotation GLdouble m_angle; GLdouble m_x, m_y, m_z; GLdouble m_width, m_height; }; class CTexturedRectangle: public CRectangle { private: protected: public: CTexturedRectangle(){} virtual ~CTexturedRectangle(){} GLuint m_tex_id, m_displaylist; GLdouble m_tex_left, m_tex_right, m_tex_top, m_tex_bottom; GLint m_tex_width, m_tex_height; virtual void load_tga(const char* const file_name) { SDL_Surface* surf; surf = IMG_Load(file_name); glGenTextures(1,&m_tex_id); m_tex_width = surf->w; m_tex_height = surf->h; glBindTexture(GL_TEXTURE_2D, m_tex_id); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); // Linear Filtering glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering gluBuild2DMipmaps(GL_TEXTURE_2D, 3, m_tex_width, m_tex_height, GL_BGR, GL_UNSIGNED_BYTE, surf->pixels); SDL_FreeSurface(surf); } }; class CAlphaTexturedRectangle: public CTexturedRectangle { private: CCamera* m_pcamera; //Used to determine distance to object protected: public: CAlphaTexturedRectangle(){} ~CAlphaTexturedRectangle(){} GLdouble m_distance; void load_tga(const char* const file_name) { SDL_Surface* surf; surf = IMG_Load(file_name); glGenTextures(1,&m_tex_id); m_tex_width = surf->w; m_tex_height = surf->h; glBindTexture(GL_TEXTURE_2D, m_tex_id); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); // Linear Filtering glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering gluBuild2DMipmaps(GL_TEXTURE_2D, 4, m_tex_width, m_tex_height, GL_BGRA, GL_UNSIGNED_BYTE, surf->pixels); SDL_FreeSurface(surf); } inline void set_camera(CCamera* pcamera) { m_pcamera = pcamera; } inline bool operator< (const CAlphaTexturedRectangle& right) { return m_distance < right.m_distance; } }; class CSnowman: public CAlphaTexturedRectangle { private: enum t_snowman {EVIL_SNOWMAN, GOOD_SNOWMAN}; t_snowman m_snowman_type; protected: public: CSnowman(){} ~CSnowman(){} }; class CSnowflake: public CTexturedRectangle { private: protected: public: CSnowflake(){} ~CSnowflake(){} }; int main(int argc, char* argv[]) { std::vector<CSnowman> snowmen; std::vector<CSnowflake> snowflakes; std::vector<CAlphaTexturedRectangle> sorted_rectangles; snowmen.resize(5); snowflakes.resize(1000); sorted_rectangles.push_back(*snowmen.begin()); return 0; }
  11. Hello, Right now I snowflakes made from texture mapped triangle strips using a 4-channel .tga file. I am storing the snowflakes (a class) in a std::vector so each frame after I populate the world with snow flakes I: 1) update the position of all snow flakes 2) calculate the distance from the eye and sort (most negative snow flake draws first) 3) determine if they are in the viewing volume and if so call the display list. This seems to work quite well. If you have any comments on how this could be improved I would love to hear them, because I am here to learn... alas I have a problem... Now I want to add snowmen to the scene who is also a 4-channel .tga texture.. seeing that these snow men also use alpha-blending they must be drawn in the correct order along with the snowflakes. Obviously my vector isn't going to work anymore. What sort of data structure could I use to hold (and sort) multiple types of objects? It would be nice if all different types of objects that use alpha blending had their own storage, because updating and drawing might require different parameters and it would be nice to know what type of object you are dealing with. Right now the only solution I can think of (and it is horrible) is something like this: for x = each snowman draw all snowflakes further away than snowman(x) draw snowman(x) end draw all snow flakes closer than final snowman. This really stings, what if I add more types of objects with alpha blending? It quickly becomes very messy. At the very least I hope you understand my problem, and if you have any helpful comments I would love to hear them! Thanks in advance, Sam
  12. Alright thanks. I can render all printable characters, but in order to make my life easier I am trying to draw lines and points while in SDL_GL_Enter2DMode(); (you know, just so I can see if I am chopping at the right point) but I can not draw anything while in 2D mode. Do you know any reason why I wouldn't be able to? Thanks, Sam
  13. Doh! I figured it out. In the print_glstr function I declared texMinX and friends as int... they should have been GLfloat. Also, I fixed the font alignment... Now you mentioned using one texture to hold all of the font information. What are the reasons/benefits of doing this? If I did store them as one texture I could just render one surface that contains all printable characters, and then "chop" the texture into display lists using the glyph metrics correct? Thanks! Sam #include <SDL/SDL.h> #include <SDL/SDL_ttf.h> #include <GL/glew.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <limits.h> #define PI 3.141592653589793238462643 typedef struct { int minx, maxx, miny, maxy, advance; GLfloat texcoord[4]; GLuint texid; } t_glyph; typedef struct { int style, pointsize, height, ascent, descent, lineskip; SDL_Color color; t_glyph glyphs[128]; } t_font; int build_font(char* filename, t_font* font); void print_glstr(int x, int y, t_font* font, char* str); void set_perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); void SDL_GL_Enter2DMode(); void SDL_GL_Leave2DMode(); static int power_of_two(int input); GLuint SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord); int main(int argc, char* argv[]) { t_font font; SDL_Surface* screen; GLenum glerr; char buffer[256]; unsigned int frame_cnt, old_ticks; GLfloat frame_rate; SDL_Color white = {0xFF, 0xFF, 0xFF, 0x00}; if ( SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO) < 0 ) { fprintf(stderr, "ERROR Initializing SDL: %s\n", SDL_GetError()); return -1; } atexit(SDL_Quit); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); screen = SDL_SetVideoMode(1024, 768, 32, SDL_OPENGL | SDL_FULLSCREEN); if ( screen == NULL ) { fprintf(stderr, "ERROR Couldn't set video mode: %s\n", SDL_GetError()); return -1; } SDL_WM_SetCaption("Sam's Font Example", 0); if ( TTF_Init() < 0 ) { fprintf(stderr, "ERROR Initializing TTF Engine: %s\n", TTF_GetError()); return -1; } atexit(TTF_Quit); glerr = glewInit(); if ( glerr != GLEW_OK ) { fprintf(stderr, "ERROR Initializing GLEW: %s\n", glewGetErrorString(glerr)); return -1; } glViewport(0, 0, screen->w, screen->h); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); set_perspective(45.0f, (GLdouble) screen->w / screen->h, 1.0f, 1000.0f); glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glShadeModel(GL_SMOOTH); font.pointsize = 20; font.style = TTF_STYLE_NORMAL; memcpy(&(font.color), &white, sizeof(SDL_Color)); if ( build_font(argv[1],&font) < 0 ) { fprintf(stderr, "ERROR building font: %s\n", TTF_GetError()); return -1; } frame_cnt = 0; old_ticks = SDL_GetTicks(); frame_rate = 0.0; while ( SDL_GetTicks() < 10000 ) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslated(0.0, 0.0, -5.0); SDL_GL_Enter2DMode(); sprintf(buffer, "Frame Rate - %f", frame_rate); print_glstr(0, font.height, &font, buffer); // print_glstr(0, 100, &font, " !\"#$%&'()*+,-./0123456789:;<=>?@"); // print_glstr(0, 200, &font, "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"); // print_glstr(0, 300, &font, "abcdefghijklmnopqrstuvwxyz{|}~"); SDL_GL_Leave2DMode(); SDL_GL_SwapBuffers(); frame_cnt++; if (frame_cnt >= 100) { frame_rate = (GLfloat)frame_cnt/((GLfloat)(SDL_GetTicks() - old_ticks)/1000.0f); old_ticks = SDL_GetTicks(); frame_cnt = 0; } } SDL_FreeSurface(screen); return 0; } int build_font(char* filename, t_font* font) { TTF_Font* ttffont; SDL_Surface* surf; int i; GLenum gl_error; ttffont = TTF_OpenFont(filename, font->pointsize); if (ttffont == NULL) { TTF_SetError("ERROR opening font: %s\n", TTF_GetError()); return -1; } TTF_SetFontStyle(ttffont, font->style); font->ascent = TTF_FontAscent(ttffont); font->descent = TTF_FontDescent(ttffont); font->height = TTF_FontHeight(ttffont); font->lineskip = TTF_FontLineSkip(ttffont); for ( i = ' '; i <= '~'; i++ ) { surf = TTF_RenderGlyph_Blended(ttffont, i, font->color); if ( surf == NULL ) { TTF_SetError("ERROR rendering glyph %c: %s\n", (char)i, TTF_GetError()); TTF_CloseFont(ttffont); return -1; } TTF_GlyphMetrics(ttffont, i, &(font->glyphs[i].minx), &(font->glyphs[i].maxx), &(font->glyphs[i].miny), &(font->glyphs[i].maxy), &(font->glyphs[i].advance)); font->glyphs[i].texid = SDL_GL_LoadTexture(surf, font->glyphs[i].texcoord); if ( (gl_error = glGetError()) != GL_NO_ERROR ) { /* If this failed, the text may exceed texture size limits */ TTF_SetError("Warning: Couldn't create texture: 0x%x\n", gl_error); SDL_FreeSurface(surf); TTF_CloseFont(ttffont); return -1; } SDL_FreeSurface(surf); } TTF_CloseFont(ttffont); return 0; } void print_glstr(int x, int y, t_font* font, char* str) { GLfloat texMinX, texMaxX, texMinY, texMaxY; GLfloat left, right, top, bottom; t_glyph* g; while (*str != 0) { g = &(font->glyphs[(int)*str]); texMinX = g->texcoord[0]; texMinY = g->texcoord[1]; texMaxX = g->texcoord[2]; texMaxY = g->texcoord[3]; left = x + g->minx; right = x + g->maxx - g->minx; top = y - g->maxy; bottom = y - g->miny; glBindTexture(GL_TEXTURE_2D, g->texid); glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(texMinX, texMinY); glVertex2f( left, top); glTexCoord2f(texMaxX, texMinY); glVertex2f(right, top); glTexCoord2f(texMinX, texMaxY); glVertex2f( left, bottom); glTexCoord2f(texMaxX, texMaxY); glVertex2f(right, bottom); glEnd(); x += g->advance; str++; } } void set_perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) { GLdouble ymax; ymax = zNear * tan(fovy * PI / 360.0f); glFrustum(-ymax*aspect, ymax*aspect, -ymax, ymax, zNear, zFar); } void SDL_GL_Enter2DMode() { SDL_Surface *screen = SDL_GetVideoSurface(); /* Note, there may be other things you need to change, depending on how you have your OpenGL state set up. */ glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); /* This allows alpha blending of 2D textures with the scene */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glViewport(0, 0, screen->w, screen->h); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0.0, (GLdouble)screen->w, (GLdouble)screen->h, 0.0, 0.0, 1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } void SDL_GL_Leave2DMode() { glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glPopAttrib(); } /* Quick utility function for texture creation */ static int power_of_two(int input) { int value = 1; while ( value < input ) { value <<= 1; } return value; } GLuint SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord) { GLuint texture; int w, h; SDL_Surface *image; SDL_Rect area; Uint32 saved_flags; Uint8 saved_alpha; /* Use the surface width and height expanded to powers of 2 */ w = power_of_two(surface->w); h = power_of_two(surface->h); texcoord[0] = 0.0f; /* Min X */ texcoord[1] = 0.0f; /* Min Y */ texcoord[2] = (GLfloat)surface->w / w; /* Max X */ texcoord[3] = (GLfloat)surface->h / h; /* Max Y */ image = SDL_CreateRGBSurface( SDL_SWSURFACE, w, h, 32, #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 #else 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF #endif ); if ( image == NULL ) { return 0; } /* Save the alpha blending attributes */ saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK); saved_alpha = surface->format->alpha; if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) { SDL_SetAlpha(surface, 0, 0); } /* Copy the surface into the GL texture image */ area.x = 0; area.y = 0; area.w = surface->w; area.h = surface->h; SDL_BlitSurface(surface, &area, image, &area); /* Restore the alpha blending attributes */ if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) { SDL_SetAlpha(surface, saved_flags, saved_alpha); } /* Create an OpenGL texture for the image */ glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); SDL_FreeSurface(image); /* No longer needed */ return texture; }
  14. Hello, I have been hacking at the SDL_ttf glfont.c example (included with the SDL_ttf source code) file in order to improve performance by pre-caching the ogl textures. As it stands right now it seems to render 'i' and 'l' correctly but all other glyphs show up as white or gray rectangles. Any help you might be able to offer would be greatly appreciated. I am not sure if this is an SDL problem I am having or an OpenGL... Here is the nice color coded version: http://paste.lisp.org/display/29373 Or see the attached code Thanks, Sam #include <SDL/SDL.h> #include <SDL/SDL_ttf.h> #include <SDL/SDL_opengl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #define PI 3.141592653589793238462643 typedef struct { int minx, maxx, miny, maxy, advance; GLfloat texcoord[4]; GLuint texid; } t_glyph; typedef struct { int style, pointsize, height, ascent, descent, lineskip; SDL_Color color; t_glyph glyphs[128]; } t_font; int build_font(char* filename, t_font* font); void print_glstr(int x, int y, t_font* font, char* str); void set_perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); void SDL_GL_Enter2DMode(); void SDL_GL_Leave2DMode(); static int power_of_two(int input); GLuint SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord); int main(int argc, char* argv[]) { t_font font; SDL_Surface* screen; SDL_Color white = {0xFF, 0xFF, 0xFF, 0x00}; if ( SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO) < 0 ) { fprintf(stderr, "ERROR Initializing SDL: %s\n", SDL_GetError()); return -1; } atexit(SDL_Quit); if ( TTF_Init() < 0 ) { fprintf(stderr, "ERROR Initializing TTF Engine: %s\n", TTF_GetError()); return -1; } atexit(TTF_Quit); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); screen = SDL_SetVideoMode(800, 600, 32, SDL_OPENGL); if ( screen == NULL ) { fprintf(stderr, "ERROR Couldn't set video mode: %s\n", SDL_GetError()); return -1; } glViewport(0, 0, screen->w, screen->h); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); set_perspective(45.0f, (GLdouble) screen->w / screen->h, 1.0f, 100.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glShadeModel(GL_SMOOTH); glClearColor(0.0, 0.0, 0.0, 1.0); font.pointsize = 20; font.style = TTF_STYLE_NORMAL; memcpy(&(font.color), &white, sizeof(SDL_Color)); if ( build_font("MONACO.TTF",&font) < 0) { fprintf(stderr, "ERROR building font: %s\n", TTF_GetError()); return -1; } while ( SDL_GetTicks() < 5000 ) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslated(0.0, 0.0, -5.0); glBegin(GL_POINTS); glVertex3d(0.0,0.0,0.0); glEnd(); SDL_GL_Enter2DMode(); print_glstr(100, 500, &font, "abcdefghijklmnopqrstuvwxyz"); SDL_GL_Leave2DMode(); SDL_GL_SwapBuffers(); } SDL_FreeSurface(screen); return 0; } int build_font(char* filename, t_font* font) { TTF_Font* ttffont; SDL_Surface* surf; int i; GLenum gl_error; ttffont = TTF_OpenFont(filename, font->pointsize); if (ttffont == NULL) { TTF_SetError("ERROR opening font: %s\n", TTF_GetError()); return -1; } TTF_SetFontStyle(ttffont, font->style); font->ascent = TTF_FontAscent(ttffont); font->descent = TTF_FontDescent(ttffont); font->height = TTF_FontHeight(ttffont); font->lineskip = TTF_FontLineSkip(ttffont); for ( i = ' '; i <= '~'; i++ ) { surf = TTF_RenderGlyph_Blended(ttffont, i, font->color); if ( surf == NULL ) { TTF_SetError("ERROR rendering glyph %c: %s\n", (char)i, TTF_GetError()); TTF_CloseFont(ttffont); return -1; } TTF_GlyphMetrics(ttffont, i, &(font->glyphs[i].minx), &(font->glyphs[i].maxx), &(font->glyphs[i].miny), &(font->glyphs[i].maxy), &(font->glyphs[i].advance)); font->glyphs[i].texid = SDL_GL_LoadTexture(surf, font->glyphs[i].texcoord); if ( (gl_error = glGetError()) != GL_NO_ERROR ) { /* If this failed, the text may exceed texture size limits */ TTF_SetError("Warning: Couldn't create texture: 0x%x\n", gl_error); SDL_FreeSurface(surf); TTF_CloseFont(ttffont); return -1; } SDL_FreeSurface(surf); } TTF_CloseFont(ttffont); return 0; } void print_glstr(int x, int y, t_font* font, char* str) { int texMinX, texMaxX, texMinY, texMaxY, i, w, h; while (*str != 0) { i = (int)*str; texMinX = font->glyphs[i].texcoord[0]; texMinY = font->glyphs[i].texcoord[1]; texMaxX = font->glyphs[i].texcoord[2]; texMaxY = font->glyphs[i].texcoord[3]; w = font->glyphs[i].maxx; h = font->glyphs[i].maxy; glBindTexture(GL_TEXTURE_2D, font->glyphs[i].texid); glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(texMinX, texMinY); glVertex2i(x, y ); glTexCoord2f(texMaxX, texMinY); glVertex2i(x+w, y ); glTexCoord2f(texMinX, texMaxY); glVertex2i(x, y+h); glTexCoord2f(texMaxX, texMaxY); glVertex2i(x+w, y+h); glEnd(); x += font->glyphs[i].advance; str++; } } void set_perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) { GLdouble ymax; ymax = zNear * tan(fovy * PI / 360.0f); glFrustum(-ymax*aspect, ymax*aspect, -ymax, ymax, zNear, zFar); } void SDL_GL_Enter2DMode() { SDL_Surface *screen = SDL_GetVideoSurface(); /* Note, there may be other things you need to change, depending on how you have your OpenGL state set up. */ glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); /* This allows alpha blending of 2D textures with the scene */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glViewport(0, 0, screen->w, screen->h); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0.0, (GLdouble)screen->w, (GLdouble)screen->h, 0.0, 0.0, 1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } void SDL_GL_Leave2DMode() { glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glPopAttrib(); } /* Quick utility function for texture creation */ static int power_of_two(int input) { int value = 1; while ( value < input ) { value <<= 1; } return value; } GLuint SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord) { GLuint texture; int w, h; SDL_Surface *image; SDL_Rect area; Uint32 saved_flags; Uint8 saved_alpha; /* Use the surface width and height expanded to powers of 2 */ w = power_of_two(surface->w); h = power_of_two(surface->h); texcoord[0] = 0.0f; /* Min X */ texcoord[1] = 0.0f; /* Min Y */ texcoord[2] = (GLfloat)surface->w / w; /* Max X */ texcoord[3] = (GLfloat)surface->h / h; /* Max Y */ image = SDL_CreateRGBSurface( SDL_SWSURFACE, w, h, 32, #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 #else 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF #endif ); if ( image == NULL ) { return 0; } /* Save the alpha blending attributes */ saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK); saved_alpha = surface->format->alpha; if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) { SDL_SetAlpha(surface, 0, 0); } /* Copy the surface into the GL texture image */ area.x = 0; area.y = 0; area.w = surface->w; area.h = surface->h; SDL_BlitSurface(surface, &area, image, &area); /* Restore the alpha blending attributes */ if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) { SDL_SetAlpha(surface, saved_flags, saved_alpha); } /* Create an OpenGL texture for the image */ glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); SDL_FreeSurface(image); /* No longer needed */ return texture; }
  15. Hmmm, if no one sees the problem right away maybe you could give me some tips on debugging applications with OpenGL? If I used a software renderer like MESA maybe I could use traditional debugging techniques? Right now I am staring at the code saying "Well, it looks like it should work!" Thanks, Sam