Tweaks to B3D accelerator code.

Alan Grimes alangrimes at starpower.net
Wed Mar 9 14:26:02 UTC 2005


I got my build working well enough that I was able to play around with 
some of the Baloon3D code. (Ask Ian why you are having problems building 
B3D on unix... it's his fault!)


Attached is a new version of the cross-platform code.

Changes:

1. Removed many error tests... OpenGL is a safe protocol so extra error 
checking is not required. Any sanity checks should be accomplished in 
the gererated portion of the code, before it reaches the OpenGL 
interface anyway. This will allow the code to run smoother, especially 
through deep pipelines.

2. I massacred glSetTransform. It was being overly cautious about 
setting up the matricies, (setting them to identity before doing 
anything), and it was manually transposing the input matrices... The 
version of OpenGL on my system has its own transpose function which, 
presumably, is better tuned for the implementation's internal 
representation format. It also makes the code alot cleaner on the client 
side.

The version provided does run both the 3D demos in 3.7 and the teapot 
stuff in Croquet. -- the build can'
t find the croquet sources though I don't know why that is...


In the B3D demos of 3.7, it gets around 21-26 FPS in software rendering, 
and around 48fps in hardware acceleration mode. There are some minor 
glitches with the grass color but otherwise it's a good driver...


-------------- next part --------------
/****************************************************************************
*   PROJECT: Squeak 3D accelerator
*   FILE:    sqOpenGLRenderer.c
*   CONTENT: Generic (cross-platform) bindings for OpenGL
*
*   AUTHOR:  Andreas Raab (ar)
*   ADDRESS: Walt Disney Imagineering, Glendale, CA
*   EMAIL:   Andreas.Raab at disney.com
*   RCSID:   $Id: sqOpenGLRenderer.c 909 2004-08-31 21:13:51Z bertf $
*
*   NOTES: 
*
*
*****************************************************************************/
#ifdef WIN32
# include <windows.h>
# include <winerror.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sqVirtualMachine.h"
#include "sqConfig.h"
#include "sqPlatformSpecific.h"
#include "B3DAcceleratorPlugin.h"

#if defined (B3DX_GL)

#include "sqOpenGLRenderer.h"

#if !defined(GL_VERSION_1_1)
#warning "This system does not support OpenGL 1.1"
#endif

// not really used yet, but this is my hardware and I intend to add GL 1.2 features
#if !defined(GL_VERSION_1_2)
#warning "This system does not support OpenGL 1.2"
#endif


static float blackLight[4] = { 0.0, 0.0, 0.0, 0.0 };

/*****************************************************************************/


/* Pbuffers are maintained by the next layer down from OpenGL, in the case of X11, 
   it's the GLX interface. Therefore we need to send these calls down to our 
   platform code to get our Inf0z.
 */ 

int glGetRendererSurfaceHandle(int handle) {
  /* If we were to use p-buffers, this would be the place to 
     return a surface handle for the p-buffer so Squeak can
     blt directly to it. Note that this is a ZILLION times
     faster when it comes to compositing; so it is definitely
     a good idea when supported. However, I don't have the
     time to figure it out so I'll just leave this as an
     exercise for the interested reader :-)
   */
/*
	struct glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}

*/
	return -1; /* e.g., fail */
}

int glGetRendererColorMasks(int handle, int *masks) {
  /* If a surface is provided, this is the place to fill
     in the color masks for the surface. Since we don't
     provide any, we just bail out.
   */
/*

	struct glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}
*/

	return 0; /* e.g., fail */
}

int glGetRendererSurfaceWidth(int handle) {
  /* If a surface is provided return the width of it */
/*

	struct glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}
*/

	return -1; /* e.g., fail */
}

int glGetRendererSurfaceHeight(int handle) {
  /* If a surface is provided return the height of it */
/*
	struct glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}
*/

	return -1; /* e.g., fail */
}

int glGetRendererSurfaceDepth(int handle) {
  /* If a surface is provided return the depth of it */
/*

	struct glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}
*/
	return -1; /* e.g., fail */
}

/*****************************************************************************/

/* texture support */
int glAllocateTexture(int handle, int w, int h, int d) /* return handle or -1 on error */
{   GLuint texture;
	char *errMsg = "";

	struct glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}

	if(w & (w-1)) return -1; /* not power of two */
	if(h & (h-1)) return -1; /* not power of two */

	DPRINTF(5, (fp, "### Allocating new texture (w = %d, h = %d, d = %d)\n", w, h, d));

	glGenTextures(1, &texture);

	DPRINTF(5, (fp, "Allocated texture id = %d\n", texture));

	glBindTexture(GL_TEXTURE_2D, texture);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

	errMsg = "glTexImage2D() failed";
	glTexImage2D(GL_TEXTURE_2D, /* target */
				 0, /* mipmap level */
				 4, /* components */
				 w, /* width */
				 h, /* height */
				 0, /* border */
				 GL_RGBA, /* format */
				 GL_UNSIGNED_BYTE, /* type */
				 NULL /* image data - if NULL contents is unspecified */);
	if((glErr = glGetError()) != GL_NO_ERROR) goto FAILED;
	DPRINTF(5, (fp,"\tid = %d\n", texture));
	return texture;
FAILED:
	DPRINTF(1, (fp, "ERROR (glAllocateTexture): %s -- %s\n", errMsg, glErrString()));
	glDeleteTextures(1, &texture);
	return -1;
}

