Exemple #1
0
/* <84171> ../engine/r_studio.c:1351 */
void EXT_FUNC GetAttachment(const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles)
{
	mstudioattachment_t *pattachment;
	vec3_t angles;

	angles[0] = -pEdict->v.angles[0];
	angles[1] = pEdict->v.angles[1];
	angles[2] = pEdict->v.angles[2];
	
	pstudiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[pEdict->v.modelindex]);
	pattachment = (mstudioattachment_t *)((char *)pstudiohdr + pstudiohdr->attachmentindex);
	pattachment += iAttachment;

	g_pSvBlendingAPI->SV_StudioSetupBones(
		g_psv.models[pEdict->v.modelindex],
		pEdict->v.frame,
		pEdict->v.sequence,
		angles,
		pEdict->v.origin,
		pEdict->v.controller,
		pEdict->v.blending,
		pattachment->bone,
		pEdict
	);

	if (rgflOrigin)
		VectorTransform(pattachment->org, (float *)bonetransform[pattachment->bone], rgflOrigin);
}
Exemple #2
0
/*
================
R_AliasDrawModel
================
*/
void R_AliasDrawModel(alight_t *plighting)
{
	finalvert_t		finalverts[MAXALIASVERTS +
							   ((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1];
	auxvert_t		auxverts[MAXALIASVERTS];

	r_amodels_drawn++;

// cache align
	pfinalverts = (finalvert_t *)
				  (((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
	pauxverts = &auxverts[0];

	paliashdr = (aliashdr_t *)Mod_Extradata(currententity->model);
	pmdl = (mdl_t *)((byte *)paliashdr + paliashdr->model);

	R_AliasSetupSkin();
	R_AliasSetUpTransform(currententity->trivial_accept);
	R_AliasSetupLighting(plighting);
	R_AliasSetupFrame();

	if (!currententity->colormap)
	{
		Sys_Error("R_AliasDrawModel: !currententity->colormap");
	}

	r_affinetridesc.drawtype = (currententity->trivial_accept == 3) &&
							   r_recursiveaffinetriangles;

	if (r_affinetridesc.drawtype)
	{
		D_PolysetUpdateTables();		// FIXME: precalc...
	}
	else
	{
#if	id386
		D_Aff8Patch(currententity->colormap);
#endif
	}

	acolormap = currententity->colormap;

	if (currententity != &cl.viewent)
	{
		ziscale = (float)0x8000 * (float)0x10000;
	}
	else
	{
		ziscale = (float)0x8000 * (float)0x10000 * 3.0;
	}

	if (currententity->trivial_accept)
	{
		R_AliasPrepareUnclippedPoints();
	}
	else
	{
		R_AliasPreparePoints();
	}
}
Exemple #3
0
/* <8402e> ../engine/r_studio.c:1264 */
qboolean SV_CheckSphereIntersection(edict_t *ent, const vec_t *start, const vec_t *end)
{
	studiohdr_t *studiohdr;
	mstudioseqdesc_t *pseqdesc;

	vec3_t traceOrg;
	vec3_t traceDir;
	float radiusSquared;
	vec3_t maxDim;

	radiusSquared = 0.0f;
	if (!(ent->v.flags & FL_CLIENT))
		return 1;

	traceOrg[0] = start[0];
	traceOrg[1] = start[1];
	traceOrg[2] = start[2];
	traceDir[0] = end[0] - start[0];
	traceDir[1] = end[1] - start[1];
	traceDir[2] = end[2] - start[2];

	studiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[ent->v.modelindex]);
	pseqdesc = (mstudioseqdesc_t *)((char *)studiohdr + studiohdr->seqindex);
	pseqdesc += ent->v.sequence;
	for (int i = 0; i < 3; i++)
	{
		maxDim[i] = max(fabs(pseqdesc->bbmax[i]), fabs(pseqdesc->bbmin[i]));
	}
	radiusSquared = maxDim[0] * maxDim[0] + maxDim[1] * maxDim[1] + maxDim[2] * maxDim[2];
	return DoesSphereIntersect(ent->v.origin, radiusSquared, traceOrg, traceDir) != 0;
}
Exemple #4
0
/* <83a1c> ../engine/r_studio.c:844 */
hull_t *R_StudioHull(model_t *pModel, float frame, int sequence, const vec_t *angles, const vec_t *origin, const vec_t *size, const unsigned char *pcontroller, const unsigned char *pblending, int *pNumHulls, const edict_t *pEdict, int bSkipShield)
{
	SV_InitStudioHull();

	if (r_cachestudio.value != 0)
	{
#ifdef SWDS
		Sys_Error(__FUNCTION__ ": Studio state caching is not used on server");
#endif
		// TODO: Reverse for client-side
	}

	pstudiohdr = (studiohdr_t*)Mod_Extradata(pModel);

	vec_t angles2[3] = { -angles[0], angles[1], angles[2] };
	g_pSvBlendingAPI->SV_StudioSetupBones(pModel, frame, sequence, angles2, origin, pcontroller, pblending, -1, pEdict);

	mstudiobbox_t* pbbox = (mstudiobbox_t *)((char *)pstudiohdr + pstudiohdr->hitboxindex);
	for (int i = 0; i < pstudiohdr->numhitboxes; i++)
	{
		if (bSkipShield && i == 21) continue;

		studio_hull_hitgroup[i] = pbbox[i].group;

		for (int j = 0; j < 3; j++)
		{
			mplane_t* plane0 = &studio_planes[i * 6 + j * 2 + 0];
			mplane_t* plane1 = &studio_planes[i * 6 + j * 2 + 1];
			SV_SetStudioHullPlane(plane0, pbbox[i].bone, j, pbbox[i].bbmax[j]);
			SV_SetStudioHullPlane(plane1, pbbox[i].bone, j, pbbox[i].bbmin[j]);

			plane0->dist += fabs(plane0->normal[0] * size[0]) + fabs(plane0->normal[1] * size[1]) + fabs(plane0->normal[2] * size[2]);
			plane1->dist -= fabs(plane1->normal[0] * size[0]) + fabs(plane1->normal[1] * size[1]) + fabs(plane1->normal[2] * size[2]);
		}
	}

	*pNumHulls = (bSkipShield == 1) ? pstudiohdr->numhitboxes - 1 : pstudiohdr->numhitboxes;
	if (r_cachestudio.value != 0)
	{
#ifdef SWDS
		Sys_Error(__FUNCTION__ ": Studio state caching is not used on server");
#endif
		// TODO: Reverse for client-side
		//	R_AddToStudioCache(float frame,
		//		int sequence,
		//		const vec_t *angles,
		//		const vec_t *origin,
		//		const vec_t *size,
		//		const unsigned char *controller,
		//		const unsigned char *pblending,
		//		model_t *pModel,
		//		hull_t *pHulls,
		//		int numhulls); /* size=0, low_pc=0 */ //   917
	}

	return &studio_hull[0];
}
Exemple #5
0
void R_DrawAliasBatchPass (entity_t **ents, int numents, qbool showtris)
{
    int i;
    gltexture_t *lasttexture = NULL;
    gltexture_t *lastfullbright = NULL;

    if (!numents)
        return;

    if (showtris)
        GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_REPLACE);
    else if (gl_overbright.value)
        GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_RGB_SCALE_ARB);
    else
        GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_MODULATE);

    for (i = 0; i < numents; i++)
    {
        entity_t *ent = ents[i];
        aliasstate_t *state = &ent->aliasstate;
        aliashdr_t *hdr = Mod_Extradata (ent->model);

        // we need a separate test for culling here as r_shadows mode doesn't cull
        if (ent->visframe != r_framecount)
            continue;

        if (!showtris && ((state->tx != lasttexture) || (state->fb != lastfullbright)))
        {
            if (state->fb)
            {
                GL_TexEnv (GL_TEXTURE1_ARB, GL_TEXTURE_2D, GL_ADD);
                GL_BindTexture (GL_TEXTURE1_ARB, state->fb);
            }
            else
                GL_TexEnv (GL_TEXTURE1_ARB, GL_TEXTURE_2D, GL_NONE);

            GL_BindTexture (GL_TEXTURE0_ARB, state->tx);

            lasttexture = state->tx;
            lastfullbright = state->fb;
        }

        // OK, this works better in GL... go figure...
        R_DrawAliasModel (ent, hdr, state, showtris);
    }

    GL_TexEnv (GL_TEXTURE1_ARB, GL_TEXTURE_2D, GL_NONE);
    GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_REPLACE);

    qglColor4f (1, 1, 1, 1);

    // go back to the world matrix
    qglLoadMatrixf (r_world_matrix.m16);
}
Exemple #6
0
/*
=============
GL_DrawAliasShadow -- johnfitz -- rewritten

TODO: orient shadow onto "lightplane" (a global mplane_t*)
=============
*/
void GL_DrawAliasShadow (entity_t *e)
{
	float	shadowmatrix[16] = {1,				0,				0,				0,
								0,				1,				0,				0,
								SHADOW_SKEW_X,	SHADOW_SKEW_Y,	SHADOW_VSCALE,	0,
								0,				0,				SHADOW_HEIGHT,	1};
	float		lheight;
	aliashdr_t	*paliashdr;
	lerpdata_t	lerpdata;

	if (R_CullModelForEntity(e))
		return;

	if (e == &cl.viewent || e->model->flags & MOD_NOSHADOW)
		return;

	entalpha = ENTALPHA_DECODE(e->alpha);
	if (entalpha == 0) return;

	paliashdr = (aliashdr_t *)Mod_Extradata (e->model);
	R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
	R_SetupEntityTransform (e, &lerpdata);
	R_LightPoint (e->origin);
	lheight = currententity->origin[2] - lightspot[2];

// set up matrix
    glPushMatrix ();
	glTranslatef (lerpdata.origin[0],  lerpdata.origin[1],  lerpdata.origin[2]);
	glTranslatef (0,0,-lheight);
	glMultMatrixf (shadowmatrix);
	glTranslatef (0,0,lheight);
	glRotatef (lerpdata.angles[1],  0, 0, 1);
	glRotatef (-lerpdata.angles[0],  0, 1, 0);
	glRotatef (lerpdata.angles[2],  1, 0, 0);
	glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
	glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);

