|
/* |
|
* This is a modified version of osdemo.c that will draw the utah teapot in an |
|
* offscreen buffer, then write it to a file. - Matt |
|
* |
|
* Hacked together from: |
|
* - osdemo.c (ftp://ftp.freedesktop.org/pub/mesa/demos/8.3.0/mesa-demos-8.3.0.tar.gz) |
|
* - glut_teapot.c (https://www.opengl.org/resources/libraries/glut/glut37.zip) |
|
* - teapot.c (https://www.cs.uaf.edu/~cs381/examples/teapot.c) |
|
*/ |
|
|
|
/* |
|
* Demo of off-screen Mesa rendering |
|
* |
|
* See Mesa/include/GL/osmesa.h for documentation of the OSMesa functions. |
|
* |
|
* If you want to render BIG images you'll probably have to increase |
|
* MAX_WIDTH and MAX_Height in src/config.h. |
|
* |
|
* This program is in the public domain. |
|
* |
|
* Brian Paul |
|
* |
|
* PPM output provided by Joerg Schmalzl. |
|
* ASCII PPM output added by Brian Paul. |
|
* |
|
* Usage: osdemo [filename] |
|
*/ |
|
|
|
/* Copyright (c) Mark J. Kilgard, 1994. */ |
|
|
|
/** |
|
(c) Copyright 1993, Silicon Graphics, Inc. |
|
|
|
ALL RIGHTS RESERVED |
|
|
|
Permission to use, copy, modify, and distribute this software |
|
for any purpose and without fee is hereby granted, provided |
|
that the above copyright notice appear in all copies and that |
|
both the copyright notice and this permission notice appear in |
|
supporting documentation, and that the name of Silicon |
|
Graphics, Inc. not be used in advertising or publicity |
|
pertaining to distribution of the software without specific, |
|
written prior permission. |
|
|
|
THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU |
|
"AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR |
|
OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF |
|
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO |
|
EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE |
|
ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR |
|
CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, |
|
INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, |
|
SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR |
|
NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY |
|
OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR |
|
PERFORMANCE OF THIS SOFTWARE. |
|
|
|
US Government Users Restricted Rights |
|
|
|
Use, duplication, or disclosure by the Government is subject to |
|
restrictions set forth in FAR 52.227.19(c)(2) or subparagraph |
|
(c)(1)(ii) of the Rights in Technical Data and Computer |
|
Software clause at DFARS 252.227-7013 and/or in similar or |
|
successor clauses in the FAR or the DOD or NASA FAR |
|
Supplement. Unpublished-- rights reserved under the copyright |
|
laws of the United States. Contractor/manufacturer is Silicon |
|
Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA |
|
94039-7311. |
|
|
|
OpenGL(TM) is a trademark of Silicon Graphics, Inc. |
|
*/ |
|
|
|
/* |
|
* teapot.c |
|
* This program displays the Utah teapot. |
|
* Modified from OpenGL Programming Guide (red book) by MGR - 071103 |
|
* |
|
* Copyright (c) 1993-1999, Silicon Graphics, Inc. |
|
* OpenGL(R) is a registered trademark of Silicon Graphics, Inc. |
|
*/ |
|
|
|
#include <math.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include "GL/osmesa.h" |
|
#include "gl_wrap.h" |
|
#include <stdlib.h> |
|
|
|
static int Width = 400; |
|
static int Height = 400; |
|
GLuint teapotList; |
|
|
|
/* Rim, body, lid, and bottom data must be reflected in x and |
|
y; handle and spout data across the y axis only. */ |
|
|
|
static int patchdata[][16] = |
|
{ |
|
/* rim */ |
|
{102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, |
|
12, 13, 14, 15}, |
|
/* body */ |
|
{12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, |
|
24, 25, 26, 27}, |
|
{24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, |
|
37, 38, 39, 40}, |
|
/* lid */ |
|
{96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, |
|
101, 0, 1, 2, 3,}, |
|
{0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, |
|
113, 114, 115, 116, 117}, |
|
/* bottom */ |
|
{118, 118, 118, 118, 124, 122, 119, 121, 123, 126, |
|
125, 120, 40, 39, 38, 37}, |
|
/* handle */ |
|
{41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, |
|
53, 54, 55, 56}, |
|
{53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, |
|
28, 65, 66, 67}, |
|
/* spout */ |
|
{68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, |
|
80, 81, 82, 83}, |
|
{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, |
|
92, 93, 94, 95} |
|
}; |
|
/* *INDENT-OFF* */ |
|
|
|
static float cpdata[][3] = |
|
{ |
|
{0.2, 0, 2.7}, {0.2, -0.112, 2.7}, {0.112, -0.2, 2.7}, {0, |
|
-0.2, 2.7}, {1.3375, 0, 2.53125}, {1.3375, -0.749, 2.53125}, |
|
{0.749, -1.3375, 2.53125}, {0, -1.3375, 2.53125}, {1.4375, |
|
0, 2.53125}, {1.4375, -0.805, 2.53125}, {0.805, -1.4375, |
|
2.53125}, {0, -1.4375, 2.53125}, {1.5, 0, 2.4}, {1.5, -0.84, |
|
2.4}, {0.84, -1.5, 2.4}, {0, -1.5, 2.4}, {1.75, 0, 1.875}, |
|
{1.75, -0.98, 1.875}, {0.98, -1.75, 1.875}, {0, -1.75, |
|
1.875}, {2, 0, 1.35}, {2, -1.12, 1.35}, {1.12, -2, 1.35}, |
|
{0, -2, 1.35}, {2, 0, 0.9}, {2, -1.12, 0.9}, {1.12, -2, |
|
0.9}, {0, -2, 0.9}, {-2, 0, 0.9}, {2, 0, 0.45}, {2, -1.12, |
|
0.45}, {1.12, -2, 0.45}, {0, -2, 0.45}, {1.5, 0, 0.225}, |
|
{1.5, -0.84, 0.225}, {0.84, -1.5, 0.225}, {0, -1.5, 0.225}, |
|
{1.5, 0, 0.15}, {1.5, -0.84, 0.15}, {0.84, -1.5, 0.15}, {0, |
|
-1.5, 0.15}, {-1.6, 0, 2.025}, {-1.6, -0.3, 2.025}, {-1.5, |
|
-0.3, 2.25}, {-1.5, 0, 2.25}, {-2.3, 0, 2.025}, {-2.3, -0.3, |
|
2.025}, {-2.5, -0.3, 2.25}, {-2.5, 0, 2.25}, {-2.7, 0, |
|
2.025}, {-2.7, -0.3, 2.025}, {-3, -0.3, 2.25}, {-3, 0, |
|
2.25}, {-2.7, 0, 1.8}, {-2.7, -0.3, 1.8}, {-3, -0.3, 1.8}, |
|
{-3, 0, 1.8}, {-2.7, 0, 1.575}, {-2.7, -0.3, 1.575}, {-3, |
|
-0.3, 1.35}, {-3, 0, 1.35}, {-2.5, 0, 1.125}, {-2.5, -0.3, |
|
1.125}, {-2.65, -0.3, 0.9375}, {-2.65, 0, 0.9375}, {-2, |
|
-0.3, 0.9}, {-1.9, -0.3, 0.6}, {-1.9, 0, 0.6}, {1.7, 0, |
|
1.425}, {1.7, -0.66, 1.425}, {1.7, -0.66, 0.6}, {1.7, 0, |
|
0.6}, {2.6, 0, 1.425}, {2.6, -0.66, 1.425}, {3.1, -0.66, |
|
0.825}, {3.1, 0, 0.825}, {2.3, 0, 2.1}, {2.3, -0.25, 2.1}, |
|
{2.4, -0.25, 2.025}, {2.4, 0, 2.025}, {2.7, 0, 2.4}, {2.7, |
|
-0.25, 2.4}, {3.3, -0.25, 2.4}, {3.3, 0, 2.4}, {2.8, 0, |
|
2.475}, {2.8, -0.25, 2.475}, {3.525, -0.25, 2.49375}, |
|
{3.525, 0, 2.49375}, {2.9, 0, 2.475}, {2.9, -0.15, 2.475}, |
|
{3.45, -0.15, 2.5125}, {3.45, 0, 2.5125}, {2.8, 0, 2.4}, |
|
{2.8, -0.15, 2.4}, {3.2, -0.15, 2.4}, {3.2, 0, 2.4}, {0, 0, |
|
3.15}, {0.8, 0, 3.15}, {0.8, -0.45, 3.15}, {0.45, -0.8, |
|
3.15}, {0, -0.8, 3.15}, {0, 0, 2.85}, {1.4, 0, 2.4}, {1.4, |
|
-0.784, 2.4}, {0.784, -1.4, 2.4}, {0, -1.4, 2.4}, {0.4, 0, |
|
2.55}, {0.4, -0.224, 2.55}, {0.224, -0.4, 2.55}, {0, -0.4, |
|
2.55}, {1.3, 0, 2.55}, {1.3, -0.728, 2.55}, {0.728, -1.3, |
|
2.55}, {0, -1.3, 2.55}, {1.3, 0, 2.4}, {1.3, -0.728, 2.4}, |
|
{0.728, -1.3, 2.4}, {0, -1.3, 2.4}, {0, 0, 0}, {1.425, |
|
-0.798, 0}, {1.5, 0, 0.075}, {1.425, 0, 0}, {0.798, -1.425, |
|
0}, {0, -1.5, 0.075}, {0, -1.425, 0}, {1.5, -0.84, 0.075}, |
|
{0.84, -1.5, 0.075} |
|
}; |
|
|
|
static float tex[2][2][2] = |
|
{ |
|
{ {0, 0}, |
|
{1, 0}}, |
|
{ {0, 1}, |
|
{1, 1}} |
|
}; |
|
|
|
static void |
|
teapot(GLint grid, GLdouble scale, GLenum type) |
|
{ |
|
float p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3]; |
|
long i, j, k, l; |
|
|
|
glPushAttrib(GL_ENABLE_BIT | GL_EVAL_BIT); |
|
glEnable(GL_AUTO_NORMAL); |
|
glEnable(GL_NORMALIZE); |
|
glEnable(GL_MAP2_VERTEX_3); |
|
glEnable(GL_MAP2_TEXTURE_COORD_2); |
|
glPushMatrix(); |
|
glRotatef(270.0, 1.0, 0.0, 0.0); |
|
glScalef(0.5 * scale, 0.5 * scale, 0.5 * scale); |
|
glTranslatef(0.0, 0.0, -1.5); |
|
for (i = 0; i < 10; i++) { |
|
for (j = 0; j < 4; j++) { |
|
for (k = 0; k < 4; k++) { |
|
for (l = 0; l < 3; l++) { |
|
p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; |
|
q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l]; |
|
if (l == 1) |
|
q[j][k][l] *= -1.0; |
|
if (i < 6) { |
|
r[j][k][l] = |
|
cpdata[patchdata[i][j * 4 + (3 - k)]][l]; |
|
if (l == 0) |
|
r[j][k][l] *= -1.0; |
|
s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; |
|
if (l == 0) |
|
s[j][k][l] *= -1.0; |
|
if (l == 1) |
|
s[j][k][l] *= -1.0; |
|
} |
|
} |
|
} |
|
} |
|
glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, |
|
&tex[0][0][0]); |
|
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, |
|
&p[0][0][0]); |
|
glMapGrid2f(grid, 0.0, 1.0, grid, 0.0, 1.0); |
|
glEvalMesh2(type, 0, grid, 0, grid); |
|
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, |
|
&q[0][0][0]); |
|
glEvalMesh2(type, 0, grid, 0, grid); |
|
if (i < 6) { |
|
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, |
|
&r[0][0][0]); |
|
glEvalMesh2(type, 0, grid, 0, grid); |
|
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, |
|
&s[0][0][0]); |
|
glEvalMesh2(type, 0, grid, 0, grid); |
|
} |
|
} |
|
glPopMatrix(); |
|
glPopAttrib(); |
|
} |
|
|
|
void APIENTRY |
|
glutSolidTeapot(GLdouble scale) |
|
{ |
|
teapot(14, scale, GL_FILL); |
|
} |
|
|
|
void APIENTRY |
|
glutWireTeapot(GLdouble scale) |
|
{ |
|
teapot(10, scale, GL_LINE); |
|
} |
|
|
|
/* |
|
* Initialize depth buffer, projection matrix, light source, and lighting |
|
* model. Do not specify a material property here. |
|
*/ |
|
void init(void) |
|
{ |
|
GLfloat ambient[] = {0.1, 0.1, 0.1, 1.0}; |
|
GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0}; |
|
GLfloat specular[] = {1.0, 1.0, 1.0, 1.0}; |
|
GLfloat position[] = { 1.0, 1.0, 1.0, 0.0 }; |
|
|
|
GLfloat lmodel_ambient[] = {0.2, 0.2, 0.2, 1.0}; |
|
GLfloat local_view[] = {0.0}; |
|
|
|
glShadeModel(GL_FLAT); |
|
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); |
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); |
|
glLightfv(GL_LIGHT0, GL_POSITION, position); |
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); |
|
glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view); |
|
|
|
glFrontFace(GL_CW); |
|
glEnable(GL_LIGHTING); |
|
glEnable(GL_LIGHT0); |
|
glEnable(GL_AUTO_NORMAL); |
|
glEnable(GL_NORMALIZE); |
|
glEnable(GL_DEPTH_TEST); |
|
/* be efficient--make teapot display list */ |
|
teapotList = glGenLists(1); |
|
glNewList (teapotList, GL_COMPILE); |
|
glutSolidTeapot(5.0); |
|
glEndList (); |
|
} |
|
|
|
/* |
|
* Move object into position. Use 3rd through 12th |
|
* parameters to specify the material property. Draw a teapot. |
|
*/ |
|
void renderTeapot(GLfloat x, GLfloat y, |
|
GLfloat ambr, GLfloat ambg, GLfloat ambb, |
|
GLfloat difr, GLfloat difg, GLfloat difb, |
|
GLfloat specr, GLfloat specg, GLfloat specb, GLfloat shine) |
|
{ |
|
GLfloat mat[4]; |
|
|
|
glPushMatrix(); |
|
glTranslatef(x, y, 0.0); |
|
mat[0] = ambr; mat[1] = ambg; mat[2] = ambb; mat[3] = 1.0; |
|
glMaterialfv(GL_FRONT, GL_AMBIENT, mat); |
|
mat[0] = difr; mat[1] = difg; mat[2] = difb; |
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat); |
|
mat[0] = specr; mat[1] = specg; mat[2] = specb; |
|
glMaterialfv(GL_FRONT, GL_SPECULAR, mat); |
|
glMaterialf(GL_FRONT, GL_SHININESS, shine * 128.0); |
|
glCallList(teapotList); |
|
glPopMatrix(); |
|
} |
|
|
|
/** |
|
* First column: emerald, jade, obsidian, pearl, ruby, turquoise |
|
* 2nd column: brass, bronze, chrome, copper, gold, silver |
|
* 3rd column: black, cyan, green, red, white, yellow plastic |
|
* 4th column: black, cyan, green, red, white, yellow rubber |
|
*/ |
|
void display(void) |
|
{ |
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
|
renderTeapot(8.0, 8.0, |
|
0.1, 0.5, 0.1, |
|
0.1, 0.5, 0.1, |
|
0.1, 0.5, 0.1, 0.25); |
|
glFlush(); |
|
} |
|
|
|
void reshape(int w, int h) |
|
{ |
|
glViewport(0, 0, (GLsizei) w, (GLsizei) h); |
|
glMatrixMode(GL_PROJECTION); |
|
glLoadIdentity(); |
|
if (w <= h) |
|
glOrtho(0.0, 16.0, 0.0, 16.0*(GLfloat)h/(GLfloat)w, |
|
-10.0, 10.0); |
|
else |
|
glOrtho(0.0, 16.0*(GLfloat)w/(GLfloat)h, 0.0, 16.0, |
|
-10.0, 10.0); |
|
glMatrixMode(GL_MODELVIEW); |
|
} |
|
|
|
static void |
|
render_image(void) |
|
{ |
|
init(); |
|
reshape(Width, Height); |
|
display(); |
|
|
|
/* This is very important!!! |
|
* Make sure buffered commands are finished!!! |
|
*/ |
|
glFinish(); |
|
} |
|
|
|
static void |
|
write_targa(const char *filename, const GLubyte *buffer, int width, int height) |
|
{ |
|
FILE *f = fopen( filename, "w" ); |
|
if (f) { |
|
int i, x, y; |
|
const GLubyte *ptr = buffer; |
|
printf ("osdemo, writing tga file \n"); |
|
fputc (0x00, f); /* ID Length, 0 => No ID */ |
|
fputc (0x00, f); /* Color Map Type, 0 => No color map included */ |
|
fputc (0x02, f); /* Image Type, 2 => Uncompressed, True-color Image */ |
|
fputc (0x00, f); /* Next five bytes are about the color map entries */ |
|
fputc (0x00, f); /* 2 bytes Index, 2 bytes length, 1 byte size */ |
|
fputc (0x00, f); |
|
fputc (0x00, f); |
|
fputc (0x00, f); |
|
fputc (0x00, f); /* X-origin of Image */ |
|
fputc (0x00, f); |
|
fputc (0x00, f); /* Y-origin of Image */ |
|
fputc (0x00, f); |
|
fputc (Width & 0xff, f); /* Image Width */ |
|
fputc ((Width>>8) & 0xff, f); |
|
fputc (Height & 0xff, f); /* Image Height */ |
|
fputc ((Height>>8) & 0xff, f); |
|
fputc (0x18, f); /* Pixel Depth, 0x18 => 24 Bits */ |
|
fputc (0x20, f); /* Image Descriptor */ |
|
fclose(f); |
|
f = fopen( filename, "ab" ); /* reopen in binary append mode */ |
|
for (y=height-1; y>=0; y--) { |
|
for (x=0; x<width; x++) { |
|
i = (y*width + x) * 4; |
|
fputc(ptr[i+2], f); /* write blue */ |
|
fputc(ptr[i+1], f); /* write green */ |
|
fputc(ptr[i], f); /* write red */ |
|
} |
|
} |
|
} |
|
} |
|
|
|
int |
|
main(int argc, char *argv[]) |
|
{ |
|
OSMesaContext ctx; |
|
void *buffer; |
|
char *filename = NULL; |
|
|
|
if (argc < 2) { |
|
fprintf(stderr, "Usage:\n"); |
|
fprintf(stderr, " teapot filename [width height]\n"); |
|
return 0; |
|
} |
|
|
|
filename = argv[1]; |
|
if (argc == 4) { |
|
Width = atoi(argv[2]); |
|
Height = atoi(argv[3]); |
|
} |
|
|
|
/* Create an RGBA-mode context */ |
|
#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305 |
|
/* specify Z, stencil, accum sizes */ |
|
ctx = OSMesaCreateContextExt( OSMESA_RGBA, 16, 0, 0, NULL ); |
|
#else |
|
ctx = OSMesaCreateContext( OSMESA_RGBA, NULL ); |
|
#endif |
|
if (!ctx) { |
|
printf("OSMesaCreateContext failed!\n"); |
|
return 0; |
|
} |
|
|
|
/* Allocate the image buffer */ |
|
buffer = malloc( Width * Height * 4 * sizeof(GLubyte) ); |
|
if (!buffer) { |
|
printf("Alloc image buffer failed!\n"); |
|
return 0; |
|
} |
|
|
|
/* Bind the buffer to the context and make it current */ |
|
if (!OSMesaMakeCurrent( ctx, buffer, GL_UNSIGNED_BYTE, Width, Height )) { |
|
printf("OSMesaMakeCurrent failed!\n"); |
|
return 0; |
|
} |
|
|
|
{ |
|
int z, s, a; |
|
glGetIntegerv(GL_DEPTH_BITS, &z); |
|
glGetIntegerv(GL_STENCIL_BITS, &s); |
|
glGetIntegerv(GL_ACCUM_RED_BITS, &a); |
|
printf("Depth=%d Stencil=%d Accum=%d\n", z, s, a); |
|
} |
|
|
|
render_image(); |
|
|
|
if (filename != NULL) { |
|
write_targa(filename, buffer, Width, Height); |
|
} |
|
else { |
|
printf("Specify a filename if you want to make an image file\n"); |
|
} |
|
|
|
printf("all done\n"); |
|
|
|
/* free the image buffer */ |
|
free( buffer ); |
|
|
|
/* destroy the context */ |
|
OSMesaDestroyContext( ctx ); |
|
|
|
return 0; |
|
} |
osdemo output
![](https://cloud.githubusercontent.com/assets/8210/12862619/5ed87d86-cc2a-11e5-8d47-eb6604705ad0.png)
## teapot.c output