Sign in to follow this  
MajinMusashi

OpenGL OpenGL fonts, what is the best way to go?

Recommended Posts

I've already read some tutorials about font rendering using OpenGL, and implemented 2D Bitmap Fonts (NeHe lesson 17). Now, I'm starting a new project, and want to know if this is really the best way to follow. I know a interesting alternative: - GNU Freetype library: seems very good to me, but from what I've read from NeHe it has a somewhat bigger overhead than other methods; What do you think is the best way out? What do you currently use in your projects to output text? I'm safe with FreeType? Thanks!!! PS.: the project I'm working on must be multiplatform, thus I can't use "wgl" or other OS dependent stuff.

Share this post


Link to post
Share on other sites
For most practical purposes, you can simply make an image of the words you need and manipulate them. If I need anything larger, I usually use bitmap fonts, although I use vector arrays rather then display lists like nehe does.

Share this post


Link to post
Share on other sites
Quote:
Original post by Binomine
For most practical purposes, you can simply make an image of the words you need and manipulate them. If I need anything larger, I usually use bitmap fonts, although I use vector arrays rather then display lists like nehe does.

As I will also use text output for debugging purposes and character "speech", image words seems not to be the best way to go.

Thanks, Binomine!!!

Share this post


Link to post
Share on other sites
Quote:
Original post by Vampyre_Dark
glFont works great.
http://students.cs.byu.edu/~bfish/glfont.php


Very interesting, Vampyre, but I can't rely on a specific operating system, and this solution seems to be not so flexible.

Thanks anyway!!!

Share this post


Link to post
Share on other sites
texture fonts was the only cross platform font i could find. but its also really flexible, you can make it any color and scale and rotate it just like any other quad. check out this NeHe tutorial.

if you dont want to do that, google for "GLFT", i heard it is a good library for fonts.

Share this post


Link to post
Share on other sites
I use SDL_TTF, this implies you're using SDL, and if you're going multi platform I highly recommend it. It looks nice (AA) and supports Unicode(you can write in japanese), and it's easier to change fonts (and font size).

The problem is getting it to work (handling character returns, tabs, and getting the data to a texture) and work fast. For instance generating a new texture every frame for a fps counter will kill the fps, so you need to update the texture (or better just a subsection of it). It took me a while to get it to a nominally cost.

Bitmap fonts tend to be good enough for most peoples needs though, and they're pretty easy to get working well.

Share this post