int glDestroyTexture(int rendererHandle, int handle) /* return true on success, false on error */
{
	struct glRenderer *renderer = glRendererFromHandle(rendererHandle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}

	if(!glIsTexture(handle)) {
		return 0;
	}
	DPRINTF(5, (fp, "### Destroying texture (id = %d)\n", handle));
	glDeleteTextures(1, (GLuint*) &handle);
	ERROR_CHECK;
	return 1;
}

int glActualTextureDepth(int rendererHandle, int handle) /* return depth or <0 on error */
{
	struct glRenderer *renderer = glRendererFromHandle(rendererHandle);
	if(!renderer) return -1;
	return 32;
}

int glTextureColorMasks(int rendererHandle, int handle, int masks[4])  /* return true on success, false on error */
{
	struct glRenderer *renderer = glRendererFromHandle(rendererHandle);
	if(!renderer) return 0;
#ifdef LSB_FIRST
	masks[3] = 0xFF000000;
	masks[2] = 0x00FF0000;
	masks[1] = 0x0000FF00;
	masks[0] = 0x000000FF;
#else
	masks[0] = 0xFF000000;
	masks[1] = 0x00FF0000;
	masks[2] = 0x0000FF00;
	masks[3] = 0x000000FF;
#endif
	return 1;
}

int glTextureByteSex(int rendererHandle, int handle) /* return > 0 if MSB, = 0 if LSB, < 0 if error */
{
	struct glRenderer *renderer = glRendererFromHandle(rendererHandle);
	if(!renderer) return -1;
#ifdef LSB_FIRST
	return 0;
#else
	return 1;
#endif
}

int glTextureSurfaceHandle(int rendererHandle, int handle) {
  /* GL textures are not directly accessible */
  return -1;
}

int glUploadTexture(int rendererHandle, int handle, int w, int h, int d, void* bits)
{
	int y;
	struct glRenderer *renderer = glRendererFromHandle(rendererHandle);
	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}

	if((d != 32 ) || (!glIsTexture(handle))) return 0;

	DPRINTF(5, (fp, "### Uploading texture (w = %d, h = %d, d = %d, id = %d)\n", w, h, d, handle));
	glBindTexture(GL_TEXTURE_2D, handle);
	ERROR_CHECK;
	for(y = 0; y < h; y++) {
		glTexSubImage2D(GL_TEXTURE_2D, /* target */
						0, /* level */
						0, /* xoffset */
						y, /* yoffset */
						w, /* width */
						1, /* height */
						GL_RGBA, /* format */
						GL_UNSIGNED_BYTE, /* type */
						((char*)bits) + (y*w*4));
		ERROR_CHECK;
	}
	return 1;
}

int glCompositeTexture(int rendererHandle, int handle, int x, int y, int w, int h, int translucent)
{
	struct glRenderer *renderer = glRendererFromHandle(rendererHandle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}

	if(!glIsTexture(handle)) return 0;

	DPRINTF(7, (fp, "glCompositeTexture(%d, %d, %d, %d)\n", x, y, w, h));
	{
		/* setup a transformation so that we're dealing with pixel x/y coordinate systems */
		glPushMatrix();
		glLoadIdentity();
		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		glLoadIdentity();
		ERROR_CHECK;
		/* matrix backup complete - now install new mapping */
		{
			int width = renderer->bufferRect[2];
			int height = renderer->bufferRect[3];
			glViewport(0, 0, width, height);
			/* now remap from lower left origin to upper left origin 
			   while scaling from (-width,+width) to (-1, +1) */
			glScaled(2.0/width, -2.0/height, 1.0);
			/* offset origin to start at 0,0 rather than -width/2,-height/2 */
			glTranslated(width*-0.5, height*-0.5, 0.0);
			ERROR_CHECK;
		}
		/* setup the right shading rules */
		glPushAttrib(GL_ALL_ATTRIB_BITS);
		{
			glShadeModel(GL_FLAT);
			glEnable(GL_TEXTURE_2D);
			glDisable(GL_COLOR_MATERIAL);
			glDisable(GL_DITHER);
			glDisable(GL_LIGHTING);
			glDisable(GL_DEPTH_TEST);
			glDisable(GL_BLEND);
			glDisable(GL_CULL_FACE);
			glDepthMask(GL_FALSE);
			glColor4d(1.0, 1.0, 1.0, 1.0);
			glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
		}
		ERROR_CHECK;

		/* prepare for translucency */
		if(translucent) {
			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		}
		ERROR_CHECK;
	}

	{
		/* and *THAT* is the hard work ;-))) */
		glBindTexture(GL_TEXTURE_2D, handle);
		ERROR_CHECK;
		x -= renderer->bufferRect[0];
		y -= renderer->bufferRect[1];
		DPRINTF(7, (fp, "glRecti(%d, %d, %d, %d)\n", x, y, w, h));
		glBegin(GL_QUADS);
			glTexCoord2d(0.0, 0.0);
			glVertex2i(x, y);
			glTexCoord2d(1.0, 0.0);
			glVertex2i(x+w, y);
			glTexCoord2d(1.0, 1.0);
			glVertex2i(x+w, y+h);
			glTexCoord2d(0.0, 1.0);
			glVertex2i(x, y+h);
		glEnd();
		ERROR_CHECK;
	}
	/* and restore everything back to normal */
	{
		glPopAttrib();
		/* BUG BUG BUG - Mac OpenGL has a problem with glPushAttrib/glShadeModel/glPopAttrib - BUG BUG BUG */
		glShadeModel(GL_SMOOTH);
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
		glPopMatrix();
	}
	ERROR_CHECK;
	/* done */
	return 1;
}

