GLIM Version 0.3 released.

GLIM - OpenGL Immediate Mode Emulation

has been released in version 0.3.

Check it out.

GLIM gives you an interface very much like OpenGL’s own immediate mode. It uses no deprecated functions, so it can be used with OpenGL 3.x and it works very well with GLSL shaders, without the need to worry how to bind vertex-arrays to shaders, etc. It is intended for when you want to render small or medium sized pieces of geometry, and just want to get it done easily. It uses VBOs internally and achieves decent performance.

New in release 0.3 is, that you can now specify batches of geometry once and render them as often, as you like, sort of like a geometry-only display-list. This achieves very good performance.

An example:




void RenderStuff (bool bRecreate)
{
	static GLIM_BATCH glim;
	
	// clear the batch, if the geometry shall be recreated
	if (bRecreate)
		glim.Clear ();
		
	// if it is not yet created, do it
	if (glim.isCleared ())
	{
		glim.BeginBatch ();
		
			// define the shader attribute "Color"
			glim.Attribute4ub ("Color", 255, 0, 0, 255);

			// define a red quad
			glim.Begin (GLIM_QUADS);
				glim.Vertex (-1, -1, 0);
				glim.Vertex (1, -1, 0);
				glim.Vertex (1, 1, 0);
				glim.Vertex (-1, 1, 0);
			glim.End ();
	
		glim.EndBatch ();
	}
	
	// bind shader, set states ...
	
	// render the geometry
	glim.RenderBatch ();
}



This is only a very basic example, but it should show that the interface is very straight-forward to use. All you need to do is bind a GLSL shader, that contains the attribute “Color” and GLIM will do the rest at the “RenderBatch” call.

If you simply want to render constantly changing data, you can actually ignore calling “Clear” and “isCleared” altogether.

Have fun with it,
Jan.

Cool, works on Linux with only minor changes. The header name Main.h is a little indescript :wink: To make and install it as a library permanently it would be better to have a more descriptive header name like glim.h.

Here’s a simple test code modified from lighthouse tutorials. Uses glut and glew.


/*

Simple Demo for GLSL
www.lighthouse3d.com

modifed to try-out GLIM

Note the expected shaders files are;

minimal.vert
------------
attribute vec4 Color;
varying vec4 gl_FrontColor; // writable on the vertex shader
void main()
{  
  gl_FrontColor = Color;
  gl_Position = ftransform();
}

minimal.frag
------------
void main()
{
  gl_FragColor = gl_Color;
}

*/
#include <GL/glew.h>
#include <GL/glut.h>

#include "../Main.h"      // for glim

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

GLfloat gAngle = 0;
GLuint v,f,p;

void RenderGLIMStuff (bool bRecreate)
{
  static NS_GLIM::GLIM_BATCH glim;

  // clear the batch, if the geometry shall be recreated
  if (bRecreate)
    glim.Clear ();

  // if it is not yet created, do it
  if (glim.isCleared ())
  {
    glim.BeginBatch ();

    // define the shader attribute "Color"
    glim.Attribute4ub ("Color", 255, 0, 0, 255);

    // define a red quad
    glim.Begin (NS_GLIM::GLIM_QUADS);
      glim.Attribute4ub ("Color", 255,   0,   0, 255); glim.Vertex (-1,-1, 0);
      glim.Attribute4ub ("Color", 255, 255,   0, 255); glim.Vertex ( 1,-1, 0);
      glim.Attribute4ub ("Color", 255,   0, 255, 255); glim.Vertex ( 1, 1, 0);
      glim.Attribute4ub ("Color", 255, 255, 255, 255); glim.Vertex (-1, 1, 0);
    glim.End ();

    glim.EndBatch ();
  }

  // bind shader, set states ...

  // render the geometry
  glim.RenderBatch ();
}

void renderScene(void)
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glLoadIdentity();
  gluLookAt(0.0,0.0,5.0,
    0.0,0.0,-1.0,
    0.0f,1.0f,0.0f);

  glRotatef(gAngle,0,1,1);
  RenderGLIMStuff(0);

  glutSwapBuffers();
}

