void dc_init(void)
{
	if (debug_inited) {
		return;
	}

	debug_inited = TRUE;

	// Init window settings
	dc_font = FONT1;
	row_height = ((Current_font->h) * 3) / 2;	// Row/Line height, in pixels
	col_width = Current_font->w;			// Col/Character width, in pixels
	dc_scroll_x = 0;
	dc_scroll_y = 0;
	DCOLS = (gr_screen.max_w / col_width) - 1;	// Subtract as needed. Windowed mode has some quirks with the resolution
	DROWS = (gr_screen.max_h / row_height) - 2;
	DBCOLS = DCOLS;
	DBROWS = 2 * DROWS;

	// Init History
	dc_history.clear();
	dc_history.push_back("");
	last_oldcommand = dc_history.begin();

	// Init buffers
	dc_buffer.clear();
	dc_buffer.push_back("");
	
	dc_command_buf.reserve(MAX_CLI_LEN);
	dc_command_buf.clear();

	sprintf(dc_title, "FreeSpace Open v%i.%i.%i", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD);
	dc_printf("Debug console started.\n" );
}
ParticleEffectIndex parseEffectElement(EffectType forcedType, const SCP_string& name) {
	if (!optional_string("$New Effect")) {
		SCP_string newName;
		stuff_string(newName, F_NAME);

		auto index = ParticleManager::get()->getEffectByName(newName);

		if (index < 0) {
			error_display(0, "Unknown particle effect name '%s' encountered!", newName.c_str());
		}
		if (forcedType != EffectType::Invalid) {
			// Validate the effect type
			auto effect = ParticleManager::get()->getEffect(index);

			if (effect->getType() != forcedType) {
				error_display(0, "Particle effect '%s' has the wrong effect type! Expected %s but was %s!",
							  getEffectTypeName(forcedType), getEffectTypeName(effect->getType()));
			}
		}

		return index;
	}

	if (forcedType == EffectType::Invalid) {
		forcedType = parseEffectType();
	}

	auto effect = constructEffect(name, forcedType);

	return ParticleManager::get()->addEffect(effect);
}
bool RocketRenderingInterface::LoadTexture(TextureHandle& texture_handle, Vector2i& texture_dimensions,
                                           const String& source)
{
	GR_DEBUG_SCOPE("libRocket::LoadTexture");
	SCP_string filename;
	int dir_type;
	if (!RocketFileInterface::getCFilePath(source, filename, dir_type)) {
		return false;
	}

	auto period_pos = filename.rfind('.');
	if (period_pos != SCP_string::npos) {
		filename = filename.substr(0, period_pos);
	}

	auto id = bm_load_either(filename.c_str(), nullptr, nullptr, nullptr, false, dir_type);
	if (id < 0) {
		return false;
	}

	int w, h;
	bm_get_info(id, &w, &h);

	texture_dimensions.x = w;
	texture_dimensions.y = h;

	auto* tex   = new Texture();
	tex->handle = id;

	texture_handle = get_texture_handle(tex);

	return true;
}
// debug console function called to determine which player to kick
void multi_dcf_kick()
{
	int player_num,idx;
	SCP_string arg;

	// get the callsign of the player to kick
	dc_stuff_string(arg);

	player_num = -1;
	for(idx=0;idx<MAX_PLAYERS;idx++){
		if(MULTI_CONNECTED(Net_players[idx]) && (stricmp(Net_players[idx].m_player->callsign, arg.c_str()) == 0)) {
			player_num = idx;
			break;
		}
	}

	// if we didn't find the player, notify of the results
	if(player_num == -1){
		dc_printf("Could not find player %s to kick!", arg.c_str());
	} 
	// if we found the guy, then try and kick him
	else {
		multi_kick_player(player_num);
	}
}
// given a valid XSTR() tag piece of text, extract the string portion, return it in out, nonzero on success
int lcl_ext_get_text(const SCP_string &xstr, SCP_string &out)
{
	size_t open_quote_pos, close_quote_pos;

	// this is some crazy wack-ass code.
	// look for the open quote
	open_quote_pos = xstr.find('\"');
	if (open_quote_pos == SCP_string::npos) {
		error_display(0, "Error parsing XSTR() tag %s\n", xstr.c_str());
		return 0;
	}

	// look for the close quote
	close_quote_pos = xstr.find('\"', open_quote_pos+1);
	if (close_quote_pos == SCP_string::npos) {
		error_display(0, "Error parsing XSTR() tag %s\n", xstr.c_str());
		return 0;
	}

	// now that we know the boundaries of the actual string in the XSTR() tag, copy it
	out.assign(xstr, open_quote_pos + 1, close_quote_pos - open_quote_pos - 1);

	// success
	return 1;
}
// ============================== IMPLEMENTATIONS =============================
void dc_do_command(SCP_string *cmd_str)
{
	/**
	 * Grab the first word from the cmd_str
	 *  If it is not a literal, ignore it "Invalid keyword: %s"
	 *  Search for the command...
	 *      Compare the word against valid commands
	 *      If command not found, ignore it "Invalid or unknown command: %s"\
	 *  Process the command...
	 *      Call the function to process the command (the rest of the command line is in the parser)
	 *          Function takes care of long_help and status depending on the mode.
	 */
	int i;
	SCP_string command;
	extern debug_command* dc_commands[];	// z64: I don't like this extern here, at all. Nope nope nope.

	if (cmd_str->empty()) {
		return;
	}

	dc_parse_init(*cmd_str);

	dc_stuff_string_white(command);		// Grab the first token, presumably this is a command

	for (i = 0; i < dc_commands_size; ++i) {

		if (stricmp(dc_commands[i]->name, command.c_str()) == 0) {
			break;
		} // Else, continue
	}

	if (i == dc_commands_size) {
		dc_printf("Command not found: '%s'\n", command.c_str());
		return;
	} // Else, we found our command

	try {
		dc_commands[i]->func();	// Run the command!
	
	} catch (errParseString err) {
		dc_printf("Require string(s) not found: \n");
		for (uint j = 0; j < err.expected_tokens.size(); ++j) {
			dc_printf("%i: %s\n", j, err.expected_tokens[j].c_str());
		}

		dc_printf("Found '%s' instead\n", err.found_token.c_str());
	
	} catch (errParse err) {
		dc_printf("Invalid argument. Expected %s, found '%s'\n", token_str[err.expected_type], err.found_token.c_str());

	}

	// dc_maybe_stuff_string is vulnerable to overflow. Once the errParseOverflow throw class (or w/e) gets
	// implemented, this last command should be put into its own try{} catch{} block.
	if (dc_maybe_stuff_string(command)) {
		dc_printf( "Ignoring the unused command line tail '%s'\n", command.c_str() );
	}
}
Exemple #7
0
		void Warning(const char* filename, int line, const char* format, ...)
		{
#ifndef NDEBUG
			SCP_string msg;
			va_list args;

			va_start(args, format);
			vsprintf(msg, format, args);
			va_end(args);

			ReleaseWarning(filename, line, "%s", msg.c_str());
#endif
		}
