Building a simple 2D graphics library in SDL

Sage
Posts: 1,403
Joined: 2005.07
Post: #16
You are not reinventing the wheel.

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
jab630
Unregistered
 
Post: #17
unknown Wrote:You are not reinventing the wheel.
Writing a routine that draws a rectangle? That seems to me a bit like reinventing the wheel.

Google turned up a number of libraries for OpenGL:

CPW
Fast Light Toolkit
Freeglut
GLFW
GLOW Toolkit
GLT and GlutMaster
NGL
OpenML

Does anyone who has used any of these know if one is particularly well suited to what I need to do?
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #18
There aren't any libraries that are better suited to what your stated requirements at the top of this thread are than plain old OpenGL. Making a routine to draw a rectangle in OpenGL is not considered reinventing the wheel -- it's pretty basic and only takes a few lines. Trying to stack another library on top isn't going to help for your project. Annoying as it may seem, maybe you should take a stab at it. Start at http://nehe.gamedev.net/ to find the basics you're looking for.
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #19
you say:

Quote:Like I said, I don't want to reinvent the wheel, and these seem like such basic things, though the setup to do them in OpenGL is annoying enough that a 2D OpenGL library ought to exist.

and

Quote:I just want to make sure I'm not going to be reinventing the wheel before I go at it.

then:

Quote:Writing a routine that draws a rectangle? That seems to me a bit like reinventing the wheel.


I say, wtf are you asking about reinventing the wheel then, eh?
You are not reinventing the wheel because everyone in the world isn't going to start using your design, its just something you should get done asap so you can do somthing more interesting and non trivial sooner.


edit: Maybe you want to try out somthing like METAL BASIC http://www.iit.edu/~sarimar/GDS/

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Member
Posts: 168
Joined: 2004.10
Post: #20
jab630 Wrote:Writing a routine that draws a rectangle? That seems to me a bit like reinventing the wheel.

But you're not doing that, you're writing a routine which calls an API call to draw a rectangle, and you're giving it the specifics of that rectangle, such as it's texture, position, size, place of each vertex etc. The wheel has already been invented, and what you're doing is utilising it.
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #21
glBegin(GL_QUADS);

//4 glVertex2f calls

glEnd();

that's pretty damn easy. Even the circle, which would normally be the hardest, is made easy with a gluDisk call.
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #22
Or just glRect().
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #23
heh, I forgot all about that. Rasp
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #24
The only things you're doing that will require writing any much code at all are images and circles. You should be able to use some trig you learned age 14 to do the circle in 10 minutes. That only leaves images, and yes, there are plenty of third-party libraries for loading images. Which one you choose will depend on your requirements.
Quote this message in a reply
Member
Posts: 749
Joined: 2003.01
Post: #25
Quote:You should be able to use some trig you learned age 14 to do the circle in 10 minutes.
How would you code a circle? personally i woud just take a big circle bitmap and then scale it at the right size. Otherwise use a gluDisk.

if not what, draw it "by lines"? (calculate the left_x and the right_x for every y and draw the horizonta line?) That would work in a "pixelated" enviroment, but wouldn't fit nicely in the more "abstract" opengl setting. Or just replicate a gluDisk?

©h€ck øut µy stuƒƒ åt ragdollsoft.com
New game in development Rubber Ninjas - Mac Games Downloads
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #26
The circle bitmap might be the right approach, but depending on the size variation of the circles, you might have to do some funky stuff to use different resolution textures.

The "obvious" way to do it with geometry is to draw it with a single TRIANGLE_FAN -- put the initial point in the center of the circle, and calculate some number of points around the circumference using basic trig.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #27
Here, I wrote the library. You have to provide the OpenGL context. You also have to provide the image loading, which is noted in the source. Then simply call INIT once at startup, and call UPDATE every frame, giving it the bounds of your GL context. I didn't spend even one brain-cycle on doing *any* optimizations -- It's all brute force here ;-) There are probably a whole bunch of mistakes in there too, but I tested it minimally and it works just fine as far as I can tell.

If somebody sees something that really bothers them or they'd like to add to it, or change it, then feel free to knock yourself out ;-) Maybe actually code the circle function using something other than gluDisk as I did. Maybe write a silly little texture loader? Whatever, have fun with it...

Here's the header "jab630LIB.h":

Code:
typedef const char*        String;

