Ejemplo n.º 1
0
/**
 * @brief Add a callback of a function into a node event. There can be more than on listener.
 * @param[in,out] node The node to add the listener to.
 * @param[in] property The property of the node to add the listener to.
 * @param[in] functionNode The node of the listener callback.
 */
void UI_AddListener (uiNode_t *node, const value_t *property, const uiNode_t *functionNode)
{
	if (node->dynamic) {
		Com_Printf("UI_AddListener: '%s' is a dynamic node. We can't listen it.\n", UI_GetPath(node));
		return;
	}
	if (functionNode->dynamic) {
		Com_Printf("UI_AddListener: '%s' is a dynamic node. It can't be a listener callback.\n", UI_GetPath(functionNode));
		return;
	}

	/* create the call action */
	uiAction_t* const action = Mem_PoolAllocType(uiAction_t, ui_sysPool);
	uiAction_t* const value  = Mem_PoolAllocType(uiAction_t, ui_sysPool);
	value->d.terminal.d1.constString = Mem_PoolStrDup(UI_GetPath(functionNode), ui_sysPool, 0);
	value->next = NULL;
	action->type = EA_LISTENER;
	action->d.nonTerminal.left = value;
	/** @todo It is a hack, we should remove that */
	action->d.terminal.d2.constData = &functionNode->onClick;
	action->next = NULL;

	/* insert the action */
	uiAction_t** anchor = &Com_GetValue<uiAction_t*>(node, property);
	while (*anchor)
		anchor = &(*anchor)->next;
	*anchor = action;
}
Ejemplo n.º 2
0
static linkedList_t *LIST_AllocateEntry(void* const data, linkedList_t* const next = 0)
{
	linkedList_t* const e = Mem_PoolAllocType(linkedList_t, com_genericPool);
	e->data = data;
	e->next = next;
	return e;
}
Ejemplo n.º 3
0
static void UI_MaterialEditorNewStage_f (void)
{
	material_t* m;
	int id;

	if (Cmd_Argc() < 2) {
		Com_Printf("Usage: %s <image index>\n", Cmd_Argv(0));
		return;
	}

	id = atoi(Cmd_Argv(1));
	if (id < 0 || id >= r_numImages) {
		Com_Printf("Given image index (%i) is out of bounds\n", id);
		return;
	}

	m = &R_GetImageAtIndex(id)->material;
	materialStage_t* const s = Mem_PoolAllocType(materialStage_t, vid_imagePool);
	m->num_stages++;

	/* append the stage to the chain */
	if (!m->stages)
		m->stages = s;
	else {
		materialStage_t* ss = m->stages;
		while (ss->next)
			ss = ss->next;
		ss->next = s;
	}

	UI_MaterialEditorUpdate(R_GetImageAtIndex(id), s);
}
Ejemplo n.º 4
0
/**
 * @brief Loads and registers a sound file for later use
 * @param[in] soundFile The name of the soundfile, relative to the sounds dir
 * @return The index of the loaded sample or 0
 * @sa S_LoadSound
 */
int S_LoadSampleIdx (const char* soundFile)
{
	Mix_Chunk* chunk;
	char name[MAX_QPATH];
	unsigned hash;

	if (!s_env.initialized)
		return 0;

	Com_StripExtension(soundFile, name, sizeof(name));

	if (s_sample_t* const sample = S_FindByName(name))
		return sample->index;

	/* make sure the sound is loaded */
	chunk = S_LoadSampleChunk(name);
	if (!chunk)
		return 0;		/* couldn't load the sound's data */

	hash = Com_HashKey(name, SAMPLE_HASH_SIZE);
	s_sample_t* const sample = Mem_PoolAllocType(s_sample_t, cl_soundSysPool);
	sample->name = Mem_PoolStrDup(name, cl_soundSysPool, 0);
	sample->chunk = chunk;
	sample->hashNext = sampleHash[hash];
	sampleHash[hash] = sample;
	sampleIndex[++sampleIndexLast] = sample;
	sample->index = sampleIndexLast;
	return sample->index;
}
Ejemplo n.º 5
0
/**
 * @brief Init or return a cvar
 * @param[in] var_name The cvar name
 * @param[in] var_value The standard cvar value (will be set if the cvar doesn't exist)
 * @param[in] flags CVAR_USERINFO, CVAR_LATCH, CVAR_SERVERINFO, CVAR_ARCHIVE and so on
 * @param[in] desc This is a short description of the cvar (see console command cvarlist)
 * @note CVAR_ARCHIVE: Cvar will be saved to config.cfg when game shuts down - and
 * will be reloaded when game starts up the next time
 * @note CVAR_LATCH: Latched cvars will be updated at the next map load
 * @note CVAR_SERVERINFO: This cvar will be send in the server info response strings (server browser)
 * @note CVAR_NOSET: This cvar can not be set from the commandline
 * @note CVAR_USERINFO: This cvar will be added to the userinfo string when changed (network synced)
 * @note CVAR_DEVELOPER: Only changeable if we are in development mode
 * If the variable already exists, the value will not be set
 * The flags will be or'ed in if the variable exists.
 */
