[iortcw] 34/152: All: Rend2: Add named cubemaps and per-map env.json parsing

Simon McVittie smcv at debian.org
Fri Sep 8 10:39:54 UTC 2017


This is an automated email from the git hooks/post-receive script.

smcv pushed a commit to annotated tag 1.5a
in repository iortcw.

commit 4274e127505b116ce232d2d36c1c7b0815523e97
Author: MAN-AT-ARMS <M4N4T4RMS at gmail.com>
Date:   Fri Feb 19 17:13:11 2016 -0500

    All: Rend2: Add named cubemaps and per-map env.json parsing
---
 MP/code/qcommon/json.h     | 353 +++++++++++++++++++++++++++++++++++++++++++++
 MP/code/rend2/tr_backend.c |  11 +-
 MP/code/rend2/tr_bsp.c     |  97 ++++++++++++-
 MP/code/rend2/tr_local.h   |   1 +
 MP/code/rend2/tr_main.c    |   2 +-
 SP/code/qcommon/json.h     | 353 +++++++++++++++++++++++++++++++++++++++++++++
 SP/code/rend2/tr_backend.c |  11 +-
 SP/code/rend2/tr_bsp.c     |  97 ++++++++++++-
 SP/code/rend2/tr_local.h   |   1 +
 SP/code/rend2/tr_main.c    |   2 +-
 10 files changed, 916 insertions(+), 12 deletions(-)