int parseAnimation(bool critical) {
	SCP_string name;
	stuff_string(name, F_FILESPEC);

	auto handle = bm_load_animation(name.c_str());

	if (handle < 0) {
		int level = critical ? 1 : 0;
		error_display(level, "Failed to load effect %s!", name.c_str());
	}

	return handle;
}
void dc_printf(const char *format, ...)
{
	SCP_string tmp;
	va_list args;
	SCP_string::iterator tmp_it;

	va_start(args, format);
	vsprintf(tmp, format, args);
	va_end(args);

	for (tmp_it = tmp.begin(); tmp_it != tmp.end(); ++tmp_it) {
		dc_putc(*tmp_it);
	}
}
HKEY get_registry_keyname(char* out_keyname, const char* section)
{
	// Every compiler from Visual Studio 2008 onward should have support for UAC
#if _MSC_VER >= 1400
	if (userSIDValid)
	{
		if (needsWOW64())
		{
			if (section) {
				sprintf(out_keyname, "%s_Classes\\VirtualStore\\Machine\\Software\\Wow6432Node\\%s\\%s\\%s", userSID.c_str(), szCompanyName, szAppName, section);
			}
			else {
				sprintf(out_keyname, "%s_Classes\\VirtualStore\\Machine\\Software\\Wow6432Node\\%s\\%s", userSID.c_str(), szCompanyName, szAppName);
			}
		}
		else
		{
			if (section) {
				sprintf(out_keyname, "%s_Classes\\VirtualStore\\Machine\\Software\\%s\\%s\\%s", userSID.c_str(), szCompanyName, szAppName, section);
			}
			else {
				sprintf(out_keyname, "%s_Classes\\VirtualStore\\Machine\\Software\\%s\\%s", userSID.c_str(), szCompanyName, szAppName);
			}
		}

		return HKEY_USERS;
	}
	else
	{
		// This will probably fail
		if (section) {
			sprintf(out_keyname, "Software\\%s\\%s\\%s", szCompanyName, szAppName, section);
		}
		else {
			sprintf(out_keyname, "Software\\%s\\%s", szCompanyName, szAppName);
		}

		return HKEY_LOCAL_MACHINE;
	}
#else
	if (section) {
		sprintf(out_keyname, "Software\\%s\\%s\\%s", szCompanyName, szAppName, section);
	}
	else {
		sprintf(out_keyname, "Software\\%s\\%s", szCompanyName, szAppName);
	}

	return HKEY_LOCAL_MACHINE;
#endif
}
void outwnd_printf(const char *id, const char *format, ...)
{
	SCP_string temp;
	va_list args;

	if ( (id == NULL) || (format == NULL) )
		return;

	va_start(args, format);
	vsprintf(temp, format, args);
	va_end(args);

	outwnd_print(id, temp.c_str());
}
void outwnd_printf2(const char *format, ...)
{
	SCP_string temp;
	va_list args;

	if (format == NULL)
		return;

	va_start(args, format);
	vsprintf(temp, format, args);
	va_end(args);

	outwnd_print("General", temp.c_str());
}
static void opengl_purge_shader_cache_type(const char* ext) {

	SCP_string filter("*.");
	filter += ext;

	// Previously the cache files were stored in the mod directory. Since we have a better system now, those files
	// should be cleaned out. This is only needed if we have a mod directory since otherwise we would delete the actual
	// cache files
	if (Cmdline_mod != nullptr && strlen(Cmdline_mod) > 0) {
		SCP_vector<SCP_string> cache_files;
		cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, nullptr,
		                 CF_LOCATION_TYPE_PRIMARY_MOD | CF_LOCATION_TYPE_SECONDARY_MODS);

		for (auto& file : cache_files) {
			cf_delete((file + "." + ext).c_str(), CF_TYPE_CACHE,
			          CF_LOCATION_TYPE_PRIMARY_MOD | CF_LOCATION_TYPE_SECONDARY_MODS);
		}
	}

	SCP_vector<SCP_string> cache_files;
	SCP_vector<file_list_info> file_info;
	cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, &file_info,
	                 CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);

	Assertion(cache_files.size() == file_info.size(),
			  "cf_get_file_list returned different sizes for file names and file informations!");

	const auto TIMEOUT = 2.0 * 30.0 * 24.0 * 60.0 * 60.0; // purge timeout in seconds which is ~2 months
	const SCP_string PREFIX = "ogl_shader-";

	auto now = std::time(nullptr);
	for (size_t i = 0; i < cache_files.size(); ++i) {
		auto& name = cache_files[i];
		auto write_time = file_info[i].write_time;

		if (name.compare(0, PREFIX.size(), PREFIX) != 0) {
			// Not an OpenGL cache file
			continue;
		}

		auto diff = std::difftime(now, write_time);

		if (diff > TIMEOUT) {
			auto full_name = name + "." + ext;

			cf_delete(full_name.c_str(), CF_TYPE_CACHE);
		}
	}
}
Exemple #14
0
		void WarningEx(const char* filename, int line, const char* format, ...)
		{
#ifndef NDEBUG
			if (Cmdline_extra_warn) {
				SCP_string msg;
				va_list args;

				va_start(args, format);
				vsprintf(msg, format, args);
				va_end(args);

				Warning(filename, line, "%s", msg.c_str());
			}
#endif
		}