/*****************************************************************************/

int glSetViewport(int handle, int x, int y, int w, int h) /* return true on success, false on error */
{
	struct glRenderer *renderer = glRendererFromHandle(handle);
	if(!renderer || !glMakeCurrentRenderer(renderer)) return 0;

	DPRINTF(5, (fp, "### New Viewport\n"));
	renderer->viewport[0] = x;
	renderer->viewport[1] = y;
	renderer->viewport[2] = w;
	renderer->viewport[3] = h;
	x -= renderer->bufferRect[0];
	y -= renderer->bufferRect[1];
	DPRINTF(5, (fp, "\tx: %d\n\ty: %d\n\tw: %d\n\th: %d\n", x, y, w, h));

	glViewport(x, renderer->bufferRect[3] - (y+h), w, h);
	return 1;
}

int glClearDepthBuffer(int handle) /* return true on success, false on error */
{
	struct glRenderer *renderer = glRendererFromHandle(handle);
	if(!renderer || !glMakeCurrentRenderer(renderer)) return 0;
	DPRINTF(5, (fp, "### Clearing depth buffer\n"));
	glClear(GL_DEPTH_BUFFER_BIT);
	return 1;
}

int glClearViewport(int handle, unsigned int bgra, unsigned int pv) /* return true on success, false on error */
{
	struct glRenderer *renderer = glRendererFromHandle(handle);
	if(!renderer || !glMakeCurrentRenderer(renderer)) return 0;

	DPRINTF(5, (fp, "### Clearing viewport buffer\n"));

// this looks much less wrong than it used to but that doesn't mean it's right... =( 
	glClearColor(  ((bgra >> 16) & 0xff) / 255.0, 
		       ((bgra >>  8) & 0xff) / 255.0, 
			(bgra        & 0xff) / 255.0, 
			(bgra >> 24)         / 255.0);

	glClear(GL_COLOR_BUFFER_BIT);
	return 1;
}

int glFinishRenderer(int handle) /* return true on success, false on error */
{
	struct glRenderer *renderer = glRendererFromHandle(handle);
	if(!renderer || !glMakeCurrentRenderer(renderer)) return 0;
	DPRINTF(5, (fp, "### Finishing renderer\n"));
	glFinish();
	return 1;
}

int glFlushRenderer(int handle) /* return true on success, false on error */
{
	struct glRenderer *renderer = glRendererFromHandle(handle);
	if(!renderer || !glMakeCurrentRenderer(renderer)) return 0;

	DPRINTF(5, (fp, "### Flushing renderer\n"));
	glFlush();
	return 1;
}

int glSwapRendererBuffers(int handle) /* return true on success, false on error */
{
	struct glRenderer *renderer = glRendererFromHandle(handle);
	if(!renderer || !glMakeCurrentRenderer(renderer)) return 0;

	DPRINTF(5, (fp, "### Swapping renderer buffers\n"));
	glSwapBuffers(renderer);
	ERROR_CHECK;
	return 1;
}

int glSetTransform(int handle, float *modelViewMatrix, float *projectionMatrix) {
	struct glRenderer *renderer = glRendererFromHandle(handle);
	if(!renderer || !glMakeCurrentRenderer(renderer)) return 0;

	DPRINTF(5, (fp, "### Installing new transformations\n"));

	glMatrixMode(GL_PROJECTION);
	if(projectionMatrix) glLoadTransposeMatrixf(projectionMatrix);

	glMatrixMode(GL_MODELVIEW);
	if(modelViewMatrix) glLoadTransposeMatrixf(modelViewMatrix);

	return 1;
}

int glDisableLights(int handle) {
	int i;
	GLint max;
	struct glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}

	DPRINTF(5, (fp, "### Disabling all lights\n"));
	glGetIntegerv(GL_MAX_LIGHTS, &max);

	for(i = 0; i < max; i++) {
		glDisable(GL_LIGHT0+i);
		if( (glErr = glGetError()) != GL_NO_ERROR) 
			DPRINTF(1, (fp,"ERROR (glDisableLights): glDisable(GL_LIGHT%d) failed -- %s\n", i, glErrString()));
	}
	return 1;
}

