/*
=================
R_DrawAliasModel

=================
*/
void R_DrawAliasModel (entity_t *e)
{
	int			i, j;
	int			lnum;
	vec3_t		dist;
	float		add;
	model_t		*clmodel;
	vec3_t		mins, maxs;
	aliashdr_t	*paliashdr;
	trivertx_t	*verts, *v;
	int			index;
	float		s, t, an;
	int			anim;

	clmodel = currententity->model;

	VectorAdd (currententity->origin, clmodel->mins, mins);
	VectorAdd (currententity->origin, clmodel->maxs, maxs);

	if (R_CullBox (mins, maxs))
		return;


	VectorCopy (currententity->origin, r_entorigin);
	VectorSubtract (r_origin, r_entorigin, modelorg);

	//
	// get lighting information
	//

	ambientlight = shadelight = R_LightPoint (currententity->origin);

	// allways give the gun some light
	if (e == &cl.viewent && ambientlight < 24)
		ambientlight = shadelight = 24;

	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
	{
		if (cl_dlights[lnum].die >= cl.time)
		{
			VectorSubtract (currententity->origin,
							cl_dlights[lnum].origin,
							dist);
			add = cl_dlights[lnum].radius - Length(dist);

			if (add > 0) {
				ambientlight += add;
				//ZOID models should be affected by dlights as well
				shadelight += add;
			}
		}
	}

	// clamp lighting so it doesn't overbright as much
	if (ambientlight > 128)
		ambientlight = 128;
	if (ambientlight + shadelight > 192)
		shadelight = 192 - ambientlight;

	// ZOID: never allow players to go totally black
	i = currententity - cl_entities;
	if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
		if (ambientlight < 8)
			ambientlight = shadelight = 8;

	// HACK HACK HACK -- no fullbright colors, so make torches full light
	if (!strcmp (clmodel->name, "progs/flame2.mdl")
		|| !strcmp (clmodel->name, "progs/flame.mdl") )
		ambientlight = shadelight = 256;

	shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
	shadelight = shadelight / 200.0;

	an = e->angles[1]/180*M_PI;
	shadevector[0] = cos(-an);
	shadevector[1] = sin(-an);
	shadevector[2] = 1;
	VectorNormalize (shadevector);

	//
	// locate the proper data
	//
	paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);

	c_alias_polys += paliashdr->numtris;

	//
	// draw all the triangles
	//

	GL_DisableMultitexture();

    glPushMatrix ();
	R_RotateForEntity (e);

	if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) {
		glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8));
// double size of eyes, since they are really hard to see in gl
		glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2);
	} else {
		glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
		glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
	}

	anim = (int)(cl.time*10) & 3;
    GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]);

	// we can't dynamically colormap textures, so they are cached
	// seperately for the players.  Heads are just uncolored.
	if (currententity->colormap != vid.colormap && !gl_nocolors.value)
	{
		i = currententity - cl_entities;
		if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
		    GL_Bind(playertextures - 1 + i);
	}

	if (gl_smoothmodels.value)
		glShadeModel (GL_SMOOTH);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

	if (gl_affinemodels.value)
		glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);

	R_SetupAliasFrame (currententity->frame, paliashdr);

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

	glShadeModel (GL_FLAT);
	if (gl_affinemodels.value)
		glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	glPopMatrix ();

	if (r_shadows.value)
	{
		glPushMatrix ();
		R_RotateForEntity (e);
		glDisable (GL_TEXTURE_2D);
		glEnable (GL_BLEND);
		glColor4f (0,0,0,0.5);
		GL_DrawAliasShadow (paliashdr, lastposenum);
		glEnable (GL_TEXTURE_2D);
		glDisable (GL_BLEND);
		glColor4f (1,1,1,1);
		glPopMatrix ();
	}

}
Exemple #2
0
/*
=================
R_DrawSpriteModel -- johnfitz -- rewritten: now supports all orientations
=================
*/
void R_DrawSpriteModel (entity_t *e)
{
	vec3_t			point, v_forward, v_right, v_up;
	msprite_t		*psprite;
	mspriteframe_t	*frame;
	float			*s_up, *s_right;
	float			angle, sr, cr;

	//TODO: frustum cull it?

	frame = R_GetSpriteFrame (e);
	psprite = (msprite_t *) currententity->model->cache.data;

	switch(psprite->type)
	{
	case SPR_VP_PARALLEL_UPRIGHT: //faces view plane, up is towards the heavens
		v_up[0] = 0;
		v_up[1] = 0;
		v_up[2] = 1;
		s_up = v_up;
		s_right = vright;
		break;
	case SPR_FACING_UPRIGHT: //faces camera origin, up is towards the heavens
		VectorSubtract(currententity->origin, r_origin, v_forward);
		v_forward[2] = 0;
		VectorNormalizeFast(v_forward);
		v_right[0] = v_forward[1];
		v_right[1] = -v_forward[0];
		v_right[2] = 0;
		v_up[0] = 0;
		v_up[1] = 0;
		v_up[2] = 1;
		s_up = v_up;
		s_right = v_right;
		break;
	case SPR_VP_PARALLEL: //faces view plane, up is towards the top of the screen
		s_up = vup;
		s_right = vright;
		break;
	case SPR_ORIENTED: //pitch yaw roll are independent of camera
		AngleVectors (currententity->angles, v_forward, v_right, v_up);
		s_up = v_up;
		s_right = v_right;
		break;
	case SPR_VP_PARALLEL_ORIENTED: //faces view plane, but obeys roll value
		angle = currententity->angles[ROLL] * M_PI_DIV_180;
		sr = sin(angle);
		cr = cos(angle);
		v_right[0] = vright[0] * cr + vup[0] * sr;
		v_right[1] = vright[1] * cr + vup[1] * sr;
		v_right[2] = vright[2] * cr + vup[2] * sr;
		v_up[0] = vright[0] * -sr + vup[0] * cr;
		v_up[1] = vright[1] * -sr + vup[1] * cr;
		v_up[2] = vright[2] * -sr + vup[2] * cr;
		s_up = v_up;
		s_right = v_right;
		break;
	default:
		return;
	}

	//johnfitz: offset decals
	if (psprite->type == SPR_ORIENTED)
		GL_PolygonOffset (OFFSET_DECAL);

	glColor3f (1,1,1);

	GL_DisableMultitexture();

	GL_Bind(frame->gltexture);

	glEnable (GL_ALPHA_TEST);
	glBegin (GL_TRIANGLE_FAN); //was GL_QUADS, but changed to support r_showtris

	glTexCoord2f (0, frame->tmax);
	VectorMA (e->origin, frame->down, s_up, point);
	VectorMA (point, frame->left, s_right, point);
	glVertex3fv (point);

	glTexCoord2f (0, 0);
	VectorMA (e->origin, frame->up, s_up, point);
	VectorMA (point, frame->left, s_right, point);
	glVertex3fv (point);

	glTexCoord2f (frame->smax, 0);
	VectorMA (e->origin, frame->up, s_up, point);
	VectorMA (point, frame->right, s_right, point);
	glVertex3fv (point);

	glTexCoord2f (frame->smax, frame->tmax);
	VectorMA (e->origin, frame->down, s_up, point);
	VectorMA (point, frame->right, s_right, point);
	glVertex3fv (point);

	glEnd ();
	glDisable (GL_ALPHA_TEST);

	//johnfitz: offset decals
	if (psprite->type == SPR_ORIENTED)
		GL_PolygonOffset (OFFSET_NONE);
}
Exemple #3
0
//void GL_DrawQ3AliasFrame (md3header_mem_t *header, int lastpose, int pose, float blend, qboolean mtex)
void GL_DrawQ3AliasFrame (const md3header_t *header, const entity_t *e, int pose, float blend, qboolean mtex)
/*******JDH*******/
{
   int               i, j, k, index;
   int               frame;
   int               lastframe;
   int               vertframeoffset;
   int               lastvertframeoffset;
   float            /*alpha, */iblend;
   md3surface_t   *surf;
   md3st_t         *tc, *xycoord;
   md3tri_t      *tris;
   md3vert_t      *verts, *vertslast, *currvert, *lastvert;
   md3shader_t		*shaders;
//  vec3_t			currnorm, lastnorm;

	r_modelalpha = GL_GetAliasAlpha (e);

	if (r_modelalpha < 1.0)
		glEnable (GL_BLEND);

	blend = bound(0, blend, 1);
	iblend = 1.0 - blend;

	surf = (md3surface_t *)((byte *)header + header->surface_offs);

	for (i = 0; i < header->num_surfaces; i++)
	{
		if (surf->num_surf_frames == 0)
		{
			surf = (md3surface_t *)((byte *)surf + surf->end_offs);
			continue;   //shouldn't ever do this, each surface should have at least one frame
		}

		//get pointer to shaders (ie. textures)
		shaders = (md3shader_t *)((byte *)surf + surf->shader_offs);
		index = shaders[e->skinnum % surf->num_surf_shaders].index;

		GL_Bind (index);

		frame = pose % surf->num_surf_frames;   //cap the frame inside the list of frames in the model
		vertframeoffset = frame * surf->num_surf_verts * sizeof(md3vert_t);
		/*******JDH*******/
		//lastframe = lastpose%surf->num_surf_frames;
		lastframe = e->lastpose % surf->num_surf_frames;
		/*******JDH*******/
		lastvertframeoffset = lastframe*surf->num_surf_verts * sizeof(md3vert_t);

		tc = (md3st_t *)((byte *)surf + surf->tc_offs);
		tris = (md3tri_t *)((byte *)surf + surf->tris_offs);
		verts = (md3vert_t *)((byte *)surf + surf->vert_offs + vertframeoffset);
		vertslast = (md3vert_t *)((byte *)surf + surf->vert_offs + lastvertframeoffset);

		/*if (blend >=1)
		{
		//glNormalPointer(GL_FLOAT, 6 * sizeof(float), (float *)verts->normal);
		//glEnableClientState(GL_NORMAL_ARRAY);

		glVertexPointer(3, GL_SHORT, sizeof( md3vert_t ), verts->vec);
		glEnableClientState(GL_VERTEX_ARRAY);

		glTexCoordPointer(2, GL_FLOAT, 0, (float *)tc);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);

		glDrawElements(GL_TRIANGLES, surf->num_surf_tris*3, GL_UNSIGNED_INT, tris);

		//glDisableClientState(GL_NORMAL_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		}
		else*/
		{
		//interpolated

			glBegin(GL_TRIANGLES);
			//for each triangle
			for (j = 0; j < surf->num_surf_tris; j++)
			{
				//draw the poly
				for (k=0; k < 3; k++)
				{
					index = tris[j].tri[k];
					xycoord = &tc[index];

					if (mtex)
					{
						qglMultiTexCoord2f (GL_TEXTURE0_ARB, xycoord->s, xycoord->t);
						qglMultiTexCoord2f (GL_TEXTURE1_ARB, xycoord->s, xycoord->t);
					}
					else
					{
						glTexCoord2f (xycoord->s, xycoord->t);
					}

					currvert = &verts[index];
					lastvert = &vertslast[index];

					GL_SetupMD3Light (currvert, lastvert, r_modelalpha);

					glVertex3f ((currvert->vec[0] * blend + lastvert->vec[0] * iblend) / 64.0,
								(currvert->vec[1] * blend + lastvert->vec[1] * iblend) / 64.0,
								(currvert->vec[2] * blend + lastvert->vec[2] * iblend) / 64.0);

					/*MD3_ConvertNormal (currvert->normal, currnorm);
					MD3_ConvertNormal (lastvert->normal, lastnorm);

					glNormal3f (currnorm[0] * blend + lastnorm[0] * iblend,
								currnorm[1] * blend + lastnorm[1] * iblend,
								currnorm[2] * blend + lastnorm[2] * iblend);*/
				}
			}

			glEnd();
		}

		surf = (md3surface_t *)((byte *)surf + surf->end_offs);
	}

	if (r_modelalpha < 1.0)
		glDisable (GL_BLEND);

	glColor3f (1, 1, 1);
}
Exemple #4
0
static void ProjectDlightTexture_scalar( void ) {
	int		i, l;
	vec3_t	origin;
	float	*texCoords;
	byte	*colors;
	int		*intColors;
	byte	clipBits[SHADER_MAX_VERTEXES];
	float	texCoordsArray[SHADER_MAX_VERTEXES][2];
	byte	colorArray[SHADER_MAX_VERTEXES][4];
	glIndex_t	hitIndexes[SHADER_MAX_INDEXES];
	int		numIndexes;
	float	scale;
	float	radius;
	float	radiusInverseCubed;
	float	intensity, remainder;
	vec3_t	floatColor;
	float	modulate = 0.0f;
	qboolean vertexLight;

	if ( !backEnd.refdef.num_dlights ) {
		return;
	}

	for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
		dlight_t	*dl;

		if ( !( tess.dlightBits & ( 1 << l ) ) ) {
			continue;	// this surface definately doesn't have any of this light
		}

		// clear colors
		Com_Memset( colorArray, 0, sizeof( colorArray ) );

		texCoords = texCoordsArray[0];
		colors = colorArray[0];

		dl = &backEnd.refdef.dlights[l];
		VectorCopy( dl->transformed, origin );
		radius = dl->radius;
		scale = 1.0f / radius;
		radiusInverseCubed = dl->radiusInverseCubed;
		intensity = dl->intensity;

		vertexLight = ( ( dl->flags & REF_DIRECTED_DLIGHT ) || ( dl->flags & REF_VERTEX_DLIGHT ) );

		// directional lights have max intensity and washout remainder intensity
		if ( dl->flags & REF_DIRECTED_DLIGHT ) {
			remainder = intensity * 0.125;
		} else {
			remainder = 0.0f;
		}

		if(r_greyscale->integer)
		{
			float luminance;

			luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f;
			floatColor[0] = floatColor[1] = floatColor[2] = luminance;
		}
		else if(r_greyscale->value)
		{
			float luminance;
			
			luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f;
			floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value);
			floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value);
			floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value);
		}
		else
		{
			floatColor[0] = dl->color[0] * 255.0f;
			floatColor[1] = dl->color[1] * 255.0f;
			floatColor[2] = dl->color[2] * 255.0f;
		}

		for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
			int		clip = 0;
			vec3_t	dist;
			
			VectorSubtract( origin, tess.xyz[i], dist );

			backEnd.pc.c_dlightVertexes++;

			// directional dlight, origin is a directional normal
			if ( dl->flags & REF_DIRECTED_DLIGHT ) {
				// twosided surfaces use absolute value of the calculated lighting
				modulate = intensity * DotProduct( dl->origin, tess.normal[ i ] );
				if ( tess.shader->cullType == CT_TWO_SIDED ) {
					modulate = fabs( modulate );
				}
				modulate += remainder;
			}
			// spherical vertex lit dlight
			else if ( dl->flags & REF_VERTEX_DLIGHT )
			{
				vec3_t	dir;

				dir[ 0 ] = radius - fabs( dist[ 0 ] );
				if ( dir[ 0 ] <= 0.0f ) {
					continue;
				}
				dir[ 1 ] = radius - fabs( dist[ 1 ] );
				if ( dir[ 1 ] <= 0.0f ) {
					continue;
				}
				dir[ 2 ] = radius - fabs( dist[ 2 ] );
				if ( dir[ 2 ] <= 0.0f ) {
					continue;
				}

				modulate = intensity * dir[ 0 ] * dir[ 1 ] * dir[ 2 ] * radiusInverseCubed;
			}
			// vertical cylinder dlight
			else
			{
				texCoords[0] = 0.5f + dist[0] * scale;
				texCoords[1] = 0.5f + dist[1] * scale;

				if( !r_dlightBacks->integer &&
						// dist . tess.normal[i]
						( dist[0] * tess.normal[i][0] +
						dist[1] * tess.normal[i][1] +
						dist[2] * tess.normal[i][2] ) < 0.0f ) {
					clip = 63;
				} else {
					if ( texCoords[0] < 0.0f ) {
						clip |= 1;
					} else if ( texCoords[0] > 1.0f ) {
						clip |= 2;
					}
					if ( texCoords[1] < 0.0f ) {
						clip |= 4;
					} else if ( texCoords[1] > 1.0f ) {
						clip |= 8;
					}
					texCoords[0] = texCoords[0];
					texCoords[1] = texCoords[1];

					// modulate the strength based on the height and color
					if ( dist[2] > radius ) {
						clip |= 16;
						modulate = 0.0f;
					} else if ( dist[2] < -radius ) {
						clip |= 32;
						modulate = 0.0f;
					} else {
						dist[2] = Q_fabs(dist[2]);
						if ( dist[2] < radius * 0.5f ) {
							modulate = intensity;
						} else {
							modulate = intensity * 2.0f * (radius - dist[2]) * scale;
						}
					}
				}
			}

			// optimizations
			if ( vertexLight && modulate < ( 1.0f / 128.0f ) ) {
				continue;
			} else if ( modulate > 1.0f ) {
				modulate = 1.0f;
			}

			clipBits[i] = clip;
			colors[0] = Com_Clamp( 0, 255, ri.ftol(floatColor[0] * modulate) );
			colors[1] = Com_Clamp( 0, 255, ri.ftol(floatColor[1] * modulate) );
			colors[2] = Com_Clamp( 0, 255, ri.ftol(floatColor[2] * modulate) );
			colors[3] = 255;
		}

		// build a list of triangles that need light
		intColors = (int*) colorArray;
		numIndexes = 0;
		for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
			int		a, b, c;

			a = tess.indexes[i];
			b = tess.indexes[i+1];
			c = tess.indexes[i+2];
			if ( vertexLight ) {
				if ( !( intColors[ a ] | intColors[ b ] | intColors[ c ] ) ) {
					continue;
				}
			} else {
				if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
					continue;	// not lighted
				}
			}
			hitIndexes[numIndexes] = a;
			hitIndexes[numIndexes+1] = b;
			hitIndexes[numIndexes+2] = c;
			numIndexes += 3;
		}

		if ( !numIndexes ) {
			continue;
		}

		if ( !vertexLight ) {
			qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
			qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
		} else {
			qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
		}

		qglEnableClientState( GL_COLOR_ARRAY );
		qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );

		if ( dl->dlshader ) {
			shader_t *dls = dl->dlshader;

			for ( i = 0; i < dls->numUnfoggedPasses; i++ ) {
				shaderStage_t *stage = dls->stages[i];
				R_BindAnimatedImage( &dls->stages[i]->bundle[0] );
				GL_State( stage->stateBits | GLS_DEPTHFUNC_EQUAL );
				R_DrawElements( numIndexes, hitIndexes );
				backEnd.pc.c_totalIndexes += numIndexes;
				backEnd.pc.c_dlightIndexes += numIndexes;
			}
		} else {
			R_FogOff();
			if ( !vertexLight ) {
				GL_Bind( tr.dlightImage );
			} else {
				GL_Bind( tr.whiteImage );
			}
			// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
			// where they aren't rendered
			if ( dl->flags & REF_ADDITIVE_DLIGHT ) {
				GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
			}
			else {
				GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
			}
			R_DrawElements( numIndexes, hitIndexes );
			backEnd.pc.c_totalIndexes += numIndexes;
			backEnd.pc.c_dlightIndexes += numIndexes;
			RB_FogOn();
		}
	}
}
void StencilShadow::RenderShadow()
{
#ifndef DISABLE_STENCILSHADOW
	DWORD lighting, fog, srcblend, destblend, alphablend, zwrite, zfunc, cullmode;

	GL_State(GLS_DEFAULT);

	glw_state->device->GetRenderState( D3DRS_LIGHTING, &lighting );
	glw_state->device->GetRenderState( D3DRS_FOGENABLE, &fog );
	glw_state->device->GetRenderState( D3DRS_SRCBLEND, &srcblend );
	glw_state->device->GetRenderState( D3DRS_DESTBLEND, &destblend );
	glw_state->device->GetRenderState( D3DRS_ALPHABLENDENABLE, &alphablend );
	glw_state->device->GetRenderState( D3DRS_ZWRITEENABLE, &zwrite );
	glw_state->device->GetRenderState( D3DRS_ZFUNC, &zfunc );
	glw_state->device->GetRenderState( D3DRS_CULLMODE, &cullmode );

	pVerts = NULL;
	pExtrusions = NULL;

	GL_Bind( tr.whiteImage );

	glw_state->device->SetRenderState( D3DRS_LIGHTING, FALSE );
	glw_state->device->SetRenderState( D3DRS_FOGENABLE, FALSE );

	glw_state->device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
	glw_state->device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );

    // Disable z-buffer writes (note: z-testing still occurs), and enable the
    // stencil-buffer
    glw_state->device->SetRenderState( D3DRS_ZWRITEENABLE,  FALSE );
    glw_state->device->SetRenderState( D3DRS_STENCILENABLE, TRUE );

    // Don't bother with interpolating color
    glw_state->device->SetRenderState( D3DRS_SHADEMODE,     D3DSHADE_FLAT );

	glw_state->device->SetRenderState( D3DRS_ZFUNC,			D3DCMP_LESS );

    // Set up stencil compare function, reference value, and masks.
    // Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.
    // Note: since we set up the stencil-test to always pass, the STENCILFAIL
    // renderstate is really not needed.
    glw_state->device->SetRenderState( D3DRS_STENCILFUNC,   D3DCMP_ALWAYS );
