Esempio n. 1
0
static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
{
    int s, t;

    GL_Bind( image );

#ifdef _XBOX
    int verts = ((maxs[0]+HALF_SKY_SUBDIVISIONS) - (mins[0]+HALF_SKY_SUBDIVISIONS)) * 2 + 2;
#endif

    for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
    {
#ifdef _XBOX
        qglBeginEXT( GL_TRIANGLE_STRIP, verts, 0, 0, verts, 0);
#else
        qglBegin( GL_TRIANGLE_STRIP );
#endif

        for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
        {
            qglTexCoord2fv( s_skyTexCoords[t][s] );
            qglVertex3fv( s_skyPoints[t][s] );

            qglTexCoord2fv( s_skyTexCoords[t+1][s] );
            qglVertex3fv( s_skyPoints[t+1][s] );
        }

        qglEnd();
    }
}
Esempio n. 2
0
static void DrawSkySideInner( struct image_s *image, const int mins[2], const int maxs[2] ) {
	int s, t;

	GL_Bind( image );

	//qglDisable (GL_BLEND);
	qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	qglEnable( GL_BLEND );
	GL_TexEnv( GL_MODULATE );

	for ( t = mins[1] + HALF_SKY_SUBDIVISIONS; t < maxs[1] + HALF_SKY_SUBDIVISIONS; t++ )
	{
		qglBegin( GL_TRIANGLE_STRIP );

		for ( s = mins[0] + HALF_SKY_SUBDIVISIONS; s <= maxs[0] + HALF_SKY_SUBDIVISIONS; s++ )
		{
			qglTexCoord2fv( s_skyTexCoords[t][s] );
			qglVertex3fv( s_skyPoints[t][s] );

			qglTexCoord2fv( s_skyTexCoords[t + 1][s] );
			qglVertex3fv( s_skyPoints[t + 1][s] );
		}

		qglEnd();
	}

	qglDisable( GL_BLEND );
}
Esempio n. 3
0
static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
{
	int s, t;

	GL_Bind( image );
	#ifdef HAVE_GLES
	GLfloat vtx[3*1024];	// arbitrary sized
	GLfloat tex[2*1024];
	int idx;
	
	GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY);
	GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY);
	if (glcol)
		qglDisableClientState(GL_COLOR_ARRAY);
	if (!text)
		qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
	#endif

	for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
	{
#ifdef HAVE_GLES
		idx=0;
#else
		qglBegin( GL_TRIANGLE_STRIP );
#endif

		for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
		{
			#ifdef HAVE_GLES
			memcpy(tex+idx*2, s_skyTexCoords[t][s], sizeof(GLfloat)*2);
			memcpy(vtx+idx*3, s_skyPoints[t][s], sizeof(GLfloat)*3);
			idx++;
			memcpy(tex+idx*2, s_skyTexCoords[t+1][s], sizeof(GLfloat)*2);
			memcpy(vtx+idx*3, s_skyPoints[t+1][s], sizeof(GLfloat)*3);
			idx++;
			#else
			qglTexCoord2fv( s_skyTexCoords[t][s] );
			qglVertex3fv( s_skyPoints[t][s] );

			qglTexCoord2fv( s_skyTexCoords[t+1][s] );
			qglVertex3fv( s_skyPoints[t+1][s] );
			#endif
		}

		#ifdef HAVE_GLES
		//*TODO* Try to switch from many DrawArrays of GL_TRIANGLE_STRIP to a single DrawArrays of TRIANGLES to see if it perform better
		qglVertexPointer (3, GL_FLOAT, 0, vtx);
		qglTexCoordPointer(2, GL_FLOAT, 0, tex);
		qglDrawArrays(GL_TRIANGLE_STRIP, 0, idx);
		#else
		qglEnd();
		#endif
	}
	#ifdef HAVE_GLES
	if (glcol)
		qglEnableClientState(GL_COLOR_ARRAY);
	if (!text)
		qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
	#endif
}
Esempio n. 4
0
void Terrain_DrawFace( brush_t *brush, terrainFace_t *terraface ) {
	terrainMesh_t	*pm;
	terravert_t		a0;
	terravert_t		a1;
	terravert_t		a2;

	pm = brush->pTerrain;
   
	Terrain_GetTriangle( pm, terraface->index, &a0, &a1, &a2 );

	qglBindTexture( GL_TEXTURE_2D, terraface->texture->texture_number );
	qglBegin( GL_TRIANGLES );

	// first tri
	qglColor4fv( a0.rgba );
	qglTexCoord2fv( a0.tc );
	qglVertex3fv( a0.xyz );

	qglColor4fv( a1.rgba );
	qglTexCoord2fv( a1.tc );
	qglVertex3fv( a1.xyz );

	qglColor4fv( a2.rgba );
	qglTexCoord2fv( a2.tc );
	qglVertex3fv( a2.xyz );

	qglEnd ();
}
Esempio n. 5
0
/*
================
R_ArrayElementDiscrete

This is just for OpenGL conformance testing, it should never be the fastest
================
*/
static void APIENTRY R_ArrayElementDiscrete( GLint index ) {
	qglColor4ubv( tess.svars.colors[ index ] );
	if ( glState.currenttmu ) {
		qglMultiTexCoord2fARB( 0, tess.svars.texcoords[ 0 ][ index ][0], tess.svars.texcoords[ 0 ][ index ][1] );
		qglMultiTexCoord2fARB( 1, tess.svars.texcoords[ 1 ][ index ][0], tess.svars.texcoords[ 1 ][ index ][1] );
	} else {
		qglTexCoord2fv( tess.svars.texcoords[ 0 ][ index ] );
	}
	qglVertex3fv( tess.xyz[ index ].v );
}
Esempio n. 6
0
static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
{
	int s, t;
	unsigned i;
	vec3_t points[(SKY_SUBDIVISIONS+1) * (SKY_SUBDIVISIONS+1)];
	float texcoords[(SKY_SUBDIVISIONS+1) * (SKY_SUBDIVISIONS+1) * 2];

	GL_Bind( image );

	for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
	{
#ifndef GL_VERSION_ES_CM_1_0
		qglBegin( GL_TRIANGLE_STRIP );

		for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
		{
			qglTexCoord2fv( s_skyTexCoords[t][s] );
			qglVertex3fv( s_skyPoints[t][s] );

			qglTexCoord2fv( s_skyTexCoords[t+1][s] );
			qglVertex3fv( s_skyPoints[t+1][s] );
		}

		qglEnd();
#else
		for ( s = mins[0]+HALF_SKY_SUBDIVISIONS, i = 0; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++, i += 2 )
		{
			VectorCopy( s_skyPoints[t][s], points[i] );
			VectorCopy( s_skyPoints[t+1][s], points[i+1] );
			texcoords[i*2] = s_skyTexCoords[t][s][0];
			texcoords[i*2+1] = s_skyTexCoords[t][s][1];
			texcoords[i*2+2] = s_skyTexCoords[t+1][s][0];
			texcoords[i*2+3] = s_skyTexCoords[t+1][s][1];
		}
		qglEnableClientState ( GL_VERTEX_ARRAY );
		qglEnableClientState ( GL_TEXTURE_COORD_ARRAY );
		qglTexCoordPointer ( 2, GL_FLOAT, 0, texcoords );
		qglVertexPointer ( 3, GL_FLOAT, 0, points );
		qglDrawArrays( GL_TRIANGLE_STRIP, 0, i );
#endif
	}
}
Esempio n. 7
0
File: sky.c Progetto: icanhas/yantar
static void
DrawSkySide(struct Img *image, const int mins[2], const int maxs[2])
{
	int s, t;

	GL_Bind(image);

	for(t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++){
		qglBegin(GL_TRIANGLE_STRIP);

		for(s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++){
			qglTexCoord2fv(s_skyTexCoords[t][s]);
			qglVertex3fv(s_skyPoints[t][s]);

			qglTexCoord2fv(s_skyTexCoords[t+1][s]);
			qglVertex3fv(s_skyPoints[t+1][s]);
		}

		qglEnd();
	}
}
Esempio n. 8
0
void glTexturedBox(idVec3 &point, float size, const idMaterial *mat) {
    qglTranslatef(point.x, point.y, point.z);
    for (int i = 0; i < numQuads; i++) {
        qglBegin(GL_QUADS);
        for (int j = 0; j < 4; j++) {
            idVec3 v = cubeData[i * 4 + j].xyz;
            v *= size;
            qglTexCoord2fv(cubeData[i * 4 + j].st.ToFloatPtr());
            qglVertex3fv(v.ToFloatPtr());
        }
        qglEnd();
    }
}
Esempio n. 9
0
/*
=============
EmitWaterPolys

Does a water warp
=============
*/
void EmitWaterPolys (const glpoly_t *p, qboolean flowing)
{
	const float	*v;
	vec_t		st[2], scroll;
	int			i, nv;

	if (flowing)
		scroll = -64 * ( (r_newrefdef.time*0.5f) - (int)(r_newrefdef.time*0.5f) );
	else
		scroll = 0;

	v = p->verts[0];
	nv = p->numverts;

	qglBegin (GL_TRIANGLE_FAN);
	if (!flowing && gl_waterwaves->value) {
		vec3_t		wv;   // Water waves

		for (i = 0; i < nv; i++, v += VERTEXSIZE) {
			st[0] = (v[3] + TURBSIN(v[4], 0.125f) + scroll) * ONEDIV64;
			st[1] = (v[4] + TURBSIN(v[3], 0.125f)) * ONEDIV64;
			qglTexCoord2fv(st);

			wv[0] = v[0];
			wv[1] = v[1];
			wv[2] = v[2] + gl_waterwaves->value *(float)sin(v[0]*0.025f+r_newrefdef.time)*(float)sin(v[2]*0.05f+r_newrefdef.time)
					+ gl_waterwaves->value *(float)sin(v[1]*0.025f+r_newrefdef.time*2)*(float)sin(v[2]*0.05f+r_newrefdef.time);
			qglVertex3fv(wv);
		}
	} else {
		for (i = 0; i < nv; i++, v += VERTEXSIZE) {
			st[0] = (v[3] + TURBSIN(v[4], 0.125f) + scroll) * ONEDIV64;
			st[1] = (v[4] + TURBSIN(v[3], 0.125f)) * ONEDIV64;
			qglTexCoord2fv (st);
			qglVertex3fv (v);
		}
	}
	qglEnd ();
}
/*
=================
RB_DrawElementsImmediate

Draws with immediate mode commands, which is going to be very slow.
This should never happen if the vertex cache is operating properly.
=================
*/
void RB_DrawElementsImmediate( const srfTriangles_t *tri ) {
	backEnd.pc.c_drawElements++;
	backEnd.pc.c_drawIndexes += tri->numIndexes;
	backEnd.pc.c_drawVertexes += tri->numVerts;

	if ( tri->ambientSurface != NULL  ) {
		if ( tri->indexes == tri->ambientSurface->indexes ) {
			backEnd.pc.c_drawRefIndexes += tri->numIndexes;
		}
		if ( tri->verts == tri->ambientSurface->verts ) {
			backEnd.pc.c_drawRefVertexes += tri->numVerts;
		}
	}

	qglBegin( GL_TRIANGLES );
	for ( int i = 0 ; i < tri->numIndexes ; i++ ) {
		qglTexCoord2fv( tri->verts[ tri->indexes[i] ].st.ToFloatPtr() );
		qglVertex3fv( tri->verts[ tri->indexes[i] ].xyz.ToFloatPtr() );
	}
	qglEnd();
}
Esempio n. 11
0
void GLRB_DrawSkyBox( const skyboxDrawInfo_t* skybox, const float* eye_origin, const float* colorTint )
{
    int i, j, k;

    qglColor3fv( colorTint );		
	qglPushMatrix ();
	GL_State( 0 );
	qglTranslatef( eye_origin[0], eye_origin[1], eye_origin[2] );

    for ( i = 0; i < 6; ++i )
    {
        const skyboxSideDrawInfo_t* side = &skybox->sides[i];

        if ( !side->image )
            continue;

        GL_Bind( side->image );

        for ( j = 0; j < side->stripCount; ++j )
        {
            int start = side->stripInfo[j].offset;
            int end = side->stripInfo[j].length + start;

            qglBegin( GL_TRIANGLE_STRIP );

            for ( k = start; k < end; ++k )
            {
                qglTexCoord2fv( skybox->tbuffer + 2 * k );
                qglVertex3fv( skybox->vbuffer + 3 * k );
            }

            qglEnd();
        }
    }

	qglPopMatrix();
}
Esempio n. 12
0
/*
===================
DrawPatch
===================
*/
void DrawPatch (face_t *cf, float ctrl[3][3][5]) {
	int		i, j;
	float	u, v;
	vec5_t	verts[CBLOCK_SUBDIVISIONS+1][CBLOCK_SUBDIVISIONS+1];

	if (curveFile) {
		fprintf (curveFile, "PATCH {\n");
		fprintf (curveFile, "textures/%s\n", cf->texdef.name);
		Write3DMatrix (curveFile, 3, 3, 5, (float *)ctrl);
		fprintf (curveFile, "}\n");
		return;
	}

	for (i = 0 ; i <= CBLOCK_SUBDIVISIONS ; i++) {
		for (j = 0 ; j <= CBLOCK_SUBDIVISIONS ; j++) {
			u = (float)i / CBLOCK_SUBDIVISIONS;
			v = (float)j / CBLOCK_SUBDIVISIONS;
			SamplePatch (ctrl, u, v, verts[i][j]);
		}
	}

	if ( bevelBrush ) {
		face_t		*f;
		vec3_t		v0, v1, v2;
		vec3_t		d1, d2, cross;

		for (i = 0 ; i < CBLOCK_SUBDIVISIONS ; i++) {
			for (j = 0 ; j < CBLOCK_SUBDIVISIONS ; j++) {
				VectorCopy( verts[i][j], v0 );
				VectorCopy( verts[i][j+1], v1 );
				VectorCopy( verts[i+1][j], v2 );

				VectorSubtract( v0, v1, d1 );
				VectorSubtract( v2, v1, d2 );
				CrossProduct( d1, d2, cross );
				if ( VectorLength( cross ) == 0 ) {
					continue;	// degenerate
				}
				f = Face_Clone( bevelBrush->brush_faces );
				f->texdef.flags |= SURF_CURVE_FAKE;
				VectorCopy( v0, f->planepts[0] );
				VectorCopy( v1, f->planepts[1] );
				VectorCopy( v2, f->planepts[2] );
				Brush_MakeFacePlane( f );
				f->next = bevelBrush->brush_faces;
				bevelBrush->brush_faces = f;
			}
		}
		return;
	}



	qglBindTexture (GL_TEXTURE_2D, cf->d_texture->texture_number);

  float fColor[3];
  SetColor(cf, fColor);


	for (i = 0 ; i < CBLOCK_SUBDIVISIONS ; i++) {
		qglBegin (GL_QUAD_STRIP);
		for (j = 0 ; j <= CBLOCK_SUBDIVISIONS ; j++) {
			qglTexCoord2fv( verts[i+1][j] + 3 );
			qglVertex3fv( verts[i+1][j] );
			qglTexCoord2fv( verts[i][j] + 3 );
			qglVertex3fv( verts[i][j] );
      DecColor(fColor);
		}
		qglEnd ();
	}
}
Esempio n. 13
0
/*
===============
DrawRuledSurface
===============
*/
void DrawRuledSurface (face_t *cf, float ctrl[2][3][5] ) {
	int			j, k, l;
	vec5_t		curve[2][CBLOCK_SUBDIVISIONS+1];
	//float		u;
	float		*v;

	if (curveFile) {
		fprintf (curveFile, "RULED {\n");
		fprintf (curveFile, "textures/%s\n", cf->texdef.name);
		Write3DMatrix (curveFile, 2, 3, 5, (float *)ctrl);
		fprintf (curveFile, "}\n");
		return;
	}

	for (j = 0 ; j < 2 ; j++) {
		for (l = 0 ; l < 5 ; l++) {
			float	a, b, c;
			float	qA, qB, qC;
			float	f;
			int		k;

			a = ctrl[j][0][l];
			b = ctrl[j][1][l];
			c = ctrl[j][2][l];
			qA = a - 2 * b + c;
			qB = 2 * b - 2 * a;
			qC = a;

			for (k = 0 ; k <= CBLOCK_SUBDIVISIONS ; k++) {
				f = (float)k / CBLOCK_SUBDIVISIONS;
				curve[j][k][l] = qA*f*f + qB*f + qC;
			}
		}
	}

	if ( bevelBrush ) {
		face_t	*f;

		for (k = 0 ; k < CBLOCK_SUBDIVISIONS ; k++) {
			f = Face_Clone( bevelBrush->brush_faces );
			f->texdef.flags |= SURF_CURVE_FAKE;
			f->next = bevelBrush->brush_faces;
			bevelBrush->brush_faces = f;

			VectorCopy( curve[0][k], f->planepts[0] );
			VectorCopy( curve[1][k], f->planepts[1] );
			VectorCopy( curve[0][k+1], f->planepts[2] );
			Brush_MakeFacePlane( f );
		}
		return;
	}



	qglBindTexture (GL_TEXTURE_2D, cf->d_texture->texture_number);

  float fColor[3];
  SetColor(cf, fColor);

	qglBegin (GL_QUAD_STRIP);
	for (k = 0 ; k <= CBLOCK_SUBDIVISIONS ; k++) {
		v = curve[0][k];
		qglTexCoord2fv( v + 3 );
		qglVertex3fv( v );

		v = curve[1][k];
		qglTexCoord2fv( v + 3 );
		qglVertex3fv( v );
	}


	qglEnd ();
}
Esempio n. 14
0
/*
===============
DrawCurveFan

Draws a curve as part of a flat surface
===============
*/
void DrawCurveFan (face_t *cf, vec5_t opposite, vec5_t prev, vec5_t peak, vec5_t next) {
	int			i, k, l;
	float		coef[5][3];

	// write it out
	if (curveFile) {
		vec5_t	vecs[4];

		for ( i = 0 ; i < 5 ; i++ ) {
			vecs[0][i] = opposite[i];
			vecs[1][i] = prev[i];
			vecs[2][i] = peak[i];
			vecs[3][i] = next[i];
		}
		fprintf (curveFile, "CURVEFAN {\n");
		fprintf (curveFile, "textures/%s\n", cf->texdef.name);
		Write2DMatrix (curveFile, 4, 5, (float *)vecs);
		fprintf (curveFile, "}\n");
		return;
	}

	// calculate the coefficients
	for (l = 0 ; l < 5 ; l++) {
		float	a, b, c;

		a = prev[l];
		b = peak[l];
		c = next[l];
		coef[l][0] = a;
		coef[l][1] = 2 * b - 2 * a;
		coef[l][2] = a - 2 * b + c;
	}


	// draw it
	qglBindTexture (GL_TEXTURE_2D, cf->d_texture->texture_number);


  float fColor[3];
  SetColor(cf, fColor);


	qglBegin (GL_TRIANGLE_FAN);

	qglTexCoord2fv( opposite + 3 );
	qglVertex3fv( opposite );

	for ( k = 0 ; k <= CBLOCK_SUBDIVISIONS ; k++ ) {
		vec5_t		curve;
		float		f;

		f = (float)k / CBLOCK_SUBDIVISIONS;
		for ( l = 0 ; l < 5 ; l++ ) {
			curve[l] = coef[l][2]*f*f + coef[l][1]*f + coef[l][0];
		}

		qglTexCoord2fv( curve + 3 );
		qglVertex3fv( curve );
    DecColor(fColor);
	}

	qglEnd ();
}
Esempio n. 15
0
void QueueDraw(){
	guint32 i, k;
	face_t *face;
	winding_t *w;
	int j, nDrawMode = g_pParentWnd->GetCamera().draw_mode;

	if ( notex_faces->len ) {
		qglDisable( GL_TEXTURE_2D );

		for ( i = 0; i < notex_faces->len; i++ )
		{
			face = (face_t*)notex_faces->pdata[i];
			w = face->face_winding;

			qglBegin( GL_POLYGON );

			/*
			   if (b->patchBrush)
			   //++timo FIXME: find a use case for this??
			   qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13);
			   else
			 */
			qglColor4f( face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans() );

			if ( g_PrefsDlg.m_bGLLighting ) {
				qglNormal3fv( face->plane.normal );
			}

			for ( j = 0; j < w->numpoints; j++ )
			{
				if ( nDrawMode == cd_texture || nDrawMode == cd_light ) {
					qglTexCoord2fv( &w->points[j][3] );
				}
				qglVertex3fv( w->points[j] );
			}

			qglEnd();
		}
	}

	if ( !len ) {
		return;
	}

	if ( nDrawMode == cd_texture || nDrawMode == cd_light ) {
		qglEnable( GL_TEXTURE_2D );
	}

	for ( k = 0; k < len; k++ )
	{
		qglBindTexture( GL_TEXTURE_2D, sort[k].texture->texture_number );

		for ( i = 0; i < sort[k].faces->len; i++ )
		{
			face = (face_t*)sort[k].faces->pdata[i];
			w = face->face_winding;

			qglBegin( GL_POLYGON );
			/*
			   if (b->patchBrush)
			   //++timo FIXME: find a use case for this??
			   qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13);
			   else
			 */
			qglColor4f( face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans() );

			if ( g_PrefsDlg.m_bGLLighting ) {
				qglNormal3fv( face->plane.normal );
			}

			for ( j = 0; j < w->numpoints; j++ )
			{
				if ( nDrawMode == cd_texture || nDrawMode == cd_light ) {
					qglTexCoord2fv( &w->points[j][3] );
				}
				qglVertex3fv( w->points[j] );
			}

			qglEnd();
		}
	}
	qglBindTexture( GL_TEXTURE_2D, 0 );
}
Esempio n. 16
0
void DrawTerrain( terrainMesh_t *pm, bool bPoints, bool bShade ) {
	int				i;
	int				w;
	int				h;
	int				x;
	int				y;
	//int			n;
	//float			x1;
	//float			y1;
	float			scale_x;
	float			scale_y;
	//vec3_t		pSelectedPoints[ MAX_TERRA_POINTS ];
	//int			nIndex;
	terravert_t		a0;
	terravert_t		a1;
	terravert_t		a2;
	terravert_t		b0;
	terravert_t		b1;
	terravert_t		b2;
	terrainVert_t	*vert;
	qtexture_t		*texture;

	h = pm->height - 1;
	w = pm->width - 1;
   
	scale_x = pm->scale_x;
	scale_y = pm->scale_y;

	qglShadeModel (GL_SMOOTH);

	if ( bShade ) {
		for( i = 0; i < pm->numtextures; i++ ) {
			texture = pm->textures[ i ];

			qglBindTexture( GL_TEXTURE_2D, texture->texture_number );

			vert = pm->heightmap;
			for( y = 0; y < h; y++ ) {
				qglBegin( GL_TRIANGLES );

				for( x = 0; x < w; x++, vert++ ) {
					Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture );

					// first tri
					if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) {
						qglColor4fv( a0.rgba );
						qglTexCoord2fv( a0.tc );
						qglVertex3fv( a0.xyz );

						qglColor4fv( a1.rgba );
						qglTexCoord2fv( a1.tc );
						qglVertex3fv( a1.xyz );

						qglColor4fv( a2.rgba );
						qglTexCoord2fv( a2.tc );
						qglVertex3fv( a2.xyz );
					}

					// second tri
					if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) {
						qglColor4fv( b0.rgba );
						qglTexCoord2fv( b0.tc );
						qglVertex3fv( b0.xyz );

						qglColor4fv( b1.rgba );
						qglTexCoord2fv( b1.tc );
						qglVertex3fv( b1.xyz );

						qglColor4fv( b2.rgba );
						qglTexCoord2fv( b2.tc );
						qglVertex3fv( b2.xyz );
					}
				}

			qglEnd ();
			}
		}
	} else {
		for( i = 0; i < pm->numtextures; i++ ) {
			texture = pm->textures[ i ];

			qglBindTexture( GL_TEXTURE_2D, texture->texture_number );

			vert = pm->heightmap;
			for( y = 0; y < h; y++ ) {
				qglBegin( GL_TRIANGLES );

				for( x = 0; x < w; x++, vert++ ) {
					Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture );

					// first tri
					if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) {
						qglColor4fv( a0.rgba );
						qglTexCoord2fv( a0.tc );
						qglVertex3fv( a0.xyz );

						qglColor4fv( a1.rgba );
						qglTexCoord2fv( a1.tc );
						qglVertex3fv( a1.xyz );

						qglColor4fv( a2.rgba );
						qglTexCoord2fv( a2.tc );
						qglVertex3fv( a2.xyz );
					}

					// second tri
					if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) {
						qglColor4fv( b0.rgba );
						qglTexCoord2fv( b0.tc );
						qglVertex3fv( b0.xyz );

						qglColor4fv( b1.rgba );
						qglTexCoord2fv( b1.tc );
						qglVertex3fv( b1.xyz );

						qglColor4fv( b2.rgba );
						qglTexCoord2fv( b2.tc );
						qglVertex3fv( b2.xyz );
					}
				}
				qglEnd ();
			}
		}
	}

	qglPushAttrib( GL_CURRENT_BIT );

	bool bDisabledLighting = qglIsEnabled( GL_LIGHTING );
	if ( bDisabledLighting ) {
		qglDisable( GL_LIGHTING );
	}