// draw it
	glDepthMask(GL_FALSE);
	glEnable (GL_BLEND);
	GL_DisableMultitexture ();
	glDisable (GL_TEXTURE_2D);
	shading = false;
	glColor4f(0,0,0,entalpha * 0.5);
	GL_DrawAliasFrame (paliashdr, lerpdata);
	glEnable (GL_TEXTURE_2D);
	glDisable (GL_BLEND);
	glDepthMask(GL_TRUE);

//clean up
	glPopMatrix ();
}
Exemple #7
0
static void
PrintFrameName(model_t *m, int frame)
{
    aliashdr_t *hdr;
    maliasframedesc_t *pframedesc;

    hdr = Mod_Extradata(m);
    if (!hdr)
	return;
    pframedesc = &hdr->frames[frame];

    Con_Printf("frame %i: %s\n", frame, pframedesc->name);
}
Exemple #8
0
/*
====================
StudioGetAttachment
====================
*/
void Mod_StudioGetAttachment( const edict_t *e, int iAttachment, float *origin, float *angles )
{
	mstudioattachment_t		*pAtt;
	vec3_t			angles2;
	model_t			*mod;

	mod = Mod_Handle( e->v.modelindex );
	mod_studiohdr = (studiohdr_t *)Mod_Extradata( mod );
	if( !mod_studiohdr ) return;

	if( mod_studiohdr->numattachments <= 0 )
		return;

	ASSERT( pBlendAPI != NULL );

	if( mod_studiohdr->numattachments > MAXSTUDIOATTACHMENTS )
	{
		mod_studiohdr->numattachments = MAXSTUDIOATTACHMENTS; // reduce it
		MsgDev( D_WARN, "SV_StudioGetAttahment: too many attachments on %s\n", mod_studiohdr->name );
	}

	iAttachment = bound( 0, iAttachment, mod_studiohdr->numattachments );

	// calculate attachment origin and angles
	pAtt = (mstudioattachment_t *)((byte *)mod_studiohdr + mod_studiohdr->attachmentindex);

	VectorCopy( e->v.angles, angles2 );

	if( !( host.features & ENGINE_COMPENSATE_QUAKE_BUG ))
		angles2[PITCH] = -angles2[PITCH];

	pBlendAPI->SV_StudioSetupBones( mod, e->v.frame, e->v.sequence, angles2, e->v.origin,
		e->v.controller, e->v.blending, pAtt[iAttachment].bone, e );

	// compute pos and angles
	if( origin != NULL )
		Matrix3x4_VectorTransform( studio_bones[pAtt[iAttachment].bone], pAtt[iAttachment].org, origin );

	if( sv_allow_studio_attachment_angles->integer && origin != NULL && angles != NULL )
	{
		vec3_t	forward, bonepos;

		Matrix3x4_OriginFromMatrix( studio_bones[pAtt[iAttachment].bone], bonepos );
		VectorSubtract( origin, bonepos, forward ); // make forward
		VectorNormalizeFast( forward );
		VectorAngles( forward, angles );
	}
}
Exemple #9
0
/*
================
GLMesh_LoadVertexBuffers

Loop over all precached alias models, and upload each one to a VBO.
================
*/
void GLMesh_LoadVertexBuffers (void)
{
	int j;
	qmodel_t *m;
	const aliashdr_t *hdr;

	for (j = 1; j < MAX_MODELS; j++)
	{
		if (!(m = cl.model_precache[j])) break;
		if (m->type != mod_alias) continue;

		hdr = (const aliashdr_t *) Mod_Extradata (m);
		
		GLMesh_LoadVertexBuffer (m, hdr);
	}
}
Exemple #10
0
/*
====================
GetBonePosition
====================
*/
void Mod_GetBonePosition( const edict_t *e, int iBone, float *origin, float *angles )
{
	model_t	*mod;

	mod = Mod_Handle( e->v.modelindex );
	mod_studiohdr = (studiohdr_t *)Mod_Extradata( mod );
	if( !mod_studiohdr ) return;

	ASSERT( pBlendAPI != NULL );

	pBlendAPI->SV_StudioSetupBones( mod, e->v.frame, e->v.sequence, e->v.angles, e->v.origin,
		e->v.controller, e->v.blending, iBone, e );

	if( origin ) Matrix3x4_OriginFromMatrix( studio_bones[iBone], origin );
	if( angles ) VectorAngles( studio_bones[iBone][0], angles ); // bone forward to angles
}
Exemple #11
0
/* <83db3> ../engine/r_studio.c:957 */
int R_StudioBodyVariations(model_t *model)
{
	if (model->type != mod_studio)
		return 0;

	studiohdr_t *shdr = (studiohdr_t *)Mod_Extradata(model);
	if (!shdr)
		return 0;

	int count = 1;
	mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((char *)shdr + shdr->bodypartindex);
	for (int i = 0; i < shdr->numbodyparts; i++, pbodypart++)
	{
		count *= pbodypart->nummodels;
	}

	return count;
}
Exemple #12
0
/* <8411a> ../engine/r_studio.c:1329 */
void EXT_FUNC GetBonePosition(const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles)
{
	pstudiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[pEdict->v.modelindex]);
	g_pSvBlendingAPI->SV_StudioSetupBones(
		g_psv.models[pEdict->v.modelindex],
		pEdict->v.frame,
		pEdict->v.sequence,
		pEdict->v.angles,
		pEdict->v.origin,
		pEdict->v.controller,
		pEdict->v.blending,
		iBone,
		pEdict
	);

	if (rgflOrigin)
	{
		rgflOrigin[0] = bonetransform[iBone][0][3];
		rgflOrigin[1] = bonetransform[iBone][1][3];
		rgflOrigin[2] = bonetransform[iBone][2][3];
	}
}
Exemple #13
0
/*
===========
R_AddEfrags
===========
*/
void R_AddEfrags( cl_entity_t *ent )
{
	int	i;
		
	if( !ent->model )
		return;

	r_addent = ent;
	lastlink = &ent->efrag;
	r_pefragtopnode = NULL;

	// NOTE: can't copy these bounds directly into model->mins\model->maxs
	// because all other code don't expected this
	if( ent->model->type == mod_studio )
	{
		studiohdr_t *phdr = (studiohdr_t *)Mod_Extradata( ent->model );
		mstudioseqdesc_t *pseqdesc;

		if( !phdr ) return;
		pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex);

		for( i = 0; i < 3; i++ )
		{
			r_emins[i] = ent->origin[i] + pseqdesc[0].bbmin[i];
			r_emaxs[i] = ent->origin[i] + pseqdesc[0].bbmax[i];
		}
	}
	else
	{
		for( i = 0; i < 3; i++ )
		{
			r_emins[i] = ent->origin[i] + ent->model->mins[i];
			r_emaxs[i] = ent->origin[i] + ent->model->maxs[i];
		}
	}

	R_SplitEntityOnNode( cl.worldmodel->nodes );
	ent->topnode = r_pefragtopnode;
}
Exemple #14
0
/*
=================
R_DrawAliasModel_ShowTris -- johnfitz
=================
*/
void R_DrawAliasModel_ShowTris (entity_t *e)
{
	aliashdr_t	*paliashdr;
	lerpdata_t	lerpdata;

	if (R_CullModelForEntity(e))
		return;

	paliashdr = (aliashdr_t *)Mod_Extradata (e->model);
	R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
	R_SetupEntityTransform (e, &lerpdata);

    glPushMatrix ();
	R_RotateForEntity (lerpdata.origin,lerpdata.angles);
	glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
	glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);

	shading = false;
	glColor3f(1,1,1);
	GL_DrawAliasFrame (paliashdr, lerpdata);

	glPopMatrix ();
}
Exemple #15
0
/*
====================
CL_AllocRemapInfo

Allocate new remap info per entity
and make copy of remap textures
====================
*/
void CL_AllocRemapInfo( int topcolor, int bottomcolor )
{
	remap_info_t	*info;
	studiohdr_t	*phdr;
	mstudiotexture_t	*src, *dst;
	int		i, size;

	if( !RI.currententity ) return;
	i = ( RI.currententity == &clgame.viewent ) ? clgame.maxEntities : RI.currententity->curstate.number;

	if( !RI.currentmodel || RI.currentmodel->type != mod_studio )
	{
		// entity has changed model by another type, release remap info
		if( clgame.remap_info[i] )
		{
			CL_FreeRemapInfo( clgame.remap_info[i] );
			clgame.remap_info[i] = NULL;
		}
		return; // missed or hide model, ignore it
	}

	// model doesn't contains remap textures
	if( RI.currentmodel->numtextures <= 0 )
	{
		// entity has changed model with no remap textures
		if( clgame.remap_info[i] )
		{
			CL_FreeRemapInfo( clgame.remap_info[i] );
			clgame.remap_info[i] = NULL;
		}
		return;
	}

	phdr = (studiohdr_t *)Mod_Extradata( RI.currentmodel );
	if( !phdr ) return;	// missed header ???

	src = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex);
	dst = (clgame.remap_info[i] ? clgame.remap_info[i]->ptexture : NULL); 

	// NOTE: we must copy all the structures 'mstudiotexture_t' for easy access when model is rendering
	if( !CL_CmpStudioTextures( phdr->numtextures, src, dst ) || clgame.remap_info[i]->model != RI.currentmodel )
	{
		// this code catches studiomodel change with another studiomodel with remap textures
		// e.g. playermodel 'barney' with playermodel 'gordon'
		if( clgame.remap_info[i] ) CL_FreeRemapInfo( clgame.remap_info[i] ); // free old info
		size = sizeof( remap_info_t ) + ( sizeof( mstudiotexture_t ) * phdr->numtextures );
		info = clgame.remap_info[i] = Mem_Alloc( clgame.mempool, size );	
		info->ptexture = (mstudiotexture_t *)(info + 1); // textures are immediately comes after remap_info
	}
	else
	{
		// studiomodel is valid, nothing to change
		return;
	}

	info->numtextures = phdr->numtextures;
	info->model = RI.currentmodel;
	info->topcolor = topcolor;
	info->bottomcolor = bottomcolor;

	src = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex);
	dst = info->ptexture;

	// copy unchanged first
	Q_memcpy( dst, src, sizeof( mstudiotexture_t ) * phdr->numtextures );

	// make local copies for remap textures
	for( i = 0; i < info->numtextures; i++ )
	{
		if( dst[i].flags & STUDIO_NF_COLORMAP )
			CL_DuplicateTexture( &dst[i], topcolor, bottomcolor );
	}
}
Exemple #16
0
/*
================
R_AliasCheckBBox
================
*/
qboolean R_AliasCheckBBox(void)
{
	int					i, flags, frame, numv;
	aliashdr_t			*pahdr;
	float				zi, basepts[8][3], v0, v1, frac;
	finalvert_t			*pv0, *pv1, viewpts[16];
	auxvert_t			*pa0, *pa1, viewaux[16];
	maliasframedesc_t	*pframedesc;
	qboolean			zclipped, zfullyclipped;
	unsigned			anyclip, allclip;
	int					minz;

// expand, rotate, and translate points into worldspace

	currententity->trivial_accept = 0;
	pmodel = currententity->model;
	pahdr = Mod_Extradata(pmodel);
	pmdl = (mdl_t *)((byte *)pahdr + pahdr->model);

	R_AliasSetUpTransform(0);

// construct the base bounding box for this frame
	frame = currententity->frame;
// TODO: don't repeat this check when drawing?
	if ((frame >= pmdl->numframes) || (frame < 0))
	{
		Con_DPrintf("No such frame %d %s\n", frame,
					pmodel->name);
		frame = 0;
	}

	pframedesc = &pahdr->frames[frame];

// x worldspace coordinates
	basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] =
										(float)pframedesc->bboxmin.v[0];
	basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] =
										(float)pframedesc->bboxmax.v[0];