void CIRCLE(String ID, int x, int y, int radius, int R, int G, int B);
void RECTANGLE(String ID, int x, int y, int width, int height, int R, int G, int B);
void IMAGE(String ID, String filename, int x, int y, int width, int height);
void HIDE(String ID);
void DELETE(String ID);
void SHOW(String ID);
void MOVE(String ID, int x, int y);
void RESIZE(String ID, int width, int height);
void ROTATE(String ID, int degrees);
void UPDATE(int boundsWidth, int boundsHeight);
void INIT(void);
void QUIT();

Here's the C file "jab630LIB.c":
Code:
#include "jab630LIB.h"
#include <stdlib.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/glu.h>

#define    MAX_ENTITIES    256
#define kVISIBLE        1
#define kHIDDEN            0

enum
{
    kNOTHING,
    kCIRCLE,
    kRECTANGLE,
    kIMAGE
};

typedef struct
{
    GLint    type;
    GLint    visibility;
    GLubyte    R, G, B;
    GLint    x, y;
    GLint    width, height;
    GLint    heading;
    GLuint    imageID;
} Entity;

Entity            entity[MAX_ENTITIES];
GLUquadricObj    *circle = NULL;

static void DrawCircle(Entity *entity);
static void DrawRectangle(Entity *entity);
static void DrawSprite(Entity *entity);

void CIRCLE(String ID, int x, int y, int radius, int R, int G, int B)
{
    int    i;
    
    i = atoi(ID);
    if (i > MAX_ENTITIES - 1 || i < 0) return;
    entity[i].type = kCIRCLE;
    entity[i].visibility = kVISIBLE;
    entity[i].R = R;
    entity[i].G = G;
    entity[i].B = B;
    entity[i].x = x;
    entity[i].y = y;
    entity[i].width = radius * 2;
    entity[i].height = radius * 2;
    entity[i].heading = 0;
    entity[i].imageID = 0;
}

void RECTANGLE(String ID, int x, int y, int width, int height, int R, int G, int B)
{
    int    i;
    
    i = atoi(ID);
    if (i > MAX_ENTITIES - 1 || i < 0) return;
    entity[i].type = kRECTANGLE;
    entity[i].visibility = kVISIBLE;
    entity[i].R = R;
    entity[i].G = G;
    entity[i].B = B;
    entity[i].x = x;
    entity[i].y = y;
    entity[i].width = width;
    entity[i].height = height;
    entity[i].heading = 0;
    entity[i].imageID = 0;
}

void IMAGE(String ID, String filename, int x, int y, int width, int height)
{
    int    i;
    
    i = atoi(ID);
    if (i > MAX_ENTITIES - 1 || i < 0) return;
    entity[i].type = kIMAGE;
    entity[i].visibility = kVISIBLE;
    entity[i].R = 255;
    entity[i].G = 255;
    entity[i].B = 255;
    entity[i].x = x;
    entity[i].y = y;
    entity[i].width = width;
    entity[i].height = height;
    entity[i].heading = 0;
    
    // ***** TBD *****
    // get your own texture id from OpenGL using something like:
    // entity[i].imageID = LoadMyImage(filename);
    
    // - for now it's just a meaningless placeholder
    // - you'll have to ask someone for help if you don't know what to do here
    entity[i].imageID = 0;
}

void HIDE(String ID)
{
    int    i;
    
    i = atoi(ID);
    if (i > MAX_ENTITIES - 1 || i < 0) return;
    entity[i].visibility = kHIDDEN;
}

void DELETE(String ID)
{
    int    i;
    
    i = atoi(ID);
    entity[i].type = kNOTHING;
}

void SHOW(String ID)
{
    int    i;
    
    i = atoi(ID);
    if (i > MAX_ENTITIES - 1 || i < 0) return;
    entity[i].visibility = kVISIBLE;
}

void MOVE(String ID, int x, int y)
{
    int    i;
    
    i = atoi(ID);
    if (i > MAX_ENTITIES - 1 || i < 0) return;
    entity[i].x += x;
    entity[i].y += y;
}

void RESIZE(String ID, int width, int height)
{
    int    i;
    
    i = atoi(ID);
    if (i > MAX_ENTITIES - 1 || i < 0) return;
    entity[i].width = width;
    entity[i].height = height;
}

void ROTATE(String ID, int degrees)
{
    int    i;
    
    i = atoi(ID);
    if (i > MAX_ENTITIES - 1 || i < 0) return;
    entity[i].heading += degrees;
    
    while (entity[i].heading > 360)
        entity[i].heading -= 360;
    while (entity[i].heading < 0)
        entity[i].heading += 360;
}