/*
 * validate that a pilot/player was created with the same language FSO is currently using
 *
 * @param pilots callsign
 * @note not longer needed if intel entry "primary keys" change to a non-translated value
 */
bool valid_pilot_lang(char *callsign)
{
	char pilot_lang[LCL_LANG_NAME_LEN+1], current_lang[LCL_LANG_NAME_LEN+1];
	SCP_string filename = callsign;

	filename += ".plr";
	lcl_get_language_name(current_lang);

	if (Pilot.verify(filename.c_str(), NULL, pilot_lang)) {
		if (!strcmp(current_lang, pilot_lang)) {
			return true;
		}
	}
	return false;
}
/**
 * Builds the output text.
 */
void profile_dump_output()
{
    if (Cmdline_frame_profile) {
        end_profile_time = timer_get_microseconds();

        if (Cmdline_profile_write_file)
        {
            profiling_file << end_profile_time << ";" << (end_profile_time - start_profile_time) << std::endl;
        }

        profile_output.clear();
        profile_output += "  Avg :  Min :  Max :   # : Profile Name\n";
        profile_output += "----------------------------------------\n";

        for(int i = 0; i < (int)samples.size(); i++) {
            uint64_t sample_time;
            float percent_time, avg_time, min_time, max_time;
            uint64_t avg_micro_seconds, min_micro_seconds, max_micro_seconds;

            Assert(samples[i].open_profiles == 0);

            sample_time = samples[i].accumulator - samples[i].children_sample_time;

            if (end_profile_time == start_profile_time) {
                percent_time = 0.0f;
            } else {
                percent_time = (i2fl(sample_time) / i2fl(end_profile_time - start_profile_time)) *100.0f;
            }

            avg_micro_seconds = min_micro_seconds = max_micro_seconds = sample_time;
            avg_time = min_time = max_time = percent_time;

            // add new measurement into the history and get avg, min, and max
            store_profile_in_history(samples[i].name, percent_time, sample_time);
            get_profile_from_history(samples[i].name, &avg_time, &min_time, &max_time, &avg_micro_seconds, &min_micro_seconds, &max_micro_seconds);

            // format the data
            char avg[64], min[64], max[64], num[64];

            sprintf(avg, "%3.1f%% (%3.1fms)", avg_time, i2fl(avg_micro_seconds)*0.001f);
            sprintf(min, "%3.1f%% (%3.1fms)", min_time, i2fl(min_micro_seconds)*0.001f);
            sprintf(max, "%3.1f%% (%3.1fms)", max_time, i2fl(max_micro_seconds)*0.001f);
            sprintf(num, "%3d", samples[i].profile_instances);

            SCP_string indented_name(samples[i].name);

            for(uint indent = 0; indent < samples[i].num_parents; indent++) {
                indented_name = ">" + indented_name;
            }

            char line[256];
            sprintf(line, "%5s : %5s : %5s : %3s : ", avg, min, max, num);

            profile_output += line + indented_name + "\n";
        }

        samples.clear();
        start_profile_time = timer_get_microseconds();
    }
}
Exemple #17
0
void dc_draw(bool show_prompt = FALSE)
{
	gr_clear();
	font::set_font(dc_font);
	gr_set_color_fast( &Color_bright );
	int w;
	gr_get_string_size(&w, nullptr, dc_title.c_str());

	gr_string((gr_screen.clip_width - w) / 2, 3, dc_title.c_str(), GR_RESIZE_NONE );

	gr_set_color_fast( &Color_normal );

	dc_draw_window(show_prompt);

	gr_flip();
}
// printf function itself called by the ml_printf macro
void ml_printf(const char *format, ...)
{
	SCP_string temp;
	va_list args;

	if (format == NULL) {
		return;
	}
	
	// format the text
	va_start(args, format);
	vsprintf(temp, format, args);
	va_end(args);

	// log the string including the time
	log_string(LOGFILE_MULTI_LOG, temp.c_str(), 1);
}
ParticleEffectIndex ParticleManager::getEffectByName(const SCP_string& name) {
	if (name.empty()) {
		// Don't allow empty names, it's a special case for effects that should not be referenced.
		return -1;
	}

	auto foundIterator = find_if(m_effects.begin(), m_effects.end(),
								 [&name](const std::shared_ptr<ParticleEffect>& ptr) {
									 return !stricmp(ptr->getName().c_str(), name.c_str());
								 });

	if (foundIterator == m_effects.end()) {
		return -1;
	}

	return distance(m_effects.begin(), foundIterator);
}
ParticleEffectIndex parseEffect(const SCP_string& objectName) {
	SCP_string name;
	stuff_string(name, F_NAME);

	auto idx = ParticleManager::get()->getEffectByName(name);

	if (idx < 0) {
		if (objectName.empty()) {
			error_display(0, "Unknown particle effect name '%s' encountered!", name.c_str());
		} else {
			error_display(0, "Unknown particle effect name '%s' encountered while parsing '%s'!", name.c_str(),
						  objectName.c_str());
		}
	}

	return idx;
}
Exemple #21
0
		void AssertMessage(const char * text, const char * filename, int linenum, const char * format, ...)
		{
			// We only want to display the file name
			filename = clean_filename(filename);

			SCP_stringstream msgStream;
			msgStream << "Assert: \"" << text << "\"\n";
			msgStream << "File: " << filename << "\n";
			msgStream << "Line: " << linenum << "\n";
			
			if (format != nullptr)
			{
				SCP_string buffer;
				va_list args;

				va_start(args, format);
				vsprintf(buffer, format, args);
				va_end(args);

				msgStream << buffer << "\n";
				mprintf(("ASSERTION: \"%s\" at %s:%d\n %s\n", text, filename, linenum, buffer.c_str()));
			}
			else
			{
				// No additional message
				mprintf(("ASSERTION: \"%s\" at %s:%d\n", text, filename, linenum));
			}

			if (running_unittests) {
				throw AssertException(msgStream.str());
			}

			msgStream << "\n";
			msgStream << dump_stacktrace();

			SCP_string messageText = msgStream.str();
			set_clipboard_text(messageText.c_str());

			messageText = truncateLines(msgStream, Messagebox_lines);
			messageText += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n";
			messageText += "\n\nUse Debug to break into Debugger, Exit will close the application.\n";

			Error(messageText.c_str());
		}