// y worldspace coordinates
	basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] =
										(float)pframedesc->bboxmin.v[1];
	basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] =
										(float)pframedesc->bboxmax.v[1];

// z worldspace coordinates
	basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] =
										(float)pframedesc->bboxmin.v[2];
	basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] =
										(float)pframedesc->bboxmax.v[2];

	zclipped = false;
	zfullyclipped = true;

	minz = 9999;
	for (i=0; i<8 ; i++)
	{
		R_AliasTransformVector(&basepts[i][0], &viewaux[i].fv[0]);

		if (viewaux[i].fv[2] < ALIAS_Z_CLIP_PLANE)
		{
			// we must clip points that are closer than the near clip plane
			viewpts[i].flags = ALIAS_Z_CLIP;
			zclipped = true;
		}
		else
		{
			if (viewaux[i].fv[2] < minz)
			{
				minz = viewaux[i].fv[2];
			}
			viewpts[i].flags = 0;
			zfullyclipped = false;
		}
	}


	if (zfullyclipped)
	{
		return false;	// everything was near-z-clipped
	}

	numv = 8;

	if (zclipped)
	{
		// organize points by edges, use edges to get new points (possible trivial
		// reject)
		for (i=0 ; i<12 ; i++)
		{
			// edge endpoints
			pv0 = &viewpts[aedges[i].index0];
			pv1 = &viewpts[aedges[i].index1];
			pa0 = &viewaux[aedges[i].index0];
			pa1 = &viewaux[aedges[i].index1];

			// if one end is clipped and the other isn't, make a new point
			if (pv0->flags ^ pv1->flags)
			{
				frac = (ALIAS_Z_CLIP_PLANE - pa0->fv[2]) /
					   (pa1->fv[2] - pa0->fv[2]);
				viewaux[numv].fv[0] = pa0->fv[0] +
									  (pa1->fv[0] - pa0->fv[0]) * frac;
				viewaux[numv].fv[1] = pa0->fv[1] +
									  (pa1->fv[1] - pa0->fv[1]) * frac;
				viewaux[numv].fv[2] = ALIAS_Z_CLIP_PLANE;
				viewpts[numv].flags = 0;
				numv++;
			}
		}
	}