void UPDATE(int boundsWidth, int boundsHeight)
{
    int    i;
    
    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(0, 0, (GLfloat)boundsWidth, (GLfloat)boundsHeight);
    
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    gluOrtho2D(0.0f, (GLfloat)boundsWidth, 0.0f, (GLfloat)boundsHeight);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    
    glLoadIdentity();
    
    for (i = 0; i < MAX_ENTITIES; i++)
    {
        if (entity[i].type == kNOTHING ||
            entity[i].visibility != kVISIBLE) continue;
        switch (entity[i].type)
        {
            case kCIRCLE:
                DrawCircle(&entity[i]);
                break;
            case kRECTANGLE:
                DrawRectangle(&entity[i]);
                break;
            case kIMAGE:
                DrawSprite(&entity[i]);
                break;
            default:
                continue;
        }
    }
                

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
}

void INIT(void)
{
    int    i;
    
    for (i = 0; i < MAX_ENTITIES; i++)
    {
        entity[i].type = kNOTHING;
    }
    
    if (circle == NULL)
    {
        circle = gluNewQuadric();
    }
    
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_LIGHTING);
}

void QUIT(void)
{
    ExitToShell();
}

static void DrawCircle(Entity *entity)
{
    GLdouble    radius;
    
    radius = (GLdouble)entity->width * 0.25;
    
    glPushMatrix();
    glDisable(GL_TEXTURE_2D);
    glColor3ub(entity->R, entity->G, entity->B);
    glTranslatef((GLfloat)entity->x, (GLfloat)entity->y, 0.0f);
    gluDisk(circle, 0.0, radius, 20, 1);
    glPopMatrix();
}

static void DrawRectangle(Entity *entity)
{
    GLint    halfWidth = entity->width * 0.5f;
    GLint    halfHeight = entity->height * 0.5f;
    
    glPushMatrix();
    glDisable(GL_TEXTURE_2D);
    glColor3ub(entity->R, entity->G, entity->B);
    glTranslatef((GLfloat)entity->x, (GLfloat)entity->y, 0.0f);
    glRotatef(entity->heading, 0.0f, 0.0f, 1.0f);
    glRecti(-halfWidth, -halfHeight, halfWidth, halfHeight);
    glPopMatrix();
}

static void DrawSprite(Entity *entity)
{
    GLint    halfWidth = entity->width * 0.5f;
    GLint    halfHeight = entity->height * 0.5f;
    
    glPushMatrix();
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, entity->imageID);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glTranslatef((GLfloat)entity->x, (GLfloat)entity->y, 0.0f);
    glRotatef(entity->heading, 0.0f, 0.0f, 1.0f);
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f);
        glVertex2i(- halfWidth, -halfHeight);
        glTexCoord2f(1.0f, 0.0f);
        glVertex2i(halfWidth, -halfHeight);
        glTexCoord2f(1.0f, 1.0f);
        glVertex2i(halfWidth, halfHeight);
        glTexCoord2f(0.0f, 1.0f);
        glVertex2i(-halfWidth, halfHeight);
    glEnd();
    glPopMatrix();
}
Quote this message in a reply
jab630
Unregistered
 
Post: #28
AnotherJake:
Thanks for going above and beyond. I'm actually going to stick with SDL for the following reasons:
- The graphics I'm doing are so simple that it will be plenty fast enough.
- The most important thing is that this be simple and straightforward to maintain since I'm graduating this semester and the people who will be using it don't have that much programming experience and no OpenGL experience.
- Someone on gamedev.net just told me about sdl_draw (http://sourceforge.net/projects/sdl-draw/), which is exactly what I'm looking for.

Thanks anyway,
Josh
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #29
You could also check out sdl_prim and sdl_gfx. I've used those before.

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #30
jab630 Wrote:AnotherJake:
Thanks for going above and beyond. I'm actually going to stick with SDL for the following reasons...
Sure, no problem. I was under the impression that you were looking for speed, so I figured I'd demonstrate just how easy it is to do with OpenGL. It's less than 300 lines including the header -- maybe only fifty of which have anything to do with OpenGL. But anyway, hey, if you think you've found a better way to suit your needs, then by all means, rock on!
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Free, Portable Graphics loading library/Header Jones 5 3,119 Feb 7, 2006 12:15 PM
Last Post: Zekaric
  Building SDL Framework &amp; miniaturize fix PowerMacX 3 3,746 Oct 22, 2004 06:31 PM
Last Post: PowerMacX
  SDL Simple Graphics? IBethune 1 3,221 Jun 29, 2003 04:51 AM
Last Post: OneSadCookie