int glLoadMaterial(int handle, B3DPrimitiveMaterial *mat)
{
	struct glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}

	DPRINTF(5, (fp, "### New Material\n"));
	if(!mat) {
		DPRINTF(5, (fp, "\tOFF (material == nil)\n"));
		glDisable(GL_LIGHTING);
		return 1;
	}
	DPRINTF(5, (fp, "\tambient  : %g, %g, %g, %g\n",mat->ambient[0], mat->ambient[1], mat->ambient[2], mat->ambient[3]));
	DPRINTF(5, (fp, "\tdiffuse  : %g, %g, %g, %g\n",mat->diffuse[0], mat->diffuse[1], mat->diffuse[2], mat->diffuse[3]));
	DPRINTF(5, (fp, "\tspecular : %g, %g, %g, %g\n",mat->specular[0], mat->specular[1], mat->specular[2], mat->specular[3]));
	DPRINTF(5, (fp, "\temission : %g, %g, %g, %g\n",mat->emission[0], mat->emission[1], mat->emission[2], mat->emission[3]));
	DPRINTF(5, (fp, "\tshininess: %g\n", mat->shininess));

	glEnable(GL_LIGHTING);
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat->ambient);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat->diffuse);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat->specular);
	glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mat->emission);
	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mat->shininess);
	return 1;
}

int glLoadLight(int handle, int idx, B3DPrimitiveLight *light)
{
	float pos[4];
	int index = GL_LIGHT0 + idx;
	struct glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}

	DPRINTF(5, (fp, "### New Light (%d)\n", idx));

	if(!light) {
		DPRINTF(5, (fp, "\tDISABLED\n"));
		glDisable(index);
		ERROR_CHECK;
		return 1;
	}
	glEnable(index);
	ERROR_CHECK;