// project the vertices that remain after clipping
	anyclip = 0;
	allclip = ALIAS_XY_CLIP_MASK;

// TODO: probably should do this loop in ASM, especially if we use floats
	for (i=0 ; i<numv ; i++)
	{
		// we don't need to bother with vertices that were z-clipped
		if (viewpts[i].flags & ALIAS_Z_CLIP)
		{
			continue;
		}

		zi = 1.0 / viewaux[i].fv[2];

		// FIXME: do with chop mode in ASM, or convert to float
		v0 = (viewaux[i].fv[0] * xscale * zi) + xcenter;
		v1 = (viewaux[i].fv[1] * yscale * zi) + ycenter;

		flags = 0;

		if (v0 < r_refdef.fvrectx)
		{
			flags |= ALIAS_LEFT_CLIP;
		}
		if (v1 < r_refdef.fvrecty)
		{
			flags |= ALIAS_TOP_CLIP;
		}
		if (v0 > r_refdef.fvrectright)
		{
			flags |= ALIAS_RIGHT_CLIP;
		}
		if (v1 > r_refdef.fvrectbottom)
		{
			flags |= ALIAS_BOTTOM_CLIP;
		}

		anyclip |= flags;
		allclip &= flags;
	}

	if (allclip)
	{
		return false;    // trivial reject off one side
	}

	currententity->trivial_accept = !anyclip & !zclipped;

	if (currententity->trivial_accept)
	{
		if (minz > (r_aliastransition + (pmdl->size * r_resfudge)))
		{
			currententity->trivial_accept |= 2;
		}
	}

	return true;
}
Exemple #17
0
/*
=================
R_DrawQ3Model

Modified Dr Labmans
md3 code splitting it
up to make it easier
to add dynamic lighting code
=================
*/
void R_DrawQ3Model (entity_t *e)
{
   md3header_t      *header;
   //md3shader_t      *shader;
   md3surface_t   *surf;

/*	if (!gl_notrans.value)	// always true if not -nehahra
	{
		r_modelalpha = e->transparency;
		if (r_modelalpha == 0)
			r_modelalpha = 1.0;
	}
	else
	{
		r_modelalpha = 1.0;
	}
*/
/*************** FIXME: combine with alias model code! ***************/


   R_CalcMD3Lighting (e, e->model);

   // Get the model data
   header = (md3header_t *)Mod_Extradata (e->model);

   // locate the proper data "huh surface related"!
   surf = (md3surface_t *)((byte *)header + header->surface_offs);

   c_alias_polys += surf->num_surf_tris;

/*******JDH*******
   //get pointer to shaders
   shader = (md3shader_t *)((byte *)surf + surf->shader_offs);

	//shaders = shader[(currententity->skinnum%surf->num_surf_shaders)].texnum;
	shaders = shader[ e->skinnum % surf->num_surf_shaders ].index;

   if (shaders) {
      GL_Bind(shaders);
   } else {
      GL_Bind(0);
   }
*******JDH*******/

   glPushMatrix();

   //interpolate unless its the viewmodel
   if (gl_interpolate_animation.value && (e != &cl.viewent))
   {
      R_BlendedRotateForEntity (e);
   }
   else
   {
      R_RotateForEntity (e);
   }

   if (gl_smoothmodels.value)
      glShadeModel (GL_SMOOTH);

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

   R_SetupQ3AliasFrame (e->frame, header, e, gl_mtexable);
   glShadeModel (GL_FLAT);

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

   glPopMatrix();
}
Exemple #18
0
void R_DrawAliasModel(entity_t *e) {
    extern void AddFire(vec3_t org, float size);

    int lnum;
    vec3_t dist;
    float add;
    model_t *clmodel;
    vec3_t mins, maxs;
    aliashdr_t *paliashdr;
    float an; //s, t,
    int anim;
    md2_t *pheader; // LH / muff
    int shell; //QMB :model shells

    //not implemented yet
    //	byte		c, *color;	//QMB :color map

    //does the model need a shell?
    if (cl.items & IT_QUAD && e == &cl.viewent)
        shell = true;
    else
        shell = false;

    //set get the model from the e
    clmodel = e->model;

    //work out its max and mins
    VectorAdd(e->origin, clmodel->mins, mins);
    VectorAdd(e->origin, clmodel->maxs, maxs);
    //make sure its in screen
    if (R_CullBox(mins, maxs) && e != &cl.viewent)
        return;

    //QMB: FIXME
    //should use a particle emitter linked to the model for its org
    //needs to be linked when the model is created and distroyed when
    //the entity is distroyed
    //check if its a fire and add the particle effect
    if (!strcmp(clmodel->name, "progs/flame.mdl"))
        AddFire(e->origin, 4);

    if (!strcmp(clmodel->name, "progs/flame2.mdl")) {
        AddFire(e->origin, 10);
        return; //do not draw the big fire model, its just a place holder for the particles
    }

    // get lighting information
    //QMB: FIXME
    //SHOULD CHANGE TO A PASSED VAR
    //get vertex normals (for lighting and shells)
    shadedots = r_avertexnormal_dots[((int) (e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];

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

    //get the light for the model
    R_LightPoint(e->origin); // LordHavoc: lightcolor is all that matters from this

    //work out lighting from the dynamic lights
    for (lnum = 0; lnum < MAX_DLIGHTS; lnum++) {
        //if the light is alive
        if (cl_dlights[lnum].die >= cl.time) {
            //work out the distance to the light
            VectorSubtract(e->origin, cl_dlights[lnum].origin, dist);
            add = cl_dlights[lnum].radius - VectorLength(dist);
            //if its close enough add light from it
            if (add > 0) {
                lightcolor[0] += add * cl_dlights[lnum].colour[0];
                lightcolor[1] += add * cl_dlights[lnum].colour[1];
                lightcolor[2] += add * cl_dlights[lnum].colour[2];
            }
        }
    }

    //scale lighting to floating point
    VectorScale(lightcolor, 1.0f / 200.0f, lightcolor);

    // locate the proper data
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    if (gl_n_patches && gl_npatches.getBool()) {
        glEnable(GL_PN_TRIANGLES_ATI);
        glPNTrianglesiATI(GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, gl_npatches.getInt());

        if (true)
            glPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI);
        else
            glPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI);

        if (true)
            glPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI);
        else
            glPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI);
    }

    if (clmodel->aliastype == MD3IDHEADER) {
        //do nothing for testing
        if (!r_modeltexture.getBool()) {
            GL_DisableTMU(GL_TEXTURE0_ARB);
        }//disable texture if needed

        R_DrawQ3Model(e, false, false);

        if (!r_modeltexture.getBool()) {
            GL_EnableTMU(GL_TEXTURE0_ARB);
        }//enable texture if needed

        if (r_celshading.getBool() || r_outline.getBool()) {
            glCullFace(GL_BACK);
            glEnable(GL_BLEND);
            glPolygonMode(GL_FRONT, GL_LINE);

            if (e == &cl.viewent) {
                glLineWidth(1.0f);
            } else {
                glLineWidth(5.0f);
            }

            glEnable(GL_LINE_SMOOTH);

            GL_DisableTMU(GL_TEXTURE0_ARB);

            glColor3f(0.0, 0.0, 0.0);
            R_DrawQ3Model(e, false, true);
            glColor3f(1.0, 1.0, 1.0);

            GL_EnableTMU(GL_TEXTURE0_ARB);

            glPolygonMode(GL_FRONT, GL_FILL);
            glDisable(GL_BLEND);
            glCullFace(GL_FRONT);
        }

        if (shell) {
            glBindTexture(GL_TEXTURE_2D, quadtexture);
            glColor4f(1.0, 1.0, 1.0, 0.5);
            glEnable(GL_BLEND);
            R_DrawQ3Model(e, true, false);
            glDisable(GL_BLEND);
            glColor3f(1.0, 1.0, 1.0);
        }
    } else if (clmodel->aliastype != ALIASTYPE_MD2) {
        paliashdr = (aliashdr_t *) Mod_Extradata(e->model);
        c_alias_polys += paliashdr->numtris;

        glPushMatrix();

        //interpolate unless its the viewmodel
        if (e != &cl.viewent)
            R_BlendedRotateForEntity(e);
        else
            R_RotateForEntity(e);

        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;
        glBindTexture(GL_TEXTURE_2D, paliashdr->gl_texturenum[e->skinnum][anim]);

        // draw all the triangles
        if (!r_modeltexture.getBool()) {
            GL_DisableTMU(GL_TEXTURE0_ARB);
        } else {
            //highlighting test code
            if (0 && gl_textureunits > 2) {
                GL_EnableTMU(GL_TEXTURE1_ARB);

                glBindTexture(GL_TEXTURE_2D, TextureManager::highlighttexture);

                glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
                glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
                glEnable(GL_TEXTURE_GEN_S);
                glEnable(GL_TEXTURE_GEN_T);
                //need correct mode
                glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
                glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
                glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0);

                //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
            }
        }

        glColor3fv(lightcolor);
        R_SetupAliasBlendedFrame(e->frame, paliashdr, e, false, false);
        glDisable(GL_TEXTURE_1D);

        if (r_celshading.getBool() || r_outline.getBool()) {
            glColor3f(0.0, 0.0, 0.0);
            R_SetupAliasBlendedFrame(e->frame, paliashdr, e, false, true);
            glColor3f(1.0, 1.0, 1.0);
        }

        if (!r_modeltexture.getBool()) {
            GL_EnableTMU(GL_TEXTURE0_ARB);
        } else {
            if (0 && gl_textureunits > 2) {
                //highlighting test code
                glDisable(GL_TEXTURE_GEN_S);
                glDisable(GL_TEXTURE_GEN_T);
                GL_DisableTMU(GL_TEXTURE1_ARB);
                glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
            }
        }
        glActiveTexture(GL_TEXTURE0_ARB);

        //colour map code... not working yet...
        /*		if (e->colormap != vid.colormap && !gl_nocolors.value)
                {
                    if (paliashdr->gl_texturenumColorMap&&paliashdr->gl_texturenumColorMap){
                        glBindTexture(GL_TEXTURE_2D,paliashdr->gl_texturenumColorMap);
                        c = (byte)e->colormap & 0xF0;
                        c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
                        color = (byte *) (&d_8to24table[c]);
                        //glColor3fv(color);
                        glColor3f(1.0,1.0,1.0);
                    }
                }*/
        if (shell) {
            glBindTexture(GL_TEXTURE_2D, quadtexture);
            glColor4f(1.0, 1.0, 1.0, 0.5);
            glEnable(GL_BLEND);
            R_SetupAliasBlendedFrame(e->frame, paliashdr, e, true, false);
            glDisable(GL_BLEND);
            glColor3f(1.0, 1.0, 1.0);
        }
        glPopMatrix();

    } else {
        pheader = (md2_t *) Mod_Extradata(e->model);
        c_alias_polys += pheader->num_tris;

        glBindTexture(GL_TEXTURE_2D, pheader->gl_texturenum[e->skinnum]);
        R_SetupQ2AliasFrame(e, pheader);
    }

    if (gl_n_patches && gl_npatches.getBool()) {
        glDisable(GL_PN_TRIANGLES_ATI);
    }

    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
