Exemple #1
0
/**
 * @brief Generates a single texture coordinate for the specified stage and vertex.
 */
static void R_StageTexCoord (const materialStage_t *stage, const vec3_t v, const vec2_t in, vec2_t out)
{
	if (stage->flags & STAGE_ENVMAP) {  /* generate texcoords */
		vec3_t tmp;
		VectorSubtract(v, refdef.viewOrigin, tmp);
		VectorNormalizeFast(tmp);
		Vector2Copy(tmp, out);
	} else {  /* or use the ones we were given */
		Vector2Copy(in, out);
	}
}
Exemple #2
0
static bool G_InventoryPlaceItemAdjacent (edict_t *ent)
{
	vec2_t oldPos; /* if we have to place it to adjacent  */
	edict_t *floorAdjacent;
	int i;

	Vector2Copy(ent->pos, oldPos);
	floorAdjacent = NULL;

	for (i = 0; i < DIRECTIONS; i++) {
		/** @todo Check whether movement is possible here - otherwise don't use this field */
		/* extend pos with the direction vectors */
		/** @todo Don't know why the adjacent stuff has been disabled, but if it was buggy, it's probably */
		/** because the third ent->pos in the next line should be pos[1] ?!. (Duke, 13.1.11) */
		Vector2Set(ent->pos, ent->pos[0] + dvecs[i][0], ent->pos[0] + dvecs[i][1]);
		/* now try to get a floor entity for that new location */
		floorAdjacent = G_GetFloorItems(ent);
		if (!floorAdjacent) {
			floorAdjacent = G_SpawnFloor(ent->pos);
		} else {
			/* destroy this edict (send this event to all clients that see the edict) */
			G_EventPerish(floorAdjacent);
			G_VisFlagsReset(floorAdjacent);
		}

		INVSH_FindSpace(&floorAdjacent->i, &ic->item, INVDEF(gi.csi->idFloor), &x, &y, ic);
		if (x != NONE) {
			ic->x = x;
			ic->y = y;
			ic->next = FLOOR(floorAdjacent);
			FLOOR(floorAdjacent) = ic;
			break;
		}
		/* restore original pos */
		Vector2Copy(oldPos, ent->pos);
	}

	/* added to adjacent pos? */
	if (i < DIRECTIONS) {
		/* restore original pos - if no free space, this was done
		 * already in the for loop */
		Vector2Copy(oldPos, ent->pos);
		return false;
	}

	if (floorAdjacent)
		G_CheckVis(floorAdjacent, true);

	return true;
}
/**
 * @brief Intercept mission ends: UFO leave earth.
 * @param[in] mission Pointer to the mission
 * @param[in] destroyed true if the UFO actually destroyed the installation, false else
 * @note Intercept mission -- Stage 3
 */
void CP_InterceptMissionLeave (mission_t* mission, bool destroyed)
{
	installation_t* installation;

	assert(mission->ufo);

	mission->stage = STAGE_RETURN_TO_ORBIT;

	/* if the mission was an attack of an installation, destroy it */
	installation = mission->data.installation;
	if (installation) {
		vec3_t missionPos;

		Vector2Copy(mission->pos, missionPos);
		missionPos[2] = installation->pos[2];
		if (destroyed && VectorCompareEps(missionPos, installation->pos, UFO_EPSILON))
			INS_DestroyInstallation(installation);
	}

	CP_MissionDisableTimeLimit(mission);
	UFO_SetRandomDest(mission->ufo);
	CP_MissionRemoveFromGeoscape(mission);
	/* Display UFO on geoscape if it is detected */
	mission->ufo->landed = false;
}
/**
 * @brief Set base attack mission, and go to base position.
 * @note Base attack mission -- Stage 1
 */
static void CP_BaseAttackGoToBase (mission_t *mission)
{
	base_t *base;

	mission->stage = STAGE_MISSION_GOTO;

	base = CP_BaseAttackChooseBase();
	if (!base) {
		Com_Printf("CP_BaseAttackGoToBase: no base found\n");
		CP_MissionRemove(mission);
		return;
	}
	mission->data.base = base;

	mission->mapDef = Com_GetMapDefinitionByID("baseattack");
	if (!mission->mapDef) {
		CP_MissionRemove(mission);
		Com_Error(ERR_DROP, "Could not find mapdef baseattack");
		return;
	}

	Vector2Copy(base->pos, mission->pos);
	mission->posAssigned = qtrue;

	Com_sprintf(mission->location, sizeof(mission->location), "%s", base->name);

	if (mission->ufo) {
		CP_MissionDisableTimeLimit(mission);
		UFO_SendToDestination(mission->ufo, mission->pos);
	} else {
		/* Go to next stage on next frame */
		mission->finalDate = ccs.date;
	}
}
Exemple #5
0
/**
 * @brief Build a new installation
 * @param[in] installationTemplate Template pointer
 * @param[in] pos Position on Globe to build at
 * @param[in] name The name of the installation - might already be in utf-8
 */
installation_t* INS_Build (const installationTemplate_t *installationTemplate, const vec2_t pos, const char *name)
{
	installation_t installation;
	const int newInstallationAlienInterest = 1.0f;

	OBJZERO(installation);

	Vector2Copy(pos, installation.pos);
	Q_strncpyz(installation.name, name, sizeof(installation.name));
	installation.idx = ccs.campaignStats.installationsBuilt;
	installation.installationStatus = INSTALLATION_UNDER_CONSTRUCTION;
	installation.installationTemplate = installationTemplate;
	installation.buildStart = ccs.date.day;

	/* a new installation is not discovered (yet) */
	installation.alienInterest = newInstallationAlienInterest;

	/* intialise hit points */
	installation.installationDamage = installation.installationTemplate->maxDamage;

	/* Reset Radar */
	RADAR_Initialise(&(installation.radar), 0.0f, 0.0f, 0.0f, qfalse);

	ccs.campaignStats.installationsBuilt++;
	return (installation_t*)(LIST_Add(&ccs.installations, (void*)&installation, sizeof(installation)))->data;
}
Exemple #6
0
/**
 * @brief Give a random position to the given UFO
 * @param[in] ufocraft Pointer to the UFO which position will be changed.
 * @sa UFO_SetRandomDest
 */
static void UFO_SetRandomPos (aircraft_t* ufocraft)
{
	vec2_t pos;

	CP_GetRandomPosOnGeoscape(pos, qfalse);

	Vector2Copy(pos, ufocraft->pos);
}
static void SCP_CampaignAddMission (setState_t *set)
{
	actMis_t *mis;
	mission_t * mission;
	const nation_t *nation;

	/* add mission */
	if (scd->numActiveMissions >= MAX_ACTMISSIONS) {
		return;
	}

	mis = &scd->activeMissions[scd->numActiveMissions];
	OBJZERO(*mis);

	/* set relevant info */
	mis->def = SCP_GetMission(set);
	if (mis->def == NULL) {
		return;
	}
	mis->cause = set;

	if (set->def->expire.day)
		mis->expire = Date_Add(ccs.date, set->def->expire);

	/* prepare next event (if any) */
	set->num++;
	if (set->def->number && set->num >= set->def->number) {
		set->active = false;
	} else {
		const date_t minTime = {0, 0};
		set->event = Date_Add(ccs.date, Date_Random(minTime, set->def->frame));
	}

	mission = CP_CreateNewMission(INTERESTCATEGORY_TERROR_ATTACK, true);
	mission->mapDef = cgi->Com_GetMapDefinitionByID(mis->def->id);
	if (!mission->mapDef) {
		Com_Printf("SCP_CampaignAddMission: Could not get the mapdef '%s'\n", mis->def->id);
		CP_MissionRemove(mission);
		return;
	}
	Vector2Copy(mis->def->pos, mission->pos);
	mission->posAssigned = true;
	nation = MAP_GetNation(mission->pos);
	if (nation) {
		Com_sprintf(mission->location, sizeof(mission->location), "%s", _(nation->name));
	} else {
		Com_sprintf(mission->location, sizeof(mission->location), "%s", _("No nation"));
	}
	CP_TerrorMissionStart(mission);
	mission->finalDate = mis->expire;
	mis->mission = mission;

	Com_Printf("spawned map '%s'\n", mis->def->id);

	scd->numActiveMissions++;
}
/**
 * @brief return true if the node size change and update the cache
 */
bool uiAbstractScrollableNode::isSizeChange (uiNode_t *node)
{
	assert(UI_Node_IsScrollableContainer(node));

	if (!Vector2Equal(node->box.size, EXTRADATA(node).cacheSize)) {
		Vector2Copy(node->box.size, EXTRADATA(node).cacheSize);
		return true;
	}
	return false;
}
Exemple #9
0
/*
===============
V_MergeOverviewRefdef

merge refdef with overview settings
===============
*/
void V_MergeOverviewRefdef( ref_params_t *fd )
{
	ref_overview_t	*ov = &clgame.overView;
	float		aspect;
	float		size_x, size_y;
	vec2_t		mins, maxs;

	if( !gl_overview->integer ) return;

	// NOTE: Xash3D may use 16:9 or 16:10 aspects
	aspect = (float)glState.width / (float)glState.height;

	size_x = fabs( 8192.0f / ov->flZoom );
	size_y = fabs( 8192.0f / (ov->flZoom * aspect ));

	// compute rectangle
	ov->xLeft = -(size_x / 2);
	ov->xRight = (size_x / 2);
	ov->xTop = -(size_y / 2);
	ov->xBottom = (size_y / 2);

	if( gl_overview->integer == 1 )
	{
		Con_NPrintf( 0, " Overview: Zoom %.2f, Map Origin (%.2f, %.2f, %.2f), Z Min %.2f, Z Max %.2f, Rotated %i\n",
		ov->flZoom, ov->origin[0], ov->origin[1], ov->origin[2], ov->zNear, ov->zFar, ov->rotated );
	}

	VectorCopy( ov->origin, fd->vieworg );
	fd->vieworg[2] = ov->zFar + ov->zNear;
	Vector2Copy( fd->vieworg, mins );
	Vector2Copy( fd->vieworg, maxs );

	mins[!ov->rotated] += ov->xLeft;
	maxs[!ov->rotated] += ov->xRight;
	mins[ov->rotated] += ov->xTop;
	maxs[ov->rotated] += ov->xBottom;

	fd->viewangles[0] = 90.0f;
	fd->viewangles[1] = 90.0f;
	fd->viewangles[2] = (ov->rotated) ? (ov->flZoom < 0.0f) ? 180.0f : 0.0f : (ov->flZoom < 0.0f) ? -90.0f : 90.0f;

	Mod_SetOrthoBounds( mins, maxs );
}
/**
 * @brief return true if the node size change and update the cache
 */