diff --git a/MP/code/qcommon/json.h b/MP/code/qcommon/json.h
new file mode 100644
index 0000000..cfc5b3c
--- /dev/null
+++ b/MP/code/qcommon/json.h
@@ -0,0 +1,353 @@
+/*
+===========================================================================
+Copyright (C) 2016 James Canete
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+===========================================================================
+*/
+
+#ifndef JSON_H
+#define JSON_H
+
+enum
+{
+	JSONTYPE_STRING, // string
+	JSONTYPE_OBJECT, // object
+	JSONTYPE_ARRAY,  // array
+	JSONTYPE_VALUE,  // number, true, false, or null
+	JSONTYPE_ERROR   // out of data
+};
+
+// --------------------------------------------------------------------------
+//   Array Functions
+// --------------------------------------------------------------------------
+
+// Get pointer to first value in array
+// When given pointer to an array, returns pointer to the first
+// returns NULL if array is empty or not an array.
+const char *JSON_ArrayGetFirstValue(const char *json, const char *jsonEnd);
+
+// Get pointer to next value in array
+// When given pointer to a value, returns pointer to the next value
+// returns NULL when no next value.
+const char *JSON_ArrayGetNextValue(const char *json, const char *jsonEnd);
+
+// Get pointers to values in an array
+// returns 0 if not an array, array is empty, or out of data
+// returns number of values in the array and copies into index if successful
+unsigned int JSON_ArrayGetIndex(const char *json, const char *jsonEnd, const char **indexes, unsigned int numIndexes);
+
+// Get pointer to indexed value from array
+// returns NULL if not an array, no index, or out of data
+const char *JSON_ArrayGetValue(const char *json, const char *jsonEnd, unsigned int index);
+
+// --------------------------------------------------------------------------
+//   Object Functions
+// --------------------------------------------------------------------------
+
+// Get pointer to named value from object
+// returns NULL if not an object, name not found, or out of data
+const char *JSON_ObjectGetNamedValue(const char *json, const char *jsonEnd, const char *name);
+
+// --------------------------------------------------------------------------
+//   Value Functions
+// --------------------------------------------------------------------------
+
+// Get type of value
+// returns JSONTYPE_ERROR if out of data
+unsigned int JSON_ValueGetType(const char *json, const char *jsonEnd);
+
+// Get value as string
+// returns 0 if out of data
+// returns length and copies into string if successful, including terminating nul.
+// string values are stripped of enclosing quotes but not escaped
+unsigned int JSON_ValueGetString(const char *json, const char *jsonEnd, char *outString, unsigned int stringLen);
+
+// Get value as appropriate type
+// returns 0 if value is false, value is null, or out of data
+// returns 1 if value is true
+// returns value otherwise
+double JSON_ValueGetDouble(const char *json, const char *jsonEnd);
+float JSON_ValueGetFloat(const char *json, const char *jsonEnd);
+int JSON_ValueGetInt(const char *json, const char *jsonEnd);
+
+#endif
+
+#ifdef JSON_IMPLEMENTATION
+#include <stdio.h>
+
+// --------------------------------------------------------------------------
+//   Internal Functions
+// --------------------------------------------------------------------------
+
+static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd);
+static const char *JSON_SkipString(const char *json, const char *jsonEnd);
+static const char *JSON_SkipStruct(const char *json, const char *jsonEnd);
+static const char *JSON_SkipValue(const char *json, const char *jsonEnd);
+static const char *JSON_SkipValueAndSeparators(const char *json, const char *jsonEnd);
+
+#define IS_SEPARATOR(x)    ((x) == ' ' || (x) == '\t' || (x) == '\n' || (x) == '\r' || (x) == ',' || (x) == ':')
+#define IS_STRUCT_OPEN(x)  ((x) == '{' || (x) == '[')
+#define IS_STRUCT_CLOSE(x) ((x) == '}' || (x) == ']')
+
+static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd)
+{
+	while (json < jsonEnd && IS_SEPARATOR(*json))
+		json++;
+
+	return json;
+}
+
+static const char *JSON_SkipString(const char *json, const char *jsonEnd)
+{
+	for (json++; json < jsonEnd && *json != '"'; json++)
+		if (*json == '\\')
+			json++;
+
+	return (json + 1 > jsonEnd) ? jsonEnd : json + 1;
+}
+
+static const char *JSON_SkipStruct(const char *json, const char *jsonEnd)
+{
+	json = JSON_SkipSeparators(json + 1, jsonEnd);
+	while (json < jsonEnd && !IS_STRUCT_CLOSE(*json))
+		json = JSON_SkipValueAndSeparators(json, jsonEnd);
+
+	return (json + 1 > jsonEnd) ? jsonEnd : json + 1;
+}
+
+static const char *JSON_SkipValue(const char *json, const char *jsonEnd)
+{
+	if (json >= jsonEnd)
+		return jsonEnd;
+	else if (*json == '"')
+		json = JSON_SkipString(json, jsonEnd);
+	else if (IS_STRUCT_OPEN(*json))
+		json = JSON_SkipStruct(json, jsonEnd);
+	else
+	{
+		while (json < jsonEnd && !IS_SEPARATOR(*json) && !IS_STRUCT_CLOSE(*json))
+			json++;
+	}
+
+	return json;
+}
+
+static const char *JSON_SkipValueAndSeparators(const char *json, const char *jsonEnd)
+{
+	json = JSON_SkipValue(json, jsonEnd);
+	return JSON_SkipSeparators(json, jsonEnd);
+}
+
+// returns 0 if value requires more parsing, 1 if no more data/false/null, 2 if true
+static unsigned int JSON_NoParse(const char *json, const char *jsonEnd)
+{
+	if (!json || json >= jsonEnd || *json == 'f' || *json == 'n')
+		return 1;
+
+	if (*json == 't')
+		return 2;
+
+	return 0;
+}
+
+// --------------------------------------------------------------------------
+//   Array Functions
+// --------------------------------------------------------------------------
+
+const char *JSON_ArrayGetFirstValue(const char *json, const char *jsonEnd)
+{
+	if (!json || json >= jsonEnd || !IS_STRUCT_OPEN(*json))
+		return NULL;
+
+	json = JSON_SkipSeparators(json + 1, jsonEnd);
+
+	return (json >= jsonEnd || IS_STRUCT_CLOSE(*json)) ? NULL : json;
+}
+
+const char *JSON_ArrayGetNextValue(const char *json, const char *jsonEnd)
+{
+	if (!json || json >= jsonEnd || IS_STRUCT_CLOSE(*json))
+		return NULL;
+
+	json = JSON_SkipValueAndSeparators(json, jsonEnd);
+
+	return (json >= jsonEnd || IS_STRUCT_CLOSE(*json)) ? NULL : json;
+}
+
+unsigned int JSON_ArrayGetIndex(const char *json, const char *jsonEnd, const char **indexes, unsigned int numIndexes)
+{
+	unsigned int length = 0;
+
+	for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json; json = JSON_ArrayGetNextValue(json, jsonEnd))
+	{
+		if (indexes && numIndexes)
+		{
+			*indexes++ = json;
+			numIndexes--;
+		}
+		length++;
+	}
+
+	return length;
+}
+
+const char *JSON_ArrayGetValue(const char *json, const char *jsonEnd, unsigned int index)
+{
+	for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json && index; json = JSON_ArrayGetNextValue(json, jsonEnd))
+		index--;
+
+	return json;
+}
+
+// --------------------------------------------------------------------------
+//   Object Functions
+// --------------------------------------------------------------------------
+
+const char *JSON_ObjectGetNamedValue(const char *json, const char *jsonEnd, const char *name)
+{
+	unsigned int nameLen = strlen(name);
+
+	for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json; json = JSON_ArrayGetNextValue(json, jsonEnd))
+	{
+		if (*json == '"')
+		{
+			const char *thisNameStart, *thisNameEnd;
+
+			thisNameStart = json + 1;
+			json = JSON_SkipString(json, jsonEnd);
+			thisNameEnd = json - 1;
+			json = JSON_SkipSeparators(json, jsonEnd);
+
+			if ((unsigned int)(thisNameEnd - thisNameStart) == nameLen)
+				if (strncmp(thisNameStart, name, nameLen) == 0)
+					return json;
+		}
+	}
+
+	return NULL;
+}
+
+// --------------------------------------------------------------------------
+//   Value Functions
+// --------------------------------------------------------------------------
+
+unsigned int JSON_ValueGetType(const char *json, const char *jsonEnd)
+{
+	if (!json || json >= jsonEnd)
+		return JSONTYPE_ERROR;
+	else if (*json == '"')
+		return JSONTYPE_STRING;
+	else if (*json == '{')
+		return JSONTYPE_OBJECT;
+	else if (*json == '[')
+		return JSONTYPE_ARRAY;
+
+	return JSONTYPE_VALUE;
+}
+
+unsigned int JSON_ValueGetString(const char *json, const char *jsonEnd, char *outString, unsigned int stringLen)
+{
+	const char *stringEnd, *stringStart;
+
+	if (!json)
+	{
+		*outString = '\0';
+		return 0;
+	}
+
+	stringStart = json;
+	stringEnd = JSON_SkipValue(stringStart, jsonEnd);
+	if (stringEnd >= jsonEnd)
+	{
+		*outString = '\0';
+		return 0;
+	}
+
+	// skip enclosing quotes if they exist
+	if (*stringStart == '"')
+		stringStart++;
+
+	if (*(stringEnd - 1) == '"')
+		stringEnd--;
+
+	stringLen--;
+	if (stringLen > stringEnd - stringStart)
+		stringLen = stringEnd - stringStart;
+
+	json = stringStart;
+	while (stringLen--)
+		*outString++ = *json++;
+	*outString = '\0';
+
+	return stringEnd - stringStart;
+}
+
+double JSON_ValueGetDouble(const char *json, const char *jsonEnd)
+{
+	char cValue[256];
+	double dValue = 0.0;
+	unsigned int np = JSON_NoParse(json, jsonEnd);
+
+	if (np)
+		return (double)(np - 1);
+
+	if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+		return 0.0;
+
+	sscanf(cValue, "%lf", &dValue);
+
+	return dValue;
+}
+
+float JSON_ValueGetFloat(const char *json, const char *jsonEnd)
+{
+	char cValue[256];
+	float fValue = 0.0f;
+	unsigned int np = JSON_NoParse(json, jsonEnd);
+
+	if (np)
+		return (float)(np - 1);
+
+	if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+		return 0.0f;
+
+	sscanf(cValue, "%f", &fValue);
+
+	return fValue;
+}
+
+int JSON_ValueGetInt(const char *json, const char *jsonEnd)
+{
+	char cValue[256];
+	int iValue = 0;
+	unsigned int np = JSON_NoParse(json, jsonEnd);
+
+	if (np)
+		return np - 1;
+
+	if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+		return 0;
+
+	sscanf(cValue, "%d", &iValue);
+
+	return iValue;
+}
+
+#undef IS_SEPARATOR
+#undef IS_STRUCT_OPEN
+#undef IS_STRUCT_CLOSE
+
+#endif
diff --git a/MP/code/rend2/tr_backend.c b/MP/code/rend2/tr_backend.c
index f33e5a5..7ac01f6 100644
--- a/MP/code/rend2/tr_backend.c
+++ b/MP/code/rend2/tr_backend.c
@@ -1942,7 +1942,16 @@ const void *RB_ExportCubemaps(const void *data)
 				p += sideSize;
 			}
 