#ifdef _STENCIL_REVERSE
	glw_state->device->SetRenderState( D3DRS_STENCILZFAIL,  D3DSTENCILOP_INCR );
    glw_state->device->SetRenderState( D3DRS_STENCILFAIL,   D3DSTENCILOP_KEEP );
	glw_state->device->SetRenderState( D3DRS_STENCILPASS,   D3DSTENCILOP_KEEP );
#else
	glw_state->device->SetRenderState( D3DRS_STENCILZFAIL,  D3DSTENCILOP_KEEP );
    glw_state->device->SetRenderState( D3DRS_STENCILFAIL,   D3DSTENCILOP_KEEP );
	glw_state->device->SetRenderState( D3DRS_STENCILPASS,   D3DSTENCILOP_INCR );	
#endif

    // If ztest passes, inc/decrement stencil buffer value
    glw_state->device->SetRenderState( D3DRS_STENCILREF,       0x1 );
    glw_state->device->SetRenderState( D3DRS_STENCILMASK,      0x7f ); //0xffffffff );
    glw_state->device->SetRenderState( D3DRS_STENCILWRITEMASK, 0x7f ); //0xffffffff );

    // Make sure that no pixels get drawn to the frame buffer
    glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
    glw_state->device->SetRenderState( D3DRS_COLORWRITEENABLE, 0 );

	glw_state->device->SetTexture(0, NULL);
	glw_state->device->SetTexture(1, NULL);

	// Compute the matrix set
    XGMATRIX matComposite, matProjectionViewport, matWorld;
	glw_state->device->GetProjectionViewportMatrix( &matProjectionViewport );

	XGMatrixMultiply( &matComposite, (XGMATRIX*)glw_state->matrixStack[glwstate_t::MatrixMode_Model]->GetTop(), &matProjectionViewport );

	// Transpose and set the composite matrix.
	XGMatrixTranspose( &matComposite, &matComposite );
	glw_state->device->SetVertexShaderConstant( CV_WORLDVIEWPROJ_0, &matComposite, 4 );

	// Set viewport offsets.
	float fViewportOffsets[4] = { 0.53125f, 0.53125f, 0.0f, 0.0f };
	glw_state->device->SetVertexShaderConstant( CV_VIEWPORT_OFFSETS, &fViewportOffsets, 1 );

	glw_state->device->SetVertexShader(m_dwVertexShaderShadow);

#ifdef _STENCIL_REVERSE
	qglCullFace( GL_FRONT );
#else
	qglCullFace( GL_BACK );
#endif

	BuildEdges();

	// Draw front-side of shadow volume in stencil/z only
	if(m_nIndexes)
        renderObject_Shadow( D3DPT_QUADLIST, m_nIndexes, m_shadowIndexes );
#ifdef _STENCIL_REVERSE
	if(m_nIndexesCap)
        renderObject_Shadow( D3DPT_TRIANGLELIST, m_nIndexesCap, m_shadowIndexesCap );
#endif

	// Now reverse cull order so back sides of shadow volume are written.
#ifdef _STENCIL_REVERSE
	qglCullFace( GL_BACK );
#else
    qglCullFace( GL_FRONT );
#endif

    // Decrement stencil buffer value
#ifdef _STENCIL_REVERSE
	glw_state->device->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_DECR );
#else
	glw_state->device->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECR );
#endif

	// Draw back-side of shadow volume in stencil/z only
	if(m_nIndexes)
        renderObject_Shadow( D3DPT_QUADLIST, m_nIndexes, m_shadowIndexes );
#ifdef _STENCIL_REVERSE
	if(m_nIndexesCap)
        renderObject_Shadow( D3DPT_TRIANGLELIST, m_nIndexesCap, m_shadowIndexesCap );
#endif

	// Restore render states
	glw_state->device->SetRenderState( D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALL );

    glw_state->device->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
	glw_state->device->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
	glw_state->device->SetRenderState( D3DRS_LIGHTING, lighting );
	glw_state->device->SetRenderState( D3DRS_FOGENABLE, fog );
	glw_state->device->SetRenderState( D3DRS_SRCBLEND, srcblend );
	glw_state->device->SetRenderState( D3DRS_DESTBLEND, destblend );
	glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, alphablend );
	glw_state->device->SetRenderState( D3DRS_ZWRITEENABLE, zwrite );
	glw_state->device->SetRenderState( D3DRS_ZFUNC, zfunc );
	glw_state->device->SetRenderState( D3DRS_CULLMODE, cullmode );