qboolean UI_AbstractScrollableNodeIsSizeChange (uiNode_t *node)
{
	assert(UI_NodeInstanceOf(node, "abstractscrollable"));

	if (!Vector2Equal(node->size, EXTRADATA(node).cacheSize)) {
		Vector2Copy(node->size, EXTRADATA(node).cacheSize);
		return qtrue;
	}
	return qfalse;
}
Exemple #11
0
static polyVert_t* createVertexArray(Rocket::Core::Vertex* vertices,
                                     int count) {
    polyVert_t* verts =
            static_cast<polyVert_t*>(Z_Malloc(sizeof(polyVert_t) * count));

    for (int i = 0; i < count; i++) {
        polyVert_t& polyVert = verts[i];
        Rocket::Core::Vertex& vert = vertices[i];

        Vector2Copy(vert.position, polyVert.xyz);

        polyVert.modulate[0] = vert.colour.red;
        polyVert.modulate[1] = vert.colour.green;
        polyVert.modulate[2] = vert.colour.blue;
        polyVert.modulate[3] = vert.colour.alpha;

        Vector2Copy(vert.tex_coord, polyVert.st);
    }

    return verts;
}
Exemple #12
0
/**
 * @brief Make the UFOs run
 * @param[in] campaign The campaign data structure
 * @param[in] deltaTime The time passed since last call
 */
void UFO_CampaignRunUFOs (const campaign_t* campaign, int deltaTime)
{
	int ufoIdx, k;

	/* now the ufos are flying around, too - cycle backward - ufo might be destroyed */
	for (ufoIdx = ccs.numUFOs - 1; ufoIdx >= 0; ufoIdx--) {
		aircraft_t *ufo = UFO_GetByIDX(ufoIdx);
		/* don't run a landed ufo */
		if (ufo->landed)
			continue;

		/* Every UFO on geoscape should have a mission assigned */
		assert(ufo->mission);

		/* reached target and not following a phalanx aircraft? then we need a new destination */
		if (AIR_AircraftMakeMove(deltaTime, ufo) && ufo->status != AIR_UFO) {
			float *end;
			end = ufo->route.point[ufo->route.numPoints - 1];
			Vector2Copy(end, ufo->pos);
			MAP_CheckPositionBoundaries(ufo->pos);
			if (ufo->mission->stage == STAGE_INTERCEPT && ufo->mission->data.aircraft) {
				/* Attacking an installation: fly over this installation */
				UFO_SetRandomDestAround(ufo, ufo->mission->pos);
			} else
				UFO_SetRandomDest(ufo);
			if (CP_CheckNextStageDestination(campaign, ufo))
				/* UFO has been removed from game */
				continue;
			/* UFO was destroyed (maybe because the mission was removed) */
			if (ufoIdx == ccs.numUFOs)
				continue;
		}

		/* is there a PHALANX aircraft to shoot at ? */
		UFO_SearchAircraftTarget(campaign, ufo);

		/* antimatter tanks */
		if (ufo->fuel <= 0)
			ufo->fuel = ufo->stats[AIR_STATS_FUELSIZE];

		/* Update delay to launch next projectile */
		for (k = 0; k < ufo->maxWeapons; k++) {
			aircraftSlot_t *slot = &ufo->weapons[k];
			if (slot->delayNextShot > 0)
				slot->delayNextShot -= deltaTime;
		}
	}
}
/**
 * @brief UFO starts to attack the installation.
 * @note Intercept mission -- Stage 2
 */
static void CP_InterceptAttackInstallation (mission_t* mission)
{
	const date_t minAttackDelay = {0, 3600};
	const date_t attackDelay = {0, 21600};		/* How long the UFO should stay on earth */
	installation_t* installation;
	vec3_t missionPos;

	mission->stage = STAGE_INTERCEPT;

	installation = mission->data.installation;
	Vector2Copy(mission->pos, missionPos);
	if (!VectorCompareEps(missionPos, installation->pos, UFO_EPSILON)) {
		mission->finalDate = ccs.date;
		return;
	}

	/* Make round around the position of the mission */
	UFO_SetRandomDestAround(mission->ufo, mission->pos);
	mission->finalDate = Date_Add(ccs.date, Date_Random(minAttackDelay, attackDelay));
}
/**
 * @brief Set Terror attack mission, and go to Terror attack mission pos.
 * @note Terror attack mission -- Stage 1
 * @note Terror missions can only take place in city: pick one in ccs.cities.
 */
static void CP_TerrorMissionGo (mission_t *mission)
{
	int counter;

	mission->stage = STAGE_MISSION_GOTO;

	/* Choose a map */
	for (counter = 0; counter < MAX_POS_LOOP; counter++) {
		city_t *city = CP_ChooseCity();

		if (!city)
			continue;

		if (GEO_PositionCloseToBase(city->pos))
			continue;

		if (!CP_ChooseMap(mission, city->pos))
			continue;

		if (CP_TerrorInCity(city))
			continue;

		Vector2Copy(city->pos, mission->pos);
		mission->data.city = city;
		mission->posAssigned = true;
		break;
	}
	if (counter >= MAX_POS_LOOP) {
		Com_DPrintf(DEBUG_CLIENT, "CP_TerrorMissionGo: Could not set position.\n");
		CP_MissionRemove(mission);
		return;
	}

	if (mission->ufo) {
		CP_MissionDisableTimeLimit(mission);
		UFO_SendToDestination(mission->ufo, mission->pos);
	} else {
		/* Go to next stage on next frame */
		mission->finalDate = ccs.date;
	}
}
/**
 * @brief Set Intercept mission: UFO chooses an installation an flies to it.
 * @note Intercept mission -- Stage 1
 */
void CP_InterceptGoToInstallation (mission_t* mission)
{
	installation_t* installation;
	assert(mission->ufo);

	mission->stage = STAGE_MISSION_GOTO;

	installation = CP_InterceptChooseInstallation(mission);
	if (!installation) {
		Com_Printf("CP_InterceptGoToInstallation: no installation found\n");
		CP_MissionRemove(mission);
		return;
	}
	mission->data.installation = installation;

	Vector2Copy(installation->pos, mission->pos);
	mission->posAssigned = true;

	CP_MissionDisableTimeLimit(mission);
	UFO_SendToDestination(mission->ufo, mission->pos);
}
/**
 * @brief Go to base position.
 * @param[in,out] mission Pointer to the mission
 * @note Supply mission -- Stage 1
 */