-			Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/%03d.dds", tr.world->baseName, i);
+			if (cubemap->name[0])
+			{
+				COM_StripExtension(cubemap->name, filename, MAX_QPATH);
+				Q_strcat(filename, MAX_QPATH, ".dds");
+			}
+			else
+			{
+				Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/%03d.dds", tr.world->baseName, i);
+			}
+
 			R_SaveDDS(filename, cubemapPixels, r_cubemapSize->integer, r_cubemapSize->integer, 6);
 			ri.Printf(PRINT_ALL, "Saved cubemap %d as %s\n", i, filename);
 		}
diff --git a/MP/code/rend2/tr_bsp.c b/MP/code/rend2/tr_bsp.c
index 0fa488a..7461051 100644
--- a/MP/code/rend2/tr_bsp.c
+++ b/MP/code/rend2/tr_bsp.c
@@ -30,6 +30,10 @@ If you have questions concerning this license or the applicable additional terms
 
 #include "tr_local.h"
 
+#define JSON_IMPLEMENTATION
+#include "../qcommon/json.h"
+#undef JSON_IMPLEMENTATION
+
 /*
 
 Loads and prepares a map file for scene rendering.
@@ -3323,6 +3327,78 @@ qboolean R_ParseSpawnVars( char *spawnVarChars, int maxSpawnVarChars, int *numSp
 	return qtrue;
 }
 
+void R_LoadEnvironmentJson(const char *baseName)
+{
+	char filename[MAX_QPATH];
+
+	union {
+		char *c;
+		void *v;
+	} buffer;
+	char *bufferEnd;
+
+	const char *cubemapArrayJson;
+	int filelen, i;
+
+	Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/env.json", baseName);
+
+	filelen = ri.FS_ReadFile(filename, &buffer.v);
+	if (!buffer.c)
+		return;
+	bufferEnd = buffer.c + filelen;
+
+	if (JSON_ValueGetType(buffer.c, bufferEnd) != JSONTYPE_OBJECT)
+	{
+		ri.Printf(PRINT_ALL, "Bad %s: does not start with a object\n", filename);
+		ri.FS_FreeFile(buffer.v);
+		return;
+	}
+
+	cubemapArrayJson = JSON_ObjectGetNamedValue(buffer.c, bufferEnd, "Cubemaps");
+	if (!cubemapArrayJson)
+	{
+		ri.Printf(PRINT_ALL, "Bad %s: no Cubemaps\n", filename);
+		ri.FS_FreeFile(buffer.v);
+		return;
+	}
+
+	if (JSON_ValueGetType(cubemapArrayJson, bufferEnd) != JSONTYPE_ARRAY)
+	{
+		ri.Printf(PRINT_ALL, "Bad %s: Cubemaps not an array\n", filename);
+		ri.FS_FreeFile(buffer.v);
+		return;
+	}
+
+	tr.numCubemaps = JSON_ArrayGetIndex(cubemapArrayJson, bufferEnd, NULL, 0);
+	tr.cubemaps = ri.Hunk_Alloc(tr.numCubemaps * sizeof(*tr.cubemaps), h_low);
+	memset(tr.cubemaps, 0, tr.numCubemaps * sizeof(*tr.cubemaps));
+
+	for (i = 0; i < tr.numCubemaps; i++)
+	{
+		cubemap_t *cubemap = &tr.cubemaps[i];
+		const char *cubemapJson, *keyValueJson, *indexes[3];
+		int j;
+
+		cubemapJson = JSON_ArrayGetValue(cubemapArrayJson, bufferEnd, i);
+
+		keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Name");
+		if (!JSON_ValueGetString(keyValueJson, bufferEnd, cubemap->name, MAX_QPATH))
+			cubemap->name[0] = '\0';
+
+		keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Position");
+		JSON_ArrayGetIndex(keyValueJson, bufferEnd, indexes, 3);
+		for (j = 0; j < 3; j++)
+			cubemap->origin[j] = JSON_ValueGetFloat(indexes[j], bufferEnd);
+
+		cubemap->parallaxRadius = 1000.0f;
+		keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Radius");
+		if (keyValueJson)
+			cubemap->parallaxRadius = JSON_ValueGetFloat(keyValueJson, bufferEnd);
+	}
+
+	ri.FS_FreeFile(buffer.v);
+}
+
 void R_LoadCubemapEntities(char *cubemapEntityName)
 {
 	char spawnVarChars[2048];
@@ -3354,16 +3430,21 @@ void R_LoadCubemapEntities(char *cubemapEntityName)
 	while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars))
 	{
 		int i;
+		char name[MAX_QPATH];
 		qboolean isCubemap = qfalse;
 		qboolean originSet = qfalse;
 		vec3_t origin;
 		float parallaxRadius = 1000.0f;
 
+		name[0] = '\0';
 		for (i = 0; i < numSpawnVars; i++)
 		{
 			if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName))
 				isCubemap = qtrue;
 
+			if (!Q_stricmp(spawnVars[i][0], "name"))
+				Q_strncpyz(name, spawnVars[i][1], MAX_QPATH);
+
 			if (!Q_stricmp(spawnVars[i][0], "origin"))
 			{
 				sscanf(spawnVars[i][1], "%f %f %f", &origin[0], &origin[1], &origin[2]);
@@ -3377,9 +3458,10 @@ void R_LoadCubemapEntities(char *cubemapEntityName)
 
 		if (isCubemap && originSet)
 		{
-			//ri.Printf(PRINT_ALL, "cubemap at %f %f %f\n", origin[0], origin[1], origin[2]);
-			VectorCopy(origin, tr.cubemaps[numCubemaps].origin);
-			tr.cubemaps[numCubemaps].parallaxRadius = parallaxRadius;
+			cubemap_t *cubemap = &tr.cubemaps[numCubemaps];
+			Q_strncpyz(cubemap->name, name, MAX_QPATH);
+			VectorCopy(origin, cubemap->origin);
+			cubemap->parallaxRadius = parallaxRadius;
 			numCubemaps++;
 		}
 	}
@@ -3796,7 +3878,14 @@ void RE_LoadWorldMap( const char *name ) {
 	// load cubemaps
 	if (r_cubeMapping->integer)
 	{
-		R_LoadCubemapEntities("misc_cubemap");
+		// Try loading an env.json file first
+		R_LoadEnvironmentJson(s_worldData.baseName);
+
+		if (!tr.numCubemaps)
+		{
+			R_LoadCubemapEntities("misc_cubemap");
+		}
+
 		if (!tr.numCubemaps)
 		{
 			// use locations as cubemaps
diff --git a/MP/code/rend2/tr_local.h b/MP/code/rend2/tr_local.h
index b5bae66..b2a7f7e 100644
--- a/MP/code/rend2/tr_local.h
+++ b/MP/code/rend2/tr_local.h
@@ -554,6 +554,7 @@ static ID_INLINE qboolean ShaderRequiresCPUDeforms(const shader_t * shader)
 }
 
 typedef struct cubemap_s {
+	char name[MAX_QPATH];
 	vec3_t origin;
 	float parallaxRadius;
 	image_t *image;
diff --git a/MP/code/rend2/tr_main.c b/MP/code/rend2/tr_main.c
index 0ee2e5e..a107443 100644
--- a/MP/code/rend2/tr_main.c
+++ b/MP/code/rend2/tr_main.c
@@ -3216,7 +3216,7 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene )
 		// only print message for first side
 		if (directed[0] + directed[1] + directed[2] == 0 && cubemapSide == 0)
 		{
-			ri.Printf(PRINT_ALL, "cubemap %d (%f, %f, %f) is outside the lightgrid!\n", cubemapIndex, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]);
+			ri.Printf(PRINT_ALL, "cubemap %d %s (%f, %f, %f) is outside the lightgrid!\n", cubemapIndex, tr.cubemaps[cubemapIndex].name, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]);
 		}
 	}
 
diff --git a/SP/code/qcommon/json.h b/SP/code/qcommon/json.h
new file mode 100644
index 0000000..cfc5b3c
--- /dev/null
+++ b/SP/code/qcommon/json.h
@@ -0,0 +1,353 @@
+/*
+===========================================================================
+Copyright (C) 2016 James Canete
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+===========================================================================
+*/
+
+#ifndef JSON_H
+#define JSON_H
+
+enum
+{
+	JSONTYPE_STRING, // string
+	JSONTYPE_OBJECT, // object
+	JSONTYPE_ARRAY,  // array
+	JSONTYPE_VALUE,  // number, true, false, or null
+	JSONTYPE_ERROR   // out of data
+};
+
+// --------------------------------------------------------------------------
+//   Array Functions
+// --------------------------------------------------------------------------
+
+// Get pointer to first value in array
+// When given pointer to an array, returns pointer to the first
+// returns NULL if array is empty or not an array.
+const char *JSON_ArrayGetFirstValue(const char *json, const char *jsonEnd);
+
+// Get pointer to next value in array
+// When given pointer to a value, returns pointer to the next value
+// returns NULL when no next value.
+const char *JSON_ArrayGetNextValue(const char *json, const char *jsonEnd);
+
+// Get pointers to values in an array
+// returns 0 if not an array, array is empty, or out of data
+// returns number of values in the array and copies into index if successful
+unsigned int JSON_ArrayGetIndex(const char *json, const char *jsonEnd, const char **indexes, unsigned int numIndexes);
+
+// Get pointer to indexed value from array
+// returns NULL if not an array, no index, or out of data
+const char *JSON_ArrayGetValue(const char *json, const char *jsonEnd, unsigned int index);
+
+// --------------------------------------------------------------------------
+//   Object Functions
+// --------------------------------------------------------------------------
+
+// Get pointer to named value from object
+// returns NULL if not an object, name not found, or out of data
+const char *JSON_ObjectGetNamedValue(const char *json, const char *jsonEnd, const char *name);
+
+// --------------------------------------------------------------------------
+//   Value Functions
+// --------------------------------------------------------------------------
+
+// Get type of value
+// returns JSONTYPE_ERROR if out of data
+unsigned int JSON_ValueGetType(const char *json, const char *jsonEnd);
+
+// Get value as string
+// returns 0 if out of data
+// returns length and copies into string if successful, including terminating nul.
+// string values are stripped of enclosing quotes but not escaped
+unsigned int JSON_ValueGetString(const char *json, const char *jsonEnd, char *outString, unsigned int stringLen);
+
+// Get value as appropriate type
+// returns 0 if value is false, value is null, or out of data
+// returns 1 if value is true
+// returns value otherwise
+double JSON_ValueGetDouble(const char *json, const char *jsonEnd);
+float JSON_ValueGetFloat(const char *json, const char *jsonEnd);
+int JSON_ValueGetInt(const char *json, const char *jsonEnd);
+
+#endif
+
+#ifdef JSON_IMPLEMENTATION
+#include <stdio.h>
+
+// --------------------------------------------------------------------------
+//   Internal Functions
+// --------------------------------------------------------------------------
+
+static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd);
+static const char *JSON_SkipString(const char *json, const char *jsonEnd);
+static const char *JSON_SkipStruct(const char *json, const char *jsonEnd);
+static const char *JSON_SkipValue(const char *json, const char *jsonEnd);
+static const char *JSON_SkipValueAndSeparators(const char *json, const char *jsonEnd);
+
+#define IS_SEPARATOR(x)    ((x) == ' ' || (x) == '\t' || (x) == '\n' || (x) == '\r' || (x) == ',' || (x) == ':')
+#define IS_STRUCT_OPEN(x)  ((x) == '{' || (x) == '[')
+#define IS_STRUCT_CLOSE(x) ((x) == '}' || (x) == ']')
+
+static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd)
+{
+	while (json < jsonEnd && IS_SEPARATOR(*json))
+		json++;
+
+	return json;
+}
+
+static const char *JSON_SkipString(const char *json, const char *jsonEnd)
+{
+	for (json++; json < jsonEnd && *json != '"'; json++)
+		if (*json == '\\')
+			json++;
+
+	return (json + 1 > jsonEnd) ? jsonEnd : json + 1;
+}
+
+static const char *JSON_SkipStruct(const char *json, const char *jsonEnd)
+{
+	json = JSON_SkipSeparators(json + 1, jsonEnd);
+	while (json < jsonEnd && !IS_STRUCT_CLOSE(*json))
+		json = JSON_SkipValueAndSeparators(json, jsonEnd);
+
+	return (json + 1 > jsonEnd) ? jsonEnd : json + 1;
+}
+
+static const char *JSON_SkipValue(const char *json, const char *jsonEnd)
+{
+	if (json >= jsonEnd)
+		return jsonEnd;
+	else if (*json == '"')
+		json = JSON_SkipString(json, jsonEnd);
+	else if (IS_STRUCT_OPEN(*json))
+		json = JSON_SkipStruct(json, jsonEnd);
+	else
+	{
+		while (json < jsonEnd && !IS_SEPARATOR(*json) && !IS_STRUCT_CLOSE(*json))
+			json++;
+	}
+
+	return json;
+}
+
+static const char *JSON_SkipValueAndSeparators(const char *json, const char *jsonEnd)
+{
+	json = JSON_SkipValue(json, jsonEnd);
+	return JSON_SkipSeparators(json, jsonEnd);
+}
+
+// returns 0 if value requires more parsing, 1 if no more data/false/null, 2 if true
+static unsigned int JSON_NoParse(const char *json, const char *jsonEnd)
+{
+	if (!json || json >= jsonEnd || *json == 'f' || *json == 'n')
+		return 1;
+
+	if (*json == 't')
+		return 2;
+
+	return 0;
+}
+
+// --------------------------------------------------------------------------
+//   Array Functions
+// --------------------------------------------------------------------------
+
+const char *JSON_ArrayGetFirstValue(const char *json, const char *jsonEnd)
+{
+	if (!json || json >= jsonEnd || !IS_STRUCT_OPEN(*json))
+		return NULL;
+
+	json = JSON_SkipSeparators(json + 1, jsonEnd);
+
+	return (json >= jsonEnd || IS_STRUCT_CLOSE(*json)) ? NULL : json;
+}
+
+const char *JSON_ArrayGetNextValue(const char *json, const char *jsonEnd)
+{
+	if (!json || json >= jsonEnd || IS_STRUCT_CLOSE(*json))
+		return NULL;
+
+	json = JSON_SkipValueAndSeparators(json, jsonEnd);
+
+	return (json >= jsonEnd || IS_STRUCT_CLOSE(*json)) ? NULL : json;
+}
+
+unsigned int JSON_ArrayGetIndex(const char *json, const char *jsonEnd, const char **indexes, unsigned int numIndexes)
+{
+	unsigned int length = 0;
+
+	for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json; json = JSON_ArrayGetNextValue(json, jsonEnd))
+	{
+		if (indexes && numIndexes)
+		{
+			*indexes++ = json;
+			numIndexes--;
+		}
+		length++;
+	}
+
+	return length;
+}
+
+const char *JSON_ArrayGetValue(const char *json, const char *jsonEnd, unsigned int index)
+{
+	for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json && index; json = JSON_ArrayGetNextValue(json, jsonEnd))
+		index--;
+
+	return json;
+}
+
+// --------------------------------------------------------------------------
+//   Object Functions
+// --------------------------------------------------------------------------
+
+const char *JSON_ObjectGetNamedValue(const char *json, const char *jsonEnd, const char *name)
+{
+	unsigned int nameLen = strlen(name);
+
+	for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json; json = JSON_ArrayGetNextValue(json, jsonEnd))
+	{
+		if (*json == '"')
+		{
+			const char *thisNameStart, *thisNameEnd;
+
+			thisNameStart = json + 1;
+			json = JSON_SkipString(json, jsonEnd);
+			thisNameEnd = json - 1;
+			json = JSON_SkipSeparators(json, jsonEnd);
+
+			if ((unsigned int)(thisNameEnd - thisNameStart) == nameLen)
+				if (strncmp(thisNameStart, name, nameLen) == 0)
+					return json;
+		}
+	}
+
+	return NULL;
+}
+
+// --------------------------------------------------------------------------
+//   Value Functions
+// --------------------------------------------------------------------------
+
+unsigned int JSON_ValueGetType(const char *json, const char *jsonEnd)
+{
+	if (!json || json >= jsonEnd)
+		return JSONTYPE_ERROR;
+	else if (*json == '"')
+		return JSONTYPE_STRING;
+	else if (*json == '{')
+		return JSONTYPE_OBJECT;
+	else if (*json == '[')
+		return JSONTYPE_ARRAY;
+
+	return JSONTYPE_VALUE;
+}
+
+unsigned int JSON_ValueGetString(const char *json, const char *jsonEnd, char *outString, unsigned int stringLen)
+{
+	const char *stringEnd, *stringStart;
+
+	if (!json)
+	{
+		*outString = '\0';
+		return 0;
+	}
+
+	stringStart = json;
+	stringEnd = JSON_SkipValue(stringStart, jsonEnd);
+	if (stringEnd >= jsonEnd)
+	{
+		*outString = '\0';
+		return 0;
+	}
+
+	// skip enclosing quotes if they exist
+	if (*stringStart == '"')
+		stringStart++;
+
+	if (*(stringEnd - 1) == '"')
+		stringEnd--;
+
+	stringLen--;
+	if (stringLen > stringEnd - stringStart)
+		stringLen = stringEnd - stringStart;
+
+	json = stringStart;
+	while (stringLen--)
+		*outString++ = *json++;
+	*outString = '\0';
+
+	return stringEnd - stringStart;
+}
+
+double JSON_ValueGetDouble(const char *json, const char *jsonEnd)
+{
+	char cValue[256];
+	double dValue = 0.0;
+	unsigned int np = JSON_NoParse(json, jsonEnd);
+
+	if (np)
+		return (double)(np - 1);
+
+	if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+		return 0.0;
+
+	sscanf(cValue, "%lf", &dValue);
+
+	return dValue;
+}
+
+float JSON_ValueGetFloat(const char *json, const char *jsonEnd)
+{
+	char cValue[256];
+	float fValue = 0.0f;
+	unsigned int np = JSON_NoParse(json, jsonEnd);
+
+	if (np)
+		return (float)(np - 1);
+
+	if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+		return 0.0f;
+
+	sscanf(cValue, "%f", &fValue);
+
+	return fValue;
+}
+
+int JSON_ValueGetInt(const char *json, const char *jsonEnd)
+{
+	char cValue[256];
+	int iValue = 0;
+	unsigned int np = JSON_NoParse(json, jsonEnd);
+
+	if (np)
+		return np - 1;
+
+	if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+		return 0;
+
+	sscanf(cValue, "%d", &iValue);
+
+	return iValue;
+}
+
+#undef IS_SEPARATOR
+#undef IS_STRUCT_OPEN
+#undef IS_STRUCT_CLOSE
+
+#endif
diff --git a/SP/code/rend2/tr_backend.c b/SP/code/rend2/tr_backend.c
index 8223e32..ed156fd 100644
--- a/SP/code/rend2/tr_backend.c
+++ b/SP/code/rend2/tr_backend.c
@@ -2194,7 +2194,16 @@ const void *RB_ExportCubemaps(const void *data)
 				p += sideSize;
 			}
 
