Write a buffer to a file WITHOUT opening a window?

So, I’m writing a buffer to a file as a bitmap. I want to be able to run this program without ever actually launching the winow, preferrably on a machine that isn’t even running X concurrently. Is this possible? I’m using GLUT to do it all, and it seems that no drawing to buffers occurs until glutMainLoop is entered-- and this automatically draws the window. Suggestions?
Cheers,
Michael

Originally posted by mrshirts:
So, I’m writing a buffer to a file as a bitmap. I want to be able to run this program without ever actually launching the winow, preferrably on a machine that isn’t even running X concurrently. Is this possible? I’m using GLUT to do it all, and it seems that no drawing to buffers occurs until glutMainLoop is entered-- and this automatically draws the window. Suggestions?
Cheers,
Michael

Just browsing through the Red Book revealed:

Create surfaces that support rendering (both on-screen and off-screen):

glXCreatePixmap …
glXCreatePbuffer …

Maybe these functions would help?

I’m going to try playing around with them right now…
I’ll post my code here if I get anywhere.

Hope this helps

Here’s my code… this draws a lit sphere to a
.bmp file.

This will not make a window, but I think it does
require that an X server be running.

CFLAGS = -I/usr/X11R6/include

all: render2bmp

render2bmp: render2bmp.o
cc -o render2bmp render2bmp.o -L/usr/X11R6/lib -lglut -lGLU -lGL -lXext -lX11

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <GL/glx.h>
#include <GL/glu.h>

void Render(int w, int h)
{
/* Draw a lit sphere /
/
Taken right out of the red book */
GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0};
GLfloat diffuse_material[] = {0.5, 0.5, 0.5, 1.0};

glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse_material);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 25.0);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);

glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);

glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h) {
glOrtho(-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,
1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
} else {
glOrtho(-1.5*(GLfloat)w/(GLfloat)h,
1.5*(GLfloat)w/(GLfloat)h,
-1.5, 1.5, -10.0, 10.0);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSolidSphere(1.0, 20, 16);
glFlush();
}

int MakeBMP(const char *fname, const unsigned char image, int w, int h)
{
/
See http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/BMP.txt */
struct BMPHeader {
unsigned short type;
unsigned int size;
unsigned short res1;
unsigned short res2;
unsigned int offset;
} attribute((packed)) header;
struct BMPInfo {
unsigned int size;
unsigned int width;
unsigned int height;
unsigned short planes;
unsigned short bit_count;
unsigned int comp;
unsigned int sizeImage;
unsigned int x_pels_per_meter;
unsigned int y_pels_per_meter;
unsigned int clr_used;
unsigned int clr_important;
} attribute((packed)) info;
FILE *fp;
int ret = 0;

/* Open file /
fp = fopen(fname, “wb”);
if (!fp) {
fprintf(stderr,
"Unable to open %s for writing
",
fname);
ret = -1;
} else {
/
Header */
header.type = ‘B’ | ‘M’ << 8;
header.size = sizeof(header) + sizeof(info) + w * h * 3;
header.res1 = header.res2 = 0;
header.offset = sizeof(header) + sizeof(info);
info.size = sizeof(info);
info.width = w;
info.height = h;
info.planes = 1;
info.bit_count = 24;
info.comp = 0;
info.sizeImage = w * h * 3;
info.x_pels_per_meter = info.y_pels_per_meter = 0;
info.clr_used = 0;
info.clr_important = 0;

  fwrite(&header, sizeof(header), 1, fp);
  fwrite(&info, sizeof(info), 1, fp);
  
  fwrite(image, sizeof(unsigned char), h*w*3, fp);

}

if (fp) {
fclose(fp);
}

return ret;
}

int main(int argc, char **argv)
{
Display *dpy = NULL;
XVisualInfo *vi = NULL;
GLXContext cx = NULL;
Pixmap pmap;
GLXPixmap glxpmap ;
unsigned char *image = NULL;
const int attrib_list[] = {GLX_DOUBLEBUFFER, GLX_RGBA,
GLX_DEPTH_SIZE, 16,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
None};
const int width = 300;
const int height = 300;
int ret = 0;

/* Create a pixmap to render into */
dpy = XOpenDisplay(NULL);
if (dpy == NULL) {
fprintf(stderr, "Could not open display
");
ret = -1;
goto abort;
}

if (!glXQueryExtension(dpy, NULL, NULL)) {
fprintf(stderr, "X server has no GLX extension
");
ret = -1;
goto abort;
}

vi = glXChooseVisual(dpy, DefaultScreen(dpy), (int *)attrib_list);
if (vi == NULL) {
fprintf(stderr, "could not create visual
");
ret = -1;
goto abort;
}

cx = glXCreateContext(dpy, vi, NULL, 0);

if (cx == NULL) {
fprintf(stderr, "could not create rendering context
");
ret = -1;
goto abort;
}

pmap = XCreatePixmap(dpy, RootWindow(dpy, vi->screen),
width, height, vi->depth);
glxpmap = glXCreateGLXPixmap(dpy, vi, pmap);
glXMakeCurrent(dpy, glxpmap, cx);

/* Now render scene */
Render(width, height);

/* Save the frame buffer to a BMP */
image = (unsigned char )malloc(sizeof(unsigned char)widthheight3);
if (!image) {
fprintf(stderr, "Unable to allocate image buffer
");
ret = -1;
goto abort;
}
glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, image);
MakeBMP(“render2bmp.bmp”, image, width, height);

/* Clean up /
abort:
if (cx && dpy) {
glXDestroyContext(dpy, cx);
}
if (dpy) {
/
MesaGL seems to be missing this… doesn’t link so well /
/
glXDestroyPixmap(dpy, glxpmap); */
}
if (dpy) {
XFreePixmap(dpy, pmap);
}
if (dpy) {
XCloseDisplay(dpy);
}
if (image) {
free(image);
}

return ret;
}

Hope this helps

If you do not need hardware rendering you could use OSMesa which renders right into a memory buffer.

Judd Tracy