/*
	DPRINTF(5, (fp, "\tambient       : %g, %g, %g, %g\n",light->ambient[0], light->ambient[1], light->ambient[2], light->ambient[3]));
	DPRINTF(5, (fp, "\tdiffuse       : %g, %g, %g, %g\n",light->diffuse[0], light->diffuse[1], light->diffuse[2], light->diffuse[3]));
	DPRINTF(5, (fp, "\tspecular      : %g, %g, %g, %g\n",light->specular[0], light->specular[1], light->specular[2], light->specular[3]));
	DPRINTF(5, (fp, "\tposition      : %g, %g, %g\n",light->position[0], light->position[1], light->position[2]));
	DPRINTF(5, (fp, "\tdirection     : %g, %g, %g\n",light->direction[0], light->direction[1], light->direction[2]));
	DPRINTF(5, (fp, "\tattenuation   : %g, %g, %g\n",light->attenuation[0], light->attenuation[1], light->attenuation[2]));
	DPRINTF(5, (fp, "\tflags [%d]:", light->flags));

	if(light->flags & B3D_LIGHT_AMBIENT) DPRINTF(5,(fp," B3D_LIGHT_AMBIENT"));
	if(light->flags & B3D_LIGHT_DIFFUSE) DPRINTF(5,(fp," B3D_LIGHT_DIFFUSE"));
	if(light->flags & B3D_LIGHT_SPECULAR) DPRINTF(5,(fp," B3D_LIGHT_SPECULAR"));
	if(light->flags & B3D_LIGHT_POSITIONAL) DPRINTF(5,(fp," B3D_LIGHT_POSITIONAL"));
	if(light->flags & B3D_LIGHT_DIRECTIONAL) DPRINTF(5,(fp," B3D_LIGHT_DIRECTIONAL"));
	if(light->flags & B3D_LIGHT_ATTENUATED) DPRINTF(5,(fp," B3D_LIGHT_ATTENUATED"));
	if(light->flags & B3D_LIGHT_HAS_SPOT) DPRINTF(5,(fp," B3D_LIGHT_HAS_SPOT"));

	DPRINTF(5, (fp, "\n"));
	DPRINTF(5, (fp, "\tspot exponent : %g\n", light->spotExponent));
	DPRINTF(5, (fp, "### Installing Light (%d)\n", idx));

*/

	if(light->flags & B3D_LIGHT_AMBIENT) {
		DPRINTF(5, (fp, "\tambient  : %g, %g, %g, %g\n",light->ambient[0], light->ambient[1], light->ambient[2], light->ambient[3]));
		glLightfv(index, GL_AMBIENT, light->ambient);
	} else {
		DPRINTF(5, (fp, "\tambient  : OFF (0, 0, 0, 1)\n"));
		glLightfv(index, GL_AMBIENT, blackLight);
	}

	if(light->flags & B3D_LIGHT_DIFFUSE) {
		DPRINTF(5, (fp, "\tdiffuse  : %g, %g, %g, %g\n",light->diffuse[0], light->diffuse[1], light->diffuse[2], light->diffuse[3]));
		glLightfv(index, GL_DIFFUSE, light->diffuse);
	} else {
		DPRINTF(5, (fp, "\tdiffuse  : OFF (0, 0, 0, 1)\n"));
		glLightfv(index, GL_DIFFUSE, blackLight);
	}

	if(light->flags & B3D_LIGHT_SPECULAR) {
		DPRINTF(5, (fp, "\tspecular : %g, %g, %g, %g\n",light->specular[0], light->specular[1], light->specular[2], light->specular[3]));
		glLightfv(index, GL_SPECULAR, light->specular);
	} else {
		DPRINTF(5, (fp, "\tspecular : OFF (0, 0, 0, 1)\n"));
		glLightfv(index, GL_SPECULAR, blackLight);
	}

	if(light->flags & B3D_LIGHT_POSITIONAL) {
		DPRINTF(5, (fp, "\tposition : %g, %g, %g\n",light->position[0], light->position[1], light->position[2]));
		pos[0] = light->position[0];
		pos[1] = light->position[1];
		pos[2] = light->position[2];
		pos[3] = 1.0;
		/* @@@ FIXME: Squeak pre-transforms the light @@@ */
		glPushMatrix();
		glLoadIdentity();
		glLightfv(index, GL_POSITION, pos);
		glPopMatrix();
	} else {
		if(light->flags & B3D_LIGHT_DIRECTIONAL) {
			DPRINTF(5, (fp, "\tdirection: %g, %g, %g\n",light->direction[0], light->direction[1], light->direction[2]));
			pos[0] = light->direction[0];
			pos[1] = light->direction[1];
			pos[2] = light->direction[2];
			pos[3] = 0.0;
			/* @@@ FIXME: Squeak pre-transforms the light @@@ */
			glPushMatrix();
			glLoadIdentity();
			glLightfv(index, GL_POSITION, pos);
			glPopMatrix();
		}
	}

	if(light->flags & B3D_LIGHT_ATTENUATED) {
		DPRINTF(5, (fp, "\tattenuation: %g, %g, %g\n",light->attenuation[0], light->attenuation[1], light->attenuation[2]));
		glLightf(index, GL_CONSTANT_ATTENUATION,  light->attenuation[0]);
		glLightf(index, GL_LINEAR_ATTENUATION,    light->attenuation[1]);
		glLightf(index, GL_QUADRATIC_ATTENUATION, light->attenuation[2]);
	} else {
		DPRINTF(5, (fp, "\tattenuation: OFF (1, 0, 0)\n"));
		glLightf(index, GL_CONSTANT_ATTENUATION,  1.0);
		glLightf(index, GL_LINEAR_ATTENUATION,    0.0);
		glLightf(index, GL_QUADRATIC_ATTENUATION, 0.0);
	}

	if(light->flags & B3D_LIGHT_HAS_SPOT) {
		DPRINTF(5, (fp, "\tspot exponent : %g\n", light->spotExponent));
		DPRINTF(5, (fp, "\tspot cutoff   : ???\n"));
		DPRINTF(5, (fp, "\tspot direction: %g, %g, %g\n",light->direction[0], light->direction[1], light->direction[2]));
		glLightf(index, GL_SPOT_EXPONENT, light->spotExponent);
		glLightf(index, GL_SPOT_CUTOFF, light->spotExponent);
		glLightfv(index, GL_SPOT_DIRECTION, light->direction);
	} else {
		glLightf(index, GL_SPOT_EXPONENT, 0.0);
		glLightf(index, GL_SPOT_CUTOFF, 180.0);
	}
	return 1;
}

int glSetFog(int handle, int fogType, double density, 
             double fogRangeStart, double fogRangeEnd, int rgba) 
{
	GLfloat fogColor[4];
	glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) return 0;
	if(fogType == 0) {
		glDisable(GL_FOG);
		ERROR_CHECK;
		return 1;
	}

  glEnable(GL_FOG);
  if(fogType == 1) glFogi(GL_FOG_MODE, GL_LINEAR);
  if(fogType == 2) glFogi(GL_FOG_MODE, GL_EXP);
  if(fogType == 3) glFogi(GL_FOG_MODE, GL_EXP2);
  glFogf(GL_FOG_DENSITY, (GLfloat)density);
  glFogf(GL_FOG_START, (GLfloat)fogRangeStart);
  glFogf(GL_FOG_END, (GLfloat)fogRangeEnd);
  fogColor[0] = ((rgba >> 16) & 255) / 255.0;
  fogColor[1] = ((rgba >>  8) & 255) / 255.0;
  fogColor[2] = (rgba & 255) / 255.0;
  fogColor[3] = (rgba >> 24) / 255.0;
  glFogfv(GL_FOG_COLOR, fogColor);

/* enable pixel fog */
	glHint(GL_FOG_HINT, GL_NICEST);
	return 1;
}

