Inside3D!
     

OpenGL 2D Examples - 101 The 2D Basics (w/pics)

 
Post new topic   Reply to topic    Inside3d Forums Forum Index -> OpenGL Programming
View previous topic :: View next topic  
Author Message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Mon Dec 15, 2008 12:51 pm    Post subject: OpenGL 2D Examples - 101 The 2D Basics (w/pics) Reply with quote

I'm rather unsatisfied with how difficult and scattered good OpenGL tutorials are. I'm going to document this stuff here so I can find it and so anyone else interested now or in the future can find it.

This thread is going to focus exclusively on 2D drawing because my immediate interest is exploring the possibility of more lively HUDs to go along with the more lively modding capabilities (whether CSQC or coded in engine doesn't matter to me).

Think vehicle HUDs with speedometers, "Objective Hint Displays", maybe even "mini-maps". We'll see ...

This is going to start very simple and build its way up eventually.

This focuses exclusively on drawing code:

1. No window initialization or texture upload, etc.
2. Assumes a view window of 512 x 512
3. The buffer swapping is assumed to occur at end of every frame


Last edited by Baker on Wed Dec 17, 2008 2:48 am; edited 2 times in total
Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Mon Dec 15, 2008 12:52 pm    Post subject: Reply with quote

How To Draw A Line

Objective: draw a line



Code:
// Initialization
glClearColor (0, 0, 0, 0) // Clear to black
glMatrixMode (GL_PROJECTION) // Projection view
glOrtho (0, 512, 512, 0) // Define display coordinates (left, bottom, right top)


Code:
// Render Frame
glClear (GL_COLOR_BUFFER_BIT)  // Clear it
glColor3f (1,0,0) // RGB = Red
glBegin (GL_LINES) // Draw lines
        glVertex2d (128, 256) // x1,y1
        glVertex2d (384, 256) // x2,y2
glend ()


Last edited by Baker on Tue Dec 16, 2008 2:40 am; edited 2 times in total
Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Mon Dec 15, 2008 1:02 pm    Post subject: Reply with quote

How To Draw A Rectangle

Objective: draw a rectangle

A key difference between this and the above is the use of GL_LINE_LOOP instead of GL_LINES.

GL_LINE_LOOP closes the sequence so a final line is draw from x4,y4 back to x1,y1. If you use GL_LINES, it will only draw 2 lines: x1,y1 to x2, y2 and then x3,y3 to x4,y4.



Code:
// Initialization
glClearColor (0, 0, 0, 0) // Clear to black
glMatrixMode (GL_PROJECTION) // Projection view
glOrtho (0, 512, 512, 0) // Define display coordinates (left, bottom, right top)



Code:
// Render Frame
glClear (GL_COLOR_BUFFER_BIT)  // Clear it
glColor3f (0,0,1) // RGB = Blue
glBegin (GL_LINE_LOOP) // Draw line loop
        glVertex2d (128, 128) // x1 y1
        glVertex2d (384, 128) // x2 y2
        glVertex2d (384, 384) // x3 y3
        glVertex2d (128, 384) // x4 y4
glend ()


Now ...



Draw Filled Rectangle

We are just making 1 change. Change GL_LINE_LOOP to GL_POLYGON. For the differentiation purposes, changing the color to green.


Code:
// Render Frame
glClear (GL_COLOR_BUFFER_BIT)  // Clear it
glColor3f (0,1,0) // RGB = Green
glBegin (GL_POLYGON) // Filled polygon
        glVertex2d (128, 128) // x1 y1
        glVertex2d (384, 128) // x2 y2
        glVertex2d (384, 384) // x3 y3
        glVertex2d (128, 384) // x4 y4
glend ()




Unclosed Dashed Line Sequence with Line Width

Modifying the above to use GL_LINE_STRIP, which is a series of connected lines but unlike GL_LINE_LOOP does not close it.

Also modifying the line width and using glLineStipple to make the lines dashed.


Code:

glClear (GL_COLOR_BUFFER_BIT)  // Clear it
glColor3f (1,0,0) // RGB = Yellowish

glLineWidth (4)  // Set line width to 4
glLineStipple (1, 0xf0f0)  // Repeat count, repeat pattern
glEnable (GL_LINE_STIPPLE) // Turn stipple on

glBegin (GL_LINE_STRIP) // This is like line loop, except doesn't close
        glVertex2d (128, 128) // x1 y1
        glVertex2d (384, 128) // x2 y2
        glVertex2d (384, 384) // x3 y3
        glVertex2d (128, 384) // x4 y4
glend ()
glDisable (GL_LINE_STIPPLE) // Turn it back off


Note: An RGB color table can be found at this link. RGB = red green blue with values from 0 to 255, OpenGL uses 0.0 to 1.0 to represent these values.
Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Tue Dec 16, 2008 2:50 am    Post subject: Reply with quote



How To Draw A Simple Circle

You won't be able to tell from the above resampled image, but this circle is NOT anti-aliased.

Code:
    Const PI = 3.141592
    Const X = 256
    Const Y = 256
    Const Radius = 60
   
    glColor3f (1, 0.5, 0)  // Orange
   
    glBegin (GL_POLYGON)
    For angle = 0 To PI * 2 Step 0.01 //  Circumference of circle = 2PI * r
        glVertex2f (X + Sin(angle) * Radius, Y + Cos(angle) * Radius)
    Next
    glEnd ()


Now let's take a close look at this before getting into the anti-aliasing issue. Notice the circle is NOT smooth.

Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Tue Dec 16, 2008 3:10 am    Post subject: Reply with quote



How To Draw A Simple Outlined Circle

We are getting to the anti-aliasing issue.

But first, let's draw a simple outline of a circle. Simply change GL_POLYGON to GL_LINE_LOOP.


Code:
    Const PI = 3.141592
    Const X = 256
    Const Y = 256
    Const Radius = 60
   
    glColor3f (1, 0.5, 0)  // Orange
   
    glBegin (GL_LINE_LOOP)
    For angle = 0 To PI * 2 Step 0.01 //  Circumference of circle = 2PI * r
        glVertex2f (X + Sin(angle) * Radius, Y + Cos(angle) * Radius)
    Next
    glEnd ()


Again it isn't smooth. Now we are going to smooth it.



How To Draw An Anti-Aliased Outlined Circle


Quote:
Const PI = 3.141592
Const X = 256
Const Y = 256
Const Radius = 60

glColor3f (1, 0.5, 0) // Orange

glEnable (GL_BLEND)
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable (GL_LINE_SMOOTH)

glBegin (GL_LINE_LOOP)
For angle = 0 To PI * 2 Step 0.01 // Circumference of circle = 2PI * r
glVertex2f (X + Sin(angle) * Radius, Y + Cos(angle) * Radius)
Next
glEnd ()
glDisable (GL_BLEND)


Ok, what we did above is turn blending on and then set the blending algorithm function (there are several). Then we turned line smoothing on and now the circle is anti-aliased.

We needed to do this because we are going to hit some rocks in trying to create an anti-aliased filled circle while sticking to OpenGL 1.2.

Many Intel display adapters support only OpenGL 1.2 and we don't want to rely on anything that isn't universally available. They ship as the default "video card" in tons of desktops and laptops and we're doing simple 2D graphics here and cutting out a large % of computer would be crazy.


Last edited by Baker on Tue Dec 16, 2008 3:42 am; edited 1 time in total
Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Tue Dec 16, 2008 3:35 am    Post subject: Reply with quote

Failing At Drawing An Anti-Aliased Filled Circle

Ok, in the immediately above example we made an anti-aliased circle outline usign GL_LINE_SMOOTH.

So all we need to do is take the filled circle code from a couple of examples ago and use GL_POLYGON_SMOOTH.


Quote:
Const PI = 3.141592
Const X = 256
Const Y = 256
Const Radius = 60

glColor3f (1, 0.5, 0) // Orange
glEnable (GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable (GL_POLYGON_SMOOTH)

glBegin (GL_POLYGON)
For angle = 0 To PI * 2 Step 0.01 // Circumference of circle = 2PI * r
glVertex2f (X + Sin(angle) * Radius, Y + Cos(angle) * Radius)
Next
glEnd ()
glDisable (GL_BLEND)


Easy! Right? ... If fishes were wishes ...



Succeeding At Drawing An Anti-Aliased Filled Circle


We are getting an effect called tessellation where as the pixels are drawn, the anti-alias is creating this effect.

I know of no easy way to solve this with OpenGL 1.2 and I've found a lot of dead-ends. So let's do this another way:

1. Then we draw the filled circle without anti-aliasing
2. We will draw the anti-aliased outline of the circle.
3. Result = anti-aliased circle.

(No we aren't going to use OpenGL 2.0, that isn't acceptable .. we want OpenGL 1.2 for broad compatibility particularly with Intel display adapters .. see above. Nor do we want to use an ARB extension, we shouldn't be at the mercy of an extension being available.)

Code:
    Const PI = 3.141592
    Const X = 256
    Const Y = 256
    Const Radius = 60
       
    glClear (GL_COLOR_BUFFER_BIT)
   
    // Draw the filled circle
   
    glColor3f (1, 0.5, 0)       '// Set to orange
   
   
    glBegin (GL_POLYGON)
    For angle = 0 To PI * 2 Step 0.01
        glVertex2f (X + Sin(angle) * Radius, Y + Cos(angle) * Radius)
    Next
    glEnd ()

    // Draw the anti-aliased outline
   
    glEnable (GL_BLEND)
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glEnable (GL_LINE_SMOOTH)
    glBegin (GL_LINE_LOOP)
    For angle = 0 To PI * 2 Step 0.01
        glVertex2f(X + Sin(angle) * Radius, Y + Cos(angle) * Radius)
    Next
    glDisable (GL_BLEND)
    glEnd ()




So we combine them together and viola ....

Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Tue Dec 16, 2008 7:59 am    Post subject: Reply with quote



Drawing a Generic Speedometer

Ok, we can draw a circle. Can draw lines. A point is just using GL_POINT instead of GL_LINES.

Let's draw a quicky speedometer and have the needle.

Code:
    Static mph = 0
   
    mph = (mph + 1) Mod 160
   
    Const pi = 3.141592
    Const X = 256
    Const Y = 256
    Const Radius = 120
       
    glClear (GL_COLOR_BUFFER_BIT)
   
    // Draw the outline
   
    glColor3f (1, 0.5, 0)
   
    // Draw the filled circle
    glLineWidth (1)
    glBegin(GL_POLYGON)
    For angle = 0 To pi * 2 Step 0.01
        // Let's toy with the color a little to make it a gradient
        colorgrad = 0.2 - angle * 0.1
        glColor3f (colorgrad, colorgrad, colorgrad)
       
        glVertex2f (X + Sin(angle) * Radius, Y + Cos(angle) * Radius)
    Next
    glEnd ()
     
   
    // Speed marks
   
    glLineWidth (1)
    glColor3f (0.8, 0.8, 0.8)  // Mostly whiteish
    glEnable (GL_BLEND)
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glEnable (GL_LINE_SMOOTH)
    glBegin (GL_LINES)
   
    // This looks a little ugly, I'll explain ...
    startangle = 2 * PI * 0.125  // We are starting the marks at 12.5% left of bottom center
    endangle = 2 * PI - startangle // We are ending the marks at 12.5% right of bottom center
    usableRange = 2 * PI * 0.75  // Our usable range is 75% of the diameter
   
    For angle =  startangle to endangle Step usableRange / 10  // We want 11 marks so we divide by 10
        glVertex2f (X + Sin(angle) * Radius * 0.8, Y + Cos(angle) * Radius * 0.8)  // We start the line inside a little
        glVertex2f (X + Sin(angle) * Radius, Y + Cos(angle) * Radius)  // To the end point at the edge
    Next
    glEnd ()
    glDisable (GL_BLEND)
   
    // Outline
   
    glColor3f (0.4, 0.4, 0.4) // Grayish
    glLineWidth (5)
    glEnable (GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glEnable (GL_LINE_SMOOTH)
    glBegin (GL_LINE_LOOP)
    For angle = 0 To pi * 2 Step 0.01
        glVertex2f (X + Sin(angle) * Radius, Y + Cos(angle) * Radius)
    Next
    glDisable (GL_BLEND)
    glEnd ()

    // Draw the needle
    glColor3f (0.5, 0, 0) // Red
    glLineWidth (5) // Let's make it wider
    glEnable (GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glEnable (GL_LINE_SMOOTH)
    glBegin (GL_LINES)
   
    // Here is our formula, the 20 represents the starting point = 0 and the 200 represents 100% of the range
    // So each MPH is 0.5% of the diameter
    // Confused?  Don't worry about it.
   
    angle = (1 - ((mph + 20) / 200)) * 2 * pi  // each ticker value of 1 represents 0.5% degrees with a free 10% starting point = 0
       // ticker range is constrained to 75% of radius
        glVertex2f (X + Sin(angle) * Radius * -0.03, Y + Cos(angle) * Radius * -0.03)
        glVertex2f (X + Sin(angle) * Radius * 0.9, Y + Cos(angle) * Radius * 0.9)
   
    glDisable (GL_BLEND)
    glEnd ()

    // Here is the little thing holding the needle in place
    // Let's make it small and subtle
    // But it helps give us a sense of centeredness
   
    glPointSize (2)
    glColor3f (0.2, 0, 0)  // Dark Red
     
    glEnable (GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glEnable (GL_POINT_SMOOTH)
       
    glBegin(GL_POINTS)
        glVertex2f (X, Y)
    glEnd ()
    glDisable (GL_BLEND)
Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Tue Dec 16, 2008 8:13 am    Post subject: Reply with quote



Drawing a Cool Speedometer

Not going to cover texture loading (see post #1). It is a lot of fumbling around with the bytes and then working within the framework of the "the texture size must be a power of 2" fun.

Code:
    Static mph = 0
    mph = (mph + 1) Mod 100
       
    Const PI = 3.141592
    Const X = 256
    Const Y = 256
    Const Radius = 90
       
    glClear GL_COLOR_BUFFER_BIT
   
    // Some texture constants
    Const glsl = 0
    Const gltl = 0
    Const glsh = 1
    Const glth = 1
    Const Halfpicwidth = 128
    Const Halfpicheight = 128
   
    // Draw our speedometer texture
    glColor4f (1, 1, 1, 1)
    glEnable (GL_TEXTURE_2D)  // Enable 2d texture
    glBindTexture (GL_TEXTURE_2D, SpeedometerTexture)  // Select texture
   
    // Coordinates
    glBegin (GL_QUADS)
       glTexCoord2f (glsl, gltl)
       glVertex2f (X - Halfpicwidth , Y - Halfpicheight )
       glTexCoord2f (glsh, gltl)
       glVertex2f (X + Halfpicwidth , Y - Halfpicheight )
       glTexCoord2f (glsh, glth)
       glVertex2f (X + Halfpicwidth , Y + Halfpicheight )
       glTexCoord2f (glsl, glth)
       glVertex2f (X - Halfpicwidth , Y + Halfpicheight )
    glEnd ()
    glDisable (GL_TEXTURE_2D)

    // Needle
    glColor3f (0.9, 0.7, 0.2)  // Yellowish orange
    glLineWidth (2)
    glEnable (GL_BLEND)
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glEnable (GL_LINE_SMOOTH)
    glBegin (GL_LINES)
        // Like last time, this is just translating the MPH to the range we get to use
        angle = (1 - ((mph * 1.2 + 40) / 200)) * 2 * pi
   
        glVertex2f (X + Sin(angle) * Radius * -0.03, Y + Cos(angle) * Radius * -0.03)
        glVertex2f (X + Sin(angle) * Radius * 0.9, Y + Cos(angle) * Radius * 0.9)
   
    glDisable (GL_BLEND)
    glEnd ()

    // We need something holding the needle in place
    glPointSize (2)
    glColor3f (0.2, 0, 0)      // Dark Red
     
    glEnable (GL_BLEND)
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glEnable (GL_POINT_SMOOTH)
       
    glBegin (GL_POINTS)
        glVertex2f(X, Y)
    glEnd ()
    glDisable (GL_BLEND)

Back to top
View user's profile Send private message
Willem



Joined: 23 Jan 2008
Posts: 73

PostPosted: Tue Dec 16, 2008 10:56 am    Post subject: Reply with quote

Hey, thanks for the info on stippling. I had no idea OpenGL could do that! I've added it to a few places in my editor code now. Smile
_________________
www.wantonhubris.com
Back to top
View user's profile Send private message Visit poster's website
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Wed Dec 17, 2008 2:47 am    Post subject: Reply with quote

Willem wrote:
Hey, thanks for the info on stippling. I had no idea OpenGL could do that! I've added it to a few places in my editor code now. Smile


Hey if I ever decide to learn Objective-C I'll probably be deciphering TogTag's source, so back at ya. Very Happy
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Inside3d Forums Forum Index -> OpenGL Programming All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2004 phpBB Group