Link to post
Share on other sites
Since I could never get SDL_TTF to work with OpenGL (More specifically I couldn't work out how to convert an SDL_Surface* to an OpenGL texture) I use BMF_Font http://trenki.50free.org/bmf/
But if something better comes along Im happy to use it.
I heard that the Freetype library is pretty hard to use.

Share this post


Link to post
Share on other sites
Quote:
Original post by sand_man
Since I could never get SDL_TTF to work with OpenGL (More specifically I couldn't work out how to convert an SDL_Surface* to an OpenGL texture) I use BMF_Font http://trenki.50free.org/bmf/
But if something better comes along Im happy to use it.
I heard that the Freetype library is pretty hard to use.


Very interesting, Sand_man! And, to convert as SDL_Surface to an OpenGL texture:


void C_Texture::createTexture( GLuint *texture, char *textureName ) {
// SDL_Surface *textureImage;
if ( textureImage = SDL_LoadBMP( textureName ) ) {
glGenTextures( 1, texture );
glBindTexture( GL_TEXTURE_2D, *texture );
glTexImage2D( GL_TEXTURE_2D, 0, 3, textureImage->w, textureImage->h, 0, GL_BGR, GL_UNSIGNED_BYTE, textureImage->pixels );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
}
}


Share this post


Link to post
Share on other sites
Quote:
Original post by Cocalus
I use SDL_TTF, this implies you're using SDL, and if you're going multi platform I highly recommend it. It looks nice (AA) and supports Unicode(you can write in japanese), and it's easier to change fonts (and font size).

Very interesting!

Quote:

The problem is getting it to work (handling character returns, tabs, and getting the data to a texture) and work fast. For instance generating a new texture every frame for a fps counter will kill the fps, so you need to update the texture (or better just a subsection of it). It took me a while to get it to a nominally cost.

Ah, using glTexSubImage2D...

[/quote]
Bitmap fonts tend to be good enough for most peoples needs though, and they're pretty easy to get working well.[/quote]
Yes, they are fine.

Share this post


Link to post
Share on other sites
As for that cost of using SDL_TTF and creating each frame new SDL_Surface through SDL_TTF and then converting it to GL texture, there is one good solution for this problem.

Say, you are creating fps counter that can rapidly change from frame to frame. You don't want to generate new texture every frame cause that would kill your performance, so what do you do? During font loading you instruct your FontMgr to generate all of 0-9 digits so that each will be prerendered on *separate* texture (1 will have its own, 2 will have its own etc.), and if you're using this font and use special function for rendering, renderer should automatically glue appropriate textures together.

So if you pass "123" using that font, renderer will render texture that "1" owns, at initial position, then it will add "1" texture width to initial position and render at that point texture for "2" etc. This gonna save you hellovalot fps.

Also, if you're sure that specific string won't change over time (ie. player or level name) then just render it once on texture and later on use that texture, no need to recreate it etc. This gonna save you even more fps.

HTH

Share this post


Link to post
Share on other sites
Ups, Nife is truly right - it's much better cause your memory won't be fragmented.
However, there is one "little" problem - for some fonts which must be generated with really big characters there is a chance that you will run out of max texture width ie. when trying to render them all horizontally. And there is no easy (and not taking too much cycles and memory) solution to this problem, because in SDL_TTF there is no easy way to tell how much space this particular character will take when rendered without actually *rendering* it, which would allow for rendering characters in rows :-/ (or am I missing something??)

Share this post


Link to post
Share on other sites
I've never worked with this library, but it seems like you could render each char to get its dimensions, and then create a single texture from the individual ones (or just rerender the bigger texture). You are going to need the dimensions for each character anyway to set up the texture coords. If you did this at startup, or even offline, the speed shouldn't be an issue.

You will absolutely want only one texture for the font however. This way you can put all your text into a single vertex array, bind only one texture, and draw everything in one go.

Share this post


Link to post
Share on other sites
Quote:

I've never worked with this library, but it seems like you could render each char to get its dimensions, and then create a single texture from the individual ones (or just rerender the bigger texture). You are going to need the dimensions for each character anyway to set up the texture coords. If you did this at startup, or even offline, the speed shouldn't be an issue.


That's why I wrote "and not taking too much cycles and memory". I've thought about it, problem is that creating new texture (ok, in reality SDL_Surface) for every glyph (more then 100 in ASCII?) for every font will take very much memory, which in turn (allocating, merging, deallocating) will be cycle expensive. Also it should be done at startup, so in theory you need to hunt throughout all your game code for font definitions and move them to startup code, which sometimes can turn to serious troubles and hacks.
Though it seems that's one of the best approaches.

Quote:
You will absolutely want only one texture for the font however. This way you can put all your text into a single vertex array, bind only one texture, and draw everything in one go.


For some games that would be true, but in my case - no, it can't be done. Not to mention GUI, where each control can have it's own font type, font size, font color, font attributes etc.

Anyway, thx for the info.

Share this post


Link to post
Share on other sites
Quote:
Original post by Koshmaar
For some games that would be true, but in my case - no, it can't be done. Not to mention GUI, where each control can have it's own font type, font size, font color, font attributes etc.


You're right, my method is only good if you're using 1 size and 1 attribute for each font (which is what I'm using). The color can always achieved by real-time coloring..

Share this post


Link to post
Share on other sites
If you want an idea of the cost of SDL_TTF, I tested my app,

with a fps counter (updated every frame) with SDL_TTF (an ostream I feed the fps into, an some other data, which totals 8 calls to SDL_TTF rendering function), with glTexSubImage2D and no mipmaps I get 1.80984ms per frame

with no fps counter at all, I get 1.5713133 ms per frame.

So the fps counter cost me about 0.23852 ms. or the difference between 60 FPS and 59.153 FPS. But it took me a while to tweak it (I use SDL bliting to combine the separate text pieces so I only call glTexSubImage2D once a frame).

Share this post


Link to post
Share on other sites
Hmm, for my font rendering, i spent quite alot of time tweaking/optimising on writing a font rendering solution.

Basically, the user defines a font like this:

Font myFont;
myFont.load("myFont.jpg","myFontWidths.dat",Color);

Basically the first parameter is the texture containing the font, the second stores the font widths and the last is self explanatory.

Each Font Object has a dynamic buffer/mesh which grows/shrinks based on what is required to be rendered for any one frame.

In my main loop i just need to do this

myFont.draw("Hello World!", 100, 100);
myFont.draw("Another line of text", 200, 200);

What happens is that everytime a draw call is made, the dynamic buffer is appended with quads/UV coordinates based on XY positions. The font does not immediately render upon executing the draw call.

When it's time to draw the frame, the font simply sets the font texture once and sends in 1 large vertex array. I use a vector for the buffer and do not deallocate the buffer at the end of the frame, i simply reuse it, this means 0 allocation/deallocation of memory. The exception is when the total characters for any 1 frame is larger than the previous.

Advantages:

1 draw call per font. (Remember draw calls are extremely expensive)
Texture fonts (I believe they are the fastest way to draw text)
Flexibility (Just change the texture for a new font, use a bigger texture for bigger fonts)
Extremely fast


Share this post


Link to post
Share on other sites
Lately I've read interesting approach to font rendering, here's quote from mail of Bob Pendelton from SDL mailing list:

Quote:

(...) For outline fonts I usually render each glyph/size/color once when it is
first used by the program and convert it to a texture at that point.
Then I draw text by texture mapping the rectangles for each individual
glyph in a string. Doing that spreads the time cost of rendering strings
out so you don't have the long pause caused by rendering every glyph in
a font. It also means you only have a texture for each glyph that has
been used. It is surprising how few glyphs are ever used. Then to, it
saves time by never rendering a glyph/size/color more than one.
Typically, if you are rendering a number of strings and you render all
of each string using SDL_ttf you will render the same glyph/size/color
many times. It seems to be a good way to render antialiased text. (...)


Later on I've asked about that memory fragmenation issue that have been discussed here, and Bob replied:

Quote:

The answer is "that depends". The way I describe doesn't have any
visible effect on runtime performance and only loads glyphs that you
actually use. But, as you point out, it might cause memory fragmentation
problems. I have never seen that problem, and there are several reasons
for that. 1) I always set a video ram budget and stick to it. The budget
is set at a percentage, usually 70% of the size of the memory on the
video cards I'm targeting. 2) Programs follow a fixed pattern in
allocating memory, first allocate all rendering buffers, second allocate
textures and such, then allocate glyphs as they are needed. By
allocating the big stuff first you avoid memory fragmentation. You only
get into problems when you free a bunch of textures and load new ones.
Not usually a problem. 3) I keep a copy of the glyph in ram so I can
free all the texture glyphs and reload them without having to rerender
them.

OTOH, It is not hard to render all of the glyphs of a font into a set
(not one, but several) textures in advance. Just write, or find, a
utility to do it for you. Then keep font data around that has the size,
texture number, and location within a texture for each glyph in the
font. Then you load the textures and use the font. This approach has
very little run time overhead, but it can use a *lot* of memory for
large fonts (serious problem for CJK fonts) and loads lots of glyphs
that you will never use. But, it might be the best way in memory tight
situations because the memory usage is always 100% predictable in
advance. Which make sticking to a memory budget a lot easier even if it
does use up memory you may never need to use.

You also have to take into account the kind of application you are
writing. If you are writing a typical, you don't have a lot of text and
don't use a lot of glyphs. If you are writing a GUI for a word processor
you are going to use a lot of glyphs.

As I said, it depends, use your best judgment based on the application
you are currently building. There is no one answer that is always better
than all the others. And, when using your judgment remember that
tomorrow memory will be cheaper and video cards will be faster.



Now that's what I call good explanation :-)

Share this post


Link to post
Share on other sites
Try Here

Here's something I knocked up which should probably mean I'll never have to write another text rendering utility ever again(as long as I stick to OpenGL). It loads the glyphs dynamically, so(with error trapping aside):


fontUtil->GetFace("Tahoma")->Select(12)->RenderText("Hello World",GLFonts::DefaultOutputOpts);


The tahoma face will be loaded automatically if it doesn't already exist, then you select which point size you need, then simply the text you wish to render, with output operations to select italicized text, alignment, etc). It still needs a bit of cleaning up as it stands, but I hope it's some help :)