#endif
}
/*
=================
R_Bloom_GeneratexCross - alternative bluring method
=================
*/
void R_Bloom_GeneratexCross( void )
{
    int			i;
    static int		BLOOM_BLUR_RADIUS = 8;
    //static float	BLOOM_BLUR_INTENSITY = 2.5f;
    float	BLOOM_BLUR_INTENSITY;
    static float intensity;
    static float range;

    //set up sample size workspace
    qglViewport( 0, 0, sample_width, sample_height );
    qglMatrixMode( GL_PROJECTION );
    qglLoadIdentity ();
    qglOrtho(0, sample_width, sample_height, 0, -10, 100);
    qglMatrixMode( GL_MODELVIEW );
    qglLoadIdentity ();

    //copy small scene into r_bloomeffecttexture
    GL_Bind(0, r_bloomeffecttexture);
    qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);

    //start modifying the small scene corner
    qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
    GL_Enable(GL_BLEND);

    //darkening passes
    if( r_bloom_darken->value )
    {
        GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
        GL_TexEnv(GL_MODULATE);

        for(i=0; i<r_bloom_darken->value ; i++) {
            R_Bloom_SamplePass( 0, 0 );
        }
        qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);
    }

    //bluring passes
    if( BLOOM_BLUR_RADIUS ) {

        GL_BlendFunc(GL_ONE, GL_ONE);

        range = (float)BLOOM_BLUR_RADIUS;

        BLOOM_BLUR_INTENSITY = r_bloom_intensity->value;
        //diagonal-cross draw 4 passes to add initial smooth
        qglColor4f( 0.5f, 0.5f, 0.5f, 1.0);
        R_Bloom_SamplePass( 1, 1 );
        R_Bloom_SamplePass( -1, 1 );
        R_Bloom_SamplePass( -1, -1 );
        R_Bloom_SamplePass( 1, -1 );
        qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);

        for(i=-(BLOOM_BLUR_RADIUS+1); i<BLOOM_BLUR_RADIUS; i++) {
            intensity = BLOOM_BLUR_INTENSITY/(range*2+1)*(1 - fabs(i*i)/(float)(range*range));
            if( intensity < 0.05f ) continue;
            qglColor4f( intensity, intensity, intensity, 1.0f);
            R_Bloom_SamplePass( i, 0 );
            //R_Bloom_SamplePass( -i, 0 );
        }

        qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);

        //for(i=0;i<BLOOM_BLUR_RADIUS;i++) {
        for(i=-(BLOOM_BLUR_RADIUS+1); i<BLOOM_BLUR_RADIUS; i++) {
            intensity = BLOOM_BLUR_INTENSITY/(range*2+1)*(1 - fabs(i*i)/(float)(range*range));
            if( intensity < 0.05f ) continue;
            qglColor4f( intensity, intensity, intensity, 1.0f);
            R_Bloom_SamplePass( 0, i );
            //R_Bloom_SamplePass( 0, -i );
        }

        qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);
    }

    //restore full screen workspace
    qglViewport( 0, 0, glState.width, glState.height );
    qglMatrixMode( GL_PROJECTION );
    qglLoadIdentity ();
    qglOrtho(0, glState.width, glState.height, 0, -10, 100);
    qglMatrixMode( GL_MODELVIEW );
    qglLoadIdentity ();
}
void R_BloomBlend ( refdef_t *fd )
{
    if( !(fd->rdflags & RDF_BLOOM) || !r_bloom->value || r_showtris->value )
        return;

    if( !BLOOM_SIZE )
        R_Bloom_InitTextures();

    if( screen_texture_width < BLOOM_SIZE ||
            screen_texture_height < BLOOM_SIZE )
        return;

    //set up full screen workspace
    qglViewport ( 0, 0, vid.width, vid.height );
    GL_TexEnv (GL_REPLACE); // Knightmare added
    GL_Disable (GL_DEPTH_TEST);
    qglMatrixMode (GL_PROJECTION);
    qglLoadIdentity ();
    qglOrtho(0, vid.width, vid.height, 0, -10, 100);
    qglMatrixMode (GL_MODELVIEW);
    qglLoadIdentity ();
    GL_Disable (GL_CULL_FACE);

    GL_Disable (GL_BLEND);
    qglEnable (GL_TEXTURE_2D);

    qglColor4f (1, 1, 1, 1);

    //set up current sizes
    curView_x = fd->x;
    curView_y = fd->y;
    curView_width = fd->width;
    curView_height = fd->height;
    screenText_tcw = ((float)fd->width / (float)screen_texture_width);
    screenText_tch = ((float)fd->height / (float)screen_texture_height);
    if( fd->height > fd->width ) {
        sampleText_tcw = ((float)fd->width / (float)fd->height);
        sampleText_tch = 1.0f;
    } else {
        sampleText_tcw = 1.0f;
        sampleText_tch = ((float)fd->height / (float)fd->width);
    }
    sample_width = BLOOM_SIZE * sampleText_tcw;
    sample_height = BLOOM_SIZE * sampleText_tch;

    //copy the screen space we'll use to work into the backup texture
    GL_Bind(r_bloombackuptexture->texnum);
    qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, r_screenbackuptexture_size * sampleText_tcw, r_screenbackuptexture_size * sampleText_tch);

    //create the bloom image
    R_Bloom_DownsampleView();
    R_Bloom_GeneratexDiamonds( fd );
    //R_Bloom_GeneratexCross();

    //restore the screen-backup to the screen
    GL_Disable(GL_BLEND);
    GL_Bind(r_bloombackuptexture->texnum);
    qglColor4f( 1, 1, 1, 1 );
    R_Bloom_Quad( 0,
                  vid.height - (r_screenbackuptexture_size * sampleText_tch),
                  r_screenbackuptexture_size * sampleText_tcw,
                  r_screenbackuptexture_size * sampleText_tch,
                  sampleText_tcw,
                  sampleText_tch );

    R_Bloom_DrawEffect( fd );

    // Knightmare added
    R_SetupGL ();
    GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    qglEnable (GL_TEXTURE_2D);
    qglColor4f(1,1,1,1);
}
static void ProjectDlightTexture_altivec( void ) {
	int		i, l;
	vec_t	origin0, origin1, origin2;
	float   texCoords0, texCoords1;
	vector float floatColorVec0, floatColorVec1;
	vector float modulateVec, colorVec, zero;
	vector short colorShort;
	vector signed int colorInt;
	vector unsigned char floatColorVecPerm, modulatePerm, colorChar;
	vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff,
                                               0x00, 0x00, 0x00, 0xff,
                                               0x00, 0x00, 0x00, 0xff,
                                               0x00, 0x00, 0x00, 0xff);
	float	*texCoords;
	byte	*colors;
	byte	clipBits[SHADER_MAX_VERTEXES];
	float	texCoordsArray[SHADER_MAX_VERTEXES][2];
	byte	colorArray[SHADER_MAX_VERTEXES][4];
	unsigned	hitIndexes[SHADER_MAX_INDEXES];
	int		numIndexes;
	float	scale;
	float	radius;
	vec3_t	floatColor;
	float	modulate = 0.0f;

	if ( !backEnd.refdef.num_dlights ) {
		return;
	}

	// There has to be a better way to do this so that floatColor
	// and/or modulate are already 16-byte aligned.
	floatColorVecPerm = vec_lvsl(0,(float *)floatColor);
	modulatePerm = vec_lvsl(0,(float *)&modulate);
	modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0);
	zero = (vector float)vec_splat_s8(0);

	for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
		dlight_t	*dl;

		if ( !( tess.dlightBits & ( 1 << l ) ) ) {
			continue;	// this surface definately doesn't have any of this light
		}
		texCoords = texCoordsArray[0];
		colors = colorArray[0];

		dl = &backEnd.refdef.dlights[l];
		origin0 = dl->transformed[0];
		origin1 = dl->transformed[1];
		origin2 = dl->transformed[2];
		radius = dl->radius;
		scale = 1.0f / radius;

		if(r_greyscale->integer)
		{
			float luminance;
			
			luminance = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3;
			floatColor[0] = floatColor[1] = floatColor[2] = luminance;
		}
		else
		{
			floatColor[0] = dl->color[0] * 255.0f;
			floatColor[1] = dl->color[1] * 255.0f;
			floatColor[2] = dl->color[2] * 255.0f;
		}
		floatColorVec0 = vec_ld(0, floatColor);
		floatColorVec1 = vec_ld(11, floatColor);
		floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm);
		for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
			int		clip = 0;
			vec_t dist0, dist1, dist2;
			
			dist0 = origin0 - tess.xyz[i][0];
			dist1 = origin1 - tess.xyz[i][1];
			dist2 = origin2 - tess.xyz[i][2];

			backEnd.pc.c_dlightVertexes++;

			texCoords0 = 0.5f + dist0 * scale;
			texCoords1 = 0.5f + dist1 * scale;

			if( !r_dlightBacks->integer &&
					// dist . tess.normal[i]
					( dist0 * tess.normal[i][0] +
					dist1 * tess.normal[i][1] +
					dist2 * tess.normal[i][2] ) < 0.0f ) {
				clip = 63;
			} else {
				if ( texCoords0 < 0.0f ) {
					clip |= 1;
				} else if ( texCoords0 > 1.0f ) {
					clip |= 2;
				}
				if ( texCoords1 < 0.0f ) {
					clip |= 4;
				} else if ( texCoords1 > 1.0f ) {
					clip |= 8;
				}
				texCoords[0] = texCoords0;
				texCoords[1] = texCoords1;

				// modulate the strength based on the height and color
				if ( dist2 > radius ) {
					clip |= 16;
					modulate = 0.0f;
				} else if ( dist2 < -radius ) {
					clip |= 32;
					modulate = 0.0f;
				} else {
					dist2 = Q_fabs(dist2);
					if ( dist2 < radius * 0.5f ) {
						modulate = 1.0f;
					} else {
						modulate = 2.0f * (radius - dist2) * scale;
					}
				}
			}
			clipBits[i] = clip;

			modulateVec = vec_ld(0,(float *)&modulate);
			modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm);
			colorVec = vec_madd(floatColorVec0,modulateVec,zero);
			colorInt = vec_cts(colorVec,0);	// RGBx
			colorShort = vec_pack(colorInt,colorInt);		// RGBxRGBx
			colorChar = vec_packsu(colorShort,colorShort);	// RGBxRGBxRGBxRGBx
			colorChar = vec_sel(colorChar,vSel,vSel);		// RGBARGBARGBARGBA replace alpha with 255
			vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors);	// store color
		}

		// build a list of triangles that need light
		numIndexes = 0;
		for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
			int		a, b, c;

			a = tess.indexes[i];
			b = tess.indexes[i+1];
			c = tess.indexes[i+2];
			if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
				continue;	// not lighted
			}
			hitIndexes[numIndexes] = a;
			hitIndexes[numIndexes+1] = b;
			hitIndexes[numIndexes+2] = c;
			numIndexes += 3;
		}

		if ( !numIndexes ) {
			continue;
		}

		qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
		qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );

		qglEnableClientState( GL_COLOR_ARRAY );
		qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );

		GL_Bind( tr.dlightImage );
		// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
		// where they aren't rendered
		if ( dl->additive ) {
			GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
		}
		else {
			GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
		}
		R_DrawElements( numIndexes, hitIndexes );
		backEnd.pc.c_totalIndexes += numIndexes;
		backEnd.pc.c_dlightIndexes += numIndexes;
	}
}
static void ProjectDlightTexture_scalar( void ) {
	int		i, l;
	vec3_t	origin;
	float	*texCoords;
	byte	*colors;
	byte	clipBits[SHADER_MAX_VERTEXES];
	float	texCoordsArray[SHADER_MAX_VERTEXES][2];
	byte	colorArray[SHADER_MAX_VERTEXES][4];
	unsigned	hitIndexes[SHADER_MAX_INDEXES];
	int		numIndexes;
	float	scale;
	float	radius;
	vec3_t	floatColor;
	float	modulate = 0.0f;

	if ( !backEnd.refdef.num_dlights ) {
		return;
	}

	for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
		dlight_t	*dl;

		if ( !( tess.dlightBits & ( 1 << l ) ) ) {
			continue;	// this surface definately doesn't have any of this light
		}
		texCoords = texCoordsArray[0];
		colors = colorArray[0];

		dl = &backEnd.refdef.dlights[l];
		VectorCopy( dl->transformed, origin );
		radius = dl->radius;
		scale = 1.0f / radius;

		if(r_greyscale->integer)
		{
			float luminance;
			
			luminance = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3;
			floatColor[0] = floatColor[1] = floatColor[2] = luminance;
		}
		else
		{
			floatColor[0] = dl->color[0] * 255.0f;
			floatColor[1] = dl->color[1] * 255.0f;
			floatColor[2] = dl->color[2] * 255.0f;
		}

		for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
			int		clip = 0;
			vec3_t	dist;
			
			VectorSubtract( origin, tess.xyz[i], dist );

			backEnd.pc.c_dlightVertexes++;

			texCoords[0] = 0.5f + dist[0] * scale;
			texCoords[1] = 0.5f + dist[1] * scale;

			if( !r_dlightBacks->integer &&
					// dist . tess.normal[i]
					( dist[0] * tess.normal[i][0] +
					dist[1] * tess.normal[i][1] +
					dist[2] * tess.normal[i][2] ) < 0.0f ) {
				clip = 63;
			} else {
				if ( texCoords[0] < 0.0f ) {
					clip |= 1;
				} else if ( texCoords[0] > 1.0f ) {
					clip |= 2;
				}
				if ( texCoords[1] < 0.0f ) {
					clip |= 4;
				} else if ( texCoords[1] > 1.0f ) {
					clip |= 8;
				}
				texCoords[0] = texCoords[0];
				texCoords[1] = texCoords[1];

				// modulate the strength based on the height and color
				if ( dist[2] > radius ) {
					clip |= 16;
					modulate = 0.0f;
				} else if ( dist[2] < -radius ) {
					clip |= 32;
					modulate = 0.0f;
				} else {
					dist[2] = Q_fabs(dist[2]);
					if ( dist[2] < radius * 0.5f ) {
						modulate = 1.0f;
					} else {
						modulate = 2.0f * (radius - dist[2]) * scale;
					}
				}
			}
			clipBits[i] = clip;
			colors[0] = myftol(floatColor[0] * modulate);
			colors[1] = myftol(floatColor[1] * modulate);
			colors[2] = myftol(floatColor[2] * modulate);
			colors[3] = 255;
		}

		// build a list of triangles that need light
		numIndexes = 0;
		for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
			int		a, b, c;

			a = tess.indexes[i];
			b = tess.indexes[i+1];
			c = tess.indexes[i+2];
			if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
				continue;	// not lighted
			}
			hitIndexes[numIndexes] = a;
			hitIndexes[numIndexes+1] = b;
			hitIndexes[numIndexes+2] = c;
			numIndexes += 3;
		}

		if ( !numIndexes ) {
			continue;
		}

		qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
		qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );

		qglEnableClientState( GL_COLOR_ARRAY );
		qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );

		GL_Bind( tr.dlightImage );
		// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
		// where they aren't rendered
		if ( dl->additive ) {
			GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
		}
		else {
			GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
		}
		R_DrawElements( numIndexes, hitIndexes );
		backEnd.pc.c_totalIndexes += numIndexes;
		backEnd.pc.c_dlightIndexes += numIndexes;
	}
}
Exemple #10
0
static void ForwardDlight( void ) {
	int		l;
	//vec3_t	origin;
	//float	scale;
	float	radius;

	int deformGen;
	vec5_t deformParams;
	
	vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
	float eyeT = 0;

	shaderCommands_t *input = &tess;
	shaderStage_t *pStage = tess.xstages[0];

	if ( !backEnd.refdef.num_dlights ) {
		return;
	}
	
	ComputeDeformValues(&deformGen, deformParams);

	ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT);

	for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
		dlight_t	*dl;
		shaderProgram_t *sp;
		vec4_t vector;
		vec4_t texMatrix;
		vec4_t texOffTurb;

		if ( !( tess.dlightBits & ( 1 << l ) ) ) {
			continue;	// this surface definately doesn't have any of this light
		}

		dl = &backEnd.refdef.dlights[l];
		//VectorCopy( dl->transformed, origin );
		radius = dl->radius;
		//scale = 1.0f / radius;

		//if (pStage->glslShaderGroup == tr.lightallShader)
		{
			int index = pStage->glslShaderIndex;

			index &= ~LIGHTDEF_LIGHTTYPE_MASK;
			index |= LIGHTDEF_USE_LIGHT_VECTOR;

			sp = &tr.lightallShader[index];
		}

		backEnd.pc.c_lightallDraws++;

		GLSL_BindProgram(sp);

		GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
		GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin);
		GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin);

		GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);

		GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
		if (deformGen != DGEN_NONE)
		{
			GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
			GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
		}

		if ( input->fogNum ) {
			vec4_t fogColorMask;

			GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector);
			GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector);
			GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT);

			ComputeFogColorMask(pStage, fogColorMask);

			GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask);
		}

		{
			vec4_t baseColor;
			vec4_t vertColor;

			ComputeShaderColors(pStage, baseColor, vertColor, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);

			GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor);
			GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor);
		}

		if (pStage->alphaGen == AGEN_PORTAL)
		{
			GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange);
		}

		GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen);
		GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen);

		GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, dl->color);

		VectorSet(vector, 0, 0, 0);
		GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vector);

		VectorCopy(dl->origin, vector);
		vector[3] = 1.0f;
		GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector);

		GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius);

		GLSL_SetUniformVec4(sp, UNIFORM_NORMALSCALE, pStage->normalScale);
		GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, pStage->specularScale);
		
		// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
		// where they aren't rendered
		GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );

		GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix);

		if (pStage->bundle[TB_DIFFUSEMAP].image[0])
			R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP);

		// bind textures that are sampled and used in the glsl shader, and
		// bind whiteImage to textures that are sampled but zeroed in the glsl shader
		//
		// alternatives:
		//  - use the last bound texture
		//     -> costs more to sample a higher res texture then throw out the result
		//  - disable texture sampling in glsl shader with #ifdefs, as before
		//     -> increases the number of shaders that must be compiled
		//

		if (pStage->bundle[TB_NORMALMAP].image[0])
		{
			R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP);
		}
		else if (r_normalMapping->integer)
			GL_BindToTMU( tr.whiteImage, TB_NORMALMAP );

		if (pStage->bundle[TB_SPECULARMAP].image[0])
		{
			R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP);
		}
		else if (r_specularMapping->integer)
			GL_BindToTMU( tr.whiteImage, TB_SPECULARMAP );

		{
			vec4_t enableTextures;

			VectorSet4(enableTextures, 0.0f, 0.0f, 0.0f, 0.0f);
			GLSL_SetUniformVec4(sp, UNIFORM_ENABLETEXTURES, enableTextures);
		}

		if (r_dlightMode->integer >= 2)
		{
			GL_SelectTexture(TB_SHADOWMAP);
			GL_Bind(tr.shadowCubemaps[l]);
			GL_SelectTexture(0);
		}

		ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb );
		GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix);
		GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb);

		GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen);

		//
		// draw
		//

		if (input->multiDrawPrimitives)
		{
			R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
		}
		else
		{
			R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
		}

		backEnd.pc.c_totalIndexes += tess.numIndexes;
		backEnd.pc.c_dlightIndexes += tess.numIndexes;
		backEnd.pc.c_dlightVertexes += tess.numVertexes;
	}
}
Exemple #11
0
/*
 * RB_GLSL_IterateStagesGeneric
 * Iterate over each stage of a shader
 */
