Beispiel #1
0
void idSplineList::draw(bool editMode) {
	int i;
	vec4_t yellow(1, 1, 0, 1);
        
	if (controlPoints.Num() == 0) {
		return;
	}

	if (dirty) {
		buildSpline();
	}


	qglColor3fv(controlColor);
	qglPointSize(5);
	
	qglBegin(GL_POINTS);
	for (i = 0; i < controlPoints.Num(); i++) {
		qglVertex3fv(*controlPoints[i]);
	}
	qglEnd();
	
	if (editMode) {
		for(i = 0; i < controlPoints.Num(); i++) {
			glBox(activeColor, *controlPoints[i], 4);
		}
	}

	//Draw the curve
	qglColor3fv(pathColor);
	qglBegin(GL_LINE_STRIP);
	int count = splinePoints.Num();
	for (i = 0; i < count; i++) {
		qglVertex3fv(*splinePoints[i]);
	}
	qglEnd();

	if (editMode) {
		qglColor3fv(segmentColor);
		qglPointSize(3);
		qglBegin(GL_POINTS);
		for (i = 0; i < count; i++) {
			qglVertex3fv(*splinePoints[i]);
		}
		qglEnd();
	}
	if (count > 0) {
		//assert(activeSegment >=0 && activeSegment < count);
		if (activeSegment >=0 && activeSegment < count) {
			glBox(activeColor, *splinePoints[activeSegment], 6);
			glBox(yellow, *splinePoints[activeSegment], 8);
		}
	}

}
Beispiel #2
0
void glBox(idVec3_t &color, idVec3_t &point, float size) {
	idVec3_t mins(point);
	idVec3_t maxs(point);
	mins[0] -= size;
	mins[1] += size;
	mins[2] -= size;
	maxs[0] += size;
	maxs[1] -= size;
	maxs[2] += size;
	qglColor3fv(color);
	qglBegin(GL_LINE_LOOP);
	qglVertex3f(mins[0],mins[1],mins[2]);
	qglVertex3f(maxs[0],mins[1],mins[2]);
	qglVertex3f(maxs[0],maxs[1],mins[2]);
	qglVertex3f(mins[0],maxs[1],mins[2]);
	qglEnd();
	qglBegin(GL_LINE_LOOP);
	qglVertex3f(mins[0],mins[1],maxs[2]);
	qglVertex3f(maxs[0],mins[1],maxs[2]);
	qglVertex3f(maxs[0],maxs[1],maxs[2]);
	qglVertex3f(mins[0],maxs[1],maxs[2]);
	qglEnd();

	qglBegin(GL_LINES);
  	qglVertex3f(mins[0],mins[1],mins[2]);
	qglVertex3f(mins[0],mins[1],maxs[2]);
	qglVertex3f(mins[0],maxs[1],maxs[2]);
	qglVertex3f(mins[0],maxs[1],mins[2]);
	qglVertex3f(maxs[0],mins[1],mins[2]);
	qglVertex3f(maxs[0],mins[1],maxs[2]);
	qglVertex3f(maxs[0],maxs[1],maxs[2]);
	qglVertex3f(maxs[0],maxs[1],mins[2]);
	qglEnd();

}
Beispiel #3
0
void Terrain_DrawXY( terrainMesh_t *pm, entity_t *owner ) {
	qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
   
	if ( pm->bSelected ) {
		qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_SELBRUSHES ] );
	} else if ( owner != world_entity && _stricmp( owner->eclass->name, "func_group" ) ) {
		qglColor3fv( owner->eclass->color );
	} else {
		//FIXME
		qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_BRUSHES ] );
	}
	
	qglLineWidth( 1 );

	DrawTerrain( pm, pm->bSelected );

	qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
}
Beispiel #4
0
void SetColor(face_t* f, float fColor[3])
{
	return;
  if (g_bCamPaint)
  {
    fColor[0] = f->d_color[0];
    fColor[1] = f->d_color[1];
    fColor[2] = f->d_color[2];
	  qglColor3fv(fColor);
  }
}
Beispiel #5
0
/*
================
glLabeledPoint
================
*/
void glLabeledPoint(idVec4 &color, idVec3 &point, float size, const char *label) {
	qglColor3fv( color.ToFloatPtr() );
	qglPointSize( size );
	qglBegin( GL_POINTS );
	qglVertex3fv( point.ToFloatPtr() );
	qglEnd();
	idVec3 v = point;
	v.x += 1;
	v.y += 1;
	v.z += 1;
	qglRasterPos3fv( v.ToFloatPtr() );
	qglCallLists( strlen(label), GL_UNSIGNED_BYTE, label );
}
Beispiel #6
0
void DecColor(float fColor[3])
{
	return;
  if (g_bCamPaint)
  {
    fColor[0] -= fDec;
    fColor[1] -= fDec ;
    fColor[2] -= fDec;
    for (int i = 0; i < 3; i++)
    {
      if (fColor[i] <= fLowerLimit)
        fColor[i] = fFullBright;
    }
	  qglColor3fv(fColor);
  }
}
void GLRB_DrawBeam( const image_t* image, const float* color, const vec3_t startPoints[], const vec3_t endPoints[], int segs )
{
    int i;

	GL_Bind( image );

	GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );

	qglColor3fv( color );

	qglBegin( GL_TRIANGLE_STRIP );
	for ( i = 0; i <= segs; i++ ) {
		qglVertex3fv( startPoints[ i % segs] );
		qglVertex3fv( endPoints[ i % segs] );
	}
	qglEnd();
}
Beispiel #8
0
/*
================
glBox
================
*/
void glBox(idVec4 &color, idVec3 &point, float size) {
	idVec3 mins(point);
	idVec3 maxs(point);
	mins[0] -= size;
	mins[1] += size;
	mins[2] -= size;
	maxs[0] += size;
	maxs[1] -= size;
	maxs[2] += size;
	idVec4	saveColor;
	qglGetFloatv(GL_CURRENT_COLOR, saveColor.ToFloatPtr());
	qglColor3fv( color.ToFloatPtr() );
	qglBegin(GL_LINE_LOOP);
	qglVertex3f(mins[0],mins[1],mins[2]);
	qglVertex3f(maxs[0],mins[1],mins[2]);
	qglVertex3f(maxs[0],maxs[1],mins[2]);
	qglVertex3f(mins[0],maxs[1],mins[2]);
	qglEnd();
	qglBegin(GL_LINE_LOOP);
	qglVertex3f(mins[0],mins[1],maxs[2]);
	qglVertex3f(maxs[0],mins[1],maxs[2]);
	qglVertex3f(maxs[0],maxs[1],maxs[2]);
	qglVertex3f(mins[0],maxs[1],maxs[2]);
	qglEnd();

	qglBegin(GL_LINES);
  	qglVertex3f(mins[0],mins[1],mins[2]);
	qglVertex3f(mins[0],mins[1],maxs[2]);
	qglVertex3f(mins[0],maxs[1],maxs[2]);
	qglVertex3f(mins[0],maxs[1],mins[2]);
	qglVertex3f(maxs[0],mins[1],mins[2]);
	qglVertex3f(maxs[0],mins[1],maxs[2]);
	qglVertex3f(maxs[0],maxs[1],maxs[2]);
	qglVertex3f(maxs[0],maxs[1],mins[2]);
	qglEnd();
	qglColor4fv(saveColor.ToFloatPtr());

}
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();
}
Beispiel #10
0
/*
==============
Z_Draw
==============
*/
void Z_Draw (void)
{
    brush_t	*brush;
	float	w, h;
	double	start, end;
	qtexture_t	*q;
	float	top, bottom;
	vec3_t	org_top, org_bottom, dir_up, dir_down;
	int xCam = z.width/3;

	if (!active_brushes.next)
		return;	// not valid yet

	if (z.timing)
		start = Sys_DoubleTime ();

	//
	// clear
	//
	qglViewport(0, 0, z.width, z.height);

	qglClearColor (
		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0],
		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1],
		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],
		0);

    /* GL Bug */ 
	/* When not using hw acceleration, gl will fault if we clear the depth 
	buffer bit on the first pass. The hack fix is to set the GL_DEPTH_BUFFER_BIT
	only after Z_Draw() has been called once. Yeah, right. */
	qglClear(glbitClear); 
	glbitClear |= GL_DEPTH_BUFFER_BIT;

	qglMatrixMode(GL_PROJECTION);

  qglLoadIdentity ();
	w = z.width/2 / z.scale;
	h = z.height/2 / z.scale;
	qglOrtho (-w, w, z.origin[2]-h, z.origin[2]+h, -8, 8);

	qglDisable(GL_TEXTURE_2D);
	qglDisable(GL_TEXTURE_1D);
	qglDisable(GL_DEPTH_TEST);
	qglDisable(GL_BLEND);


	//
	// now draw the grid
	//
	Z_DrawGrid ();

	//
	// draw stuff
	//

	qglDisable(GL_CULL_FACE);

	qglShadeModel (GL_FLAT);

	qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);

	qglDisable(GL_TEXTURE_2D);
	qglDisable(GL_BLEND);
	qglDisable(GL_DEPTH_TEST);


	// draw filled interiors and edges
	dir_up[0] = 0 ; dir_up[1] = 0; dir_up[2] = 1;
	dir_down[0] = 0 ; dir_down[1] = 0; dir_down[2] = -1;
	VectorCopy (z.origin, org_top);
	org_top[2] = MAX_WORLD_COORD;//4096;	// MAX_WORLD_COORD  ?  (John said this didn't work, Hmmmmmm)	// !suspect!
	VectorCopy (z.origin, org_bottom);
	org_bottom[2] = MIN_WORLD_COORD;//-4096;	// MIN_WORLD_COORD?    " "  !suspect!

	for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
	{
		if (brush->mins[0] >= z.origin[0]
			|| brush->maxs[0] <= z.origin[0]
			|| brush->mins[1] >= z.origin[1]
			|| brush->maxs[1] <= z.origin[1])
			continue;

		if (!Brush_Ray (org_top, dir_down, brush, &top))
			continue;
		top = org_top[2] - top;
		if (!Brush_Ray (org_bottom, dir_up, brush, &bottom))
			continue;
		bottom = org_bottom[2] + bottom;

		q = Texture_ForName (brush->brush_faces->texdef.name);
		qglColor3f (q->color[0], q->color[1], q->color[2]);
		qglBegin (GL_QUADS);
		qglVertex2f (-xCam, bottom);
		qglVertex2f (xCam, bottom);
		qglVertex2f (xCam, top);
		qglVertex2f (-xCam, top);
		qglEnd ();

		qglColor3f (1,1,1);
		qglBegin (GL_LINE_LOOP);
		qglVertex2f (-xCam, bottom);
		qglVertex2f (xCam, bottom);
		qglVertex2f (xCam, top);
		qglVertex2f (-xCam, top);
		qglEnd ();
	}

	//
	// now draw selected brushes
	//
	for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
	{
		if ( !(brush->mins[0] >= z.origin[0]
			|| brush->maxs[0] <= z.origin[0]
			|| brush->mins[1] >= z.origin[1]
			|| brush->maxs[1] <= z.origin[1]) )
		{
			if (Brush_Ray (org_top, dir_down, brush, &top))
			{
				top = org_top[2] - top;
				if (Brush_Ray (org_bottom, dir_up, brush, &bottom))
				{
					bottom = org_bottom[2] + bottom;

					q = Texture_ForName (brush->brush_faces->texdef.name);
					qglColor3f (q->color[0], q->color[1], q->color[2]);
					qglBegin (GL_QUADS);
					qglVertex2f (-xCam, bottom);
					qglVertex2f (xCam, bottom);
					qglVertex2f (xCam, top);
					qglVertex2f (-xCam, top);
					qglEnd ();
				}
			}
		}

	  qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]);
		qglBegin (GL_LINE_LOOP);
		qglVertex2f (-xCam, brush->mins[2]);
		qglVertex2f (xCam, brush->mins[2]);
		qglVertex2f (xCam, brush->maxs[2]);
		qglVertex2f (-xCam, brush->maxs[2]);
		qglEnd ();
	}


	ZDrawCameraIcon ();
	ZDrawZClip();

  qglFinish();
	QE_CheckOpenGLForErrors();

	if (z.timing)
	{
		end = Sys_DoubleTime ();
		Sys_Printf ("z: %i ms\n", (int)(1000*(end-start)));
	}
}
Beispiel #11
0
/*
==============
Z_DrawGrid
==============
*/
void Z_DrawGrid (void)
{
	float	zz, zb, ze;
	int		w, h;
	char	text[32];

	w = z.width/2 / z.scale;
	h = z.height/2 / z.scale;

	zb = z.origin[2] - h;
	if (zb < region_mins[2])
		zb = region_mins[2];
	zb = 64 * floor (zb/64);

	ze = z.origin[2] + h;
	if (ze > region_maxs[2])
		ze = region_maxs[2];
	ze = 64 * ceil (ze/64);

	// draw major blocks

	qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]);

	qglBegin (GL_LINES);

	qglVertex2f (0, zb);
	qglVertex2f (0, ze);

	for (zz=zb ; zz<ze ; zz+=64)
	{
		qglVertex2f (-w, zz);
		qglVertex2f (w, zz);
	}

	qglEnd ();

	// draw minor blocks
	if (g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*z.scale >= 4 &&
      g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR] != g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK])
	{
		qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]);

		qglBegin (GL_LINES);
		for (zz=zb ; zz<ze ; zz+=g_qeglobals.d_gridsize)
		{
			if ( ! ((int)zz & 63) )
				continue;
			qglVertex2f (-w, zz);
			qglVertex2f (w, zz);
		}
		qglEnd ();
	}

	// draw coordinate text if needed

	qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT]);

	for (zz=zb ; zz<ze ; zz+=64)
	{
		qglRasterPos2f (-w+1, zz);
		sprintf (text, "%i",(int)zz);
		qglCallLists (strlen(text), GL_UNSIGNED_BYTE, text);
	}
}
Beispiel #12
0
/*
==============
Z_DrawGrid
==============
*/
void Z_DrawGrid (void)
{
	float	zz, zb, ze;
	float	w, h;
	char	text[32];

	w = (z.width/2 / z.scale);
	h = (z.height/2 / z.scale);

	zb = z.origin[2] - h;
	if (zb < region_mins[2])
		zb = region_mins[2];
	zb = 64 * floor (zb/64);

	ze = z.origin[2] + h;
	if (ze > region_maxs[2])
		ze = region_maxs[2];
	ze = 64 * ceil (ze/64);

	// draw major blocks

	qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]);

	if ( g_qeglobals.d_showgrid )
	{
	  if (g_qeglobals.d_gridsize < 128)
	  {
	    qglBegin (GL_LINES);

	    qglVertex2f (0, zb);
	    qglVertex2f (0, ze);

	    for (zz=zb ; zz<ze ; zz+=64)
	    {
	      qglVertex2f (-w, zz);
	      qglVertex2f (w, zz);
	    }

	    qglEnd ();
	  }
	  else
	  {
	    qglBegin (GL_LINES);

	    qglVertex2f (0, zb);
	    qglVertex2f (0, ze);

	    for (zz=zb ; zz<ze ; zz+=64)
	    {
        // d_gridsize >= 128 .. it's an int for sure
	      if ( ((int)zz & ((int)g_qeglobals.d_gridsize-1)) != 0 )
      		continue;

	      qglVertex2f (-w, zz);
	      qglVertex2f (w, zz);
	    }

	    qglEnd ();
	  }
	}

	// draw minor blocks
	if (g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*z.scale >= 4 &&
      g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR] != g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK])
	{
		qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]);

		qglBegin (GL_LINES);
		for (zz=zb ; zz<ze ; zz+=g_qeglobals.d_gridsize)
		{
			if ( ! ((int)zz & 63) )
				continue;
			qglVertex2f (-w, zz);
			qglVertex2f (w, zz);
		}
		qglEnd ();
	}

	// draw coordinate text if needed

	if ( g_qeglobals.d_savedinfo.show_coordinates)
	{
		qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT]);

		int step = (int)(g_qeglobals.d_gridsize > 64 ? g_qeglobals.d_gridsize : 64);
		zb = z.origin[2] - h;
		if (zb < region_mins[2])
			zb = region_mins[2];
		zb = step * floor (zb/step);

		for (zz=zb ; zz<ze ; zz+=step)
		{
			qglRasterPos2f (-w+(1/z.scale), zz);
			sprintf (text, "%i",(int)zz);
			gtk_glwidget_print_string(text);
		}
	}
}
Beispiel #13
0
/*
==================
RB_FogPass
==================
*/
static void RB_FogPass( const drawSurf_t *drawSurfs,  const drawSurf_t *drawSurfs2 ) {
	const srfTriangles_t*frustumTris;
	drawSurf_t			ds;
	const idMaterial	*lightShader;
	const shaderStage_t	*stage;
	const float			*regs;

	// create a surface for the light frustom triangles, which are oriented drawn side out
	frustumTris = backEnd.vLight->frustumTris;

	// if we ran out of vertex cache memory, skip it
	if ( !frustumTris->ambientCache ) {
		return;
	}
	memset( &ds, 0, sizeof( ds ) );
	ds.space = &backEnd.viewDef->worldSpace;
	ds.geo = frustumTris;
	ds.scissorRect = backEnd.viewDef->scissor;

	// find the current color and density of the fog
	lightShader = backEnd.vLight->lightShader;
	regs = backEnd.vLight->shaderRegisters;
	// assume fog shaders have only a single stage
	stage = lightShader->GetStage(0);

	backEnd.lightColor[0] = regs[ stage->color.registers[0] ];
	backEnd.lightColor[1] = regs[ stage->color.registers[1] ];
	backEnd.lightColor[2] = regs[ stage->color.registers[2] ];
	backEnd.lightColor[3] = regs[ stage->color.registers[3] ];

	qglColor3fv( backEnd.lightColor );

	// calculate the falloff planes
	float	a;

	// if they left the default value on, set a fog distance of 500
	if ( backEnd.lightColor[3] <= 1.0 ) {
		a = -0.5f / DEFAULT_FOG_DISTANCE;
	} else {
		// otherwise, distance = alpha color
		a = -0.5f / backEnd.lightColor[3];
	}

	GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );

	// texture 0 is the falloff image
	GL_SelectTexture( 0 );
	globalImages->fogImage->Bind();
	//GL_Bind( tr.whiteImage );
	qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
	qglEnable( GL_TEXTURE_GEN_S );
	qglEnable( GL_TEXTURE_GEN_T );
	qglTexCoord2f( 0.5f, 0.5f );		// make sure Q is set

	fogPlanes[0][0] = a * backEnd.viewDef->worldSpace.modelViewMatrix[2];
	fogPlanes[0][1] = a * backEnd.viewDef->worldSpace.modelViewMatrix[6];
	fogPlanes[0][2] = a * backEnd.viewDef->worldSpace.modelViewMatrix[10];
	fogPlanes[0][3] = a * backEnd.viewDef->worldSpace.modelViewMatrix[14];

	fogPlanes[1][0] = a * backEnd.viewDef->worldSpace.modelViewMatrix[0];
	fogPlanes[1][1] = a * backEnd.viewDef->worldSpace.modelViewMatrix[4];
	fogPlanes[1][2] = a * backEnd.viewDef->worldSpace.modelViewMatrix[8];
	fogPlanes[1][3] = a * backEnd.viewDef->worldSpace.modelViewMatrix[12];


	// texture 1 is the entering plane fade correction
	GL_SelectTexture( 1 );
	globalImages->fogEnterImage->Bind();
	qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
	qglEnable( GL_TEXTURE_GEN_S );
	qglEnable( GL_TEXTURE_GEN_T );

	// T will get a texgen for the fade plane, which is always the "top" plane on unrotated lights
	fogPlanes[2][0] = 0.001f * backEnd.vLight->fogPlane[0];
	fogPlanes[2][1] = 0.001f * backEnd.vLight->fogPlane[1];
	fogPlanes[2][2] = 0.001f * backEnd.vLight->fogPlane[2];
	fogPlanes[2][3] = 0.001f * backEnd.vLight->fogPlane[3];

	// S is based on the view origin
	float s = backEnd.viewDef->renderView.vieworg * fogPlanes[2].Normal() + fogPlanes[2][3];

	fogPlanes[3][0] = 0;
	fogPlanes[3][1] = 0;
	fogPlanes[3][2] = 0;
	fogPlanes[3][3] = FOG_ENTER + s;

	qglTexCoord2f( FOG_ENTER + s, FOG_ENTER );


	// draw it
	RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_BasicFog );
	RB_RenderDrawSurfChainWithFunction( drawSurfs2, RB_T_BasicFog );

	// the light frustum bounding planes aren't in the depth buffer, so use depthfunc_less instead
	// of depthfunc_equal
	GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_LESS );
	GL_Cull( CT_BACK_SIDED );
	RB_RenderDrawSurfChainWithFunction( &ds, RB_T_BasicFog );
	GL_Cull( CT_FRONT_SIDED );

	GL_SelectTexture( 1 );
	qglDisable( GL_TEXTURE_GEN_S );
	qglDisable( GL_TEXTURE_GEN_T );
	globalImages->BindNull();

	GL_SelectTexture( 0 );
	qglDisable( GL_TEXTURE_GEN_S );
	qglDisable( GL_TEXTURE_GEN_T );
}
Beispiel #14
0
/*
==============
R_CalcBones

    The list of bones[] should only be built and modified from within here
==============
*/
void R_CalcBones(mdsHeader_t *header, const refEntity_t *refent, int *boneList, int numBones)
{
	int   i;
	int   *boneRefs;
	float torsoWeight;

	// if the entity has changed since the last time the bones were built, reset them
	if (memcmp(&lastBoneEntity, refent, sizeof(refEntity_t)))
	{
		// different, cached bones are not valid
		memset(validBones, 0, header->numBones);
		lastBoneEntity = *refent;

		// (SA) also reset these counter statics
		//----(SA)	print stats for the complete model (not per-surface)
		if (r_bonesDebug->integer == 4 && totalrt)
		{
			Ren_Print("Lod %.2f  verts %4d/%4d  tris %4d/%4d  (%.2f%%)\n",
			          lodScale,
			          totalrv,
			          totalv,
			          totalrt,
			          totalt,
			          ( float )(100.0 * totalrt) / (float) totalt);
		}
		totalrv = totalrt = totalv = totalt = 0;
	}

	memset(newBones, 0, header->numBones);

	if (refent->oldframe == refent->frame)
	{
		backlerp  = 0;
		frontlerp = 1;
	}
	else
	{
		backlerp  = refent->backlerp;
		frontlerp = 1.0f - backlerp;
	}

	if (refent->oldTorsoFrame == refent->torsoFrame)
	{
		torsoBacklerp  = 0;
		torsoFrontlerp = 1;
	}
	else
	{
		torsoBacklerp  = refent->torsoBacklerp;
		torsoFrontlerp = 1.0f - torsoBacklerp;
	}

	frameSize = (int) (sizeof(mdsFrame_t) + (header->numBones - 1) * sizeof(mdsBoneFrameCompressed_t));

	frame = ( mdsFrame_t * )((byte *)header + header->ofsFrames +
	                         refent->frame * frameSize);
	torsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames +
	                              refent->torsoFrame * frameSize);
	oldFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames +
	                            refent->oldframe * frameSize);
	oldTorsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames +
	                                 refent->oldTorsoFrame * frameSize);

	// lerp all the needed bones (torsoParent is always the first bone in the list)
	cBoneList      = frame->bones;
	cBoneListTorso = torsoFrame->bones;

	boneInfo = ( mdsBoneInfo_t * )((byte *)header + header->ofsBones);
	boneRefs = boneList;
	//
	Matrix3Transpose(refent->torsoAxis, torsoAxis);