-			Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/%03d.dds", tr.world->baseName, i);
+			if (cubemap->name[0])
+			{
+				COM_StripExtension(cubemap->name, filename, MAX_QPATH);
+				Q_strcat(filename, MAX_QPATH, ".dds");
+			}
+			else
+			{
+				Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/%03d.dds", tr.world->baseName, i);
+			}
+
 			R_SaveDDS(filename, cubemapPixels, r_cubemapSize->integer, r_cubemapSize->integer, 6);
 			ri.Printf(PRINT_ALL, "Saved cubemap %d as %s\n", i, filename);
 		}
diff --git a/SP/code/rend2/tr_bsp.c b/SP/code/rend2/tr_bsp.c
index 06398e9..73d89da 100644
--- a/SP/code/rend2/tr_bsp.c
+++ b/SP/code/rend2/tr_bsp.c
@@ -30,6 +30,10 @@ If you have questions concerning this license or the applicable additional terms
 
 #include "tr_local.h"
 
+#define JSON_IMPLEMENTATION
+#include "../qcommon/json.h"
+#undef JSON_IMPLEMENTATION
+
 /*
 
 Loads and prepares a map file for scene rendering.
@@ -3310,6 +3314,78 @@ qboolean R_ParseSpawnVars( char *spawnVarChars, int maxSpawnVarChars, int *numSp
 	return qtrue;
 }
 
+void R_LoadEnvironmentJson(const char *baseName)
+{
+	char filename[MAX_QPATH];
+
+	union {
+		char *c;
+		void *v;
+	} buffer;
+	char *bufferEnd;
+
+	const char *cubemapArrayJson;
+	int filelen, i;
+
+	Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/env.json", baseName);
+
+	filelen = ri.FS_ReadFile(filename, &buffer.v);
+	if (!buffer.c)
+		return;
+	bufferEnd = buffer.c + filelen;
+
+	if (JSON_ValueGetType(buffer.c, bufferEnd) != JSONTYPE_OBJECT)
+	{
+		ri.Printf(PRINT_ALL, "Bad %s: does not start with a object\n", filename);
+		ri.FS_FreeFile(buffer.v);
+		return;
+	}
+
+	cubemapArrayJson = JSON_ObjectGetNamedValue(buffer.c, bufferEnd, "Cubemaps");
+	if (!cubemapArrayJson)
+	{
+		ri.Printf(PRINT_ALL, "Bad %s: no Cubemaps\n", filename);
+		ri.FS_FreeFile(buffer.v);
+		return;
+	}
+
+	if (JSON_ValueGetType(cubemapArrayJson, bufferEnd) != JSONTYPE_ARRAY)
+	{
+		ri.Printf(PRINT_ALL, "Bad %s: Cubemaps not an array\n", filename);
+		ri.FS_FreeFile(buffer.v);
+		return;
+	}
+
+	tr.numCubemaps = JSON_ArrayGetIndex(cubemapArrayJson, bufferEnd, NULL, 0);
+	tr.cubemaps = ri.Hunk_Alloc(tr.numCubemaps * sizeof(*tr.cubemaps), h_low);
+	memset(tr.cubemaps, 0, tr.numCubemaps * sizeof(*tr.cubemaps));
+
+	for (i = 0; i < tr.numCubemaps; i++)
+	{
+		cubemap_t *cubemap = &tr.cubemaps[i];
+		const char *cubemapJson, *keyValueJson, *indexes[3];
+		int j;
+
+		cubemapJson = JSON_ArrayGetValue(cubemapArrayJson, bufferEnd, i);
+
+		keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Name");
+		if (!JSON_ValueGetString(keyValueJson, bufferEnd, cubemap->name, MAX_QPATH))
+			cubemap->name[0] = '\0';
+
+		keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Position");
+		JSON_ArrayGetIndex(keyValueJson, bufferEnd, indexes, 3);
+		for (j = 0; j < 3; j++)
+			cubemap->origin[j] = JSON_ValueGetFloat(indexes[j], bufferEnd);
+
+		cubemap->parallaxRadius = 1000.0f;
+		keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Radius");
+		if (keyValueJson)
+			cubemap->parallaxRadius = JSON_ValueGetFloat(keyValueJson, bufferEnd);
+	}
+
+	ri.FS_FreeFile(buffer.v);
+}
+
 void R_LoadCubemapEntities(char *cubemapEntityName)
 {
 	char spawnVarChars[2048];
@@ -3341,16 +3417,21 @@ void R_LoadCubemapEntities(char *cubemapEntityName)
 	while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars))
 	{
 		int i;
+		char name[MAX_QPATH];
 		qboolean isCubemap = qfalse;
 		qboolean originSet = qfalse;
 		vec3_t origin;
 		float parallaxRadius = 1000.0f;
 
+		name[0] = '\0';
 		for (i = 0; i < numSpawnVars; i++)
 		{
 			if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName))
 				isCubemap = qtrue;
 
+			if (!Q_stricmp(spawnVars[i][0], "name"))
+				Q_strncpyz(name, spawnVars[i][1], MAX_QPATH);
+
 			if (!Q_stricmp(spawnVars[i][0], "origin"))
 			{
 				sscanf(spawnVars[i][1], "%f %f %f", &origin[0], &origin[1], &origin[2]);
@@ -3364,9 +3445,10 @@ void R_LoadCubemapEntities(char *cubemapEntityName)
 
 		if (isCubemap && originSet)
 		{
-			//ri.Printf(PRINT_ALL, "cubemap at %f %f %f\n", origin[0], origin[1], origin[2]);
-			VectorCopy(origin, tr.cubemaps[numCubemaps].origin);
-			tr.cubemaps[numCubemaps].parallaxRadius = parallaxRadius;
+			cubemap_t *cubemap = &tr.cubemaps[numCubemaps];
+			Q_strncpyz(cubemap->name, name, MAX_QPATH);
+			VectorCopy(origin, cubemap->origin);
+			cubemap->parallaxRadius = parallaxRadius;
 			numCubemaps++;
 		}
 	}
@@ -3785,7 +3867,14 @@ void RE_LoadWorldMap( const char *name ) {
 	// load cubemaps
 	if (r_cubeMapping->integer)
 	{
-		R_LoadCubemapEntities("misc_cubemap");
+		// Try loading an env.json file first
+		R_LoadEnvironmentJson(s_worldData.baseName);
+
+		if (!tr.numCubemaps)
+		{
+			R_LoadCubemapEntities("misc_cubemap");
+		}
+
 		if (!tr.numCubemaps)
 		{
 			// use ai markers as cubemaps
diff --git a/SP/code/rend2/tr_local.h b/SP/code/rend2/tr_local.h
index 0435b29..554427c 100644
--- a/SP/code/rend2/tr_local.h
+++ b/SP/code/rend2/tr_local.h
@@ -557,6 +557,7 @@ static ID_INLINE qboolean ShaderRequiresCPUDeforms(const shader_t * shader)
 }
 
 typedef struct cubemap_s {
+	char name[MAX_QPATH];
 	vec3_t origin;
 	float parallaxRadius;
 	image_t *image;
diff --git a/SP/code/rend2/tr_main.c b/SP/code/rend2/tr_main.c
index 79a5d46..86df639 100644
--- a/SP/code/rend2/tr_main.c
+++ b/SP/code/rend2/tr_main.c
@@ -3264,7 +3264,7 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene )
 		// only print message for first side
 		if (directed[0] + directed[1] + directed[2] == 0 && cubemapSide == 0)
 		{
-			ri.Printf(PRINT_ALL, "cubemap %d (%f, %f, %f) is outside the lightgrid!\n", cubemapIndex, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]);
+			ri.Printf(PRINT_ALL, "cubemap %d %s (%f, %f, %f) is outside the lightgrid!\n", cubemapIndex, tr.cubemaps[cubemapIndex].name, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]);
 		}
 	}
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/iortcw.git



More information about the Pkg-games-commits mailing list