The calling for rendering might seem a bit lengthy, but a quick wrapper for selecting a default font shouldn't take more than a couple of minutes to knock up :)

Also note you can use friendly font names, like "Courier New", instead of locating the TTF file yourself, you can also type in the filename if you so wish(in the case of having custom fonts you distribute with your app). Only problem with this is, that this feature is Windows only, it's easily removable from the rest of the text output util, though.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by nife
Quote:
Original post by Koshmaar
For some games that would be true, but in my case - no, it can't be done. Not to mention GUI, where each control can have it's own font type, font size, font color, font attributes etc.


You're right, my method is only good if you're using 1 size and 1 attribute for each font (which is what I'm using). The color can always achieved by real-time coloring..


You could use a simple caching scheme; its unlikely that most gui's are going to want more than one font in perhaps a couple of sizes (I mean, look at windows or a desktop linux [without a word-processor open, that's cheating!])

Share this post


Link to post
Share on other sites
What about unicode-enabled font rendering functions in OpenGL? I looked thru here, OpenGL Font Survey, but I saw nothing that either confirmed nor denied that unicode does/does not work with any of these font renderers. I'd really like to have unicode support in the game I'm writing right now, and we're using SDL so SDL_ttf is always an option, but I'm concerned about the overhead costs in converting the SDL font surfaces to OpenGL textures. (I don't have an extensive graphics background btw). We were planning on going with FTGL until we found out that it doesn't mention anything about Unicode. Thanks!

Share this post


Link to post
Share on other sites
Quote:

but I'm concerned about the overhead costs in converting the SDL font surfaces to OpenGL textures. (I don't have an extensive graphics background btw).