#if 0
	terrainVert_t	*currentrow;
	terrainVert_t	*nextrow;
	float			x2;
	float			y2;

	// Draw normals
	qglDisable( GL_TEXTURE_2D );
	qglDisable( GL_BLEND );
	qglColor3f( 1, 1, 1 );
	qglBegin( GL_LINES );

	y2 = pm->origin[ 1 ];
	nextrow = pm->heightmap;
	for( y = 0; y < h; y++ ) {
		y1 = y2;
		y2 += scale_y;

		x2 = pm->origin[ 0 ];
		currentrow = nextrow;
		nextrow = currentrow + pm->width;
		for( x = 0; x < w; x++ ) {
			x1 = x2;
			x2 += scale_x;

			// normals
			qglVertex3f( x1, y1, pm->origin[ 2 ] + currentrow[ x ].height );
			qglVertex3f( x1 + currentrow[ x ].normal[ 0 ] * 16.0f, y1 + currentrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x ].height + currentrow[ x ].normal[ 2 ] * 16.0f );

			qglVertex3f( x2, y1, pm->origin[ 2 ] + currentrow[ x + 1 ].height );
			qglVertex3f( x2 + currentrow[ x + 1 ].normal[ 0 ] * 16.0f, y1 + currentrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x + 1 ].height + currentrow[ x + 1 ].normal[ 2 ] * 16.0f );

			qglVertex3f( x1, y2, pm->origin[ 2 ] + nextrow[ x ].height );
			qglVertex3f( x1 + nextrow[ x ].normal[ 0 ] * 16.0f, y2 + nextrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x ].height + nextrow[ x ].normal[ 2 ] * 16.0f );

			qglVertex3f( x2, y2, pm->origin[ 2 ] + nextrow[ x + 1 ].height );
			qglVertex3f( x2 + nextrow[ x + 1 ].normal[ 0 ] * 16.0f, y2 + nextrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x + 1 ].height + nextrow[ x + 1 ].normal[ 2 ] * 16.0f );
		}
	}

	qglEnd ();
	qglEnable( GL_TEXTURE_2D );