#ifdef HIGH_PRECISION_BONES
	if (qtrue)
	{
#else
	if (!backlerp && !torsoBacklerp)
	{
#endif
		for (i = 0; i < numBones; i++, boneRefs++)
		{
			if (validBones[*boneRefs])
			{
				// this bone is still in the cache
				bones[*boneRefs] = rawBones[*boneRefs];
				continue;
			}

			// find our parent, and make sure it has been calculated
			if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent]))
			{
				R_CalcBone(header, refent, boneInfo[*boneRefs].parent);
			}

			R_CalcBone(header, refent, *boneRefs);
		}
	}
	else        // interpolated
	{
		cOldBoneList      = oldFrame->bones;
		cOldBoneListTorso = oldTorsoFrame->bones;

		for (i = 0; i < numBones; i++, boneRefs++)
		{
			if (validBones[*boneRefs])
			{
				// this bone is still in the cache
				bones[*boneRefs] = rawBones[*boneRefs];
				continue;
			}

			// find our parent, and make sure it has been calculated
			if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent]))
			{
				R_CalcBoneLerp(header, refent, boneInfo[*boneRefs].parent);
			}

			R_CalcBoneLerp(header, refent, *boneRefs);
		}
	}

	// adjust for torso rotations
	torsoWeight = 0;
	boneRefs    = boneList;
	for (i = 0; i < numBones; i++, boneRefs++)
	{
		thisBoneInfo = &boneInfo[*boneRefs];
		bonePtr      = &bones[*boneRefs];
		// add torso rotation
		if (thisBoneInfo->torsoWeight > 0)
		{
			if (!newBones[*boneRefs])
			{
				// just copy it back from the previous calc
				bones[*boneRefs] = oldBones[*boneRefs];
				continue;
			}

			if (!(thisBoneInfo->flags & BONEFLAG_TAG))
			{
				// 1st multiply with the bone->matrix
				// 2nd translation for rotation relative to bone around torso parent offset
				VectorSubtract(bonePtr->translation, torsoParentOffset, t);
				Matrix4FromAxisPlusTranslation(bonePtr->matrix, t, m1);
				// 3rd scaled rotation
				// 4th translate back to torso parent offset
				// use previously created matrix if available for the same weight
				if (torsoWeight != thisBoneInfo->torsoWeight)
				{
					Matrix4FromScaledAxisPlusTranslation(torsoAxis, thisBoneInfo->torsoWeight, torsoParentOffset, m2);
					torsoWeight = thisBoneInfo->torsoWeight;
				}
				// multiply matrices to create one matrix to do all calculations
				Matrix4MultiplyInto3x3AndTranslation(m2, m1, bonePtr->matrix, bonePtr->translation);

			}
			else        // tag's require special handling
			{   // rotate each of the axis by the torsoAngles
				LocalScaledMatrixTransformVector(bonePtr->matrix[0], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[0]);
				LocalScaledMatrixTransformVector(bonePtr->matrix[1], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[1]);
				LocalScaledMatrixTransformVector(bonePtr->matrix[2], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[2]);
				memcpy(bonePtr->matrix, tmpAxis, sizeof(tmpAxis));

				// rotate the translation around the torsoParent
				VectorSubtract(bonePtr->translation, torsoParentOffset, t);
				LocalScaledMatrixTransformVector(t, thisBoneInfo->torsoWeight, torsoAxis, bonePtr->translation);
				VectorAdd(bonePtr->translation, torsoParentOffset, bonePtr->translation);
			}
		}
	}

	// backup the final bones
	memcpy(oldBones, bones, sizeof(bones[0]) * header->numBones);
}