If you are doing it every frame, then even for small texts it's gonna bite you for no good! Ie. I've coded little application using my engine, just black screen and nothing more. It run at 70 fps (with vsync enabled), stats were displayed at upper window border. Ok, I've added 2 strings that would display coordinates of mouse cursor, ie. "122 243" etc. It was done with theese functions:


void SC :: Renderer :: RenderText(const char * _text, const char * _fontName, usint _size, const TScrPoint & _position,
uchar _r, uchar _g, uchar _b, ulint _style, eTextPosition _justify, eTextRenderMode _rMode)
{
TextObjHandle renderedText = CreateTextTexture(_text, _fontName, _size, _r, _g, _b, _style, _rMode);

TScrPoint pos (_position);

if (_justify == tp_Centered) // center text
pos.x = pos.x - (renderedText.width)/2;

if (_justify == tp_Right) // justify to right
pos.x = pos.x - renderedText.width;

boundTexture.id = renderedText.id;
boundTexture.width = PowerOfTwo(renderedText.width);
boundTexture.height = PowerOfTwo(renderedText.height);

RenderTexture(pos, renderedText.width, renderedText.height, 1, TScrPnt(0,0), renderedText.width, renderedText.height);
FreeTextObj(renderedText);
}

SC :: TextObjHandle SC :: Renderer :: CreateTextTexture(const char * _text, const char * _fontName, usint _size, uchar _r,
uchar _g, uchar _b, ulint _style, eTextRenderMode _rMode)
{
TTF_Font * font = getFontMgr.GetFont(_fontName, _size);
TextObjHandle textObj;
textObj.id = 0;

if (!font)
{
logError2("Renderer", "Couldn't find font to output text:")
return textObj;
}

TTF_SetFontStyle(font, _style);
SDL_Color clrFg = {_r, _g, _b, 0}; // color of text

SDL_Surface * tmp;

if (_rMode == trm_Solid)
tmp = TTF_RenderText_Solid( font, _text, clrFg);
else if (_rMode == trm_Blended)
tmp = TTF_RenderText_Blended( font, _text, clrFg);

if (tmp == 0)
{
logError2("Renderer", "Couldn't create texture for rendered text")
return textObj;
}

// -------------------------------------------------

// OpenGL need to use the surface with width and height expanded to powers of 2
usint w = PowerOfTwo(tmp->w);
usint h = PowerOfTwo(tmp->h);

SDL_Surface * image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);

if ( image == 0 )
{
logError2("Renderer", "Couldn't create texture for rendered text")
SC_ASSERT(0)
return textObj;
}

// copy the tmp into the GL texture image
SDL_Rect area;
area.x = 0;
area.y = 0;
area.w = tmp->w;
area.h = tmp->h;

SDL_BlitSurface(tmp, &area, image, &area);

// create an OpenGL texture for the image
glGenTextures(1, &textObj.id);
glBindTexture(GL_TEXTURE_2D, textObj.id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);

// set texture for use
textObj.width = tmp->w;
textObj.height = tmp->h;

SDL_FreeSurface(tmp);
SDL_FreeSurface(image);

return textObj;
}





