	for (i = 0; i <clp->objcount; i++) {
		g = clp->atm[i].geometryindex;
		f = clp->atm[i].frameindex;
		if (clp->frm[f].display == 0)
			continue;
		glPushMatrix();
		TransformFrame(clp->frm, f);
//		DrawAxis();
		for (j = 0; j < clp->geo[g].splitcount; j++) {
			istransparent = 0;
			splt = &clp->geo[g].splt[j];
			vert = clp->geo[g].vertices;
			norm = clp->geo[g].normals;
			vc = clp->geo[g].vc;
			uv = clp->geo[g].uv[0];
			/* Disable reflection map and unbind any textures */
			glActiveTextureARB(GL_TEXTURE2_ARB);
			glDisable(GL_TEXTURE_GEN_S);
			glDisable(GL_TEXTURE_GEN_T);
			glBindTexture(GL_TEXTURE_2D, 0);
			glActiveTextureARB(GL_TEXTURE0_ARB);
			glBindTexture(GL_TEXTURE_2D, 0);
			/* Bind a diffuse map if we have one */
			if (clp->geo[g].mat[splt->matindex].hastexture) {
				t = &clp->geo[g].mat[splt->matindex].tex;
				
				texindex = GetTextureIndex(mdl->texturefiles,
				                           t->tex);
				glActiveTextureARB(GL_TEXTURE0_ARB);
				glBindTexture(GL_TEXTURE_2D,
				              mdl->textures[texindex]);
				/* If we have an alpha, use this instead */
				if (strcmp(t->alpha, "") != 0)
					istransparent = 1;
				if (0) {
//				if (strcmp(t->alpha, "") != 0) {
					glActiveTextureARB(GL_TEXTURE1_ARB);
					glClientActiveTextureARB(GL_TEXTURE1_ARB);
					glTexEnvi(GL_TEXTURE_ENV,
					          GL_TEXTURE_ENV_MODE,
					          GL_REPLACE);
					glTexEnvi(GL_TEXTURE_ENV,
					          GL_SOURCE0_RGB_EXT,
					          GL_PREVIOUS_EXT);
					glTexEnvi(GL_TEXTURE_ENV,
					          GL_OPERAND0_RGB_EXT,
					          GL_SRC_COLOR);
					glTexEnvi(GL_TEXTURE_ENV,
					          GL_SOURCE1_RGB_EXT,
					          GL_TEXTURE);
					glTexEnvi(GL_TEXTURE_ENV,
					          GL_OPERAND1_RGB_EXT,
					          GL_SRC_ALPHA);
					texindex = GetTextureIndex(mdl->
					                     texturefiles,
					                     t->alpha);
					glBindTexture(GL_TEXTURE_2D,
					              mdl->textures[texindex]);
					istransparent = 1;
				}
			//	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
			}
			/* Bind a reflection map if we have one */
			if (clp->geo[g].mat[splt->matindex].hasreflection) {
				t = &clp->geo[g].mat[splt->matindex].reflection;
				
				texindex = GetTextureIndex(mdl->texturefiles,
				                           t->tex);
				glActiveTextureARB(GL_TEXTURE2_ARB);
				glBindTexture(GL_TEXTURE_2D,
				              mdl->textures[texindex]);
				glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
				glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
				glEnable(GL_TEXTURE_GEN_S);
				glEnable(GL_TEXTURE_GEN_T);
				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
			}
			/* Set Colors to material color */
			color[0] = (float)
				clp->geo[g].mat[splt->matindex].color[0]/255;
			color[1] = (float)
				clp->geo[g].mat[splt->matindex].color[1]/255;
			color[2] = (float)
				clp->geo[g].mat[splt->matindex].color[2]/255;
			color[3] = (float)
				clp->geo[g].mat[splt->matindex].color[3]/255;
			if (color[3] != 1.0)
				istransparent = 1;
			/* If the split is transparent and we don't want
			 * to draw it (or vice versa), skip to the next */
			if (istransparent != disptrans)
				continue;
			glDisable(GL_BLEND);
			if (istransparent) {
				glEnable(GL_BLEND);
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			}
			glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
			if (clp->geo[g].facetype == 1) {
				glBegin(GL_TRIANGLE_STRIP);
			for (k = 0; k < splt->indexcount-2; k++) {
				int m;
				for (m = 0; m < 3; m++) {
				l = splt->indices[k+m];
				if (clp->geo[g].normaltype == 0)
					glNormal3fv(norm[l]);
				else if (clp->geo[g].normaltype == 1)
					glNormal3fv(splt->normals[k]);
				else {
					fprintf(stderr,"Unknown normal type\n");
					exitprog(0);
				}
				if (clp->geo[g].newuvsets >= 1)
					glMultiTexCoord2f(GL_TEXTURE0_ARB,
							  uv[l][0],
							  uv[l][1]);
				glVertex3fv(vert[l]);
				}
			}
			glEnd();
			}
			else {
				glBegin(GL_TRIANGLES);
			for (k = 0; k < splt->indexcount; k++) {
				l = splt->indices[k];
				if (clp->geo[g].normaltype == 0)
					glNormal3fv(norm[l]);
				else if (clp->geo[g].normaltype == 2)
					glNormal3fv(splt->normals[k/3]);
				else {
					fprintf(stderr,"Unknown normal type\n");
					exitprog(0);
				}
				if (clp->geo[g].newuvsets >= 1)
					glMultiTexCoord2f(GL_TEXTURE0_ARB,
							  uv[l][0],
							  uv[l][1]);
				glVertex3fv(vert[l]);
			}
			glEnd();
			}
//			if ((clp->geo[g].flags & HASVCOLORS) != 0) {
//				color[0] = (float) vc[0]/255;
//				color[1] = (float) vc[1]/255;
//				color[2] = (float) vc[2]/255;
//				color[3] = (float) vc[3]/255;
//				glMaterialfv(GL_FRONT_AND_BACK,
//				             GL_DIFFUSE, color);
//			} else {
//				color[0] = (float) 128/255;
//				color[1] = (float) 128/255;
//				color[2] = (float) 128/255;
//				color[3] = (float) 255/255;
//				glMaterialfv(GL_FRONT_AND_BACK,
//				             GL_DIFFUSE, color);
//			}
		glPopMatrix();
void LoadTextures(Model *mdl)
	int i, j;
	int found;
	found = 0;
	glEnable(GL_TEXTURE_2D);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glGenTextures(mdl->texturecount, mdl->textures);
	for (i = 0; i < mdl->texturecount; i++) {
		glBindTexture(GL_TEXTURE_2D, mdl->textures[i]);
		for (j = 0; j < mdl->txdcount; j++) {
			if (strcmp(mdl->texturefiles[i], mdl->texlist[j].name)
			    == 0 || strcmp(mdl->texturefiles[i],
				           mdl->texlist[j].alpha) == 0) {
				found = 1;
				break;
			} else
				found = 0;
		if (!found)
			continue;
		if (mdl->texlist[j].bpp == 8 || mdl->texlist[j].bpp == 4) {
			printf("paletted picture\n");
			glTexImage2D(GL_TEXTURE_2D, 0, mdl->texlist[j].channels,
				     mdl->texlist[j].width,
			             mdl->texlist[j].height, 0,
				     mdl->texlist[j].format, GL_UNSIGNED_BYTE,
				     mdl->texlist[j].data[0]);
		} else
		if (mdl->texlist[j].bpp == 16) {
			printf("16 bit picture..not supported\n");
			exitprog(0);
			switch (mdl->texlist[j].compression) {
			case 1:
				if (mdl->texlist[j].hasalpha)
				glCompressedTexImage2DARB(GL_TEXTURE_2D, 0,
					GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
					mdl->texlist[j].width,
					mdl->texlist[j].height, 0,
					mdl->texlist[j].size,
					mdl->texlist[j].data[0]);
				else
				glCompressedTexImage2DARB(GL_TEXTURE_2D, 0,
					GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
					mdl->texlist[j].width,
					mdl->texlist[j].height, 0,
					mdl->texlist[j].size,
					mdl->texlist[j].data[0]);
				break;
			case 3:
				glCompressedTexImage2DARB(GL_TEXTURE_2D, 0,
					GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
					mdl->texlist[j].width,
					mdl->texlist[j].height, 0,
					mdl->texlist[j].size,
					mdl->texlist[j].data[0]);
				break;
			case 5:
				glCompressedTexImage2DARB(GL_TEXTURE_2D, 0,
					GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
					mdl->texlist[j].width,
					mdl->texlist[j].height, 0,
					mdl->texlist[j].size,
					mdl->texlist[j].data);
				break;
			default:
				printf("Unknown compression format\n");
				exitprog(0);
			}
		} else if (mdl->texlist[j].bpp == 32) {
			glTexImage2D(GL_TEXTURE_2D, 0, 4,
			             mdl->texlist[j].width,
			             mdl->texlist[j].height, 0,
			             GL_RGBA,
			             GL_UNSIGNED_BYTE, mdl->texlist[j].data_a[0]);
		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);
void RenderScene(void)
	int i;
	finish = clock() ;
	duration += (double)(finish - start) / CLOCKS_PER_SEC ;
	frames ++ ;
	FPS = frames / duration ;
	start = clock() ;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0.0f, 1.0f, 0.0f, 1.0f);
	glMatrixMode(GL_MODELVIEW);
	PrintFPS();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glTranslatef(xPos, yPos, zPos);
	glRotatef(xRot, 1.0f, 0.0f, 0.0f);
	glRotatef(yRot, 0.0f, 1.0f, 0.0f);
	glRotatef(zRot, 0.0f, 0.0f, 1.0f);
	/* Display solid objects */
	for (i = 0; i < objscount; i++)
		DisplayModel(objs[i].mdl, 0);
	/* Display transparent objects */
	for (i = 0; i < objscount; i++)
		DisplayModel(objs[i].mdl, 1);
	glutSwapBuffers();
void SpecialKeyPressed(int key, int x, int y)
	switch (key) {
	case GLUT_KEY_UP:
		if (glutGetModifiers() == GLUT_ACTIVE_SHIFT)
			xRot -= 2.0f;
		else
			xRot -= 0.7f;
		break;
	case GLUT_KEY_DOWN:
		if (glutGetModifiers() == GLUT_ACTIVE_SHIFT)
			xRot += 2.0f;
		else
			xRot += 0.7f;
		break;
	case GLUT_KEY_LEFT:
		if (glutGetModifiers() == GLUT_ACTIVE_SHIFT)
			zRot -= 2.0f;
		else
			zRot -= 0.7f;
		break;
	case GLUT_KEY_RIGHT:
		if (glutGetModifiers() == GLUT_ACTIVE_SHIFT)
			zRot += 2.0f;
		else
			zRot += 0.7f;
		break;
	case GLUT_KEY_PAGE_UP:
		if (glutGetModifiers() == GLUT_ACTIVE_SHIFT)
			zPos += 0.7f;
		else
			zPos += 0.2f;
		break;
	case GLUT_KEY_PAGE_DOWN:
		if (glutGetModifiers() == GLUT_ACTIVE_SHIFT)
			zPos -= 0.7f;
		else
			zPos -= 0.2f;
		break;
	default:
		break;
	glutPostRedisplay();
void isvisible(void)
	if (objs[whichobj].mdl->clp->frm[whichframe].display == 1)
		printf("Object \"%s\" is visible.\n",
		       objs[whichobj].mdl->clp->frm[whichframe].name);
	else
		printf("Object \"%s\" is not visible.\n",
		        objs[whichobj].mdl->clp->frm[whichframe].name);
void KeyPressed(unsigned char key, int z, int y)
	switch(key) {
	case 'q':
		yRot -= 0.7f;
		break;
	case 'Q':
		yRot -= 2.0f;
		break;
	case 'e':
		yRot += 0.7f;
		break;
	case 'E':
		yRot += 2.0f;
		break;
	case 'h':
		xPos += 0.1f;
		break;
	case 'H':
		xPos += 0.2f;
		break;
	case 'j':
		yPos += 0.1f;
		break;
	case 'J':
		yPos += 0.2f;
		break;
	case 'k':
		yPos -= 0.1f;
		break;
	case 'K':
		yPos -= 0.2f;
		break;
	case 'l':
		xPos -= 0.1f;
		break;
	case 'L':
		xPos -= 0.2f;
		break;
	case 't':
	case 'T':
		if (textured == 1)
			glDisable(GL_TEXTURE_2D);
		else
			glEnable(GL_TEXTURE_2D);
		textured = !textured;
		break;
	case 'O':
		if (whichobj == 0)
			whichobj = objscount;
		whichobj--;
		whichframe = 0;
		isvisible();
		break;
	case 'o':
		whichobj++;
		if (whichobj == objscount)
			whichobj = 0;
		isvisible();
		break;
	case 'F':
		if (whichframe == 0)
			whichframe = objs[whichobj].mdl->clp->frmcount;
		whichframe--;
		isvisible();
		break;
	case 'f':
		whichframe++;
		if (whichframe == objs[whichobj].mdl->clp->frmcount)
			whichframe = 0;
		isvisible();
		break;
	case 'V':
	case 'v':
		objs[whichobj].mdl->clp->frm[whichframe].display =
			!objs[whichobj].mdl->clp->frm[whichframe].display;
		isvisible();
		break;
	case 'c':
	case 'C':
		printf("\nCamera position: %f %f %f\n", xPos, yPos, zPos);
		printf("Camera roatation: %f %f %f\n\n", xRot, yRot, zRot);
		break;
	case 'i':
	case 'I':
		objscount = 0;
		if (objs != NULL) {
			DestroyObjs(objs);
			free(objs);
		if ((objs = ReadIde(ide)) == NULL) {
			objscount = 0;
			exitprog(0);
		objs->mdl = LoadModel(objs->Model, objs->Texture, img, 0);
		objscount = 1;
		break;
	case ESCAPE:
		exitprog(0);
	default:
		break;
	glutPostRedisplay();
void ChangeSize(int w, int h)
	if(h == 0)
		h = 1;
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f, (GLfloat) w/(GLfloat)h, 0.1f, 2000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
	glTranslatef(0.0f, 0.0f, 0.0f);
Model *LoadModel(char *dfffile, char *txdfile, FILE **img, int arnum)
	int generictxd;
	int i;
	DirEntry *dff, *txd;
	Model *mdl;
	UseTextures = 1;
	txd = NULL;
	dff = GetFileOffset(filenum[arnum], filelist[arnum], dfffile);
	if (dff == NULL) {
		fprintf(stderr, "Could not find %s in img file\n", dfffile);
		exitprog(0);
	if (strcmp(txdfile, "generic.txd") == 0)
		generictxd = 1;
	else
		generictxd = 0;
	if (!generictxd) {
		txd = GetFileOffset(filenum[arnum], filelist[arnum], txdfile);
		if (txd == NULL) {
			fprintf(stderr, "Could not find %s in img file\n", txdfile);
			exitprog(0);
	mdl = (Model *) malloc(sizeof(Model));
	mdl->clp = (clump *) malloc(sizeof(clumHX