cvar_t* Cvar_GetOrCreate (const char* var_name, const char* var_value, int flags, const char* desc)
{
	const unsigned hash = Com_HashKey(var_name, CVAR_HASH_SIZE);

	if (flags & (CVAR_USERINFO | CVAR_SERVERINFO)) {
		if (!Cvar_InfoValidate(var_name)) {
			Com_Printf("invalid info cvar name\n");
			return nullptr;
		}
	}

	if (cvar_t* const var = Cvar_FindVar(var_name)) {
		if (!var->defaultString && (flags & CVAR_CHEAT))
			var->defaultString = Mem_PoolStrDup(var_value, com_cvarSysPool, 0);
		var->flags |= flags;
		if (desc) {
			Mem_Free(var->description);
			var->description = Mem_PoolStrDup(desc, com_cvarSysPool, 0);
		}
		return var;
	}

	if (!var_value)
		return nullptr;

	if (flags & (CVAR_USERINFO | CVAR_SERVERINFO)) {
		if (!Cvar_InfoValidate(var_value)) {
			Com_Printf("invalid info cvar value '%s' of cvar '%s'\n", var_value, var_name);
			return nullptr;
		}
	}

	cvar_t* const var = Mem_PoolAllocType(cvar_t, com_cvarSysPool);
	var->name = Mem_PoolStrDup(var_name, com_cvarSysPool, 0);
	var->string = Mem_PoolStrDup(var_value, com_cvarSysPool, 0);
	var->oldString = nullptr;
	var->modified = true;
	var->value = atof(var->string);
	var->integer = atoi(var->string);
	if (desc)
		var->description = Mem_PoolStrDup(desc, com_cvarSysPool, 0);

	HASH_Add(cvarVarsHash, var, hash);
	/* link the variable in */
	var->next = cvarVars;
	cvarVars = var;
	if (var->next)
		var->next->prev = var;

	var->flags = flags;
	if (var->flags & CVAR_CHEAT)
		var->defaultString = Mem_PoolStrDup(var_value, com_cvarSysPool, 0);

	for (CvarListeners::iterator i = cvarListeners.begin(); i != cvarListeners.end(); ++i) {
		(*i)->onCreate(var);
	}

	return var;
}
Ejemplo n.º 6
0
/**
 * @sa NET_DatagramSocketNew
 */
static struct datagram_socket* NET_DatagramSocketDoNew (const struct addrinfo* addr)
{
	SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
	int t = 1;
	const int index = NET_DatagramFindFreeSocket();

	if (index == -1) {
		Com_Printf("Too many datagram sockets open\n");
		return nullptr;
	}

	if (sock == INVALID_SOCKET) {
		Com_Printf("Failed to create socket: %s\n", netStringError(netError));
		return nullptr;
	}

	if (!NET_SocketSetNonBlocking(sock)) {
		netCloseSocket(sock);
		return nullptr;
	}

	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &t, sizeof(t)) != 0) {
		Com_Printf("Failed to set SO_REUSEADDR on socket: %s\n", netStringError(netError));
		netCloseSocket(sock);
		return nullptr;
	}

	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(t)) != 0) {
		Com_Printf("Failed to set SO_BROADCAST on socket: %s\n", netStringError(netError));
		netCloseSocket(sock);
		return nullptr;
	}

	if (bind(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
		Com_Printf("Failed to bind socket: %s\n", netStringError(netError));
		netCloseSocket(sock);
		return nullptr;
	}

	maxfd = std::max(sock + 1, maxfd);
	FD_SET(sock, &read_fds);

	datagram_socket* const s = Mem_PoolAllocType(datagram_socket, com_networkPool);
	s->family = addr->ai_family;
	s->addrlen = addr->ai_addrlen;
	s->socket = sock;
	s->index = index;
	s->queue = nullptr;
	s->queue_tail = &s->queue;
	s->func = nullptr;
	datagram_sockets[index] = s;

	return s;
}
Ejemplo n.º 7
0
/**
 * @brief Reorders all surfaces arrays for the specified model, grouping the surface
 * pointers by texture.  This dramatically reduces glBindTexture calls.
 */