Exemple #19
0
/*
=================
R_DrawAliasModel -- johnfitz -- almost completely rewritten
=================
*/
void R_DrawAliasModel (entity_t *e)
{
	aliashdr_t	*paliashdr;
	int			i, anim;
	gltexture_t	*tx, *fb;
	lerpdata_t	lerpdata;

	//
	// setup pose/lerp data -- do it first so we don't miss updates due to culling
	//
	paliashdr = (aliashdr_t *)Mod_Extradata (e->model);
	R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
	R_SetupEntityTransform (e, &lerpdata);

	//
	// cull it
	//
	if (R_CullModelForEntity(e))
		return;

	//
	// transform it
	//
    glPushMatrix ();
	R_RotateForEntity (lerpdata.origin, lerpdata.angles);
	glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
	glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);

	//
	// random stuff
	//
	if (gl_smoothmodels.value && !r_drawflat_cheatsafe)
		glShadeModel (GL_SMOOTH);
	if (gl_affinemodels.value)
		glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
	overbright = gl_overbright_models.value;
	shading = true;

	//
	// set up for alpha blending
	//
	if (r_drawflat_cheatsafe || r_lightmap_cheatsafe) //no alpha in drawflat or lightmap mode
		entalpha = 1;
	else
		entalpha = ENTALPHA_DECODE(e->alpha);
	if (entalpha == 0)
		goto cleanup;
	if (entalpha < 1)
	{
		if (!gl_texture_env_combine) overbright = false; //overbright can't be done in a single pass without combiners
		glDepthMask(GL_FALSE);
		glEnable(GL_BLEND);
	}

	//
	// set up lighting
	//
	rs_aliaspolys += paliashdr->numtris;
	R_SetupAliasLighting (e);

	//
	// set up textures
	//
	GL_DisableMultitexture();
	anim = (int)(cl.time*10) & 3;
	tx = paliashdr->gltextures[e->skinnum][anim];
	fb = paliashdr->fbtextures[e->skinnum][anim];
	if (e->colormap != vid.colormap && !gl_nocolors.value)
	{
		i = e - cl_entities;
		if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
		    tx = playertextures[i - 1];
	}
	if (!gl_fullbrights.value)
		fb = NULL;

	//
	// draw it
	//
	if (r_drawflat_cheatsafe)
	{
		glDisable (GL_TEXTURE_2D);
		GL_DrawAliasFrame (paliashdr, lerpdata);
		glEnable (GL_TEXTURE_2D);
		srand((int) (cl.time * 1000)); //restore randomness
	}
	else if (r_fullbright_cheatsafe)
	{
		GL_Bind (tx);
		shading = false;
		glColor4f(1,1,1,entalpha);
		GL_DrawAliasFrame (paliashdr, lerpdata);
		if (fb)
		{
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
			GL_Bind(fb);
			glEnable(GL_BLEND);
			glBlendFunc (GL_ONE, GL_ONE);
			glDepthMask(GL_FALSE);
			glColor3f(entalpha,entalpha,entalpha);
			Fog_StartAdditive ();
			GL_DrawAliasFrame (paliashdr, lerpdata);
			Fog_StopAdditive ();
			glDepthMask(GL_TRUE);
			glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glDisable(GL_BLEND);
		}
	}
	else if (r_lightmap_cheatsafe)
	{
		glDisable (GL_TEXTURE_2D);
		shading = false;
		glColor3f(1,1,1);
		GL_DrawAliasFrame (paliashdr, lerpdata);
		glEnable (GL_TEXTURE_2D);
	}
	else if (overbright)
	{
		if  (gl_texture_env_combine && gl_mtexable && gl_texture_env_add && fb) //case 1: everything in one pass
		{
			GL_Bind (tx);
			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
			glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
			GL_EnableMultitexture(); // selects TEXTURE1
			GL_Bind (fb);
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
			glEnable(GL_BLEND);
			GL_DrawAliasFrame (paliashdr, lerpdata);
			glDisable(GL_BLEND);
			GL_DisableMultitexture();
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
		}
		else if (gl_texture_env_combine) //case 2: overbright in one pass, then fullbright pass
		{
		// first pass
			GL_Bind(tx);
			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
			glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
			GL_DrawAliasFrame (paliashdr, lerpdata);
			glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f);
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
		// second pass
			if (fb)
			{
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
				GL_Bind(fb);
				glEnable(GL_BLEND);
				glBlendFunc (GL_ONE, GL_ONE);
				glDepthMask(GL_FALSE);
				shading = false;
				glColor3f(entalpha,entalpha,entalpha);
				Fog_StartAdditive ();
				GL_DrawAliasFrame (paliashdr, lerpdata);
				Fog_StopAdditive ();
				glDepthMask(GL_TRUE);
				glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				glDisable(GL_BLEND);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
			}
		}
		else //case 3: overbright in two passes, then fullbright pass
		{
		// first pass
			GL_Bind(tx);
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
			GL_DrawAliasFrame (paliashdr, lerpdata);
		// second pass -- additive with black fog, to double the object colors but not the fog color
			glEnable(GL_BLEND);
			glBlendFunc (GL_ONE, GL_ONE);
			glDepthMask(GL_FALSE);
			Fog_StartAdditive ();
			GL_DrawAliasFrame (paliashdr, lerpdata);
			Fog_StopAdditive ();
			glDepthMask(GL_TRUE);
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glDisable(GL_BLEND);
		// third pass
			if (fb)
			{
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
				GL_Bind(fb);
				glEnable(GL_BLEND);
				glBlendFunc (GL_ONE, GL_ONE);
				glDepthMask(GL_FALSE);
				shading = false;
				glColor3f(entalpha,entalpha,entalpha);
				Fog_StartAdditive ();
				GL_DrawAliasFrame (paliashdr, lerpdata);
				Fog_StopAdditive ();
				glDepthMask(GL_TRUE);
				glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				glDisable(GL_BLEND);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
			}
		}
	}
	else
	{
		if (gl_mtexable && gl_texture_env_add && fb) //case 4: fullbright mask using multitexture
		{
			GL_DisableMultitexture(); // selects TEXTURE0
			GL_Bind (tx);
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
			GL_EnableMultitexture(); // selects TEXTURE1
			GL_Bind (fb);
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
			glEnable(GL_BLEND);
			GL_DrawAliasFrame (paliashdr, lerpdata);
			glDisable(GL_BLEND);
			GL_DisableMultitexture();
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
		}
		else //case 5: fullbright mask without multitexture
		{
		// first pass
			GL_Bind(tx);
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
			GL_DrawAliasFrame (paliashdr, lerpdata);
		// second pass
			if (fb)
			{
				GL_Bind(fb);
				glEnable(GL_BLEND);
				glBlendFunc (GL_ONE, GL_ONE);
				glDepthMask(GL_FALSE);
				shading = false;
				glColor3f(entalpha,entalpha,entalpha);
				Fog_StartAdditive ();
				GL_DrawAliasFrame (paliashdr, lerpdata);
				Fog_StopAdditive ();
				glDepthMask(GL_TRUE);
				glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				glDisable(GL_BLEND);
			}
		}
	}