static void RB_GLSL_IterateStagesGeneric(shaderCommands_t *input) {
	int	stage;

	for(stage = 0; stage < MAX_SHADER_STAGES; stage++) {
		shaderStage_t	*pStage = tess.xstages[stage];
		glslProgram_t	*program;

		if (!pStage || pStage->program == tr.skipProgram)
			break;

		/* set state */
		GL_State(pStage->stateBits);

		/*
		 * this is an ugly hack to work around a GeForce driver
		 * bug with multitexture and clip planes
		 */
		if (backEnd.viewParms.isPortal)
			qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

		if (pStage->program)
			/* use specified program */
			R_GLSL_UseProgram(pStage->program);
		else
			/* use default program */
			R_GLSL_UseProgram(tr.defaultProgram);

		program = tr.programs[glState.currentProgram];

		/* alphaGen */
		if (program->u_AlphaGen > -1)
			R_GLSL_SetUniform_AlphaGen(program, pStage->alphaGen);

		/* ambient light */
		if (program->u_AmbientLight > -1)
			R_GLSL_SetUniform_AmbientLight(program, backEnd.currentEntity->ambientLight);

		/* dynamic light */
		if (program->u_DynamicLight > -1)
			R_GLSL_SetUniform_DynamicLight(program, backEnd.currentEntity->dynamicLight);

		/* light distance */
		if (program->u_LightDistance > -1)
			R_GLSL_SetUniform_LightDistance(program, backEnd.currentEntity->lightDistance);

		/* rgbGen */
		if (program->u_ColorGen > -1)
			R_GLSL_SetUniform_ColorGen(program, pStage->rgbGen);

		/* constant color */
		if (program->u_ConstantColor > -1)
			R_GLSL_SetUniform_ConstantColor(program, pStage->constantColor);

		/* directed light */
		if (program->u_DirectedLight > -1)
			R_GLSL_SetUniform_DirectedLight(program, backEnd.currentEntity->directedLight);

		/* entity color */
		if (program->u_EntityColor > -1)
			R_GLSL_SetUniform_EntityColor(program, backEnd.currentEntity->e.shaderRGBA);

		/* fog color */
		if (program->u_FogColor > -1 && tess.fogNum)
			R_GLSL_SetUniform_FogColor(program, (tr.world->fogs + tess.fogNum)->colorInt);

		/* greyscale */
		if (program->u_Greyscale > -1)
			R_GLSL_SetUniform_Greyscale(program, r_greyscale->integer);

		/* identity light */
		if (program->u_IdentityLight > -1)
			R_GLSL_SetUniform_IdentityLight(program, tr.identityLight);

		/* light direction */
		if (program->u_LightDirection > -1)
			R_GLSL_SetUniform_LightDirection(program, backEnd.currentEntity->lightDir);

		/* model view matrix */
		if (program->u_ModelViewMatrix > -1)
			R_GLSL_SetUniform_ModelViewMatrix(program, glState.currentModelViewMatrix);

		/* model view projection matrix */
		if (program->u_ModelViewProjectionMatrix > -1)
			R_GLSL_SetUniform_ModelViewProjectionMatrix(program, glState.currentModelViewProjectionMatrix);

		/* projection matrix */
		if (program->u_ProjectionMatrix > -1)
			R_GLSL_SetUniform_ProjectionMatrix(program, glState.currentProjectionMatrix);

		/* texture coordinates 0 */
		if (program->u_TCGen0 > -1)
			R_GLSL_SetUniform_TCGen0(program, pStage->bundle[0].tcGen);

		/* texture coordinates 1 */
		if (program->u_TCGen1 > -1)
			R_GLSL_SetUniform_TCGen1(program, pStage->bundle[1].tcGen);

		/* tex env */
		if (program->u_TexEnv > -1) {
			if (r_lightmap->integer)
				R_GLSL_SetUniform_TexEnv(program, GL_REPLACE);
			else
				R_GLSL_SetUniform_TexEnv(program, input->shader->multitextureEnv);
		}

		/* texture unit 0 */
		if (program->u_Texture0 > -1 && pStage->bundle[0].image[0]) {
			GL_SelectTexture(0);

			if (pStage->bundle[0].vertexLightmap && ((r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2) && r_lightmap->integer)
				GL_Bind(tr.whiteImage);
			else
				R_BindAnimatedImage(&pStage->bundle[0]);
		}

		/* texture unit 1 */
		if (program->u_Texture1 > -1 && pStage->bundle[1].image[0]) {
			GL_SelectTexture(1);
			qglEnable(GL_TEXTURE_2D);
			R_BindAnimatedImage(&pStage->bundle[1]);
		}

		/* texture unit 2 */
		if (program->u_Texture2 > -1 && pStage->bundle[2].image[0]) {
			GL_SelectTexture(2);
			qglEnable(GL_TEXTURE_2D);
			R_BindAnimatedImage(&pStage->bundle[2]);
		}

		/* texture unit 3 */
		if (program->u_Texture3 > -1 && pStage->bundle[3].image[0]) {
			GL_SelectTexture(3);
			qglEnable(GL_TEXTURE_2D);
			R_BindAnimatedImage(&pStage->bundle[3]);
		}

		/* texture unit 4 */
		if (program->u_Texture4 > -1 && pStage->bundle[4].image[0]) {
			GL_SelectTexture(4);
			qglEnable(GL_TEXTURE_2D);
			R_BindAnimatedImage(&pStage->bundle[4]);
		}

		/* texture unit 5 */
		if (program->u_Texture5 > -1 && pStage->bundle[5].image[0]) {
			GL_SelectTexture(5);
			qglEnable(GL_TEXTURE_2D);
			R_BindAnimatedImage(&pStage->bundle[5]);
		}

		/* texture unit 6 */
		if (program->u_Texture6 > -1 && pStage->bundle[6].image[0]) {
			GL_SelectTexture(6);
			qglEnable(GL_TEXTURE_2D);
			R_BindAnimatedImage(&pStage->bundle[6]);
		}

		/* texture unit 7 */
		if (program->u_Texture7 > -1 && pStage->bundle[7].image[0]) {
			GL_SelectTexture(7);
			qglEnable(GL_TEXTURE_2D);
			R_BindAnimatedImage(&pStage->bundle[7]);
		}

		/* time */
		if (program->u_Time > -1)
			R_GLSL_SetUniform_Time(program, input->shaderTime);

		/* view origin */
		if (program->u_ViewOrigin > -1)
			R_GLSL_SetUniform_ViewOrigin(program, backEnd.or.viewOrigin);

		/* draw */
		R_DrawElements(input->numIndexes, input->indexes);

		/* disable texture unit 7 */
		if (program->u_Texture7 > -1)
			qglDisable(GL_TEXTURE_2D);

		/* disable texture unit 6 */
		if (program->u_Texture6 > -1) {
			GL_SelectTexture(6);
			qglDisable(GL_TEXTURE_2D);
		}

		/* disable texture unit 5 */
		if (program->u_Texture5 > -1) {
			GL_SelectTexture(5);
			qglDisable(GL_TEXTURE_2D);
		}

		/* disable texture unit 4 */
		if (program->u_Texture4 > -1) {
			GL_SelectTexture(4);
			qglDisable(GL_TEXTURE_2D);
		}

		/* disable texture unit 3 */
		if (program->u_Texture3 > -1) {
			GL_SelectTexture(3);
			qglDisable(GL_TEXTURE_2D);
		}

		/* disable texture unit 2 */
		if (program->u_Texture2 > -1) {
			GL_SelectTexture(2);
			qglDisable(GL_TEXTURE_2D);
		}

		/* disable texture unit 1 */
		if (program->u_Texture1 > -1) {
			GL_SelectTexture(1);
			qglDisable(GL_TEXTURE_2D);
			qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
		}

		/* switch to texture unit 0 */
		GL_SelectTexture(0);

		/* allow skipping out to show just lightmaps during development */
		if (r_lightmap->integer && (pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap))
			break;
	}

	/* switch to standard rendering pipeline */
	R_GLSL_UseProgram(0);
}
Exemple #12
0
void R_DrawParticles (void)
{
	particle_t		*p, *kill;
	float			grav;
	int				i;
	float			time2, time3;
	float			time1;
	float			dvel, blend, blend1;
	float			frametime;
	vec3_t			up, right, neworg;
	float			scale, sscale;
	ParticleEmitter_t *ekill, *emt;

	if (gl_wireframe.value)
		return;

	glFogfv(GL_FOG_COLOR, color_black); //Done in actual function now (stops "triangle effect") - Eradicator
	glEnable (GL_BLEND);
	glBlendFunc (GL_ONE, GL_ONE);
	glEnable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER,0.01);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glDepthMask(0);

	VectorScale (vup, 1, up);
	VectorScale (vright, 1, right);
	glMatrixMode(GL_TEXTURE);

	frametime = cl.time - cl.oldtime;
	time3 = frametime * 15;
	time2 = frametime * 10; // 15;
	time1 = frametime * 5;
	grav = frametime * sv_gravity.value * 0.05;
	dvel = 4*frametime;

	//remove expired emitters
	for ( ;; ) 
	{
		ekill = active_emitters;
		if (ekill && ekill->die < cl.time)
		{
			active_emitters = ekill->next;
			ekill->next = free_emitters;
			free_emitters = ekill;
			continue;
		}
		break;
	}

	//Do the particle logic/drawing
	for (emt=active_emitters ; emt ; emt=emt->next)
	{
		for ( ;; )
		{
			ekill = emt->next;
			//XYZ
			if (ekill && (ekill->die < cl.time))
			{
				emt->next = ekill->next;
				ekill->next = free_emitters;
				free_emitters = ekill;
				continue;
			}
			break;
		}

		if (emt->nexttick < cl.time) {
			vec3_t length;
			VectorSubtract(emt->origin, r_refdef.vieworg, length);
			//dont emit if we are to far away to see it
			if (Length(length) < 600.0f) {
				for (i=0; i<emt->count; i++) {
					InitParticleFromEffect(emt->effect,emt->origin);
				}
			}
			emt->nexttick = cl.time + emt->tick;
		}
	}

	//remove expired particles
	for ( ;; ) 
	{
		kill = active_particles;
		if (kill && kill->die < cl.time)
		{
			active_particles = kill->next;
			kill->next = free_particles;
			free_particles = kill;
			continue;
		}
		break;
	}

	//Do the particle logic/drawing
	for (p=active_particles ; p ; p=p->next)
	{
		for ( ;; )
		{
			kill = p->next;
			//XYZ
			if (kill && ((kill->die < cl.time) || (kill->numbounces <= 0)))
			{
				p->next = kill->next;
				kill->next = free_particles;
				free_particles = kill;
				continue;
			}
			break;
		}

		scale = p->size;
		p->size += p->growspeed*frametime;

		//calculate color based on life ...
		blend = (p->die-cl.time)/p->lifetime;
		blend1 = 1-blend;
		for (i=0; i<3; i++) {
			p->color[i] = p->startcolor[i] * blend + p->endcolor[i] * blend1;
		}

		if ((p->die - cl.time) < 0.5) {
			float fade = 2*(p->die - cl.time);
			glColor4f(p->color[0]*fade, p->color[1]*fade, p->color[2]*fade, fade);
		} else {
			glColor3fv(&p->color[0]);
		}

		GL_Bind(p->texture);
		glBlendFunc (p->srcblend, p->dstblend);

		//Align with velocity
		if (p->velaligned){
			float lscale;
			VectorCopy (p->vel, up);
			VectorNormalize(up);
			CrossProduct(vpn,up,right);
			VectorNormalize(right);
			lscale = (Length(p->vel)*p->velscale);
			VectorScale(up,lscale,up);
		} else {
			VectorCopy (vup, up);
			VectorCopy (vright, right);
		}

		glLoadIdentity();
		glTranslatef(0.5,0.5,0);
		glRotatef(p->rot,0,0,1);
		glTranslatef(-0.5,-0.5,0);

		sscale = -scale/4;
		VectorMA(p->org,sscale,up,neworg);
		VectorMA(neworg,sscale,right,neworg);

                // draw the particle as two triangles
                scale /= 2;
		glBegin(GL_TRIANGLE_FAN);
		glTexCoord2f (0,0);
		glVertex3fv (neworg);
		glTexCoord2f (0,1);
		glVertex3f (neworg[0] + up[0]*scale, neworg[1] + up[1]*scale,
                            neworg[2] + up[2]*scale);
		glTexCoord2f (1,1);
		glVertex3f (neworg[0] + up[0]*scale + right[0]*scale, neworg[1] + up[1]*scale + right[1]*scale,
                            neworg[2] + up[2]*scale + right[2]*scale);
		glTexCoord2f (1,0);
		glVertex3f (neworg[0] + right[0]*scale, neworg[1] + right[1]*scale,
                            neworg[2] + right[2]*scale);
		glEnd();
                scale *= 2;

		//calculate new position/rotation
		neworg[0] = p->org[0]+p->vel[0]*frametime;
		neworg[1] = p->org[1]+p->vel[1]*frametime;
		neworg[2] = p->org[2]+p->vel[2]*frametime;
		p->rot = p->rot+p->rspeed*frametime;

		//do collision detection
		{
			trace_t	trace;
			float	d;

			memset (&trace, 0, sizeof(trace));
			trace.fraction = 1;
			SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, p->org, neworg, &trace);

			if (trace.fraction < 1) {
				vec3_t tangent;
				//calc reflection vector
				d = DotProduct (p->vel, trace.plane.normal);
				VectorMA (p->vel, -2*d, trace.plane.normal, p->vel);
				VectorScale(p->vel,0.33,p->vel);
				VectorCopy(trace.endpos,p->org);
				//XYZ
				p->numbounces--;

				if (p->spawn) {
					CrossProduct(trace.plane.normal,p->vel,tangent);
					if (p->spawn->align == align_surf) {
						R_SpawnDecal(p->org, trace.plane.normal, tangent, p->spawn);
					} else {
						InitParticleFromEffect(p->spawn, p->org);
					}
				}
			} else {
				VectorCopy(neworg,p->org);
			}
		}

		for (i=0; i<3; i++) {
			p->vel[i] += p->gravity[i]*frametime;
		}
		
		for (i=0; i<3; i++) {
			p->vel[i] *= p->drag[i];
		}
	}

	glDepthMask(1);
	glDisable (GL_BLEND);
	glDisable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER,0.666);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	//XYZ
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glFogfv(GL_FOG_COLOR, fog_color); //Done in actual function now (stops "triangle effect") - Eradicator
}
void CRainSystem::Render(void)
{
	int			i;
	SParticle	*item;
	vec4_t		forward, down, left;
	vec3_t		pos;
//	float		percent;
	float		radius;

	CWorldEffectsSystem::Render();

	if (mFadeAlpha <= 0.0)
	{
		return;
	}

	VectorScale(backEnd.viewParms.or.axis[0], 1, forward);		// forward
	VectorScale(backEnd.viewParms.or.axis[1], 0.2f, left);		// left
	down[0] = 0 - mWindDirection[0] * mRainHeight * mWindAngle;
	down[1] = 0 - mWindDirection[1] * mRainHeight * mWindAngle;
	down[2] = -mRainHeight;

	GL_Bind(mImage);

	GL_State(GLS_ALPHA);
	qglEnable(GL_TEXTURE_2D);
	qglDisable(GL_CULL_FACE);

	qglMatrixMode(GL_MODELVIEW);
	qglPushMatrix();
    qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1],  backEnd.viewParms.or.origin[2]);

	item = mRainList;
	qglBegin(GL_TRIANGLES );
	for(i=mMaxRain;i;i--)
	{
/*		percent = (item->pos[1] -(-20.0)) / (20.0 - (-20.0));
		percent *= forward[2];
		if (percent < 0.0)
		{
			radius = 10 * (percent + 1.0);
		}
		else
		{
			radius = 10 * (1.0 - percent);
		}*/
		radius = item->pos[1];
		if (item->pos[2] < 0.0)
		{
//			radius *= 1.0 - (item->pos[2] / 40.0);
			float alpha = mAlpha * (item->pos[1] / -item->pos[2]);

			if (alpha > mAlpha)
			{
				alpha = mAlpha;
			}
			qglColor4f(1.0, 1.0, 1.0, alpha * mFadeAlpha);
		}
		else
		{
			qglColor4f(1.0, 1.0, 1.0, mAlpha * mFadeAlpha);
//			radius *= 1.0 + (item->pos[2] / 20.0);
		}

		pos[0] = sin(item->pos[0]) * radius + (item->pos[2] * mWindDirection[0] * mWindAngle);
		pos[1] = cos(item->pos[0]) * radius + (item->pos[2] * mWindDirection[1] * mWindAngle);
		pos[2] = item->pos[2];

		qglTexCoord2f(1.0, 0.0);
		qglVertex3f(pos[0],
					pos[1],
					pos[2]);

		qglTexCoord2f(0.0, 0.0);
		qglVertex3f(pos[0] + left[0],
					pos[1] + left[1],
					pos[2] + left[2]);
		
		qglTexCoord2f(0.0, 1.0);
		qglVertex3f(pos[0] + down[0] + left[0],
					pos[1] + down[1] + left[1],
					pos[2] + down[2] + left[2]);
		item++;
	}
	qglEnd();

	qglEnable(GL_CULL_FACE);

	qglPopMatrix();
}
CRainSystem::CRainSystem(int maxRain) :
	mMaxRain(maxRain),
	mNextWindGust(0),
	mRainHeight(5),
	mAlpha(0.15f),
	mWindAngle(1.0f),

	mFadeAlpha(0.0f),
	mIsRaining(false)

