1#include "ShaderBuilder.h"
3#include "Utilities/Strings.h"
4#include "Utilities/Preprocessor.h"
5#include "ResourceStore.h"
6#include "Renderer/EnginePermutations.h"
8#include "Rendering/IGraphicsDevice.h"
10#include "Foundation/Logging/Logger.h"
11#include "Foundation/StringUtilities.h"
12#include "Foundation/StringView.h"
21 constexpr size_t InitialBufferCapasity = 4096u;
26 } engineTextures[] = {
27 { Strings::add(
"environmentSky"), Strings::add(
"ENVIRONMENT_SKY")},
28 { Strings::add(
"environmentRadiance"), Strings::add(
"ENVIRONMENT_RADIANCE")},
29 { Strings::add(
"environmentIrradiance"), Strings::add(
"ENVIRONMENT_IRRADIANCE")},
30 { Strings::add(
"ambientIrradiance"), Strings::add(
"AMBIENT_IRRADIANCE")},
31 { Strings::add(
"brdfLUT"), Strings::add(
"BRDF_LUT")},
32 { Strings::add(
"cascadedShadowMap"), Strings::add(
"CASCADEDSHADOWMAP")},
33 { Strings::add(
"cubeShadowMap"), Strings::add(
"CUBESHADOWMAP")}
36 struct EngineBufferMember
44 Strings::add(
"projectionMatrix"),
45 Strings::add(
"viewMatrix"),
46 Strings::add(
"inverseViewMatrix"),
47 Strings::add(
"inverseProjectionMatrix"),
48 Strings::add(
"worldToClipMatrix"),
49 Strings::add(
"projectionParameters"),
50 Strings::add(
"clippingPlanes"),
51 Strings::add(
"originHigh"),
52 Strings::add(
"originLow"),
53 Strings::add(
"blueNoiseOffset"),
54 Strings::add(
"viewportOrigin"),
55 Strings::add(
"viewportSize"),
56 Strings::add(
"viewportSizeRcp"),
57 Strings::add(
"shadowDepthClamp"),
58 Strings::add(
"animationTime"),
59 Strings::add(
"exposure"),
60 Strings::add(
"sceneFlags"),
61 Strings::add(
"clientFlags"),
62 Strings::add(
"environmentRadianceMips"),
63 Strings::add(
"environmentIrradianceMips")
67 Strings::add(
"getPeriodicWorldPos"),
68 Strings::add(
"getPeriodicWorldPosAndCell")
72 Strings::add(
"getClipFromViewMatrix"),
73 Strings::add(
"getClipFromWorldMatrix"),
74 Strings::add(
"getViewFromWorldMatrix"),
75 Strings::add(
"getViewFromClipMatrix"),
76 Strings::add(
"getWorldFromViewMatrix"),
77 Strings::add(
"getViewFromViewportMatrix")
81 Strings::add(
"worldMatrix"),
82 Strings::add(
"objectId")
86 Strings::add(
"boneTransforms")
90 Strings::add(
"lightPositions"),
91 Strings::add(
"lightDirections"),
92 Strings::add(
"lightColorIntensity"),
93 Strings::add(
"lightParameters"),
94 Strings::add(
"numLights"),
95 Strings::add(
"eyePosition"),
96 Strings::add(
"fogColor"),
97 Strings::add(
"fogDistance"),
98 Strings::add(
"fogAmount"),
99 Strings::add(
"fogEnabled"),
100 Strings::add(
"ambientIntensity"),
101 Strings::add(
"ambientColor"),
102 Strings::add(
"environmentBrightness"),
103 Strings::add(
"skyMultiplier"),
104 Strings::add(
"seaFlags"),
105 Strings::add(
"flags")
109 Strings::add(
"shadows"),
110 Strings::add(
"cascadeOffsets")
113 struct EngineBuffer {
117 } engineBuffers[] = {
118 { sceneBufferMembers,
sizeof(sceneBufferMembers) /
sizeof(sceneBufferMembers[0]), Strings::add(
"SCENEBUFFER") },
119 { sceneGetters,
sizeof(sceneGetters) /
sizeof(sceneGetters[0]), Strings::add(
"SCENEGETTERS") },
120 { viewGetters,
sizeof(viewGetters) /
sizeof(viewGetters[0]), Strings::add(
"VIEWGETTERS") },
121 { objectBufferMembers,
sizeof(objectBufferMembers) /
sizeof(objectBufferMembers[0]), Strings::add(
"OBJECTBUFFER") },
122 { animationBufferMembers,
sizeof(animationBufferMembers) /
sizeof(animationBufferMembers[0]), Strings::add(
"ANIMATIONBUFFER") },
123 { lightBufferMembers,
sizeof(lightBufferMembers) /
sizeof(lightBufferMembers[0]), Strings::add(
"LIGHTBUFFER") },
124 { shadowBufferMembers,
sizeof(shadowBufferMembers) /
sizeof(shadowBufferMembers[0]), Strings::add(
"SHADOWBUFFER") }
131 content.append(
"#include \"");
133 content.append(path.to_string_view());
134 content.append(
"\"\n");
137 void changeSuffix(std::string& dst,
const std::string_view& from,
const std::string_view& to)
139 auto pos = dst.find(from);
140 if (pos == std::string::npos)
return;
141 dst.replace(pos, to.length(), to);
144 void addEffectDefinesAndStuff(std::string& output,
145 const std::vector<std::pair<std::string, std::string>>& definitions,
146 uint32_t multiViewCount,
bool isVertexShader)
148 output.append(
"#version 300 es\n");
149 if (multiViewCount) {
150 std::string multiViewCountString = std::to_string(multiViewCount);
151 if (isVertexShader) {
152 output.append(
"#extension GL_OVR_multiview : require\nlayout(num_views=");
153 output.append(multiViewCountString);
154 output.append(
") in;\n");
156 output.append(
"#define COGS_MULTIVIEW ");
157 output.append(multiViewCountString);
160 output.append(
"precision highp float;\n"
161 "precision highp int;\n"
162 "precision highp sampler2DArrayShadow;\n"
163 "precision highp samplerCubeShadow;\n"
164 "precision mediump sampler2DArray;\n"
165 "precision highp isampler2D;\n"
166 "precision highp usampler2D;\n"
167 "precision highp usampler2DArray;\n"
168 "precision highp isampler2DArray;\n"
169 "layout (std140) uniform;\n");
170 for (
const std::pair<std::string,std::string>& define : definitions) {
171 output.append(
"#define ");
172 output.append(define.first);
174 output.append(define.second);
179 [[nodiscard]] std::string_view attributeVaryingType(
const MaterialDataType type)
182 case MaterialDataType::Float:
return "float ";
break;
183 case MaterialDataType::Float2:
return "vec2 ";
break;
184 case MaterialDataType::Float3:
return "vec3 ";
break;
185 case MaterialDataType::Float4:
return "vec4 ";
break;
186 case MaterialDataType::Float4x4:
return "mat4 ";
break;
187 case MaterialDataType::Int:
return "int ";
break;
188 case MaterialDataType::Int2:
return "ivec4 ";
break;
189 case MaterialDataType::Int3:
return "ivec3 ";
break;
190 case MaterialDataType::Int4:
return "ivec4 ";
break;
191 case MaterialDataType::UInt:
return "uint ";
break;
192 case MaterialDataType::UInt2:
return "uvec4 ";
break;
193 case MaterialDataType::UInt3:
return "uvec3 ";
break;
194 case MaterialDataType::UInt4:
return "uvec4 ";
break;
195 case MaterialDataType::SV_IsFrontFace:
return "bool ";
break;
196 case MaterialDataType::VFACE:
return "float ";
break;
197 case MaterialDataType::Position:
return "vec4 ";
break;
199 LOG_ERROR(logger,
"Unsupported attribute type %d",
int(type));
205 const char* semanticNames[]
215 static_assert(
sizeof(semanticNames) ==
sizeof(semanticNames[0]) * (size_t(ShaderInterfaceMemberDefinition::SemanticName::FirstSystemValueSemantic) - 1));
221 if ((attribute.semantic.name != ShaderInterfaceMemberDefinition::SemanticName::None)
222 && (
size_t(attribute.semantic.name) <
size_t(ShaderInterfaceMemberDefinition::SemanticName::FirstSystemValueSemantic)))
224 shaderSource.append(
"in ");
225 shaderSource.append(attributeVaryingType(attribute.type));
226 shaderSource.append(semanticNames[
size_t(attribute.semantic.name) - 1]);
227 shaderSource.append(std::to_string(attribute.semantic.slot));
228 shaderSource.append(
";\n");
231 switch (attribute.semantic.name) {
232 case ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID: [[fallthrough]];
233 case ShaderInterfaceMemberDefinition::SemanticName::SV_InstanceID:
236 LOG_WARNING(logger,
"Unexpected semantic name '%.*s'",
237 StringViewFormat(ShaderInterfaceMemberDefinition::semanticNameString(attribute.semantic.name)));
241 shaderSource.append(
"\n");
246 shaderSource.append(
"struct ");
247 shaderSource.append(name);
248 shaderSource.append(
" {\n");
249 for (
const auto& attribute : iface.members) {
250 shaderSource.append(
" ");
251 shaderSource.append(attributeVaryingType(attribute.type));
252 shaderSource.append(attribute.name);
253 shaderSource.append(
";\n");
255 shaderSource.append(
"};\n\n");
258 void addAttributeImportFunc(std::string& shaderSource,
const std::string_view& name,
const ShaderInterfaceDefinition& iface)
260 shaderSource.append(name);
261 shaderSource.append(
" importAttributes() {\n");
262 shaderSource.append(
" ");
263 shaderSource.append(name);
264 shaderSource.append(
" t;\n");
265 for (
const auto& attribute : iface.members) {
268 if ((attribute.semantic.name != ShaderInterfaceMemberDefinition::SemanticName::None)
269 && (
size_t(attribute.semantic.name) <
size_t(ShaderInterfaceMemberDefinition::SemanticName::FirstSystemValueSemantic)))
271 shaderSource.append(
" t.");
272 shaderSource.append(attribute.name);
273 shaderSource.append(
" = ");
274 shaderSource.append(semanticNames[
size_t(attribute.semantic.name) - 1]);
275 shaderSource.append(std::to_string(attribute.semantic.slot));
276 shaderSource.append(
";\n");
279 switch (attribute.semantic.name) {
280 case ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID:
281 shaderSource.append(
" t.");
282 shaderSource.append(attribute.name);
283 shaderSource.append(
" = ");
284 shaderSource.append(attributeVaryingType(attribute.type));
285 shaderSource.append(
"(gl_VertexID);\n");
287 case ShaderInterfaceMemberDefinition::SemanticName::SV_InstanceID:
288 shaderSource.append(
" t.");
289 shaderSource.append(attribute.name);
290 shaderSource.append(
" = ");
291 shaderSource.append(attributeVaryingType(attribute.type));
292 shaderSource.append(
"(gl_InstanceID);\n");
299 shaderSource.append(
" return t;\n}\n\n");
302 void addInOutVariables(std::string& shaderSource,
const std::string_view& prefix,
const ShaderInterfaceDefinition& iface,
bool in)
304 if (iface.members.empty())
return;
305 for (
const auto& out : iface.members) {
307 case MaterialDataType::SV_IsFrontFace:
308 case MaterialDataType::VFACE:
312 if (out.modifiers & ShaderInterfaceMemberDefinition::CentroidModifier) {
313 shaderSource.append(
"centroid ");
315 if (out.modifiers & ShaderInterfaceMemberDefinition::NointerpolationModifier) {
316 shaderSource.append(
"flat ");
318 shaderSource.append(in ?
"in " :
"out ");
319 shaderSource.append(attributeVaryingType(out.type));
320 shaderSource.append(prefix);
321 shaderSource.append(out.name);
322 shaderSource.append(
";\n");
326 shaderSource.append(
"\n");
329 void addInterfaceConstructor(std::string& shaderSource,
const std::string_view& name,
const ShaderInterfaceDefinition& iface)
331 shaderSource.append(name);
332 shaderSource.append(
" create");
333 shaderSource.append(name);
334 shaderSource.append(
"() {\n");
335 shaderSource.append(
" ");
336 shaderSource.append(name);
337 shaderSource.append(
" t;\n");
338 for (
const auto& attribute : iface.members) {
339 const char* initializer =
nullptr;
340 switch (attribute.type) {
341 case MaterialDataType::Float: initializer =
"0.0;\n";
break;
342 case MaterialDataType::Float2: initializer =
"vec2(0);\n";
break;
343 case MaterialDataType::Float3: initializer =
"vec3(0);\n";
break;
344 case MaterialDataType::Float4: initializer =
"vec4(0);\n";
break;
345 case MaterialDataType::Float4x4: initializer =
"mat4(0);\n";
break;
350 shaderSource.append(
" t.");
351 shaderSource.append(attribute.name);
352 shaderSource.append(
" = ");
353 shaderSource.append(initializer);
356 shaderSource.append(
" return t;\n}\n\n");
361 shaderSource.append(
"void exportOut(");
362 shaderSource.append(name);
363 shaderSource.append(
" vertexOut) {\n");
364 for (
const auto& attribute : iface.members) {
365 switch (attribute.type) {
366 case MaterialDataType::SV_IsFrontFace:
367 case MaterialDataType::VFACE:
371 shaderSource.append(
" vsfs_");
372 shaderSource.append(attribute.name);
373 shaderSource.append(
" = vertexOut.");
374 shaderSource.append(attribute.name);
375 shaderSource.append(
";\n");
379 shaderSource.append(
"}\n");
384 shaderSource.append(name);
385 shaderSource.append(
" importIn() {\n ");
386 shaderSource.append(name);
387 shaderSource.append(
" t;\n");
388 for (
const auto& attribute : iface.members) {
389 switch (attribute.type) {
390 case MaterialDataType::SV_IsFrontFace:
391 shaderSource.append(
" t.");
392 shaderSource.append(attribute.name);
393 shaderSource.append(
" = gl_FrontFacing;\n");
395 case MaterialDataType::VFACE:
396 shaderSource.append(
" t.");
397 shaderSource.append(attribute.name);
398 shaderSource.append(
" = gl_FrontFacing ? 1.0 : -1.0;\n");
400 case MaterialDataType::Position:
401 shaderSource.append(
" t.");
402 shaderSource.append(attribute.name);
403 shaderSource.append(
" = gl_FragCoord;\n");
406 shaderSource.append(
" t.");
407 shaderSource.append(attribute.name);
408 shaderSource.append(
" = vsfs_");
409 shaderSource.append(attribute.name);
410 shaderSource.append(
";\n");
414 shaderSource.append(
" return t;\n}\n");
419 shaderSource.append(
"void transferAttributes(in VertexIn vertexIn, inout VertexOut vertexOut) {\n");
421 if (member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::SV_VertexID)
continue;
423 if (dMember.name == member.name) {
424 shaderSource.append(
" vertexOut.");
425 shaderSource.append(member.name);
426 shaderSource.append(
" = ");
427 if (dMember.type == MaterialDataType::Float3 && member.type == MaterialDataType::Float2 && member.semantic.name == ShaderInterfaceMemberDefinition::SemanticName::Normal) {
428 shaderSource.append(
"octDecode(vertexIn.");
429 shaderSource.append(member.name);
430 shaderSource.append(
"); \n");
433 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float3) {
434 shaderSource.append(
"vec4(vertexIn.");
435 shaderSource.append(member.name);
436 shaderSource.append(
", 1.0);\n");
439 if (dMember.type == MaterialDataType::Float4 && member.type == MaterialDataType::Float2) {
440 shaderSource.append(
"vec4(vertexIn.");
441 shaderSource.append(member.name);
442 shaderSource.append(
", 0.0, 1.0);\n");
446 if (dMember.type != member.type) {
447 switch (dMember.type) {
448 case MaterialDataType::Float: shaderSource.append(
"float("); close =
true;
break;
449 case MaterialDataType::Float2: shaderSource.append(
"vec2("); close =
true;
break;
450 case MaterialDataType::Float3: shaderSource.append(
"vec3("); close =
true;
break;
451 case MaterialDataType::Float4: shaderSource.append(
"vec4("); close =
true;
break;
452 case MaterialDataType::Float4x4: shaderSource.append(
"mat4("); close =
true;
break;
453 case MaterialDataType::Int: shaderSource.append(
"int("); close =
true;
break;
454 case MaterialDataType::Int2: shaderSource.append(
"ivec2("); close =
true;
break;
455 case MaterialDataType::Int3: shaderSource.append(
"ivec3("); close =
true;
break;
456 case MaterialDataType::Int4: shaderSource.append(
"ivec4("); close =
true;
break;
457 case MaterialDataType::UInt: shaderSource.append(
"uint("); close =
true;
break;
458 case MaterialDataType::UInt2: shaderSource.append(
"uvec2("); close =
true;
break;
459 case MaterialDataType::UInt3: shaderSource.append(
"uvec3("); close =
true;
break;
460 case MaterialDataType::UInt4: shaderSource.append(
"uvec4("); close =
true;
break;
465 shaderSource.append(
"vertexIn.");
466 shaderSource.append(member.name);
467 if (close) shaderSource.append(1,
')');
468 shaderSource.append(
";\n");
473 shaderSource.append(
"}\n");
477 void addEngineUniformBuffer(std::string& shaderSource,
const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen)
479 for (
const EngineBuffer& engineBuffer : engineBuffers) {
482 bool referenced =
false;
483 for (
size_t i = 0; i < engineBuffer.count; i++) {
484 if (identifiersSeen.contains(engineBuffer.members[i])) {
493 shaderSource.append(
"#define COGS_");
494 shaderSource.append(Strings::get(engineBuffer.name).to_string_view());
495 shaderSource.append(
"_REFERENCED 1\n");
500 void addUniformBuffer(std::string& shaderSource,
501 const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen,
504 if (definition.values.empty())
return;
507 bool isInUse =
false;
509 if (identifiersSeen.contains(Strings::add(member.name))) {
514 if (!isInUse)
return;
517 shaderSource.append(
"uniform ");
518 shaderSource.append(definition.name);
519 shaderSource.append(
" {\n");
521 shaderSource.append(2,
' ');
522 switch (member.type) {
523 case MaterialDataType::Float: shaderSource.append(
"float");
break;
524 case MaterialDataType::Float2: shaderSource.append(
"vec2");
break;
525 case MaterialDataType::Float3: shaderSource.append(
"vec3");
break;
526 case MaterialDataType::Float4: shaderSource.append(
"vec4");
break;
527 case MaterialDataType::Float4x4: shaderSource.append(
"mat4");
break;
528 case MaterialDataType::Float4Array: shaderSource.append(
"vec4");
break;
529 case MaterialDataType::Float4x4Array: shaderSource.append(
"mat4");
break;
530 case MaterialDataType::Int: shaderSource.append(
"int");
break;
531 case MaterialDataType::Int2: shaderSource.append(
"ivec2");
break;
532 case MaterialDataType::Int3: shaderSource.append(
"ivec3");
break;
533 case MaterialDataType::Int4: shaderSource.append(
"ivec4");
break;
534 case MaterialDataType::UInt: shaderSource.append(
"uint");
break;
535 case MaterialDataType::UInt2: shaderSource.append(
"uvec2");
break;
536 case MaterialDataType::UInt3: shaderSource.append(
"uvec3");
break;
537 case MaterialDataType::UInt4: shaderSource.append(
"uvec4");
break;
538 case MaterialDataType::Bool: shaderSource.append(
"bool");
break;
540 shaderSource.append(
"<invalid type>");
543 shaderSource.append(1,
' ');
544 shaderSource.append(member.name);
545 if (member.type == MaterialDataType::Float4Array || member.type == MaterialDataType::Float4x4Array) {
546 assert(member.dimension !=
static_cast<size_t>(-1));
547 shaderSource.append(
"[");
548 shaderSource.append(std::to_string(member.dimension));
549 shaderSource.append(
"]");
551 shaderSource.append(
";\n");
553 shaderSource.append(
"};\n");
557 void addEngineUniforms(std::string& shaderSource,
const std::unordered_set<StringRef>& identifiersSeen)
559 for (
auto& item : engineUniforms) {
560 bool active = identifiersSeen.count(item.name);
561 for (
auto dependee : item.dependees) {
562 active = active || identifiersSeen.count(dependee);
565 shaderSource.append(
"uniform ");
567 case MaterialDataType::Float4:
568 shaderSource.append(
"vec4 ");
570 case MaterialDataType::Float4x4:
571 shaderSource.append(
"mat4 ");
574 assert(
false &&
"Unhandled material data type");
576 auto name = Strings::get(item.name);
577 shaderSource.append(name.to_string_view());
578 shaderSource.append(
";\n");
581 if (identifiersSeen.count(objectId)) shaderSource.append(
"float objectId() { return objectData.x; }\n");
582 if (identifiersSeen.count(animationTime)) shaderSource.append(
"float animationTime() { return objectData.y; }\n");
583 if (identifiersSeen.count(environmentRadianceMips)) shaderSource.append(
"float environmentRadianceMips() { return environmentInfo.x; }\n");
584 if (identifiersSeen.count(environmentIrradianceMips)) shaderSource.append(
"float environmentIrradianceMips() { return environmentInfo.y; }\n");
585 if (identifiersSeen.count(exposure)) shaderSource.append(
"float exposure() { return environmentInfo.z; }\n");
586 if (identifiersSeen.count(environmentBrightness)) shaderSource.append(
"float environmentBrightness() { return environmentInfo.w; }\n");
593 shaderSource.append(
"uniform ");
596 case MaterialTypePrecision::Default:
598 case MaterialTypePrecision::Low:
599 shaderSource.append(
"lowp ");
601 case MaterialTypePrecision::Medium:
602 shaderSource.append(
"mediump ");
604 case MaterialTypePrecision::High:
605 shaderSource.append(
"highp ");
608 assert(
false &&
"Invalid enum value");
614 case MaterialDataType::Unknown:
615 case MaterialDataType::Float:
616 case MaterialDataType::Float2:
617 case MaterialDataType::Float3:
618 case MaterialDataType::Float4:
621 case MaterialDataType::Int:
622 case MaterialDataType::Int2:
623 case MaterialDataType::Int3:
624 case MaterialDataType::Int4:
625 shaderSource.append(
"i");
628 case MaterialDataType::UInt:
629 case MaterialDataType::UInt2:
630 case MaterialDataType::UInt3:
631 case MaterialDataType::UInt4:
632 shaderSource.append(
"u");
635 LOG_ERROR(logger,
"Unexpected texture format: %s", DataTypeNames[
static_cast<size_t>(format) < std::size(DataTypeNames) ?
static_cast<size_t>(format) : 0]);
640 case TextureDimensions::Texture2D:
641 shaderSource.append(
"sampler2D ");
643 case TextureDimensions::TexureCube:
644 shaderSource.append(
"samplerCube ");
646 case TextureDimensions::Texture2DArray:
647 shaderSource.append(
"sampler2DArray ");
649 case TextureDimensions::Texture3D:
650 shaderSource.append(
"sampler3D ");
653 LOG_ERROR(logger,
"Unsupported texture type %d",
int(kind));
657 shaderSource.append(
";\n");
660 void addTextures(std::string& shaderSource,
661 const std::unordered_set<Cogs::Core::StringRef>& identifiersSeen,
662 const std::vector<MaterialTextureDefinition>& definition)
664 for (
auto& texture : engineTextures) {
665 if (identifiersSeen.contains(texture.name)) {
666 shaderSource.append(
"#define COGS_");
667 shaderSource.append(Strings::get(texture.defineName).to_string_view());
668 shaderSource.append(
"_REFERENCED 1\n");
671 for (
auto& texture : definition) {
672 if (identifiersSeen.contains(Strings::add(texture.name))) {
673 addTextureDeclaration(shaderSource, texture.name, texture.dimensions, texture.format, texture.precision);
676 shaderSource.append(
"\n");
680bool addPermutationFragmentOutput(std::string& source,
const std::vector<EffectOutputMemberDefinition> outputDefinition,
const std::vector<std::pair<std::string, std::string>>& definitions,
bool depthOnly) {
681 bool outputDepth =
false;
682 bool hasColorAttachments = !outputDefinition.empty() && !depthOnly;
684 std::string targetString =
"COGS_CUSTOM_DEPTH_WRITE";
685 auto it = std::find_if(definitions.begin(), definitions.end(),
686 [&targetString](
const std::pair<std::string, std::string>& p) {
687 return p.first == targetString;
690 if (it != definitions.end()) {
691 outputDepth = it->second !=
"0";
694 if (!outputDepth && !hasColorAttachments) {
698 std::string outVariables;
700 source.append(
"struct FragmentOut {\n");
701 if (hasColorAttachments) {
702 for (
auto member : outputDefinition) {
703 outVariables.append(
"layout(location = " + std::to_string(member.target) +
") out " + std::string(attributeVaryingType(member.dataType)) +
"po_" + member.name +
";\n");
705 source.append(
" " + std::string(attributeVaryingType(member.dataType)) +
" " + member.name +
";\n");
709 source.append(
" float fragDepth;\n");
711 source.append(
"};\n");
712 source.append(outVariables);
716void addMainFunction(std::string& source,
const std::vector<EffectOutputMemberDefinition> outputDefinition,
const std::vector<std::pair<std::string, std::string>>& definitions,
bool depthOnly,
bool hasOutput) {
720 VertexIn In = importIn();
727 bool outputDepth =
false;
728 std::string targetString =
"COGS_CUSTOM_DEPTH_WRITE";
729 auto it = std::find_if(definitions.begin(), definitions.end(),
730 [&targetString](
const std::pair<std::string, std::string>& p) {
731 return p.first == targetString;
734 if (it != definitions.end()) {
735 outputDepth = it->second !=
"0";
738 source.append(
"void exportOut(FragmentOut Out) {\n");
740 for (
auto member : outputDefinition) {
741 source.append(
" po_");
742 source.append(member.name);
743 source.append(
" = Out.");
744 source.append(member.name);
745 source.append(
";\n");
749 source.append(
" gl_FragDepth = Out.fragDepth;\n");
751 source.append(
"}\n");
754 VertexIn In = importIn();
755 FragmentOut Out = permutationMain(In);
762 out.members.reserve(a.members.size() + b.members.size());
764 for (
auto member : b.members) {
766 for (
auto existingMember : a.members) {
767 if (member.name == existingMember.name) {
773 out.members.push_back(member);
778bool Cogs::Core::buildEffectES3(
Context* context,
779 std::vector<std::pair<std::string, std::string>>& definitions,
782 uint32_t multiViewCount)
784 if (!materialDefinition.effect.geometryShader.entryPoint.empty()) {
785 LOG_ERROR(logger,
"%s: Geometry shader not allowed in GLES3.", materialDefinition.name.c_str());
788 if (!materialDefinition.effect.hullShader.entryPoint.empty()) {
789 LOG_ERROR(logger,
"%s: Hull shader not allowed in GLES3.", materialDefinition.name.c_str());
792 if (!materialDefinition.effect.domainShader.entryPoint.empty()) {
793 LOG_ERROR(logger,
"%s: Domain shader not allowed in GLES3.", materialDefinition.name.c_str());
796 if (!materialDefinition.effect.computeShader.entryPoint.empty()) {
797 LOG_ERROR(logger,
"%s: Compute shader not allowed in GLES3.", materialDefinition.name.c_str());
801 changeSuffix(materialDefinition.effect.vertexShader.customSourcePath,
".hlsl",
".es30.glsl");
802 changeSuffix(materialDefinition.effect.pixelShader.customSourcePath,
".hlsl",
".es30.glsl");
803 std::string_view prefix = materialDefinition.name;
806 concatUniqueMembers(materialDefinition.effect.vertexShader.shaderInterface, permutation.getDefinition()->vertexInterface, vertexInterface);
808 concatUniqueMembers(materialDefinition.effect.pixelShader.shaderInterface, permutation.getDefinition()->surfaceInterface, surfaceInterface);
813 pp.
processed.reserve(::InitialBufferCapasity);
815 std::string vsheader;
816 vsheader.reserve(::InitialBufferCapasity);
817 addEffectDefinesAndStuff(vsheader, definitions, multiViewCount,
true);
818 vsheader.append(
"#define COGS_VERTEX_SHADER 1\n");
819 if (!pp.
process(context, vsheader))
return false;
824 vsbody.reserve(::InitialBufferCapasity);
825 addAttributes(vsbody, vertexInterface);
826 addInterfaceStruct(vsbody,
"VertexIn", vertexInterface);
827 addAttributeImportFunc(vsbody,
"VertexIn", vertexInterface);
828 addInOutVariables(vsbody,
"vsfs_",surfaceInterface,
false);
829 addInterfaceStruct(vsbody,
"VertexOut",surfaceInterface);
830 addInterfaceConstructor(vsbody,
"VertexOut",surfaceInterface);
831 addExportOutFunc(vsbody,
"VertexOut",surfaceInterface);
832 addTransferFunc(vsbody, materialDefinition.effect.vertexShader, materialDefinition.effect.pixelShader);
833 addInclude(vsbody,
Cogs::StringView(), materialDefinition.effect.vertexShader.customSourcePath);
835 vsbody.append(
"#define MATERIAL_VERTEX_FUNCTION ");
836 vsbody.append(materialDefinition.effect.vertexShader.entryPoint.empty() ?
"vertexFunction" : materialDefinition.effect.vertexShader.entryPoint);
840 vsbody.append(
"#define VERTEX_FUNCTION invokeMaterial\n");
841 std::string permutationVS = permutation.getDefinition()->vertexShader;
842 changeSuffix(permutationVS,
".hlsl",
".es30.glsl");
843 addInclude(vsbody,
nullptr, permutationVS);
845 if (!pp.
process(context, vsbody))
return false;
849 std::string vsuniforms;
850 vsuniforms.reserve(::InitialBufferCapasity);
858 addTextures(vsuniforms, pp.
identifiersSeen, materialDefinition.properties.textures);
861 if (!pp.
process(context, vsuniforms))
return false;
865 const std::string shaderName = Cogs::stringConcatenate({ prefix,
"VertexShader", permutation.getDefinition()->name,
".es30.glsl" });
866 const std::string all = Cogs::stringConcatenate({ vsheader, vsuniforms, vsbody });
869#ifndef __EMSCRIPTEN__
870 FILE* f = fopen(shaderName.c_str(),
"wb");
871 fwrite(all.c_str(), all.length(), 1, f);
873 LOG_DEBUG(logger,
"Generated %s", shaderName.c_str());
877 std::string vspath =
"Shaders/" + shaderName;
883 pp.
processed.reserve(::InitialBufferCapasity);
885 std::string fsheader;
886 fsheader.reserve(::InitialBufferCapasity);
887 addEffectDefinesAndStuff(fsheader, definitions, multiViewCount,
false);
888 fsheader.append(
"#define COGS_FRAGMENT_SHADER 1\n");
889 if (!pp.
process(context, fsheader))
return false;
894 fsbody.reserve(::InitialBufferCapasity);
895 addInOutVariables(fsbody,
"vsfs_",surfaceInterface,
true);
896 addInterfaceStruct(fsbody,
"VertexIn",surfaceInterface);
897 addImportInFunc(fsbody,
"VertexIn",surfaceInterface);
898 addInclude(fsbody,
nullptr, materialDefinition.effect.pixelShader.customSourcePath);
900 fsbody.append(
"#define MATERIAL_SURFACE_FUNCTION ");
901 fsbody.append(materialDefinition.effect.pixelShader.entryPoint.empty() ?
"surfaceFunction" : materialDefinition.effect.pixelShader.entryPoint);
905 bool hasOutputStruct = addPermutationFragmentOutput(fsbody, permutation.getDefinition()->outputs.members, definitions, permutation.isDepthOnly());
907 fsbody.append(
"#define SURFACE_FUNCTION invokeMaterial\n");
908 std::string permutationPS = permutation.getDefinition()->pixelShader;
909 changeSuffix(permutationPS,
".hlsl",
".es30.glsl");
910 addInclude(fsbody,
nullptr, permutationPS);
912 if (!pp.
process(context, fsbody))
return false;
916 addMainFunction(fsbody, permutation.getDefinition()->outputs.members, definitions, permutation.isDepthOnly(), hasOutputStruct);
918 std::string fsuniforms;
919 fsuniforms.reserve(::InitialBufferCapasity);
927 addTextures(fsuniforms, pp.
identifiersSeen, materialDefinition.properties.textures);
928 addInclude(fsuniforms,
nullptr,
"Engine/Common.es30.glsl");
930 if (!pp.
process(context, fsuniforms))
return false;
934 const std::string shaderName = Cogs::stringConcatenate({ prefix,
"PixelShader", permutation.getDefinition()->name,
".es30.glsl" });
935 const std::string all = Cogs::stringConcatenate({ fsheader, fsuniforms, fsbody });
938#ifndef __EMSCRIPTEN__
939 FILE* f = fopen(shaderName.c_str(),
"wb");
940 fwrite(all.c_str(), all.length(), 1, f);
942 LOG_DEBUG(logger,
"Generated %s", shaderName.c_str());
946 std::string fspath =
"Shaders/" + shaderName;
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class ResourceStore > resourceStore
ResourceStore service instance.
Log implementation class.
Provides a weakly referenced view over the contents of a string.
constexpr size_t size() const noexcept
Get the size of the string.
constexpr std::string_view to_string_view() const noexcept
Create a standard library string_view of the same view.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
TextureDimensions
Texture dimensions.
MaterialDataType
Defines available data types for material properties.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
bool process(Context *context, const StringView input)
Run a text block through the preprocessor.
std::unordered_set< StringRef > identifiersSeen
Set of identifiers encountered in active text.
std::string processed
Resulting processed text.