As you can see, it's SDL_TTF & OpenGL version (sure, it's crappy and not optimized, but IMHO nothing great can be achieved by optimizing theese, because slowliness is caused by external code and hardware limitations). So every frame RenderText was called twice. And FPS fall to 65 - that's 2,5 frames for every rapidly changing text. As you can see, cost is really high :-/
Also, I've tested whether it was fault of dynamic texture creation or some screwed OpenGL code in RenderFont, so I've used this:



struct TextObjHandle
{
GLuint id;
ulint width, height;
};

bool SC :: Renderer :: CreateTextObject(TextObjHandle & _handle, const char * _text, const char * _fontName, usint _size,
uchar _r, uchar _g, uchar _b, ulint _style, eTextRenderMode _rMode)
{
_handle = CreateTextTexture(_text, _fontName, _size, _r, _g, _b, _style, _rMode);
return (_handle.id != 0);
}


void SC :: Renderer :: FreeTextObj(TextObjHandle & _handle)
{
glDeleteTextures(1, &_handle.id);
_handle.id = 0;
}


void SC :: Renderer :: RenderText(const TextObjHandle & _handle, const TScrPoint & _position, eTextPosition _justify)
{
TScrPoint pos (_position);

if (_justify == tp_Centered) // center text
pos.x = pos.x - (_handle.width)/2;

if (_justify == tp_Right) // justify to right
pos.x = pos.x - _handle.width;

boundTexture.id = _handle.id;
boundTexture.width = PowerOfTwo(_handle.width);
boundTexture.height = PowerOfTwo(_handle.height);
glBindTexture(GL_TEXTURE_2D, _handle.id);

RenderTexture(pos, _handle.width, _handle.height, 1, TScrPnt(0,0), _handle.width, _handle.height);
}




Created 2 static (non changing) strings, erased old ones and tested again. And you know what? It was 70 FPS :-/

In this situation you'll realize that for any serious project that uses fast changing texts with SDL_TTF & OpenGL, Bob Pendelton's solution that I've posted here before is really neccessary (obviously I will use it in my engine).

Share this post


Link to post
Share on other sites
Koshmaar: Not to be mean or anything but your test is really flawed, first testing with v-sync on is generally bad, The difference would have been huge with it off.

And it looks like you didn't use glTexSubImage2D, which is a MASSIVE optimization for this (the glGenTextures is the real problem). I went from ~16ms per frame to ~1.6ms per frame (or 60fps to 600fps).

I use ms for performance, because fps can be a misleading way to find the cost of functions, for example the difference between 1200 fps and 900 fps is the same as 60 fps and 59.016 fps. So if you write some cool function earlier in you project that's called once per frame and doesn't depend on the complexity of the scene (fps counter is a good example), but you decide to drop of it because it cost you 300 fps (when your app runs at 1200 fps), then late in your project you try to remake it and it only cost you 2 fps (when your app now runs at 60 fps), you in fact wasted your time making a slower function and would have been better off keeping the first one.

I'll say texture map fonts are probably faster in most cases and definitely easier to use efficiently. Although with a huge block of static text, SDL_TTF's ability to do it in 1 quad could be better than texture fonts, but that's an unlikely case in a game. But the cost of SDL_TTF isn't really that bad if you tweak it right (I gave 0.23852ms for a fps counter), but tweaking it is tricky, glTexSubImage2D is the biggest improvement, also huge font sizes can be become costly.

As for the Unicode thing I know SDL_TTF can (In spite of my compiler not being setup for Unicode I did get it to print out some Japanese fonts from a ttf file). And for full Unicode normal texture fonts could be be costly in texture memory. For example 2^16 different fonts at 16x16 would be 16777216 texels, for a 8 bit (for alpha blending) texture that is 16MB for one font map (64MB for 32x32 fonts, 256MB for 64x64 fonts).