cleanup:
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	glShadeModel (GL_FLAT);
	glDepthMask(GL_TRUE);
	glDisable(GL_BLEND);
	glColor3f(1,1,1);
	glPopMatrix ();
}
Exemple #20
0
void R_SetupAliasModel (entity_t *e)
{
    aliashdr_t	*paliashdr;
    int			anim;
    aliasstate_t	*state = &e->aliasstate;

    // initially not visible
    e->visframe = -1;

    // setup pose/lerp data -- do it first so we don't miss updates due to culling
    paliashdr = (aliashdr_t *) Mod_Extradata (e->model);
    R_SetupAliasFrame (e, paliashdr, e->frame, state);
    R_SetupEntityTransform (e, state);
    R_BBoxForEnt (e);

    // cull it (the viewmodel is never culled)
    if (r_shadows.value > 0.01f)
    {
        if (!(e->renderfx & RF_WEAPONMODEL))
        {
            if (R_CullBox (e->mins, e->maxs))
                e->visframe = -1;
            else
                e->visframe = r_framecount;
        }
    }
    else
    {
        if (!(e->renderfx & RF_WEAPONMODEL))
        {
            if (R_CullBox (e->mins, e->maxs))
                return;
        }

        // the ent is visible now
        e->visframe = r_framecount;
    }

    // set up lighting
    overbright = gl_overbright.value;
    rs_aliaspolys += paliashdr->numtris;
    R_SetupAliasLighting (e, state->shadelight);

    // store out the alpha value
    state->shadelight[3] = ((float) e->alpha / 255.0f);

    // set up textures
    anim = (int) (cl.time * 10) & 3;
    state->tx = paliashdr->gltextures[e->skinnum][anim];

    // ensure we have a valid texture
    if (!state->tx) state->tx = notexture;

    if (!gl_fullbrights.value)
        state->fb = NULL;
    else
        state->fb = paliashdr->fbtextures[e->skinnum][anim];

    if (e->colormap && (e->model->modhint == MOD_PLAYER || e->renderfx & RF_PLAYERMODEL) && !gl_nocolors.value)
        R_GetTranslatedPlayerSkin (e->colormap, &state->tx, &state->fb);
}
Exemple #21
0
void R_DrawAliasShadows (entity_t **ents, int numents, void *meshbuffer)
{
    if (r_shadows.value > 0.01f)
    {
        int i;
        qbool stateset = false;
        byte shadecolor[4] = {0, 0, 0, 128};
//		extern int gl_stencilbits;

        for (i = 0; i < numents; i++)
        {
            entity_t *ent = ents[i];
            glmatrix eshadow;

            if (!(ent->model->flags & MOD_NOSHADOW))
            {
                aliasstate_t *state = &ent->aliasstate;
                aliashdr_t *hdr = Mod_Extradata (ent->model);
                float lheight = state->origin[2] - state->lightspot[2];

                if (!stateset)
                {
                    float *mesh = (float *) meshbuffer;

                    qglDepthMask (GL_FALSE);
                    qglEnable (GL_BLEND);
                    GL_TexEnv (GL_TEXTURE1_ARB, GL_TEXTURE_2D, GL_NONE);
                    GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_NONE);
                    qglColor4f (0, 0, 0, r_shadows.value);
                    shadecolor[3] = BYTE_CLAMPF (r_shadows.value);

                    /*
                    if (gl_stencilbits)
                    {
                    	qglEnable (GL_STENCIL_TEST);
                    	qglStencilFunc (GL_EQUAL, 1, 2);
                    	qglStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
                    }
                    */

                    GL_SetStreamSource (GLSTREAM_POSITION, 3, GL_FLOAT, sizeof (float) * 4, mesh);
                    GL_SetStreamSource (GLSTREAM_COLOR, 4, GL_UNSIGNED_BYTE, sizeof (float) * 4, &mesh[3]);
                    GL_SetStreamSource (GLSTREAM_TEXCOORD0, 0, GL_NONE, 0, NULL);
                    GL_SetStreamSource (GLSTREAM_TEXCOORD1, 0, GL_NONE, 0, NULL);
                    GL_SetStreamSource (GLSTREAM_TEXCOORD2, 0, GL_NONE, 0, NULL);

                    stateset = true;
                }

                GL_LoadMatrix (&eshadow, &r_world_matrix);

                if (state->origin[0] || state->origin[1] || state->origin[2])
                    GL_TranslateMatrix (&eshadow, state->origin[0], state->origin[1], state->origin[2]);

                GL_TranslateMatrix (&eshadow, 0, 0, -lheight);
                GL_MultiplyMatrix (&eshadow, &shadowmatrix, &eshadow);
                GL_TranslateMatrix (&eshadow, 0, 0, lheight);

                if (state->angles[1]) GL_RotateMatrix (&eshadow, state->angles[1], 0, 0, 1);

                GL_TranslateMatrix (&eshadow, hdr->scale_origin[0], hdr->scale_origin[1], hdr->scale_origin[2]);
                GL_ScaleMatrix (&eshadow, hdr->scale[0], hdr->scale[1], hdr->scale[2]);

                qglLoadMatrixf (eshadow.m16);

                R_DrawAliasShadow (ent, hdr, state, (float *) meshbuffer, (float *) shadecolor);
            }
        }

        if (stateset)
        {
            /*
            if (gl_stencilbits)
            	qglDisable (GL_STENCIL_TEST);
            */

            GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_REPLACE);
            qglDisable (GL_BLEND);
            qglDepthMask (GL_TRUE);
            qglColor4f (1, 1, 1, 1);

            qglLoadMatrixf (r_world_matrix.m16);
        }
    }
}
Exemple #22
0
/*
================
R_AliasDrawModel
================
*/
void R_AliasDrawModel (alight_t *plighting)
{
finalvert_t		finalverts[MAXALIASVERTS + ((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1];
        auxvert_t      	auxverts[MAXALIASVERTS];
//	finalvert_t		*finalverts;
//	auxvert_t		*auxverts;


	//Anders> Change malloc to static allocated memory to avoid malloc?
	//  	finalverts = malloc( (sizeof(finalvert_t)*MAXALIASVERTS) + (sizeof(finalvert_t)*(((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1)));
	//        auxverts   = malloc( (sizeof(finalvert_t)*MAXALIASVERTS));

	GpError("R_AliasDrawModel A",11);

	r_amodels_drawn++;

// cache align
	pfinalverts = (finalvert_t *)
			(((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
	pauxverts = &auxverts[0];

	GpError("R_AliasDrawModel B",11);

	paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);
	pmdl = (mdl_t *)((byte *)paliashdr + paliashdr->model);

	GpError("R_AliasDrawModel C",11);
	R_AliasSetupSkin ();
	GpError("R_AliasDrawModel D",11);
	R_AliasSetUpTransform (currententity->trivial_accept);
	GpError("R_AliasDrawModel E",11);
	R_AliasSetupLighting (plighting);
	GpError("R_AliasDrawModel F",11);
	R_AliasSetupFrame ();
	GpError("R_AliasDrawModel G",11);

	if (!currententity->colormap)
		Sys_Error ("R_AliasDrawModel: !currententity->colormap");

	r_affinetridesc.drawtype = (currententity->trivial_accept == 3) &&
			r_recursiveaffinetriangles;

	if (r_affinetridesc.drawtype)
	{
		GpError("R_AliasDrawModel H",11);
		D_PolysetUpdateTables ();		// FIXME: precalc...
	}
	else
	{
#if	id386
		D_Aff8Patch (currententity->colormap);
#endif
	}

	acolormap = currententity->colormap;

	if (currententity != &cl.viewent)
		ziscale = (float)0x8000 * (float)0x10000;
	else
		ziscale = (float)0x8000 * (float)0x10000 * 3.0;

	if (currententity->trivial_accept){
		GpError("R_AliasDrawModel I",11);
		R_AliasPrepareUnclippedPoints ();
	}
	else{
		GpError("R_AliasDrawModel J",11);
		R_AliasPreparePoints ();
	}
	//		free(finalverts);
	//		free(auxverts);
	GpError("R_AliasDrawModel end",11);
}
Exemple #23
0
/*
=================
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 #24
0
void R_AliasDrawModel (alight_t *plighting)
#endif
{
// h2
	int		mls;
	int		i, j;
	byte	*dest, *source, *sourceA;
// h2

	finalvert_t		finalverts[MAXALIASVERTS +
						((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1];
	auxvert_t		auxverts[MAXALIASVERTS];

	r_amodels_drawn++;

// cache align
	pfinalverts = (finalvert_t *)
			(((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));


#ifdef INTERPOL7
	if(r_lerpmodels->value)
	pauxverts = &r_auxverts[0];
	else
	pauxverts = &auxverts[0];
#else
	pauxverts = &auxverts[0];
#endif
	paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);
	pmdl = (mdl_t *)((byte *)paliashdr + paliashdr->model);

	R_AliasSetupSkin ();
#ifdef INTERPOL7
	if (r_lerpmodels->value)
	R_AliasSetUpTransform (0);
		else
	R_AliasSetUpTransform (currententity->trivial_accept);
//	R_AliasSetUpTransform (currententity->trivial_accept);
#else
	R_AliasSetUpTransform (currententity->trivial_accept);
#endif
	if (r_shading->value > 1 && (lightingavailable))
		R_AliasSetupLighting_enhanced (plighting);	// leilei - further hacked
	else if (r_shading->value > 1 && !lightingavailable)
		R_AliasSetupLighting (plighting);	// no lighting available so we fall back
		else
		if (r_shading->value)
		R_AliasSetupLighting (plighting);
		else
			R_AliasSetupLightingSimple (plighting);
#ifdef INTERPOL7
		R_AliasSetupFrame (currententity);
#else
		R_AliasSetupFrame ();
#endif


	if (!currententity->colormap)
		Sys_Error ("R_AliasDrawModel: !currententity->colormap");

	if (!coloredlights){
	r_affinetridesc.drawtype = (currententity->trivial_accept == 3) &&
			r_recursiveaffinetriangles;
	}
	
	if (r_affinetridesc.drawtype)
	{
		D_PolysetUpdateTables ();		// FIXME: precalc...

	}
	else
	{
#if	id386broken
		D_Aff8Patch (currententity->colormap);
#endif
	}

	acolormap = currententity->colormap;
#ifdef VMTOC
//	if (viewmodel)
//		ziscale = (float)0x8000 * (float)0x10000 * 3.0;
//	else
	 if (viewmodel)
		ziscale = (float)0x8000 * (float)0x10000 * 3.0;
	else
		ziscale = (float)0x8000 * (float)0x10000;
#else
	if (currententity != &cl.viewent)
		ziscale = (float)0x8000 * (float)0x10000;
	 else
		ziscale = (float)0x8000 * (float)0x10000 * 3.0;
#endif
	if (currententity->trivial_accept)
		R_AliasPrepareUnclippedPoints ();
	else
		R_AliasPreparePoints ();
}
Exemple #25
0
/* <83e97> ../engine/r_studio.c:1015 */
hull_t *SV_HullForStudioModel(const edict_t *pEdict, const vec_t *mins, const vec_t *maxs, vec_t *offset, int *pNumHulls)
{
	qboolean useComplexHull = FALSE;
	vec3_t size;
	float factor = 0.5;
	int bSkipShield = 0;
	size[0] = maxs[0] - mins[0];
	size[1] = maxs[1] - mins[1];
	size[2] = maxs[2] - mins[2];
	if (VectorCompare(vec3_origin, size))
	{
		if (!(gGlobalVariables.trace_flags & FTRACE_SIMPLEBOX))
		{
			useComplexHull = TRUE;
			if (pEdict->v.flags & FL_CLIENT)
			{
				if (sv_clienttrace.value == 0.0)
				{
					useComplexHull = FALSE;
				}
				else
				{
					size[2] = 1.0f;
					size[1] = 1.0f;
					size[0] = 1.0f;
					factor = sv_clienttrace.value * 0.5f;
				}
			}
		}
	}
	if (pEdict->v.gamestate == 1 && (g_bIsTerrorStrike == 1 || g_bIsCStrike == 1 || g_bIsCZero == 1))
		bSkipShield = 1;

	if ((g_psv.models[pEdict->v.modelindex]->flags & FL_ONGROUND) || useComplexHull == TRUE)
	{
		VectorScale(size, factor, size);
		offset[0] = 0;
		offset[1] = 0;
		offset[2] = 0;
		if (pEdict->v.flags & FL_CLIENT)
		{
			pstudiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[pEdict->v.modelindex]);

			mstudioseqdesc_t* pseqdesc = (mstudioseqdesc_t *)((char*)pstudiohdr + pstudiohdr->seqindex);
			pseqdesc += pEdict->v.sequence;

			vec3_t angles;
			angles[0] = pEdict->v.angles[0];
			angles[1] = pEdict->v.angles[1];
			angles[2] = pEdict->v.angles[2];

			int iBlend;
			R_StudioPlayerBlend(pseqdesc, &iBlend, angles);

			unsigned char blending = (unsigned char)iBlend;
			unsigned char controller[4] = { 0x7F, 0x7F, 0x7F, 0x7F };
			return R_StudioHull(
				g_psv.models[pEdict->v.modelindex],
				pEdict->v.frame,
				pEdict->v.sequence,
				angles,
				pEdict->v.origin,
				size,
				controller,
				&blending,
				pNumHulls,
				pEdict,
				bSkipShield);
		}
		else
		{
			return R_StudioHull(
				g_psv.models[pEdict->v.modelindex],
				pEdict->v.frame,
				pEdict->v.sequence,
				pEdict->v.angles,
				pEdict->v.origin,
				size,
				pEdict->v.controller,
				pEdict->v.blending,
				pNumHulls,
				pEdict,
				bSkipShield);
		}
	}
	else
	{
		*pNumHulls = 1;
		return SV_HullForEntity((edict_t *)pEdict, mins, maxs, offset);
	}
}
Exemple #26
0
/*
====================
HullForStudio

NOTE: pEdict may be NULL
====================
*/
hull_t *Mod_HullForStudio( model_t *model, float frame, int sequence, vec3_t angles, vec3_t origin, vec3_t size, byte *pcontroller, byte *pblending, int *numhitboxes, edict_t *pEdict )
{
	vec3_t		angles2;
	mstudiocache_t	*bonecache;
	mstudiobbox_t	*phitbox;
	int		i, j;
	qboolean bSkipShield = 0;

	ASSERT( numhitboxes );

	*numhitboxes = 0; // assume error

	if((sv_skipshield->integer == 1 && pEdict && pEdict->v.gamestate == 1) || sv_skipshield->integer == 2)
		bSkipShield = 1;

	if( mod_studiocache->integer )
	{
		bonecache = Mod_CheckStudioCache( model, frame, sequence, angles, origin, size, pcontroller, pblending );

		if( bonecache != NULL )
		{
			Q_memcpy( studio_planes, &cache_planes[bonecache->current_plane], bonecache->numhitboxes * sizeof( mplane_t ) * 6 );
			Q_memcpy( studio_hull_hitgroup, &cache_hull_hitgroup[bonecache->current_hull], bonecache->numhitboxes * sizeof( uint ));
			Q_memcpy( studio_hull, &cache_hull[bonecache->current_hull], bonecache->numhitboxes * sizeof( hull_t ));

			*numhitboxes = bonecache->numhitboxes;
			return studio_hull;
		}
	}

	mod_studiohdr = Mod_Extradata( model );
	if( !mod_studiohdr ) return NULL; // probably not a studiomodel

	ASSERT( pBlendAPI != NULL );

	VectorCopy( angles, angles2 );

	if( !( host.features & ENGINE_COMPENSATE_QUAKE_BUG ))
		angles2[PITCH] = -angles2[PITCH]; // stupid quake bug

	pBlendAPI->SV_StudioSetupBones( model, frame, sequence, angles2, origin, pcontroller, pblending, -1, pEdict );
	phitbox = (mstudiobbox_t *)((byte *)mod_studiohdr + mod_studiohdr->hitboxindex);

	for( i = j = 0; i < mod_studiohdr->numhitboxes; i++, j += 6 )
	{
		studio_hull_hitgroup[i] = phitbox[i].group;

		Mod_SetStudioHullPlane( &studio_planes[j+0], phitbox[i].bone, 0, phitbox[i].bbmax[0] );
		Mod_SetStudioHullPlane( &studio_planes[j+1], phitbox[i].bone, 0, phitbox[i].bbmin[0] );
		Mod_SetStudioHullPlane( &studio_planes[j+2], phitbox[i].bone, 1, phitbox[i].bbmax[1] );
		Mod_SetStudioHullPlane( &studio_planes[j+3], phitbox[i].bone, 1, phitbox[i].bbmin[1] );
		Mod_SetStudioHullPlane( &studio_planes[j+4], phitbox[i].bone, 2, phitbox[i].bbmax[2] );
		Mod_SetStudioHullPlane( &studio_planes[j+5], phitbox[i].bone, 2, phitbox[i].bbmin[2] );

		studio_planes[j+0].dist += DotProductFabs( studio_planes[j+0].normal, size );
		studio_planes[j+1].dist -= DotProductFabs( studio_planes[j+1].normal, size );
		studio_planes[j+2].dist += DotProductFabs( studio_planes[j+2].normal, size );
		studio_planes[j+3].dist -= DotProductFabs( studio_planes[j+3].normal, size );
		studio_planes[j+4].dist += DotProductFabs( studio_planes[j+4].normal, size );
		studio_planes[j+5].dist -= DotProductFabs( studio_planes[j+5].normal, size );
	}

	// tell trace code about hitbox count
	*numhitboxes = (bSkipShield == true) ? mod_studiohdr->numhitboxes - 1 : mod_studiohdr->numhitboxes;

	if( mod_studiocache->integer )
	{
		Mod_AddToStudioCache( frame, sequence, angles, origin, size, pcontroller, pblending, model, studio_hull, *numhitboxes );
	}

	return studio_hull;
}