Esempio n. 1
0
void R_DrawStretchImage (float x, float y, int w, int h, const image_t *image)
{
	if (!image)
		return;

	R_DrawTexture(image->texnum, x * viddef.rx, y * viddef.ry, w * viddef.rx, h * viddef.ry);
}
Esempio n. 2
0
/**
 * @brief Draws an image or parts of it
 * @param x X position to draw the image to
 * @param y Y position to draw the image to
 * @param[in] image Pointer to the imlage to display
 */
void R_DrawImage (float x, float y, const image_t *image)
{
	if (!image)
		return;

	R_DrawTexture(image->texnum, x * viddef.rx, y * viddef.ry, image->width * viddef.rx, image->height * viddef.ry);
}
Esempio n. 3
0
/**
 * @brief responsible for drawing the 3d globe on geoscape
 * param[in] rotate the rotate angle of the globe
 * param[in] zoom the current globe zoon
 * param[in] map the prefix of the map to use (image must be at base/pics/menu/\<map\>_[day|night])
 * @sa R_DrawFlatGeoscape
 * @sa R_SphereGenerate
 */
void R_Draw3DGlobe (const vec2_t pos, const vec2_t size, int day, int second, const vec3_t rotate, float zoom, const char *map,
					bool disableSolarRender, float ambient, bool overlayNation, bool overlayXVI, bool overlayRadar, image_t *r_xviTexture,
					image_t *r_radarTexture, bool renderNationGlow)
{
	/* globe scaling */
	const float fullscale = zoom / STANDARD_3D_ZOOM;

	/* lighting colors */
	static const vec4_t diffuseLightColor = { 1.75f, 1.75f, 1.75f, 1.0f };
	static const vec4_t specularLightColor = { 2.0f, 1.9f, 1.7f, 1.0f };
	static const vec4_t darknessLightColor = { 0.0f, 0.0f, 0.0f, 1.0f };
	static const vec4_t brightDiffuseLightColor = { 5.0f, 5.0f, 5.0f, 1.0f };
	const vec4_t ambientLightColor = { ambient + 0.2f, ambient + 0.2f, ambient + 0.2f, ambient + 0.2f };
	/* billboard textures */
	image_t *starfield;
	image_t *halo;
	image_t *sun;
	image_t *sunOverlay;

	/* set distance of the sun and moon to make them static on starfield when
	 * time is stoped.  this distance should be used for any celestial body
	 * considered at infinite location (sun, moon) */
	static const float celestialDist = 1.37f * SKYBOX_HALFSIZE;
	static const float moonSize = 0.025f;
	vec4_t sunPos;
	vec4_t antiSunPos;
	vec4_t moonLoc;
	vec4_t sunLoc;

	/* normalize */
	const float nx = pos[0] * viddef.rx;
	const float ny = pos[1] * viddef.ry;
	const float nw = size[0] * viddef.rx;
	const float nh = size[1] * viddef.ry;

	/* Earth center is in the middle of node.
	 * Due to Orthographic view, this is also camera position */
	const vec3_t earthPos = { nx + nw / 2.0f, ny + nh / 2.0f, 0.0f };

	/* estimate the progress through the current season so we can do
	 * smooth transitions between textures.  Currently there are 12
	 * "seasons", because we have one image per Earth-month. */
	const float season = (float) (day % DAYS_PER_YEAR) / ((float) (DAYS_PER_YEAR) / (float) (SEASONS_PER_YEAR));
	const int currSeason = (int) floorf(season) % SEASONS_PER_YEAR;
	const int nextSeason = (int) ceilf(season) % SEASONS_PER_YEAR;
	const float seasonProgress = season - (float) currSeason;

	/* Compute sun position in absolute frame */
	const float q = (day % DAYS_PER_YEAR * SECONDS_PER_DAY + second) * (2.0f * M_PI / (SECONDS_PER_DAY * DAYS_PER_YEAR));	/* sun rotation (year) */
	const float a = cos(q) * SIN_ALPHA;	/* due to earth obliquity */
	const float sqrta = sqrt(0.5f * (1 - a * a));

	/* earth rotation (day) */
	const float p = (second - SECONDS_PER_DAY / 4) * (2.0f * M_PI / SECONDS_PER_DAY);
	/* lunar orbit */
	const float m = p + (((double)((10 * day % 249) / 10.0f) + ((double)second / (double)SECONDS_PER_DAY)) / 24.9f) * (2.0f * M_PI);

	glPushMatrix();
	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glDisable(GL_LIGHTING);
	/* draw the starfield, rotating with the planet */
	starfield = R_FindImage(va("pics/geoscape/%s_stars", map), it_wrappic);
	if (starfield != r_noTexture)
		R_DrawStarfield(starfield->texnum, earthPos, rotate, p);

	glPopMatrix();

	/* set up position vectors for celestial bodies */
	Vector4Set(sunPos, cos(p) * sqrta, -sin(p) * sqrta, a, 0);
	Vector4Set(antiSunPos, -cos(p) * sqrta, sin(p) * sqrta, -a, 0);

	/* Rotate the sun in the relative frame of player view, to get sun location */
	R_RotateCelestialBody(sunPos, sunLoc, rotate, earthPos, 1.0f);
	/* load sun texture image */
	sun = R_FindImage(va("pics/geoscape/%s_sun", map), it_wrappic);
	sunOverlay = R_FindImage(va("pics/geoscape/%s_sun_overlay", map), it_pic);
	if (sun != r_noTexture && sunOverlay != r_noTexture && sunLoc[2] > 0 && !disableSolarRender) {
		const int sunx = earthPos[0] + viddef.rx * (-128.0f + celestialDist * (sunLoc[0] - earthPos[0]));
		const int suny = earthPos[1] + viddef.ry * (-128.0f + celestialDist * (sunLoc[1] - earthPos[1]));

		R_DrawTexture(sunOverlay->texnum, sunx, suny, 256.0f * viddef.rx, 256.0f * viddef.ry);
		R_DrawBuffers(2);
		R_DrawTexture(sun->texnum, sunx, suny, 256.0 * viddef.rx, 256.0 * viddef.ry);
		R_DrawBuffers(1);
	}

	/* calculate position of the moon (it rotates around earth with a period of
	 * about 24.9 h, and we must take day into account to avoid moon to "jump"
	 * every time the day is changing) */
	VectorSet(moonLoc, cos(m) * sqrta, -sin(m) * sqrta, a);
	R_RotateCelestialBody(moonLoc, moonLoc, rotate, earthPos, celestialDist);

	/* free last month's texture image */
	if (r_globeEarth.season != currSeason) {
		r_globeEarth.season = currSeason;
		R_FreeImage(r_globeEarth.texture);
	}

	/* load diffuse texture map (with embedded night-glow map as alpha channel) */
	r_globeEarth.texture = R_FindImage(va("pics/geoscape/%s/%s_season_%02d", r_config.lodDir, map, currSeason), it_wrappic);
	if (r_globeEarth.texture == r_noTexture)
		Com_Error(ERR_FATAL, "Could not find pics/geoscape/%s/%s_season_%02d\n", r_config.lodDir, map, currSeason);

	/* set up for advanced GLSL rendering if we have the capability */
	if (r_programs->integer) {
		r_globeEarth.glslProgram = r_state.geoscape_program;
		/* load earth image for the next month so we can blend them */
		r_globeEarth.blendTexture = R_FindImage(va("pics/geoscape/%s/%s_season_%02d", r_config.lodDir, map, nextSeason), it_wrappic);
		if (r_globeEarth.blendTexture == r_noTexture)
			Com_Error(ERR_FATAL, "Could not find pics/geoscape/%s/%s_season_%02d\n", r_config.lodDir, map, nextSeason);

		/* load normal map (with embedded gloss map as alpha channel) */
		r_globeEarth.normalMap = R_FindImage(va("pics/geoscape/%s/%s_bump", r_config.lodDir, map), it_wrappic);
		if (r_globeEarth.normalMap == r_noTexture)
			r_globeEarth.normalMap = nullptr;

		/* weight the blending based on how much of the month has elapsed */
		r_globeEarth.blendScale = seasonProgress;
		/* set up lights for nighttime city glow */
		VectorCopy(antiSunPos, r_globeEarth.nightLightPos);
		glLightfv(GL_LIGHT1, GL_AMBIENT, darknessLightColor);
		glLightfv(GL_LIGHT1, GL_DIFFUSE, brightDiffuseLightColor);
		glLightfv(GL_LIGHT1, GL_SPECULAR, darknessLightColor);

		r_globeEarth.glowScale = 0.7f;
	}

	/* load moon texture image */
	r_globeMoon.texture = R_FindImage(va("pics/geoscape/%s_moon", map), it_wrappic);

	/* globe texture scaling */
	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glScalef(2.0f, 1.0f, 1.0f);
	glMatrixMode(GL_MODELVIEW);

	/* enable the lighting */
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLightColor);
	glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLightColor);
	glLightfv(GL_LIGHT0, GL_SPECULAR, specularLightColor);

	/* draw the moon */
	if (r_globeMoon.texture != r_noTexture && moonLoc[2] > 0 && !disableSolarRender)
		R_SphereRender(&r_globeMoon, moonLoc, rotate, moonSize, sunPos);

	/* activate depth to hide 3D models behind earth */
	glEnable(GL_DEPTH_TEST);

	/* draw the earth */
	R_DrawBuffers(2);
