Esempio n. 1
0
/*
 * @brief Handles the actual loading of .ogg music files.
 */
static _Bool S_LoadMusicFile(const char *name, void **buffer, SDL_RWops **rw, Mix_Music **music) {
	char path[MAX_QPATH];

	*music = NULL;

	StripExtension(name, path);
	g_snprintf(path, sizeof(path), "music/%s.ogg", name);

	int32_t len;
	if ((len = Fs_Load(path, buffer)) != -1) {

		if ((*rw = SDL_RWFromMem(*buffer, len))) {

			if ((*music = Mix_LoadMUS_RW(*rw))) {
				Com_Debug("Loaded %s\n", name);
			} else {
				Com_Warn("Failed to load %s: %s\n", name, Mix_GetError());
				SDL_FreeRW(*rw);
			}
		} else {
			Com_Warn("Failed to create SDL_RWops for %s\n", name);
			Fs_Free(*buffer);
		}
	} else {
		Com_Debug("Failed to load %s\n", name);
	}

	return *music != NULL;
}
Esempio n. 2
0
/*
 * @brief
 */
void R_ProgramVariable(r_variable_t *variable, GLenum type, const char *name) {

	memset(variable, 0, sizeof(*variable));
	variable->location = -1;

	if (!r_state.active_program) {
		Com_Warn("No program currently bound\n");
		return;
	}

	switch (type) {
	case R_ATTRIBUTE:
		variable->location = qglGetAttribLocation(r_state.active_program->id, name);
		break;
	default:
		variable->location = qglGetUniformLocation(r_state.active_program->id, name);
		break;
	}

	if (variable->location == -1) {
		Com_Warn("Failed to resolve variable %s in program %s\n", name,
				r_state.active_program->name);
		return;
	}

	variable->type = type;
	g_strlcpy(variable->name, name, sizeof(variable->name));
	memset(&variable->value, 0xff, sizeof(variable->value));
}
Esempio n. 3
0
/*
 * @brief
 */
s_sample_t *S_LoadModelSample(entity_state_t *ent, const char *name) {
	char model[MAX_QPATH];
	char path[MAX_QPATH];
	char alias[MAX_QPATH];
	s_sample_t *sample;

	if (!s_env.initialized)
		return NULL;

	// determine what model the client is using
	memset(model, 0, sizeof(model));

	if (ent->number - 1 >= MAX_CLIENTS) {
		Com_Warn("Invalid client entity: %d\n", ent->number - 1);
		return NULL;
	}

	uint16_t n = CS_CLIENTS + ent->number - 1;
	if (cl.config_strings[n][0]) {
		char *p = strchr(cl.config_strings[n], '\\');
		if (p) {
			p += 1;
			strcpy(model, p);
			p = strchr(model, '/');
			if (p)
				*p = 0;
		}
	}

	// if we can't figure it out, use common
	if (*model == '\0')
		strcpy(model, "common");

	// see if we already know of the model-specific sound
	g_snprintf(alias, sizeof(path), "#players/%s/%s", model, name + 1);
	sample = (s_sample_t *) S_FindMedia(alias);

	if (sample)
		return sample;

	// we don't, try it
	sample = S_LoadSample(alias);

	if (sample->chunk)
		return sample;

	// that didn't work, so load the common one and alias it
	// the media subsystem will free the previous sample for us
	g_snprintf(path, sizeof(path), "#players/common/%s", name + 1);
	sample = S_LoadSample(path);

	if (sample->chunk)
		return S_AliasSample(sample, alias);

	Com_Warn("Failed to load %s\n", alias);
	return NULL;
}
Esempio n. 4
0
/*
 * @brief
 */
static void S_LoadSampleChunk(s_sample_t *sample) {
	char path[MAX_QPATH];
	void *buf;
	int32_t i, len;
	SDL_RWops *rw;

	if (sample->media.name[0] == '*') // place holder
		return;

	if (sample->media.name[0] == '#') { // global path
		g_strlcpy(path, (sample->media.name + 1), sizeof(path));
	} else { // or relative
		g_snprintf(path, sizeof(path), "sounds/%s", sample->media.name);
	}

	buf = NULL;
	rw = NULL;

	i = 0;
	while (SAMPLE_TYPES[i]) {

		StripExtension(path, path);
		g_strlcat(path, SAMPLE_TYPES[i++], sizeof(path));

		if ((len = Fs_Load(path, &buf)) == -1)
			continue;

		if (!(rw = SDL_RWFromMem(buf, len))) {
			Fs_Free(buf);
			continue;
		}

		if (!(sample->chunk = Mix_LoadWAV_RW(rw, false)))
			Com_Warn("%s\n", Mix_GetError());

		Fs_Free(buf);

		SDL_FreeRW(rw);

		if (sample->chunk) { // success
			break;
		}
	}

	if (sample->chunk) {
		Mix_VolumeChunk(sample->chunk, s_volume->value * MIX_MAX_VOLUME);
		Com_Debug("Loaded %s\n", path);
	} else {
		if (g_str_has_prefix(sample->media.name, "#players")) {
			Com_Debug("Failed to load player sample %s\n", sample->media.name);
		} else {
			Com_Warn("Failed to load %s\n", sample->media.name);
		}
	}
}
Esempio n. 5
0
/*
 * @brief
 */