int glGetIntProperty(int handle, int prop)
{
  GLint v;

  glRenderer *renderer = glRendererFromHandle(handle);
  if(!renderer || !glMakeCurrentRenderer(renderer)) return 0;

  if(prop < 0) return glGetIntPropertyOS(handle, prop);

  switch(prop) {
  case 1: /* backface culling */
    if(!glIsEnabled(GL_CULL_FACE)) return 0;
    glGetIntegerv(GL_FRONT_FACE, &v);
    if(v == GL_CW) return 1;
    if(v == GL_CCW) return -1;
    return 0;
  case 2: /* polygon mode */
    glGetIntegerv(GL_POLYGON_MODE, &v);
    return v;
  case 3: /* point size */
    glGetIntegerv(GL_POINT_SIZE, &v);
    return v;
  case 4: /* line width */
    glGetIntegerv(GL_LINE_WIDTH, &v);
    return v;
  case 5: /* blend enable */
    return glIsEnabled(GL_BLEND);
  case 6: /* blend source factor */
  case 7: /* blend dest factor */
    if(prop == 6)
      glGetIntegerv(GL_BLEND_SRC, &v);
    else
      glGetIntegerv(GL_BLEND_DST, &v);
    switch(v) {
        case GL_ZERO: return 0;
        case GL_ONE: return 1;
        case GL_SRC_COLOR: return 2;
        case GL_ONE_MINUS_SRC_COLOR: return 3;
        case GL_DST_COLOR: return 4;
        case GL_ONE_MINUS_DST_COLOR: return 5;
        case GL_SRC_ALPHA: return 6;
        case GL_ONE_MINUS_SRC_ALPHA: return 7;
        case GL_DST_ALPHA: return 8;
        case GL_ONE_MINUS_DST_ALPHA: return 9;
        case GL_SRC_ALPHA_SATURATE: return 10;
        default: return -1;
    }
  }
  return 0;
}

int glSetIntProperty(int handle, int prop, int value)
{
  glRenderer *renderer = glRendererFromHandle(handle);
  if(!renderer || !glMakeCurrentRenderer(renderer)) return 0;

  if(prop < 0) return glSetIntPropertyOS(handle, prop, value);

  switch(prop) {
  case 1: /* backface culling */
    if(!value) {
      glDisable(GL_CULL_FACE);
      ERROR_CHECK;
      return 1;
    }
    glEnable(GL_CULL_FACE);
    glFrontFace(value == 1 ? GL_CCW : GL_CW);
    ERROR_CHECK;
    return 1;
  case 2: /* polygon mode */
    if(value == 0) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    else if(value == 1) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    else if(value == 2) glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
    else return 0;
    return 1;
  case 3: /* point size */
    glPointSize(value);
    ERROR_CHECK;
    return 1;
  case 4: /* line width */
    glLineWidth(value);
    ERROR_CHECK;
    return 1;
  case 5: /* blend enable */
    if(value)
      glEnable(GL_BLEND);
    else
      glDisable(GL_BLEND);
    return 1;
  case 6: /* blend source factor */
  case 7: /* blend dest factor */
		{
		int factor;
		GLint src, dst;
		switch(value) {
			case 0: factor = GL_ZERO; break;
		 	case 1: factor = GL_ONE; break;
		       	case 2: factor = GL_SRC_COLOR; break;
		       	case 3: factor = GL_ONE_MINUS_SRC_COLOR; break;
		        case 4: factor = GL_DST_COLOR; break;
		        case 5: factor = GL_ONE_MINUS_DST_COLOR; break;
		        case 6: factor = GL_SRC_ALPHA; break;
		       	case 7: factor = GL_ONE_MINUS_SRC_ALPHA; break;
		        case 8: factor = GL_DST_ALPHA; break;
		        case 9: factor = GL_ONE_MINUS_DST_ALPHA; break;
			case 10: factor = GL_SRC_ALPHA_SATURATE; break;
			default: return 0;
			}
			glGetIntegerv(GL_BLEND_SRC, &src);
			glGetIntegerv(GL_BLEND_DST, &dst);
			if(prop == 6) src = factor;
				else dst = factor;
			glBlendFunc(src,dst);
			return 1;
		}
	}
	return 0;
}


#ifndef GL_VERSION_1_1
static void glRenderVertex(B3DPrimitiveVertex *vtx, int flags)
{
	DPRINTF(10, (fp, "["));
	if(flags & 1) {
		unsigned int vv = vtx->pixelValue32;
		DPRINTF(10, (fp, "C(%d, %d, %d, %d)",(vv >> 16) & 255, (vv >> 8) & 255, vv & 255, vv >> 24));
		glColor4ub( (vv >> 16) & 255, (vv >> 8) & 255, vv & 255, vv >> 24 );
	}
	if(flags & 2) {
		DPRINTF(10, (fp, "N(%g, %g, %g)", vtx->normal[0], vtx->normal[1], vtx->normal[2]));
		glNormal3fv(vtx->normal);
	}
	if(flags & 4) {
		DPRINTF(10, (fp, "T(%g, %g)", vtx->texCoord[0], vtx->texCoord[1]));
		glTexCoord2fv(vtx->texCoord);
	}
	DPRINTF(10, (fp, "V(%g, %g, %g)]\n", vtx->position[0], vtx->position[1], vtx->position[2]));
	glVertex3fv(vtx->position);
}
#endif