#endif

#if 0
	if ( bPoints && ( g_qeglobals.d_select_mode == sel_terrainpoint || g_qeglobals.d_select_mode == sel_area ) ) {
		qglPointSize( 6 );
		qglDisable( GL_TEXTURE_2D );
		qglDisable( GL_BLEND );

		qglBegin( GL_POINTS );

		nIndex = 0;

		qglColor4f( 1, 0, 1, 1 );

		y1 = pm->origin[ 1 ];
		for ( y = 0; y < pm->height; y++, y1 += pm->scale_y ) {
			x1 = pm->origin[ 0 ];
			for( x = 0; x < pm->width; x++, x1 += pm->scale_x ) {
				// FIXME: need to not do loop lookups inside here
				n = Terrain_PointInMoveList( &pm->heightmap[ x + y * pm->width ] );
				if ( n >= 0 ) {
					VectorSet( pSelectedPoints[ nIndex ], x1, y1, pm->heightmap[ x + y * pm->width ].height + pm->origin[ 2 ] );
					nIndex++;
				} else {
					qglVertex3f( x1, y1, pm->origin[ 2 ] + pm->heightmap[ x + y * pm->width ].height );
				}
			}
		}

		qglEnd();
		
		qglEnable( GL_TEXTURE_2D );

		if ( nIndex > 0 ) {
			qglBegin( GL_POINTS );
			qglColor4f( 0, 0, 1, 1 );
			while( nIndex-- > 0 ) {
				qglVertex3fv( pSelectedPoints[ nIndex ] );
			}
		
			qglEnd();
		}
	}
