Sign in to follow this  

OpenGL Building a GUI system ( Maybe from scratch)

This topic is 1420 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Dear people, I'm involved on a project where I have to create an user Interface (GUI system) that must to run across multiple platforms.

I did some research and found that there is plenty of libraries out there, like GiGi, GLUI, CEGUI, and a lot of others, including QT.

Most of the Libraries that I found are built upon OpenGL and SDL but I'm not confident of using any of them yet. Maybe because they are little confusing, but for sure because in one of the target plataforms , there is nothing more that openGL-ES. The libraries I found are simply not ready for the platform.

 

So, I started thinking on implementing the Gui system from scratch, even because the requirements are not so big. I need some buttons and other basic controls, editable text fields, and maybe a window to show 3D objects. I would be convinced of implementig the Gui upon OpenGL, maybe SDL to increase portability. But I'm still in doubt between two approaches I imagined.

 

Ipproach 1: Creating GUI elements as textured 3D rectangles.

I could have a sprite sheet to contain the graphics for most of the basic GUI elements, and a reusable mesh , so It would not have too many draw calls. I'm affraid of using this approach because the editable text fields. I think the texture for those elements must be procedural and unique for each text field, And I will have a lot of them, So it will increase the number of draw calls per frame as I need to redraw all the scene in openGL  ( Of  course  there is the option of not clear the buffer and redraw only the object that changed. but I´m not sure if it is a good Idea in OpenGL )

 

Ipproach 2: Using OpenGL only as a flipping multiplatform surface.

 

I could build the entire GUI as single texture. The GUI would be rasterized on a big buffer, and than used as a texture for a 3D rectangle that covers all openGL viewport. Using this approach, despite the Window would be flipped at a great frame rate, the texture that actually contains the Gui can be redrawn only when something changes. In fact , the only part that must be redrawn is the element that changed, and its children. That approach was proven at the old days of Graphic interfacing, using Win32 GDI. But in those days we did not rasterize in HD. 

 

So, I would like to ask you people, if anyone have built a GUI from scratch like the ways above , or something completly different. I? just trying to choose the best patch here . .

Edited by Artur Corrêa

Share this post


Link to post
Share on other sites

Hello,

 

It depends on your target platforms, and what kind of content you have to display. First approach is fine on PC with modern hardware.

 

If you have large texts to display, it may be a good idea to not redraw everthing every frame.

 

But have you considered mixing the 2 approches ? Using a method 1 to draw in a render texture ?

Share this post


Link to post
Share on other sites
An incresingly popular option - one I haven't tried myself but will be sometime this year on a commercial project - is to use something like CEF (Chromium Embedded Framework) or Awesomium. You really don't need to overthink performance too much outside of in-game HUDs, and even then you can usually tolerate a few frame's lag. Chrome does all its rendering in a separate process and then you feed the result of that into the scene as an overlay when it's ready. Gives you the full flexibility of HTML/CSS/JS/canvas for making your GUIs (which is a very strong option given all the work that's gone into making open source frameworks for easy to use and beautiful web interfaces) as well as letting you integrate Web content (think Unity's asset store or the like).

IF you do build things on your own, don't worry so much about text. Draw the text input fields as if they were empty so they draw efficiently like every other GUI element. Keep their clip regions for text around. Then do another pass drawing the text output for all text fields on that layer combined, calculating the glyph placement with the clip regions. If you have only a single font and no overlapping GUI elements/layers, you'll need only a single extra draw call. Even if you do have a few fonts and layers, we're talking only a handful of extra draw calls. Even if it were a lot, the render performance doesn't matter that much outside of the real-time game screen. Optimize where it matters and don't waste time/effort where it doesn't.

Share this post


Link to post
Share on other sites

I'm using something similar to what you described in Approach 1. No problems with performance (although my projects aren't gui heavy), for gui heavy stuff I tend to prefer using Gtk and Qt (when i use C++) or WPF (WinForms in older days) once I work with C#.

 

As for implementation, in my current version I already have most of GUI elements that are generally used (starting with buttons, checkboxes, through comboboxes, sliders, ending with switchable containers) -> I've also created a simple language to describe my GUI elements, the harder part is actually allowing to specify actions inside the file (F.e. by function name - which works quite well for me).

 