static void CP_SupplyGoToBase (mission_t *mission)
{
	alienBase_t *alienBase;

	assert(mission->ufo);

	mission->stage = STAGE_MISSION_GOTO;

	/* Maybe base has been destroyed since mission creation ? */
	if (!AB_CheckSupplyMissionPossible()) {
		Com_DPrintf(DEBUG_CLIENT, "No base in game: removing supply mission.\n");
		CP_MissionRemove(mission);
		return;
	}

	alienBase = AB_ChooseBaseToSupply();
	assert(alienBase);
	mission->data.alienBase = alienBase;
	Vector2Copy(alienBase->pos, mission->pos);

	UFO_SendToDestination(mission->ufo, mission->pos);
}
//----------------------------
void CPoly::Draw()
{
	polyVert_t	verts[MAX_CPOLY_VERTS];

	for ( int i = 0; i < mCount; i++ )
	{
		// Add our midpoint and vert offset to get the actual vertex
		VectorAdd( mOrigin1, mOrg[i], verts[i].xyz );

		// Assign the same color to each vert
		verts[i].modulate[0] = mRefEnt.shaderRGBA[0];
		verts[i].modulate[1] = mRefEnt.shaderRGBA[1];
		verts[i].modulate[2] = mRefEnt.shaderRGBA[2];
		verts[i].modulate[3] = mRefEnt.shaderRGBA[3];

		// Copy the ST coords
		Vector2Copy( mST[i], verts[i].st );
	}

	// Add this poly
	theFxHelper.AddPolyToScene( mRefEnt.customShader, mCount, verts );

	drawnFx++;
}
Exemple #18
0
/** @note Defaults should match those of ufo2map, or lighting will be inconsistent between world and models */
static void SP_worldspawn (const localEntityParse_t* entData)
{
	/* maximum level */
	cl.mapMaxLevel = entData->maxLevel;

	if (GAME_IsMultiplayer()) {
		if (cl_teamnum->integer > entData->maxMultiplayerTeams || cl_teamnum->integer <= TEAM_CIVILIAN) {
			Com_Printf("The selected team is not usable. "
				"The map doesn't support %i teams but only %i teams\n",
				cl_teamnum->integer, entData->maxMultiplayerTeams);
			Cvar_SetValue("cl_teamnum", TEAM_DEFAULT);
			Com_Printf("Set teamnum to %i\n", cl_teamnum->integer);
		}
	}

	/** @todo - make sun position/color vary based on local time at location? */
	const int dayLightmap = CL_GetConfigStringInteger(CS_LIGHTMAP);

	/** @note Some vectors have exra elements to comply with mathlib and/or OpenGL conventions, but handled as shorter ones */
	vec3_t sunAngles;
	vec4_t sunColor;
	vec_t sunIntensity;
	if (dayLightmap) {
		/* set defaults for daylight */
		Vector4Set(refdef.ambientColor, 0.26, 0.26, 0.26, 1.0);
		sunIntensity = 280;
		VectorSet(sunAngles, -75, 100, 0);
		Vector4Set(sunColor, 0.90, 0.75, 0.65, 1.0);

		/* override defaults with data from worldspawn entity, if any */
		if (VectorNotEmpty(entData->ambientDayColor))
			VectorCopy(entData->ambientDayColor, refdef.ambientColor);

		if (entData->dayLight)
			sunIntensity = entData->dayLight;

		if (Vector2NotEmpty(entData->daySunAngles))
			Vector2Copy(entData->daySunAngles, sunAngles);

		if (VectorNotEmpty(entData->daySunColor))
			VectorCopy(entData->daySunColor, sunColor);

		Vector4Set(refdef.sunSpecularColor, 1.0, 1.0, 0.9, 1);
	} else {
		/* set defaults for night light */
		Vector4Set(refdef.ambientColor, 0.16, 0.16, 0.17, 1.0);
		sunIntensity = 15;
		VectorSet(sunAngles, -80, 220, 0);
		Vector4Set(sunColor, 0.25, 0.25, 0.35, 1.0);

		/* override defaults with data from worldspawn entity, if any */
		if (VectorNotEmpty(entData->ambientNightColor))
			VectorCopy(entData->ambientNightColor, refdef.ambientColor);

		if (entData->nightLight)
			sunIntensity = entData->nightLight;

		if (Vector2NotEmpty(entData->nightSunAngles))
			Vector2Copy(entData->nightSunAngles, sunAngles);

		if (VectorNotEmpty(entData->nightSunColor))
			VectorCopy(entData->nightSunColor, sunColor);

		Vector4Set(refdef.sunSpecularColor, 0.5, 0.5, 0.7, 1);
	}

	ColorNormalize(sunColor, sunColor);
	VectorScale(sunColor, sunIntensity/255.0, sunColor);
	Vector4Copy(sunColor, refdef.sunDiffuseColor);

	/* clamp ambient for models */
	Vector4Copy(refdef.ambientColor, refdef.modelAmbientColor);
	for (int i = 0; i < 3; i++)
		if (refdef.modelAmbientColor[i] < MIN_AMBIENT_COMPONENT)
			refdef.modelAmbientColor[i] = MIN_AMBIENT_COMPONENT;

	/* scale it into a reasonable range, the clamp above ensures this will work */
	while (VectorSum(refdef.modelAmbientColor) < MIN_AMBIENT_SUM)
		VectorScale(refdef.modelAmbientColor, 1.25, refdef.modelAmbientColor);

	AngleVectors(sunAngles, refdef.sunVector, nullptr, nullptr);
	refdef.sunVector[3] = 0.0; /* to use as directional light source in OpenGL */

	/** @todo Parse fog from worldspawn config */
	refdef.weather = WEATHER_NONE;
	refdef.fogColor[3] = 1.0;
	VectorSet(refdef.fogColor, 0.75, 0.75, 0.75);
}
Exemple #19
0
void uiEkgNode::draw (uiNode_t *node)
{
	vec2_t size;
	vec2_t nodepos;
	const image_t *image;

	const char* imageName = UI_GetReferenceString(node, EXTRADATA(node).super.source);
	if (Q_strnull(imageName))
		return;

	UI_GetNodeAbsPos(node, nodepos);

	image = UI_LoadWrappedImage(imageName);
	if (image) {
		const int ekgHeight = node->box.size[1];
		const int ekgWidth = image->width;
		/* we have different ekg parts in each ekg image... */
		const int ekgImageParts = image->height / node->box.size[1];
		const int ekgMaxIndex = ekgImageParts - 1;
		/* we change the index of the image part in 20s steps */
		/** @todo this magic number should be replaced with a sane calculation of the value */
		const int ekgDivide = 20;
		/* If we are in the range of (ekgMaxValue + ekgDivide, ekgMaxValue) we are using the first image */
		const int ekgMaxValue = ekgDivide * ekgMaxIndex;
		int ekgValue;
		float current;

		/** @todo these cvars should come from the script */
		/* ekg_morale and ekg_hp are the node names */
		if (node->name[0] == 'm')
			current = Cvar_GetValue("mn_morale") / EXTRADATA(node).scaleCvarValue;
		else
			current = Cvar_GetValue("mn_hp") / EXTRADATA(node).scaleCvarValue;

		ekgValue = std::min((int)current, ekgMaxValue);

		EXTRADATA(node).super.texl[1] = (ekgMaxIndex - (int)(ekgValue / ekgDivide)) * ekgHeight;
		EXTRADATA(node).super.texh[1] = EXTRADATA(node).super.texl[1] + ekgHeight;
		EXTRADATA(node).super.texl[0] = -(int) (EXTRADATA(node).scrollSpeed * CL_Milliseconds()) % ekgWidth;
		EXTRADATA(node).super.texh[0] = EXTRADATA(node).super.texl[0] + node->box.size[0];
		/** @todo code is duplicated in the image node code */
		if (node->box.size[0] && !node->box.size[1]) {
			const float scale = image->width / node->box.size[0];
			Vector2Set(size, node->box.size[0], image->height / scale);
		} else if (node->box.size[1] && !node->box.size[0]) {
			const float scale = image->height / node->box.size[1];
			Vector2Set(size, image->width / scale, node->box.size[1]);
		} else {
			if (EXTRADATA(node).super.preventRatio) {
				/* maximize the image into the bounding box */
				const float ratio = (float) image->width / (float) image->height;
				if (node->box.size[1] * ratio > node->box.size[0]) {
					Vector2Set(size, node->box.size[0], node->box.size[0] / ratio);
				} else {
					Vector2Set(size, node->box.size[1] * ratio, node->box.size[1]);
				}
			} else {
				Vector2Copy(node->box.size, size);
			}
		}
		UI_DrawNormImage(false, nodepos[0], nodepos[1], size[0], size[1],
				EXTRADATA(node).super.texh[0], EXTRADATA(node).super.texh[1], EXTRADATA(node).super.texl[0], EXTRADATA(node).super.texl[1], image);
	}
}
Exemple #20
0
/**
 * @brief Calculates normals and tangents for all frames and does vertex merging based on smoothness
 * @param mesh The mesh to calculate normals for
 * @param nFrames How many frames the mesh has
 * @param smoothness How aggressively should normals be smoothed; value is compared with dotproduct of vectors to decide if they should be merged
 * @sa R_ModCalcNormalsAndTangents
 */
