RF_Type::Bool AppendFormat() { StringBuilder builder; builder.AppendFormat("Hello %s!", "World"); return builder.Length() == 12 && builder.Size() == 13 && builder.Capacity() >= 13 && builder.AsCString() != 0; }
// ------------------------------------------------------------------------------------------ //! Generates a structure inside GLSL shader. //! @param Struct Structure object definition. //! @param Builder Output for the shader code. void GLSLGenerator::GenerateShaderStruct(HLSLStruct const* const Struct, StringBuilder& Builder) { Builder.AppendFormat("\n\nstruct %s\n{", Struct->Name.CStr()); for (auto const& Definition : Struct->InnerDefinitions) { HLSLVariable const* const StructField = static_cast<HLSLVariable const*>(Definition); Builder.AppendFormat("\n\t%s %s", StructField->Type->Name.CStr(), StructField->Name.CStr()); if (StructField->ArrayRank != 0) { // Adding array information for our field.. Builder.AppendFormat("[%d]", static_cast<int>(StructField->ArrayRank)); } Builder.Append(';'); } Builder.Append("\n};"); }
// ------------------------------------------------------------------------------------------ //! Generates a HLSL source code from the specified parsed static variable definition. //! @param StaticVariable Parsed shader static variable, produced by @ref HLSLParser. //! @param Builder Output for the shader code. void GLSLGenerator::GenerateShaderStaticVariable(HLSLVariable const* const StaticVariable, StringBuilder& Builder) { // Skipping samplers. if (StaticVariable->Type->Class == GD_HLSL_TYPE_CLASS_SAMPLER) return; Builder.Append("\n\n"); if (StaticVariable->Binding != nullptr) { // Emitting the global uniform variable. HLSLRegister const* const StaticVariableRegister = static_cast<HLSLRegister const*>(StaticVariable->Binding); Builder.AppendFormat("layout(location = %d) \nuniform ", static_cast<int>(StaticVariableRegister->RegisterID)); } Builder.AppendFormat("%s %s", StaticVariable->Type->Name.CStr(), StaticVariable->Name.CStr()); if (StaticVariable->ArrayRank != 0) { // Adding array information for our field.. Builder.AppendFormat("[%d]", static_cast<int>(StaticVariable->ArrayRank)); } Builder.Append(';'); }
// ------------------------------------------------------------------------------------------ //! Generates a HLSL source code from the specified parsed static function definition. //! @param StaticFunction Parsed shader static function, produced by @ref HLSLParser. //! @param Builder Output for the shader code. void GLSLGenerator::GenerateShaderStaticFunction(HLSLFunction const* const StaticFunction, StringBuilder& Builder) { if (StaticFunction->Type->Name == "main") { //! @todo Possibly this is an entry point? We need just to mangle code here. throw GLSLCompilerErrorException("it is not allowed to name a function 'main'."); } Builder.AppendFormat("\n\ninline %s %s(", StaticFunction->Type->Name.CStr(), StaticFunction->Name.CStr()); for (SizeTp cnt = 0; cnt < StaticFunction->Arguments.GetLength(); ++cnt) { // Emitting function parameter.. auto const& Argument = StaticFunction->Arguments[cnt]; Builder.AppendFormat("%s%s %s %s", (Argument->AccsessType & GD_HLSL_ARGUMENT_IN) != 0 ? "in" : "", (Argument->AccsessType & GD_HLSL_ARGUMENT_OUT) != 0 ? "out" : "" , Argument->Type->Name.CStr(), Argument->Name.CStr()); if (cnt != StaticFunction->Arguments.GetLength() - 1) { // This is not the last argument, appending comma after it. Builder.AppendFormat(", "); } } Builder.AppendFormat(")\n%s", StaticFunction->Body.CStr()); }
// ------------------------------------------------------------------------------------------ //! Generates a structure inside GLSL shader. //! @param ConstantBuffer Constant buffer object definition. //! @param Builder Output for the shader code. //! @param SupportsConstantBuffers Boolean variable for the support of the uniform buffers. //! @param ShaderType Target type of the shader. void GLSLGenerator::GenerateShaderConstantBuffer(HLSLCBuffer const* const ConstantBuffer, StringBuilder& Builder, bool const SupportsConstantBuffers, IGraphicsShaderType const ShaderType) { if (ConstantBuffer->Register == nullptr) { throw GLSLCompilerErrorException("constant buffer '%s' does not contains meta information about register.", ConstantBuffer->Name.CStr()); } if (SupportsConstantBuffers) { // This platform supports constant buffers, defining it. Builder.AppendFormat("\n\nlayout(std140, row_major, binding = %d) \nuniform %s \n{" , static_cast<int>(ConstantBuffer->Register->RegisterID) + static_cast<int>(ShaderType) * static_cast<int>(GD_HRI_SHADER_MAX_CBUFFERS_LOCATIONS) , ConstantBuffer->Name.CStr()); } else { // Emulating behavior of the constant buffers through uniform variables. Builder.AppendFormat("\n\n// uniform %s {", ConstantBuffer->Name.CStr()); } for (auto const& Definition : ConstantBuffer->InnerDefinitions) { auto const ConstantBufferField = static_cast<UniquePtr<HLSLVariable const>>(Definition); if (SupportsConstantBuffers) { // Emitting a field of the inform buffer. Builder.AppendFormat("\n\t%s %s", ConstantBufferField->Type->Name.CStr(), ConstantBufferField->Name.CStr()); } else { // Emitting a standalone uniform variable. Builder.AppendFormat("\nlayout(row_major) \nuniform %s %s", ConstantBufferField->Type->Name.CStr(), ConstantBufferField->Name.CStr()); } if (ConstantBufferField->ArrayRank != 0) { // Adding array information for our field.. Builder.AppendFormat("[%d]", static_cast<int>(ConstantBufferField->ArrayRank)); } Builder.Append(';'); } if (SupportsConstantBuffers) Builder.Append("\n};"); else Builder.AppendFormat("\n// }\t// uniform %s.", ConstantBuffer->Name.CStr()); }
// ------------------------------------------------------------------------------------------ //! @todo Document and cleanup me. void GLSLGenerator::GenerateShaderEntryPoint(HLSLFunction const* const EntryPoint, StringBuilder& Builder) { StringBuilder FakeEntryAssigment; StringBuilder FakeEntryInvocation; StringBuilder FakeEntryInternals, FakeEntryExternals; int LastUsedSemanticIn = 0, LastUsedSemanticOut = 0; for (auto const& Argument : EntryPoint->Arguments) { CStr const ArgumentAccessType = Argument->AccsessType == GD_HLSL_ARGUMENT_IN ? "in " : "out"; int& LastUsedSemantic = Argument->AccsessType == GD_HLSL_ARGUMENT_IN ? LastUsedSemanticIn : LastUsedSemanticOut; if (Argument->Type->Class == GD_HLSL_TYPE_CLASS_STRUCT) { if (Argument->AccsessType == GD_HLSL_ARGUMENT_IN) { FakeEntryInvocation.AppendFormat("%s(", Argument->Type->Name.CStr(), Argument->Name.CStr()); } else { FakeEntryInvocation.AppendFormat("%s, ", Argument->Name.CStr()); FakeEntryInternals.AppendFormat("\n\t%s %s;", Argument->Type->Name.CStr(), Argument->Name.CStr()); } auto const Struct = static_cast<HLSLStruct const*>(Argument->Type); for (auto const& Definition : Struct->InnerDefinitions) { auto const StructField = static_cast<HLSLVariable const*>(Definition); // auto const StructFieldSemantic = static_cast<HLSLSemantic const*>(StructField->Binding); FakeEntryExternals.AppendFormat("\nlayout(location = %d) %s %s Varying%s%s;", LastUsedSemantic , ArgumentAccessType, StructField->Type->Name.CStr(), Argument->Name.CStr(), StructField->Name.CStr()); if (Argument->AccsessType == GD_HLSL_ARGUMENT_IN) FakeEntryInvocation.AppendFormat("Varying%s%s, ", Argument->Name.CStr(), StructField->Name.CStr()); else FakeEntryAssigment.AppendFormat("\n\tVarying%s%s = %s.%s;", Argument->Name.CStr(), StructField->Name.CStr(), Argument->Name.CStr(), StructField->Name.CStr()); LastUsedSemantic += 1; } if (Argument->AccsessType == GD_HLSL_ARGUMENT_IN) { //! @todo Refactor this awful code. *(FakeEntryInvocation.CStr() + FakeEntryInvocation.GetLength() - 2) = ')'; // Removing trailing comma. *(FakeEntryInvocation.CStr() + FakeEntryInvocation.GetLength() - 1) = ','; // Removing trailing space. FakeEntryInvocation.Append(' '); } } else { auto const ArgumentSemantic = static_cast<HLSLSemantic const*>(Argument->Binding); if (Argument->AccsessType == GD_HLSL_ARGUMENT_OUT) { if (ArgumentSemantic->Semantic == GD_HLSL_SEMANTIC_SV_Position) FakeEntryAssigment.AppendFormat("\n\tgl_Position = %s;", Argument->Name.CStr()); } FakeEntryExternals.AppendFormat("\nlayout(location = %d) %s %s Varying%s;", LastUsedSemantic, ArgumentAccessType, Argument->Type->Name.CStr(), Argument->Name.CStr()); FakeEntryInvocation.AppendFormat("Varying%s, ", Argument->Name.CStr()); LastUsedSemantic += 1; } } //! @todo Refactor this awful code. *(FakeEntryInvocation.CStr() + FakeEntryInvocation.GetLength() - 2) = ')'; // Removing trailing comma. *(FakeEntryInvocation.CStr() + FakeEntryInvocation.GetLength() - 1) = ';'; // Removing trailing space. FakeEntryInvocation = Move(StringBuilder().AppendFormat("\n\t%s(%s", EntryPoint->Name.CStr(), FakeEntryInvocation.CStr())); if (EntryPoint->Type->Class == GD_HLSL_TYPE_CLASS_STRUCT) { FakeEntryInternals.AppendFormat("\n\t%s Ret;", EntryPoint->Type->Name.CStr()); FakeEntryInvocation = Move(StringBuilder().AppendFormat("\n\tRet = %s", FakeEntryInvocation.CStr() + 2)); HLSLStruct const* const ReturnStruct = static_cast<HLSLStruct const*>(EntryPoint->Type); for (auto const& Definition : ReturnStruct->InnerDefinitions) { HLSLVariable const* const ReturnStructField = static_cast<HLSLVariable const*>(Definition); // HLSLSemantic const* const ReturnStructFieldSemantic = static_cast<HLSLSemantic const*>(ReturnStructField->Binding); FakeEntryExternals.AppendFormat("\nlayout(location = %d) out %s VaryingRet%s;", LastUsedSemanticOut, ReturnStructField->Type->Name.CStr(), ReturnStructField->Name.CStr()); FakeEntryAssigment.AppendFormat("\n\tVaryingRet%s = Ret.%s;", ReturnStructField->Name.CStr(), ReturnStructField->Name.CStr()); LastUsedSemanticOut += 1; } } else if (EntryPoint->Semantic != nullptr) { FakeEntryExternals.AppendFormat("\nlayout(location = %d) out %s VaryingRet;", LastUsedSemanticOut, EntryPoint->Name.CStr()); FakeEntryInvocation = Move(StringBuilder().AppendFormat("\n\tVaryingRet = %s", FakeEntryInvocation.CStr() + 2)); } Builder.AppendFormat("\n%s\n\nvoid main()\n{\n%s\n%s\n%s}\n", FakeEntryExternals.CStr() , FakeEntryInternals.CStr(), FakeEntryInvocation.CStr(), FakeEntryAssigment.CStr()); }