static r_program_t *R_LoadProgram(const char *name, void(*Init)(void)) {
	r_program_t *prog;
	char log[MAX_STRING_CHARS];
	uint32_t e;
	int32_t i;

	for (i = 0; i < MAX_PROGRAMS; i++) {
		prog = &r_state.programs[i];

		if (!prog->id)
			break;
	}

	if (i == MAX_PROGRAMS) {
		Com_Warn("MAX_PROGRAMS reached\n");
		return NULL;
	}

	g_strlcpy(prog->name, name, sizeof(prog->name));

	prog->id = qglCreateProgram();

	prog->v = R_LoadShader(GL_VERTEX_SHADER, va("%s_vs.glsl", name));
	prog->f = R_LoadShader(GL_FRAGMENT_SHADER, va("%s_fs.glsl", name));

	if (prog->v)
		qglAttachShader(prog->id, prog->v->id);
	if (prog->f)
		qglAttachShader(prog->id, prog->f->id);

	qglLinkProgram(prog->id);

	qglGetProgramiv(prog->id, GL_LINK_STATUS, &e);
	if (!e) {
		qglGetProgramInfoLog(prog->id, sizeof(log) - 1, NULL, log);
		Com_Warn("%s: %s\n", prog->name, log);

		R_ShutdownProgram(prog);
		return NULL;
	}

	prog->Init = Init;

	if (prog->Init) { // invoke initialization function
		R_UseProgram(prog);

		prog->Init();

		R_UseProgram(NULL);
	}

	R_GetError(prog->name);

	return prog;
}
Esempio n. 6
0
/*
 * Pak_ReadPakfile
 *
 * Return a populated Pakfile from the specified path, with entries
 * hashed by name for fast finds.
 */
pak_t *Pak_ReadPakfile(const char *pakfile) {
	pak_header_t header;
	int i;
	pak_t *pak;

	pak = (pak_t *) Z_Malloc(sizeof(*pak));

	pak->handle = fopen(pakfile, "rb");
	if (!pak->handle) {
		Com_Warn("Pak_ReadPakfile: Couldn't open %s.\n", pakfile);
		Z_Free(pak);
		return NULL;
	}

	strcpy(pak->file_name, pakfile);

	Fs_Read(&header, 1, sizeof(pak_header_t), pak->handle);
	if (LittleLong(header.ident) != PAK_HEADER) {
		Com_Warn("Pak_ReadPakfile: %s is not a pak file.\n", pakfile);
		Fs_CloseFile(pak->handle);
		Z_Free(pak);
		return NULL;
	}

	header.dir_ofs = LittleLong(header.dir_ofs);
	header.dir_len = LittleLong(header.dir_len);

	pak->num_entries = header.dir_len / sizeof(pak_entry_t);
	if (pak->num_entries > MAX_PAK_ENTRIES) {
		Com_Warn("Pak_ReadPakfile: %s has %i files.\n", pakfile,
				pak->num_entries);
		Fs_CloseFile(pak->handle);
		Z_Free(pak);
		return NULL;
	}

	pak->entries = (pak_entry_t *) Z_Malloc(
			pak->num_entries * sizeof(pak_entry_t));

	fseek(pak->handle, header.dir_ofs, SEEK_SET);
	Fs_Read(pak->entries, 1, header.dir_len, pak->handle);

	Hash_Init(&pak->hash_table);

	// parse the directory
	for (i = 0; i < pak->num_entries; ++i) {
		pak->entries[i].file_ofs = LittleLong(pak->entries[i].file_ofs);
		pak->entries[i].file_len = LittleLong(pak->entries[i].file_len);

		Hash_Put(&pak->hash_table, pak->entries[i].name, &pak->entries[i]);
	}

	return pak;
}
Esempio n. 7
0
/*
 * Sv_ConfigStrings_f
 */