{
	char			name[256];
	unsigned char	*data, *pos;
	int				width, height;
	int				x, y;

	mSpread[0] = (float)(M_PI*2.0);		// angle spread
	mSpread[1] = 20.0f;			// radius spread
	mSpread[2] = 20.0f;			// z spread

	mMinVelocity[0] = 0.1f;
	mMaxVelocity[0] = -0.1f;
	mMinVelocity[1] = 0.1f;
	mMaxVelocity[1] = -0.1f;
	mMinVelocity[2] = -60.0;
	mMaxVelocity[2] = -50.0;

	mWindDuration = 15;
	mWindLow = 50;
	mWindMin = 0.01f;
	mWindMax = 0.05f;

	mWindChange = 0;
	mWindDirection[0] = mWindDirection[1] = mWindDirection[2] = 0.0;

	mRainList = new SParticle[mMaxRain];

	sprintf(name, "gfx/world/rain.tga");
	R_LoadImage( name, &data, &width, &height );
	if (!data)
	{
		ri.Error (ERR_DROP, "Could not load %s", name);
	}

	pos = data;
	for(y=0;y<height;y++)
	{
		for(x=0;x<width;x++)
		{
			pos[3] = pos[0];
			pos += 4;
		}
	}

	mImage = R_CreateImage(name, data, width, height, false, false, false, GL_CLAMP);
	GL_Bind(mImage);
	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

	Init();
}
Exemple #15
0
/*
================
Tess_StageIteratorSky

All of the visible sky triangles are in tess

Other things could be stuck in here, like birds in the sky, etc
================
*/
void Tess_StageIteratorSky( void )
{
	// log this call
	if ( r_logFile->integer )
	{
		// don't just call LogComment, or we will get
		// a call to va() every frame!
		GLimp_LogComment( va
		                  ( "--- Tess_StageIteratorSky( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
		                    tess.numVertexes, tess.numIndexes / 3 ) );
	}

	if ( r_fastsky->integer )
	{
		return;
	}

	// trebor: HACK why does this happen with cg_draw2D 0 ?
	if ( tess.stageIteratorFunc2 == NULL )
	{
		//tess.stageIteratorFunc2 = Tess_StageIteratorGeneric;
		ri.Error( ERR_FATAL, "tess.stageIteratorFunc == NULL" );
	}

	GL_Cull(CT_TWO_SIDED);

	if ( tess.stageIteratorFunc2 == &Tess_StageIteratorDepthFill )
	{
		// go through all the polygons and project them onto
		// the sky box to see which blocks on each side need
		// to be drawn
		Tess_ClipSkyPolygons();

		// generate the vertexes for all the clouds, which will be drawn
		// by the generic shader routine
		BuildCloudData();

		if ( tess.numVertexes || tess.multiDrawPrimitives )
		{
			tess.stageIteratorFunc2();
		}
	}
	else
	{
		if ( tess.stageIteratorFunc2 == &Tess_StageIteratorGBuffer )
		{
			R_BindFBO( tr.geometricRenderFBO );
		}

		// go through all the polygons and project them onto
		// the sky box to see which blocks on each side need
		// to be drawn
		Tess_ClipSkyPolygons();

		// r_showSky will let all the sky blocks be drawn in
		// front of everything to allow developers to see how
		// much sky is getting sucked in

		if ( r_showSky->integer )
		{
			glDepthRange( 0.0, 0.0 );
		}
		else
		{
			glDepthRange( 1.0, 1.0 );
		}

		// draw the outer skybox
		if ( tess.surfaceShader->sky.outerbox && tess.surfaceShader->sky.outerbox != tr.blackCubeImage )
		{
#if 1
			R_BindVBO( tess.vbo );
			R_BindIBO( tess.ibo );

			gl_skyboxShader->BindProgram();

			gl_skyboxShader->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin );  // in world space

			gl_skyboxShader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix );
			gl_skyboxShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] );

			gl_skyboxShader->SetRequiredVertexPointers();

			// bind u_ColorMap
			GL_SelectTexture( 0 );
			GL_Bind( tess.surfaceShader->sky.outerbox );

			DrawSkyBox( tess.surfaceShader );
#endif
		}

		// generate the vertexes for all the clouds, which will be drawn
		// by the generic shader routine
		BuildCloudData();

		if ( tess.numVertexes || tess.multiDrawPrimitives )
		{
			tess.stageIteratorFunc2();
		}

		// Tr3B: TODO draw the inner skybox?

		if ( tess.stageIteratorFunc2 == Tess_StageIteratorGBuffer )
		{
			R_BindNullFBO();
		}

		if ( tess.stageIteratorFunc2 != Tess_StageIteratorDepthFill )
		{
			// back to standard depth range
			glDepthRange( 0.0, 1.0 );

			// note that sky was drawn so we will draw a sun later
			backEnd.skyRenderedThisView = qtrue;
		}
	}
}
Exemple #16
0
void R_DrawSkyBox (void)
{
#ifdef ENABLE_HYG_STARS
	R_DrawStars(); // jitstarviewer
#else
	int		i;

	if (fogenabled) // jitfog
		qgl.Disable(GL_FOG);

	if (skyrotate)
	{
		// check for no sky at all
		for (i = 0; i < 6; ++i)
		{
			if (skymins[0][i] < skymaxs[0][i] && skymins[1][i] < skymaxs[1][i])
				break;
		}

		if (i == 6)
			return;		// nothing visible
	}

	qgl.PushMatrix();
	qgl.Translatef(r_origin[0], r_origin[1], r_origin[2]);
	qgl.Rotatef(r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]);

	if (fogenabled && sky_images[0] == r_whitetexture) // jitfog
	{
		qgl.Color3fv(fogcolor);
		GLSTATE_ENABLE_BLEND
		GL_TexEnv(GL_MODULATE);
	}

	for (i = 0; i < 6; ++i)
	{
		if (skyrotate)
		{
			// hack, forces full sky to draw when rotating
			skymins[0][i] = -1;
			skymins[1][i] = -1;
			skymaxs[0][i] = 1;
			skymaxs[1][i] = 1;
		}

		if (skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i])
			continue;

		GL_Bind(sky_images[skytexorder[i]]->texnum);

		qgl.Begin(GL_QUADS);
		MakeSkyVec(skymins[0][i], skymins[1][i], i);
		MakeSkyVec(skymins[0][i], skymaxs[1][i], i);
		MakeSkyVec(skymaxs[0][i], skymaxs[1][i], i);
		MakeSkyVec(skymaxs[0][i], skymins[1][i], i);
		qgl.End();
	}

	qgl.PopMatrix();

	if (fogenabled) // jitfog
	{
		qgl.Color3f(1, 1, 1);
		GLSTATE_DISABLE_BLEND
		qgl.Enable(GL_FOG);
	}