#ifdef DBG_PROFILE_BONES
#define DBG_SHOWTIME    Ren_Print("%i: %i, ", di++, (dt = ri.Milliseconds()) - ldt); ldt = dt;
#else
#define DBG_SHOWTIME    ;
#endif

/*
==============
RB_SurfaceAnim
==============
*/
void RB_SurfaceAnim(mdsSurface_t *surface)
{
	int         j, k;
	refEntity_t *refent;
	int         *boneList;
	mdsHeader_t *header;

#ifdef DBG_PROFILE_BONES
	int di = 0, dt, ldt;

	dt  = ri.Milliseconds();
	ldt = dt;
#endif

	refent   = &backEnd.currentEntity->e;
	boneList = ( int * )((byte *)surface + surface->ofsBoneReferences);
	header   = ( mdsHeader_t * )((byte *)surface + surface->ofsHeader);

	R_CalcBones(header, (const refEntity_t *)refent, boneList, surface->numBoneReferences);

	DBG_SHOWTIME

	// calculate LOD
	// TODO: lerp the radius and origin
	VectorAdd(refent->origin, frame->localOrigin, vec);
	lodRadius = frame->radius;
	lodScale  = RB_CalcMDSLod(refent, vec, lodRadius, header->lodBias, header->lodScale);


//DBG_SHOWTIME

	// modification to allow dead skeletal bodies to go below minlod (experiment)
	if (refent->reFlags & REFLAG_DEAD_LOD)
	{
		if (lodScale < 0.35)       // allow dead to lod down to 35% (even if below surf->minLod) (%35 is arbitrary and probably not good generally.  worked for the blackguard/infantry as a test though)
		{
			lodScale = 0.35;
		}
		render_count = ROUND_INT(surface->numVerts * lodScale);

	}
	else
	{
		render_count = ROUND_INT(surface->numVerts * lodScale);
		if (render_count < surface->minLod)
		{
			if (!(refent->reFlags & REFLAG_DEAD_LOD))
			{
				render_count = surface->minLod;
			}
		}
	}

	if (render_count > surface->numVerts)
	{
		render_count = surface->numVerts;
	}

	RB_CheckOverflow(render_count, surface->numTriangles);

//DBG_SHOWTIME

	// setup triangle list
	RB_CheckOverflow(surface->numVerts, surface->numTriangles * 3);

//DBG_SHOWTIME

	collapse_map = ( int * )(( byte * )surface + surface->ofsCollapseMap);
	triangles    = ( int * )((byte *)surface + surface->ofsTriangles);
	indexes      = surface->numTriangles * 3;
	baseIndex    = tess.numIndexes;
	baseVertex   = tess.numVertexes;
	oldIndexes   = baseIndex;

	tess.numVertexes += render_count;

	pIndexes = &tess.indexes[baseIndex];

//DBG_SHOWTIME

	if (render_count == surface->numVerts)
	{
		memcpy(pIndexes, triangles, sizeof(triangles[0]) * indexes);
		if (baseVertex)
		{
			glIndex_t *indexesEnd;
			for (indexesEnd = pIndexes + indexes ; pIndexes < indexesEnd ; pIndexes++)
			{
				*pIndexes += baseVertex;
			}
		}
		tess.numIndexes += indexes;
	}
	else
	{
		int *collapseEnd;

		pCollapse = collapse;
		for (j = 0; j < render_count; pCollapse++, j++)
		{
			*pCollapse = j;
		}

		pCollapseMap = &collapse_map[render_count];
		for (collapseEnd = collapse + surface->numVerts ; pCollapse < collapseEnd; pCollapse++, pCollapseMap++)
		{
			*pCollapse = collapse[*pCollapseMap];
		}

		for (j = 0 ; j < indexes ; j += 3)
		{
			p0 = collapse[*(triangles++)];
			p1 = collapse[*(triangles++)];
			p2 = collapse[*(triangles++)];

			// FIXME
			// note:  serious optimization opportunity here,
			//  by sorting the triangles the following "continue"
			//  could have been made into a "break" statement.
			if (p0 == p1 || p1 == p2 || p2 == p0)
			{
				continue;
			}

			*(pIndexes++)    = baseVertex + p0;
			*(pIndexes++)    = baseVertex + p1;
			*(pIndexes++)    = baseVertex + p2;
			tess.numIndexes += 3;
		}

		baseIndex = tess.numIndexes;
	}

//DBG_SHOWTIME

	// deform the vertexes by the lerped bones

	numVerts   = surface->numVerts;
	v          = ( mdsVertex_t * )((byte *)surface + surface->ofsVerts);
	tempVert   = ( float * )(tess.xyz + baseVertex);
	tempNormal = ( float * )(tess.normal + baseVertex);
	for (j = 0; j < render_count; j++, tempVert += 4, tempNormal += 4)
	{
		mdsWeight_t *w;

		VectorClear(tempVert);

		w = v->weights;
		for (k = 0 ; k < v->numWeights ; k++, w++)
		{
			bone = &bones[w->boneIndex];
			LocalAddScaledMatrixTransformVectorTranslate(w->offset, w->boneWeight, bone->matrix, bone->translation, tempVert);
		}

		LocalMatrixTransformVector(v->normal, bones[v->weights[0].boneIndex].matrix, tempNormal);

		tess.texCoords0[baseVertex + j].v[0] = v->texCoords[0];
		tess.texCoords0[baseVertex + j].v[1] = v->texCoords[1];

		v = (mdsVertex_t *)&v->weights[v->numWeights];
	}

	DBG_SHOWTIME

	if (r_bonesDebug->integer)
	{
		if (r_bonesDebug->integer < 3)
		{
			int i;

			// DEBUG: show the bones as a stick figure with axis at each bone
			boneRefs = ( int * )((byte *)surface + surface->ofsBoneReferences);
			for (i = 0; i < surface->numBoneReferences; i++, boneRefs++)
			{
				bonePtr = &bones[*boneRefs];

				GL_Bind(tr.whiteImage);
				qglLineWidth(1);
				qglBegin(GL_LINES);
				for (j = 0; j < 3; j++)
				{
					VectorClear(vec);
					vec[j] = 1;
					qglColor3fv(vec);
					qglVertex3fv(bonePtr->translation);
					VectorMA(bonePtr->translation, 5, bonePtr->matrix[j], vec);
					qglVertex3fv(vec);
				}
				qglEnd();

				// connect to our parent if it's valid
				if (validBones[boneInfo[*boneRefs].parent])
				{
					qglLineWidth(2);
					qglBegin(GL_LINES);
					qglColor3f(.6, .6, .6);
					qglVertex3fv(bonePtr->translation);
					qglVertex3fv(bones[boneInfo[*boneRefs].parent].translation);
					qglEnd();
				}

				qglLineWidth(1);
			}
		}

		if (r_bonesDebug->integer == 3 || r_bonesDebug->integer == 4)
		{
			int render_indexes = (tess.numIndexes - oldIndexes);

			// show mesh edges
			tempVert   = ( float * )(tess.xyz + baseVertex);
			tempNormal = ( float * )(tess.normal + baseVertex);

			GL_Bind(tr.whiteImage);
			qglLineWidth(1);
			qglBegin(GL_LINES);
			qglColor3f(.0, .0, .8);

			pIndexes = &tess.indexes[oldIndexes];
			for (j = 0; j < render_indexes / 3; j++, pIndexes += 3)
			{
				qglVertex3fv(tempVert + 4 * pIndexes[0]);
				qglVertex3fv(tempVert + 4 * pIndexes[1]);

				qglVertex3fv(tempVert + 4 * pIndexes[1]);
				qglVertex3fv(tempVert + 4 * pIndexes[2]);

				qglVertex3fv(tempVert + 4 * pIndexes[2]);
				qglVertex3fv(tempVert + 4 * pIndexes[0]);
			}

			qglEnd();

			// track debug stats
			if (r_bonesDebug->integer == 4)
			{
				totalrv += render_count;
				totalrt += render_indexes / 3;
				totalv  += surface->numVerts;
				totalt  += surface->numTriangles;
			}

			if (r_bonesDebug->integer == 3)
			{
				Ren_Print("Lod %.2f  verts %4d/%4d  tris %4d/%4d  (%.2f%%)\n", lodScale, render_count, surface->numVerts, render_indexes / 3, surface->numTriangles,
				          ( float )(100.0 * render_indexes / 3) / (float) surface->numTriangles);
			}
		}
	}

	if (r_bonesDebug->integer > 1)
	{
		// dont draw the actual surface
		tess.numIndexes  = oldIndexes;
		tess.numVertexes = baseVertex;
		return;
	}

#ifdef DBG_PROFILE_BONES
	Ren_Print("\n");
#endif
}
/*
==============
CZWnd::Z_Draw
==============
*/
void CZWnd::Z_Draw( void ) {
	brush_t		*brush;
	float		w, h;
	float		top, bottom;
	idVec3		org_top, org_bottom, dir_up, dir_down;
	int			xCam = z.width / 3 / z.scale;	// sikk - Keep brush widths proportional to window

	if ( !active_brushes.next ) {
		return; // not valid yet
	}

	// clear
	qglViewport( 0, 0, z.width, z.height );
	qglScissor( 0, 0, z.width, z.height );

	qglClearColor( g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0],
				   g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1],
				   g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],
				   0 );

	/*
	 * GL Bug £
	 * When not using hw acceleration, gl will fault if we clear the depth buffer bit
	 * on the first pass. The hack fix is to set the GL_DEPTH_BUFFER_BIT only after
	 * Z_Draw() has been called once. Yeah, right. £
	 * qglClear(glbitClear);
	 */
	qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	//
	// glbitClear |= GL_DEPTH_BUFFER_BIT;
	// qglClear(GL_DEPTH_BUFFER_BIT);
	//
	qglMatrixMode( GL_PROJECTION );
	qglLoadIdentity();

	w = z.width / 2 / z.scale;
	h = z.height / 2 / z.scale;
	qglOrtho( -w, w, z.origin[2] - h, z.origin[2] + h, -8, 8 );

	globalImages->BindNull();
	qglDisable( GL_DEPTH_TEST );
	qglDisable( GL_BLEND );

	// now draw the grid
	Z_DrawGrid();

	// draw stuff
	qglDisable( GL_CULL_FACE );

	qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

	globalImages->BindNull();

	// draw filled interiors and edges
	dir_up[0] = 0;
	dir_up[1] = 0;
	dir_up[2] = 1;
	dir_down[0] = 0;
	dir_down[1] = 0;
	dir_down[2] = -1;
	VectorCopy( z.origin, org_top );
	org_top[2] = 4096;
	VectorCopy( z.origin, org_bottom );
	org_bottom[2] = -4096;

	for ( brush = active_brushes.next; brush != &active_brushes; brush = brush->next ) {
		if ( brush->mins[0] >= z.origin[0] ||
			 brush->maxs[0] <= z.origin[0] ||
			 brush->mins[1] >= z.origin[1] ||
			 brush->maxs[1] <= z.origin[1] ) {
			continue;
		}

		if ( !Brush_Ray( org_top, dir_down, brush, &top ) ) {
			continue;
		}

		top = org_top[2] - top;
		if ( !Brush_Ray( org_bottom, dir_up, brush, &bottom ) ) {
			continue;
		}

		bottom = org_bottom[2] + bottom;

		//q = declManager->FindMaterial( brush->brush_faces->texdef.name );
		qglColor3f( brush->owner->eclass->color.x, brush->owner->eclass->color.y, brush->owner->eclass->color.z );
		qglBegin( GL_QUADS );
		qglVertex2f( -xCam, bottom );
		qglVertex2f( xCam, bottom );
		qglVertex2f( xCam, top );
		qglVertex2f( -xCam, top );
		qglEnd();

		qglColor3f( 1, 1, 1 );
		qglBegin( GL_LINE_LOOP );
		qglVertex2f( -xCam, bottom );
		qglVertex2f( xCam, bottom );
		qglVertex2f( xCam, top );
		qglVertex2f( -xCam, top );
		qglEnd();
	}

	// now draw selected brushes
	for ( brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next ) {
		if ( !( brush->mins[0] >= z.origin[0] ||
				brush->maxs[0] <= z.origin[0] ||
				brush->mins[1] >= z.origin[1] ||
				brush->maxs[1] <= z.origin[1] ) ) {
			if ( Brush_Ray( org_top, dir_down, brush, &top ) ) {
				top = org_top[2] - top;
				if ( Brush_Ray( org_bottom, dir_up, brush, &bottom ) ) {
					bottom = org_bottom[2] + bottom;

					//q = declManager->FindMaterial( brush->brush_faces->texdef.name );
					qglColor3f( brush->owner->eclass->color.x, brush->owner->eclass->color.y, brush->owner->eclass->color.z );
					qglBegin( GL_QUADS );
					qglVertex2f( -xCam, bottom );
					qglVertex2f( xCam, bottom );
					qglVertex2f( xCam, top );
					qglVertex2f( -xCam, top );
					qglEnd();
				}
			}
		}

		qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr() );
		qglBegin( GL_LINE_LOOP );
		qglVertex2f( -xCam, brush->mins[2] );
		qglVertex2f( xCam, brush->mins[2] );
		qglVertex2f( xCam, brush->maxs[2] );
		qglVertex2f( -xCam, brush->maxs[2] );
		qglEnd();
	}

	Z_DrawCameraIcon();
	Z_DrawZClip();

	qglFinish();
	QE_CheckOpenGLForErrors();
}
/*
==============
CZWnd::Z_DrawGrid
==============
*/
void CZWnd::Z_DrawGrid( void ) {
	float	zz, zb, ze;
	int		w, h;
	char	text[ 32 ];

	w = z.width / 2 / z.scale;
	h = z.height / 2 / z.scale;

// ---> sikk - Fixed Grid
//	int nSize = 1.0f / g_qeglobals.d_gridsize * 256;
	float fScale = 1.0f / g_qeglobals.d_gridsize * 8;
	int stepSize = g_qeglobals.d_gridsize * 8 * fScale / 2 / z.scale;
	if ( stepSize < g_qeglobals.d_gridsize * 8 ) {
		stepSize = g_qeglobals.d_gridsize * 8;
	} else {
		int i;
		for ( i = 1; i < stepSize; i <<= 1 ) {}
		stepSize = i;
	}
//	int stepSize = max( 64, g_qeglobals.d_gridsize );	// sikk - Larger Grid Sizes - Added
// <--- sikk - Fixed Grid

	zb = z.origin[2] - h;
	if ( zb < region_mins[ 2 ] ) {
		zb = region_mins[ 2 ];
	}
	zb = stepSize * floor( zb / stepSize );				// sikk - Larger Grid Sizes	- was 64

	ze = z.origin[2] + h;
	if ( ze > region_maxs[ 2 ] ) {
		ze = region_maxs[ 2 ];
	}
	ze = stepSize * ceil( ze / stepSize );				// sikk - Larger Grid Sizes	- was 64

	// draw minor blocks
	if ( //z.scale > fScale &&	// sikk - Fixed grid
		 g_qeglobals.d_showgrid &&
		 //g_qeglobals.d_gridsize * z.scale >= 4 &&
		!g_qeglobals.d_savedinfo.colors[ COLOR_GRIDMINOR ].Compare( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDBACK ] ) ) {

		qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDMINOR ].ToFloatPtr() );
		qglBegin( GL_LINES );
		for ( zz = zb; zz < ze; zz += stepSize / 8 ) {
// ---> sikk - Fixed grid
			//if ( !( (int)zz & 63 ) ) {
			//	continue;
			//}
//<--- sikk - Fixed grid
			qglVertex2f( -w, zz );
			qglVertex2f( w, zz );
		}
		qglEnd();
	}

	// draw major blocks
	qglBegin( GL_LINES );
	qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDMAJOR ].ToFloatPtr() );
	qglVertex2f( 0, zb );
	qglVertex2f( 0, ze );
	for ( zz = zb; zz < ze; zz += stepSize ) {			// sikk - Larger Grid Sizes	- was 64
		if ( zz == 0 ) { 
			qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDTEXT ].ToFloatPtr() );
		} else {
			qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDMAJOR ].ToFloatPtr() );
		}
		qglVertex2f( -w, zz );
		qglVertex2f( w, zz );
	}
	qglEnd();

	// draw coordinate text if needed
	qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDTEXT ].ToFloatPtr() );

	for ( zz = zb; zz < ze; zz += stepSize ) {
		qglRasterPos2f( -w + 1, zz );
		sprintf( text, "%i", (int)zz );
		qglCallLists( strlen( text ), GL_UNSIGNED_BYTE, text );
	}
}