#if 0 /* old rendering code which doesn't render city lights in FFP */
	if (r_programs->integer == 0) /* ignore alpha channel, since the city-light map is stored there */
		glBlendFunc(GL_ONE, GL_ZERO);

	R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);

	if (r_programs->integer == 0) /* restore default blend function */
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#else /* new which does render city lights in FFP */
	if (r_programs->integer == 0) {
		/* set up rendering of city lights map, which is stored in alpha channel; OpenGL 1.3 required */
		R_SelectTexture(&texunit_diffuse); /* select texture to edit texture environment for */
		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); /* enable color combiner */
		/* setup texture combiner to blend between daylight diffuse map stored in the RGB channels of the diffuse texture
		 * and the monochomatic emission map (which simulates city lights) stored in the alpha channel;
		 * incoming color value is the blend factor.
		 */
		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); /* set day color as blending target*/
		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); /* set night color as blending source */
		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS); /* set incoming color as blending factor */
		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); /* set blending mode to interpolation from src1 to src0 */
		/* copy alpha from incoming color, bypassing the value read from texture, which is not a "real" alpha anyway */
		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
	}

	R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);

	if (r_programs->integer == 0) { /* disable combiner */
		R_SelectTexture(&texunit_diffuse);
		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	}
#endif

	r_globeEarthAtmosphere.texture = R_FindImage(va("pics/geoscape/%s_atmosphere", map), it_wrappic);

	/* Draw earth atmosphere */
	/** @todo render atmosphere glow even when postprocessing is disabled */
	if (r_programs->integer && r_postprocess->integer) {
		r_globeEarthAtmosphere.normalMap = r_globeEarth.normalMap;
		r_globeEarthAtmosphere.glowScale = 1.0;
		r_globeEarthAtmosphere.blendScale = -1.0;
		r_globeEarthAtmosphere.glslProgram = r_state.atmosphere_program;
		R_SphereRender(&r_globeEarthAtmosphere, earthPos, rotate, fullscale, sunPos);
	} else {
		halo = R_FindImage("pics/geoscape/map_earth_halo", it_pic);
		if (halo != r_noTexture) {
			/** @todo Replace this magic number with some speaking constant */
			const float earthSizeX = fullscale * 20500.0f * viddef.rx;
			const float earthSizeY = fullscale * 20500.0f * viddef.ry;
			glMatrixMode(GL_TEXTURE);
			glPushMatrix();
			glLoadIdentity();
			glDisable(GL_LIGHTING);

			R_DrawTexture(halo->texnum, earthPos[0] - earthSizeX * 0.5f, earthPos[1] - earthSizeY * 0.5f, earthSizeX, earthSizeY);
			glEnable(GL_LIGHTING);
			glPopMatrix();
			glMatrixMode(GL_MODELVIEW);
		}
	}

	R_DrawBuffers(1);
	glDisable(GL_DEPTH_TEST);

	/* draw nation overlay */
	if (overlayNation) {
		r_globeEarth.overlay = R_FindImage(va("pics/geoscape/%s_nations_overlay", map), it_wrappic);
		if (r_globeEarth.overlay == r_noTexture)
			Com_Error(ERR_FATAL, "Could not load geoscape nation overlay image");

		R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);

		if (renderNationGlow) {
			/* draw glowing borders */
			r_globeEarth.overlay = R_FindImage(va("pics/geoscape/%s_nations_overlay_glow", map), it_wrappic);
			if (r_globeEarth.overlay == r_noTexture)
				Com_Error(ERR_FATAL, "Could not load geoscape nation overlay glow image");

			R_DrawBuffers(2);
			glDisable(GL_LIGHTING);
			R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);
			glEnable(GL_LIGHTING);
			R_DrawBuffers(1);
		}

		r_globeEarth.overlay = nullptr;
	}
	/* draw XVI overlay */
	if (overlayXVI) {
		r_globeEarth.overlay = R_FindImage(va("pics/geoscape/%s_xvi_overlay", map), it_wrappic);
		r_globeEarth.overlayAlphaMask = r_xviTexture;
		assert(r_globeEarth.overlayAlphaMask);
		R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);
		r_globeEarth.overlayAlphaMask = nullptr;
		r_globeEarth.overlay = nullptr;
	}
	/* draw radar overlay */
	if (overlayRadar) {
		r_globeEarth.overlay = r_radarTexture;
		assert(r_globeEarth.overlay);
		R_SphereRender(&r_globeEarth, earthPos, rotate, fullscale, sunPos);
		r_globeEarth.overlay = nullptr;
	}

	/* disable 3d geoscape lighting */
	glDisable(GL_LIGHTING);

	/* restore the previous matrix */
	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
}