void R_ModCalcUniqueNormalsAndTangents (mAliasMesh_t *mesh, int nFrames, float smoothness)
{
	int i, j;
	vec3_t triangleNormals[MAX_ALIAS_TRIS];
	vec3_t triangleTangents[MAX_ALIAS_TRIS];
	vec3_t triangleBitangents[MAX_ALIAS_TRIS];
	const mAliasVertex_t *vertexes = mesh->vertexes;
	mAliasCoord_t *stcoords = mesh->stcoords;
	mAliasVertex_t *newVertexes;
	mAliasComplexVertex_t tmpVertexes[MAX_ALIAS_VERTS];
	vec3_t tmpBitangents[MAX_ALIAS_VERTS];
	mAliasCoord_t *newStcoords;
	const int numIndexes = mesh->num_tris * 3;
	const int32_t *indexArray = mesh->indexes;
	int32_t *newIndexArray;
	int indRemap[MAX_ALIAS_VERTS];
	int sharedTris[MAX_ALIAS_VERTS];
	int numVerts = 0;

	newIndexArray = (int32_t *)Mem_PoolAlloc(sizeof(int32_t) * numIndexes, vid_modelPool, 0);

	/* calculate per-triangle surface normals */
	for (i = 0, j = 0; i < numIndexes; i += 3, j++) {
		vec3_t dir1, dir2;
		vec2_t dir1uv, dir2uv;

		/* calculate two mostly perpendicular edge directions */
		VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1);
		VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2);
		Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv);
		Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv);

		/* we have two edge directions, we can calculate a third vector from
		 * them, which is the direction of the surface normal */
		CrossProduct(dir1, dir2, triangleNormals[j]);

		/* then we use the texture coordinates to calculate a tangent space */
		if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) {
			const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]);
			vec3_t tmp1, tmp2;

			/* calculate tangent */
			VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1);
			VectorMul(dir1uv[1] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleTangents[j]);

			/* calculate bitangent */
			VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1);
			VectorMul(dir1uv[0] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleBitangents[j]);
		} else {
			const float frac = 1.0 / (0.00001);
			vec3_t tmp1, tmp2;

			/* calculate tangent */
			VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1);
			VectorMul(dir1uv[1] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleTangents[j]);

			/* calculate bitangent */
			VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1);
			VectorMul(dir1uv[0] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleBitangents[j]);
		}

		/* normalize */
		VectorNormalizeFast(triangleNormals[j]);
		VectorNormalizeFast(triangleTangents[j]);
		VectorNormalizeFast(triangleBitangents[j]);

		Orthogonalize(triangleTangents[j], triangleBitangents[j]);
	}

	/* do smoothing */
	for (i = 0; i < numIndexes; i++) {
		const int idx = (i - i % 3) / 3;
		VectorCopy(triangleNormals[idx], tmpVertexes[i].normal);
		VectorCopy(triangleTangents[idx], tmpVertexes[i].tangent);
		VectorCopy(triangleBitangents[idx], tmpBitangents[i]);

		for (j = 0; j < numIndexes; j++) {
			const int idx2 = (j - j % 3) / 3;
			/* don't add a vertex with itself */
			if (j == i)
				continue;

			/* only average normals if vertices have the same position
			 * and the normals aren't too far apart to start with */
			if (VectorEqual(vertexes[indexArray[i]].point, vertexes[indexArray[j]].point)
					&& DotProduct(triangleNormals[idx], triangleNormals[idx2]) > smoothness) {
				/* average the normals */
				VectorAdd(tmpVertexes[i].normal, triangleNormals[idx2], tmpVertexes[i].normal);

				/* if the tangents match as well, average them too.
				 * Note that having matching normals without matching tangents happens
				 * when the order of vertices in two triangles sharing the vertex
				 * in question is different.  This happens quite frequently if the
				 * modeler does not go out of their way to avoid it. */

				if (Vector2Equal(stcoords[indexArray[i]], stcoords[indexArray[j]])
						&& DotProduct(triangleTangents[idx], triangleTangents[idx2]) > smoothness
						&& DotProduct(triangleBitangents[idx], triangleBitangents[idx2]) > smoothness) {
					/* average the tangents */
					VectorAdd(tmpVertexes[i].tangent, triangleTangents[idx2], tmpVertexes[i].tangent);
					VectorAdd(tmpBitangents[i], triangleBitangents[idx2], tmpBitangents[i]);
				}
			}
		}

		VectorNormalizeFast(tmpVertexes[i].normal);
		VectorNormalizeFast(tmpVertexes[i].tangent);
		VectorNormalizeFast(tmpBitangents[i]);
	}

	/* assume all vertices are unique until proven otherwise */
	for (i = 0; i < numIndexes; i++)
		indRemap[i] = -1;

	/* merge vertices that have become identical */
	for (i = 0; i < numIndexes; i++) {
		vec3_t n, b, t, v;
		if (indRemap[i] != -1)
			continue;

		for (j = i + 1; j < numIndexes; j++) {
			if (Vector2Equal(stcoords[indexArray[i]], stcoords[indexArray[j]])
					&& VectorEqual(vertexes[indexArray[i]].point, vertexes[indexArray[j]].point)
					&& (DotProduct(tmpVertexes[i].normal, tmpVertexes[j].normal) > smoothness)
					&& (DotProduct(tmpVertexes[i].tangent, tmpVertexes[j].tangent) > smoothness)) {
				indRemap[j] = i;
				newIndexArray[j] = numVerts;
			}
		}

		VectorCopy(tmpVertexes[i].normal, n);
		VectorCopy(tmpVertexes[i].tangent, t);
		VectorCopy(tmpBitangents[i], b);

		/* normalization here does shared-vertex smoothing */
		VectorNormalizeFast(n);
		VectorNormalizeFast(t);
		VectorNormalizeFast(b);

		/* Grahm-Schmidt orthogonalization */
		VectorMul(DotProduct(t, n), n, v);
		VectorSubtract(t, v, t);
		VectorNormalizeFast(t);

		/* calculate handedness */
		CrossProduct(n, t, v);
		tmpVertexes[i].tangent[3] = (DotProduct(v, b) < 0.0) ? -1.0 : 1.0;
		VectorCopy(n, tmpVertexes[i].normal);
		VectorCopy(t, tmpVertexes[i].tangent);

		newIndexArray[i] = numVerts++;
		indRemap[i] = i;
	}

	for (i = 0; i < numVerts; i++)
		sharedTris[i] = 0;

	for (i = 0; i < numIndexes; i++)
		sharedTris[newIndexArray[i]]++;

	/* set up reverse-index that maps Vertex objects to a list of triangle verts */
	mesh->revIndexes = (mIndexList_t *)Mem_PoolAlloc(sizeof(mIndexList_t) * numVerts, vid_modelPool, 0);
	for (i = 0; i < numVerts; i++) {
		mesh->revIndexes[i].length = 0;
		mesh->revIndexes[i].list = (int32_t *)Mem_PoolAlloc(sizeof(int32_t) * sharedTris[i], vid_modelPool, 0);
	}

	/* merge identical vertexes, storing only unique ones */
	newVertexes = (mAliasVertex_t *)Mem_PoolAlloc(sizeof(mAliasVertex_t) * numVerts * nFrames, vid_modelPool, 0);
	newStcoords = (mAliasCoord_t *)Mem_PoolAlloc(sizeof(mAliasCoord_t) * numVerts, vid_modelPool, 0);
	for (i = 0; i < numIndexes; i++) {
		const int idx = indexArray[indRemap[i]];
		const int idx2 = newIndexArray[i];

		/* add vertex to new vertex array */
		VectorCopy(vertexes[idx].point, newVertexes[idx2].point);
		Vector2Copy(stcoords[idx], newStcoords[idx2]);
		mesh->revIndexes[idx2].list[mesh->revIndexes[idx2].length++] = i;
	}

	/* copy over the points from successive frames */
	for (i = 1; i < nFrames; i++) {
		for (j = 0; j < numIndexes; j++) {
			const int idx = indexArray[indRemap[j]] + (mesh->num_verts * i);
			const int idx2 = newIndexArray[j] + (numVerts * i);

			VectorCopy(vertexes[idx].point, newVertexes[idx2].point);
		}
	}

	/* copy new arrays back into original mesh */
	Mem_Free(mesh->stcoords);
	Mem_Free(mesh->indexes);
	Mem_Free(mesh->vertexes);

	mesh->num_verts = numVerts;
	mesh->vertexes = newVertexes;
	mesh->stcoords = newStcoords;
	mesh->indexes = newIndexArray;
}
Exemple #21
0
/**
 * @brief Converts the model data into the opengl arrays
 * @param mod The model to convert
 * @param mesh The particular mesh of the model to convert
 * @param backlerp The linear back interpolation when loading the data
 * @param framenum The frame number of the mesh to load (if animated)
 * @param oldframenum The old frame number (used to interpolate)
 * @param prerender If this is @c true, all data is filled to the arrays. If @c false, then
 * e.g. the normals are only filled to the arrays if the lighting is activated.
 *
 * @note If GLSL programs are enabled, the actual interpolation will be done on the GPU, but
 * this function is still needed to fill the GL arrays for the keyframes
 */
void R_FillArrayData (mAliasModel_t* mod, mAliasMesh_t *mesh, float backlerp, int framenum, int oldframenum, qboolean prerender)
{
	const mAliasFrame_t *frame, *oldframe;
	vec3_t move;
	const float frontlerp = 1.0 - backlerp;
	vec3_t r_mesh_verts[MAX_ALIAS_VERTS];
	vec_t *texcoord_array, *vertex_array_3d;

	frame = mod->frames + framenum;
	oldframe = mod->frames + oldframenum;

	/* try to do keyframe-interpolation on the GPU if possible*/
	if (r_state.lighting_enabled) {
		/* we only need to change the array data if we've switched to a new keyframe */
		if (mod->curFrame != framenum) {
			/* if we're rendering frames in order, the "next" keyframe from the previous
			 * time through will be our "previous" keyframe now, so we can swap pointers
			 * instead of generating it again from scratch */
			if (mod->curFrame == oldframenum) {
				vec_t *tmp1 = mesh->verts;
				vec_t *tmp2 = mesh->normals;
				vec_t *tmp3 = mesh->tangents;

				mesh->verts = mesh->next_verts;
				mesh->next_verts = tmp1;

				mesh->normals = mesh->next_normals;
				mesh->next_normals = tmp2;

				mesh->tangents = mesh->next_tangents;
				mesh->next_tangents = tmp3;

				/* if we're alternating between two keyframes, we don't need to generate
				 * anything; otherwise, generate the "next" keyframe*/
				if (mod->oldFrame != framenum)
					R_ModCalcNormalsAndTangents(mesh, framenum, frame->translate, qfalse);
			} else {
				/* if we're starting a new animation or otherwise not rendering keyframes
				 * in order, we need to fill the arrays for both keyframes */
				R_ModCalcNormalsAndTangents(mesh, oldframenum, oldframe->translate, qtrue);
				R_ModCalcNormalsAndTangents(mesh, framenum, frame->translate, qfalse);
			}
			/* keep track of which keyframes are currently stored in our arrays */
			mod->oldFrame = oldframenum;
			mod->curFrame = framenum;
		}
	} else { /* otherwise, we have to do it on the CPU */
		const mAliasVertex_t *v, *ov;
		int i;
		assert(mesh->num_verts < lengthof(r_mesh_verts));
		v = &mesh->vertexes[framenum * mesh->num_verts];
		ov = &mesh->vertexes[oldframenum * mesh->num_verts];

		if (prerender)
			R_ModCalcNormalsAndTangents(mesh, 0, oldframe->translate, qtrue);

		for (i = 0; i < 3; i++)
			move[i] = backlerp * oldframe->translate[i] + frontlerp * frame->translate[i];

		for (i = 0; i < mesh->num_verts; i++, v++, ov++) {  /* lerp the verts */
			VectorSet(r_mesh_verts[i],
					move[0] + ov->point[0] * backlerp + v->point[0] * frontlerp,
					move[1] + ov->point[1] * backlerp + v->point[1] * frontlerp,
					move[2] + ov->point[2] * backlerp + v->point[2] * frontlerp);
		}

		texcoord_array = texunit_diffuse.texcoord_array;
		vertex_array_3d = r_state.vertex_array_3d;

		/** @todo damn slow - optimize this */
		for (i = 0; i < mesh->num_tris; i++) {  /* draw the tris */
			int j;
			for (j = 0; j < 3; j++) {
				const int arrayIndex = 3 * i + j;
				const int meshIndex = mesh->indexes[arrayIndex];
				Vector2Copy(mesh->stcoords[meshIndex], texcoord_array);
				VectorCopy(r_mesh_verts[meshIndex], vertex_array_3d);

				texcoord_array += 2;
				vertex_array_3d += 3;
			}
		}
	}
}
/**
 * @brief Draw the base inventory
 * @return The full height requested by the current view (not the node height)
 */
