void opengl_draw_textured_quad(GLfloat x1,
							   GLfloat y1,
							   GLfloat u1,
							   GLfloat v1,
							   GLfloat x2,
							   GLfloat y2,
							   GLfloat u2,
							   GLfloat v2) {
	GR_DEBUG_SCOPE("Draw textured quad");

	GLfloat glVertices[4][4] = {
		{ x1, y1, u1, v1 },
		{ x1, y2, u1, v2 },
		{ x2, y1, u2, v1 },
		{ x2, y2, u2, v2 }
	};

	vertex_layout vert_def;

	vert_def.add_vertex_component(vertex_format_data::POSITION2, sizeof(GLfloat) * 4, 0);
	vert_def.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(GLfloat) * 4, sizeof(GLfloat) * 2);

	opengl_render_primitives_immediate(PRIM_TYPE_TRISTRIP, &vert_def, 4, glVertices, sizeof(GLfloat) * 4 * 4);
}
void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_shader_t &new_shader)
{
	opengl_shader_type_t *sdr_info = &GL_shader_types[sdr];

	Assert(sdr_info->type_id == sdr);
	mprintf(("Compiling new shader:\n"));
	mprintf(("	%s\n", sdr_info->description));

	// figure out if the variant requested needs a geometry shader
	bool use_geo_sdr = false;

	// do we even have a geometry shader?
	if (sdr_info->geo != NULL) {
		for (int i = 0; i < GL_num_shader_variants; ++i) {
			opengl_shader_variant_t *variant = &GL_shader_variants[i];

			if (variant->type_id == sdr && flags & variant->flag && variant->use_geometry_sdr) {
				use_geo_sdr = true;
				break;
			}
		}
	}

	auto vert_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->vert, flags, use_geo_sdr);
	auto frag_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->frag, flags, use_geo_sdr);
	SCP_vector<SCP_string> geom_content;

	if (use_geo_sdr) {
		// read geometry shader
		geom_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->geo, flags, use_geo_sdr);
	}

	auto shader_hash = get_shader_hash(vert_content, geom_content, frag_content);
	std::unique_ptr<opengl::ShaderProgram> program(new opengl::ShaderProgram(sdr_info->description));

	if (!load_cached_shader_binary(program.get(), shader_hash)) {
		GR_DEBUG_SCOPE("Compiling shader code");
		try {
			program->addShaderCode(opengl::STAGE_VERTEX, sdr_info->vert, vert_content);
			program->addShaderCode(opengl::STAGE_FRAGMENT, sdr_info->frag, frag_content);
			if (use_geo_sdr) {
				program->addShaderCode(opengl::STAGE_GEOMETRY, sdr_info->geo, geom_content);
			}

			for (size_t i = 0; i < GL_vertex_attrib_info.size(); ++i) {
				// Check that the enum values match the position in the vector to make accessing that information more efficient
				Assertion(GL_vertex_attrib_info[i].attribute_id == (int)i, "Mistmatch between enum values and attribute vector detected!");

				// assign vert attribute binding locations before we link the shader
				glBindAttribLocation(program->getShaderHandle(), (GLint)i, GL_vertex_attrib_info[i].name.c_str());
			}

			// bind fragment data locations before we link the shader
			glBindFragDataLocation(program->getShaderHandle(), 0, "fragOut0");
			glBindFragDataLocation(program->getShaderHandle(), 1, "fragOut1");
			glBindFragDataLocation(program->getShaderHandle(), 2, "fragOut2");
			glBindFragDataLocation(program->getShaderHandle(), 3, "fragOut3");
			glBindFragDataLocation(program->getShaderHandle(), 4, "fragOut4");

			if (do_shader_caching()) {
				// Enable shader caching
				glProgramParameteri(program->getShaderHandle(), GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
			}

			program->linkProgram();
		}
		catch (const std::exception&) {
			// Since all shaders are required a compilation failure is a fatal error
			Error(LOCATION, "A shader failed to compile! Check the debug log for more information.");
		}

		cache_program_binary(program->getShaderHandle(), shader_hash);
	}

	new_shader.shader = sdr_info->type_id;
	new_shader.flags = flags;
	new_shader.program = std::move(program);

	opengl_shader_set_current(&new_shader);

	// initialize the attributes
	for (auto& attr : sdr_info->attributes) {
		new_shader.program->initAttribute(GL_vertex_attrib_info[attr].name, GL_vertex_attrib_info[attr].attribute_id, GL_vertex_attrib_info[attr].default_value);
	}

	for (auto& uniform_block : GL_uniform_blocks) {
		auto blockIndex = glGetUniformBlockIndex(new_shader.program->getShaderHandle(), uniform_block.name);

		if (blockIndex != GL_INVALID_INDEX) {
			glUniformBlockBinding(new_shader.program->getShaderHandle(), blockIndex, static_cast<GLuint>(uniform_block.block_type));
		}
	}

	mprintf(("Shader Variant Features:\n"));

	// initialize all uniforms and attributes that are specific to this variant
	for (int i = 0; i < GL_num_shader_variants; ++i) {
		opengl_shader_variant_t &variant = GL_shader_variants[i];

		if (sdr_info->type_id == variant.type_id && variant.flag & flags) {
			for (auto& attr : variant.attributes) {
				auto& attr_info = GL_vertex_attrib_info[attr];
				new_shader.program->initAttribute(attr_info.name, attr_info.attribute_id, attr_info.default_value);
			}

			mprintf(("	%s\n", variant.description));
		}
	}

	opengl_set_default_uniforms(new_shader);
}
static bool load_cached_shader_binary(opengl::ShaderProgram* program, const SCP_string& hash) {
	if (!do_shader_caching()) {
		return false;
	}

	auto base_filename = SCP_string("ogl_shader-") + hash;

	auto metadata = base_filename + ".json";
	auto binary = base_filename + ".bin";

	auto metadata_fp = cfopen(metadata.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE, false,
	                          CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
	if (!metadata_fp) {
		nprintf(("ShaderCache", "Metadata file does not exist.\n"));
		return false;
	}

	auto size = cfilelength(metadata_fp);
	SCP_string metadata_content;
	metadata_content.resize((size_t) size);
	cfread(&metadata_content[0], 1, size, metadata_fp);

	cfclose(metadata_fp);

	auto metadata_root = json_loads(metadata_content.c_str(), 0, nullptr);
	if (!metadata_root) {
		mprintf(("Loading of cache metadata failed! Falling back to GLSL shader...\n"));
		return false;
	}

	json_int_t format;
	if (json_unpack(metadata_root, "{sI}", "format", &format) != 0) {
		mprintf(("Failed to unpack values from metadata JSON! Falling back to GLSL shader...\n"));
		return false;
	}
	auto binary_format = (GLenum) format;
	json_decref(metadata_root);

	bool supported = false;
	for (auto supported_fmt : GL_binary_formats) {
		if ((GLenum)supported_fmt == binary_format) {
			supported = true;
			break;
		}
	}

	if (!supported) {
		// This can happen in case an implementation stops supporting a particular binary format
		nprintf(("ShaderCache", "Unsupported binary format %d encountered in shader cache.\n", binary_format));
		return false;
	}

	auto binary_fp = cfopen(binary.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE, false,
	                        CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
	if (!binary_fp) {
		nprintf(("ShaderCache", "Binary file does not exist.\n"));
		return false;
	}
	
	GR_DEBUG_SCOPE("Loading cached shader");
	
	SCP_vector<uint8_t> buffer;
	int length = cfilelength(binary_fp);
	buffer.resize((size_t) length);
	cfread(&buffer[0], 1, length, binary_fp);

	cfclose(binary_fp);

	// Load the data!
	glProgramBinary(program->getShaderHandle(), binary_format, buffer.data(), (GLsizei) buffer.size());

	// Check the status...
	GLint status;
	glGetProgramiv(program->getShaderHandle(), GL_LINK_STATUS, &status);

	return status == GL_TRUE;
}
Exemplo n.º 4
0
void credits_do_frame(float frametime)
{
	GR_DEBUG_SCOPE("Credits do frame");

	int i, k, next, percent, bm1, bm2;
	int bx1, by1, bw1, bh1;
	int bx2, by2, bw2, bh2;

	// Use this id to trigger the start of music playing on the credits screen
	if ( timestamp_elapsed(Credits_music_begin_timestamp) ) {
		Credits_music_begin_timestamp = 0;
		credits_start_music();
	}

	k = Ui_window.process();
	switch (k) {
	case KEY_ESC:
		gameseq_post_event(GS_EVENT_MAIN_MENU);
		key_flush();
		break;

	case KEY_CTRLED | KEY_UP:
	case KEY_SHIFTED | KEY_TAB:
		if ( !(Player->flags & PLAYER_FLAGS_IS_MULTI) ) {
			credits_screen_button_pressed(CUTSCENES_BUTTON);
			break;
		}
		// else, react like tab key.

	case KEY_CTRLED | KEY_DOWN:
	case KEY_TAB:
		credits_screen_button_pressed(TECH_DATABASE_BUTTON);
		break;

	default:
		break;
	} // end switch

	for (i=0; i<NUM_BUTTONS; i++){
		if (Buttons[i][gr_screen.res].button.pressed()){
			if (credits_screen_button_pressed(i)){
				return;
			}
		}
	}

	gr_reset_clip();	
	GR_MAYBE_CLEAR_RES(Background_bitmap);
	if (Background_bitmap >= 0) {
		gr_set_bitmap(Background_bitmap);
		gr_bitmap(0, 0, GR_RESIZE_MENU);
	} 

	percent = (int) (100.0f - (Credits_artwork_display_time - Credits_counter) * 100.0f / Credits_artwork_fade_time);
	if (percent < 0){
		percent = 0;
	}

	next = Credits_artwork_index + 1;
	if (next >= Credits_num_images){
		next = 0;
	}

	if (Credits_bmps[Credits_artwork_index] < 0) {
		char buf[40];

		if (gr_screen.res == GR_1024) {
			sprintf(buf, NOX("2_CrIm%.2d"), Credits_artwork_index);
		} else {
			sprintf(buf, NOX("CrIm%.2d"), Credits_artwork_index);
		}
		Credits_bmps[Credits_artwork_index] = bm_load(buf);
	}

	if (Credits_bmps[next] < 0) {
		char buf[40];

		if (gr_screen.res == GR_1024) {
			sprintf(buf, NOX("2_CrIm%.2d"), next);
		} else {
			sprintf(buf, NOX("CrIm%.2d"), next);
		}
		Credits_bmps[next] = bm_load(buf);
	}

	bm1 = Credits_bmps[Credits_artwork_index];
	bm2 = Credits_bmps[next];

	if((bm1 != -1) && (bm2 != -1)){
		GR_DEBUG_SCOPE("Render credits bitmap");

		Assert(percent >= 0 && percent <= 100);

		// get width and height
		bm_get_info(bm1, &bw1, &bh1, NULL, NULL, NULL);	
		bm_get_info(bm2, &bw2, &bh2, NULL, NULL, NULL);	
	
		// determine where to draw the coords
		bx1 = Credits_image_coords[gr_screen.res][CREDITS_X_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_W_COORD] - bw1)/2);
		by1 = Credits_image_coords[gr_screen.res][CREDITS_Y_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_H_COORD] - bh1)/2);
		bx2 = Credits_image_coords[gr_screen.res][CREDITS_X_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_W_COORD] - bw2)/2);
		by2 = Credits_image_coords[gr_screen.res][CREDITS_Y_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_H_COORD] - bh2)/2);

		auto alpha = (float)percent / 100.0f;

		gr_set_bitmap(bm1, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.0f - alpha);
		gr_bitmap(bx1, by1, GR_RESIZE_MENU);

		gr_set_bitmap(bm2, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha);
		gr_bitmap(bx2, by2, GR_RESIZE_MENU);
	}

	Ui_window.draw();

	for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){
		if (Buttons[i][gr_screen.res].button.button_down()){
			break;
		}
	}

	if (i > CREDITS_BUTTON){
		Buttons[CREDITS_BUTTON][gr_screen.res].button.draw_forced(2);
	}

	gr_set_clip(Credits_text_coords[gr_screen.res][CREDITS_X_COORD], Credits_text_coords[gr_screen.res][CREDITS_Y_COORD], Credits_text_coords[gr_screen.res][CREDITS_W_COORD], Credits_text_coords[gr_screen.res][CREDITS_H_COORD], GR_RESIZE_MENU);
	font::set_font(font::FONT1);
	gr_set_color_fast(&Color_normal);
	
	int y_offset = 0;
	for (SCP_vector<SCP_string>::iterator iter = Credit_text_parts.begin(); iter != Credit_text_parts.end(); ++iter)
	{
		size_t currentPos = 0;
		size_t lineEnd;
		do
		{
			int height;
			int width;
			lineEnd = iter->find('\n', currentPos);

			auto length = lineEnd - currentPos;
			if (lineEnd == SCP_string::npos)
			{
				length = std::numeric_limits<size_t>::max();
			}

			gr_get_string_size(&width, &height, iter->c_str() + currentPos, static_cast<int>(length));
			// Check if the text part is actually visible
			if (Credit_position + y_offset + height > 0.0f)
			{
				float x = static_cast<float>((gr_screen.clip_width_unscaled - width) / 2);
				gr_string(x, Credit_position + y_offset, iter->c_str() + currentPos, GR_RESIZE_MENU, static_cast<int>(length));
			}

			y_offset += height;
			currentPos = lineEnd + 1;
		} while (lineEnd < iter->length() && lineEnd != SCP_string::npos);
	}

	int temp_time;
	temp_time = timer_get_milliseconds();

	Credits_frametime = temp_time - Credits_last_time;
	Credits_last_time = temp_time;
	timestamp_inc(i2f(Credits_frametime) / TIMESTAMP_FREQUENCY);

	float fl_frametime = i2fl(Credits_frametime) / 1000.f;
	if (keyd_pressed[KEY_LSHIFT]) {
		Credit_position -= fl_frametime * Credits_scroll_rate * 4.0f;
	} else {
		Credit_position -= fl_frametime * Credits_scroll_rate;
	}

	if (Credit_position < Credit_stop_pos){
		Credit_position = Credit_start_pos;
	}

	Credits_counter += fl_frametime;
	while (Credits_counter >= Credits_artwork_display_time) {
		Credits_counter -= Credits_artwork_display_time;
		Credits_artwork_index = next;
	}

	gr_flip();
}
static bool load_cached_shader_binary(opengl::ShaderProgram* program, SCP_string hash) {
	if (!do_shader_caching()) {
		return false;
	}

	auto base_filename = SCP_string("ogl_shader-") + hash;

	auto metadata = base_filename + ".json";
	auto binary = base_filename + ".bin";

	auto metadata_fp = cfopen(metadata.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE);
	if (!metadata_fp) {
		nprintf(("ShaderCache", "Metadata file does not exist.\n"));
		return false;
	}

	auto size = cfilelength(metadata_fp);
	SCP_string metadata_content;
	metadata_content.resize((size_t) size);
	cfread(&metadata_content[0], 1, size, metadata_fp);

	cfclose(metadata_fp);

	auto metadata_root = json_loads(metadata_content.c_str(), 0, nullptr);
	if (!metadata_root) {
		mprintf(("Loading of cache metadata failed! Falling back to GLSL shader...\n"));
		return false;
	}

	json_int_t format;
	if (json_unpack(metadata_root, "{sI}", "format", &format) != 0) {
		mprintf(("Failed to unpack values from metadata JSON! Falling back to GLSL shader...\n"));
		return false;
	}
	auto binary_format = (GLenum) format;
	json_decref(metadata_root);

	auto binary_fp = cfopen(binary.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE);
	if (!binary_fp) {
		nprintf(("ShaderCache", "Binary file does not exist.\n"));
		return false;
	}
	
	GR_DEBUG_SCOPE("Loading cached shader");
	
	SCP_vector<uint8_t> buffer;
	int length = cfilelength(binary_fp);
	buffer.resize((size_t) length);
	cfread(&buffer[0], 1, length, binary_fp);

	cfclose(binary_fp);

	// Load the data!
	glProgramBinary(program->getShaderHandle(), binary_format, buffer.data(), (GLsizei) buffer.size());

	// Check the status...
	GLint status;
	glGetProgramiv(program->getShaderHandle(), GL_LINK_STATUS, &status);

	return status == GL_TRUE;
}
void gr_opengl_update_distortion()
{
	if (Distortion_framebuffer == 0) {
		// distortion is disabled
		return;
	}

	GR_DEBUG_SCOPE("Update distortion");
	TRACE_SCOPE(tracing::UpdateDistortion);

	GLboolean depth = GL_state.DepthTest(GL_FALSE);
	GLboolean depth_mask = GL_state.DepthMask(GL_FALSE);
	GLboolean blend = GL_state.Blend(GL_FALSE);
	GLboolean cull = GL_state.CullFace(GL_FALSE);

	opengl_shader_set_passthrough(true);

	GL_state.PushFramebufferState();
	GL_state.BindFrameBuffer(Distortion_framebuffer);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Distortion_texture[!Distortion_switch], 0);
	glDrawBuffer(GL_COLOR_ATTACHMENT0);

	glViewport(0,0,32,32);
	GL_state.Texture.Enable(0, GL_TEXTURE_2D, Distortion_texture[Distortion_switch]);
	glClearColor(0.5f, 0.5f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);

	vertex vertices[4];

	vertices[0].texture_position.u = 0.0f;
	vertices[0].texture_position.v = 0.0f;

	vertices[1].texture_position.u = 0.96875f;
	vertices[1].texture_position.v = 0.0f;

	vertices[2].texture_position.u = 0.0f;
	vertices[2].texture_position.v = 1.0f;

	vertices[3].texture_position.u = 0.96875f;
	vertices[3].texture_position.v = 1.0f;
	
	vertices[0].screen.xyw.x = 0.03f*(float)gr_screen.max_w;
	vertices[0].screen.xyw.y = (float)gr_screen.max_h;

	vertices[1].screen.xyw.x = (float)gr_screen.max_w;
	vertices[1].screen.xyw.y = (float)gr_screen.max_h;

	vertices[2].screen.xyw.x = 0.03f*(float)gr_screen.max_w;
	vertices[2].screen.xyw.y = 0.0f;

	vertices[3].screen.xyw.x = (float)gr_screen.max_w;
	vertices[3].screen.xyw.y = 0.0f;

	vertex_layout vert_def;

	vert_def.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex), offsetof(vertex, screen));
	vert_def.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex), offsetof(vertex, texture_position));

	opengl_render_primitives_immediate(PRIM_TYPE_TRISTRIP, &vert_def, 4, vertices, sizeof(vertex) * 4);

	opengl_shader_set_passthrough(false);

	vertex distortion_verts[33];

	for(int i = 0; i < 33; i++)
	{
		distortion_verts[i].r = (ubyte)rand() % 256;
		distortion_verts[i].g = (ubyte)rand() % 256;
		distortion_verts[i].b = 255;
		distortion_verts[i].a = 255;

		distortion_verts[i].screen.xyw.x = 1.f;
		distortion_verts[i].screen.xyw.y = (float)gr_screen.max_h*0.03125f*i;
	}

	vert_def = vertex_layout();

	vert_def.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex), offsetof(vertex, screen));
	vert_def.add_vertex_component(vertex_format_data::COLOR4, sizeof(vertex), offsetof(vertex, r));

	opengl_render_primitives_immediate(PRIM_TYPE_POINTS, &vert_def, 33, distortion_verts, 33 * sizeof(vertex));

	Distortion_switch = !Distortion_switch;

	// reset state
	GL_state.PopFramebufferState();

	glViewport(0,0,gr_screen.max_w,gr_screen.max_h);

	GL_state.DepthTest(depth);
	GL_state.DepthMask(depth_mask);
	GL_state.Blend(blend);
	GL_state.CullFace(cull);
}
void gr_opengl_scene_texture_end()
{

	if ( !Scene_framebuffer_in_frame ) {
		return;
	}

	GR_DEBUG_SCOPE("End scene texture");
	TRACE_SCOPE(tracing::SceneTextureEnd);

	time_buffer+=flFrametime;
	if(time_buffer>0.03f)
	{
		gr_opengl_update_distortion();
		time_buffer = 0.0f;
	}

	if ( Gr_post_processing_enabled && !PostProcessing_override ) {
		gr_post_process_end();
	} else {
		GR_DEBUG_SCOPE("Draw scene texture");
		TRACE_SCOPE(tracing::DrawSceneTexture);

		GLboolean depth = GL_state.DepthTest(GL_FALSE);
		GLboolean depth_mask = GL_state.DepthMask(GL_FALSE);
		GLboolean blend = GL_state.Blend(GL_FALSE);
		GLboolean cull = GL_state.CullFace(GL_FALSE);

		GL_state.PopFramebufferState();

		GL_state.Texture.Enable(0, GL_TEXTURE_2D, Scene_color_texture);

		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		opengl_shader_set_passthrough(true);

		GL_state.Array.BindArrayBuffer(0);

		if (GL_rendering_to_texture)
		{
			opengl_draw_textured_quad(0.0f, 0.0f, 0.0f, 0.0f, (float)gr_screen.max_w, (float)gr_screen.max_h, Scene_texture_u_scale, Scene_texture_v_scale);
		}
		else
		{
			opengl_draw_textured_quad(0.0f, 0.0f, 0.0f, Scene_texture_v_scale, (float)gr_screen.max_w, (float)gr_screen.max_h, Scene_texture_u_scale, 0.0f);
		}

		// reset state
		GL_state.DepthTest(depth);
		GL_state.DepthMask(depth_mask);
		GL_state.Blend(blend);
		GL_state.CullFace(cull);
	}

	// Reset the UV scale values

	Scene_texture_u_scale = 1.0f;
	Scene_texture_v_scale = 1.0f;

	Scene_framebuffer_in_frame = false;
	High_dynamic_range = false;
}
Exemplo n.º 8
0
void HudGaugeShield::showShields(object *objp, int mode)
{
//	static int fod_model = -1;
	float			max_shield;
	int			hud_color_index, range;
	int			sx, sy, i;
	ship			*sp;
	ship_info	*sip;
	hud_frames	*sgp=NULL;

	if ( objp->type != OBJ_SHIP )
		return;

	// Goober5000 - don't show if primitive sensors
	if ( Ships[Player_obj->instance].flags[Ship::Ship_Flags::Primitive_sensors] )
		return;

	sp = &Ships[objp->instance];
	sip = &Ship_info[sp->ship_info_index];

//	bool digitus_improbus = (fod_model != -2 && strstr(sp->ship_name, "Sathanas") != NULL);
	if ( sip->shield_icon_index == 255 && !(sip->flags[Ship::Info_Flags::Generate_hud_icon]) /*&& !digitus_improbus*/) {
		return;
	}

	setGaugeColor();

	// load in shield frames if not already loaded
	if (sip->shield_icon_index != 255) {
		sgp = &Shield_gauges.at(sip->shield_icon_index);

		if ( (sgp->first_frame == -1) && (sip->shield_icon_index < Hud_shield_filenames.size()) ) {
			sgp->first_frame = bm_load_animation(Hud_shield_filenames.at(sip->shield_icon_index).c_str(), &sgp->num_frames);
			if (sgp->first_frame == -1) {
				if (!shield_ani_warning_displayed_already) {
					shield_ani_warning_displayed_already = true;
					Warning(LOCATION, "Could not load in the HUD shield ani: %s\n", Hud_shield_filenames.at(sip->shield_icon_index).c_str());
				}
				return;
			}
		}
	}

	sx = position[0];
	sy = position[1];

	sx += fl2i(HUD_offset_x);
	sy += fl2i(HUD_offset_y);

	// draw the ship first
	maybeFlashShield(SHIELD_HIT_PLAYER, Shield_hit_data[SHIELD_HIT_PLAYER].hull_hit_index);

	if(sip->shield_icon_index != 255)
	{
		renderBitmap(sgp->first_frame, sx, sy);
	}
	else
	{
		GR_DEBUG_SCOPE("Render generated shield icon");

		bool g3_yourself = !g3_in_frame();
		angles rot_angles = {-1.570796327f,0.0f,0.0f};
		matrix	object_orient;

		vm_angles_2_matrix(&object_orient, &rot_angles);

		const int CLIP_WIDTH = 112;
		const int CLIP_HEIGHT = 93;
		gr_screen.clip_width = CLIP_WIDTH;
		gr_screen.clip_height = CLIP_HEIGHT;

		//Fire it up
		if(g3_yourself)
			g3_start_frame(1);
		hud_save_restore_camera_data(1);
		setClip(sx, sy, CLIP_WIDTH, CLIP_HEIGHT);

		//if(!digitus_improbus)
			g3_set_view_matrix( &sip->closeup_pos, &vmd_identity_matrix, sip->closeup_zoom * 2.5f);
		/*else
		{
			vec3d finger_vec = {0.0f, 0.0f, 176.0f};
			g3_set_view_matrix( &finger_vec, &vmd_identity_matrix, 1.0f);
		}*/

		gr_set_proj_matrix(0.5f*Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance);
		gr_set_view_matrix(&Eye_position, &Eye_matrix);

		//We're ready to show stuff
		//if(!digitus_improbus)
		{
			model_render_params render_info;

			render_info.set_flags(MR_NO_LIGHTING | MR_AUTOCENTER | MR_NO_FOGGING);
			render_info.set_replacement_textures(sp->ship_replacement_textures);
			render_info.set_detail_level_lock(1);
			render_info.set_object_number(OBJ_INDEX(objp));

			model_render_immediate( &render_info, sip->model_num, &object_orient, &vmd_zero_vector );
		}
		/*else
		{
			if(fod_model == -1)
			{
				fod_model = model_load(NOX("FoD.pof"), 0, NULL);
				if(fod_model == -1)
				{
					fod_model = -2;
					return;
				}
			}
			model_render(fod_model, &object_orient, &vmd_zero_vector, MR_NO_LIGHTING | MR_LOCK_DETAIL | MR_AUTOCENTER | MR_NO_FOGGING, -1, -1);
		}*/

		//We're done
		gr_end_view_matrix();
		gr_end_proj_matrix();
		if(g3_yourself)
			g3_end_frame();
		hud_save_restore_camera_data(0);

		resetClip();
	}

	if(!sip->max_shield_strength)
		return;

	// draw the quadrants
	//
	// Draw shield quadrants at one of NUM_SHIELD_LEVELS
	max_shield = shield_get_max_quad(objp);

	coord2d shield_icon_coords[6];

	for ( i = 0; i < objp->n_quadrants; i++ ) {

		if ( objp->flags[Object::Object_Flags::No_shields] ) {
			break;
		}

		if ( !(sip->flags[Ship::Info_Flags::Model_point_shields]) ) {
			if ( objp->shield_quadrant[Quadrant_xlate[i]] < 0.1f )
				continue;
		} else {
			if ( objp->shield_quadrant[i] < 0.1f )
				continue;
		}
		GR_DEBUG_SCOPE("Render shield quadrant");

		range = MAX(HUD_COLOR_ALPHA_MAX, HUD_color_alpha + objp->n_quadrants);

		if ( !(sip->flags[Ship::Info_Flags::Model_point_shields]) )
			hud_color_index = fl2i( (objp->shield_quadrant[Quadrant_xlate[i]] / max_shield) * range);
		else
			hud_color_index = fl2i( (objp->shield_quadrant[i] / max_shield) * range);

		Assert(hud_color_index >= 0 && hud_color_index <= range);

		if ( hud_color_index < 0 ) {
			hud_color_index = 0;
		}
		if ( hud_color_index >= HUD_NUM_COLOR_LEVELS ) {
			hud_color_index = HUD_NUM_COLOR_LEVELS - 1;
		}

		int flash=0;
		flash = maybeFlashShield(mode, i);
		
				
		if ( !flash ) {
			// gr_set_color_fast(&HUD_color_defaults[hud_color_index]);
			setGaugeColor(hud_color_index);
			

			if(sip->shield_icon_index != 255)
			{
				int framenum = sgp->first_frame+i+1;
				if (framenum < sgp->first_frame+sgp->num_frames)
					renderBitmap(framenum, sx, sy);
			}
			else
			{
				//Ugh, draw four shield quadrants
				static const int TRI_EDGE = 6;
				static const int BAR_LENGTH = 112;
				static const int BAR_HEIGHT = 63;
				static const int BAR_WIDTH = 6;
				static const int SHIELD_OFFSET = BAR_WIDTH + TRI_EDGE + 3;

				switch(i)
				{
					//Top
					case 0:
						shield_icon_coords[0].x = sx;                     shield_icon_coords[0].y = sy+BAR_WIDTH+TRI_EDGE;
						shield_icon_coords[1].x = sx;                     shield_icon_coords[1].y = sy;
						shield_icon_coords[2].x = sx+TRI_EDGE;            shield_icon_coords[2].y = sy+BAR_WIDTH;
						shield_icon_coords[3].x = sx+BAR_LENGTH;          shield_icon_coords[3].y = sy;
						shield_icon_coords[4].x = sx+BAR_LENGTH-TRI_EDGE; shield_icon_coords[4].y = sy+BAR_WIDTH;
						shield_icon_coords[5].x = sx+BAR_LENGTH;          shield_icon_coords[5].y = sy+BAR_WIDTH+TRI_EDGE;
						renderShieldIcon(shield_icon_coords);
						break;
					//Left
					case 3:
						sy += SHIELD_OFFSET;
						shield_icon_coords[0].x = sx+BAR_WIDTH+TRI_EDGE; shield_icon_coords[0].y = sy+BAR_HEIGHT;
						shield_icon_coords[1].x = sx;                    shield_icon_coords[1].y = sy+BAR_HEIGHT;
						shield_icon_coords[2].x = sx+BAR_WIDTH;          shield_icon_coords[2].y = sy+BAR_HEIGHT-TRI_EDGE;
						shield_icon_coords[3].x = sx;                    shield_icon_coords[3].y = sy;
						shield_icon_coords[4].x = sx+BAR_WIDTH;          shield_icon_coords[4].y = sy+TRI_EDGE;
						shield_icon_coords[5].x = sx+BAR_WIDTH+TRI_EDGE; shield_icon_coords[5].y = sy;
						renderShieldIcon(shield_icon_coords);
						sy -= SHIELD_OFFSET + BAR_WIDTH + TRI_EDGE;
						break;
					//Right
					case 1:
						sx += BAR_LENGTH;
						sy += SHIELD_OFFSET;
						shield_icon_coords[0].x = sx-BAR_WIDTH-TRI_EDGE; shield_icon_coords[0].y = sy;
						shield_icon_coords[1].x = sx;                    shield_icon_coords[1].y = sy;
						shield_icon_coords[2].x = sx-BAR_WIDTH;          shield_icon_coords[2].y = sy+TRI_EDGE;
						shield_icon_coords[3].x = sx;                    shield_icon_coords[3].y = sy+BAR_HEIGHT;
						shield_icon_coords[4].x = sx-BAR_WIDTH;          shield_icon_coords[4].y = sy+BAR_HEIGHT-TRI_EDGE;
						shield_icon_coords[5].x = sx-BAR_WIDTH-TRI_EDGE; shield_icon_coords[5].y = sy+BAR_HEIGHT;
						renderShieldIcon(shield_icon_coords);
						sx -= BAR_LENGTH;
						sy -= SHIELD_OFFSET;
						break;
					//Bottom
					case 2:
						sy += BAR_HEIGHT + SHIELD_OFFSET*2 - BAR_WIDTH - TRI_EDGE;
						shield_icon_coords[0].x = sx+BAR_LENGTH;          shield_icon_coords[0].y = sy;
						shield_icon_coords[1].x = sx+BAR_LENGTH;          shield_icon_coords[1].y = sy+BAR_WIDTH+TRI_EDGE;
						shield_icon_coords[2].x = sx+BAR_LENGTH-TRI_EDGE; shield_icon_coords[2].y = sy+TRI_EDGE;
						shield_icon_coords[3].x = sx;                     shield_icon_coords[3].y = sy+BAR_WIDTH+TRI_EDGE;
						shield_icon_coords[4].x = sx+TRI_EDGE;            shield_icon_coords[4].y = sy+TRI_EDGE;
						shield_icon_coords[5].x = sx;                     shield_icon_coords[5].y = sy;
						renderShieldIcon(shield_icon_coords);
						sy -= BAR_HEIGHT + SHIELD_OFFSET*2 - BAR_WIDTH - TRI_EDGE;
						break;
					//Whoops?
					default:
						nprintf(("HUD", "Invalid shield quadrant %d specified!\n", i));
						break;
				}
			}
		}
	}

	// hud_set_default_color();
}