static void R_SortSurfacesArrays (const model_t *mod)
{
	const mBspSurface_t *surf, *s;
	int i, ns;
	mBspSurfaces_t **r_sorted_surfaces = Mem_AllocTypeN(mBspSurfaces_t *, r_numImages);

	/* resolve the start surface and total surface count */
	s = &mod->bsp.surfaces[mod->bsp.firstmodelsurface];
	ns = mod->bsp.nummodelsurfaces;

	/* allocate the per-texture surfaces arrays and determine counts */
	for (i = 0, surf = s; i < ns; i++, surf++) {
		int index = R_GetImageIndex(surf->texinfo->image);
		mBspSurfaces_t *surfs = r_sorted_surfaces[index];
		if (!surfs) {  /* allocate it */
			surfs = Mem_PoolAllocType(mBspSurfaces_t, vid_modelPool);
			r_sorted_surfaces[index] = surfs;
		}

		surfs->count++;
	}

	/* allocate the surfaces pointers based on counts */
	for (i = 0; i < r_numImages; i++) {
		mBspSurfaces_t *surfs = r_sorted_surfaces[i];
		if (surfs) {
			surfs->surfaces = Mem_PoolAllocTypeN(mBspSurface_t*, surfs->count, vid_modelPool);
			surfs->count = 0;
		}
	}

	/* sort the model's surfaces arrays into the per-texture arrays */
	for (i = 0; i < NUM_SURFACES_ARRAYS; i++) {
		if (mod->bsp.sorted_surfaces[i]->count) {
			R_SortSurfacesArrays_(mod->bsp.sorted_surfaces[i], r_sorted_surfaces);
			Com_DPrintf(DEBUG_RENDERER, "%i: #%i surfaces\n", i, mod->bsp.sorted_surfaces[i]->count);
		}
	}

	/* free the per-texture surfaces arrays */
	for (i = 0; i < r_numImages; i++) {
		mBspSurfaces_t *surfs = r_sorted_surfaces[i];
		if (surfs) {
			Mem_Free(surfs->surfaces);
			Mem_Free(surfs);
		}
	}

	Mem_Free(r_sorted_surfaces);
}
Ejemplo n.º 8
0
/**
 * @brief Set a new action to a @c uiAction_t pointer
 * @param[in,out] action Allocated action
 * @param[in] type Only @c EA_CMD is supported
 * @param[in] data The data for this action - in case of @c EA_CMD this is the commandline
 * @note You first have to free existing node actions - only free those that are
 * not static in @c ui_global.actions array
 * @todo we should create a function to free the memory. We can use a tag in the Mem_PoolAlloc
 * calls and use use Mem_FreeTag.
 */
