Compositor::Ptr CompositorLoader::ParseCompositor(ResourceManager& resourceManager, const json::Value& root) { Compositor::Ptr result(new Compositor()); if (root["renderTargets"].GetType() != ObjectVal) { throw FormatException("renderTargets must be an object"); } json::Object renderTargets = root["renderTargets"].ToObject(); ParseRenderTargets(result, renderTargets); const Value& stages = root["stages"]; if (stages.GetType() != ArrayVal) { throw FormatException("stages must be an array"); } Array arrayStages = stages.ToArray(); for (auto it = arrayStages.begin(); it != arrayStages.end(); ++it) { ParseStage(resourceManager, result, *it); } return result; }
/** * Parses the source text from an idMaterial and initializes the editor dictionary representation * of the material. * @param src The idLexer object that contains the material text. */ void MaterialDoc::ParseMaterial(idLexer* src) { idToken token; //Parse past the name src->SkipUntilString("{"); while ( 1 ) { if ( !src->ExpectAnyToken( &token ) ) { //Todo: Add some error checking here return; } if ( token == "}" ) { break; } if(ParseMaterialDef(&token, src, MaterialDefManager::MATERIAL_DEF_MATERIAL, &editMaterial.materialData)) { continue; } if ( !token.Icmp( "diffusemap" ) ) { //Added as a special stage idStr str; src->ReadRestOfLine( str ); AddSpecialMapStage("diffusemap", str); } else if ( !token.Icmp( "specularmap" ) ) { idStr str; src->ReadRestOfLine( str ); AddSpecialMapStage("specularmap", str); } else if ( !token.Icmp( "bumpmap" ) ) { idStr str; src->ReadRestOfLine( str ); AddSpecialMapStage("bumpmap", str); } else if( token == "{" ) { ParseStage(src); } } }
/** * @brief The current text pointer is at the explicit text definition of the * shader. Parse it into the global shader variable. Later functions * will optimize it. * @param[in,out] _text * @return */ qboolean ParseShaderR1(char *_text) { char **text = &_text; char *token; int s = 0; shader.explicitlyDefined = qtrue; token = COM_ParseExt2(text, qtrue); if (token[0] != '{') { Ren_Warning("WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name); return qfalse; } while (1) { token = COM_ParseExt2(text, qtrue); if (!token[0]) { Ren_Warning("WARNING: no concluding '}' in shader %s\n", shader.name); return qfalse; } // end of shader definition if (token[0] == '}') { break; } // stage definition else if (token[0] == '{') { if (s >= MAX_SHADER_STAGES) { Ren_Warning("WARNING: too many stages in shader %s (max is %i)\n", shader.name, MAX_SHADER_STAGES); return qfalse; } if (!ParseStage(&stages[s], text)) { Ren_Warning("WARNING: can't parse stages of shader %s @[%.50s ...]\n", shader.name, _text); return qfalse; } stages[s].active = qtrue; s++; continue; } // skip stuff that only the QuakeEdRadient needs else if (!Q_stricmpn(token, "qer", 3)) { SkipRestOfLine(text); continue; } // skip description else if (!Q_stricmp(token, "description")) { SkipRestOfLine(text); continue; } // skip renderbump else if (!Q_stricmp(token, "renderbump")) { SkipRestOfLine(text); continue; } // skip unsmoothedTangents else if (!Q_stricmp(token, "unsmoothedTangents")) { Ren_Warning("WARNING: unsmoothedTangents keyword not supported in shader '%s'\n", shader.name); continue; } // skip guiSurf else if (!Q_stricmp(token, "guiSurf")) { SkipRestOfLine(text); continue; } // skip decalInfo else if (!Q_stricmp(token, "decalInfo")) { Ren_Warning("WARNING: decalInfo keyword not supported in shader '%s'\n", shader.name); SkipRestOfLine(text); continue; } // skip Quake4's extra material types else if (!Q_stricmp(token, "materialType")) { Ren_Warning("WARNING: materialType keyword not supported in shader '%s'\n", shader.name); SkipRestOfLine(text); continue; } // skip Prey's extra material types else if (!Q_stricmpn(token, "matter", 6)) { //Ren_Warning( "WARNING: materialType keyword not supported in shader '%s'\n", shader.name); SkipRestOfLine(text); continue; } // sun parms else if (!Q_stricmp(token, "xmap_sun") || !Q_stricmp(token, "q3map_sun")) { float a, b; token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } tr.sunLight[0] = atof(token); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } tr.sunLight[1] = atof(token); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } tr.sunLight[2] = atof(token); VectorNormalize(tr.sunLight); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } a = atof(token); VectorScale(tr.sunLight, a, tr.sunLight); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } a = atof(token); a = a / 180 * M_PI; token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'xmap_sun' keyword in shader '%s'\n", shader.name); continue; } b = atof(token); b = b / 180 * M_PI; tr.sunDirection[0] = cos(a) * cos(b); tr.sunDirection[1] = sin(a) * cos(b); tr.sunDirection[2] = sin(b); continue; } // noShadows else if (!Q_stricmp(token, "noShadows")) { shader.noShadows = qtrue; continue; } // noSelfShadow else if (!Q_stricmp(token, "noSelfShadow")) { Ren_Warning("WARNING: noSelfShadow keyword not supported in shader '%s'\n", shader.name); continue; } // forceShadows else if (!Q_stricmp(token, "forceShadows")) { Ren_Warning("WARNING: forceShadows keyword not supported in shader '%s'\n", shader.name); continue; } // forceOverlays else if (!Q_stricmp(token, "forceOverlays")) { Ren_Warning("WARNING: forceOverlays keyword not supported in shader '%s'\n", shader.name); continue; } // noPortalFog else if (!Q_stricmp(token, "noPortalFog")) { Ren_Warning("WARNING: noPortalFog keyword not supported in shader '%s'\n", shader.name); continue; } // fogLight else if (!Q_stricmp(token, "fogLight")) { Ren_Warning("WARNING: fogLight keyword not supported in shader '%s'\n", shader.name); shader.fogLight = qtrue; continue; } // blendLight else if (!Q_stricmp(token, "blendLight")) { Ren_Warning("WARNING: blendLight keyword not supported in shader '%s'\n", shader.name); shader.blendLight = qtrue; continue; } // ambientLight else if (!Q_stricmp(token, "ambientLight")) { Ren_Warning("WARNING: ambientLight keyword not supported in shader '%s'\n", shader.name); shader.ambientLight = qtrue; continue; } // volumetricLight else if (!Q_stricmp(token, "volumetricLight")) { shader.volumetricLight = qtrue; continue; } // translucent else if (!Q_stricmp(token, "translucent")) { shader.translucent = qtrue; continue; } // forceOpaque else if (!Q_stricmp(token, "forceOpaque")) { shader.forceOpaque = qtrue; continue; } // forceSolid else if (!Q_stricmp(token, "forceSolid") || !Q_stricmp(token, "solid")) { continue; } else if (!Q_stricmp(token, "deformVertexes") || !Q_stricmp(token, "deform")) { ParseDeform(text); continue; } else if (!Q_stricmp(token, "tesssize")) { SkipRestOfLine(text); continue; } // skip noFragment if (!Q_stricmp(token, "noFragment")) { continue; } // skip stuff that only the xmap needs else if (!Q_stricmpn(token, "xmap", 4) || !Q_stricmpn(token, "q3map", 5)) { SkipRestOfLine(text); continue; } // skip stuff that only xmap or the server needs else if (!Q_stricmp(token, "surfaceParm")) { ParseSurfaceParm(text); continue; } // no mip maps else if (!Q_stricmp(token, "nomipmap") || !Q_stricmp(token, "nomipmaps")) { shader.filterType = FT_LINEAR; shader.noPicMip = qtrue; continue; } // no picmip adjustment else if (!Q_stricmp(token, "nopicmip")) { shader.noPicMip = qtrue; continue; } // RF, allow each shader to permit compression if available else if (!Q_stricmp(token, "allowcompress")) { shader.uncompressed = qfalse; continue; } else if (!Q_stricmp(token, "nocompress")) { shader.uncompressed = qtrue; continue; } // polygonOffset else if (!Q_stricmp(token, "polygonOffset")) { shader.polygonOffset = qtrue; continue; } // parallax mapping else if (!Q_stricmp(token, "parallax")) { shader.parallax = qtrue; continue; } // entityMergable, allowing sprite surfaces from multiple entities // to be merged into one batch. This is a savings for smoke // puffs and blood, but can't be used for anything where the // shader calcs (not the surface function) reference the entity color or scroll else if (!Q_stricmp(token, "entityMergable")) { shader.entityMergable = qtrue; continue; } // fogParms else if (!Q_stricmp(token, "fogParms")) { if (!ParseVector(text, 3, shader.fogParms.color)) { return qfalse; } //shader.fogParms.colorInt = ColorBytes4(shader.fogParms.color[0] * tr.identityLight, // shader.fogParms.color[1] * tr.identityLight, // shader.fogParms.color[2] * tr.identityLight, 1.0); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: 'fogParms' incomplete - missing opacity value in shader '%s' set to 1\n", shader.name); shader.fogParms.depthForOpaque = 1; } else { shader.fogParms.depthForOpaque = atof(token); shader.fogParms.depthForOpaque = shader.fogParms.depthForOpaque < 1 ? 1 : shader.fogParms.depthForOpaque; } //shader.fogParms.tcScale = 1.0f / shader.fogParms.depthForOpaque; shader.fogVolume = qtrue; shader.sort = SS_FOG; // skip any old gradient directions SkipRestOfLine(text); continue; } // noFog else if (!Q_stricmp(token, "noFog")) { shader.noFog = qtrue; continue; } // portal else if (!Q_stricmp(token, "portal")) { shader.sort = SS_PORTAL; shader.isPortal = qtrue; token = COM_ParseExt2(text, qfalse); if (token[0]) { shader.portalRange = atof(token); } else { shader.portalRange = 256; } continue; } // portal or mirror else if (!Q_stricmp(token, "mirror")) { shader.sort = SS_PORTAL; shader.isPortal = qtrue; continue; } // skyparms <cloudheight> <outerbox> <innerbox> else if (!Q_stricmp(token, "skyparms")) { ParseSkyParms(text); continue; } // This is fixed fog for the skybox/clouds determined solely by the shader // it will not change in a level and will not be necessary // to force clients to use a sky fog the server says to. // skyfogvars <(r,g,b)> <dist> else if (!Q_stricmp(token, "skyfogvars")) { vec3_t fogColor; if (!ParseVector(text, 3, fogColor)) { return qfalse; } token = COM_ParseExt(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing density value for sky fog\n"); continue; } if (atof(token) > 1) { Ren_Warning("WARNING: last value for skyfogvars is 'density' which needs to be 0.0-1.0\n"); continue; } RE_SetFog(FOG_SKY, 0, 5, fogColor[0], fogColor[1], fogColor[2], atof(token)); continue; } // ET waterfogvars else if (!Q_stricmp(token, "waterfogvars")) { vec3_t watercolor; float fogvar; if (!ParseVector(text, 3, watercolor)) { return qfalse; } token = COM_ParseExt(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing density/distance value for water fog\n"); continue; } fogvar = atof(token); // right now allow one water color per map. I'm sure this will need // to change at some point, but I'm not sure how to track fog parameters // on a "per-water volume" basis yet. if (fogvar == 0) { // '0' specifies "use the map values for everything except the fog color // TODO } else if (fogvar > 1) { // distance "linear" fog RE_SetFog(FOG_WATER, 0, fogvar, watercolor[0], watercolor[1], watercolor[2], 1.1); } else { // density "exp" fog RE_SetFog(FOG_WATER, 0, 5, watercolor[0], watercolor[1], watercolor[2], fogvar); } continue; } // ET fogvars else if (!Q_stricmp(token, "fogvars")) { vec3_t fogColor; float fogDensity; int fogFar; if (!ParseVector(text, 3, fogColor)) { return qfalse; } token = COM_ParseExt(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing density value for the fog\n"); continue; } // NOTE: fogFar > 1 means the shader is setting the farclip, < 1 means setting // density (so old maps or maps that just need softening fog don't have to care about farclip) fogDensity = atof(token); if (fogDensity > 1) { // linear fogFar = fogDensity; } else { fogFar = 5; } RE_SetFog(FOG_MAP, 0, fogFar, fogColor[0], fogColor[1], fogColor[2], fogDensity); RE_SetFog(FOG_CMD_SWITCHFOG, FOG_MAP, 50, 0, 0, 0, 0); continue; } // ET sunshader <name> else if (!Q_stricmp(token, "sunshader")) { size_t tokenLen; token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing shader name for 'sunshader'\n"); continue; } // Don't call tr.sunShader = R_FindShader(token, SHADER_3D_STATIC, qtrue); // because it breaks the computation of the current shader tokenLen = strlen(token) + 1; tr.sunShaderName = (char *)ri.Hunk_Alloc(sizeof(char) * tokenLen, h_low); Q_strncpyz(tr.sunShaderName, token, tokenLen); } else if (!Q_stricmp(token, "lightgridmulamb")) { // ambient multiplier for lightgrid token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing value for 'lightgrid ambient multiplier'\n"); continue; } if (atof(token) > 0) { tr.lightGridMulAmbient = atof(token); } } else if (!Q_stricmp(token, "lightgridmuldir")) { // directional multiplier for lightgrid token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing value for 'lightgrid directional multiplier'\n"); continue; } if (atof(token) > 0) { tr.lightGridMulDirected = atof(token); } } // light <value> determines flaring in xmap, not needed here else if (!Q_stricmp(token, "light")) { (void) COM_ParseExt2(text, qfalse); continue; } // cull <face> else if (!Q_stricmp(token, "cull")) { token = COM_ParseExt2(text, qfalse); if (token[0] == 0) { Ren_Warning("WARNING: missing cull parms in shader '%s'\n", shader.name); continue; } if (!Q_stricmp(token, "none") || !Q_stricmp(token, "twoSided") || !Q_stricmp(token, "disable")) { shader.cullType = CT_TWO_SIDED; } else if (!Q_stricmp(token, "back") || !Q_stricmp(token, "backside") || !Q_stricmp(token, "backsided")) { shader.cullType = CT_BACK_SIDED; } else if (!Q_stricmp(token, "front")) { // CT_FRONT_SIDED is set per default see R_FindShader - nothing to do just don't throw a warning } else { Ren_Warning("WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name); } continue; } // distancecull <opaque distance> <transparent distance> <alpha threshold> else if (!Q_stricmp(token, "distancecull")) { int i; for (i = 0; i < 3; i++) { token = COM_ParseExt(text, qfalse); if (token[0] == 0) { Ren_Warning("WARNING: missing distancecull parms in shader '%s'\n", shader.name); } else { shader.distanceCull[i] = atof(token); } } if (shader.distanceCull[1] - shader.distanceCull[0] > 0) { // distanceCull[ 3 ] is an optimization shader.distanceCull[3] = 1.0f / (shader.distanceCull[1] - shader.distanceCull[0]); } else { shader.distanceCull[0] = 0; shader.distanceCull[1] = 0; shader.distanceCull[2] = 0; shader.distanceCull[3] = 0; } continue; } // twoSided else if (!Q_stricmp(token, "twoSided")) { shader.cullType = CT_TWO_SIDED; continue; } // backSided else if (!Q_stricmp(token, "backSided")) { shader.cullType = CT_BACK_SIDED; continue; } // clamp else if (!Q_stricmp(token, "clamp")) { shader.wrapType = WT_CLAMP; continue; } // edgeClamp else if (!Q_stricmp(token, "edgeClamp")) { shader.wrapType = WT_EDGE_CLAMP; continue; } // zeroClamp else if (!Q_stricmp(token, "zeroclamp")) { shader.wrapType = WT_ZERO_CLAMP; continue; } // alphaZeroClamp else if (!Q_stricmp(token, "alphaZeroClamp")) { shader.wrapType = WT_ALPHA_ZERO_CLAMP; continue; } // sort else if (!Q_stricmp(token, "sort")) { ParseSort(text); continue; } // implicit default mapping to eliminate redundant/incorrect explicit shader stages else if (!Q_stricmpn(token, "implicit", 8)) { //Ren_Warning( "WARNING: keyword '%s' not supported in shader '%s'\n", token, shader.name); //SkipRestOfLine(text); // set implicit mapping state if (!Q_stricmp(token, "implicitBlend")) { implicitStateBits = GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; implicitCullType = CT_TWO_SIDED; } else if (!Q_stricmp(token, "implicitMask")) { implicitStateBits = GLS_DEPTHMASK_TRUE | GLS_ATEST_GE_128; implicitCullType = CT_TWO_SIDED; } else // "implicitMap" { implicitStateBits = GLS_DEPTHMASK_TRUE; implicitCullType = CT_FRONT_SIDED; } // get image token = COM_ParseExt(text, qfalse); if (token[0] != '\0') { Q_strncpyz(implicitMap, token, sizeof(implicitMap)); } else { implicitMap[0] = '-'; implicitMap[1] = '\0'; } continue; } // spectrum else if (!Q_stricmp(token, "spectrum")) { Ren_Warning("WARNING: spectrum keyword not supported in shader '%s'\n", shader.name); token = COM_ParseExt2(text, qfalse); if (!token[0]) { Ren_Warning("WARNING: missing parm for 'spectrum' keyword in shader '%s'\n", shader.name); continue; } shader.spectrum = qtrue; shader.spectrumValue = atoi(token); continue; } // diffuseMap <image> else if (!Q_stricmp(token, "diffuseMap")) { ParseDiffuseMap(&stages[s], text); s++; continue; } // normalMap <image> else if (!Q_stricmp(token, "normalMap") || !Q_stricmp(token, "bumpMap")) { ParseNormalMap(&stages[s], text); s++; continue; } // specularMap <image> else if (!Q_stricmp(token, "specularMap")) { ParseSpecularMap(&stages[s], text); s++; continue; } // glowMap <image> else if (!Q_stricmp(token, "glowMap")) { ParseGlowMap(&stages[s], text); s++; continue; } // reflectionMap <image> else if (!Q_stricmp(token, "reflectionMap")) { ParseReflectionMap(&stages[s], text); s++; continue; } // reflectionMapBlended <image> else if (!Q_stricmp(token, "reflectionMapBlended")) { ParseReflectionMapBlended(&stages[s], text); s++; continue; } // lightMap <image> else if (!Q_stricmp(token, "lightMap")) { Ren_Warning("WARNING: obsolete lightMap keyword not supported in shader '%s'\n", shader.name); SkipRestOfLine(text); continue; } // lightFalloffImage <image> else if (!Q_stricmp(token, "lightFalloffImage")) { ParseLightFalloffImage(&stages[s], text); s++; continue; } // Doom 3 DECAL_MACRO else if (!Q_stricmp(token, "DECAL_MACRO")) { shader.polygonOffset = qtrue; shader.sort = SS_DECAL; SurfaceParm("discrete"); SurfaceParm("noShadows"); continue; } // Prey DECAL_ALPHATEST_MACRO else if (!Q_stricmp(token, "DECAL_ALPHATEST_MACRO")) { // what's different? shader.polygonOffset = qtrue; shader.sort = SS_DECAL; SurfaceParm("discrete"); SurfaceParm("noShadows"); continue; } else if (SurfaceParm(token)) { continue; } else { Ren_Warning("WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name); SkipRestOfLine(text); continue; } } // ignore shaders that don't have any stages, unless it is a sky or fog if (s == 0 && !shader.forceOpaque && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG) && implicitMap[0] == '\0') { return qfalse; } return qtrue; }