void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *lookupVector)
{
	SCP_string name;

	stuff_string(name, F_NAME, "\t \n");

	if (!no_create)
	{
		if (lookupVector != NULL)
		{
			if (gamesnd_lookup_name(name.c_str(), *lookupVector) >= 0)
			{
				Warning(LOCATION, "Duplicate sound name \"%s\" found!", name.c_str());
			}
		}

		gs->name = name;
	}
	else
	{
		int vectorIndex = gamesnd_lookup_name(name.c_str(), *lookupVector);

		if (vectorIndex < 0)
		{
			Warning(LOCATION, "No existing sound entry with name \"%s\" found!", name.c_str());
			no_create = false;
			gs->name = name;
		}
		else
		{
			gs = &lookupVector->at(vectorIndex);
		}
	}

	if (optional_string("+Filename:"))
	{
		parse_gamesnd_new(gs, no_create);
	}
	else
	{
		parse_gamesnd_old(gs);
	}
}
GLint opengl::ShaderUniforms::findUniformLocation(const SCP_string& name) {
	auto iter = _uniform_locations.find(name);

	if (iter == _uniform_locations.end()) {
		// Lazily initialize the uniform locations when required. This avoids keeping a list of all uniforms in the code
		auto location = glGetUniformLocation(_program->getShaderHandle(), name.c_str());

		if (location == -1)
		{
			// This can happen if the uniform has been optimized out by the driver
			mprintf(("WARNING: Failed to find uniform '%s'.\n", name.c_str()));
		}

		_uniform_locations.insert(std::make_pair(name, location));
		return location;
	}
	else {
		return iter->second;
	}
}
void opengl::ShaderUniforms::setUniformMatrix4fv(const SCP_string &name, const int count, const matrix4 *val)
{
	Assertion(GL_state.IsCurrentProgram(_program->getShaderHandle()), "The program must be current before setting uniforms!");

	size_t uniform_index = findUniform(name);
	bool resident = false;

	if (uniform_index != (size_t)-1) {
		Assert((size_t)uniform_index < _uniforms.size());

		uniform_bind *bind_info = &_uniforms[uniform_index];

		if (bind_info->type == uniform_bind::MATRIX4 && bind_info->count == count) {
			bool equal = true;

			// if the values are close enough, pass.
			for (int i = 0; i < count; ++i) {
				if (!vm_matrix_equal(val[i], _uniform_data_matrix4[bind_info->index + i])) {
					equal = false;
					break;
				}
			}

			if (equal) {
				return;
			}

			resident = true;
			for (int i = 0; i < count; ++i) {
				_uniform_data_matrix4[bind_info->index + i] = val[i];
			}
		}
	}

	if (!resident) {
		// uniform doesn't exist in our previous uniform block so queue this new value
		for (int i = 0; i < count; ++i) {
			_uniform_data_matrix4.push_back(val[i]);
		}

		uniform_bind new_bind;
		new_bind.count = count;
		new_bind.index = _uniform_data_matrix4.size() - count;
		//	new_bind.index = num_matrix_uniforms - count;
		new_bind.type = uniform_bind::MATRIX4;
		new_bind.name = name;

		_uniforms.push_back(new_bind);

		_uniform_lookup[name] = _uniforms.size() - 1;
	}

	glUniformMatrix4fv(findUniformLocation(name.c_str()), count, GL_FALSE, (const GLfloat*)val);
}
/**
 * Parse the sounds.tbl file, and load the specified sounds.
 */