static int UI_BaseInventoryNodeDrawItems (uiNode_t* node, const objDef_t* highlightType)
{
	bool outOfNode = false;
	vec2_t nodepos;
	int items = 0;
	int rowHeight = 0;
	const int cellWidth = node->box.size[0] / EXTRADATA(node).columns;
	containerItemIterator_t iterator;
	int currentHeight = 0;
	UI_GetNodeAbsPos(node, nodepos);

	UI_ContainerItemIteratorInit(&iterator, node);
	for (; iterator.itemID < csi.numODs; UI_ContainerItemIteratorNext(&iterator)) {
		const int id = iterator.itemID;
		const objDef_t* obj = INVSH_GetItemByIDX(id);
		Item tempItem(obj, nullptr, 1);
		vec3_t pos;
		vec3_t ammopos;
		const float* color;
		bool isHighlight = false;
		int amount;
		const int col = items % EXTRADATA(node).columns;
		int cellHeight = 0;
		const Item* icItem = iterator.itemFound;

		/* skip items over and bellow the node view */
		if (outOfNode || currentHeight < EXTRADATA(node).scrollY.viewPos) {
			int height;
			R_FontTextSize("f_verysmall", _(obj->name),
				cellWidth - 5, LONGLINES_WRAP, nullptr, &height, nullptr, nullptr);
			height += obj->sy * C_UNIT + 10;
			if (height > rowHeight)
				rowHeight = height;

			if (outOfNode || currentHeight + rowHeight < EXTRADATA(node).scrollY.viewPos) {
				if (col == EXTRADATA(node).columns - 1) {
					currentHeight += rowHeight;
					rowHeight = 0;
				}
				items++;
				continue;
			}
		}

		Vector2Copy(nodepos, pos);
		pos[0] += cellWidth * col;
		pos[1] += currentHeight - EXTRADATA(node).scrollY.viewPos;
		pos[2] = 0;

		if (highlightType) {
			if (obj->isAmmo())
				isHighlight = obj->isLoadableInWeapon(highlightType);
			else
				isHighlight = highlightType->isLoadableInWeapon(obj);
		}

		if (icItem != nullptr) {
			if (isHighlight)
				color = colorLoadable;
			else
				color = colorDefault;
		} else {
			if (isHighlight)
				color = colorDisabledLoadable;
			else
				color = colorDisabledHiden;
		}

		if (icItem)
			amount = icItem->getAmount();
		else
			amount = 0;

		/* draw item */
		pos[0] += obj->sx * C_UNIT / 2.0;
		pos[1] += obj->sy * C_UNIT / 2.0;
		UI_DrawItem(node, pos, &tempItem, -1, -1, scale, color);
		UI_DrawString("f_verysmall", ALIGN_LC,
			pos[0] + obj->sx * C_UNIT / 2.0, pos[1] + obj->sy * C_UNIT / 2.0,
			pos[0] + obj->sx * C_UNIT / 2.0, cellWidth - 5, /* maxWidth */
			0, va("x%i", amount));
		pos[0] -= obj->sx * C_UNIT / 2.0;
		pos[1] += obj->sy * C_UNIT / 2.0;
		cellHeight += obj->sy * C_UNIT;

		/* save position for ammo */
		Vector2Copy(pos, ammopos);
		ammopos[2] = 0;
		ammopos[0] += obj->sx * C_UNIT + 10;

		/* draw the item name. */
		cellHeight += UI_DrawString("f_verysmall", ALIGN_UL,
			pos[0], pos[1],
			pos[0], cellWidth - 5, /* max width */
			0, _(obj->name));

		/* draw ammos of weapon */
		if (obj->weapon && EXTRADATA(node).displayAmmoOfWeapon) {
			for (int ammoIdx = 0; ammoIdx < obj->numAmmos; ammoIdx++) {
				tempItem.setDef(obj->ammos[ammoIdx]);

				/* skip weapos that are their own ammo -- oneshot and such */
				if (obj == tempItem.def())
					continue;

				/* skip unusable ammo */
				if (!GAME_ItemIsUseable(tempItem.def()))
					continue;

				/* find and skip none existing ammo */
				icItem = UI_ContainerNodeGetExistingItem(node, tempItem.def(), (itemFilterTypes_t) EXTRADATA(node).filterEquipType);
				if (!icItem)
					continue;

				/* Calculate the center of the item model/image. */
				ammopos[0] += icItem->def()->sx * C_UNIT / 2.0;
				ammopos[1] -= icItem->def()->sy * C_UNIT / 2.0;
				UI_DrawItem(node, ammopos, &tempItem, -1, -1, scale, colorDefault);
				UI_DrawString("f_verysmall", ALIGN_LC,
					ammopos[0] + icItem->def()->sx * C_UNIT / 2.0, ammopos[1] + icItem->def()->sy * C_UNIT / 2.0,
					ammopos[0] + icItem->def()->sx * C_UNIT / 2.0, cellWidth - 5 - ammopos[0],	/* maxWidth */
					0, va("x%i", icItem->getAmount()));
				ammopos[0] += icItem->def()->sx * C_UNIT / 2.0;
				ammopos[1] += icItem->def()->sy * C_UNIT / 2.0;
			}
		}
		cellHeight += 10;

		if (cellHeight > rowHeight) {
			rowHeight = cellHeight;
		}

		/* add a marge between rows */
		if (col == EXTRADATA(node).columns - 1) {
			currentHeight += rowHeight;
			rowHeight = 0;
			if (currentHeight - EXTRADATA(node).scrollY.viewPos >= node->box.size[1])
				outOfNode = true;
		}

		/* count items */
		items++;
	}

	if (rowHeight != 0) {
		currentHeight += rowHeight;
	}
	return currentHeight;
}
Exemple #23
0
/**
 * @brief Calculates a per-vertex tangentspace basis and stores it in GL arrays attached to the mesh
 * @param mesh The mesh to calculate normals for
 * @param framenum The animation frame to calculate normals for
 * @param translate The frame translation for the given animation frame
 * @param backlerp Whether to store the results in the GL arrays for the previous keyframe or the next keyframe
 * @sa R_ModCalcUniqueNormalsAndTangents
 */