/* General dummy for Squeak's primitive faces */
typedef int B3DInputFace;

int glRenderVertexBuffer(int handle, int primType, int flags, int texHandle, float *vtxArray, int vtxSize, int *idxArray, int idxSize)
{
	B3DPrimitiveVertex *vtxPointer = (B3DPrimitiveVertex*) vtxArray;
	B3DInputFace *facePtr = (B3DInputFace*) idxArray;
	GLuint tracking;
	int nVertices = vtxSize;
	int i, vtxFlags;

	struct glRenderer *renderer = glRendererFromHandle(handle);

	if(!renderer || !glMakeCurrentRenderer(renderer)) {
		DPRINTF(4, (fp, "ERROR: Invalid renderer specified\n"));
		return 0;
	}


/*
	DPRINTF(5, (fp,"### Primitive : %d\n", primType));
	DPRINTF(5, (fp,"\ttexHandle   : %d\n", texHandle));
	DPRINTF(5, (fp,"\tcolor flags :"));
	if(flags & B3D_VB_TRACK_AMBIENT) DPRINTF(5,(fp," B3D_VB_TRACK_AMBIENT"));
	if(flags & B3D_VB_TRACK_DIFFUSE) DPRINTF(5,(fp," B3D_VB_TRACK_DIFFUSE"));
	if(flags & B3D_VB_TRACK_SPECULAR) DPRINTF(5,(fp," B3D_VB_TRACK_SPECULAR"));
	if(flags & B3D_VB_TRACK_EMISSION) DPRINTF(5,(fp," B3D_VB_TRACK_EMISSION"));
	DPRINTF(5, (fp,"\n\tlight flags :"));
	if(flags & B3D_VB_LOCAL_VIEWER) DPRINTF(5,(fp," B3D_VB_LOCAL_VIEWER"));
	if(flags & B3D_VB_TWO_SIDED) DPRINTF(5,(fp," B3D_VB_TWO_SIDED"));
	DPRINTF(5, (fp,"\n\tvertex flags:"));
	if(flags & B3D_VB_HAS_NORMALS) DPRINTF(5,(fp," B3D_VB_HAS_NORMALS"));
	if(flags & B3D_VB_HAS_TEXTURES) DPRINTF(5,(fp," B3D_VB_HAS_TEXTURES"));
	DPRINTF(5, (fp, "\n"));
*/


	/* process VB flags */
	tracking = 0;
	if(flags & B3D_VB_TRACK_AMBIENT) tracking |= GL_AMBIENT;
	if(flags & B3D_VB_TRACK_DIFFUSE) tracking |= GL_DIFFUSE;
	if(flags & B3D_VB_TRACK_SPECULAR) tracking |= GL_SPECULAR;
	if(flags & B3D_VB_TRACK_EMISSION) tracking |= GL_EMISSION;

	if(tracking) {
		/* in accordance with glColorMaterial man page noting:
		   Call glColorMaterial before enabling GL_COLOR_MATERIAL. */
		glColorMaterial(GL_FRONT_AND_BACK, tracking);
		glEnable(GL_COLOR_MATERIAL);
	}

	glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (flags & B3D_VB_LOCAL_VIEWER) ? 1 : 0);
	ERROR_CHECK;
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, (flags & B3D_VB_TWO_SIDED) ? 1 : 0);
	ERROR_CHECK;

	if(texHandle > 0) {
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, texHandle);
	} else 	glDisable(GL_TEXTURE_2D);

	vtxFlags = 0;
	if(tracking) vtxFlags |= 1;
	if(flags & B3D_VB_HAS_NORMALS)	vtxFlags |= 2;
	if(flags & B3D_VB_HAS_TEXTURES)	vtxFlags |= 4;

#ifdef GL_VERSION_1_1
	/* use glDrawElements() etc */
	/* @@@ HACK!!! */
	vtxPointer -= 1; /* that way we can submit all vertices at once */
	if(vtxFlags & 1) {
	  /* harumph... we need to rotate all the colors as we're getting ARGB here but GL expects RGBA... */
	  for(i=1;i<=nVertices;i++) {
	    unsigned int argb = vtxPointer[i].pixelValue32;
	    unsigned int rgba = (argb << 8) | (argb >> 24);
	    vtxPointer[i].pixelValue32 = rgba;
	  }
	  glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(B3DPrimitiveVertex), &(vtxPointer->pixelValue32));
	  glEnableClientState(GL_COLOR_ARRAY);
	}
	if(vtxFlags & 2) {
	  glNormalPointer(GL_FLOAT, sizeof(B3DPrimitiveVertex), vtxPointer->normal);
	  glEnableClientState(GL_NORMAL_ARRAY);
	}
	if(vtxFlags & 4) {
	  glTexCoordPointer(2, GL_FLOAT, sizeof(B3DPrimitiveVertex), vtxPointer->texCoord);
	  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	}

	glVertexPointer(3, GL_FLOAT, sizeof(B3DPrimitiveVertex), vtxPointer->position);
	glEnableClientState(GL_VERTEX_ARRAY);
	ERROR_CHECK;
	/* @@@ HACK!!! */
	vtxPointer += 1; /* that way we can submit all vertices at once */