#endif
}
Exemple #17
0
/*
=================
RB_ShadowTessEnd

triangleFromEdge[ v1 ][ v2 ]


  set triangle from edge( v1, v2, tri )
  if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {
  }
=================
*/
void RB_ShadowTessEnd( void ) {
	int		i;
	int		numTris;
	vec3_t	lightDir;
	GLboolean rgba[4];

	// we can only do this if we have enough space in the vertex buffers
	if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) {
		return;
	}

	if ( glConfig.stencilBits < 4 ) {
		return;
	}

	VectorCopy( backEnd.currentEntity->lightDir, lightDir );

	// project vertexes away from light direction
	for ( i = 0 ; i < tess.numVertexes ; i++ ) {
		VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] );
	}

	// decide which triangles face the light
	Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes );

	numTris = tess.numIndexes / 3;
	for ( i = 0 ; i < numTris ; i++ ) {
		int		i1, i2, i3;
		vec3_t	d1, d2, normal;
		float	*v1, *v2, *v3;
		float	d;

		i1 = tess.indexes[ i*3 + 0 ];
		i2 = tess.indexes[ i*3 + 1 ];
		i3 = tess.indexes[ i*3 + 2 ];

		v1 = tess.xyz[ i1 ];
		v2 = tess.xyz[ i2 ];
		v3 = tess.xyz[ i3 ];

		VectorSubtract( v2, v1, d1 );
		VectorSubtract( v3, v1, d2 );
		CrossProduct( d1, d2, normal );

		d = DotProduct( normal, lightDir );
		if ( d > 0 ) {
			facing[ i ] = 1;
		} else {
			facing[ i ] = 0;
		}

		// create the edges
		R_AddEdgeDef( i1, i2, facing[ i ] );
		R_AddEdgeDef( i2, i3, facing[ i ] );
		R_AddEdgeDef( i3, i1, facing[ i ] );
	}

	// draw the silhouette edges

	GL_Bind( tr.whiteImage );
	qglEnable( GL_CULL_FACE );
	GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
	qglColor3f( 0.2f, 0.2f, 0.2f );

	// don't write to the color buffer
	qglGetBooleanv(GL_COLOR_WRITEMASK, rgba);
	qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );

	qglEnable( GL_STENCIL_TEST );
	qglStencilFunc( GL_ALWAYS, 1, 255 );

	// mirrors have the culling order reversed
	if ( backEnd.viewParms.isMirror ) {
		qglCullFace( GL_FRONT );
		qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );

		R_RenderShadowEdges();

		qglCullFace( GL_BACK );
		qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );

		R_RenderShadowEdges();
	} else {
		qglCullFace( GL_BACK );
		qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );

		R_RenderShadowEdges();

		qglCullFace( GL_FRONT );
		qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );

		R_RenderShadowEdges();
	}


	// reenable writing to the color buffer
	qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]);
}
Exemple #18
0
void
Draw_ScaledPic(int x, int y, float scale, float alpha, char *pic, float red, float green, float blue, qboolean fixcoords, qboolean repscale)
{
	float		xoff, yoff;
	image_t        *gl;

	gl = Draw_FindPic(pic);
	if (!gl) {
		ri.Con_Printf(PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}
	if (scrap_dirty)
		Scrap_Upload();

	if (((gl_config.renderer == GL_RENDERER_MCD) || (gl_config.renderer & GL_RENDERER_RENDITION)) && !gl->has_alpha)
		qglDisable(GL_ALPHA_TEST);

	/* add alpha support */
	{
		qglDisable(GL_ALPHA_TEST);

		qglBindTexture(GL_TEXTURE_2D, gl->texnum);

		GL_TexEnv(GL_MODULATE);
		qglColor4f(red, green, blue, alpha);
		qglEnable(GL_BLEND);
		qglDepthMask(false);
	}

	/* NOTE: replace this with shaders as soon as they are supported */
	if (repscale)
		scale *= gl->replace_scale;	/* scale down if replacing a pcx image */

	if (fixcoords) {	/* Knightmare- whether to adjust coordinates for scaling */

		xoff = (gl->width * scale - gl->width) / 2;
		yoff = (gl->height * scale - gl->height) / 2;

		GL_Bind(gl->texnum);
		qglBegin(GL_QUADS);
		qglTexCoord2f(gl->sl, gl->tl);
		qglVertex2f(x - xoff, y - yoff);
		qglTexCoord2f(gl->sh, gl->tl);
		qglVertex2f(x + gl->width + xoff, y - yoff);
		qglTexCoord2f(gl->sh, gl->th);
		qglVertex2f(x + gl->width + xoff, y + gl->height + yoff);
		qglTexCoord2f(gl->sl, gl->th);
		qglVertex2f(x - xoff, y + gl->height + yoff);
		qglEnd();

	} else {
		xoff = gl->width * scale - gl->width;
		yoff = gl->height * scale - gl->height;

		GL_Bind(gl->texnum);
		qglBegin(GL_QUADS);
		qglTexCoord2f(gl->sl, gl->tl);
		qglVertex2f(x, y);
		qglTexCoord2f(gl->sh, gl->tl);
		qglVertex2f(x + gl->width + xoff, y);
		qglTexCoord2f(gl->sh, gl->th);
		qglVertex2f(x + gl->width + xoff, y + gl->height + yoff);
		qglTexCoord2f(gl->sl, gl->th);
		qglVertex2f(x, y + gl->height + yoff);
		qglEnd();
	}

	/* add alpha support */
	{
		qglDepthMask(true);
		GL_TexEnv(GL_REPLACE);
		qglDisable(GL_BLEND);
		qglColor4f(1, 1, 1, 1);

		qglEnable(GL_ALPHA_TEST);
	}

	if (((gl_config.renderer == GL_RENDERER_MCD) || (gl_config.renderer & GL_RENDERER_RENDITION)) && !gl->has_alpha)
		qglEnable(GL_ALPHA_TEST);
}
/*
=================
R_Bloom_GeneratexDiamonds
=================
*/
void R_Bloom_GeneratexDiamonds( refdef_t *fd )
{
    int			i, j;
    static float intensity;

    //set up sample size workspace
    qglViewport( 0, 0, sample_width, sample_height );
    qglMatrixMode( GL_PROJECTION );
    qglLoadIdentity ();
    qglOrtho(0, sample_width, sample_height, 0, -10, 100);
    qglMatrixMode( GL_MODELVIEW );
    qglLoadIdentity ();

    //copy small scene into r_bloomeffecttexture
    GL_Bind(r_bloomeffecttexture->texnum);
    qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);

    //start modifying the small scene corner
    qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
    GL_Enable(GL_BLEND);

    //Com_Printf("%d %d\n", r_bloom_darken->value, fd->bloomdarken);

    //darkening passes
    if( r_bloom_darken->value )
    {
        GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
        GL_TexEnv(GL_MODULATE);

        for(i=0; i< r_bloom_darken->value  ; i++) {
            R_Bloom_SamplePass( 0, 0 );
        }
        qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);
    }

    //bluring passes
    //GL_BlendFunc(GL_ONE, GL_ONE);
    GL_BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);



    if( r_bloom_diamond_size->value > 7 || r_bloom_diamond_size->value <= 3)
    {
        if( (int)r_bloom_diamond_size->value != 8 ) Cvar_SetValue( "r_bloom_diamond_size", 8 );

        for(i=0; i<r_bloom_diamond_size->value; i++) {
            for(j=0; j<r_bloom_diamond_size->value; j++) {
                intensity = /*bc mod*/(fd->bloomintensity +  r_bloom_intensity->value) * 0.3 * Diamond8x[i][j];
                if( intensity < r_bloom_threshold->value ) continue;
                qglColor4f( intensity, intensity, intensity, 1.0);
                R_Bloom_SamplePass( i-4, j-4 );
            }
        }
    } else if( r_bloom_diamond_size->value > 5 ) {

        if( r_bloom_diamond_size->value != 6 ) Cvar_SetValue( "r_bloom_diamond_size", 6 );

        for(i=0; i<r_bloom_diamond_size->value; i++) {
            for(j=0; j<r_bloom_diamond_size->value; j++) {
                intensity = /*bc mod*/(fd->bloomintensity + r_bloom_intensity->value) * 0.5 * Diamond6x[i][j];
                if( intensity < r_bloom_threshold->value ) continue;
                qglColor4f( intensity, intensity, intensity, 1.0);
                R_Bloom_SamplePass( i-3, j-3 );
            }
        }
    } else if( r_bloom_diamond_size->value > 3 ) {

        if( (int)r_bloom_diamond_size->value != 4 ) Cvar_SetValue( "r_bloom_diamond_size", 4 );

        for(i=0; i<r_bloom_diamond_size->value; i++) {
            for(j=0; j<r_bloom_diamond_size->value; j++) {
                intensity = /*bc mod*/(fd->bloomintensity + r_bloom_intensity->value) * 0.8f * Diamond4x[i][j];
                if( intensity < r_bloom_threshold->value ) continue;
                qglColor4f( intensity, intensity, intensity, 1.0);
                R_Bloom_SamplePass( i-2, j-2 );
            }
        }
    }

    qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height);

    //restore full screen workspace
    qglViewport( 0, 0, vid.width, vid.height );
    qglMatrixMode( GL_PROJECTION );
    qglLoadIdentity ();
    qglOrtho(0, vid.width, vid.height, 0, -10, 100);
    qglMatrixMode( GL_MODELVIEW );
    qglLoadIdentity ();
}
Exemple #20
0
static void ProjectDlightTexture( void ) {
	int		l;
	vec3_t	origin;
	float	scale;
	float	radius;
	int deformGen;
	vec5_t deformParams;

	if ( !backEnd.refdef.num_dlights ) {
		return;
	}

	ComputeDeformValues(&deformGen, deformParams);

	for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
		dlight_t	*dl;
		shaderProgram_t *sp;
		vec4_t vector;

		if ( !( tess.dlightBits & ( 1 << l ) ) ) {
			continue;	// this surface definately doesn't have any of this light
		}

		dl = &backEnd.refdef.dlights[l];
		VectorCopy( dl->transformed, origin );
		radius = dl->radius;
		scale = 1.0f / radius;

		sp = &tr.dlightShader[deformGen == DGEN_NONE ? 0 : 1];

		backEnd.pc.c_dlightDraws++;

		GLSL_BindProgram(sp);

		GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);

		GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
		
		GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
		if (deformGen != DGEN_NONE)
		{
			GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
			GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
		}

		vector[0] = dl->color[0];
		vector[1] = dl->color[1];
		vector[2] = dl->color[2];
		vector[3] = 1.0f;
		GLSL_SetUniformVec4(sp, UNIFORM_COLOR, vector);

		vector[0] = origin[0];
		vector[1] = origin[1];
		vector[2] = origin[2];
		vector[3] = scale;
		GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector);
	  
		GL_Bind( tr.dlightImage );

		// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
		// where they aren't rendered
		if ( dl->additive ) {
			GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
		}
		else {
			GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
		}

		if (tess.multiDrawPrimitives)
		{
			shaderCommands_t *input = &tess;
			R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
		}
		else
		{
			R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex);
		}

		backEnd.pc.c_totalIndexes += tess.numIndexes;
		backEnd.pc.c_dlightIndexes += tess.numIndexes;
		backEnd.pc.c_dlightVertexes += tess.numVertexes;
	}
}
Exemple #21
0
static void ProjectDlightTexture_altivec( void ) {
	int		i, l;
	vec_t	origin0, origin1, origin2;
	float   texCoords0, texCoords1;
	vector float floatColorVec0, floatColorVec1;
	vector float modulateVec, colorVec, zero;
	vector short colorShort;
	vector signed int colorInt;
	vector unsigned char floatColorVecPerm, modulatePerm, colorChar;
	vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff,
                                               0x00, 0x00, 0x00, 0xff,
                                               0x00, 0x00, 0x00, 0xff,
                                               0x00, 0x00, 0x00, 0xff);
	float	*texCoords;
	byte	*colors;
	int		*intColors;
	byte	clipBits[SHADER_MAX_VERTEXES];
	float	texCoordsArray[SHADER_MAX_VERTEXES][2];
	byte	colorArray[SHADER_MAX_VERTEXES][4];
	glIndex_t	hitIndexes[SHADER_MAX_INDEXES];
	int		numIndexes;
	float	scale;
	float	radius;
	float	radiusInverseCubed;
	float	intensity, remainder;
	vec3_t	floatColor;
	float	modulate = 0.0f;
	qboolean vertexLight;

	if ( !backEnd.refdef.num_dlights ) {
		return;
	}

	// There has to be a better way to do this so that floatColor
	// and/or modulate are already 16-byte aligned.
	floatColorVecPerm = vec_lvsl(0,(float *)floatColor);
	modulatePerm = vec_lvsl(0,(float *)&modulate);
	modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0);
	zero = (vector float)vec_splat_s8(0);

	for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
		dlight_t	*dl;

		if ( !( tess.dlightBits & ( 1 << l ) ) ) {
			continue;	// this surface definately doesn't have any of this light
		}

		// clear colors
		Com_Memset( colorArray, 0, sizeof( colorArray ) );

		texCoords = texCoordsArray[0];
		colors = colorArray[0];

		dl = &backEnd.refdef.dlights[l];
		origin0 = dl->transformed[0];
		origin1 = dl->transformed[1];
		origin2 = dl->transformed[2];
		radius = dl->radius;
		scale = 1.0f / radius;
		radiusInverseCubed = dl->radiusInverseCubed;
		intensity = dl->intensity;

		vertexLight = ( ( dl->flags & REF_DIRECTED_DLIGHT ) || ( dl->flags & REF_VERTEX_DLIGHT ) );

		// directional lights have max intensity and washout remainder intensity
		if ( dl->flags & REF_DIRECTED_DLIGHT ) {
			remainder = intensity * 0.125;
		} else {
			remainder = 0.0f;
		}

		if(r_greyscale->integer)
		{
			float luminance;
			
			luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f;
			floatColor[0] = floatColor[1] = floatColor[2] = luminance;
		}
		else if(r_greyscale->value)
		{
			float luminance;
			
			luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f;
			floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value);
			floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value);
			floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value);
		}
		else
		{
			floatColor[0] = dl->color[0] * 255.0f;
			floatColor[1] = dl->color[1] * 255.0f;
			floatColor[2] = dl->color[2] * 255.0f;
		}
		floatColorVec0 = vec_ld(0, floatColor);
		floatColorVec1 = vec_ld(11, floatColor);
		floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm);
		for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
			int		clip = 0;
			vec_t dist0, dist1, dist2;
			
			dist0 = origin0 - tess.xyz[i][0];
			dist1 = origin1 - tess.xyz[i][1];
			dist2 = origin2 - tess.xyz[i][2];

			backEnd.pc.c_dlightVertexes++;

			// directional dlight, origin is a directional normal
			if ( dl->flags & REF_DIRECTED_DLIGHT ) {
				// twosided surfaces use absolute value of the calculated lighting
				modulate = intensity * DotProduct( dl->origin, tess.normal[ i ] );
				if ( tess.shader->cullType == CT_TWO_SIDED ) {
					modulate = fabs( modulate );
				}
				modulate += remainder;
			}
			// spherical vertex lit dlight
			else if ( dl->flags & REF_VERTEX_DLIGHT )
			{
				vec3_t	dir;

				dir[ 0 ] = radius - fabs( dist0 );
				if ( dir[ 0 ] <= 0.0f ) {
					continue;
				}
				dir[ 1 ] = radius - fabs( dist1 );
				if ( dir[ 1 ] <= 0.0f ) {
					continue;
				}
				dir[ 2 ] = radius - fabs( dist2 );
				if ( dir[ 2 ] <= 0.0f ) {
					continue;
				}

				modulate = intensity * dir[ 0 ] * dir[ 1 ] * dir[ 2 ] * radiusInverseCubed;
			}
			// vertical cylinder dlight
			else
			{
				texCoords0 = 0.5f + dist0 * scale;
				texCoords1 = 0.5f + dist1 * scale;

				if( !r_dlightBacks->integer &&
						// dist . tess.normal[i]
						( dist0 * tess.normal[i][0] +
						dist1 * tess.normal[i][1] +
						dist2 * tess.normal[i][2] ) < 0.0f ) {
					clip = 63;
				} else {
					if ( texCoords0 < 0.0f ) {
						clip |= 1;
					} else if ( texCoords0 > 1.0f ) {
						clip |= 2;
					}
					if ( texCoords1 < 0.0f ) {
						clip |= 4;
					} else if ( texCoords1 > 1.0f ) {
						clip |= 8;
					}
					texCoords[0] = texCoords0;
					texCoords[1] = texCoords1;

					// modulate the strength based on the height and color
					if ( dist2 > radius ) {
						clip |= 16;
						modulate = 0.0f;
					} else if ( dist2 < -radius ) {
						clip |= 32;
						modulate = 0.0f;
					} else {
						dist2 = Q_fabs(dist2);
						if ( dist2 < radius * 0.5f ) {
							modulate = intensity;
						} else {
							modulate = intensity * 2.0f * (radius - dist2) * scale;
						}
					}
				}
			}
			clipBits[i] = clip;

			// optimizations
			if ( vertexLight && modulate < ( 1.0f / 128.0f ) ) {
				continue;
			} else if ( modulate > 1.0f ) {
				modulate = 1.0f;
			}

			// ZTM: FIXME: should probably clamp to 0-255 range before converting to char,
			// but I don't know how to do altvec stuff or if it's even used anymore
			modulateVec = vec_ld(0,(float *)&modulate);
			modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm);
			colorVec = vec_madd(floatColorVec0,modulateVec,zero);
			colorInt = vec_cts(colorVec,0);	// RGBx
			colorShort = vec_pack(colorInt,colorInt);		// RGBxRGBx
			colorChar = vec_packsu(colorShort,colorShort);	// RGBxRGBxRGBxRGBx
			colorChar = vec_sel(colorChar,vSel,vSel);		// RGBARGBARGBARGBA replace alpha with 255
			vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors);	// store color
		}

		// build a list of triangles that need light
		intColors = (int*) colorArray;
		numIndexes = 0;
		for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
			int		a, b, c;

			a = tess.indexes[i];
			b = tess.indexes[i+1];
			c = tess.indexes[i+2];
			if ( vertexLight ) {
				if ( !( intColors[ a ] | intColors[ b ] | intColors[ c ] ) ) {
					continue;
				}
			} else {
				if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
					continue;	// not lighted
				}
			}
			hitIndexes[numIndexes] = a;
			hitIndexes[numIndexes+1] = b;
			hitIndexes[numIndexes+2] = c;
			numIndexes += 3;
		}

		if ( !numIndexes ) {
			continue;
		}

		if ( !vertexLight ) {
			qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
			qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
		} else {
			qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
		}

		qglEnableClientState( GL_COLOR_ARRAY );
		qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );

		if ( dl->dlshader ) {
			shader_t *dls = dl->dlshader;

			for ( i = 0; i < dls->numUnfoggedPasses; i++ ) {
				shaderStage_t *stage = dls->stages[i];
				R_BindAnimatedImage( &dls->stages[i]->bundle[0] );
				GL_State( stage->stateBits | GLS_DEPTHFUNC_EQUAL );
				R_DrawElements( numIndexes, hitIndexes );
				backEnd.pc.c_totalIndexes += numIndexes;
				backEnd.pc.c_dlightIndexes += numIndexes;
			}
		} else {
			R_FogOff();
			if ( !vertexLight ) {
				GL_Bind( tr.dlightImage );
			} else {
				GL_Bind( tr.whiteImage );
			}
			// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
			// where they aren't rendered
			if ( dl->flags & REF_ADDITIVE_DLIGHT ) {
				GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
			}
			else {
				GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
			}
			R_DrawElements( numIndexes, hitIndexes );
			backEnd.pc.c_totalIndexes += numIndexes;
			backEnd.pc.c_dlightIndexes += numIndexes;
			RB_FogOn();
		}
	}
}
Exemple #22
0
void CQuickSpriteSystem::Flush(void)
{
	if (mNextVert==0)
	{
		return;
	}

	/*
	if (mUseFog && r_drawfog->integer == 2 &&
		mFogIndex == tr.world->globalFog)
	{ //enable hardware fog when we draw this thing if applicable -rww
		fog_t *fog = tr.world->fogs + mFogIndex;

#ifdef _XBOX
		qglFogi(GL_FOG_MODE, GL_EXP2);
#else
		qglFogf(GL_FOG_MODE, GL_EXP2);
#endif
		qglFogf(GL_FOG_DENSITY, logtestExp2 / fog->parms.depthForOpaque);
		qglFogfv(GL_FOG_COLOR, fog->parms.color);
		qglEnable(GL_FOG);
	}
	*/
	//this should not be needed, since I just wait to disable fog for the surface til after surface sprites are done

	//
	// render the main pass
	//
	R_BindAnimatedImage( mTexBundle );
	GL_State(mGLStateBits);

	//
	// set arrays and lock
	//
	qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
	qglTexCoordPointer( 2, GL_FLOAT, 0, mTextureCoords );

	qglEnableClientState( GL_COLOR_ARRAY);
	qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, mColors );

	qglVertexPointer (3, GL_FLOAT, 16, mVerts);

	if ( qglLockArraysEXT )
	{
		qglLockArraysEXT(0, mNextVert);
		GLimp_LogComment( "glLockArraysEXT\n" );
	}

	qglDrawArrays(GL_QUADS, 0, mNextVert);

	backEnd.pc.c_vertexes += mNextVert;
	backEnd.pc.c_indexes += mNextVert;
	backEnd.pc.c_totalIndexes += mNextVert;

	//only for software fog pass (global soft/volumetric) -rww
	if (mUseFog && (r_drawfog->integer != 2 || mFogIndex != tr.world->globalFog))
	{
		fog_t *fog = tr.world->fogs + mFogIndex;

		//
		// render the fog pass
		//
		GL_Bind( tr.fogImage );
		GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );

		//
		// set arrays and lock
		//
		qglTexCoordPointer( 2, GL_FLOAT, 0, mFogTextureCoords);