static void R_ModCalcNormalsAndTangents (mAliasMesh_t *mesh, int framenum, const vec3_t translate, qboolean backlerp)
{
	int i, j;
	mAliasVertex_t *vertexes = &mesh->vertexes[framenum * mesh->num_verts];
	mAliasCoord_t *stcoords = mesh->stcoords;
	const int numIndexes = mesh->num_tris * 3;
	const int32_t *indexArray = mesh->indexes;
	vec3_t triangleNormals[MAX_ALIAS_TRIS];
	vec3_t triangleTangents[MAX_ALIAS_TRIS];
	vec3_t triangleBitangents[MAX_ALIAS_TRIS];
	float *texcoords, *verts, *normals, *tangents;

	/* set up array pointers for either the previous keyframe or the next keyframe */
	texcoords = mesh->texcoords;
	if (backlerp) {
		verts = mesh->verts;
		normals = mesh->normals;
		tangents = mesh->tangents;
	} else {
		verts = mesh->next_verts;
		normals = mesh->next_normals;
		tangents = mesh->next_tangents;
	}

	/* calculate per-triangle surface normals and tangents*/
	for (i = 0, j = 0; i < numIndexes; i += 3, j++) {
		vec3_t dir1, dir2;
		vec2_t dir1uv, dir2uv;

		/* calculate two mostly perpendicular edge directions */
		VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1);
		VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2);
		Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv);
		Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv);

		/* we have two edge directions, we can calculate a third vector from
		 * them, which is the direction of the surface normal */
		CrossProduct(dir1, dir2, triangleNormals[j]);
		/* normalize */
		VectorNormalizeFast(triangleNormals[j]);

		/* then we use the texture coordinates to calculate a tangent space */
		if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) {
			const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]);
			vec3_t tmp1, tmp2;

			/* calculate tangent */
			VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1);
			VectorMul(dir1uv[1] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleTangents[j]);

			/* calculate bitangent */
			VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1);
			VectorMul(dir1uv[0] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleBitangents[j]);

			/* normalize */
			VectorNormalizeFast(triangleTangents[j]);
			VectorNormalizeFast(triangleBitangents[j]);
		} else {
			VectorClear(triangleTangents[j]);
			VectorClear(triangleBitangents[j]);
		}
	}

	/* for each vertex */
	for (i = 0; i < mesh->num_verts; i++) {
		vec3_t n, b, v;
		vec4_t t;
		const int len = mesh->revIndexes[i].length;
		const int32_t *list = mesh->revIndexes[i].list;

		VectorClear(n);
		VectorClear(t);
		VectorClear(b);

		/* for each vertex that got mapped to this one (ie. for each triangle this vertex is a part of) */
		for (j = 0; j < len; j++) {
			const int32_t idx = list[j] / 3;
			VectorAdd(n, triangleNormals[idx], n);
			VectorAdd(t, triangleTangents[idx], t);
			VectorAdd(b, triangleBitangents[idx], b);
		}

		/* normalization here does shared-vertex smoothing */
		VectorNormalizeFast(n);
		VectorNormalizeFast(t);
		VectorNormalizeFast(b);

		/* Grahm-Schmidt orthogonalization */
		Orthogonalize(t, n);

		/* calculate handedness */
		CrossProduct(n, t, v);
		t[3] = (DotProduct(v, b) < 0.0) ? -1.0 : 1.0;

		/* copy this vertex's info to all the right places in the arrays */
		for (j = 0; j < len; j++) {
			const int32_t idx = list[j];
			const int meshIndex = mesh->indexes[list[j]];
			Vector2Copy(stcoords[meshIndex], (texcoords + (2 * idx)));
			VectorAdd(vertexes[meshIndex].point, translate, (verts + (3 * idx)));
			VectorCopy(n, (normals + (3 * idx)));
			Vector4Copy(t, (tangents + (4 * idx)));
		}
	}
}
Exemple #24
0
static void PopulateWithBSPModel(bspModel_t * model, matrix_t transform)
{
	int             i, j, x, y, pw[5], r, nodeNum;
	bspDrawSurface_t *ds;
	surfaceInfo_t  *info;
	bspDrawVert_t  *verts;
	int            *indexes;
	mesh_t          srcMesh, *mesh, *subdivided;
	traceInfo_t     ti;
	traceWinding_t  tw;


	/* dummy check */
	if(model == NULL || transform == NULL)
		return;

	/* walk the list of surfaces in this model and fill out the info structs */
	for(i = 0; i < model->numBSPSurfaces; i++)
	{
		/* get surface and info */
		ds = &bspDrawSurfaces[model->firstBSPSurface + i];
		info = &surfaceInfos[model->firstBSPSurface + i];
		if(info->si == NULL)
			continue;

		/* no shadows */
		if(!info->castShadows)
			continue;

		/* patchshadows? */
		if(ds->surfaceType == MST_PATCH && patchShadows == qfalse)
			continue;

		/* some surfaces in the bsp might have been tagged as nodraw, with a bogus shader */
		if((bspShaders[ds->shaderNum].contentFlags & noDrawContentFlags) ||
		   (bspShaders[ds->shaderNum].surfaceFlags & noDrawSurfaceFlags))
			continue;

		/* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */
		if((info->si->compileFlags & C_NODRAW))
			continue;
		if((info->si->compileFlags & C_TRANSLUCENT) &&
		   !(info->si->compileFlags & C_ALPHASHADOW) && !(info->si->compileFlags & C_LIGHTFILTER))
			continue;

		/* setup trace info */
		ti.si = info->si;
		ti.castShadows = info->castShadows;
		ti.surfaceNum = model->firstBSPBrush + i;
		ti.skipGrid = (ds->surfaceType == MST_PATCH);

		/* choose which node (normal or skybox) */
		if(info->parentSurfaceNum >= 0)
		{
			nodeNum = skyboxNodeNum;

			/* sky surfaces in portal skies are ignored */
			if(info->si->compileFlags & C_SKY)
				continue;
		}
		else
			nodeNum = headNodeNum;

		/* setup trace winding */
		memset(&tw, 0, sizeof(tw));
		tw.infoNum = AddTraceInfo(&ti);
		tw.numVerts = 3;

		/* switch on type */
		switch (ds->surfaceType)
		{
				/* handle patches */
			case MST_PATCH:
				/* subdivide the surface */
				srcMesh.width = ds->patchWidth;
				srcMesh.height = ds->patchHeight;
				srcMesh.verts = &bspDrawVerts[ds->firstVert];
				//% subdivided = SubdivideMesh( srcMesh, 8, 512 );
				subdivided = SubdivideMesh2(srcMesh, info->patchIterations);

				/* fit it to the curve and remove colinear verts on rows/columns */
				PutMeshOnCurve(*subdivided);
				mesh = RemoveLinearMeshColumnsRows(subdivided);
				FreeMesh(subdivided);

				/* set verts */
				verts = mesh->verts;

				/* subdivide each quad to place the models */
				for(y = 0; y < (mesh->height - 1); y++)
				{
					for(x = 0; x < (mesh->width - 1); x++)
					{
						/* set indexes */
						pw[0] = x + (y * mesh->width);
						pw[1] = x + ((y + 1) * mesh->width);
						pw[2] = x + 1 + ((y + 1) * mesh->width);
						pw[3] = x + 1 + (y * mesh->width);
						pw[4] = x + (y * mesh->width);	/* same as pw[ 0 ] */

						/* set radix */
						r = (x + y) & 1;

						/* make first triangle */
						VectorCopy(verts[pw[r + 0]].xyz, tw.v[0].xyz);
						Vector2Copy(verts[pw[r + 0]].st, tw.v[0].st);
						VectorCopy(verts[pw[r + 1]].xyz, tw.v[1].xyz);
						Vector2Copy(verts[pw[r + 1]].st, tw.v[1].st);
						VectorCopy(verts[pw[r + 2]].xyz, tw.v[2].xyz);
						Vector2Copy(verts[pw[r + 2]].st, tw.v[2].st);
						MatrixTransformPoint2(transform, tw.v[0].xyz);
						MatrixTransformPoint2(transform, tw.v[1].xyz);
						MatrixTransformPoint2(transform, tw.v[2].xyz);
						FilterTraceWindingIntoNodes_r(&tw, nodeNum);

						/* make second triangle */
						VectorCopy(verts[pw[r + 0]].xyz, tw.v[0].xyz);
						Vector2Copy(verts[pw[r + 0]].st, tw.v[0].st);
						VectorCopy(verts[pw[r + 2]].xyz, tw.v[1].xyz);
						Vector2Copy(verts[pw[r + 2]].st, tw.v[1].st);
						VectorCopy(verts[pw[r + 3]].xyz, tw.v[2].xyz);
						Vector2Copy(verts[pw[r + 3]].st, tw.v[2].st);
						MatrixTransformPoint2(transform, tw.v[0].xyz);
						MatrixTransformPoint2(transform, tw.v[1].xyz);
						MatrixTransformPoint2(transform, tw.v[2].xyz);
						FilterTraceWindingIntoNodes_r(&tw, nodeNum);
					}
				}

				/* free the subdivided mesh */
				FreeMesh(mesh);
				break;

				/* handle triangle surfaces */
			case MST_TRIANGLE_SOUP:
			case MST_PLANAR:
				/* set verts and indexes */
				verts = &bspDrawVerts[ds->firstVert];
				indexes = &bspDrawIndexes[ds->firstIndex];

				/* walk the triangle list */
				for(j = 0; j < ds->numIndexes; j += 3)
				{
					VectorCopy(verts[indexes[j]].xyz, tw.v[0].xyz);
					Vector2Copy(verts[indexes[j]].st, tw.v[0].st);
					VectorCopy(verts[indexes[j + 1]].xyz, tw.v[1].xyz);
					Vector2Copy(verts[indexes[j + 1]].st, tw.v[1].st);
					VectorCopy(verts[indexes[j + 2]].xyz, tw.v[2].xyz);
					Vector2Copy(verts[indexes[j + 2]].st, tw.v[2].st);
					MatrixTransformPoint2(transform, tw.v[0].xyz);
					MatrixTransformPoint2(transform, tw.v[1].xyz);
					MatrixTransformPoint2(transform, tw.v[2].xyz);
					FilterTraceWindingIntoNodes_r(&tw, nodeNum);
				}
				break;

				/* other surface types do not cast shadows */
			default:
				break;
		}
	}
}
Exemple #25
0
static void PopulateWithPicoModel(int castShadows, picoModel_t * model, matrix_t transform)
{
	int             i, j, k, numSurfaces, numIndexes;
	picoSurface_t  *surface;
	picoShader_t   *shader;
	picoVec_t      *xyz, *st;
	picoIndex_t    *indexes;
	traceInfo_t     ti;
	traceWinding_t  tw;


	/* dummy check */
	if(model == NULL || transform == NULL)
		return;

	/* get info */
	numSurfaces = PicoGetModelNumSurfaces(model);

	/* walk the list of surfaces in this model and fill out the info structs */
	for(i = 0; i < numSurfaces; i++)
	{
		/* get surface */
		surface = PicoGetModelSurface(model, i);
		if(surface == NULL)
			continue;

		/* only handle triangle surfaces initially (fixme: support patches) */
		if(PicoGetSurfaceType(surface) != PICO_TRIANGLES)
			continue;

		/* get shader (fixme: support shader remapping) */
		shader = PicoGetSurfaceShader(surface);
		if(shader == NULL)
			continue;
		ti.si = ShaderInfoForShader(PicoGetShaderName(shader));
		if(ti.si == NULL)
			continue;

		/* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */
		if((ti.si->compileFlags & C_NODRAW))
			continue;
		if((ti.si->compileFlags & C_TRANSLUCENT) &&
		   !(ti.si->compileFlags & C_ALPHASHADOW) && !(ti.si->compileFlags & C_LIGHTFILTER))
			continue;

		/* setup trace info */
		ti.castShadows = castShadows;
		ti.surfaceNum = -1;
		ti.skipGrid = qtrue;	// also ignore picomodels when skipping patches

		/* setup trace winding */
		memset(&tw, 0, sizeof(tw));
		tw.infoNum = AddTraceInfo(&ti);
		tw.numVerts = 3;

		/* get info */
		numIndexes = PicoGetSurfaceNumIndexes(surface);
		indexes = PicoGetSurfaceIndexes(surface, 0);

		/* walk the triangle list */
		for(j = 0; j < numIndexes; j += 3, indexes += 3)
		{
			for(k = 0; k < 3; k++)
			{
				xyz = PicoGetSurfaceXYZ(surface, indexes[k]);
				st = PicoGetSurfaceST(surface, 0, indexes[k]);
				VectorCopy(xyz, tw.v[k].xyz);
				Vector2Copy(st, tw.v[k].st);
				MatrixTransformPoint2(transform, tw.v[k].xyz);
			}
			FilterTraceWindingIntoNodes_r(&tw, headNodeNum);
		}
	}
}
/**
 * @note this function is a copy-paste of UI_ContainerNodeDrawItems (with remove of unneeded code)
 */