I'd also like to note that making a renderer for GUI is just a minor thing (the whole GUI logic is larger part - especially when you want to describe GUI using some kind of data files).

Share this post


Link to post
Share on other sites
Thanks for the answers people
 
DTR666 , Mixing two approaches. Nice sugestion,  I have considered  something a bit different: Using approach 2 for the most complex elements, like text, those would be rasterized on a proper texture. The others could use approach 1. 
 
Seam, Thanks. I will do some research about Chromium Embbeded Framework. 
 
Vilem, Thanks for the advice, You are right. I think I will not create or use a language for describing the GUI. I think I will do it programmatically, with C++ interfaces and objects. But It will for sure have the degree of  complexity you sugest. 

Share this post


Link to post
Share on other sites

If rolling your own, I would also suggest the combo of 1 and 2. I worked out a basic Gui, working with colored triangles(I hadn't implemented textures at the time), and implementing everything essential the same way as wn32 has.

 

The GUI was rendered immediately when it needed a responsive update(button depressed, popup windows, to a full screen quad, and also regularly as a task for things like data being updated from the simulation(ike the FPS metric). During the normal render loop this was blitted to a fullscreen quad drawn with a single call.

 

Creating a plethora of different GUI objects was quite a bit of work, daunting even, considering how novice I was/am. A great learning exercise for sure, but something I would not likely repeat. The idea of CSS/HTML support really appeals to me so I think CEF would be the way to go.

Share this post


Link to post
Share on other sites

This topic is 1420 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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  

  • Similar Content

    • By xhcao
      Does sync be needed to read texture content after access texture image in compute shader?
      My simple code is as below,
      glUseProgram(program.get());
      glBindImageTexture(0, texture[0], 0, GL_FALSE, 3, GL_READ_ONLY, GL_R32UI);
      glBindImageTexture(1, texture[1], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
      glDispatchCompute(1, 1, 1);
      // Does sync be needed here?
      glUseProgram(0);
      glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
      glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                     GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
      glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
       
      Compute shader is very simple, imageLoad content from texture[0], and imageStore content to texture[1]. Does need to sync after dispatchCompute?
    • By Jonathan2006
      My question: is it possible to transform multiple angular velocities so that they can be reinserted as one? My research is below:
      // This works quat quaternion1 = GEQuaternionFromAngleRadians(angleRadiansVector1); quat quaternion2 = GEMultiplyQuaternions(quaternion1, GEQuaternionFromAngleRadians(angleRadiansVector2)); quat quaternion3 = GEMultiplyQuaternions(quaternion2, GEQuaternionFromAngleRadians(angleRadiansVector3)); glMultMatrixf(GEMat4FromQuaternion(quaternion3).array); // The first two work fine but not the third. Why? quat quaternion1 = GEQuaternionFromAngleRadians(angleRadiansVector1); vec3 vector1 = GETransformQuaternionAndVector(quaternion1, angularVelocity1); quat quaternion2 = GEQuaternionFromAngleRadians(angleRadiansVector2); vec3 vector2 = GETransformQuaternionAndVector(quaternion2, angularVelocity2); // This doesn't work //quat quaternion3 = GEQuaternionFromAngleRadians(angleRadiansVector3); //vec3 vector3 = GETransformQuaternionAndVector(quaternion3, angularVelocity3); vec3 angleVelocity = GEAddVectors(vector1, vector2); // Does not work: vec3 angleVelocity = GEAddVectors(vector1, GEAddVectors(vector2, vector3)); static vec3 angleRadiansVector; vec3 angularAcceleration = GESetVector(0.0, 0.0, 0.0); // Sending it through one angular velocity later in my motion engine angleVelocity = GEAddVectors(angleVelocity, GEMultiplyVectorAndScalar(angularAcceleration, timeStep)); angleRadiansVector = GEAddVectors(angleRadiansVector, GEMultiplyVectorAndScalar(angleVelocity, timeStep)); glMultMatrixf(GEMat4FromEulerAngle(angleRadiansVector).array); Also how do I combine multiple angularAcceleration variables? Is there an easier way to transform the angular values?
    • By dpadam450
      I have this code below in both my vertex and fragment shader, however when I request glGetUniformLocation("Lights[0].diffuse") or "Lights[0].attenuation", it returns -1. It will only give me a valid uniform location if I actually use the diffuse/attenuation variables in the VERTEX shader. Because I use position in the vertex shader, it always returns a valid uniform location. I've read that I can share uniforms across both vertex and fragment, but I'm confused what this is even compiling to if this is the case.
       
      #define NUM_LIGHTS 2
      struct Light
      {
          vec3 position;
          vec3 diffuse;
          float attenuation;
      };
      uniform Light Lights[NUM_LIGHTS];
       
       
    • By pr033r
      Hello,
      I have a Bachelor project on topic "Implenet 3D Boid's algorithm in OpenGL". All OpenGL issues works fine for me, all rendering etc. But when I started implement the boid's algorithm it was getting worse and worse. I read article (http://natureofcode.com/book/chapter-6-autonomous-agents/) inspirate from another code (here: https://github.com/jyanar/Boids/tree/master/src) but it still doesn't work like in tutorials and videos. For example the main problem: when I apply Cohesion (one of three main laws of boids) it makes some "cycling knot". Second, when some flock touch to another it scary change the coordination or respawn in origin (x: 0, y:0. z:0). Just some streng things. 
      I followed many tutorials, change a try everything but it isn't so smooth, without lags like in another videos. I really need your help. 
      My code (optimalizing branch): https://github.com/pr033r/BachelorProject/tree/Optimalizing
      Exe file (if you want to look) and models folder (for those who will download the sources):
      http://leteckaposta.cz/367190436
      Thanks for any help...

    • By Andrija
      I am currently trying to implement shadow mapping into my project , but although i can render my depth map to the screen and it looks okay , when i sample it with shadowCoords there is no shadow.
      Here is my light space matrix calculation
      mat4x4 lightViewMatrix; vec3 sun_pos = {SUN_OFFSET * the_sun->direction[0], SUN_OFFSET * the_sun->direction[1], SUN_OFFSET * the_sun->direction[2]}; mat4x4_look_at(lightViewMatrix,sun_pos,player->pos,up); mat4x4_mul(lightSpaceMatrix,lightProjMatrix,lightViewMatrix); I will tweak the values for the size and frustum of the shadow map, but for now i just want to draw shadows around the player position
      the_sun->direction is a normalized vector so i multiply it by a constant to get the position.
      player->pos is the camera position in world space
      the light projection matrix is calculated like this:
      mat4x4_ortho(lightProjMatrix,-SHADOW_FAR,SHADOW_FAR,-SHADOW_FAR,SHADOW_FAR,NEAR,SHADOW_FAR); Shadow vertex shader:
      uniform mat4 light_space_matrix; void main() { gl_Position = light_space_matrix * transfMatrix * vec4(position, 1.0f); } Shadow fragment shader:
      out float fragDepth; void main() { fragDepth = gl_FragCoord.z; } I am using deferred rendering so i have all my world positions in the g_positions buffer
      My shadow calculation in the deferred fragment shader:
      float get_shadow_fac(vec4 light_space_pos) { vec3 shadow_coords = light_space_pos.xyz / light_space_pos.w; shadow_coords = shadow_coords * 0.5 + 0.5; float closest_depth = texture(shadow_map, shadow_coords.xy).r; float current_depth = shadow_coords.z; float shadow_fac = 1.0; if(closest_depth < current_depth) shadow_fac = 0.5; return shadow_fac; } I call the function like this:
      get_shadow_fac(light_space_matrix * vec4(position,1.0)); Where position is the value i got from sampling the g_position buffer
      Here is my depth texture (i know it will produce low quality shadows but i just want to get it working for now):
      sorry because of the compression , the black smudges are trees ... https://i.stack.imgur.com/T43aK.jpg
      EDIT: Depth texture attachment:
      glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT24,fbo->width,fbo->height,0,GL_DEPTH_COMPONENT,GL_FLOAT,NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fbo->depthTexture, 0);
  • Popular Now