//		qglEnableClientState( GL_TEXTURE_COORD_ARRAY);	// Done above

		qglDisableClientState( GL_COLOR_ARRAY );
		qglColor4ubv((GLubyte *)&fog->colorInt);

//		qglVertexPointer (3, GL_FLOAT, 16, mVerts);	// Done above

		qglDrawArrays(GL_QUADS, 0, mNextVert);

		// Second pass from fog
		backEnd.pc.c_totalIndexes += mNextVert;
	}

	// 
	// unlock arrays
	//
	if (qglUnlockArraysEXT) 
	{
		qglUnlockArraysEXT();
		GLimp_LogComment( "glUnlockArraysEXT\n" );
	}

	mNextVert=0;
}
Exemple #23
0
/*
===================
RB_FogPass

Blends a fog texture on top of everything else
===================
*/
static void RB_FogPass( void ) {
	fog_t		*fog;
	unsigned	colorInt;
	fogType_t	fogType;
	int			i;

	// no world, no fogging
	if ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) {
		return;
	}

	if ( r_useGlFog->integer ) {
		return;
	}

	if ( tess.shader->isSky ) {
		fogType = tr.skyFogType;
		colorInt = tr.skyFogColorInt;
	} else {
		fog = tr.world->fogs + tess.fogNum;

		// Global fog
		if ( fog->originalBrushNumber < 0 ) {
			fogType = backEnd.refdef.fogType;
			colorInt = backEnd.refdef.fogColorInt;
		} else {
			fogType = fog->shader->fogParms.fogType;
			colorInt = fog->colorInt;
		}
	}

	if ( fogType == FT_NONE ) {
		return;
	}

	// check if any stage is fogged
	if ( tess.shader->noFog ) {
		int i;

		for ( i = 0 ; i < MAX_SHADER_STAGES; i++ ) {
			shaderStage_t *pStage = tess.xstages[i];

			if ( !pStage ) {
				return;
			}

			if ( pStage->isFogged ) {
				break;
			}
		}
	}

	qglEnableClientState( GL_COLOR_ARRAY );
	qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );

	qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
	qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );

	for ( i = 0; i < tess.numVertexes; i++ ) {
		* ( int * )&tess.svars.colors[i] = colorInt;
	}

	RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] );

	if ( fogType == FT_LINEAR ) {
		GL_Bind( tr.linearFogImage );
	} else {
		GL_Bind( tr.fogImage );
	}

	if ( tess.shader->fogPass == FP_EQUAL ) {
		GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
	} else {
		GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
	}

	R_DrawElements( tess.numIndexes, tess.indexes );
}
/*
=============
RE_StretchRaw

FIXME: not exactly backend
Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
Used for cinematics.
=============
*/
void RE_StretchRaw( int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty ) {
	int i, j;
	int start, end;

	if ( !tr.registered ) {
		return;
	}
	R_IssuePendingRenderCommands();

	if ( tess.numIndexes ) {
		RB_EndSurface();
	}

	// we definately want to sync every frame for the cinematics
	qglFinish();

	start = 0;
	if ( r_speeds->integer ) {
		start = ri.Milliseconds();
	}

	// make sure rows and cols are powers of 2
	for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
	}
	for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
	}
	if ( ( 1 << i ) != cols || ( 1 << j ) != rows ) {
		ri.Error( ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows );
	}

	GL_Bind( tr.scratchImage[client] );

	// if the scratchImage isn't in the format we want, specify it as a new texture
	if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
		tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
		tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
#ifdef USE_OPENGLES
		qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
#else
		qglTexImage2D( GL_TEXTURE_2D, 0, 3, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
#endif
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
	} else {
		if ( dirty ) {
			// otherwise, just subimage upload it so that drivers can tell we are going to be changing
			// it and don't try and do a texture compression
			qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
		}
	}

	if ( r_speeds->integer ) {
		end = ri.Milliseconds();
		ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
	}

	RB_SetGL2D();

	qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );

#ifdef USE_OPENGLES
	GLfloat tex[] = {
	 0.5f / cols,  0.5f / rows,
	 ( cols - 0.5f ) / cols ,  0.5f / rows,
	 ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows,
	 0.5f / cols, ( rows - 0.5f ) / rows };
	GLfloat vtx[] = {
	 x, y,
	 x+w, y,
	 x+w, y+h,
	 x, y+h };
	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 );
	qglTexCoordPointer( 2, GL_FLOAT, 0, tex );
	qglVertexPointer  ( 2, GL_FLOAT, 0, vtx );
	qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
	if (!text)
		qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
	if (glcol)
		qglEnableClientState(GL_COLOR_ARRAY);
#else
	qglBegin( GL_QUADS );
	qglTexCoord2f( 0.5f / cols,  0.5f / rows );
	qglVertex2f( x, y );
	qglTexCoord2f( ( cols - 0.5f ) / cols,  0.5f / rows );
	qglVertex2f( x + w, y );
	qglTexCoord2f( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows );
	qglVertex2f( x + w, y + h );
	qglTexCoord2f( 0.5f / cols, ( rows - 0.5f ) / rows );
	qglVertex2f( x, y + h );
	qglEnd();