void timer(int value)
{
  const int desiredFPS=120;
  glutTimerFunc(1000/desiredFPS, timer, ++value);
  GLfloat dt = 1./desiredFPS;

  //put your specific idle code here
  //... this code will run at desiredFPS
  gAngle += dt*360./8.; //rotate 360 degrees every 8 seconds
  //end your specific idle code here

  glutPostRedisplay(); // initiate display() call at desiredFPS rate
}

void processNormalKeys(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:  // escape key
         exit(0);
         break;
      default:
         break;
   }
}

void changeSize(int w, int h)
{
  // Prevent a divide by zero, when window is too short
  // (you cant make a window of zero width).
  if(h == 0) h = 1;
  float ratio = 1.0* w / h;

  // Set the viewport to be the entire window
  glViewport(0, 0, w, h);

  // Reset the coordinate system before modifying
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45,ratio,1,1000);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

char *textFileRead(const char *fn) 
{
  FILE *fp;
  char *content = NULL;

  int count=0;

  if (fn != NULL) {
    fp = fopen(fn,"rt");

    if (fp != NULL) {
      
      fseek(fp, 0, SEEK_END);
      count = ftell(fp);
      rewind(fp);

      if (count > 0) {
        content = (char *)malloc(sizeof(char) * (count+1));
        count = fread(content,sizeof(char),count,fp);
        content[count] = '\0';
      }
      fclose(fp);
    }
  }
  return content;
}

#define printOpenGLError() printOglError(__FILE__, __LINE__)

int printOglError(char *file, int line)
{
  //
  // Returns 1 if an OpenGL error occurred, 0 otherwise.
  //
  GLenum glErr;
  int    retCode = 0;

  glErr = glGetError();
  while (glErr != GL_NO_ERROR)
  {
    printf("glError in file %s @ line %d: %s
", file, line, gluErrorString(glErr));
    retCode = 1;
    glErr = glGetError();
  }
  return retCode;
}

void printShaderInfoLog(GLuint obj)
{
  int infologLength = 0;
  int charsWritten  = 0;
  char *infoLog;

  glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

  if (infologLength > 0)
  {
    infoLog = (char *)malloc(infologLength);
    glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
    printf("%s
",infoLog);
    free(infoLog);
  }
}

void printProgramInfoLog(GLuint obj)
{
  int infologLength = 0;
  int charsWritten  = 0;
  char *infoLog;

  glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

  if (infologLength > 0)
  {
    infoLog = (char *)malloc(infologLength);
    glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
    printf("%s
",infoLog);
    free(infoLog);
  }
}

void setShaders()
{
  char *vs = NULL,*fs = NULL;

  v = glCreateShader(GL_VERTEX_SHADER);
  f = glCreateShader(GL_FRAGMENT_SHADER);

  vs = textFileRead("minimal.vert");
  fs = textFileRead("minimal.frag");

  const char * vv = vs;
  const char * ff = fs;

  glShaderSource(v, 1, &vv,NULL);
  glShaderSource(f, 1, &ff,NULL);

  free(vs);free(fs);

  glCompileShader(v);
  glCompileShader(f);

  printShaderInfoLog(v);
  printShaderInfoLog(f);

  p = glCreateProgram();
  glAttachShader(p,v);
  glAttachShader(p,f);

  glLinkProgram(p);
  printProgramInfoLog(p);

  glUseProgram(p);
}

void clearShaders(void) 
{
  printf("Clearing up memory ...
");
  glDeleteProgram(p);
  glDeleteShader(f);
  glDeleteShader(v);
}

void init(void) 
{
  glClearColor(1.0,1.0,1.0,1.0);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);
}

int main(int argc, char **argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
  glutCreateWindow("GLIM HelloWorld");

  glewInit();
  assert(glewIsSupported("GL_VERSION_2_0"));

  glutDisplayFunc(renderScene);
  glutTimerFunc(0,timer,0);
  glutKeyboardFunc(processNormalKeys);
  glutReshapeFunc(changeSize);

  init();
  setShaders();
  atexit(clearShaders);

  glutMainLoop();

  return 0;
}

Wow! Great!

Yeah, maybe it’s a good idea to change the headers name. I’ll consider it for the next release. In the mean-time feedback about bugs, or the interface or anything else is appreciated.

Jan.