From reading some of this posts I'm thinking that using a texture for a font cache from the SDL_TTF rendering function (using glTexSubImage2D to update it) could be a good system (the cost of large font sizes would be low), the tricky part (that I can see) would be handling the varying width's (ie the cache could become fragmented), and how to handle font changes (one texture per font or one texture for the system). It would loss the the 1 quad per text block of SDL_TTF (I don't think it's that helpful), and could gain a fair speed boost (I'm assuming the time for the render function is a linear to the length of the string, ie rendering "abcd" takes 4 times as long as just "a"), but you would get all the other advantages of SDL_TTF.

Share this post


Link to post
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

Sign in to follow this  

  • Forum Statistics

    • Total Topics
      628277
    • Total Posts
      2981771
  • Similar Content

    • By mellinoe
      Hi all,
      First time poster here, although I've been reading posts here for quite a while. This place has been invaluable for learning graphics programming -- thanks for a great resource!
      Right now, I'm working on a graphics abstraction layer for .NET which supports D3D11, Vulkan, and OpenGL at the moment. I have implemented most of my planned features already, and things are working well. Some remaining features that I am planning are Compute Shaders, and some flavor of read-write shader resources. At the moment, my shaders can just get simple read-only access to a uniform (or constant) buffer, a texture, or a sampler. Unfortunately, I'm having a tough time grasping the distinctions between all of the different kinds of read-write resources that are available. In D3D alone, there seem to be 5 or 6 different kinds of resources with similar but different characteristics. On top of that, I get the impression that some of them are more or less "obsoleted" by the newer kinds, and don't have much of a place in modern code. There seem to be a few pivots:
      The data source/destination (buffer or texture) Read-write or read-only Structured or unstructured (?) Ordered vs unordered (?) These are just my observations based on a lot of MSDN and OpenGL doc reading. For my library, I'm not interested in exposing every possibility to the user -- just trying to find a good "middle-ground" that can be represented cleanly across API's which is good enough for common scenarios.
      Can anyone give a sort of "overview" of the different options, and perhaps compare/contrast the concepts between Direct3D, OpenGL, and Vulkan? I'd also be very interested in hearing how other folks have abstracted these concepts in their libraries.
    • By aejt
      I recently started getting into graphics programming (2nd try, first try was many years ago) and I'm working on a 3d rendering engine which I hope to be able to make a 3D game with sooner or later. I have plenty of C++ experience, but not a lot when it comes to graphics, and while it's definitely going much better this time, I'm having trouble figuring out how assets are usually handled by engines.
      I'm not having trouble with handling the GPU resources, but more so with how the resources should be defined and used in the system (materials, models, etc).
      This is my plan now, I've implemented most of it except for the XML parts and factories and those are the ones I'm not sure of at all:
      I have these classes:
      For GPU resources:
      Geometry: holds and manages everything needed to render a geometry: VAO, VBO, EBO. Texture: holds and manages a texture which is loaded into the GPU. Shader: holds and manages a shader which is loaded into the GPU. For assets relying on GPU resources:
      Material: holds a shader resource, multiple texture resources, as well as uniform settings. Mesh: holds a geometry and a material. Model: holds multiple meshes, possibly in a tree structure to more easily support skinning later on? For handling GPU resources:
      ResourceCache<T>: T can be any resource loaded into the GPU. It owns these resources and only hands out handles to them on request (currently string identifiers are used when requesting handles, but all resources are stored in a vector and each handle only contains resource's index in that vector) Resource<T>: The handles given out from ResourceCache. The handles are reference counted and to get the underlying resource you simply deference like with pointers (*handle).  
      And my plan is to define everything into these XML documents to abstract away files:
      Resources.xml for ref-counted GPU resources (geometry, shaders, textures) Resources are assigned names/ids and resource files, and possibly some attributes (what vertex attributes does this geometry have? what vertex attributes does this shader expect? what uniforms does this shader use? and so on) Are reference counted using ResourceCache<T> Assets.xml for assets using the GPU resources (materials, meshes, models) Assets are not reference counted, but they hold handles to ref-counted resources. References the resources defined in Resources.xml by names/ids. The XMLs are loaded into some structure in memory which is then used for loading the resources/assets using factory classes:
      Factory classes for resources:
      For example, a texture factory could contain the texture definitions from the XML containing data about textures in the game, as well as a cache containing all loaded textures. This means it has mappings from each name/id to a file and when asked to load a texture with a name/id, it can look up its path and use a "BinaryLoader" to either load the file and create the resource directly, or asynchronously load the file's data into a queue which then can be read from later to create the resources synchronously in the GL context. These factories only return handles.
      Factory classes for assets:
      Much like for resources, these classes contain the definitions for the assets they can load. For example, with the definition the MaterialFactory will know which shader, textures and possibly uniform a certain material has, and with the help of TextureFactory and ShaderFactory, it can retrieve handles to the resources it needs (Shader + Textures), setup itself from XML data (uniform values), and return a created instance of requested material. These factories return actual instances, not handles (but the instances contain handles).
       
       
      Is this a good or commonly used approach? Is this going to bite me in the ass later on? Are there other more preferable approaches? Is this outside of the scope of a 3d renderer and should be on the engine side? I'd love to receive and kind of advice or suggestions!
      Thanks!
    • By nedondev
      I 'm learning how to create game by using opengl with c/c++ coding, so here is my fist game. In video description also have game contain in Dropbox. May be I will make it better in future.
      Thanks.
    • By Abecederia
      So I've recently started learning some GLSL and now I'm toying with a POM shader. I'm trying to optimize it and notice that it starts having issues at high texture sizes, especially with self-shadowing.
      Now I know POM is expensive either way, but would pulling the heightmap out of the normalmap alpha channel and in it's own 8bit texture make doing all those dozens of texture fetches more cheap? Or is everything in the cache aligned to 32bit anyway? I haven't implemented texture compression yet, I think that would help? But regardless, should there be a performance boost from decoupling the heightmap? I could also keep it in a lower resolution than the normalmap if that would improve performance.
      Any help is much appreciated, please keep in mind I'm somewhat of a newbie. Thanks!
    • By test opty
      Hi,
      I'm trying to learn OpenGL through a website and have proceeded until this page of it. The output is a simple triangle. The problem is the complexity.
      I have read that page several times and tried to analyse the code but I haven't understood the code properly and completely yet. This is the code:
       
      #include <glad/glad.h> #include <GLFW/glfw3.h> #include <C:\Users\Abbasi\Desktop\std_lib_facilities_4.h> using namespace std; //****************************************************************************** void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window); // settings const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600; const char *vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "void main()\n" "{\n" " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" "}\0"; const char *fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" "}\n\0"; //******************************* int main() { // glfw: initialize and configure // ------------------------------ glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // glfw window creation GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "My First Triangle", nullptr, nullptr); if (window == nullptr) { cout << "Failed to create GLFW window" << endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // glad: load all OpenGL function pointers if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { cout << "Failed to initialize GLAD" << endl; return -1; } // build and compile our shader program // vertex shader int vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); glCompileShader(vertexShader); // check for shader compile errors int success; char infoLog[512]; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog); cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl; } // fragment shader int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); glCompileShader(fragmentShader); // check for shader compile errors glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog); cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl; } // link shaders int shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); // check for linking errors glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl; } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); // set up vertex data (and buffer(s)) and configure vertex attributes float vertices[] = { -0.5f, -0.5f, 0.0f, // left 0.5f, -0.5f, 0.0f, // right 0.0f, 0.5f, 0.0f // top }; unsigned int VBO, VAO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); // bind the Vertex Array Object first, then bind and set vertex buffer(s), //and then configure vertex attributes(s). glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // note that this is allowed, the call to glVertexAttribPointer registered VBO // as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind glBindBuffer(GL_ARRAY_BUFFER, 0); // You can unbind the VAO afterwards so other VAO calls won't accidentally // modify this VAO, but this rarely happens. Modifying other // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind // VAOs (nor VBOs) when it's not directly necessary. glBindVertexArray(0); // uncomment this call to draw in wireframe polygons. //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // render loop while (!glfwWindowShouldClose(window)) { // input // ----- processInput(window); // render // ------ glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // draw our first triangle glUseProgram(shaderProgram); glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to // bind it every time, but we'll do so to keep things a bit more organized glDrawArrays(GL_TRIANGLES, 0, 3); // glBindVertexArray(0); // no need to unbind it every time // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) glfwSwapBuffers(window); glfwPollEvents(); } // optional: de-allocate all resources once they've outlived their purpose: glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); // glfw: terminate, clearing all previously allocated GLFW resources. glfwTerminate(); return 0; } //************************************************** // process all input: query GLFW whether relevant keys are pressed/released // this frame and react accordingly void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); } //******************************************************************** // glfw: whenever the window size changed (by OS or user resize) this callback function executes void framebuffer_size_callback(GLFWwindow* window, int width, int height) { // make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays. glViewport(0, 0, width, height); } As you see, about 200 lines of complicated code only for a simple triangle. 
      I don't know what parts are necessary for that output. And also, what the correct order of instructions for such an output or programs is, generally. That start point is too complex for a beginner of OpenGL like me and I don't know how to make the issue solved. What are your ideas please? What is the way to figure both the code and the whole program out correctly please?
      I wish I'd read a reference that would teach me OpenGL through a step-by-step method. 
  • Popular Now