static Item* UI_BaseInventoryNodeGetItem (const uiNode_t* const node, int mouseX, int mouseY, int* contX, int* contY)
{
	bool outOfNode = false;
	vec2_t nodepos;
	int items = 0;
	int rowHeight = 0;
	const int cellWidth = node->box.size[0] / EXTRADATACONST(node).columns;
	int tempX, tempY;
	containerItemIterator_t iterator;
	int currentHeight = 0;

	if (!contX)
		contX = &tempX;
	if (!contY)
		contY = &tempY;

	UI_GetNodeAbsPos(node, nodepos);

	UI_ContainerItemIteratorInit(&iterator, node);
	for (; iterator.itemID < csi.numODs; UI_ContainerItemIteratorNext(&iterator)) {
		const int id = iterator.itemID;
		const objDef_t* obj = INVSH_GetItemByIDX(id);
		vec2_t pos;
		vec2_t ammopos;
		const int col = items % EXTRADATACONST(node).columns;
		int cellHeight = 0;
		Item* icItem = iterator.itemFound;
		int height;

		/* skip items over and bellow the node view */
		if (outOfNode || currentHeight < EXTRADATACONST(node).scrollY.viewPos) {
			int outHeight;
			R_FontTextSize("f_verysmall", _(obj->name),
				cellWidth - 5, LONGLINES_WRAP, nullptr, &outHeight, nullptr, nullptr);
			outHeight += obj->sy * C_UNIT + 10;
			if (outHeight > rowHeight)
				rowHeight = outHeight;

			if (outOfNode || currentHeight + rowHeight < EXTRADATACONST(node).scrollY.viewPos) {
				if (col == EXTRADATACONST(node).columns - 1) {
					currentHeight += rowHeight;
					rowHeight = 0;
				}
				items++;
				continue;
			}
		}

		Vector2Copy(nodepos, pos);
		pos[0] += cellWidth * col;
		pos[1] += currentHeight - EXTRADATACONST(node).scrollY.viewPos;

		/* check item */
		if (mouseY < pos[1])
			break;
		if (mouseX >= pos[0] && mouseX < pos[0] + obj->sx * C_UNIT
		 && mouseY >= pos[1] && mouseY < pos[1] + obj->sy * C_UNIT) {
			if (icItem) {
				*contX = icItem->getX();
				*contY = icItem->getY();
				return icItem;
			}
			return nullptr;
		}
		pos[1] += obj->sy * C_UNIT;
		cellHeight += obj->sy * C_UNIT;

		/* save position for ammo */
		Vector2Copy(pos, ammopos);
		ammopos[0] += obj->sx * C_UNIT + 10;

		/* draw the item name. */
		R_FontTextSize("f_verysmall", _(obj->name),
			cellWidth - 5, LONGLINES_WRAP, nullptr, &height, nullptr, nullptr);
		cellHeight += height;

		/* draw ammos of weapon */
		if (obj->weapon && EXTRADATACONST(node).displayAmmoOfWeapon) {
			for (int ammoIdx = 0; ammoIdx < obj->numAmmos; ammoIdx++) {
				const objDef_t* objammo = obj->ammos[ammoIdx];

				/* skip unusable ammo */
				if (!GAME_ItemIsUseable(objammo))
					continue;

				/* find and skip none existing ammo */
				icItem = UI_ContainerNodeGetExistingItem(node, objammo, (itemFilterTypes_t) EXTRADATACONST(node).filterEquipType);
				if (!icItem)
					continue;

				/* check ammo (ammopos in on the left-lower corner) */
				if (mouseX < ammopos[0] || mouseY >= ammopos[1])
					break;
				if (mouseX >= ammopos[0] && mouseX < ammopos[0] + objammo->sx * C_UNIT
				 && mouseY >= ammopos[1] - objammo->sy * C_UNIT && mouseY < ammopos[1]) {
					*contX = icItem->getX();
					*contY = icItem->getY();
					return icItem;
				}
				ammopos[0] += objammo->sx * C_UNIT;
			}
		}
		cellHeight += 10;

		if (cellHeight > rowHeight) {
			rowHeight = cellHeight;
		}

		/* add a margin between rows */
		if (col == EXTRADATACONST(node).columns - 1) {
			currentHeight += rowHeight;
			rowHeight = 0;
			if (currentHeight - EXTRADATACONST(node).scrollY.viewPos >= node->box.size[1])
				return nullptr;
		}

		/* count items */
		items++;
	}

	*contX = NONE;
	*contY = NONE;
	return nullptr;
}
void uiGeoscapeNode::draw (uiNode_t* node)
{
    vec2_t screenPos;

    geoscapeNode = node;
    UI_MAPEXTRADATA(node).flatgeoscape = cl_3dmap->integer == 0;
    UI_MAPEXTRADATA(node).radarOverlay = Cvar_GetValue("geo_overlay_radar");
    UI_MAPEXTRADATA(node).nationOverlay = Cvar_GetValue("geo_overlay_nation");
    UI_MAPEXTRADATA(node).xviOverlay = Cvar_GetValue("geo_overlay_xvi");
    UI_MAPEXTRADATA(node).ambientLightFactor = cl_3dmapAmbient->value;
    UI_MAPEXTRADATA(node).mapzoommin = cl_mapzoommin->value;
    UI_MAPEXTRADATA(node).mapzoommax = cl_mapzoommax->value;

    UI_GetNodeAbsPos(node, UI_MAPEXTRADATA(node).mapPos);
    Vector2Copy(node->box.size, UI_MAPEXTRADATA(node).mapSize);
    if (!UI_MAPEXTRADATACONST(node).flatgeoscape) {
        /* remove the left padding */
        UI_MAPEXTRADATA(node).mapSize[0] -= UI_MAPEXTRADATACONST(node).paddingRight;
    }

    /* Draw geoscape */
    UI_GetNodeScreenPos(node, screenPos);
    UI_PushClipRect(screenPos[0], screenPos[1], node->box.size[0], node->box.size[1]);

    if (UI_MAPEXTRADATACONST(node).smoothRotation) {
        if (UI_MAPEXTRADATACONST(node).flatgeoscape)
            smoothTranslate(node);
        else
            smoothRotate(node);
    }

    geoscapeData_t& data = *UI_MAPEXTRADATA(node).geoscapeData;
    data.geoscapeNode = node;
    GAME_DrawMap(&data);
    if (!data.active)
        return;

    const char* map = data.map;
    date_t& date = data.date;

    /* Draw the map and markers */
    if (UI_MAPEXTRADATACONST(node).flatgeoscape) {
        /* the last q value for the 2d geoscape night overlay */
        static float lastQ = 0.0f;

        /* the sun is not always in the plane of the equator on earth - calculate the angle the sun is at */
        const float q = (date.day % DAYS_PER_YEAR + (float)(date.sec / (SECONDS_PER_HOUR * 6)) / 4) * 2 * M_PI / DAYS_PER_YEAR - M_PI;
        if (lastQ != q) {
            calcAndUploadDayAndNightTexture(node, q);
            lastQ = q;
        }
        R_DrawFlatGeoscape(UI_MAPEXTRADATACONST(node).mapPos, UI_MAPEXTRADATACONST(node).mapSize, (float) date.sec / SECONDS_PER_DAY,
                           UI_MAPEXTRADATACONST(node).center[0], UI_MAPEXTRADATACONST(node).center[1], 0.5 / UI_MAPEXTRADATACONST(node).zoom, map,
                           data.nationOverlay, data.xviOverlay, data.radarOverlay, r_dayandnightTexture, r_xviTexture, r_radarTexture);

        GAME_DrawMapMarkers(node);
    } else {
        bool disableSolarRender = false;
        if (UI_MAPEXTRADATACONST(node).zoom > 3.3)
            disableSolarRender = true;

        R_EnableRenderbuffer(true);

        R_Draw3DGlobe(UI_MAPEXTRADATACONST(node).mapPos, UI_MAPEXTRADATACONST(node).mapSize, date.day, date.sec,
                      UI_MAPEXTRADATACONST(node).angles, UI_MAPEXTRADATACONST(node).zoom, map, disableSolarRender,
                      UI_MAPEXTRADATACONST(node).ambientLightFactor, UI_MAPEXTRADATA(node).nationOverlay,
                      UI_MAPEXTRADATA(node).xviOverlay, UI_MAPEXTRADATA(node).radarOverlay, r_xviTexture, r_radarTexture,
                      true);

        GAME_DrawMapMarkers(node);

        R_DrawBloom();
        R_EnableRenderbuffer(false);
    }

    UI_PopClipRect();
}
Exemple #28
0
//-------------------------
//  FX_AddPoly
//-------------------------
CPoly *FX_AddPoly( vec3_t *verts, vec2_t *st, int numVerts, 
							vec3_t vel, vec3_t accel,
							float alpha1, float alpha2, float alphaParm,
							vec3_t rgb1, vec3_t rgb2, float rgbParm,
							vec3_t rotationDelta, float bounce, int motionDelay,
							int killTime, qhandle_t shader, int flags )
{
	if ( theFxHelper.mFrameTime < 0 || !verts )
	{ // disallow adding effects when the system is paused or the user doesn't pass in a vert array
		return 0;
	}

	CPoly *fx = new CPoly;

	if ( fx )
	{
		// Do a cheesy copy of the verts and texture coords into our own structure
		for ( int i = 0; i < numVerts; i++ )
		{
			VectorCopy( verts[i], fx->mOrg[i] );
			Vector2Copy( st[i], fx->mST[i] );
		}

		fx->SetVel( vel );
		fx->SetAccel( accel );

		// RGB----------------
		fx->SetRGBStart( rgb1 );
		fx->SetRGBEnd( rgb2 );

		if (( flags & FX_RGB_PARM_MASK ) == FX_RGB_WAVE )
		{
			fx->SetRGBParm( rgbParm * PI * 0.001f );
		}
		else if ( flags & FX_RGB_PARM_MASK )
		{
			// rgbParm should be a value from 0-100..
			fx->SetRGBParm(rgbParm * 0.01f * killTime + theFxHelper.mTime + theFxHelper.mTimeFraction);
		}

		// Alpha----------------
		fx->SetAlphaStart( alpha1 );
		fx->SetAlphaEnd( alpha2 );

		if (( flags & FX_ALPHA_PARM_MASK ) == FX_ALPHA_WAVE )
		{
			fx->SetAlphaParm( alphaParm * PI * 0.001f );
		}
		else if ( flags & FX_ALPHA_PARM_MASK )
		{
			fx->SetAlphaParm(alphaParm * 0.01f * killTime + theFxHelper.mTime + theFxHelper.mTimeFraction);
		}

		fx->SetFlags( flags );
		fx->SetShader( shader );
		fx->SetRot( rotationDelta );
		fx->SetElasticity( bounce );
		fx->SetMotionTimeStamp( motionDelay );
		fx->SetNumVerts( numVerts );

		// Now that we've set our data up, let's process it into a useful format
		fx->PolyInit();

		FX_AddPrimitive( (CEffect**)&fx, killTime );
	}

	return fx;
}
Exemple #29
0
/**
 * @brief Calculate some radar values that won't change during a mission
 * @note Called for every new map (client_state_t is wiped with every
 * level change)
 */