static void Sv_ConfigStrings_f(void) {
	unsigned int start;

	Com_Debug("ConfigStrings() from %s\n", Sv_NetaddrToString(sv_client));

	if (sv_client->state != SV_CLIENT_CONNECTED) {
		Com_Warn("Sv_ConfigStrings_f: %s already spawned\n",
				Sv_NetaddrToString(sv_client));
		return;
	}

	// handle the case of a level changing while a client was connecting
	if (strtoul(Cmd_Argv(1), NULL, 0) != svs.spawn_count) {
		Com_Debug("Sv_ConfigStrings_f: Stale spawn count from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_New_f();
		return;
	}

	start = strtoul(Cmd_Argv(2), NULL, 0);

	if (start >= MAX_CONFIG_STRINGS) { // catch bad offsets
		Com_Warn("Sv_ConfigStrings_f: Bad config_string offset from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_KickClient(sv_client, NULL);
		return;
	}

	// write a packet full of data
	while (sv_client->netchan.message.size < MAX_MSG_SIZE / 2 && start
			< MAX_CONFIG_STRINGS) {
		if (sv.config_strings[start][0]) {
			Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CONFIG_STRING);
			Msg_WriteShort(&sv_client->netchan.message, start);
			Msg_WriteString(&sv_client->netchan.message,
					sv.config_strings[start]);
		}
		start++;
	}

	// send next command
	if (start == MAX_CONFIG_STRINGS) {
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
		Msg_WriteString(&sv_client->netchan.message,
				va("baselines %i 0\n", svs.spawn_count));
	} else {
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
		Msg_WriteString(&sv_client->netchan.message,
				va("config_strings %i %i\n", svs.spawn_count, start));
	}
}
Esempio n. 8
0
/*
 * @brief
 */
void R_InitGlExtensions(void) {

	// multitexture
	if (strstr(r_config.extensions_string, "GL_ARB_multitexture")) {
		qglActiveTexture = SDL_GL_GetProcAddress("glActiveTexture");
		qglClientActiveTexture = SDL_GL_GetProcAddress("glClientActiveTexture");
	} else
		Com_Error(ERR_FATAL, "GL_ARB_multitexture not found\n");

	// vertex buffer objects
	if (strstr(r_config.extensions_string, "GL_ARB_vertex_buffer_object")) {
		qglGenBuffers = SDL_GL_GetProcAddress("glGenBuffers");
		qglDeleteBuffers = SDL_GL_GetProcAddress("glDeleteBuffers");
		qglBindBuffer = SDL_GL_GetProcAddress("glBindBuffer");
		qglBufferData = SDL_GL_GetProcAddress("glBufferData");
	} else
		Com_Warn("GL_ARB_vertex_buffer_object not found\n");

	// glsl vertex and fragment shaders and programs
	if (strstr(r_config.extensions_string, "GL_ARB_fragment_shader")) {
		qglCreateShader = SDL_GL_GetProcAddress("glCreateShader");
		qglDeleteShader = SDL_GL_GetProcAddress("glDeleteShader");
		qglShaderSource = SDL_GL_GetProcAddress("glShaderSource");
		qglCompileShader = SDL_GL_GetProcAddress("glCompileShader");
		qglGetShaderiv = SDL_GL_GetProcAddress("glGetShaderiv");
		qglGetShaderInfoLog = SDL_GL_GetProcAddress("glGetShaderInfoLog");
		qglCreateProgram = SDL_GL_GetProcAddress("glCreateProgram");
		qglDeleteProgram = SDL_GL_GetProcAddress("glDeleteProgram");
		qglAttachShader = SDL_GL_GetProcAddress("glAttachShader");
		qglDetachShader = SDL_GL_GetProcAddress("glDetachShader");
		qglLinkProgram = SDL_GL_GetProcAddress("glLinkProgram");
		qglUseProgram = SDL_GL_GetProcAddress("glUseProgram");
		qglGetProgramiv = SDL_GL_GetProcAddress("glGetProgramiv");
		qglGetProgramInfoLog = SDL_GL_GetProcAddress("glGetProgramInfoLog");
		qglGetUniformLocation = SDL_GL_GetProcAddress("glGetUniformLocation");
		qglUniform1i = SDL_GL_GetProcAddress("glUniform1i");
		qglUniform1f = SDL_GL_GetProcAddress("glUniform1f");
		qglUniform3fv = SDL_GL_GetProcAddress("glUniform3fv");
		qglUniform4fv = SDL_GL_GetProcAddress("glUniform4fv");
		qglGetAttribLocation = SDL_GL_GetProcAddress("glGetAttribLocation");

		// vertex attribute arrays
		qglEnableVertexAttribArray = SDL_GL_GetProcAddress("glEnableVertexAttribArray");
		qglDisableVertexAttribArray = SDL_GL_GetProcAddress("glDisableVertexAttribArray");
		qglVertexAttribPointer = SDL_GL_GetProcAddress("glVertexAttribPointer");
	} else
		Com_Warn("GL_ARB_fragment_shader not found\n");
}
Esempio n. 9
0
/**
 * @brief Send data to the specified TCP stream.
 */
_Bool Net_SendStream(int32_t sock, const void *data, size_t len) {
	mem_buf_t buf;
	byte buffer[MAX_MSG_SIZE];

	Mem_InitBuffer(&buf, buffer, sizeof(buffer));

	// write the packet length
	Net_WriteLong(&buf, (int32_t) len);

	// and copy the payload
	Net_WriteData(&buf, data, len);

	ssize_t sent = 0;
	while ((size_t) sent < buf.size) {
		const ssize_t s = send(sock, (void *)(buf.data + sent), buf.size - sent, 0);
		if (s == -1) {
			if (Net_GetError() != EWOULDBLOCK) {
				Com_Warn("%s\n", Net_GetErrorString());
				return false;
			}
		}
		sent += s;
	}

	return sent == (ssize_t) buf.size;
}
Esempio n. 10
0
/*
 * Sv_New_f
 *
 * Sends the first message from the server to a connected client.
 * This will be sent on the initial connection and upon each server load.
 */
static void Sv_New_f(void) {
	int player_num;

	Com_Debug("New() from %s\n", Sv_NetaddrToString(sv_client));

	if (sv_client->state != SV_CLIENT_CONNECTED) {
		Com_Warn("Sv_New_f: %s already spawned\n",
				Sv_NetaddrToString(sv_client));
		return;
	}

	// demo servers will send the demo file's server info packet
	if (sv.state == SV_ACTIVE_DEMO) {
		return;
	}

	// send the server data
	Msg_WriteByte(&sv_client->netchan.message, SV_CMD_SERVER_DATA);
	Msg_WriteLong(&sv_client->netchan.message, PROTOCOL);
	Msg_WriteLong(&sv_client->netchan.message, svs.spawn_count);
	Msg_WriteLong(&sv_client->netchan.message, svs.frame_rate);
	Msg_WriteByte(&sv_client->netchan.message, 0);
	Msg_WriteString(&sv_client->netchan.message, Cvar_GetString("game"));

	player_num = sv_client - svs.clients;
	Msg_WriteShort(&sv_client->netchan.message, player_num);

	// send full level name
	Msg_WriteString(&sv_client->netchan.message, sv.config_strings[CS_NAME]);

	// begin fetching config_strings
	Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
	Msg_WriteString(&sv_client->netchan.message,
			va("config_strings %i 0\n", svs.spawn_count));
}
Esempio n. 11
0
/*
 * Cl_Record_f
 *
 * record <demo name>
 *
 * Begin recording a demo from the current frame until `stop` is issued.
 */
void Cl_Record_f(void) {

	if (Cmd_Argc() != 2) {
		Com_Print("Usage: %s <demo name>\n", Cmd_Argv(0));
		return;
	}

	if (cls.demo_file) {
		Com_Print("Already recording.\n");
		return;
	}

	if (cls.state != CL_ACTIVE) {
		Com_Print("You must be in a level to record.\n");
		return;
	}

	// open the demo file
	snprintf(cls.demo_path, sizeof(cls.demo_path), "%s/demos/%s.dem", Fs_Gamedir(), Cmd_Argv(1));

	Fs_CreatePath(cls.demo_path);
	cls.demo_file = fopen(cls.demo_path, "wb");
	if (!cls.demo_file) {
		Com_Warn("Cl_Record_f: couldn't open %s.\n", cls.demo_path);
		return;
	}

	// don't start saving messages until a non-delta compressed message is received
	cls.demo_waiting = true;

	// update user info var to inform server to send angles
	Cvar_ForceSet("recording", "1");

	Com_Print("Requesting demo support from server...\n");
}
Esempio n. 12
0
/*
 * @return The current executable path (argv[0]).
 */
const char *Sys_ExecutablePath(void) {
	static char path[MAX_OS_PATH];

#if defined(__APPLE__)
	uint32_t i = sizeof(path);

	if (_NSGetExecutablePath(path, &i) > -1) {
		return path;
	}

#elif defined(__linux__)

	if (readlink(va("/proc/%d/exe", getpid()), path, sizeof(path)) > -1) {
		return path;
	}

#elif defined(_WIN32)

	if (GetModuleFileName(0, path, sizeof(path))) {
		return path;
	}

#endif

	Com_Warn("Failed to resolve executable path\n");
	return NULL;
}
Esempio n. 13
0
/*
 * Sv_UserStringCommand
 *
 * Invoke the specified user string command.  If we don't have a function for
 * it, pass it off to the game module.
 */
static void Sv_UserStringCommand(const char *s) {
	sv_user_string_cmd_t *c;

	Cmd_TokenizeString(s);

	if (strchr(s, '\xFF')) { // catch end of message exploit
		Com_Warn("Sv_ExecuteUserCommand: Illegal command from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_KickClient(sv_client, NULL);
		return;
	}

	for (c = sv_user_string_cmds; c->name; c++) {

		if (!strcmp(Cmd_Argv(0), c->name)) {
			c->func();
			break;
		}
	}

	if (!c->name) { // unmatched command

		if (sv.state == SV_ACTIVE_GAME) // maybe the game knows what to do with it
			svs.game->ClientCommand(sv_player);
	}
}
Esempio n. 14
0
/**
 * @brief
 */
static void Ms_ParseMessage(struct sockaddr_in *from, char *data) {
	char *cmd = data;
	char *line = data;

	while (*line && *line != '\n') {
		line++;
	}

	*(line++) = '\0';
	cmd += 4;

	if (!g_ascii_strncasecmp(cmd, "ping", 4)) {
		Ms_AddServer(from);
	} else if (!g_ascii_strncasecmp(cmd, "heartbeat", 9) || !g_ascii_strncasecmp(cmd, "print", 5)) {
		Ms_Heartbeat(from);
	} else if (!g_ascii_strncasecmp(cmd, "ack", 3)) {
		Ms_Ack(from);
	} else if (!g_ascii_strncasecmp(cmd, "shutdown", 8)) {
		Ms_RemoveServer(from);
	} else if (!g_ascii_strncasecmp(cmd, "getservers", 10) || !g_ascii_strncasecmp(cmd, "y", 1)) {
		Ms_GetServers(from);
	} else {
		Com_Warn("Unknown command from %s: '%s'", atos(from), cmd);
	}
}
Esempio n. 15
0
/**
 * @brief Binds a linked model to its parent, and copies it into the view structure.
 */
const r_entity_t *R_AddLinkedEntity(const r_entity_t *parent, const r_model_t *model,
                                    const char *tag_name) {

	if (!parent) {
		Com_Warn("NULL parent\n");
		return NULL;
	}

	r_entity_t ent = *parent;

	ent.parent = parent;
	ent.tag_name = tag_name;

	ent.model = model;

	memset(ent.skins, 0, sizeof(ent.skins));
	ent.num_skins = 0;

	ent.frame = ent.old_frame = 0;

	ent.lerp = 1.0;
	ent.back_lerp = 0.0;

	return R_AddEntity(&ent);
}
Esempio n. 16
0
/*
 * @brief
 */
void R_DrawLine(r_pixel_t x1, r_pixel_t y1, r_pixel_t x2, r_pixel_t y2, int32_t c, vec_t a) {
	byte color[4];

	if (a > 1.0) {
		Com_Warn("Bad alpha %f\n", a);
		return;
	}

	if (a < 0.0) { // RGBA integer
		memcpy(color, &c, 4);
	} else { // palette index
		memcpy(color, &img_palette[c], sizeof(color));
		color[3] = a * 255;
	}

	// duplicate color data to all 4 verts
	memcpy(&r_draw.line_arrays.colors[r_draw.line_arrays.color_index + 0], color, 4);
	memcpy(&r_draw.line_arrays.colors[r_draw.line_arrays.color_index + 4], color, 4);

	r_draw.line_arrays.color_index += 8;

	// populate verts
	r_draw.line_arrays.verts[r_draw.line_arrays.vert_index + 0] = x1;
	r_draw.line_arrays.verts[r_draw.line_arrays.vert_index + 1] = y1;

	r_draw.line_arrays.verts[r_draw.line_arrays.vert_index + 2] = x2;
	r_draw.line_arrays.verts[r_draw.line_arrays.vert_index + 3] = y2;

	r_draw.line_arrays.vert_index += 4;
}
Esempio n. 17
0
static void R_LoadHeightmap(const char *name, const SDL_Surface *surf) {
	char heightmap[MAX_QPATH];

	g_strlcpy(heightmap, name, sizeof(heightmap));
	char *c = strrchr(heightmap, '_');
	if (c) {
		*c = '\0';
	}

	SDL_Surface *hsurf;
	if (Img_LoadImage(va("%s_h", heightmap), &hsurf)) {

		if (hsurf->w == surf->w && hsurf->h == surf->h) {
			Com_Debug("Merging heightmap %s\n", heightmap);

			byte *in = hsurf->pixels;
			byte *out = surf->pixels;

			const size_t len = surf->w * surf->h;
			for (size_t i = 0; i < len; i++, in += 4, out += 4) {
				out[3] = (in[0] + in[1] + in[2]) / 3.0;
			}
		} else {
			Com_Warn("Incorrect heightmap resolution for %s\n", name);
		}

		SDL_FreeSurface(hsurf);
	}
}
Esempio n. 18
0
/*
 * @brief Loads all r_bsp_inline_model_t for the specified BSP model. These are
 * later registered as first-class r_model_t's in R_SetupBspInlineModels.
 */
static void R_LoadBspInlineModels(r_bsp_model_t *bsp, const d_bsp_lump_t *l) {
	r_bsp_inline_model_t *out;
	uint16_t i, j;

	const d_bsp_model_t *in = (const void *) (mod_base + l->file_ofs);
	if (l->file_len % sizeof(*in)) {
		Com_Error(ERR_DROP, "Funny lump size\n");
	}

	bsp->num_inline_models = l->file_len / sizeof(*in);
	bsp->inline_models = out = Z_LinkMalloc(bsp->num_inline_models * sizeof(*out), bsp);

	for (i = 0; i < bsp->num_inline_models; i++, in++, out++) {

		for (j = 0; j < 3; j++) { // spread the bounds slightly
			out->mins[j] = LittleFloat(in->mins[j]) - 1.0;
			out->maxs[j] = LittleFloat(in->maxs[j]) + 1.0;

			out->origin[j] = LittleFloat(in->origin[j]);
		}
		out->radius = R_RadiusFromBounds(out->mins, out->maxs);

		out->head_node = LittleLong(in->head_node);

		// some (old) maps have invalid inline model head_nodes
		if (out->head_node < 0 || out->head_node >= bsp->num_nodes) {
			Com_Warn("Bad head_node for %d: %d\n", i, out->head_node);
			out->head_node = -1;
		}

		out->first_surface = (uint16_t) LittleLong(in->first_face);
		out->num_surfaces = (uint16_t) LittleLong(in->num_faces);
	}
}
Esempio n. 19
0
/*
 * @brief Binds the specified font, returning the character width and height.
 */
void R_BindFont(const char *name, r_pixel_t *cw, r_pixel_t *ch) {

	r_draw.font = &r_draw.fonts[1]; // medium is the default font

	if (name) { // try to find it
		uint16_t i;

		for (i = 0; i < r_draw.num_fonts; i++) {
			if (!g_strcmp0(name, r_draw.fonts[i].name)) {
				r_draw.font = &r_draw.fonts[i];
				break;
			}
		}

		if (i == r_draw.num_fonts) {
			Com_Warn("Unknown font: %s\n", name);
		}
	}

	if (cw)
		*cw = r_draw.font->char_width;

	if (ch)
		*ch = r_draw.font->char_height;
}
Esempio n. 20
0
/*
 * Cl_PredictMovement
 *
 * Run the latest movement command through the player movement code locally,
 * using the resulting origin and angles to reduce perceived latency.
 */
void Cl_PredictMovement(void) {
	int i, ack, current;
	pm_move_t pm;
	float step;

	if (cls.state != CL_ACTIVE)
		return;

	if (!cl_predict->value || (cl.frame.ps.pmove.pm_flags & PMF_NO_PREDICTION)) {
		for (i = 0; i < 3; i++) { // just set angles
			cl.predicted_angles[i] = cl.angles[i]
					+ SHORT2ANGLE(cl.frame.ps.pmove.delta_angles[i]);
		}
		return;
	}

	ack = cls.netchan.incoming_acknowledged;
	current = cls.netchan.outgoing_sequence;

	// if we are too far out of date, just freeze
	if (current - ack >= CMD_BACKUP) {
		Com_Warn("Cl_PredictMovement: Exceeded CMD_BACKUP.\n");
		return;
	}

	// copy current state to pmove
	memset(&pm, 0, sizeof(pm));
	pm.Trace = Cl_Trace;
	pm.PointContents = Cl_Pointcontents;
	pm.s = cl.frame.ps.pmove;
	pm.s.gravity = cl_gravity;

	// run frames
	while (++ack <= current) {
		const int frame = ack & CMD_MASK;
		const user_cmd_t *cmd = &cl.cmds[frame];

		if (!cmd->msec)
			continue;

		pm.cmd = *cmd;
		Pmove(&pm);

		// save for debug checking
		VectorCopy(pm.s.origin, cl.predicted_origins[frame]);
	}

	step = pm.s.origin[2] * 0.125 - cl.predicted_origin[2];

	if ((pm.s.pm_flags & PMF_ON_STAIRS) && step > 4.0) { // save for stair lerping
		cl.predicted_step_time = cls.real_time;
		cl.predicted_step = step;
	}

	// copy results out for rendering
	VectorScale(pm.s.origin, 0.125, cl.predicted_origin);
	VectorCopy(pm.angles, cl.predicted_angles);

	cl.underwater = pm.water_level > 2;
}
Esempio n. 21
0
/**
 * @brief record <demo name>
 *
 * Begin recording a demo from the current frame until `stop` is issued.
 */
void Cl_Record_f(void) {

	if (Cmd_Argc() != 2) {
		Com_Print("Usage: %s <demo name>\n", Cmd_Argv(0));
		return;
	}

	if (cls.demo_file) {
		Com_Print("Already recording\n");
		return;
	}

	if (cls.state != CL_ACTIVE) {
		Com_Print("You must be in a level to record\n");
		return;
	}

	g_snprintf(cls.demo_filename, sizeof(cls.demo_filename), "demos/%s.demo", Cmd_Argv(1));

	// open the demo file
	if (!(cls.demo_file = Fs_OpenWrite(cls.demo_filename))) {
		Com_Warn("Couldn't open %s\n", cls.demo_filename);
		return;
	}

	Com_Print("Recording to %s\n", cls.demo_filename);
}
Esempio n. 22
0
/**
 * @brief Send the servers list to the specified client address.
 */
static void Ms_GetServers(struct sockaddr_in *from) {
	mem_buf_t buf;
	byte buffer[0xffff];

	Mem_InitBuffer(&buf, buffer, sizeof(buffer));

	const char *servers = "\xFF\xFF\xFF\xFF" "servers ";
	Mem_WriteBuffer(&buf, servers, strlen(servers));

	uint32_t i = 0;
	GList *s = ms_servers;
	while (s) {
		const ms_server_t *server = (ms_server_t *) s->data;
		if (server->validated) {
			Mem_WriteBuffer(&buf, &server->addr.sin_addr, sizeof(server->addr.sin_addr));
			Mem_WriteBuffer(&buf, &server->addr.sin_port, sizeof(server->addr.sin_port));
			i++;
		}
		s = s->next;
	}

	if ((sendto(ms_sock, buf.data, buf.size, 0, (struct sockaddr *) from, sizeof(*from))) == -1) {
		Com_Warn("%s: %s\n", atos(from), strerror(errno));
	} else {
		Com_Verbose("Sent %d servers to %s\n", i, atos(from));
	}
}
Esempio n. 23
0
/*
 * @brief
 */
void Net_SendPacket(net_src_t source, size_t size, void *data, net_addr_t to) {
	struct sockaddr_in to_addr;
	int32_t sock, ret;

	if (to.type == NA_LOCAL) {
		Net_SendLocalPacket(source, size, data);
		return;
	}

	if (to.type == NA_IP_BROADCAST) {
		sock = ip_sockets[source];
		if (!sock)
			return;
	} else if (to.type == NA_IP) {
		sock = ip_sockets[source];
		if (!sock)
			return;
	} else {
		Com_Error(ERR_DROP, "Bad address type\n");
		return;
	}

	Net_NetAddrToSockaddr(&to, &to_addr);

	ret = sendto(sock, data, size, 0, (struct sockaddr *) &to_addr, sizeof(to_addr));

	if (ret == -1)
		Com_Warn("%s to %s.\n", Net_ErrorString(), Net_NetaddrToString(to));
}
Esempio n. 24
0
/*
 * @brief Searches sv.config_strings from the specified start, searching for the
 * desired name. If not found, the name can be optionally created and sent to
 * all connected clients. This allows the game to lazily load assets.
 */
static uint16_t Sv_FindIndex(const char *name, uint16_t start, uint16_t max, _Bool create) {
	uint16_t i;

	if (!name || !name[0])
		return 0;

	for (i = 0; i < max && sv.config_strings[start + i][0]; i++)
		if (!g_strcmp0(sv.config_strings[start + i], name))
			return i;

	if (!create)
		return 0;

	if (i == max) {
		Com_Warn("Max index for %s reached\n", name);
		return 0;
	}

	g_strlcpy(sv.config_strings[start + i], name, sizeof(sv.config_strings[i]));

	if (sv.state != SV_LOADING) { // send the update to everyone
		Sb_Clear(&sv.multicast);
		Msg_WriteChar(&sv.multicast, SV_CMD_CONFIG_STRING);
		Msg_WriteShort(&sv.multicast, start + i);
		Msg_WriteString(&sv.multicast, name);
		Sv_Multicast(vec3_origin, MULTICAST_ALL_R);
	}

	return i;
}
Esempio n. 25
0
/*
 * Sv_Begin_f
 */
static void Sv_Begin_f(void) {

	Com_Debug("Begin() from %s\n", Sv_NetaddrToString(sv_client));

	if (sv_client->state != SV_CLIENT_CONNECTED) { // catch duplicate spawns
		Com_Warn("Sv_Begin_f: Invalid Begin() from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_KickClient(sv_client, NULL);
		return;
	}

	if (sv.state == SV_ACTIVE_DEMO)
		return;

	// handle the case of a level changing while a client was connecting
	if (strtoul(Cmd_Argv(1), NULL, 0) != svs.spawn_count) {
		Com_Debug("Sv_Begin_f: Stale spawn count from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_New_f();
		return;
	}

	sv_client->state = SV_CLIENT_ACTIVE;

	// call the game begin function
	svs.game->ClientBegin(sv_player);

	Cbuf_InsertFromDefer();
}
Esempio n. 26
0
/*
 * @brief
 */
static void Ms_SendServersList(struct sockaddr_in *from) {
	int32_t buflen;
	char buff[0xffff];

	buflen = 0;
	memset(buff, 0, sizeof(buff));

	memcpy(buff, "\xFF\xFF\xFF\xFF""servers ", 12);
	buflen += 12;

	GList *s = ms_servers;
	while (s) {
		const ms_server_t *server = (ms_server_t *) s->data;
		if (server->validated) {
			memcpy(buff + buflen, &server->ip.sin_addr, 4);
			buflen += 4;
			memcpy(buff + buflen, &server->port, 2);
			buflen += 2;
		}
		s = s->next;
	}

	if ((sendto(ms_sock, buff, buflen, 0, (struct sockaddr *) from, sizeof(*from))) == -1)
		Com_Warn("Socket error on send: %s.\n", strerror(errno));
	else
		Com_Print("Sent server list to %s\n", inet_ntoa(from->sin_addr));
}
Esempio n. 27
0
/*
 * @brief
 */
static void Cm_DecompressVis(const byte *in, byte *out) {

	const int32_t row = (cm_vis->num_clusters + 7) >> 3;
	byte *out_p = out;

	if (!in || !cm_bsp.num_visibility) { // no vis info, so make all visible
		for (int32_t i = 0; i < row; i++) {
			*out_p++ = 0xff;
		}
	} else {
		do {
			if (*in) {
				*out_p++ = *in++;
				continue;
			}

			int32_t c = in[1];
			in += 2;
			if ((out_p - out) + c > row) {
				c = row - (out_p - out);
				Com_Warn("Overrun\n");
			}
			while (c) {
				*out_p++ = 0;
				c--;
			}
		} while (out_p - out < row);
	}
}
Esempio n. 28
0
/**
 * @brief Upload data to a sub-position in already-created buffer. You could also use this function to
 * resize an existing buffer without uploading data, although it won't make the
 * buffer smaller.
 * @param data_offset Whether the data pointer should be offset by start or not.
 */
void R_UploadToSubBuffer(r_buffer_t *buffer, const size_t start, const size_t size, const void *data,
                         const _Bool data_offset) {

	assert(buffer->bufnum != 0);

	// Check size. This is benign really, but it's usually a bug.
	if (!size) {
		Com_Warn("Attempted to upload 0 bytes to GPU\n");
		return;
	}

	// Don't allow null ptrs since bufferSubData does not allow it.
	if (!data) {
		Com_Error(ERROR_DROP, "Fatal: attempted to upload null to GPU. bufferSubData does not allow this.\n");
	}

	// offset ptr if requested
	if (start && data && data_offset) {
		data += start;
	}

	R_BindBuffer(buffer);

	// if the buffer isn't big enough to hold what we had already,
	// we have to resize the buffer
	const size_t total_size = start + size;

	if (total_size > buffer->size) {
		// if we passed a "start", the data is offset, so
		// just reset to null. This is an odd edge case and
		// it's fairly rare you'll be editing at the end first,
		// but who knows.
		if (start) {

			glBufferData(buffer->target, total_size, NULL, buffer->hint);
			R_GetError("Partial resize");
			r_view.buffer_stats[buffer->type].num_full_uploads++;
			glBufferSubData(buffer->target, start, size, data);
			R_GetError("Partial update");
			r_view.buffer_stats[buffer->type].num_partial_uploads++;
		} else {
			glBufferData(buffer->target, total_size, data, buffer->hint);
			R_GetError("Full resize");
			r_view.buffer_stats[buffer->type].num_full_uploads++;
		}

		r_state.buffers_total_bytes -= buffer->size;
		r_state.buffers_total_bytes += total_size;

		buffer->size = total_size;
	} else {
		// just update the range we specified
		glBufferSubData(buffer->target, start, size, data);
		R_GetError("Updating existing buffer");
		r_view.buffer_stats[buffer->type].num_partial_uploads++;
	}

	r_view.buffer_stats[buffer->type].size_uploaded += size;
}
Esempio n. 29
0
/*
 * @brief
 */
void Cl_ParseServers(void) {
	cl_server_info_t *server;

	byte *buffptr = net_message.data + 12;
	byte *buffend = buffptr + net_message.size - 12;

	// parse the list
	while (buffptr + 1 < buffend) {
		net_addr_t addr;
		byte ip[4];

		ip[0] = *buffptr++; // parse the address
		ip[1] = *buffptr++;
		ip[2] = *buffptr++;
		ip[3] = *buffptr++;

		uint16_t port = (*buffptr++) << 8; // and the port
		port += *buffptr++;

		char s[32];
		g_snprintf(s, sizeof(s), "%d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], port);

		Com_Debug("Parsed %s\n", s);

		if (!Net_StringToNetaddr(s, &addr)) { // make sure it's valid
			Com_Warn("Invalid address: %s\n", s);
			break;
		}

		if (!addr.port) // 0's mean we're done
			break;

		server = Cl_ServerForNetaddr(&addr);

		if (!server)
			server = Cl_AddServer(&addr);

		server->source = SERVER_SOURCE_INTERNET;
	}

	net_message.read = net_message.size;

	// then ping them

	GList *e = cls.servers;

	while (e) {
		server = (cl_server_info_t *) e->data;

		if (server->source == SERVER_SOURCE_INTERNET) {
			server->ping_time = cls.real_time;
			server->ping = 0;

			Netchan_OutOfBandPrint(NS_UDP_CLIENT, &server->addr, "info %i", PROTOCOL_MAJOR);
		}

		e = e->next;
	}
}
Esempio n. 30
0
/*
 * Cl_ParseServersList
 */
void Cl_ParseServersList(void) {
	byte *buffptr;
	byte *buffend;
	byte ip[4];
	unsigned short port;
	net_addr_t addr;
	cl_server_info_t *server;
	char s[32];

	buffptr = net_message.data + 12;
	buffend = buffptr + net_message.size - 12;

	// parse the list
	while (buffptr + 1 < buffend) {

		ip[0] = *buffptr++; // parse the address
		ip[1] = *buffptr++;
		ip[2] = *buffptr++;
		ip[3] = *buffptr++;

		port = (*buffptr++) << 8; // and the port
		port += *buffptr++;

		snprintf(s, sizeof(s), "%d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], port);

		if (!Net_StringToNetaddr(s, &addr)) { // make sure it's valid
			Com_Warn("Cl_ParseServersList: Invalid address: %s.\n", s);
			break;
		}

		if (!addr.port) // 0's mean we're done
			break;

		server = Cl_ServerForNetaddr(&addr);

		if (!server)
			server = Cl_AddServer(&addr);

		server->source = SERVER_SOURCE_INTERNET;
	}

	net_message.read = net_message.size;

	// then ping them
	server = cls.servers;

	while (server) {

		if (server->source == SERVER_SOURCE_INTERNET) {
			server->ping_time = cls.real_time;
			server->ping = 0;

			Netchan_OutOfBandPrint(NS_CLIENT, server->addr, "info %i", PROTOCOL);
		}

		server = server->next;
	}
}