#endif
}
Exemple #25
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((float) surface->numVerts * lodScale);

	}
	else
	{
		render_count = ROUND_INT((float) 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 * 3);

//DBG_SHOWTIME

	// setup triangle list

//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)
	{
		for (j = 0; j < indexes; j++)
		{
			pIndexes[j] = triangles[j] + 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);
#if 0
				// TODO: OpenGL ES renderer
				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();
#endif // 0
				// connect to our parent if it's valid
				if (validBones[boneInfo[*boneRefs].parent])
				{
					qglLineWidth(2);
#if 0
					// TODO: OpenGL ES renderer
					qglBegin(GL_LINES);
					qglColor3f(.6, .6, .6);
					qglVertex3fv(bonePtr->translation);
					qglVertex3fv(bones[boneInfo[*boneRefs].parent].translation);
					qglEnd();
#endif
				}

				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);
#if 0
			// TODO: OpenGL ES renderer
			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();
#endif // 0

			// 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
}
/*
===============
RB_ShowImages

Draw all the images to the screen, on top of whatever
was there.  This is used to test for texture thrashing.

Also called by RE_EndRegistration
===============
*/
void RB_ShowImages( void ) {
	int i;
	image_t *image;
	float x, y, w, h;
	int start, end;

	if ( !backEnd.projection2D ) {
		RB_SetGL2D();
	}

	qglClear( GL_COLOR_BUFFER_BIT );

	qglFinish();


	start = ri.Milliseconds();

	for ( i = 0 ; i < tr.numImages ; i++ ) {
		image = tr.images[i];

		w = glConfig.vidWidth / 40;
		h = glConfig.vidHeight / 30;

		x = i % 40 * w;
		y = i / 30 * h;

		// show in proportional size in mode 2
		if ( r_showImages->integer == 2 ) {
			w *= image->uploadWidth / 512.0f;
			h *= image->uploadHeight / 512.0f;
		}

#ifdef USE_OPENGLES
		GLfloat tex[] = {
		 0, 0, 
		 1, 0,
		 1, 1, 
		 0, 1 };
		GLfloat vtx[] = {
		 x, y,
		 x + w, y,
		 x + w, y + h,
		 x, y + h };
		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 );
		qglTexCoordPointer( 2, GL_FLOAT, 0, tex );
		qglVertexPointer  ( 2, GL_FLOAT, 0, vtx );
		qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
		if (glcol)
			qglEnableClientState(GL_COLOR_ARRAY);
		if (!text)
			qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
#else
		GL_Bind( image );
		qglBegin( GL_QUADS );
		qglTexCoord2f( 0, 0 );
		qglVertex2f( x, y );
		qglTexCoord2f( 1, 0 );
		qglVertex2f( x + w, y );
		qglTexCoord2f( 1, 1 );
		qglVertex2f( x + w, y + h );
		qglTexCoord2f( 0, 1 );
		qglVertex2f( x, y + h );
		qglEnd();
#endif
	}

	qglFinish();

	end = ri.Milliseconds();
	ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start );

}
Exemple #27
0
/*
=============
RE_StretchRaw

FIXME: not exactly backend
Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
Used for cinematics.
=============
*/
void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
	int			i, j;
	int			start, end;

	if ( !tr.registered ) {
		return;
	}
	R_SyncRenderThread();

	// we definately want to sync every frame for the cinematics
	qglFinish();

	start = 0;
	if ( r_speeds->integer ) {
		start = ri.Milliseconds();
	}

	// make sure rows and cols are powers of 2
	for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
	}
	for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
	}
	if ( ( 1 << i ) != cols || ( 1 << j ) != rows) {
		ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
	}

	GL_Bind( tr.scratchImage[client] );

	// if the scratchImage isn't in the format we want, specify it as a new texture
	if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
		tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
		tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
		qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );	
	} else {
		if (dirty) {
			// otherwise, just subimage upload it so that drivers can tell we are going to be changing
			// it and don't try and do a texture compression
			qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
		}
	}

	if ( r_speeds->integer ) {
		end = ri.Milliseconds();
		ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
	}

	RB_SetGL2D();

	qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );

	qglBegin (GL_QUADS);
	qglTexCoord2f ( 0.5f / cols,  0.5f / rows );
	qglVertex2f (x, y);
	qglTexCoord2f ( ( cols - 0.5f ) / cols ,  0.5f / rows );
	qglVertex2f (x+w, y);
	qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows );
	qglVertex2f (x+w, y+h);
	qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows );
	qglVertex2f (x, y+h);
	qglEnd ();
}
Exemple #28
0
void R_Bloom_Process(void)
{
	int p;
    GLint loc;

	if(!bloom_initialized)
		return;

	if(!gl_bloom.value)
		return;


	// pass filter into pass0[0]
    glUseProgram(passProg);
    loc = glGetUniformLocation(passProg, "source");
    glUniform1i(loc, 0);
    glEnable(GL_TEXTURE_2D);
	GL_Bind(scenebase.texture);
    phBindSurface(pass0, false);
	glBegin(GL_QUADS);
    glTexCoord2i(0, 0); glVertex2i(-1, -1);
	glTexCoord2i(0, 1); glVertex2i(-1, 1);
	glTexCoord2i(1, 1); glVertex2i(1, 1);
    glTexCoord2i(1, 0); glVertex2i(1, -1);
    glEnd();
    glUseProgram(0);


	// downsample the scene into the source surfaces
	glEnable(GL_TEXTURE_2D);
	GL_Bind(pass0[0].texture);

	for (p = 1; p < BLOOM_FILTER_COUNT; p++)
    {
        phBindSurface(pass0 + p, false);

		glBegin(GL_QUADS);
        glTexCoord2i(0, 0); glVertex2i(-1, -1);
		glTexCoord2i(0, 1); glVertex2i(-1, 1);
		glTexCoord2i(1, 1); glVertex2i(1, 1);
        glTexCoord2i(1, 0); glVertex2i(1, -1);
        glEnd();
    }
	

    // perform the horizontal blurring pass.
    blur(pass0, pass1, BLOOM_FILTER_COUNT, 1.0f, HORIZONTAL);

	// perform the vertical blurring pass.
    blur(pass1, pass0, BLOOM_FILTER_COUNT, 1.0f, VERTICAL);


	glUseProgram(combineProg);
    for (p = 0; p < BLOOM_FILTER_COUNT; p++)
    {
        char name[] = "Pass#";

        glActiveTexture(GL_TEXTURE0 + p);
		glEnable(GL_TEXTURE_2D);
		GL_Bind(pass0[p].texture);

        sprintf(name, "Pass%d", p);
        loc = glGetUniformLocation(combineProg, name);
        glUniform1i(loc, p);
    }


	// combine original scene
	glActiveTexture(GL_TEXTURE0 + BLOOM_FILTER_COUNT);

	if(cl.worldmodel && r_viewleaf->contents <= CONTENTS_WATER)
		GL_Bind(scenepass0.texture);
	else
		GL_Bind(scenebase.texture);

	glEnable(GL_TEXTURE_2D);
    loc = glGetUniformLocation(combineProg, "Scene");
    glUniform1i(loc, BLOOM_FILTER_COUNT);
}
Exemple #29
0
void RB_DoShadowTessEnd( vec3_t lightPos )
{
	int		i;
	int		numTris;
	vec3_t	lightDir;

	// we can only do this if we have enough space in the vertex buffers
	if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) {
		return;
	}

	if ( glConfig.stencilBits < 4 ) {
		return;
	}

#if 1 //controlled method - try to keep shadows in range so they don't show through so much -rww
	vec3_t	worldxyz;
	vec3_t	entLight;
	float	groundDist;

	VectorCopy( backEnd.currentEntity->lightDir, entLight );
	entLight[2] = 0.0f;
	VectorNormalize(entLight);

	//Oh well, just cast them straight down no matter what onto the ground plane.
	//This presets no chance of screwups and still looks better than a stupid
	//shader blob.
	VectorSet(lightDir, entLight[0]*0.3f, entLight[1]*0.3f, 1.0f);
	// project vertexes away from light direction
	for ( i = 0 ; i < tess.numVertexes ; i++ ) {
		//add or.origin to vert xyz to end up with world oriented coord, then figure
		//out the ground pos for the vert to project the shadow volume to
		VectorAdd(tess.xyz[i], backEnd.ori.origin, worldxyz);
		groundDist = worldxyz[2] - backEnd.currentEntity->e.shadowPlane;
		groundDist += 16.0f; //fudge factor
		VectorMA( tess.xyz[i], -groundDist, lightDir, tess.xyz[i+tess.numVertexes] );
	}
#else
	if (lightPos)
	{
		for ( i = 0 ; i < tess.numVertexes ; i++ )
		{
			tess.xyz[i+tess.numVertexes][0] = tess.xyz[i][0]+(( tess.xyz[i][0]-lightPos[0] )*128.0f);
			tess.xyz[i+tess.numVertexes][1] = tess.xyz[i][1]+(( tess.xyz[i][1]-lightPos[1] )*128.0f);
			tess.xyz[i+tess.numVertexes][2] = tess.xyz[i][2]+(( tess.xyz[i][2]-lightPos[2] )*128.0f);
		}
	}
	else
	{
		VectorCopy( backEnd.currentEntity->lightDir, lightDir );

		// project vertexes away from light direction
		for ( i = 0 ; i < tess.numVertexes ; i++ ) {
			VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] );
		}
	}
#endif
	// decide which triangles face the light
	memset( numEdgeDefs, 0, 4 * tess.numVertexes );

	numTris = tess.numIndexes / 3;
	for ( i = 0 ; i < numTris ; i++ ) {
		int		i1, i2, i3;
		vec3_t	d1, d2, normal;
		float	*v1, *v2, *v3;
		float	d;

		i1 = tess.indexes[ i*3 + 0 ];
		i2 = tess.indexes[ i*3 + 1 ];
		i3 = tess.indexes[ i*3 + 2 ];

		v1 = tess.xyz[ i1 ];
		v2 = tess.xyz[ i2 ];
		v3 = tess.xyz[ i3 ];

		if (!lightPos)
		{
			VectorSubtract( v2, v1, d1 );
			VectorSubtract( v3, v1, d2 );
			CrossProduct( d1, d2, normal );

			d = DotProduct( normal, lightDir );
		}
		else
		{
			float planeEq[4];
			planeEq[0] = v1[1]*(v2[2]-v3[2]) + v2[1]*(v3[2]-v1[2]) + v3[1]*(v1[2]-v2[2]);
			planeEq[1] = v1[2]*(v2[0]-v3[0]) + v2[2]*(v3[0]-v1[0]) + v3[2]*(v1[0]-v2[0]);
			planeEq[2] = v1[0]*(v2[1]-v3[1]) + v2[0]*(v3[1]-v1[1]) + v3[0]*(v1[1]-v2[1]);
			planeEq[3] = -( v1[0]*( v2[1]*v3[2] - v3[1]*v2[2] ) +
						v2[0]*(v3[1]*v1[2] - v1[1]*v3[2]) +
						v3[0]*(v1[1]*v2[2] - v2[1]*v1[2]) );

			d = planeEq[0]*lightPos[0]+
				planeEq[1]*lightPos[1]+
				planeEq[2]*lightPos[2]+
				planeEq[3];
		}

		if ( d > 0 ) {
			facing[ i ] = 1;
		} else {
			facing[ i ] = 0;
		}

		// create the edges
		R_AddEdgeDef( i1, i2, facing[ i ] );
		R_AddEdgeDef( i2, i3, facing[ i ] );
		R_AddEdgeDef( i3, i1, facing[ i ] );
	}

	GL_Bind( tr.whiteImage );
	//qglEnable( GL_CULL_FACE );
	GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );

#ifndef _DEBUG_STENCIL_SHADOWS
	qglColor3f( 0.2f, 0.2f, 0.2f );

	// don't write to the color buffer
	qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );

	qglEnable( GL_STENCIL_TEST );
	qglStencilFunc( GL_ALWAYS, 1, 255 );
#else
	qglColor3f( 1.0f, 0.0f, 0.0f );
	qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	//qglDisable(GL_DEPTH_TEST);
#endif

#ifdef _STENCIL_REVERSE
	qglDepthFunc(GL_LESS);

	//now using the Carmack Reverse<tm> -rww
	if ( backEnd.viewParms.isMirror ) {
		//qglCullFace( GL_BACK );
		GL_Cull(CT_BACK_SIDED);
		qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP );

		R_RenderShadowEdges();

		//qglCullFace( GL_FRONT );
		GL_Cull(CT_FRONT_SIDED);
		qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP );

		R_RenderShadowEdges();
	} else {
		//qglCullFace( GL_FRONT );
		GL_Cull(CT_FRONT_SIDED);
		qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP );

		R_RenderShadowEdges();

		//qglCullFace( GL_BACK );
		GL_Cull(CT_BACK_SIDED);
		qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP );

		R_RenderShadowEdges();
	}

	qglDepthFunc(GL_LEQUAL);
#else
	// mirrors have the culling order reversed
	if ( backEnd.viewParms.isMirror ) {
		qglCullFace( GL_FRONT );
		qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );

		R_RenderShadowEdges();

		qglCullFace( GL_BACK );
		qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );

		R_RenderShadowEdges();
	} else {
		qglCullFace( GL_BACK );
		qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );

		R_RenderShadowEdges();

		qglCullFace( GL_FRONT );
		qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );

		R_RenderShadowEdges();
	}
#endif

	// reenable writing to the color buffer
	qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );

#ifdef _DEBUG_STENCIL_SHADOWS
	qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
}
/*
=================
R_DrawSpriteModel

=================
*/
void R_DrawSpriteModel (entity_t *e)
{
	vec3_t	point;
	mspriteframe_t	*frame;
	float		*up, *right;
	vec3_t		v_forward, v_right, v_up;
	msprite_t		*psprite;

	// don't even bother culling, because it's just a single
	// polygon without a surface cache
	frame = R_GetSpriteFrame (e);
	psprite = (msprite_t*) currententity->model->cache.data;

	if (psprite->type == SPR_ORIENTED)
	{	// bullet marks on walls
		AngleVectors (currententity->angles, v_forward, v_right, v_up);
		up = v_up;
		right = v_right;
	}
	else
	{	// normal sprite
		up = vup;
		right = vright;
	}

	glColor3f (1,1,1);

	GL_DisableMultitexture();

    GL_Bind(frame->gl_texturenum);

	glEnable (GL_ALPHA_TEST);

#ifdef USE_OPENGLES

	{
	    float* pPoint = gVertexBuffer;
	    float texCoords[] = {
			0, 1,
			0, 0,
			1, 0,
			1, 1
		};

		VectorMA (e->origin, frame->down, up, point);
		VectorMA (point, frame->left, right, pPoint);
		pPoint += 3;

		VectorMA (e->origin, frame->up, up, point);
		VectorMA (point, frame->left, right, pPoint);
		pPoint += 3;

		VectorMA (e->origin, frame->up, up, point);
		VectorMA (point, frame->right, right, pPoint);
		pPoint += 3;

		VectorMA (e->origin, frame->down, up, point);
		VectorMA (point, frame->right, right, pPoint);

		glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
		glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
	}

#else
	glBegin (GL_QUADS);

	glTexCoord2f (0, 1);
	VectorMA (e->origin, frame->down, up, point);
	VectorMA (point, frame->left, right, point);
	glVertex3fv (point);

	glTexCoord2f (0, 0);
	VectorMA (e->origin, frame->up, up, point);
	VectorMA (point, frame->left, right, point);
	glVertex3fv (point);

	glTexCoord2f (1, 0);
	VectorMA (e->origin, frame->up, up, point);
	VectorMA (point, frame->right, right, point);
	glVertex3fv (point);

	glTexCoord2f (1, 1);
	VectorMA (e->origin, frame->down, up, point);
	VectorMA (point, frame->right, right, point);
	glVertex3fv (point);

	glEnd ();
#endif

	glDisable (GL_ALPHA_TEST);
}