void UI_PoolAllocAction (uiAction_t** action, int type, const void *data)
{
	if (*action)
		Com_Error(ERR_FATAL, "There is already an action assigned");
	*action = Mem_PoolAllocType(uiAction_t, ui_sysPool);
	(*action)->type = type;
	switch (type) {
	case EA_CMD:
		(*action)->d.terminal.d1.constString = Mem_PoolStrDup((const char *)data, ui_sysPool, 0);
		break;
	default:
		Com_Error(ERR_FATAL, "Action type %i is not yet implemented", type);
	}
}
Ejemplo n.º 9
0
static void R_LoadSurfacesArrays_ (model_t *mod)
{
	mBspSurface_t *surf, *s;
	int i, ns;

	/* allocate the surfaces array structures */
	/** @todo only one allocation should be used here - allocate the whole array with one Mem_PoolAlloc call */
	for (i = 0; i < NUM_SURFACES_ARRAYS; i++)
		mod->bsp.sorted_surfaces[i] = Mem_PoolAllocType(mBspSurfaces_t, vid_modelPool);

	/* resolve the start surface and total surface count */
	s = &mod->bsp.surfaces[mod->bsp.firstmodelsurface];
	ns = mod->bsp.nummodelsurfaces;

	/* determine the maximum counts for each rendered type in order to
	 * allocate only what is necessary for the specified model */
	for (i = 0, surf = s; i < ns; i++, surf++) {
		const mBspTexInfo_t *texinfo = surf->texinfo;
		const material_t *material = &texinfo->image->material;
		if (texinfo->flags & (SURF_BLEND33 | SURF_BLEND66)) {
			if (texinfo->flags & SURF_WARP)
				mod->bsp.blend_warp_surfaces->count++;
			else
				mod->bsp.blend_surfaces->count++;
		} else {
			if (texinfo->flags & SURF_WARP)
				mod->bsp.opaque_warp_surfaces->count++;
			else if (texinfo->flags & SURF_ALPHATEST)
				mod->bsp.alpha_test_surfaces->count++;
			else
				mod->bsp.opaque_surfaces->count++;
		}

		if (material->flags & STAGE_RENDER)
			mod->bsp.material_surfaces->count++;

		if (material->flags & STAGE_FLARE)
			mod->bsp.flare_surfaces->count++;
	}

	/* allocate the surfaces pointers based on the counts */
	for (i = 0; i < NUM_SURFACES_ARRAYS; i++) {
		mBspSurfaces_t *surfaces = mod->bsp.sorted_surfaces[i];
		if (surfaces->count) {
			surfaces->surfaces = Mem_PoolAllocTypeN(mBspSurface_t*, surfaces->count, vid_modelPool);
			surfaces->count = 0;
		}
	}
Ejemplo n.º 10
0
/**
 * @brief Append a new mapname to the list of maps for the cycle
 * @todo check for maps and valid gametypes here
 * @sa SV_MapcycleClear
 */
static void SV_MapcycleAdd (const char *mapName, bool day, const char *gameType)
{
	mapcycle_t* const mapcycle = Mem_PoolAllocType(mapcycle_t, sv_genericPool);
	mapcycle->map  = Mem_PoolStrDup(mapName, sv_genericPool, 0);
	mapcycle->day  = day;
	mapcycle->type = Mem_PoolStrDup(gameType, sv_genericPool, 0);
	mapcycle->next = 0;
	Com_DPrintf(DEBUG_SERVER, "mapcycle add: '%s' type '%s'\n", mapcycle->map, mapcycle->type);

	/* Append to end of list. */
	mapcycle_t **anchor = &mapcycleList;
	while (*anchor) anchor = &(*anchor)->next;
	*anchor = mapcycle;

	++mapcycleCount;
}
Ejemplo n.º 11
0
/**
 * @sa NET_DatagramSocketNew
 */
void NET_DatagramSend (struct datagram_socket* s, const char* buf, int len, struct sockaddr* to)
{
	if (!s || len <= 0 || !buf || !to)
		return;

	datagram* const dgram = Mem_PoolAllocType(datagram, com_networkPool);
	dgram->msg  = Mem_PoolAllocTypeN(char, len,        com_networkPool);
	dgram->addr = Mem_PoolAllocTypeN(char, s->addrlen, com_networkPool);
	memcpy(dgram->msg, buf, len);
	memcpy(dgram->addr, to, len);
	dgram->len = len;
	dgram->next = nullptr;

	*s->queue_tail = dgram;
	s->queue_tail = &dgram->next;

	FD_SET(s->socket, &write_fds);
}
Ejemplo n.º 12
0
/**
 * @brief Add a node to the child index
 */
bool UI_WindowNodeAddIndexedNode (uiNode_t* const node, uiNode_t* const child)
{
	node_index_t* a;
	unsigned int hash = Com_HashKey(child->name, INDEXEDCHILD_HASH_SIZE);
	for (a = EXTRADATA(node).index_hash[hash]; a; a = a->hash_next) {
		if (Q_streq(child->name, a->node->name)) {
			/** @todo display a warning, we must not override a node name here */
			break;
		}
	}

	if (!a) {
		a = Mem_PoolAllocType(node_index_t, ui_sysPool);
		a->next = EXTRADATA(node).index;
		a->hash_next = EXTRADATA(node).index_hash[hash];
		EXTRADATA(node).index_hash[hash] = a;
		EXTRADATA(node).index = a;
	}

	return false;
}
Ejemplo n.º 13
0
/**
 * @sa NET_StreamGetFree
 * @sa NET_StreamClose
 */
static struct net_stream* NET_StreamNew (int index)
{
	net_stream* const s = Mem_PoolAllocType(net_stream, com_networkPool);
	s->data = nullptr;
	s->loopback_peer = nullptr;
	s->loopback = false;
	s->closed = false;
	s->finished = false;
	s->ready = false;
	s->socket = INVALID_SOCKET;
	s->inbound = dbufferptr();
	s->outbound = dbufferptr();
	s->index = index;
	s->family = 0;
	s->addrlen = 0;
	s->func = nullptr;
	if (streams[index])
		NET_StreamFree(streams[index]);
	streams[index] = s;
	return s;
}
Ejemplo n.º 14
0
void R_CreateSurfaceFlare (mBspSurface_t* surf)
{
	material_t* m;
	const materialStage_t* s;
	vec3_t span;

	m = &surf->texinfo->image->material;

	if (!(m->flags & STAGE_FLARE)) /* surface is not flared */
		return;

	surf->flare = Mem_PoolAllocType(mBspFlare_t, vid_modelPool);

	/* move the flare away from the surface, into the level */
	VectorMA(surf->center, 2, surf->normal, surf->flare->origin);

	/* calculate the flare radius based on surface size */
	VectorSubtract(surf->maxs, surf->mins, span);
	surf->flare->radius = VectorLength(span);

	s = m->stages; /* resolve the flare stage */
	for (;;) {
		if (s->flags & STAGE_FLARE)
			break;
		s = s->next;
	}

	/* resolve flare color */
	if (s->flags & STAGE_COLOR)
		VectorCopy(s->color, surf->flare->color);
	else
		VectorCopy(surf->lightColor, surf->flare->color);

	/* and scaled radius */
	if (s->flags & (STAGE_SCALE_S | STAGE_SCALE_T))
		surf->flare->radius *= (s->scale.s ? s->scale.s : s->scale.t);

	/* and image */
	surf->flare->image = s->image;
}
Ejemplo n.º 15
0
/**
 * @brief Only called once at startup, not for each game
 */
void SV_Init (void)
{
	Com_Printf("\n------ server initialization -------\n");

	sv_genericPool = Mem_CreatePool("Server: Generic");

	OBJZERO(svs);

	sv = Mem_PoolAllocType(serverInstanceGame_t, sv_genericPool);

	SV_InitOperatorCommands();

	rcon_password = Cvar_Get("rcon_password", "", CVAR_ARCHIVE);
	Cvar_Get("sv_cheats", "0", CVAR_SERVERINFO | CVAR_LATCH);
	Cvar_Get("sv_protocol", DOUBLEQUOTE(PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_NOSET);
	/* this cvar will become a latched cvar when you start the server */
	sv_maxclients = Cvar_Get("sv_maxclients", "1", CVAR_SERVERINFO, "Max. connected clients");
	sv_hostname = Cvar_Get("sv_hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE, "The name of the server that is displayed in the serverlist");
	sv_http_downloadserver = Cvar_Get("sv_http_downloadserver", "", CVAR_ARCHIVE, "URL to a location where clients can download game content over HTTP");
	sv_enablemorale = Cvar_Get("sv_enablemorale", "1", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_LATCH, "Enable morale changes in multiplayer");
	sv_maxsoldiersperteam = Cvar_Get("sv_maxsoldiersperteam", "4", CVAR_ARCHIVE | CVAR_SERVERINFO, "Max. amount of soldiers per team (see sv_maxsoldiersperplayer and sv_teamplay)");
	sv_maxsoldiersperplayer = Cvar_Get("sv_maxsoldiersperplayer", STRINGIFY(MAX_ACTIVETEAM), CVAR_ARCHIVE | CVAR_SERVERINFO, "Max. amount of soldiers each player can control (see maxsoldiers and sv_teamplay)");
	Cvar_SetCheckFunction("sv_maxsoldiersperplayer", SV_CheckMaxSoldiersPerPlayer);

	sv_dumpmapassembly = Cvar_Get("sv_dumpmapassembly", "0", CVAR_ARCHIVE, "Dump map assembly information to game console");

	sv_threads = Cvar_Get("sv_threads", "1", CVAR_LATCH | CVAR_ARCHIVE, "Run the server threaded");
	sv_rma = Cvar_Get("sv_rma", "2", 0, "1 = old algorithm, 2 = new algorithm");
	sv_rmadisplaythemap = Cvar_Get("sv_rmadisplaythemap", "0", 0, "Activate rma problem output");
	sv_public = Cvar_Get("sv_public", "1", 0, "Should heartbeats be send to the masterserver");
	sv_reconnect_limit = Cvar_Get("sv_reconnect_limit", "3", CVAR_ARCHIVE, "Minimum seconds between connect messages");
	sv_timeout = Cvar_Get("sv_timeout", "20", CVAR_ARCHIVE, "Seconds until a client times out");

	SV_MapcycleInit();
	SV_LogInit();
}
Ejemplo n.º 16
0
/**
 * @brief Parse all language definitions from the script files
 */
void CL_ParseLanguages (const char* name, const char** text)
{
	const char* errhead = "CL_ParseLanguages: unexpected end of file (language ";
	const char* token;

	if (!*text) {
		Com_Printf("CL_ParseLanguages: language without body ignored (%s)\n", name);
		return;
	}

	token = Com_EParse(text, errhead, name);
	if (!*text || *token != '{') {
		Com_Printf("CL_ParseLanguages: language without body ignored (%s)\n", name);
		return;
	}

	language_t* const language = Mem_PoolAllocType(language_t, cl_genericPool);
	language->localeID = Mem_PoolStrDup(name, cl_genericPool, 0);
	language->localeString = "";
	language->nativeString = "";
	language->localeMapping = nullptr;

	do {
		/* get the name type */
		token = Com_EParse(text, errhead, name);
		if (!*text || *token == '}')
			break;
		/* inner locale id definition */
		if (Q_streq(token, "code")) {
			linkedList_t* list;
			if (!Com_ParseList(text, &list)) {
				Com_Error(ERR_DROP, "CL_ParseLanguages: error while reading language codes \"%s\"", name);
			}
			for (linkedList_t* element = list; element != nullptr; element = element->next) {
				localeMapping_t* const mapping = Mem_PoolAllocType(localeMapping_t, cl_genericPool);
				mapping->localeMapping = Mem_PoolStrDup((char*)element->data, cl_genericPool, 0);
				/* link it in */
				mapping->next = language->localeMapping;
				language->localeMapping = mapping;
			}
			LIST_Delete(&list);
		} else if (Q_streq(token, "name")) {
			token = Com_EParse(text, errhead, name);
			if (!*text || *token == '}')
				Com_Error(ERR_FATAL, "CL_ParseLanguages: Name expected for language \"%s\".\n", name);
			if (*token != '_') {
				Com_Printf("CL_ParseLanguages: language: '%s' - not marked translatable (%s)\n", name, token);
			}
			language->localeString = Mem_PoolStrDup(token, cl_genericPool, 0);
		} else if (Q_streq(token, "native")) {
			token = Com_EParse(text, errhead, name);
			if (!*text || *token == '}')
				Com_Error(ERR_FATAL, "CL_ParseLanguages: Native expected for language \"%s\".\n", name);
			language->nativeString = Mem_PoolStrDup(token, cl_genericPool, 0);
		}
	} while (*text);

	language->next = languageList;
	languageList = language;
	languageCount++;
}
Ejemplo n.º 17
0
/**
 * @todo need to merge UI model case, and the common case (looks to be a copy-pasted code)
 */
void UI_DrawModelNode (uiNode_t* node, const char* source)
{
	modelInfo_t mi;
	uiModel_t* model;
	vec3_t nodeorigin;
	vec2_t screenPos;

	assert(UI_NodeInstanceOf(node, "model"));			/**< We use model extradata */

	if (!source || source[0] == '\0')
		return;

	model = UI_GetUIModel(source);
	/* direct model name - no UI model definition */
	if (!model) {
		/* prevent the searching for a model def in the next frame */
		mi.model = R_FindModel(source);
		mi.name = source;
		if (!mi.model) {
			Com_Printf("Could not find model '%s'\n", source);
			return;
		}
	}

	/* compute the absolute origin ('origin' property is relative to the node center) */
	UI_GetNodeScreenPos(node, screenPos);
	UI_GetNodeAbsPos(node, nodeorigin);
	R_CleanupDepthBuffer(nodeorigin[0], nodeorigin[1], node->box.size[0], node->box.size[1]);
	if (EXTRADATA(node).clipOverflow) {
		UI_PushClipRect(screenPos[0], screenPos[1], node->box.size[0], node->box.size[1]);
	}
	nodeorigin[0] += node->box.size[0] / 2 + EXTRADATA(node).origin[0];
	nodeorigin[1] += node->box.size[1] / 2 + EXTRADATA(node).origin[1];
	nodeorigin[2] = EXTRADATA(node).origin[2];

	VectorMA(EXTRADATA(node).angles, cls.frametime, EXTRADATA(node).omega, EXTRADATA(node).angles);
	mi.origin = nodeorigin;
	mi.angles = EXTRADATA(node).angles;
	mi.scale = EXTRADATA(node).scale;
	mi.center = nullVector;
	mi.color = node->color;
	mi.mesh = 0;

	/* special case to draw models with UI model */
	if (model) {
		UI_DrawModelNodeWithUIModel(node, source, &mi, model);
		if (EXTRADATA(node).clipOverflow)
			UI_PopClipRect();
		return;
	}

	/* if the node is linked to a parent, the parent will display it */
	if (EXTRADATA(node).tag) {
		if (EXTRADATA(node).clipOverflow)
			UI_PopClipRect();
		return;
	}

	/* autoscale? */
	if (EXTRADATA(node).autoscale) {
		vec3_t autoScale;
		vec3_t autoCenter;
		const vec2_t size = {node->box.size[0] - node->padding, node->box.size[1] - node->padding};
		R_ModelAutoScale(size, &mi, autoScale, autoCenter);
	}

	/* no animation */
	mi.frame = 0;
	mi.oldframe = 0;
	mi.backlerp = 0;

	/* get skin */
	if (EXTRADATA(node).skin && *EXTRADATA(node).skin)
		mi.skin = atoi(UI_GetReferenceString(node, EXTRADATA(node).skin));
	else
		mi.skin = 0;

	/* do animations */
	if (EXTRADATA(node).animation && *EXTRADATA(node).animation) {
		const char* ref;
		ref = UI_GetReferenceString(node, EXTRADATA(node).animation);

		/* check whether the cvar value changed */
		if (strncmp(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE)) {
			Q_strncpyz(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE);
			/* model has changed but mem is already reserved in pool */
			Mem_Free(EXTRADATA(node).animationState);
			EXTRADATA(node).animationState = nullptr;
		}
		animState_t* as = EXTRADATA(node).animationState;
		if (!as) {
			as = Mem_PoolAllocType(animState_t, cl_genericPool);
			if (!as)
				Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", mi.name, ref);
			R_AnimChange(as, mi.model, ref);
			EXTRADATA(node).animationState = as;
		} else {
			const char* anim;
			/* change anim if needed */
			anim = R_AnimGetName(as, mi.model);
			if (anim && !Q_streq(anim, ref))
				R_AnimChange(as, mi.model, ref);
			R_AnimRun(as, mi.model, cls.frametime * 1000);
		}

		mi.frame = as->frame;
		mi.oldframe = as->oldframe;
		mi.backlerp = as->backlerp;
	}

	/* draw the main model on the node */
	R_DrawModelDirect(&mi, nullptr, nullptr);

	/* draw all children */
	if (node->firstChild) {
		uiNode_t* child;
		modelInfo_t pmi = mi;
		for (child = node->firstChild; child; child = child->next) {
			const char* tag;
			char childSource[MAX_VAR];
			const char* childRef;

			/* skip non "model" nodes */
			if (child->behaviour != node->behaviour)
				continue;

			/* skip invisible child */
			if (child->invis || !UI_CheckVisibility(child))
				continue;

			OBJZERO(mi);
			mi.angles = EXTRADATA(child).angles;
			mi.scale = EXTRADATA(child).scale;
			mi.center = nullVector;
			mi.origin = EXTRADATA(child).origin;
			mi.color = pmi.color;

			/* get the anchor name to link the model into the parent */
			tag = EXTRADATA(child).tag;

			/* init model name */
			childRef = UI_GetReferenceString(child, EXTRADATA(child).model);
			if (Q_strnull(childRef))
				childSource[0] = '\0';
			else
				Q_strncpyz(childSource, childRef, sizeof(childSource));
			mi.model = R_FindModel(childSource);
			mi.name = childSource;

			/* init skin */
			if (EXTRADATA(child).skin && *EXTRADATA(child).skin)
				mi.skin = atoi(UI_GetReferenceString(child, EXTRADATA(child).skin));
			else
				mi.skin = 0;

			R_DrawModelDirect(&mi, &pmi, tag);
		}
	}

	if (EXTRADATA(node).clipOverflow)
		UI_PopClipRect();
}
Ejemplo n.º 18
0
/**
 * @brief Load material definitions for each map that has one
 * @param[in] map the base name of the map to load the material for
 */
void R_LoadMaterials (const char *map)
{
	char path[MAX_QPATH];
	byte *fileBuffer;
	const char *buffer;
	bool inmaterial;
	image_t *image;
	material_t *m;
	materialStage_t *ss;

	/* clear previously loaded materials */
	R_ImageClearMaterials();

	if (map[0] == '+' || map[0] == '-')
		map++;
	else if (map[0] == '-')
		return;

	/* load the materials file for parsing */
	Com_sprintf(path, sizeof(path), "materials/%s.mat", Com_SkipPath(map));

	if (FS_LoadFile(path, &fileBuffer) < 1) {
		Com_DPrintf(DEBUG_RENDERER, "Couldn't load %s\n", path);
		return;
	} else {
		Com_Printf("load material file: '%s'\n", path);
		if (!r_materials->integer)
			Com_Printf("...ignore materials (r_materials is deactivated)\n");
	}

	buffer = (const char *)fileBuffer;

	inmaterial = false;
	image = nullptr;
	m = nullptr;

	while (true) {
		const char *c = Com_Parse(&buffer);

		if (c[0] == '\0')
			break;

		if (*c == '{' && !inmaterial) {
			inmaterial = true;
			continue;
		}

		if (Q_streq(c, "material")) {
			c = Com_Parse(&buffer);
			image = R_GetImage(va("textures/%s", c));
			if (image == nullptr)
				Com_DPrintf(DEBUG_RENDERER, "R_LoadMaterials: skip texture: %s - not used in the map\n", c);

			continue;
		}

		if (!image)
			continue;

		m = &image->material;

		if (Q_streq(c, "normalmap")){
			c = Com_Parse(&buffer);
			image->normalmap = R_FindImage(va("textures/%s", c), it_normalmap);

			if (image->normalmap == r_noTexture){
				Com_Printf("R_LoadMaterials: Failed to resolve normalmap: %s\n", c);
				image->normalmap = nullptr;
			}
		}

		if (Q_streq(c, "glowmap")){
			c = Com_Parse(&buffer);
			image->glowmap = R_FindImage(va("textures/%s", c), it_glowmap);

			if (image->glowmap == r_noTexture){
				Com_Printf("R_LoadMaterials: Failed to resolve glowmap: %s\n", c);
				image->glowmap = nullptr;
			}
		}

		if (Q_streq(c, "bump")) {
			m->bump = atof(Com_Parse(&buffer));
			if (m->bump < 0.0) {
				Com_Printf("R_LoadMaterials: Invalid bump value for %s\n", image->name);
				m->bump = defaultMaterial.bump;
			}
		}

		if (Q_streq(c, "parallax")) {
			m->parallax = atof(Com_Parse(&buffer));
			if (m->parallax < 0.0) {
				Com_Printf("R_LoadMaterials: Invalid parallax value for %s\n", image->name);
				m->parallax = defaultMaterial.parallax;
			}
		}

		if (Q_streq(c, "hardness")) {
			m->hardness = atof(Com_Parse(&buffer));
			if (m->hardness < 0.0) {
				Com_Printf("R_LoadMaterials: Invalid hardness value for %s\n", image->name);
				m->hardness = defaultMaterial.hardness;
			}
		}

		if (Q_streq(c, "specular")) {
			m->specular = atof(Com_Parse(&buffer));
			if (m->specular < 0.0) {
				Com_Printf("R_LoadMaterials: Invalid specular value for %s\n", image->name);
				m->specular = defaultMaterial.specular;
			}
		}

		if (Q_streq(c, "glowscale")) {
			m->glowscale = atof(Com_Parse(&buffer));
			if (m->glowscale < 0.0) {
				Com_Printf("R_LoadMaterials: Invalid glowscale value for %s\n", image->name);
				m->glowscale = defaultMaterial.glowscale;
			}
		}

		if (*c == '{' && inmaterial) {
			materialStage_t* const s = Mem_PoolAllocType(materialStage_t, vid_imagePool);
			s->glowscale = defaultMaterial.glowscale;

			if (R_ParseStage(s, &buffer) == -1) {
				Mem_Free(s);
				continue;
			}

			/* load animation frame images */
			if (s->flags & STAGE_ANIM) {
				if (R_LoadAnimImages(s) == -1) {
					Mem_Free(s);
					continue;
				}
			}

			/* append the stage to the chain */
			if (!m->stages)
				m->stages = s;
			else {
				ss = m->stages;
				while (ss->next)
					ss = ss->next;
				ss->next = s;
			}

			m->flags |= s->flags;
			m->num_stages++;
			continue;
		}

		if (*c == '}' && inmaterial) {
			Com_DPrintf(DEBUG_RENDERER, "Parsed material %s with %d stages\n", image->name, m->num_stages);
			inmaterial = false;
			image = nullptr;
			/* multiply stage glowscale values by material glowscale */
			ss = m->stages;
			while (ss) {
				ss->glowscale *= m->glowscale;
				ss = ss->next;
			}
		}
	}

	FS_FreeFile(fileBuffer);

	R_CreateMaterialData();
}
Ejemplo n.º 19
0
/**
 * @brief Adds a new message to message stack
 * @note These are the messages that are displayed at geoscape
 * @param[in] title Already translated message/mail title
 * @param[in] text Already translated message/mail body
 * @param[in] popup Show this as a popup, too?
 * @param[in] type The message type
 * @param[in] pedia Pointer to technology (only if needed)
 * @param[in] playSound Whether the sound associated with the message type should be played
 * @return message_t pointer
 * @sa UP_OpenMail_f
 * @sa CL_EventAddMail_f
 * @note this method forwards to @c MS_AddNewMessageSound with @code playSound = true @endcode
 */
uiMessageListNodeMessage_t* MS_AddNewMessage (const char* title, const char* text, messageType_t type, technology_t* pedia, bool popup, bool playSound)
{
	assert(type < MSG_MAX);

	/* allocate memory for new message - delete this with every new game */
	uiMessageListNodeMessage_t* const mess = Mem_PoolAllocType(uiMessageListNodeMessage_t, cp_campaignPool);

	switch (type) {
	case MSG_DEBUG: /**< only save them in debug mode */
		mess->iconName = "icons/message_debug";
		break;
	case MSG_INFO: /**< don't save these messages */
		mess->iconName = "icons/message_info";
		break;
	case MSG_STANDARD:
		mess->iconName = "icons/message_info";
		break;
	case MSG_RESEARCH_PROPOSAL:
		mess->iconName = "icons/message_research";
		break;
	case MSG_RESEARCH_HALTED:
		mess->iconName = "icons/message_research";
		break;
	case MSG_RESEARCH_FINISHED:
		mess->iconName = "icons/message_research";
		break;
	case MSG_CONSTRUCTION:
		mess->iconName = "icons/message_construction";
		break;
	case MSG_UFOSPOTTED:
		mess->iconName = "icons/message_ufo";
		break;
	case MSG_TERRORSITE:
		mess->iconName = "icons/message_ufo";
		break;
	case MSG_BASEATTACK:
		mess->iconName = "icons/message_ufo";
		break;
	case MSG_TRANSFERFINISHED:
		mess->iconName = "icons/message_transfer";
		break;
	case MSG_PROMOTION:
		mess->iconName = "icons/message_promotion";
		break;
	case MSG_PRODUCTION:
		mess->iconName = "icons/message_production";
		break;
	case MSG_DEATH:
		mess->iconName = "icons/message_death";
		break;
	case MSG_CRASHSITE:
		mess->iconName = "icons/message_ufo";
		break;
	case MSG_EVENT:
		mess->iconName = "icons/message_info";
		break;
	default:
		mess->iconName = "icons/message_info";
		break;
	}

	/* push the new message at the beginning of the stack */
	cgi->UI_MessageAddStack(mess);

	mess->type = type;
	mess->pedia = pedia;		/* pointer to UFOpaedia entry */

	mess->date = ccs.date;

	Q_strncpyz(mess->title, title, sizeof(mess->title));
	mess->text = cgi->PoolStrDup(text, cp_campaignPool, 0);

	/* get formatted date text */
	MS_TimestampedText(mess->timestamp, mess, sizeof(mess->timestamp));

	/* they need to be translated already */
	if (popup) {
		CP_GameTimeStop();
		CP_Popup(mess->title, "%s", mess->text);
	}

	if (playSound) {
		const char* sound = nullptr;
		switch (type) {
		case MSG_DEBUG:
			break;
		case MSG_STANDARD:
			sound = "geoscape/standard";
			break;
		case MSG_INFO:
		case MSG_TRANSFERFINISHED:
		case MSG_DEATH:
		case MSG_CONSTRUCTION:
		case MSG_PRODUCTION:
			sound = "geoscape/info";
			break;
		case MSG_RESEARCH_PROPOSAL:
		case MSG_RESEARCH_FINISHED:
			assert(pedia);
		case MSG_RESEARCH_HALTED:
		case MSG_EVENT:
		case MSG_NEWS:
			/* reread the new mails in UP_GetUnreadMails */
			ccs.numUnreadMails = -1;
			sound = "geoscape/mail";
			break;
		case MSG_UFOLOST:
			sound = "geoscape/ufolost";
			break;
		case MSG_UFOSPOTTED:
			sound = "geoscape/ufospotted";
			break;
		case MSG_BASEATTACK:
			sound = "geoscape/basealert";
			break;
		case MSG_TERRORSITE:
			sound = "geoscape/alien-activity";
			break;
		case MSG_CRASHSITE:
			sound = "geoscape/newmission";
			break;
		case MSG_PROMOTION:
			sound = "geoscape/promotion";
			break;
		case MSG_MAX:
			break;
		}

		cgi->S_StartLocalSample(sound, 1.0f);
	}

	return mess;
}
Ejemplo n.º 20
0
static cvarChangeListener_t* Cvar_GetChangeListener (cvarChangeListenerFunc_t listenerFunc)
{
	cvarChangeListener_t* const listener = Mem_PoolAllocType(cvarChangeListener_t, com_cvarSysPool);
	listener->exec = listenerFunc;
	return listener;
}