void gamesnd_parse_soundstbl()
{
	parse_sound_table("sounds.tbl");

	parse_modular_table("*-snd.tbm", parse_sound_table);

	// if we are missing any species then report
	if (!missingFlybySounds.empty())
	{
		SCP_string errorString;
		for (size_t i = 0; i < missingFlybySounds.size(); i++)
		{
			errorString.append(missingFlybySounds[i].species_name);
			errorString.append("\n");
		}

		Error(LOCATION, "The following species are missing flyby sounds in sounds.tbl:\n%s", errorString.c_str());
	}

	missingFlybySounds.clear();
}
Exemple #26
0
	int parse_font()
	{
		int font_idx;

		SCP_string input;
		stuff_string(input, F_NAME);
		SCP_stringstream ss(input);

		int fontNum;
		ss >> fontNum;

		if (ss.fail())
		{
			fontNum = FontManager::getFontIndex(input);

			if (fontNum < 0)
			{
				error_display(0, "Invalid font name \"%s\"!", input.c_str());
				font_idx = -1;
			}
			else
			{
				font_idx = fontNum;
			}
		}
		else
		{
			if (fontNum < 0 || fontNum >= FontManager::numberOfFonts())
			{
				error_display(0, "Invalid font number %d! must be greater or equal to zero and smaller than %d.", fontNum, FontManager::numberOfFonts());
				font_idx = -1;
			}
			else
			{
				font_idx = fontNum;
			}
		}

		return font_idx;
	}
