Exemple #1
0
    void Shader::Init(const char *name, const Defines &defines, const Constants &constants)
    {
        string sn(name);
        sn += GetExtension();
        StringReplace(sn, "\\", "/");

        ifstream in(sn, ifstream::in);
        if(in)
        {
            stringstream strStream;
            strStream << in.rdbuf();
            string source(strStream.str());
            source.erase(source.find_last_of('}')+1, source.length());
            InsertDefines(source, defines);
            InsertConstants(source, constants);

            const string path = sn.substr(0, sn.find_last_of("/") + 1);
            ExpandIncludes(path, source);
            FindUniformBlocks(source);
            AddHeader(source);

            Init2(source.c_str(), name);
        }
        else {
            LOG(ERROR) << "[Shader::Init] No shader file found: " << sn;
        }
        in.close();
    }
Exemple #2
0
bool GLSLTool::Assemble(
	Engine &engine,
	const r::Material &material,
	const Shader::Ref &shader,
	const r::MaterialInputMappings &mapping,
	const Shader::TexCoordMapping &tcMapping,
	r::Shader::Pass pass,
	AssembleFlags flags,
	std::ostream &out
) {
	std::stringstream ss;

	const bool GLES = (flags & kAssemble_GLES) ? true : false;

	if (!(flags&(kAssemble_VertexShader|kAssemble_PixelShader)))
		flags |= kAssemble_VertexShader;

	bool vertexShader = (flags & kAssemble_VertexShader) ? true : false;

	if (!GLES)
		ss << "#version 120\r\n";

	if (vertexShader) {
		ss << "#define VERTEX\r\n";
	} else {
		ss << "#define FRAGMENT\r\n";
		ss << "#define MATERIAL\r\n";
	}

	switch (shader->precisionMode) {
	case Shader::kPrecision_Low:
		ss << "#define PFLOAT FIXED\r\n";
		ss << "#define PFLOAT2 FIXED2\r\n";
		ss << "#define PFLOAT3 FIXED3\r\n";
		ss << "#define PFLOAT4 FIXED4\r\n";
		ss << "#define PFLOAT4X4 FIXED4X4\r\n";
		break;
	case Shader::kPrecision_Medium:
		ss << "#define PFLOAT HALF\r\n";
		ss << "#define PFLOAT2 HALF2\r\n";
		ss << "#define PFLOAT3 HALF3\r\n";
		ss << "#define PFLOAT4 HALF4\r\n";
		ss << "#define PFLOAT4X4 HALF4X4\r\n";
		break;
	case Shader::kPrecision_High:
		ss << "#define PFLOAT FLOAT\r\n";
		ss << "#define PFLOAT2 FLOAT2\r\n";
		ss << "#define PFLOAT3 FLOAT3\r\n";
		ss << "#define PFLOAT4 FLOAT4\r\n";
		ss << "#define PFLOAT4X4 FLOAT4X4\r\n";
		break;
	}

	if (pass != r::Shader::kPass_Preview) {
		if (material.skinMode == r::Material::kSkinMode_Sprite)
			ss << "#define SKIN_SPRITE\r\n";
		if (material.skinMode == r::Material::kSkinMode_Billboard)
			ss << "#define SKIN_BILLBOARD\r\n";
	}

	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_Color) > 0)
		ss << "#define SHADER_COLOR\r\n";

	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_VertexColor) > 0)
		ss << "#define SHADER_VERTEX_COLOR\r\n";

	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_Vertex) > 0)
		ss << "#define SHADER_POSITION\r\n";

	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_MV) > 0)
		ss << "#define SHADER_MV\r\n";
	
	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_PRJ) > 0)
		ss << "#define SHADER_PRJ\r\n";

	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_MVP) > 0)
		ss << "#define SHADER_MVP\r\n";

	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_InverseMV) > 0)
		ss << "#define SHADER_INVERSE_MV\r\n";

	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_InverseMVP) > 0)
		ss << "#define SHADER_INVERSE_MVP\r\n";

	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_InversePRJ) > 0)
		ss << "#define SHADER_INVERSE_PRJ\r\n";

	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_PFXVars) > 0)
		ss << "#define PFX_VARS\r\n";
		
	if (shader->MaterialSourceUsage(pass, Shader::kMaterialSource_EyeVertex) > 0)
		ss << "#define SHADER_EYE_VERTEX\r\n";

	int numTextures = 0;
	for (int i = 0; i < r::kMaxTextures; ++i) {
		if (mapping.textures[i][0] == r::kInvalidMapping)
			break; // no more texture bindings
		switch (mapping.textures[i][0]) {
		case r::kMaterialTextureSource_Texture:
			ss << "#define T" << i << "TYPE sampler2D" << "\r\n";
			break;
		default:
			break;
		}
		switch(shader->SamplerPrecisionMode(i)) {
		case Shader::kPrecision_Low:
			ss << "#define T" << i << "PRECISION lowp" << "\r\n";
			break;
		case Shader::kPrecision_Medium:
			ss << "#define T" << i << "PRECISION mediump" << "\r\n";
			break;
		case Shader::kPrecision_High:
			ss << "#define T" << i << "PRECISION highp" << "\r\n";
			break;
		}
		++numTextures;
	}

	if (numTextures > 0)
		ss << "#define TEXTURES " << numTextures << "\r\n";
	
	const Shader::IntSet &tcUsage = shader->AttributeUsage(pass, Shader::kMaterialSource_TexCoord);
	int numTexCoords = (int)tcUsage.size();
	if (numTexCoords > 0) {
		// Shaders files can read from r::kMaxTexture unique texture coordinate slots.
		// The set of read texcoord registers may be sparse. Additionally the engine only supports
		// 2 UV channels in most model data. We do some work here to map the set of read texcoord
		// registers onto the smallest possible set:
		//
		// A tcMod may take an input UV channel and modify it, meaning that texture channel is unique,
		// however there are a lot of cases where the tcMod is identity and therefore a texture coordinate
		// register in a shader can be mapped to a commmon register.

		int numTCMods = 0;
		for (int i = 0; i < r::kMaterialTextureSource_MaxIndices; ++i) {
			if (mapping.tcMods[i] == r::kInvalidMapping)
				break;
			++numTCMods;
		}
		
		// numTCMods is the number of unique texture coordinates read by the pixel shader.
		// (which have to be generated by the vertex shader).

		ss << "#define TEXCOORDS " << numTCMods << "\r\n";

		RAD_VERIFY(tcUsage.size() == tcMapping.size());

		if (vertexShader) {
			Shader::IntSet tcInputs;
			
			bool genReflect = false;
			bool genProject = false;

			for (int i = 0; i < r::kMaterialTextureSource_MaxIndices; ++i) {
				if (mapping.tcMods[i] == r::kInvalidMapping)
					break;
				int tcIndex = (int)mapping.tcMods[i];
				tcInputs.insert(material.TCUVIndex(tcIndex));

				int tcMod = material.TCModFlags(tcIndex);
				if (tcMod & r::Material::kTCModFlag_Rotate)
					ss << "#define TEXCOORD" << i << "_ROTATE\r\n";
				if (tcMod & r::Material::kTCModFlag_Scale)
					ss << "#define TEXCOORD" << i << "_SCALE\r\n";
				if (tcMod & r::Material::kTCModFlag_Shift)
					ss << "#define TEXCOORD" << i << "_SHIFT\r\n";
				if (tcMod & r::Material::kTCModFlag_Scroll)
					ss << "#define TEXCOORD" << i << "_SCROLL\r\n";
				if (tcMod & r::Material::kTCModFlag_Turb)
					ss << "#define TEXCOORD" << i << "_TURB\r\n";

				int tcGen = material.TCGen(tcIndex);
				if (tcGen == r::Material::kTCGen_EnvMap) {
					if (!genReflect) {
						genReflect = true;
						ss << "#define GENREFLECT\r\n";
					}
					ss << "#define TEXCOORD" << i << "_GENREFLECT\r\n";
				} else if (tcGen == r::Material::kTCGen_Projected) {
					if (!genProject) {
						genProject = true;
						ss << "#define GENPROJECT\r\n";
					}
					ss << "#define TEXCOORD" << i << "_GENPROJECT\r\n";
				}
			}

			ss << "#define TCINPUTS " << tcInputs.size() << "\r\n";

			for (int i = 0; i < r::kMaterialTextureSource_MaxIndices; ++i) {
				if (mapping.tcMods[i] == r::kInvalidMapping)
					break;
				int tcIndex = (int)mapping.tcMods[i];
				int uvIndex = material.TCUVIndex(tcIndex);

				int ofs = 0;
				for (Shader::IntSet::const_iterator it2 = tcInputs.begin(); it2 != tcInputs.end(); ++it2) {
					if (uvIndex == *it2)
						break;
					++ofs;
				}

				RAD_VERIFY(ofs < (int)tcInputs.size());
				ss << "#define TEXCOORD" << i << " tc" << ofs << "\r\n";
			}
		} else {
			// fragment shader inputs used generated tc's, which may have expanded from the
			// the vertex shader inputs.
			int ofs = 0;
			for (Shader::IntSet::const_iterator it = tcUsage.begin(); it != tcUsage.end(); ++it, ++ofs) {
				ss << "#define TEXCOORD" << ofs << " tc" << tcMapping[ofs].first << "\r\n";
			}
		}
	}
	
	int numColors = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_Color);

	if (numColors > 0)
		ss << "#define COLORS " << numColors << "\r\n";

	int numSpecularColors = std::max(
		shader->MaterialSourceUsage(pass, Shader::kMaterialSource_SpecularColor),
		shader->MaterialSourceUsage(pass, Shader::kMaterialSource_SpecularExponent)
	);
	if (numSpecularColors > 0)
		ss << "#define SHADER_SPECULAR_COLORS " << numSpecularColors << "\r\n";

	int numLightPos = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_LightPos);
	int numLightVec = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_LightVec);
	int numLightHalfVec = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_LightHalfVec);
	int numLightVertex = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_LightVertex);
	int numLightTanVec = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_LightTanVec);
	int numLightTanHalfVec = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_LightTanHalfVec);
	int numLightDiffuseColor = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_LightDiffuseColor);
	int numLightSpecularColor = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_LightSpecularColor);

	int numShaderNormals = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_Normal);
	int numShaderTangents = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_Tangent);
	int numShaderBitangents = shader->MaterialSourceUsage(pass, Shader::kMaterialSource_Bitangent);

	int numNormals = numShaderNormals;
	int numTangents = numShaderTangents;
	int numBitangents = numShaderBitangents;

	bool needTangents = vertexShader && (numLightTanVec || numLightTanHalfVec);
	if (needTangents) {
		numNormals = std::max(1, numShaderNormals);
		numTangents = std::max(1, numShaderTangents);
		numBitangents = std::max(1, numShaderBitangents);

		ss << "#define TANGENT_FRAME" << "\r\n";
	}

	if (numNormals > 0)
		ss << "#define NORMALS " << numNormals << "\r\n";
	if (numTangents > 0)
		ss << "#define TANGENTS " << numTangents << "\r\n";
	if (numBitangents > 0)
		ss << "#define BITANGENTS " << numBitangents << "\r\n";

	if (numShaderNormals > 0)
		ss << "#define NUM_SHADER_NORMALS " << numShaderNormals << "\r\n";
	if (numShaderTangents > 0)
		ss << "#define NUM_SHADER_TANGENTS " << numShaderTangents << "\r\n";
	if (numShaderBitangents > 0)
		ss << "#define NUM_SHADER_BITANGENTS " << numShaderBitangents << "\r\n";

	int numLights = std::max(
		numLightPos, 
		std::max(
			numLightVec, 
			std::max(
				numLightHalfVec,
				std::max(
					numLightVertex,
					std::max(
						numLightTanVec,
						std::max(
							numLightTanHalfVec,
							std::max(numLightDiffuseColor, numLightSpecularColor)
						)
					)
				)
			)
		)
	);

	if (numLights > 0) {
		ss << "#define LIGHTS " << numLights << "\r\n";
		if (numLightPos > 0)
			ss << "#define SHADER_LIGHT_POS " << numLightPos << "\r\n";
		if (numLightVec > 0)
			ss << "#define SHADER_LIGHT_VEC " << numLightVec << "\r\n";
		if (numLightHalfVec > 0)
			ss << "#define SHADER_LIGHT_HALFVEC " << numLightHalfVec << "\r\n";
		if (numLightVertex > 0)
			ss << "#define SHADER_LIGHT_VERTEXPOS " << numLightVertex << "\r\n";
		if (numLightTanVec > 0)
			ss << "#define SHADER_LIGHT_TANVEC " << numLightTanVec << "\r\n";
		if (numLightTanHalfVec > 0)
			ss << "#define SHADER_LIGHT_TANHALFVEC " << numLightTanHalfVec << "\r\n";
		if (numLightDiffuseColor > 0)
			ss << "#define SHADER_LIGHT_DIFFUSE_COLOR " << numLightDiffuseColor << "\r\n";
		if (numLightSpecularColor > 0)
			ss << "#define SHADER_LIGHT_SPECULAR_COLOR " << numLightSpecularColor << "\r\n";
	}

	if (GLES) {
		ss << "#define _GLES\r\n";
		ss << "#define MOBILE\r\n";
	}
	
	if (!Inject(engine, "@r:/Source/Shaders/Nodes/GLSL.c", ss))
		return false;
	if (!Inject(engine, "@r:/Source/Shaders/Nodes/Common.c", ss))
		return false;
	if (!Inject(engine, "@r:/Source/Shaders/Nodes/Shader.c", ss))
		return false;

	std::stringstream ex;
	if (!ExpandIncludes(*this, ss, ex))
		return false;

	if (flags & kAssemble_Optimize) {
		String in(ex.str());

		glslopt_ctx *glslopt = glslopt_initialize(GLES);

		glslopt_shader *opt_shader = glslopt_optimize(
			glslopt,
			vertexShader ? kGlslOptShaderVertex : kGlslOptShaderFragment,
			in.c_str, 
			0
		);

		char szPass[32];
		sprintf(szPass, "_pass%d", (int)pass);
		
		{
			engine.sys->files->CreateDirectory("@r:/Temp/Shaders/Logs");
			String path(CStr("@r:/Temp/Shaders/Logs/"));
			path += shader->name;
			path += szPass;
			path += "_unoptimized";
			if (vertexShader) {
				path += ".vert.glsl";
			} else {
				path += ".frag.glsl";
			}
			tools::shader_utils::SaveText(engine, path.c_str, in.c_str);
		}

		if (!glslopt_get_status(opt_shader)) {
			COut(C_Error) << "Error optimizing shader: " << std::endl << in << std::endl << glslopt_get_log(opt_shader) << std::endl;
			engine.sys->files->CreateDirectory("@r:/Temp/Shaders/Logs");

			String path;
			for (int i = 0;; ++i) {
				path.PrintfASCII("@r:/Temp/Shaders/Logs/%s_error_%d.log", shader->name.get(), i);
				if (!engine.sys->files->FileExists(path.c_str)) {
					SaveText(engine, path.c_str, in.c_str);
					break;
				}
			}
			glslopt_shader_delete(opt_shader);
			glslopt_cleanup(glslopt);
			return false;
		}

		std::stringstream z;
		if (GLES) {
			switch (shader->precisionMode) {
			case Shader::kPrecision_Low:
				z << "precision lowp float;\r\n";
				break;
			case Shader::kPrecision_Medium:
				z << "precision mediump float;\r\n";
				break;
			case Shader::kPrecision_High:
				z << "precision highp float;\r\n";
				break;
			}
		}
		z << glslopt_get_output(opt_shader);
		glslopt_shader_delete(opt_shader);
		glslopt_cleanup(glslopt);

		Copy(z, out);

		{
			engine.sys->files->CreateDirectory("@r:/Temp/Shaders/Logs");
			String path(CStr("@r:/Temp/Shaders/Logs/"));
			path += shader->name;
			path += szPass;
			path += "_optimized";
			if (vertexShader) {
				path += ".vert.glsl";
			} else {
				path += ".frag.glsl";
			}
			tools::shader_utils::SaveText(engine, path.c_str, z.str().c_str());
		}
	} else {
		Copy(ex, out);
	}

	return true;
}