static void UI_InitRadar (const uiNode_t* node)
{
	int i, j;
	const vec3_t offset = {MAP_SIZE_OFFSET, MAP_SIZE_OFFSET, MAP_SIZE_OFFSET};
	float distAB, distBC;
	vec2_t gridSize;		/**< Size of the whole grid (in tiles units) */
	vec2_t nodepos;
	vec2_t min;
	vec2_t max;

	UI_FreeRadarImages();
	UI_BuildRadarImageList(CL_GetConfigString(CS_TILES), CL_GetConfigString(CS_POSITIONS));

	UI_GetNodeAbsPos(node, nodepos);
	radar.x = nodepos[0] + node->box.size[0] / 2;
	radar.y = nodepos[1] + node->box.size[1] / 2;

	/* only check once per map whether all the needed images exist */
	for (j = 0; j < radar.numImages; j++) {
		hudRadarImage_t* tile = &radar.images[j];
		/* map_mins, map_maxs */
		for (i = 0; i < PATHFINDING_HEIGHT; i++) {
			char imagePath[MAX_QPATH];
			const image_t* image;
			if (!UI_CheckRadarImage(tile->name, i + 1)) {
				if (i == 0) {
					/* there should be at least one level */
					Com_Printf("No radar images for map: '%s'\n", tile->name);
					radar.numImages = 0;
					return;
				}
				continue;
			}

			Com_sprintf(imagePath, sizeof(imagePath), "radars/%s_%i", tile->name, i + 1);
			tile->path[i] = Mem_StrDup(imagePath);
			tile->maxlevel++;

			image = R_FindImage(va("pics/%s", tile->path[i]), it_pic);
			tile->width = image->width;
			tile->height = image->height;
			if (tile->isTile) {
				tile->gridWidth = round(image->width / 94.0f);
				tile->gridHeight = round(image->height / 94.0f);
				tile->mapWidth = tile->gridWidth * 8 * UNIT_SIZE;
				tile->mapHeight = tile->gridHeight * 8 * UNIT_SIZE;
			} else {
				tile->mapX = cl.mapData->mapBox.getMinX();
				tile->mapY = cl.mapData->mapBox.getMinY();
				tile->mapWidth = cl.mapData->mapBox.getWidthX();
				tile->mapHeight = cl.mapData->mapBox.getWidthY();
			}
		}
		if (tile->isTile) {
			tile->mapY = cl.mapData->mapBox.getMaxY() - tile->mapY - tile->mapHeight;
		}
	}

	/* center tiles into the minMap/maxMap */
	Vector2Copy(cl.mapData->mapBox.maxs, min);
	Vector2Copy(cl.mapData->mapBox.mins, max);
	for (j = 0; j < radar.numImages; j++) {
		hudRadarImage_t* tile = &radar.images[j];
		if (tile->mapX < min[0])
			min[0] = tile->mapX;
		if (tile->mapY < min[1])
			min[1] = tile->mapY;
		if (tile->mapX + tile->mapWidth > max[0])
			max[0] = tile->mapX + tile->mapWidth;
		if (tile->mapY + tile->mapHeight > max[1])
			max[1] = tile->mapY + tile->mapHeight;
	}
	/* compute translation */
	min[0] = cl.mapData->mapBox.getMinX() + (cl.mapData->mapBox.getWidthX() - (max[0] - min[0])) * 0.5 - min[0];
	min[1] = cl.mapData->mapBox.getMinY() + (cl.mapData->mapBox.getWidthY() - (max[1] - min[1])) * 0.5 - min[1];
	for (j = 0; j < radar.numImages; j++) {
		hudRadarImage_t* tile = &radar.images[j];
		tile->mapX += min[0];
		tile->mapY += min[1];
	}

	/* get the three points of the triangle */
	VectorSubtract(cl.mapData->mapBox.mins, offset, radar.a);
	VectorAdd(cl.mapData->mapBox.maxs, offset, radar.c);
	VectorSet(radar.b, radar.c[0], radar.a[1], 0);

	distAB = (Vector2Dist(radar.a, radar.b) / UNIT_SIZE);
	distBC = (Vector2Dist(radar.b, radar.c) / UNIT_SIZE);

	UI_GetRadarWidth(node, gridSize);

	/* get the dimensions for one grid field on the radar map */
	radar.gridWidth = radar.w / distAB;
	radar.gridHeight = radar.h / distBC;

	/* shift the x and y values according to their grid width/height and
	 * their gridX and gridY position */
	{
		const float radarLength = std::max(1.0f, fabsf(gridSize[0]));
		const float radarHeight = std::max(1.0f, fabsf(gridSize[1]));
		/* image grid relations */
		const float gridFactorX = radar.w / radarLength;
		const float gridFactorY = radar.h / radarHeight;
		for (j = 0; j < radar.numImages; j++) {
			hudRadarImage_t* image = &radar.images[j];

			image->x = (image->gridX - radar.gridMin[0]) * gridFactorX;
			image->y = radar.h - (image->gridY - radar.gridMin[1]) * gridFactorY - image->height;
		}
	}

	/* now align the screen coordinates like it's given by the node */
	radar.x -= (radar.w / 2);
	radar.y -= (radar.h / 2);
}
Exemple #30
0
/**
 * @brief Draws the image node
 * @param[in] node The UI node to draw
 */
void uiImageNode::draw (uiNode_t* node)
{
	vec2_t size;
	vec2_t nodepos;
	const image_t* image;
	vec2_t imagepos;
	vec2_t nodesize;

	const char* imageName = UI_GetReferenceString(node, node->image);
	if (Q_strnull(imageName))
		return;

	image = UI_LoadImage(imageName);
	if (!image)
		return;

	/* mouse darken effect */
	/** @todo convert all pic using mousefx into button.
	 * @todo delete mousefx
	 */
#if 0
	if (node->mousefx && node->state) {
		vec4_t color;
		VectorScale(node->color, 0.8, color);
		color[3] = node->color[3];
		R_Color(color);
	}
#endif

	UI_GetNodeAbsPos(node, nodepos);
	Vector2Copy(node->box.size, nodesize);
	nodesize[0] -= node->padding + node->padding;
	if (nodesize[0] < 0)
		nodesize[0] = 0;
	nodesize[1] -= node->padding + node->padding;
	if (nodesize[1] < 0)
		nodesize[1] = 0;

	/** @todo code is duplicated in the ekg node code */
	if (node->box.size[0] && !node->box.size[1]) {
		const float scale = image->width / node->box.size[0];
		Vector2Set(size, node->box.size[0], image->height / scale);
	} else if (node->box.size[1] && !node->box.size[0]) {
		const float scale = image->height / node->box.size[1];
		Vector2Set(size, image->width / scale, node->box.size[1]);
	} else {
		Vector2Copy(nodesize, size);

		if (EXTRADATA(node).preventRatio) {
			/* maximize the image into the bounding box */
			const float ratio = (float) image->width / (float) image->height;
			if (size[1] * ratio > size[0]) {
				Vector2Set(size, size[0], size[0] / ratio);
			} else {
				Vector2Set(size, size[1] * ratio, size[1]);
			}
		}
	}

	UI_ImageAlignBoxInBox(nodepos, nodesize, size, (align_t) node->contentAlign, imagepos);
	UI_DrawNormImage(false, imagepos[0] + node->padding, imagepos[1] + node->padding, size[0], size[1],
			EXTRADATA(node).texh[0], EXTRADATA(node).texh[1],
			EXTRADATA(node).texl[0], EXTRADATA(node).texl[1], image);

	/** @todo convert all pic using mousefx into button.
	 * @todo delete mousefx
	 */
#if 0
	if (node->mousefx && node->state) {
		R_Color(nullptr);
	}
#endif
}