void opengl_uniform_state::setUniformMatrix4fv(const SCP_string &name, const int count, const matrix4 *val)
{
	size_t uniform_index = findUniform(name);
	bool resident = false;

	if ( uniform_index != (size_t)-1) {
		Assert( (size_t)uniform_index < uniforms.size() );

		uniform_bind *bind_info = &uniforms[uniform_index];

		if ( bind_info->type == uniform_bind::MATRIX4 && bind_info->count == count ) {
			bool equal = true;

			// if the values are close enough, pass.
			for ( int i = 0; i < count; ++i ) {
				if ( !vm_matrix_equal(val[i], uniform_data_matrix4[bind_info->index+i]) ) {
					equal = false;
					break;
				}
			}

			if ( equal ) {
				return;
			}

			resident = true;
			for ( int i = 0; i < count; ++i ) {
				uniform_data_matrix4[bind_info->index+i] = val[i];
			}
		}
	}

	if ( !resident ) {
		// uniform doesn't exist in our previous uniform block so queue this new value
		for ( int i = 0; i < count; ++i ) {
			uniform_data_matrix4.push_back(val[i]);
		}

		uniform_bind new_bind;
		new_bind.count = count;
		new_bind.index = uniform_data_matrix4.size() - count;
		//	new_bind.index = num_matrix_uniforms - count;
		new_bind.type = uniform_bind::MATRIX4;
		new_bind.name = name;

		uniforms.push_back(new_bind);

		uniform_lookup[name] = uniforms.size()-1;
	}

	glUniformMatrix4fv(opengl_shader_get_uniform(name.c_str()), count, GL_FALSE, (const GLfloat*)val);
}
// printf function itself called by the ml_printf macro
void log_printf(int logfile_type, char *format, ...)
{
	SCP_string temp;
	va_list args;

	if (format == NULL) {
		return;
	}

	// if we don't have a valid logfile do nothing
	if (logfiles[logfile_type].log_file == NULL) {
		return;
	}
	
	// format the text
	va_start(args, format);
	vsprintf(temp, format, args);
	va_end(args);
	
	// log the string
	log_string(logfile_type, temp.c_str());
}
void dc_draw(bool show_prompt = FALSE)
{
	gr_clear();
	gr_set_font(dc_font);
	gr_set_color_fast( &Color_bright );
	gr_string( 0x8000, 3, dc_title.c_str(), GR_RESIZE_NONE );

	gr_set_color_fast( &Color_normal );

	dc_draw_window(show_prompt);

	gr_flip();
}
/**
 * Load a shader file from disc or from the builtin defaults in def_files.cpp if none can be found.
 * This function will also create a list of preprocessor defines for the GLSL compiler based on the shader flags
 * and the supported GLSL version as reported by the GPU driver.
 *
 * @param shader	shader_type enum defined with which shader we're loading
 * @param filename	C-string holding the filename (with extension) of the shader file
 * @param flags		integer variable holding a combination of SDR_* flags
 * @return			C-string holding the complete shader source code
 */
static SCP_string opengl_load_shader(const char* filename) {
	SCP_string content;
	if (Enable_external_shaders) {
		CFILE* cf_shader = cfopen(filename, "rt", CFILE_NORMAL, CF_TYPE_EFFECTS);

		if (cf_shader != NULL) {
			int len = cfilelength(cf_shader);
			content.resize(len);

			cfread(&content[0], len + 1, 1, cf_shader);
			cfclose(cf_shader);

			return content;
		}
	}

	//If we're still here, proceed with internals
	mprintf(("   Loading built-in default shader for: %s\n", filename));
	auto def_shader = defaults_get_file(filename);
	content.assign(reinterpret_cast<const char*>(def_shader.data), def_shader.size);

	return content;
}