1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6 
7 This file is part of the OpenJK source code.
8 
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22 
23 // tr_image.c
24 #include "tr_local.h"
25 
26 #include <map>
27 
28 bool gServerSkinHack = false;
29 
30 shader_t *R_FindServerShader( const char *name, const int *lightmapIndex, const byte *styles, qboolean mipRawImage );
31 static char *CommaParse( char **data_p );
32 /*
33 ===============
34 RE_SplitSkins
35 input = skinname, possibly being a macro for three skins
36 return= true if three part skins found
37 output= qualified names to three skins if return is true, undefined if false
38 ===============
39 */
RE_SplitSkins(const char * INname,char * skinhead,char * skintorso,char * skinlower)40 bool RE_SplitSkins(const char *INname, char *skinhead, char *skintorso, char *skinlower)
41 {	//INname= "models/players/jedi_tf/|head01_skin1|torso01|lower01";
42 	if (strchr(INname, '|'))
43 	{
44 		char name[MAX_QPATH];
45 		strcpy(name, INname);
46 		char *p = strchr(name, '|');
47 		*p=0;
48 		p++;
49 		//fill in the base path
50 		strcpy (skinhead, name);
51 		strcpy (skintorso, name);
52 		strcpy (skinlower, name);
53 
54 		//now get the the individual files
55 
56 		//advance to second
57 		char *p2 = strchr(p, '|');
58 		assert(p2);
59 		if (!p2)
60 		{
61 			return false;
62 		}
63 		*p2=0;
64 		p2++;
65 		strcat (skinhead, p);
66 		strcat (skinhead, ".skin");
67 
68 
69 		//advance to third
70 		p = strchr(p2, '|');
71 		assert(p);
72 		if (!p)
73 		{
74 			return false;
75 		}
76 		*p=0;
77 		p++;
78 		strcat (skintorso,p2);
79 		strcat (skintorso, ".skin");
80 
81 		strcat (skinlower,p);
82 		strcat (skinlower, ".skin");
83 
84 		return true;
85 	}
86 	return false;
87 }
88 
89 // given a name, go get the skin we want and return
RE_RegisterIndividualSkin(const char * name,qhandle_t hSkin)90 qhandle_t RE_RegisterIndividualSkin( const char *name , qhandle_t hSkin)
91 {
92 	skin_t			*skin;
93 	skinSurface_t	*surf;
94 	char			*text, *text_p;
95 	char			*token;
96 	char			surfName[MAX_QPATH];
97 
98 	// load and parse the skin file
99     ri.FS_ReadFile( name, (void **)&text );
100 	if ( !text ) {
101 #ifndef FINAL_BUILD
102 		Com_Printf( "WARNING: RE_RegisterSkin( '%s' ) failed to load!\n", name );
103 #endif
104 		return 0;
105 	}
106 
107 	assert (tr.skins[hSkin]);	//should already be setup, but might be an 3part append
108 
109 	skin = tr.skins[hSkin];
110 
111 	text_p = text;
112 	while ( text_p && *text_p ) {
113 		// get surface name
114 		token = CommaParse( &text_p );
115 		Q_strncpyz( surfName, token, sizeof( surfName ) );
116 
117 		if ( !token[0] ) {
118 			break;
119 		}
120 		// lowercase the surface name so skin compares are faster
121 		Q_strlwr( surfName );
122 
123 		if ( *text_p == ',' ) {
124 			text_p++;
125 		}
126 
127 		if ( !strncmp( token, "tag_", 4 ) ) {	//these aren't in there, but just in case you load an id style one...
128 			continue;
129 		}
130 
131 		// parse the shader name
132 		token = CommaParse( &text_p );
133 
134 		if ( !strcmp( &surfName[strlen(surfName)-4], "_off") )
135 		{
136 			if ( !strcmp( token ,"*off" ) )
137 			{
138 				continue;	//don't need these double offs
139 			}
140 			surfName[strlen(surfName)-4] = 0;	//remove the "_off"
141 		}
142 		if ((int)(sizeof( skin->surfaces) / sizeof( skin->surfaces[0] )) <= skin->numSurfaces)
143 		{
144 			assert( (int)(sizeof( skin->surfaces) / sizeof( skin->surfaces[0] )) > skin->numSurfaces );
145 			Com_Printf( "WARNING: RE_RegisterSkin( '%s' ) more than %u surfaces!\n", name, (unsigned int)ARRAY_LEN(skin->surfaces) );
146 			break;
147 		}
148 		surf = (skinSurface_t *) Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
149 		skin->surfaces[skin->numSurfaces] = (_skinSurface_t *)surf;
150 
151 		Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
152 
153 		if (gServerSkinHack)	surf->shader = R_FindServerShader( token, lightmapsNone, stylesDefault, qtrue );
154 		else					surf->shader = R_FindShader( token, lightmapsNone, stylesDefault, qtrue );
155 		skin->numSurfaces++;
156 	}
157 
158 	ri.FS_FreeFile( text );
159 
160 
161 	// never let a skin have 0 shaders
162 	if ( skin->numSurfaces == 0 ) {
163 		return 0;		// use default skin
164 	}
165 
166 	return hSkin;
167 }
168 
RE_RegisterSkin(const char * name)169 qhandle_t RE_RegisterSkin( const char *name ) {
170 	qhandle_t	hSkin;
171 	skin_t		*skin;
172 
173 	if ( !name || !name[0] ) {
174 		Com_Printf( "Empty name passed to RE_RegisterSkin\n" );
175 		return 0;
176 	}
177 
178 	if ( strlen( name ) >= MAX_QPATH ) {
179 		Com_Printf( "Skin name exceeds MAX_QPATH\n" );
180 		return 0;
181 	}
182 
183 	// see if the skin is already loaded
184 	for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) {
185 		skin = tr.skins[hSkin];
186 		if ( !Q_stricmp( skin->name, name ) ) {
187 			if( skin->numSurfaces == 0 ) {
188 				return 0;		// default skin
189 			}
190 			return hSkin;
191 		}
192 	}
193 
194 	// allocate a new skin
195 	if ( tr.numSkins == MAX_SKINS ) {
196 		Com_Printf( "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name );
197 		return 0;
198 	}
199 	tr.numSkins++;
200 	skin = (struct skin_s *)Hunk_Alloc( sizeof( skin_t ), h_low );
201 	tr.skins[hSkin] = skin;
202 	Q_strncpyz( skin->name, name, sizeof( skin->name ) );
203 	skin->numSurfaces = 0;
204 
205 	// make sure the render thread is stopped
206 	R_IssuePendingRenderCommands();
207 
208 	// If not a .skin file, load as a single shader
209 	if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) {
210 /*		skin->numSurfaces = 1;
211 		skin->surfaces[0] = (skinSurface_t *)Hunk_Alloc( sizeof(skin->surfaces[0]), h_low );
212 		skin->surfaces[0]->shader = R_FindShader( name, lightmapsNone, stylesDefault, qtrue );
213 		return hSkin;
214 */
215 	}
216 
217 	char skinhead[MAX_QPATH]={0};
218 	char skintorso[MAX_QPATH]={0};
219 	char skinlower[MAX_QPATH]={0};
220 	if ( RE_SplitSkins(name, (char*)&skinhead, (char*)&skintorso, (char*)&skinlower ) )
221 	{//three part
222 		hSkin = RE_RegisterIndividualSkin(skinhead, hSkin);
223 		if (hSkin)
224 		{
225 			hSkin = RE_RegisterIndividualSkin(skintorso, hSkin);
226 			if (hSkin)
227 			{
228 				hSkin = RE_RegisterIndividualSkin(skinlower, hSkin);
229 			}
230 		}
231 	}
232 	else
233 	{//single skin
234 		hSkin = RE_RegisterIndividualSkin(name, hSkin);
235 	}
236 	return(hSkin);
237 }
238 
239 
240 
241 /*
242 ==================
243 CommaParse
244 
245 This is unfortunate, but the skin files aren't
246 compatible with our normal parsing rules.
247 ==================
248 */
CommaParse(char ** data_p)249 static char *CommaParse( char **data_p ) {
250 	int c = 0, len;
251 	char *data;
252 	static	char	com_token[MAX_TOKEN_CHARS];
253 
254 	data = *data_p;
255 	len = 0;
256 	com_token[0] = 0;
257 
258 	// make sure incoming data is valid
259 	if ( !data ) {
260 		*data_p = NULL;
261 		return com_token;
262 	}
263 
264 	while ( 1 ) {
265 		// skip whitespace
266 		while( (c = *(const unsigned char* /*eurofix*/)data) <= ' ') {
267 			if( !c ) {
268 				break;
269 			}
270 			data++;
271 		}
272 
273 
274 		c = *data;
275 
276 		// skip double slash comments
277 		if ( c == '/' && data[1] == '/' )
278 		{
279 			while (*data && *data != '\n')
280 				data++;
281 		}
282 		// skip /* */ comments
283 		else if ( c=='/' && data[1] == '*' )
284 		{
285 			while ( *data && ( *data != '*' || data[1] != '/' ) )
286 			{
287 				data++;
288 			}
289 			if ( *data )
290 			{
291 				data += 2;
292 			}
293 		}
294 		else
295 		{
296 			break;
297 		}
298 	}
299 
300 	if ( c == 0 ) {
301 		return "";
302 	}
303 
304 	// handle quoted strings
305 	if (c == '\"')
306 	{
307 		data++;
308 		while (1)
309 		{
310 			c = *data++;
311 			if (c=='\"' || !c)
312 			{
313 				com_token[len] = 0;
314 				*data_p = ( char * ) data;
315 				return com_token;
316 			}
317 			if (len < MAX_TOKEN_CHARS - 1)
318 			{
319 				com_token[len] = c;
320 				len++;
321 			}
322 		}
323 	}
324 
325 	// parse a regular word
326 	do
327 	{
328 		if (len < MAX_TOKEN_CHARS - 1)
329 		{
330 			com_token[len] = c;
331 			len++;
332 		}
333 		data++;
334 		c = *data;
335 	} while (c>32 && c != ',' );
336 
337 	com_token[len] = 0;
338 
339 	*data_p = ( char * ) data;
340 	return com_token;
341 }
342 
343 /*
344 ===============
345 RE_RegisterServerSkin
346 
347 Mangled version of the above function to load .skin files on the server.
348 ===============
349 */
RE_RegisterServerSkin(const char * name)350 qhandle_t RE_RegisterServerSkin( const char *name ) {
351 	qhandle_t r;
352 
353 	if (ri.Cvar_VariableIntegerValue( "cl_running" ) &&
354 		ri.Com_TheHunkMarkHasBeenMade() &&
355 		ShaderHashTableExists())
356 	{ //If the client is running then we can go straight into the normal registerskin func
357 		return RE_RegisterSkin(name);
358 	}
359 
360 	gServerSkinHack = true;
361 	r = RE_RegisterSkin(name);
362 	gServerSkinHack = false;
363 
364 	return r;
365 }
366 
367 /*
368 ===============
369 R_InitSkins
370 ===============
371 */
R_InitSkins(void)372 void	R_InitSkins( void ) {
373 	skin_t		*skin;
374 
375 	tr.numSkins = 1;
376 
377 	// make the default skin have all default shaders
378 	skin = tr.skins[0] = (struct skin_s *)ri.Hunk_Alloc( sizeof( skin_t ), h_low );
379 	Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name )  );
380 	skin->numSurfaces = 1;
381 	skin->surfaces[0] = (_skinSurface_t *)ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
382 	skin->surfaces[0]->shader = tr.defaultShader;
383 }
384 
385 /*
386 ===============
387 R_GetSkinByHandle
388 ===============
389 */
R_GetSkinByHandle(qhandle_t hSkin)390 skin_t	*R_GetSkinByHandle( qhandle_t hSkin ) {
391 	if ( hSkin < 1 || hSkin >= tr.numSkins ) {
392 		return tr.skins[0];
393 	}
394 	return tr.skins[ hSkin ];
395 }
396