#endif /* GL_VERSION_1_1 */

	switch(primType) {
		case 1: /* points */
#ifdef GL_VERSION_1_1
		        glDrawArrays(GL_POINTS, 1, nVertices);
#else /* !GL_VERSION_1_1 */
			glBegin(GL_POINTS);
			for(i=0; i < nVertices; i++) glRenderVertex(vtxPointer + i, vtxFlags);
			glEnd();
#endif /* GL_VERSION_1_1 */
			break;
		case 2: /* lines */
#ifdef GL_VERSION_1_1
		        glDrawArrays(GL_LINES, 1, nVertices);
#else /* !GL_VERSION_1_1 */
			glBegin(GL_LINES);
			for(i=0; i < nVertices; i++) glRenderVertex(vtxPointer + i, vtxFlags);
			glEnd();
#endif /* GL_VERSION_1_1 */
			break;
		case 3: /* polygon */
#ifdef GL_VERSION_1_1
		        glDrawArrays(GL_POLYGON, 1, nVertices);
#else /* !GL_VERSION_1_1 */
			glBegin(GL_POLYGON);
			for(i=0; i < nVertices; i++) glRenderVertex(vtxPointer + i, vtxFlags);
			glEnd();
#endif /* GL_VERSION_1_1 */
			break;
		case 4: /* indexed lines */
#ifdef GL_VERSION_1_1
		        glDrawElements(GL_LINES, idxSize, GL_UNSIGNED_INT, facePtr);
#else /* !GL_VERSION_1_1 */
			nFaces = idxSize / 2;
			glBegin(GL_LINES);
			for(i = 0; i < nFaces; i++) {
				B3DInputFace *face = facePtr + (2*i);
				if(face[0] && face[1]) {
					DPRINTF(10, (fp,"\n"));
					glRenderVertex(vtxPointer + face[0] - 1, vtxFlags);
					glRenderVertex(vtxPointer + face[1] - 1, vtxFlags);
				}
			}
			glEnd();
#endif /* GL_VERSION_1_1 */
			break;
		case 5: /* indexed triangles */
#ifdef GL_VERSION_1_1
		        glDrawElements(GL_TRIANGLES, idxSize, GL_UNSIGNED_INT, facePtr);
#else /* !GL_VERSION_1_1 */
			nFaces = idxSize / 3;
			glBegin(GL_TRIANGLES);
			for(i = 0; i < nFaces; i++) {
				B3DInputFace *face = facePtr + (3*i);
				if(face[0] && face[1] && face[2]) {
					DPRINTF(10, (fp,"\n"));
					glRenderVertex(vtxPointer + face[0] - 1, vtxFlags);
					glRenderVertex(vtxPointer + face[1] - 1, vtxFlags);
					glRenderVertex(vtxPointer + face[2] - 1, vtxFlags);
				}
			}
			glEnd();
#endif /* GL_VERSION_1_1 */
			break;
		case 6: /* indexed quads */
#ifdef GL_VERSION_1_1
		        glDrawElements(GL_QUADS, idxSize, GL_UNSIGNED_INT, facePtr);
#else /* !GL_VERSION_1_1 */
			nFaces = idxSize / 4;
			glBegin(GL_QUADS);
			for(i = 0; i < nFaces; i++) {
				B3DInputFace *face = facePtr + (4*i);
				if(face[0] && face[1] && face[2] && face[3]) {
					DPRINTF(10, (fp,"\n"));
					glRenderVertex(vtxPointer + face[0] - 1, vtxFlags);
					glRenderVertex(vtxPointer + face[1] - 1, vtxFlags);
					glRenderVertex(vtxPointer + face[2] - 1, vtxFlags);
					glRenderVertex(vtxPointer + face[3] - 1, vtxFlags);
				}
			}
			glEnd();
#endif /* GL_VERSION_1_1 */
			break;
	}
	ERROR_CHECK;
	DPRINTF(5, (fp,"\n"));
	glDisable(GL_COLOR_MATERIAL);
	ERROR_CHECK;
#ifdef GL_VERSION_1_1
	if(vtxFlags & 1)  glDisableClientState(GL_COLOR_ARRAY);
	if(vtxFlags & 2)  glDisableClientState(GL_NORMAL_ARRAY);
	if(vtxFlags & 4)  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	ERROR_CHECK;
#endif /* GL_VERSION_1_1 */
	return 1;
}

#endif /* defined B3DX_GL */


More information about the Vm-dev mailing list