#endif

	if ( g_qeglobals.d_numterrapoints && ( ( g_qeglobals.d_select_mode == sel_terrainpoint ) || ( g_qeglobals.d_select_mode == sel_terraintexture ) ) ) {
#if 0 
		qglPointSize( 6 );
		qglDisable( GL_TEXTURE_2D );
		qglDisable( GL_BLEND );

		qglBegin( GL_POINTS );

		qglColor4f( 1, 0, 1, 1 );

		for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) {
			qglVertex3fv( g_qeglobals.d_terrapoints[ i ]->xyz );
		}

		qglEnd();
			
		qglEnable( GL_TEXTURE_2D );
#endif

		brush_t			*pb;
		terrainMesh_t	*pm;

		pm = NULL;
		for( pb = active_brushes .next; pb != &active_brushes; pb = pb->next ) {
			if ( pb->terrainBrush ) {
				pm = pb->pTerrain;
				break;
			}
		}

		if ( pm ) {
			qglDisable( GL_TEXTURE_2D );
			qglBegin( GL_TRIANGLES );
			qglEnable( GL_BLEND );

			qglColor4f( 0.25, 0.5, 1, 0.35 );

			for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) {
				terravert_t		a0;
				terravert_t		a1;
				terravert_t		a2;

				qglColor4f( 0.25, 0.5, 1, g_qeglobals.d_terrapoints[ i ]->scale * 0.75 + 0.25 );
				Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2, &a0, &a1, &a2 );

				qglVertex3fv( a0.xyz );
				qglVertex3fv( a1.xyz );
				qglVertex3fv( a2.xyz );

				Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2 + 1, &a0, &a1, &a2 );

				qglVertex3fv( a0.xyz );
				qglVertex3fv( a1.xyz );
				qglVertex3fv( a2.xyz );
			}
			qglEnd();
			
			qglDisable( GL_BLEND );
			qglEnable( GL_TEXTURE_2D );
		}
	}
}