summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/qcommon/json.h353
-rw-r--r--src/renderergl2/tr_backend.c11
-rw-r--r--src/renderergl2/tr_bsp.c97
-rw-r--r--src/renderergl2/tr_local.h1
-rw-r--r--src/renderergl2/tr_main.c2
5 files changed, 458 insertions, 6 deletions
diff --git a/src/qcommon/json.h b/src/qcommon/json.h
new file mode 100644
index 00000000..cfc5b3ca
--- /dev/null
+++ b/src/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/src/renderergl2/tr_backend.c b/src/renderergl2/tr_backend.c
index ae475b02..f7720443 100644
--- a/src/renderergl2/tr_backend.c
+++ b/src/renderergl2/tr_backend.c
@@ -1675,7 +1675,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/src/renderergl2/tr_bsp.c b/src/renderergl2/tr_bsp.c
index 2238cdaf..9a03f991 100644
--- a/src/renderergl2/tr_bsp.c
+++ b/src/renderergl2/tr_bsp.c
@@ -24,6 +24,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_local.h"
+#define JSON_IMPLEMENTATION
+#include "..\qcommon\json.h"
+#undef JSON_IMPLEMENTATION
+
/*
Loads and prepares a map file for scene rendering.
@@ -2973,6 +2977,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];
@@ -3004,16 +3080,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]);
@@ -3027,9 +3108,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++;
}
}
@@ -3420,7 +3502,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 deathmatch spawn points as cubemaps
diff --git a/src/renderergl2/tr_local.h b/src/renderergl2/tr_local.h
index 9da87e6e..62bf1e03 100644
--- a/src/renderergl2/tr_local.h
+++ b/src/renderergl2/tr_local.h
@@ -60,6 +60,7 @@ typedef unsigned int glIndex_t;
#define USE_OVERBRIGHT
typedef struct cubemap_s {
+ char name[MAX_QPATH];
vec3_t origin;
float parallaxRadius;
image_t *image;
diff --git a/src/renderergl2/tr_main.c b/src/renderergl2/tr_main.c
index 63fea5ac..f4261033 100644
--- a/src/renderergl2/tr_main.c
+++ b/src/renderergl2/tr_main.c
@@ -2937,7 +2937,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]);
}
}